Skip to content

Instantly share code, notes, and snippets.

@lishid
Last active October 13, 2023 02:58
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lishid/c10db431cb8a9e83905a3443cfdb53bb to your computer and use it in GitHub Desktop.
Save lishid/c10db431cb8a9e83905a3443cfdb53bb to your computer and use it in GitHub Desktop.
CM6 Soft Wrapping
import { RangeSetBuilder } from '@codemirror/rangeset';
import { Decoration, DecorationSet, EditorView, ViewUpdate } from '@codemirror/view';
export class SoftWrapPlugin {
decorations: DecorationSet = Decoration.none;
indentSizeCache: Record<string, number> = {};
constructor(view: EditorView) {
this.buildDeco(view);
}
update(update: ViewUpdate) {
if (update.docChanged || update.viewportChanged || update.geometryChanged) {
this.buildDeco(update.view);
}
}
buildDeco(view: EditorView) {
let basePadding = 4;
let sizes = this.indentSizeCache;
let defaultWidth = view.defaultCharacterWidth;
let builder = new RangeSetBuilder<Decoration>();
let marks: Record<string, Decoration> = {};
let measurements: { text: string, pos: number }[] = [];
view.viewportLines(line => {
let lineObj = view.state.doc.lineAt(line.from);
let match = /^\s+/.exec(lineObj.text);
if (match && match[0]) {
let text = match[0];
let size = sizes[text];
if (!size) {
measurements.push({text, pos: line.from});
size = text.length * defaultWidth;
}
if (size > 0) {
let mark = marks[size] = marks[size] || Decoration.line({attributes: {style: `text-indent:${-size}px;padding-left:${basePadding + size}px`}});
builder.add(line.from, line.from, mark);
}
}
});
this.decorations = builder.finish();
view.requestMeasure({
read: (view) => {
for (let {text, pos} of measurements) {
sizes[text] = view.coordsAtPos(pos + text.length, -1).right - view.coordsAtPos(pos, 1).left;
}
},
write() {}
});
}
clearCache() {
this.indentSizeCache = {};
}
}
export let softWrap = ViewPlugin.define(view => new SoftWrapPlugin(view), { decorations: v => v.decorations });
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment