Working on Formating DSL completion

This commit is contained in:
2026-01-31 19:09:14 +01:00
parent 778e5ac69d
commit d7ec99c3d9
77 changed files with 7563 additions and 63 deletions

View File

@@ -2114,6 +2114,175 @@ function moveColumn(table, sourceColId, targetColId) {
}, ANIMATION_DURATION);
}
/**
* Initialize DslEditor with CodeMirror 5
*
* Features:
* - DSL-based autocompletion
* - Line numbers
* - Readonly support
* - Placeholder support
* - Textarea synchronization
* - Debounced HTMX server update via updateCommandId
*
* Required CodeMirror addons:
* - addon/hint/show-hint.js
* - addon/hint/show-hint.css
* - addon/display/placeholder.js
*
* Requires:
* - htmx loaded globally
*
* @param {Object} config
*/
function initDslEditor(config) {
const {
elementId,
textareaId,
lineNumbers,
autocompletion,
placeholder,
readonly,
updateCommandId,
dsl
} = config;
const wrapper = document.getElementById(elementId);
const textarea = document.getElementById(textareaId);
const editorContainer = document.getElementById(`cm_${elementId}`);
if (!wrapper || !textarea || !editorContainer) {
console.error(`DslEditor: Missing elements for ${elementId}`);
return;
}
if (typeof CodeMirror === "undefined") {
console.error("DslEditor: CodeMirror 5 not loaded");
return;
}
/* --------------------------------------------------
* Build completion list from DSL config
* -------------------------------------------------- */
const completionItems = [];
if (dsl && dsl.completions) {
const pushAll = (items) => {
if (!Array.isArray(items)) return;
items.forEach(item => completionItems.push(item));
};
pushAll(dsl.completions.keywords);
pushAll(dsl.completions.operators);
pushAll(dsl.completions.functions);
pushAll(dsl.completions.types);
pushAll(dsl.completions.literals);
}
/* --------------------------------------------------
* DSL autocompletion hint
* -------------------------------------------------- */
function dslHint(cm) {
const cursor = cm.getCursor();
const line = cm.getLine(cursor.line);
const ch = cursor.ch;
let start = ch;
while (start > 0 && /\w/.test(line.charAt(start - 1))) {
start--;
}
const word = line.slice(start, ch);
const matches = completionItems.filter(item =>
item.startsWith(word)
);
return {
list: matches,
from: CodeMirror.Pos(cursor.line, start),
to: CodeMirror.Pos(cursor.line, ch)
};
}
/* --------------------------------------------------
* Create CodeMirror editor
* -------------------------------------------------- */
const editor = CodeMirror(editorContainer, {
value: textarea.value || "",
lineNumbers: !!lineNumbers,
readOnly: !!readonly,
placeholder: placeholder || "",
extraKeys: autocompletion ? {
"Ctrl-Space": "autocomplete"
} : {},
hintOptions: autocompletion ? {
hint: dslHint,
completeSingle: false
} : undefined
});
/* --------------------------------------------------
* Debounced update + HTMX transport
* -------------------------------------------------- */
let debounceTimer = null;
const DEBOUNCE_DELAY = 300;
editor.on("change", function (cm) {
const value = cm.getValue();
textarea.value = value;
if (!updateCommandId) return;
clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => {
wrapper.dispatchEvent(
new CustomEvent("dsl-editor-update", {
detail: {
commandId: updateCommandId,
value: value
}
})
);
}, DEBOUNCE_DELAY);
});
/* --------------------------------------------------
* HTMX listener (LOCAL to wrapper)
* -------------------------------------------------- */
if (updateCommandId && typeof htmx !== "undefined") {
wrapper.addEventListener("dsl-editor-update", function (e) {
htmx.ajax("POST", "/myfasthtml/commands", {
target: wrapper,
swap: "none",
values: {
c_id: e.detail.commandId,
content: e.detail.value
}
});
});
}
/* --------------------------------------------------
* Public API
* -------------------------------------------------- */
wrapper._dslEditor = {
editor: editor,
getContent: () => editor.getValue(),
setContent: (content) => editor.setValue(content)
};
console.debug(`DslEditor initialized (CM5 + HTMX): ${elementId} with ${dsl?.name || "DSL"}`);
}
function updateDatagridSelection(datagridId) {
const selectionManager = document.getElementById(`tsm_${datagridId}`);
if (!selectionManager) return;