- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
我们是袋鼠云数栈 UED 团队,致力于打造优秀的一站式数据中台产品。我们始终保持工匠精神,探索前端道路,为社区积累并传播经验价值.
本文作者:修能 。
这是一段平平无奇的 SQL 语法 。
SELECT id, sum(name) FROM student GROUP BY id ORDER BY id;
如果把这段代码放到 monaco-editor(@0.49.0) 中,一切也显得非常普通.
monaco.editor.create(ref.current!, {
value: 'SELECT id, sum(name) FROM student GROUP BY id ORDER BY id;',
language: "SparkSQL",
});
效果如下:
接下来我们通过 monaco-editor 提供的一些 Language Services 来针对 SparkSQL 的语言进行优化.
本文旨在提供相关思路以及 Demo,不可将相关代码用于生产环境 。
const regex1 = /.../;
const regex2 = /.../;
const regex3 = /.../;
const regex4 = /.../;
// Register a new language
monaco.languages.register({ id: "SparkSQL" });
// Register a tokens provider for the language
monaco.languages.setMonarchTokensProvider("SparkSQL", {
tokenizer: {
root: [
[regex1, "keyword"],
[regex2, "comment"],
[regex3, "function"],
[regex4, "string"],
],
},
});
// Define a new theme that contains only rules that match this language
monaco.editor.defineTheme("myCoolTheme", {
base: "vs",
inherit: false,
rules: [
{ token: "keyword", foreground: "#0000ff" },
{ token: "function", foreground: "#795e26" },
{ token: "comment", foreground: "#008000" },
{ token: "string", foreground: "#a31515" },
],
colors: {
"editor.foreground": "#001080",
},
});
不知道各位有没有疑惑,为什么 monaco-editor 的高亮和 VSCode 的高亮不太一样? 为什么使用 Monarch 而不是 textmate 的原因?
通过 registerFoldingRangeProvider可以自定义实现一些折叠代码块的逻辑 。
monaco.languages.registerFoldingRangeProvider("SparkSQL", {
provideFoldingRanges: function (model) {
const ranges: monaco.languages.FoldingRange[] = [];
for (let i = 0; i < model.getLineCount(); ) {
const lineContent = model.getLineContent(i + 1);
const isValidLine = (content: string) =>
content && !content.trim().startsWith("--");
// 整段折叠
if (isValidLine(lineContent) && !isValidLine(model.getLineContent(i))) {
const start = i + 1;
let end = start;
while (end < model.getLineCount() && model.getLineContent(end + 1)) {
end++;
}
if (end <= model.getLineCount()) {
ranges.push({
start: start,
end: end,
kind: monaco.languages.FoldingRangeKind.Region,
});
}
}
i++;
}
return ranges;
},
});
PS:如果不设置的话,monaco-editor 会根据缩紧注册默认的折叠块逻辑 。
通过 registerCompletionItemProvider可以实现自定义补全代码 。
monaco.languages.registerCompletionItemProvider("SparkSQL", {
triggerCharacters: ["."],
provideCompletionItems: function (model, position) {
const word = model.getWordUntilPosition(position);
const range: monaco.IRange = {
startLineNumber: position.lineNumber,
endLineNumber: position.lineNumber,
startColumn: word.startColumn,
endColumn: word.endColumn,
};
const offset = model.getOffsetAt(position);
const prevIdentifier = model.getWordAtPosition(
model.getPositionAt(offset - 1)
);
if (prevIdentifier?.word) {
const regex = createRegExp(
exactly("CREATE TABLE ")
.and(exactly(`${prevIdentifier.word} `))
.and(exactly("("))
.and(oneOrMore(char).groupedAs("columns"))
.and(exactly(")"))
);
const match = model.getValue().match(regex);
if (match && match.groups.columns) {
const columns = match.groups.columns;
return {
suggestions: columns.split(",").map((item) => {
const [columnName, columnType] = item.trim().split(" ");
return {
label: `${columnName.trim()}(${columnType.trim()})`,
kind: monaco.languages.CompletionItemKind.Field,
documentation: `${columnName.trim()} ${columnType.trim()}`,
insertText: columnName.trim(),
range: range,
};
}),
};
}
}
return {
suggestions: createDependencyProposals(range),
};
},
});
通过 registerHoverProvider实现悬浮后提示相关信息 。
import * as monaco from "monaco-editor";
monaco.languages.registerHoverProvider("SparkSQL", {
provideHover: function (model, position) {
const word = model.getWordAtPosition(position);
if (!word) return null;
const fullText = model.getValue();
const offset = fullText.indexOf(`CREATE TABLE ${word.word}`);
if (offset !== -1) {
const lineNumber = model.getPositionAt(offset);
const lineContent = model.getLineContent(lineNumber.lineNumber);
return {
range: new monaco.Range(
position.lineNumber,
word.startColumn,
position.lineNumber,
word.endColumn
),
contents: [
{
value: lineContent,
},
],
};
}
},
});
通过 registerInlayHintsProvider可以实现插入提示代码 。
monaco.languages.registerInlayHintsProvider("SparkSQL", {
provideInlayHints(model, range) {
const hints: monaco.languages.InlayHint[] = [];
for (let i = range.startLineNumber; i <= range.endLineNumber; i++) {
const lineContent = model.getLineContent(i);
if (lineContent.includes("sum")) {
hints.push({
label: "expr: ",
position: {
lineNumber: i,
column: lineContent.indexOf("sum") + 5,
},
kind: monaco.languages.InlayHintKind.Parameter,
});
}
}
return {
hints: hints,
dispose: function () {},
};
},
});
跳转定义/引用是一对相辅相成的 API。如果实现了跳转定义而不实现跳转引用,会让用户感到困惑。 这里我们分别registerDefinitionProvider和 registerReferenceProvider两个 API 实现跳转定义和跳转引用.
monaco.languages.registerDefinitionProvider("SparkSQL", {
provideDefinition: function (model, position) {
const lineContent = model.getLineContent(position.lineNumber);
if (lineContent.startsWith("--")) return null;
const word = model.getWordAtPosition(position);
const fullText = model.getValue();
const offset = fullText.indexOf(`CREATE TABLE ${word?.word}`);
if (offset !== -1) {
const pos = model.getPositionAt(offset + 13);
return {
uri: model.uri,
range: new monaco.Range(
pos.lineNumber,
pos.column,
pos.lineNumber,
pos.column + word!.word.length
),
};
}
},
});
monaco.languages.registerReferenceProvider("SparkSQL", {
provideReferences: function (model, position) {
const lineContent = model.getLineContent(position.lineNumber);
if (!lineContent.startsWith("CREATE TABLE")) return null;
const word = model.getWordAtPosition(position);
if (word?.word) {
const regex = createRegExp(
exactly("SELECT").and(oneOrMore(char)).and(`FROM student`),
["g"]
);
const fullText = model.getValue();
const array1: monaco.languages.Location[] = [];
while (regex.exec(fullText) !== null) {
console.log("regex:", regex.lastIndex);
const pos = model.getPositionAt(regex.lastIndex);
array1.push({
uri: model.uri,
range: new monaco.Range(
pos.lineNumber,
model.getLineMinColumn(pos.lineNumber),
pos.lineNumber,
model.getLineMaxColumn(pos.lineNumber)
),
});
}
if (array1.length) return array1;
}
return null;
},
});
可以基于 CodeAction 实现如快速修复等功能.
monaco.languages.registerCodeActionProvider("SparkSQL", {
provideCodeActions: function (model, range, context) {
const actions: monaco.languages.CodeAction[] = [];
const diagnostics = context.markers;
diagnostics.forEach((marker) => {
if (marker.code === "no-function") {
actions.push({
title: "Correct function",
diagnostics: [marker],
kind: "quickfix",
edit: {
edits: [
{
resource: model.uri,
textEdit: {
range: marker,
text: "sum",
},
versionId: model.getVersionId(),
},
],
},
isPreferred: true,
});
}
});
return {
actions: actions,
dispose: function () {},
};
},
});
PS:需要配合 Markers 一起才能显示其效果 。
instance.onDidChangeModelContent(() => {
setModelMarkers(instance.getModel());
});
众所周知,在 monaco-editor 中,如果一段文本能匹配 http(s?):的话,会自动加上超链接的标识。而通过 registerLinkProvider这个 API,我们可以自定义一些文案进行超链接的跳跃.
monaco.languages.registerLinkProvider("SparkSQL", {
provideLinks: function (model) {
const links: monaco.languages.ILink[] = [];
const lines = model.getLinesContent();
lines.forEach((line, lineIndex) => {
const idx = line.toLowerCase().indexOf("sum");
if (line.startsWith("--") && idx !== -1) {
links.push({
range: new monaco.Range(
lineIndex + 1,
idx + 1,
lineIndex + 1,
idx + 4
),
url: "https://spark.apache.org/docs/latest/api/sql/#sum",
});
}
});
return {
links: links,
};
},
});
通过registerDocumentFormattingEditProviderAPI 可以实现文档格式化的功能.
import * as monaco from "monaco-editor";
monaco.languages.registerDocumentFormattingEditProvider("SparkSQL", {
provideDocumentFormattingEdits: function (model) {
const edits: monaco.languages.TextEdit[] = [];
const lines = model.getLinesContent();
lines.forEach((line, lineNumber) => {
const trimmedLine = line.trim();
if (trimmedLine.length > 0) {
const range = new monaco.Range(
lineNumber + 1,
1,
lineNumber + 1,
line.length + 1
);
edits.push({
range: range,
text: trimmedLine,
});
}
});
return edits;
},
});
除了上述提到的这些 Language Services 的功能以外,还有很多其他的语言服务功能可以实现。这里只是抛砖引玉来提到一些 API,还有一些 API 可以关注 monaco-editor 的官方文档 API.
欢迎关注【袋鼠云数栈UED团队】~ 袋鼠云数栈 UED 团队持续为广大开发者分享技术成果,相继参与开源了欢迎 star 。
最后此篇关于monaco-editor的LanguageServices的文章就讲到这里了,如果你想了解更多关于monaco-editor的LanguageServices的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我最近在浏览 https://github.com/ory/editor/blob/master/packages/ui/src/Trash/index.js#L89 发现了一种我不明白的论点。完整代
我已经在 D 中编程了一段时间 (http://www.digitalmars.com/d/)现在。比起 Java,我更喜欢它,因为它更快。但是,我还没有找到支持代码完成和调试(Step-Over、S
如何使用 Ace 编辑器执行以下操作。 用户输入“@”字符 弹出自动完成 用户从下拉列表中进行选择 既然已经做出选择,“@”就会被删除 我基本上希望 @ 作为自动完成的触发器,但我不希望它在之后徘徊。
您可以使用 monaco.languages.typescript.typescriptDefaults.addExtraLib 添加您在 TypeScript 解析期间可能需要的任何 *.d.ts
我们公司正在使用 swagger 来记录他们的 API,目前有几个开发人员正在他们的 PC 上使用在线 swagger 编辑器。 我想将这部分设计过程移到我们的标准开发环境中,该环境位于没有互联网访问
我正在 monaco-editor 中定义新语言.我希望它会自动突出显示匹配的括号和圆括号,因为默认情况下 matchBrackets选项是真的。 我还需要做些什么吗? 示例代码: 看 this pa
我正在尝试在我目前正在开发的项目中使用 Microsoft 的 Monaco Editor。我查看了文档,发现您可以使用自定义代码完成和语法突出显示来设置自定义语言,但我找不到任何关于如何向自定义语言
我非常喜欢 Notepad++ 中的一个功能,按 Alt并用鼠标选择启用矩形选择,就像桌面上的选择...想不出一个合适的术语,也许rectangular selection或 vertical sel
有没有办法将插入符号位置作为源代码字符串中的索引? 我知道我可以获得位置,它会给我一个包含行和列的对象,但是有没有办法获取或将行 + 列转换为字符串字符索引? 例如,如果我有: using Syste
我一直在用 Balsamiq创建模型。我使用的是试用版,所以我将所有屏幕都放在一个模型中,而不是多个文件中。我想将这些模型的导出发送给我的团队,以便他们可以对其进行评论。他们需要能够轻松地添加箭头、标
默认为 CRLF。我想在处理 BASH 脚本时将其更改为 LF。请帮忙。 我已经浏览了文档,但找不到任何解决方案或示例。 最佳答案 //https://github.com/Microsoft/vsc
将任何回调附加到 editor.onDidChangeModelContent(event) 到 Monaco 实例后,如何删除(或取消绑定(bind))此函数? 例如,ACE 编辑器提供了 func
我已经将编辑器设置为只读,它是只读的,但它显示了一个光标。我想以编程方式隐藏光标(除非以编程方式,否则不通过样式)。 最佳答案 以下是建议答案的作用,用于视觉比较: 这是以前的样子: 添加: edit
我有一个用例,用户单击按钮在当前光标位置插入文本。 但是在使用 session.insert(cursorPosition, textToAdd) 插入文本之后, 光标位置移动到第一个字符。 我尝试使
我正在使用 monaco-editor 库为自定义编程语言实现网络编辑器。 我已经实现了一个 CompletionItemProvider 来提供自定义完成建议。 总的来说效果很好。但是,在执行片段时
我正在使用 monaco-editor,我想包含来自多个文件的建议。我不确定最好的方法是什么,但基本上,我希望当我在 file2.js 中导出一些函数时,能够从建议中的另一个 file1.js 访问它
我正在为我的应用程序添加 TypeScript 支持 Data-Forge Notebook . 它是一个笔记本风格的 JavaScript 应用程序。当我在代码单元格中使用“等待”关键字时,摩纳哥将
Monaco Editor 中是否有用于文本选择的事件? 我需要响应用户在编辑器中选择部分代码? 有没有更好的解决方案来使用计时器来获取选择范围? 文件似乎没有提到它。 最佳答案 您可以使用 onDi
我正在使用 monaco-editor 来显示本地代码文件的内容,这些文件可能是用各种语言编写的,所以我想知道如何根据文件的扩展名或文件的第一行动态设置/更改 monaco 编辑器的语言没有扩展名(如
在 Monaco Editor 中,使用标准初始化,例如: monaco.editor.create(document.getElementById("container"), { value
我是一名优秀的程序员,十分优秀!