update cv2

This commit is contained in:
2026-03-26 10:28:25 +01:00
parent d85405dd79
commit 2d2ba31923
7 changed files with 1198 additions and 1377 deletions

View File

@@ -24,7 +24,7 @@ export class ActionWidget extends WidgetType {
unmount(this.component);
}
const element = document.createElement("span");
element.style.paddingInline = "2px";
//element.style.paddingInline = "2px";
this.component = mount(Action, {
target: element,
@@ -43,6 +43,10 @@ export class ActionWidget extends WidgetType {
unmount(this.component);
}
}
override ignoreEvent() {
return false;
}
}
function actionWidgets(view: EditorView) {
@@ -51,13 +55,6 @@ function actionWidgets(view: EditorView) {
for (const chord of view.state.field(parsedChordsField).chords) {
if (chord.range[1] < from || chord.range[0] > to) continue;
iterActions(chord, (action) => {
if (
view.state.selection.ranges.some(
(r) => r.from <= action.range[1] && r.to > action.range[0],
)
) {
return;
}
if (action.info && action.explicit) {
const deco = Decoration.replace({
widget: new ActionWidget(action.info),

View File

@@ -4,104 +4,83 @@ import {
ViewPlugin,
ViewUpdate,
WidgetType,
type DecorationSet,
} from "@codemirror/view";
import { syntaxTree } from "@codemirror/language";
import type { Range } from "@codemirror/state";
import { mount, unmount } from "svelte";
import Action from "../components/Action.svelte";
import type { SyntaxNodeRef } from "@lezer/common";
import classNames from "./concatenator-button.module.scss";
export class DelimWidget extends WidgetType {
component?: {};
element?: HTMLElement;
constructor(readonly hasConcatenator: boolean) {
constructor() {
super();
}
override eq(other: DelimWidget) {
return this.hasConcatenator == other.hasConcatenator;
}
toDOM() {
if (!this.element) {
/*this.element = document.createElement("span");
this.element.innerHTML =
"&emsp;⇛" + (this.hasConcatenator ? "" : "&emsp;");
this.element.style.scale = "1.8";
this.element.style.color =
"color-mix(in srgb, currentColor 50%, transparent)";
if (this.hasConcatenator) {
const button = document.createElement("button");
button.className = classNames["concatenator-button"]!;
this.component = mount(Action, {
target: button,
props: { action: 574, display: "keys", inText: true, ghost: true },
});
this.element.appendChild(button);
}*/
this.element = document.createElement("div");
this.element.style.breakAfter = "column";
}
return this.element;
}
override ignoreEvent() {
return false;
}
override destroy() {
if (this.component) {
unmount(this.component);
}
const element = document.createElement("div");
element.style.breakAfter = "column";
return element;
}
}
function getJoinNode(
view: EditorView,
phraseDelimNode: SyntaxNodeRef,
): SyntaxNodeRef | null | undefined {
const firstPhraseAction = phraseDelimNode.node.nextSibling
?.getChild("ActionString")
?.node.firstChild?.node.getChild("ExplicitAction");
const idNode = firstPhraseAction?.node.getChild("ActionId");
const actionId = idNode
? view.state.doc.sliceString(idNode.from, idNode.to)
: null;
const isJoinAction =
actionId === "JOIN" &&
!!firstPhraseAction!.node.getChild("ExplicitDelimEnd");
return isJoinAction ? firstPhraseAction : null;
}
function actionWidgets(view: EditorView) {
const widgets: Range<Decoration>[] = [];
function delimWidgets(view: EditorView): {
delims: DecorationSet;
surrounding: DecorationSet;
} {
const delims: Range<Decoration>[] = [];
const surrounding: Range<Decoration>[] = [];
for (const { from, to } of view.visibleRanges) {
let chord: { from: number; to: number } | null = null;
syntaxTree(view.state).iterate({
from,
to,
enter: (node) => {
if (node.name !== "PhraseDelim") return;
const joinNode = getJoinNode(view, node);
console.log(node.name, node.from, node.to);
if (node.name === "Chord") {
chord = { from: node.from, to: node.to };
}
if (node.name !== "PhraseDelim" || chord === null) return;
let deco = Decoration.replace({
widget: new DelimWidget(!joinNode),
});
widgets.push(deco.range(node.from, node.to));
delims.push(
Decoration.mark({
class: "chord-delim",
}).range(node.from, node.to),
);
if (chord.from < node.from) {
surrounding.push(
Decoration.mark({
tagName: "div",
class: "chord-input",
}).range(chord.from, node.from),
);
}
if (chord.to > node.to) {
surrounding.push(
Decoration.mark({
tagName: "div",
class: "chord-phrase",
}).range(node.to, chord.to),
);
}
chord = null;
},
});
}
return Decoration.set(widgets);
return {
delims: Decoration.set(delims),
surrounding: Decoration.set([...surrounding, ...delims], true),
};
}
export const delimPlugin = ViewPlugin.fromClass(
class {
decorations = Decoration.none;
delims = Decoration.none;
surrounding = Decoration.none;
constructor(view: EditorView) {
this.decorations = actionWidgets(view);
const { delims, surrounding } = delimWidgets(view);
this.delims = delims;
this.surrounding = surrounding;
}
update(update: ViewUpdate) {
@@ -109,51 +88,21 @@ export const delimPlugin = ViewPlugin.fromClass(
update.docChanged ||
update.viewportChanged ||
syntaxTree(update.startState) != syntaxTree(update.state)
)
this.decorations = actionWidgets(update.view);
) {
const { delims, surrounding } = delimWidgets(update.view);
this.delims = delims;
this.surrounding = surrounding;
}
}
},
{
decorations(instance) {
return instance.decorations;
return instance.delims;
},
provide(plugin) {
return EditorView.atomicRanges.of(
(view) => view.plugin(plugin)?.decorations ?? Decoration.none,
(view) => view.plugin(plugin)?.delims ?? Decoration.none,
);
},
eventHandlers: {
click: (event, view) => {
if (!(event.target instanceof HTMLElement)) return;
if (
!(
event.target instanceof HTMLButtonElement ||
(event.target as HTMLElement).parentElement instanceof
HTMLButtonElement
)
)
return;
const chordNode = syntaxTree(view.state).resolve(
view.posAtDOM(event.target),
);
const delimNode = (
chordNode.name === "ActionString"
? chordNode.parent?.parent
: chordNode
)?.getChild("PhraseDelim");
if (!delimNode) return;
const joinNode = getJoinNode(view, delimNode);
if (!event.target.checked && !joinNode) {
view.dispatch({
changes: {
from: delimNode.to,
insert: "<JOIN>",
},
selection: { anchor: delimNode.to + "<JOIN>".length },
});
}
},
},
},
);

View File

@@ -51,10 +51,9 @@ export function createConfig(params: EditorConfig) {
actionHover,
changesPanel(),
lintGutter(),
params.rawCode ? [lineNumbers()] : [delimPlugin, actionPlugin],
params.rawCode ? [lineNumbers()] : [/*delimPlugin,*/ actionPlugin],
chordLanguageSupport(),
actionLinter({
delay: 100,
markerFilter(diagnostics) {
return diagnostics.filter((it) => it.from !== it.to);
},