Performance issues with extension

I am trying to create an extension to replace variables of the form ${variable} with a ReactJS component. It works very well, but when there are many variables, it slows down.

I based myself on the example in the documentation:

const variableMatcher = new MatchDecorator({
  regexp: /\${([^}\r\n]+)}/g,
  decoration: (match, view, pos) => {
    return Decoration.replace({
      widget: new VariableWidget(
        match[1],
        view,
        pos + 2,
        pos + match[0].length - 1
      ),
    });
  },
});

const variableHighlighter: Extension = ViewPlugin.fromClass(
  class {
    decorations: DecorationSet;

    constructor(view: EditorView) {
      this.decorations = variableMatcher.createDeco(view);
    }

    update(update: ViewUpdate) {
      this.decorations = variableMatcher.updateDeco(update, this.decorations);
    }
  },
  {
    decorations: (instance) => instance.decorations,
    provide: (plugin) =>
      EditorView.atomicRanges.of((view) => {
        return view.plugin(plugin)?.decorations || Decoration.none;
      }),
  }
);

I have the impression that every time I add a character in the editor, the entire content is reprocessed because when I put a console.log(match) here:

decoration: (match, view, pos) => {
    console.log(match);
    return Decoration.replace({
      widget: new VariableWidget(
        match[1],
        view,
        pos + 2,
        pos + match[0].length - 1
      ),
    });
  }

All variables are displayed in the console.

By debugging a bit here:

update(update: ViewUpdate) {
      this.decorations = variableMatcher.updateDeco(update, this.decorations);
    }

We realize that the updateDeco of the MatchDecorator calls createDeco when viewportChanged is true (so always true when I add a character).

I therefore feel that this is what causes the slowdowns since everything is recreated with each new character addition. The most logical thing would be to update only the line that contains modifications, right?

I think I am missing an important point.
Thank you for your help.

No, you don’t seem to be missing anything—as it is, the update logic is rarely exercised, and MatchDecorator will fully rebuild on most edits. That wasn’t intentional, and apparently went unnoticed only because rebuilding isn’t typically very expensive. This patch should address it.

Great, thank you for making this change and for your quick response. I just tested it and it works perfectly like this.