先附上官网地址你们会用到,里面有大量API功能非常丰富,本文中所用到的API里面都会提及。
MonacoEditor.
这里并不一定这样,引入的方式有很多,也可直接使用monaco-editor引入。
// An highlighted block
import loader from "@monaco-editor/loader";
loader.config({
paths: {
vs: "https://g.alicdn.com/code/lib/monaco-editor/0.31.1/min/vs"
}
});
return new Promise((resolve, inject) => {
loader
.init()
.then(monaco => {
// 兼容旧版本 monaco-editor 写死 MonacoEnvironment 的问题
window.MonacoEnvironment = undefined;
if (typeof window.define === "function" && window.define.amd) {
// make monaco-editor's loader work with webpack's umd loader
// @see https://github.com/microsoft/monaco-editor/issues/2283
delete window.define.amd;
}
resolve({
code: 1,
monaco
});
})
.catch(err => {
inject({
code: 0,
err
});
});
});
我们这里自定义一个customjava的语言,他是要基于java语言的
//monaco 为引入的monaco
this.monaco = monaco;
//在这里我们注册了customjava的预览类型
this.monaco.languages.register({ id: "customjava" });
//customTokenProvider 为customjava预览的配置,包括关键字高亮等信息
//你可以在文章结尾处获得customTokenProvider详细配置
this.monaco.languages.setMonarchTokensProvider("customjava",customTokenProvider);
// 注册主题
//你可以在文章结尾处获得customTheme主题配置,其中自定义了三中类型
this.monaco.editor.defineTheme("customTheme", customTheme);
// 注册语言配置,设置customjava的一些快捷操作
//文章结尾处获取该方法customLanguageConfiguration
this.monaco.languages.setLanguageConfiguration(
"customjava",
customLanguageConfiguration(this.monaco)
);
//customjava代码格式化问题,这里使用了groovyBeautify 他是npm里第三方格式化java代码的插件库
monaco.languages.registerDocumentFormattingEditProvider("customjava", {
provideDocumentFormattingEdits: function(model, options, token) {
var formattedCode = groovyBeautify(model.getValue());
return [
{
range: model.getFullModelRange(),
text: formattedCode
}
];
}
});
//customjava代码提示问题
//这里使用了registerCompletionItemProvider
this.languages = monaco.languages.registerCompletionItemProvider(
"customjava",
{
provideCompletionItems: () => {
let suggestions = [];
suggestions.push({
label: 提示信息,
//插入文本的方式,具体可以console monaco.languages.CompletionItemKind
kind: monaco.languages.CompletionItemKind[],
insertText: 插入的文本,
documentation: 插入的详情
});
return {
suggestions: suggestions
};
}
}
this.monacoSqlEditor = monaco.editor.create(this.$refs.sqlContainer, {
value: "",
language:"customjava",
contextmenu: true,
automaticLayout: true,
fontSize: 16,
theme: "customTheme",
inherit: true,
minimap: {
enabled: true
}
});
decorations: [],
//鼠标移入左侧时开始打断点
this.monacoSqlEditor.onMouseMove(e => {
this.removeFakeBreakPoint();
if (
e.target.detail &&
e.target.detail.offsetX &&
e.target.detail.offsetX >= 0 &&
e.target.detail.offsetX <= 40
) {
let line = e.target.position.lineNumber;
let lineContent = this.monacoSqlEditor
.getModel()
.getLineContent(line)
.trim();
if (lineContent) {
this.addFakeBreakPoint(line);
}
}
});
this.monacoSqlEditor.onMouseDown(e => {
if (
e.target.detail &&
e.target.detail.offsetX &&
e.target.detail.offsetX >= 0 &&
e.target.detail.offsetX <= 40
) {
let line = e.target.position.lineNumber;
let lineContent = this.monacoSqlEditor
.getModel()
.getLineContent(line)
.trim();
if (lineContent) {
if (!this.hasBreakPoint(line)) {
this.addBreakPoint(line);
} else {
this.removeBreakPoint(line);
}
this.getBreakpoint();
}
}
});
getBreakpoint() {
let breakpointLines = [];
if (this.monacoSqlEditor) {
let decorations = this.monacoSqlEditor.getModel().getAllDecorations();
let ids = [];
for (let decoration of decorations) {
if (
decoration.options.linesDecorationsClassName === "breakpoints-code"
) {
breakpointLines.push(decoration.range.startLineNumber);
}
}
}
},
removeFakeBreakPoint() {
let model = this.monacoSqlEditor.getModel();
this.decorations = model.deltaDecorations(this.decorations, []);
},
addFakeBreakPoint(line) {
let model = this.monacoSqlEditor.getModel();
if (this.hasBreakPoint(line)) return;
let value = {
range: new window.monaco.Range(line, 1, line, 1),
options: {
isWholeLine: true,
linesDecorationsClassName: "breakpoints-fake-code"
}
};
this.decorations = model.deltaDecorations(this.decorations, [value]);
},
hasBreakPoint(line) {
let decorations = this.monacoSqlEditor.getLineDecorations(line);
for (let decoration of decorations) {
if (
decoration.options.linesDecorationsClassName === "breakpoints-code"
) {
return true;
}
}
return false;
},
async addBreakPoint(line) {
let model = this.monacoSqlEditor.getModel();
if (!model) return;
let value = [
{
range: new window.monaco.Range(line, 1, line, 1),
options: {
isWholeLine: true,
linesDecorationsClassName: "breakpoints-code"
}
},
{
range: new window.monaco.Range(line, null, line, null),
options: {
isWholeLine: true,
className: "debug-line-color"
}
}
];
model.deltaDecorations([], value);
},
async removeBreakPoint(line) {
let model = this.monacoSqlEditor.getModel();
if (!model) return;
let decorations;
let ids = [];
if (line !== undefined) {
decorations = this.monacoSqlEditor.getLineDecorations(line);
} else {
decorations = this.monacoSqlEditor.getModel().getAllDecorations();
}
for (let decoration of decorations) {
if (decoration.options.className === "debug-line-color") {
ids.push(decoration.id);
}
if (
decoration.options.linesDecorationsClassName === "breakpoints-code"
) {
ids.push(decoration.id);
}
}
if (ids && ids.length) {
model.deltaDecorations(ids, []);
}
},
这里提供一种思路,因为语法检查需要在后台完成,前端可以不断通过socket向后端发送信息,后端校验后返回给前端结果,第几行第几列某个字段报错。
const customTokenProvider = {
defaultToken: "",
tokenPostfix: ".java",
keywords: [
"abstract",
"assert",
"goto",
"package",
"synchronized",
"boolean",
"private",
"this",
"double",
"implements",
"protected",
"throw",
"byte",
"import",
"public",
"throws",
"enum",
"instanceof",
"transient",
"extends",
"int",
"short",
"char",
"final",
"interface",
"static",
"void",
"class",
"finally",
"long",
"strictfp",
"volatile",
"const",
"float",
"native",
"super",
"true",
"false",
"def",
"null"
],
keywordsControl: [
"try",
"catch",
"return",
"new",
"break",
"case",
"else",
"if",
"switch",
"for",
"while",
"do",
"default",
"continue"
],
operators: [
"=",
">",
"<",
"!",
"~",
"?",
":",
"==",
"<=",
">=",
"!=",
"&&",
"||",
"++",
"--",
"+",
"-",
"*",
"/",
"&",
"|",
"^",
"%",
"<<",
">>",
">>>",
"+=",
"-=",
"*=",
"/=",
"&=",
"|=",
"^=",
"%=",
"<<=",
">>=",
">>>="
],
// typeKeywords: [
// "aaa",
// ],
// we include these common regular expressions
symbols: /[=>/,
escapes: /\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,
digits: /\d+(_+\d+)*/,
octaldigits: /[0-7]+(_+[0-7]+)*/,
binarydigits: /[0-1]+(_+[0-1]+)*/,
hexdigits: /[[0-9a-fA-F]+(_+[0-9a-fA-F]+)*/,
// keywordsss: ["error", "info", "warning"],
// The main tokenizer for our languages
tokenizer: {
root: [
// Special keyword with a dash
[
/[A-Z][a-z|0-9|\u4e00-\u9fa5|@|_|-]*/,
{
token: "custom-variable"
}
],
[
/[a-zA-Z_$][\w$]*/,
{
cases: {
"@keywords": { token: "keyword.$0" },
"@keywordsControl": { token: "custom-keywords" },
"@default": "identifier"
}
}
],
{ include: "@whitespace" },
// delimiters and operators
[/[{}()\[\]]/, "@brackets"],
[/[<>](?!@symbols)/, "@brackets"],
[
/@symbols/,
{
cases: {
"@operators": "delimiter",
"@default": ""
}
}
],
// @ annotations.
[/@\s*[a-zA-Z_\$][\w\$]*/, "annotation"],
// numbers
[/(@digits)[eE]([\-+]?(@digits))?[fFdD]?/, "number.float"],
[/(@digits)\.(@digits)([eE][\-+]?(@digits))?[fFdD]?/, "number.float"],
[/0[xX](@hexdigits)[Ll]?/, "number.hex"],
[/0(@octaldigits)[Ll]?/, "number.octal"],
[/0[bB](@binarydigits)[Ll]?/, "number.binary"],
[/(@digits)[fFdD]/, "number.float"],
[/(@digits)[lL]?/, "number"],
// delimiter: after number because of .\d floats
[/[;,.]/, "delimiter"],
// strings
[/"([^"\\]|\\.)*$/, "string.invalid"], // non-teminated string
[/"/, "string", "@string"],
// characters
[/'[^\\']'/, "string"],
[/(')(@escapes)(')/, ["string", "string.escape", "string"]],
[/'/, "string.invalid"]
],
// text: [
// [/^@header/, { token: "@rematch", next: "@pop" }],
// [/.*/, { token: "custom-$S2" }]
// ],
whitespace: [
[/[ \t\r\n]+/, ""],
[/\/\*\*(?!\/)/, "comment.doc", "@javadoc"],
[/\/\*/, "comment", "@comment"],
// [/\/\/.*$/, "custom-note"]
[/\/\/.*$/, "comment"]
],
comment: [
[/[^\/*]+/, "comment"],
// [/\/\*/, 'comment', '@push' ], // nested comment not allowed :-(
// [/\/\*/, 'comment.invalid' ], // this breaks block comments in the shape of /* //*/
[/\*\//, "comment", "@pop"],
[/[\/*]/, "comment"]
],
//Identical copy of comment above, except for the addition of .doc
javadoc: [
[/[^\/*]+/, "comment.doc"],
// [/\/\*/, 'comment.doc', '@push' ], // nested comment not allowed :-(
[/\/\*/, "comment.doc.invalid"],
[/\*\//, "comment.doc", "@pop"],
[/[\/*]/, "comment.doc"]
],
string: [
[/[^\\"]+/, "string"],
[/@escapes/, "string.escape"],
[/\\./, "string.escape.invalid"],
[/"/, "string", "@pop"]
]
// javaVariabel:[
// [/def+/, "variabel"],
// ]
}
}
const customTheme = {
base: "vs-dark", // 要继承的基础主题,即内置的三个:vs、vs-dark、hc-black
inherit: true, // 是否继承
rules: [
{ token: "custom-variable", foreground: "4ec9b0" },
{ token: "custom-keywords", foreground: "c586c0" },
{ token: "custom-note", foreground: "6a9955" }
],
colors: {
"editor.background": '#151414'
}
}
const customLanguageConfiguration = monaco => {
return {
wordPattern: /(-?\d*\.\d\w*)|([^\`\~\!\#\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g,
comments: {
lineComment: "//",
blockComment: ["/*", "*/"]
},
brackets: [
["{", "}"],
["[", "]"],
["(", ")"]
],
onEnterRules: [
{
// e.g. /** | */
beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/,
afterText: /^\s*\*\/$/,
action: {
indentAction: monaco.languages.IndentAction.IndentOutdent,
appendText: " * "
}
},
{
// e.g. /** ...|
beforeText: /^\s*\/\*\*(?!\/)([^\*]|\*(?!\/))*$/,
action: {
indentAction: monaco.languages.IndentAction.None,
appendText: " * "
}
},
{
// e.g. * ...|
beforeText: /^(\t|(\ \ ))*\ \*(\ ([^\*]|\*(?!\/))*)?$/,
action: {
indentAction: monaco.languages.IndentAction.None,
appendText: "* "
}
},
{
// e.g. */|
beforeText: /^(\t|(\ \ ))*\ \*\/\s*$/,
action: {
indentAction: monaco.languages.IndentAction.None,
removeText: 1
}
}
],
autoClosingPairs: [
{ open: "{", close: "}" },
{ open: "[", close: "]" },
{ open: "(", close: ")" },
{ open: '"', close: '"' },
{ open: "'", close: "'" },
{ open: "<", close: ">" },
{ open: "`", close: "`", notIn: ["string", "comment"] },
{ open: "/**", close: " */", notIn: ["string"] }
],
surroundingPairs: [
{ open: "{", close: "}" },
{ open: "[", close: "]" },
{ open: "(", close: ")" },
{ open: '"', close: '"' },
{ open: "'", close: "'" },
{ open: "<", close: ">" }
],
folding: {
markers: {
start: new RegExp("^\\s*//\\s*(?:(?:#?region\\b)|(?:),
end: new RegExp("^\\s*//\\s*(?:(?:#?endregion\\b)|(?: ))")
}
}
};
}