147 lines
3.7 KiB
JavaScript
147 lines
3.7 KiB
JavaScript
export class MonacoEditorAdapter {
|
|
constructor(hostElement) {
|
|
this.hostElement = hostElement;
|
|
this.editor = null;
|
|
this.model = null;
|
|
this.changeHandler = null;
|
|
this.suppressChange = false;
|
|
this.readOnly = true;
|
|
}
|
|
|
|
async init() {
|
|
const monaco = await this.#loadMonaco();
|
|
if (!monaco || !this.hostElement) return false;
|
|
|
|
this.#defineTheme(monaco);
|
|
this.model = monaco.editor.createModel("", "plaintext");
|
|
this.editor = monaco.editor.create(this.hostElement, {
|
|
model: this.model,
|
|
theme: "app-dark-blue",
|
|
automaticLayout: true,
|
|
readOnly: this.readOnly,
|
|
minimap: { enabled: false },
|
|
scrollBeyondLastLine: false,
|
|
fontSize: 14,
|
|
fontFamily: "IBM Plex Mono, Consolas, monospace",
|
|
tabSize: 2
|
|
});
|
|
|
|
this.model.onDidChangeContent(() => {
|
|
if (this.suppressChange || !this.changeHandler) return;
|
|
this.changeHandler(this.model.getValue());
|
|
});
|
|
|
|
return true;
|
|
}
|
|
|
|
onChange(handler) {
|
|
this.changeHandler = handler;
|
|
}
|
|
|
|
setReadOnly(readOnly) {
|
|
this.readOnly = Boolean(readOnly);
|
|
if (!this.editor) return;
|
|
this.editor.updateOptions({ readOnly: this.readOnly });
|
|
}
|
|
|
|
setValue(text) {
|
|
if (!this.model) return;
|
|
const next = text || "";
|
|
if (this.model.getValue() === next) return;
|
|
this.suppressChange = true;
|
|
this.model.pushEditOperations(
|
|
[],
|
|
[{ range: this.model.getFullModelRange(), text: next }],
|
|
() => null
|
|
);
|
|
this.model.pushStackElement();
|
|
this.suppressChange = false;
|
|
}
|
|
|
|
setLanguageByPath(path) {
|
|
if (!this.model || !window.monaco?.editor) return;
|
|
window.monaco.editor.setModelLanguage(this.model, this.#detectLanguage(path));
|
|
}
|
|
|
|
focus() {
|
|
if (this.editor) this.editor.focus();
|
|
}
|
|
|
|
layout() {
|
|
if (this.editor) this.editor.layout();
|
|
}
|
|
|
|
async #loadMonaco() {
|
|
if (window.monaco?.editor) return window.monaco;
|
|
if (typeof window.require !== "function") return null;
|
|
if (window.__monacoPromise) return window.__monacoPromise;
|
|
|
|
window.__monacoPromise = new Promise((resolve, reject) => {
|
|
window.require.config({
|
|
paths: {
|
|
vs: "https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.52.2/min/vs"
|
|
}
|
|
});
|
|
window.require(["vs/editor/editor.main"], () => resolve(window.monaco), reject);
|
|
});
|
|
|
|
return window.__monacoPromise;
|
|
}
|
|
|
|
#defineTheme(monaco) {
|
|
monaco.editor.defineTheme("app-dark-blue", {
|
|
base: "vs-dark",
|
|
inherit: true,
|
|
rules: [
|
|
{ token: "comment", foreground: "7f9bbf" },
|
|
{ token: "keyword", foreground: "8cc8ff" },
|
|
{ token: "string", foreground: "a7d98f" }
|
|
],
|
|
colors: {
|
|
"editor.background": "#0b1830",
|
|
"editor.foreground": "#dce9ff",
|
|
"editorLineNumber.foreground": "#5e79a2",
|
|
"editorLineNumber.activeForeground": "#a7c3eb",
|
|
"editor.selectionBackground": "#274f8677",
|
|
"editor.inactiveSelectionBackground": "#274f8644",
|
|
"editorCursor.foreground": "#4fa0ff"
|
|
}
|
|
});
|
|
}
|
|
|
|
#detectLanguage(path) {
|
|
const ext = (path || "").split(".").pop()?.toLowerCase();
|
|
switch (ext) {
|
|
case "js":
|
|
case "mjs":
|
|
case "cjs":
|
|
return "javascript";
|
|
case "ts":
|
|
return "typescript";
|
|
case "json":
|
|
return "json";
|
|
case "md":
|
|
case "markdown":
|
|
return "markdown";
|
|
case "yml":
|
|
case "yaml":
|
|
return "yaml";
|
|
case "xml":
|
|
return "xml";
|
|
case "html":
|
|
return "html";
|
|
case "css":
|
|
return "css";
|
|
case "sh":
|
|
case "bash":
|
|
return "shell";
|
|
case "py":
|
|
return "python";
|
|
case "toml":
|
|
return "ini";
|
|
default:
|
|
return "plaintext";
|
|
}
|
|
}
|
|
}
|