push-f
February 22, 2023, 11:35am
1
I’d like to make newline characters (\n
) visible. I tried to adapt highlightWhitespace
as follows:
function matcher(decorator: MatchDecorator): Extension {
return ViewPlugin.define((view) => ({
decorations: decorator.createDeco(view),
update(u): void {
this.decorations = decorator.updateDeco(u, this.decorations);
},
}), {
decorations: (v) => v.decorations,
});
}
const newlineHighlighter = matcher(
new MatchDecorator({
regexp: /\n/g,
decoration: (match) => Decoration.mark({ class: 'cm-newline' }),
}),
);
However this doesn’t work … the documentation states for regexp
:
The regular expression to match against the content. Will only be matched inside lines (not across them). Should have its ‘g’ flag set.
I assume this doesn’t work because the newline isn’t considered to be part of the line? How could I make this work?
marijn
February 22, 2023, 11:54am
2
Indeed, line breaks aren’t part f the text. You could write an extension that adds a widget to every line except the last line to get something like this, I suppose.
push-f
February 22, 2023, 12:34pm
3
Ah ok thanks … using widget decorators indeed works
(sidenote: I tried using an empty mark decoration but apparently mark decorations cannot be empty … hence a widget decoration)
hungify
September 29, 2024, 6:43am
4
highlightNewLine extension
import type { DecorationSet, EditorView, ViewUpdate } from '@codemirror/view'
import { Decoration, ViewPlugin, WidgetType } from '@codemirror/view'
class NewlineWidget extends WidgetType {
toDOM() {
const span = document.createElement('span')
span.className = 'cm-newline'
span.textContent = '↵'
return span
}
}
function highlightNewLine() {
return ViewPlugin.fromClass(
class {
decorations: DecorationSet
constructor(view: EditorView) {
this.decorations = this.getDecorations(view)
}
getDecorations(view: EditorView) {
const widgets = []
for (const { from, to } of view.visibleRanges) {
for (let pos = from; pos <= to;) {
const line = view.state.doc.lineAt(pos)
if (line.length === 0) {
widgets.push(Decoration.widget({ widget: new NewlineWidget(), side: 1 }).range(pos))
}
else {
widgets.push(Decoration.widget({ widget: new NewlineWidget(), side: 1 }).range(line.to))
}
pos = line.to + 1
}
}
return Decoration.set(widgets, true)
}
update(update: ViewUpdate) {
if (update.docChanged || update.viewportChanged) {
this.decorations = this.getDecorations(update.view)
}
}
},
{
decorations: v => v.decorations,
},
)
}
export { highlightNewLine }
style
.cm-newline {
color: currentColor;
pointer-events: none;
opacity: 0.5;
}
2 Likes
Thanks @hungify , this is just what I needed!