Hi! So I’m looking at doing a CodeMirror 5 to 6 upgrade and one of the options we use is firstLineNumber
. I figured that would be a good place to start learning some of the new API and how it all works together.
I was able to come up with two different implementations that both work, but I’m not sure I’m doing it in the spirit of how it was intended.
The first is a very naive implementation that creates a new config object for the lineNumbers extension then returns the extension to be given to the editor and a function that can be called to updated it:
function makeLineNumbers(initialValue)
{
const makeConfig = (startLine) => ({
formatNumber: (lineNumber, state) => "" + (lineNumber + startLine - 1);
});
const startLine = new Compartment();
const startLineFacet = Facet.define({
combine: values => values.length ? values[0] : 1
});
const configuredLineNumbers = startLine.of([
startLineFacet.of(initialValue),
lineNumbers(makeConfig(initialValue))
]);
function update(newStart, editorState)
{
const currentValue = editorState.facet(startLineFacet);
if (currentValue === newStart)
return [];
return [
startLine.reconfigure([
startLineFacet.of(newStart),
lineNumbers(makeConfig(newStart))
])
];
}
return [configuredLineNumbers, update];
}
(small note: I’m returning arrays in the update function for implementation detail convenience reasons)
The second implementation was an effort to better encapsulate the current state. It doesn’t create new configs for the lineNumbers extension but rather updates a facet value and reconfigures the compartment :
function makeLineNumbers(initial)
{
const firstLineNumber = Facet.define({
combine: values => values.length ? values[0] : 1
});
const config = {
formatNumber: (lineNumber, state) => {
const start = state.facet(firstLineNumber);
return "" + (lineNumber + start - 1);
}
};
const dynamicLineNumbers = new Compartment();
function updateIfNeeded(newStart, editorState)
{
const currentValue = editorState.facet(firstLineNumber);
if (currentValue === newStart)
return [];
return [
dynamicLineNumbers.reconfigure([
firstLineNumber.of(newStart),
lineNumbers(config)
])
];
}
const initialLineNumbers = dynamicLineNumbers.of([
firstLineNumber.of(initial),
lineNumbers(config)
]);
return [initialLineNumbers, updateIfNeeded];
}
I thought there might be some way to say the lineNumbers extension depends on the startLineNumber
facet directly, then encapsulate that in a way where I only needed to call startLineNumber.of(newValue)
when reconfiguring the compartment, but it seems like I always need to pass a new lineNumbers(config)
during the reconfiguration (even though the config object itself didn’t change".
So I’m curious what the “right way” to do this is. Am I overthinking/over-engineering it in example 2?
Thanks!
- Randy