I have a variable outside CM that holds the regexp which I need to use for highlighting some parts of the text. But when I update this variable, the MatchDecorator keeps using the initial value.
I have read this question but still can’t understand how to fix it.
What is the proper way to dynamically update the reqexp used by MatchDecorator?
let currentRegex = /^(https?):/g;
let regexpComp = new Compartment
function updateCurrentRegexp(regexp) {
currentRegex = regexp
addressLineCm.dispatch({
effects: regexpComp.reconfigure(syntaxTokens)
})
}
const syntaxMatcher = new MatchDecorator({
regexp: currentRegex,
decorate: (add, from, to, match, view) => {
console.log(from + " / " + to + " / " + currentRegex) // Same "from" and "to" all the time
let tokenClass = "highlight"
add(from, to, Decoration.mark({class: tokenClass}))
}
})
const syntaxTokens = ViewPlugin.fromClass(class {
constructor(view) {
this.placeholders = syntaxMatcher.createDeco(view);
}
update(update) {
this.placeholders = syntaxMatcher.createDeco(update.view);
}},{
decorations: (instance) => {
return instance.placeholders;
},
provide: (plugin) =>
EditorView.atomicRanges.of((view) => {
return view.plugin(plugin)?.placeholders || Decoration.none;
}),
}
);
const editor = new EditorView({
doc: `https://mysite.com/api/v3/pat/:petId?param=value&another=123`,
extensions: [
minimalSetup,
regexpComp.of(syntaxTokens),
],
parent: document.querySelector("#address-line")
})
Thank you for the reply. Could you please elaborate on “set things up”?
That’s how I understand it: I create a new copy of syntaxMatcher, then create another copy of syntaxTokens, remove the previous instance of syntaxTokens from the editor and plug in the new instance. Can you point out what should I use for updating extensions on the fly.
The config example goes into that. But for this thing it might be easier to set up a state effect that you can dispatch to reconfigure the highlighter and have your view plugin look for that in transactions.
Ok I get it work. To force your MatchDecorator to update reqexp on the fly you need (follow the comments):
let currentRegex = /^(https?):/g;
let regexpComp = new Compartment // 1. Wrap your decoration plugin with a Compartment. See the EditorView composition
function updateCurrentRegexp(regexp) {
currentRegex = regexp
addressLineCm.dispatch({
effects: regexpComp.reconfigure(syntaxTokens) // 2. When your reqexp outside CM gets changed, tell the Compartment to reconfigure the decoration plugin
})
}
function composeSyntaxMatcher() { // 3. Wrap the matcher into a function. It'll called each time when Compartment reconfigures the decoration plugin
return new MatchDecorator({
regexp: currentRegex,
decorate: (add, from, to, match, view) => {
let tokenClass = "highlight"
add(from, to, Decoration.mark({class: tokenClass}))
}
})
}
let syntaxTokens = ViewPlugin.fromClass(class {
constructor(view) {
let matcher = composeSyntaxMatcher() // 4. Here you create a matcher for the first time
this.placeholders = matcher.createDeco(view);
}
update(update) { // 5. This code gets executed when the Compartment reconfigures this plugin
let matcher = composeSyntaxMatcher() // 5.1 Here you re-create the matcher and it uses the updated reqexp
this.placeholders = matcher.createDeco(update.view);
}
}, {
decorations: (instance) => {
return instance.placeholders;
},
provide: (plugin) =>
EditorView.atomicRanges.of((view) => {
return view.plugin(plugin)?.placeholders || Decoration.none;
}),
});
addressLineCm = new EditorView({
doc: `https://mysite.com/api/v3/pat/:petId?param=value&another=123`,
extensions: [
regexpComp.of(syntaxTokens) // 1. Here you wrap decoration plugin with the Compartment
],
parent: document.querySelector("#address-line")
})