mirror of
https://github.com/CharaChorder/DeviceManager.git
synced 2026-01-19 08:22:53 +00:00
106 lines
2.5 KiB
TypeScript
106 lines
2.5 KiB
TypeScript
import {
|
|
Decoration,
|
|
EditorView,
|
|
ViewPlugin,
|
|
ViewUpdate,
|
|
WidgetType,
|
|
} from "@codemirror/view";
|
|
import { mount, unmount } from "svelte";
|
|
import Action from "$lib/components/Action.svelte";
|
|
import { syntaxTree } from "@codemirror/language";
|
|
import type { Range } from "@codemirror/state";
|
|
|
|
export class ActionWidget extends WidgetType {
|
|
component?: {};
|
|
|
|
constructor(readonly id: string | number) {
|
|
super();
|
|
this.id = id;
|
|
}
|
|
|
|
/*override eq(other: ActionWidget) {
|
|
return this.id == other.id;
|
|
}*/
|
|
|
|
toDOM() {
|
|
if (this.component) {
|
|
unmount(this.component);
|
|
}
|
|
const element = document.createElement("span");
|
|
element.style.paddingInline = "2px";
|
|
|
|
this.component = mount(Action, {
|
|
target: element,
|
|
props: { action: this.id, display: "keys", inText: true },
|
|
});
|
|
return element;
|
|
}
|
|
|
|
override ignoreEvent() {
|
|
return true;
|
|
}
|
|
|
|
override destroy() {
|
|
if (this.component) {
|
|
unmount(this.component);
|
|
}
|
|
}
|
|
}
|
|
|
|
function actionWidgets(view: EditorView) {
|
|
const widgets: Range<Decoration>[] = [];
|
|
for (const { from, to } of view.visibleRanges) {
|
|
syntaxTree(view.state).iterate({
|
|
from,
|
|
to,
|
|
enter: (node) => {
|
|
if (node.name !== "ExplicitAction") return;
|
|
const value =
|
|
node.node.getChild("ActionId") ?? node.node.getChild("HexNumber");
|
|
if (!value) return;
|
|
if (!node.node.getChild("ExplicitDelimEnd")) {
|
|
return;
|
|
}
|
|
const id = view.state.doc.sliceString(value.from, value.to);
|
|
if (value.name === "HexNumber" && id.length === 10) return;
|
|
let deco = Decoration.replace({
|
|
widget: new ActionWidget(
|
|
value.name === "ActionId" ? id : Number.parseInt(id, 16),
|
|
),
|
|
});
|
|
widgets.push(deco.range(node.from, node.to));
|
|
},
|
|
});
|
|
}
|
|
return Decoration.set(widgets);
|
|
}
|
|
|
|
export const actionPlugin = ViewPlugin.fromClass(
|
|
class {
|
|
decorations = Decoration.none;
|
|
|
|
constructor(view: EditorView) {
|
|
this.decorations = actionWidgets(view);
|
|
}
|
|
|
|
update(update: ViewUpdate) {
|
|
if (
|
|
update.docChanged ||
|
|
update.viewportChanged ||
|
|
syntaxTree(update.startState) != syntaxTree(update.state)
|
|
)
|
|
this.decorations = actionWidgets(update.view);
|
|
}
|
|
},
|
|
{
|
|
decorations(instance) {
|
|
return instance.decorations;
|
|
},
|
|
provide(plugin) {
|
|
return EditorView.atomicRanges.of(
|
|
(view) => view.plugin(plugin)?.decorations ?? Decoration.none,
|
|
);
|
|
},
|
|
},
|
|
);
|