The matchBrackets function within @codemirror/language is run via the bracketMatchingState StateField whenever the doc or selection changes.
The following flamegraph was generated using this basic sandbox, modified from the default sandbox to extend the doc to 2000 lines:
See no-throttling-export.json for the exported flamegraph.
As you can see from this flamegraph, the matchBrackets function can take a significant portion of the update cycle, taking 5.21ms out of the 7.39ms dispatch cycle (70.5%).
The effect is magnified when throttling CPU by 6x:
See 6x-throttling-export.json for the exported flamegraph.
Here, matchBrackets takes 24.17ms out of dispatch's 30.32ms (79.5%).
While investigating, I did find the maxScanDistance option, and tried setting that to a value much smaller than the default 10000. Unfortunately it appears that matchBrackets still takes a significant time to run. Here is another flamegraph generated using this modified sandbox which sets maxScanDistance to 100, and with CPU throttled by 6x:
See max-scan-distance-export.json for the exported flamegraph.
I can see that by itself, 5ms would not appear to cause a major performance problem, however we have found that this combined with our additional extensions does seem to cause "input lag", where input processing overflows into the next animation frame. We believe (and are confirming) that this occurs more commonly on lower end hardware.
Is it possible that the matchBrackets implementation could be optimised in some way? I've had a brief look at the code, and couldn't immediately come up with any suggestions.


