I found this example: CodeMirror: Visible tabs demo but I think it features CodeMirror 5. How to code it myself with CodeMirror 6?
I want to do “visible spaces”, and I think I can edit “visible tabs” to spaces.
I found this example: CodeMirror: Visible tabs demo but I think it features CodeMirror 5. How to code it myself with CodeMirror 6?
I want to do “visible spaces”, and I think I can edit “visible tabs” to spaces.
@marijn Okay, I managed to create this ViewPlugin
based on their example:
const matchDecorator = new MatchDecorator({
regexp: /^ +/gm,
decoration: match => Decoration.mark({
attributes: {class: 'cm-highlightedSpaces', 'data-display': '·'.repeat(match[0].length)},
}),
boundary: /\S/,
});
const showAllWhitespace = ViewPlugin.define(
view => ({
decorations: matchDecorator.createDeco(view),
update(viewUpdate) {
this.decorations = matchDecorator.updateDeco(viewUpdate, this.decorations);
},
}),
{
decorations: view => view.decorations,
});
But I’m using markdown language, and I only want to run these decorations, when in CodeBlock
element. Where should add the check?
@marijn I implemented the same thing as before, but without MatchDecorator
, but by iterating of syntaxTree()
myself:
import {Decoration, ViewPlugin} from "@codemirror/view"
import {syntaxTree} from "@codemirror/language"
import {RangeSetBuilder} from "@codemirror/state";
const cachedDecorations = new Map();
function whitespaceDecoration(spaces) {
const cached = cachedDecorations.get(spaces);
if (cached) {
return cached;
}
const decoration = Decoration.mark({
attributes: {class: 'cm-visibleSpaces', 'data-spaces': '·'.repeat(spaces.length)},
});
cachedDecorations.set(spaces, decoration);
return decoration;
}
function decorations({view}) {
const builder = new RangeSetBuilder();
for (const {from, to} of view.visibleRanges) {
syntaxTree(view.state).iterate({
from, to,
enter: syntaxNode => {
if (syntaxNode.name === "FencedCode") {
const content = view.state.doc.sliceString(syntaxNode.from, syntaxNode.to);
const myRe = /^ +/gm;
let myArray;
while ((myArray = myRe.exec(content)) !== null) {
const offset = myArray.index;
const length = myArray[0].length;
builder.add(
syntaxNode.from + offset,
syntaxNode.from + offset + length,
whitespaceDecoration(myArray[0]));
}
}
}
})
}
return builder.finish();
}
export const visibleSpaces = ViewPlugin.define(view => ({view}), {decorations});
Which of these approaches would be better?
MatchDecorator
, isn’t that inefficient? I would image it probably does a global match..visibleRanges
, but has to parse the tree with syntaxTree()
.Which would be better?