import { EditorView, Decoration } from '@codemirror/view'; import type { DecorationSet } from '@codemirror/view' import { StateEffect, StateField } from '@codemirror/state'; const addUnderline = StateEffect.define<{ from: number, to: number }>() const underlineField = StateField.define({ create() { return Decoration.none }, update(underlines, tr) { underlines = underlines.map(tr.changes) for (let e of tr.effects) if (e.is(addUnderline)) { underlines = underlines.update({ add: [underlineMark.range(e.value.from, e.value.from)], filter: (f, t, value) => { if (value.spec.class === 'cm-highlight') return false else return true }, }) } return underlines }, provide: f => EditorView.decorations.from(f) }) const underlineMark = Decoration.line({ class: "cm-highlight" }) const underlineTheme = EditorView.baseTheme({ ".cm-highlight": { background: "#333" } }) export default function highlight_active_line(Editor, loc) { if (!loc) return let activeLine for (let { from, to } of Editor.visibleRanges) { for (let pos = from; pos <= to;) { let line = Editor.state.doc.lineAt(pos) if (line.number === (loc.line) && line.from !== line.to) { activeLine = line break; } else { pos = line.to + 1 } } } if (activeLine) { highlightLine(Editor, activeLine); } function highlightLine(view: EditorView, line) { let effects: StateEffect[] = [addUnderline.of({ from: line.from, to: line.to })] if (!effects.length) return false if (!view.state.field(underlineField, false)) effects.push(StateEffect.appendConfig.of([underlineField, underlineTheme])) view.dispatch({ effects }) return true } }