模板语言
HTML 代码
html
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<title>Monaco Template Editor</title>
<style>
html,
body {
margin: 0;
padding: 0;
height: 100%;
overflow: hidden;
}
#container {
width: 100%;
height: 100vh;
}
</style>
</head>
<body>
<div id="container"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.53.0/min/vs/loader.min.js"></script>
<script>
require.config({
paths: { vs: "https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.45.0/min/vs" },
});
require(["vs/editor/editor.main"], function () {
const availableVariables = [
{ label: "userName", detail: "用户姓名", insertText: "userName" },
{ label: "company.name", detail: "公司名称", insertText: "company.name" },
{ label: "company.address", detail: "公司地址", insertText: "company.address" },
{ label: "order.id", detail: "订单ID", insertText: "order.id" },
];
const LANGUAGE_ID = "my-template-lang";
monaco.languages.register({ id: LANGUAGE_ID });
monaco.languages.setLanguageConfiguration(LANGUAGE_ID, {
autoClosingPairs: [
{ open: "{{", close: "}}" }, // 输入 {{ 自动补全 }}
{ open: "{", close: "}" }, // 输入 { 自动补全 }
{ open: '"', close: '"' },
{ open: "'", close: "'" },
],
});
monaco.languages.setMonarchTokensProvider(LANGUAGE_ID, {
tokenizer: {
root: [
[/\{\{/, { token: "delimiter.curly", next: "@expression" }],
[/[^\{]+/, "string"],
],
expression: [
[/[\w\.]+/, "variable.custom"],
[/\}\}/, { token: "delimiter.curly", next: "@pop" }],
[/\s+/, ""],
],
},
});
monaco.editor.defineTheme("my-template-theme", {
base: "vs-dark",
inherit: true,
rules: [
{ token: "variable.custom", foreground: "9CDCFE", fontStyle: "bold" },
{ token: "delimiter.curly", foreground: "C586C0" },
],
colors: {},
});
monaco.languages.registerCompletionItemProvider(LANGUAGE_ID, {
triggerCharacters: ["{", " ", "."], // 触发字符包含点号
provideCompletionItems: function (model, position) {
const textUntilPosition = model.getValueInRange({
startLineNumber: position.lineNumber,
startColumn: 1,
endLineNumber: position.lineNumber,
endColumn: position.column,
});
// 检测是否在 {{ }} 内
const match = textUntilPosition.match(/\{\{([^}]*)$/);
if (!match) {
return { suggestions: [] };
}
// 核心修复:手动计算当前正在输入的单词范围(包含点号)
// 匹配光标前连续的 字母、数字、下划线、点号
const wordMatch = textUntilPosition.match(/([a-zA-Z0-9_\.]+)$/);
let startColumn = position.column;
if (wordMatch) {
startColumn = position.column - wordMatch[0].length;
}
const range = {
startLineNumber: position.lineNumber,
endLineNumber: position.lineNumber,
startColumn: startColumn,
endColumn: position.column,
};
const suggestions = availableVariables.map((vari) => ({
label: vari.label,
kind: monaco.languages.CompletionItemKind.Variable,
detail: vari.detail,
insertText: vari.insertText,
range: range, // 使用手动计算的范围进行替换
}));
return { suggestions: suggestions };
},
});
monaco.editor.create(document.getElementById("container"), {
value: "输入 {{}}",
language: LANGUAGE_ID,
theme: "my-template-theme",
fontSize: 14,
});
});
</script>
</body>
</html>