1
0
Fork 0
mirror of https://github.com/kou029w/quot.git synced 2025-01-19 08:28:09 +00:00
quot/app/syntax/indent-plugins.ts

80 lines
1.9 KiB
TypeScript
Raw Normal View History

2022-09-19 16:28:45 +09:00
import { indentWithTab } from "@codemirror/commands";
import { indentService, indentUnit, syntaxTree } from "@codemirror/language";
import {
type DecorationSet,
type EditorView,
type ViewUpdate,
Decoration,
ViewPlugin,
WidgetType,
keymap,
} from "@codemirror/view";
class IndentWidget extends WidgetType {
constructor(readonly bullet: boolean) {
super();
}
toDOM() {
const indent = document.createElement("span");
indent.textContent = this.bullet ? "•" : " ";
indent.style.paddingInline = "0.5em";
return indent;
}
}
function indentDecorations(view: EditorView) {
const decorations: Array<{
from: number;
to: number;
value: Decoration;
}> = [];
for (const { from, to } of view.visibleRanges) {
syntaxTree(view.state).iterate({
from,
to,
enter(node) {
if (node.name === "Indent") {
const next = view.state.doc.sliceString(node.to, node.to + 1);
const decoration = Decoration.widget({
widget: new IndentWidget(/^[^ \t]?$/.test(next)),
});
decorations.push(decoration.range(node.from));
}
},
});
}
return Decoration.set(decorations);
}
const indentDecorationsPlugin = ViewPlugin.fromClass(
class {
decorations: DecorationSet;
constructor(view: EditorView) {
this.decorations = indentDecorations(view);
}
update(update: ViewUpdate) {
if (update.docChanged || update.viewportChanged) {
this.decorations = indentDecorations(update.view);
}
}
},
{
decorations(v) {
return v.decorations;
},
}
);
const indentPlugins = [
keymap.of([indentWithTab]),
indentUnit.of(" "),
indentService.of((context, pos) => {
const previousLine = context.lineAt(pos, -1).text;
if (previousLine.trim() === "") return null;
return /^[ \t]*/.exec(previousLine)?.[0]?.length ?? null;
}),
indentDecorationsPlugin,
];
export default indentPlugins;