巨无敌大坑:设置的文本提示项有range字段时,光标必须在range范围内,提示才会正常显示
<template>
<div class="container1" v-loading="loading" element-loading-text="资源加载中...">
<div>
<el-button size="mini" @click="formatContent">格式化</el-button>
</div>
<div ref="codeContainer" style="height: calc( 100vh - 300px )" id="container"/>
<div v-for="(item, index) in errorMsg" :key="index">{{item}}</div>
<div v-if="false">
<i class="el-icon-star-off"></i>g4Tokens
<pre><code>{{g4Tokens}}</code></pre>
<i class="el-icon-tsar-off"></i>g4Data
<pre><code>{{g4Data}}</code></pre>
<i class="el-icon-star-off"></i>contentBasicLexer
<pre><code>{{contentBasicLexer}}</code></pre>
<i class="el-icon-star-off"></i>contentBasicParser
<pre><code>{{contentBasicParser}}</code></pre>
</div>
</div>
</template>
<script>
var antlr4 = require('antlr4').default;
import * as monaco from "monaco-editor/esm/vs/editor/editor.api"
import * as c3 from "./antlr4C3/index.ts";
import { selectReturnMacheFunction } from "@/api/rule/function"
import { readResource } from "@/api/rule/resource"
import { selectModelList } from "@/api/rule/model"
import { selectVariableDetail } from "@/api/rule/variable"
import { expressionList } from "@/assets/data/expressionList.js"
import {antiShaking} from "@/utils/antiShakingThrottle"
export default {
props: {
ruleData: {},
entranceG4: {
type: String,
default: 'ruleStatement'
},
// 用于向父组件传递ruleMap
ruleMapProp: {}
},
data() {
return {
loading: false,
// 根据g4入口,获取的规则类型列表
ruleTypeList: [],
// 变量列表
variableList: null,
// 对象列表
objectList: null,
// 所有语句的平铺数组
allExpressionList: [],
// 空间项目信息
spaceData: null,
contentBasicLexer: null,
contentBasicParser: null,
dialog: false,
model: 'login',
orgRule: '',
treeData: [],
editMsg: null,
// monaco-editor注册方法
registerObject: {
completionItemProvider: null
},
tokens: [],
selectToken: null,
errorMsg: '',
LExprLexer: null,
LExprParser: null,
// // 规则提示列表
// hintList: null,
// 特殊类型列表
typeMap: {
COMPARE: '比较符',
STRING: '文本',
VARIABLE: '变量',
DIGIT: '整数',
SEMICOLON : ";"
},
// 光标前的tokens
beforeTokens: [],
beforeTokensAll: [],
// 词法和语法的
tokenMap: [],
ruleMap: null,
// 预定义生成的map
predefineMap: {},
g4Data: null,
g4Tokens: null
}
},
created() {
let treeSelect = JSON.parse(sessionStorage.getItem("treeSelect"))
this.spaceData = {
spaceName: treeSelect.spaceName,
projectName: treeSelect.projectName,
}
this.getG4File()
},
watch: {
ruleData: {
handler(n) {
this.orgRule = n
if( this.editMsg ){
var currentModel = this.editMsg.getModel();
currentModel.setValue(n)
}
},
deep: true,
immediate: true
},
entranceG4: {
handler(n) {
console.log("入口修改", n)
},
immediate: true
},
},
mounted() {
// // 根据g4入口,获取规则类型列表
// this.getRuleTypeListByEntranceG4()
// // 获取变量集里的变量列表
// this.getVariableList()
// // 获取对象列表
// this.getObjectList().then(() => {
// this.initMonaco()
// }),
// // 获取所有语句的平铺数组
// this.getAllExpressionList()
},
methods: {
// 初始化所有数据
initData() {
// 根据g4入口,获取规则类型列表
this.getRuleTypeListByEntranceG4()
// 获取变量集里的变量列表
this.getVariableList()
// 获取对象列表
this.getObjectList().then(() => {
this.initMonaco()
}),
// 获取所有语句的平铺数组
this.getAllExpressionList()
},
// 根据g4入口,获取规则类型列表
getRuleTypeListByEntranceG4() {
switch (this.entranceG4) {
case "ruleStatement":
this.ruleTypeList = ["预定义", "前置条件", "如果", "那么", "否则", "或者", "并且"]
break;
case "flowRuleStatement":
this.ruleTypeList = ["预定义", "如果", "或者", "并且"]
break;
case "booleanExpr":
this.ruleTypeList = ["如果", "或者", "并且"]
break;
case "actionStatements":
this.ruleTypeList = ["那么"]
default:
break;
}
},
// 获取所有语句的平铺数组
getAllExpressionList() {
for( let key in expressionList ){
if( key != "一个void" && key != "一个定义" )
this.allExpressionList.push(...expressionList[key])
}
},
// 获取变量集变量列表
getVariableList() {
selectVariableDetail(this.spaceData).then((response) => {
console.log("获取变量列表", response)
if( response.code == 200 ){
this.variableList = response.data.propertyVos
}
})
},
// 获取对象列表
async getObjectList(){
let response = await selectModelList(this.spaceData)
console.log("获取对象列表", response)
if( response.code == 200 ){
this.objectList = response.data
let hintObj = response.data.map((v) => {
return `一个${v.describe}`
})
hintObj.forEach((v) => {
if( expressionList.一个模型.indexOf(v) == -1 ){
expressionList.一个模型.push(v)
}
})
}
},
// 获取g4生成的js文件
getG4File(timer = 1) {
// ------- TODO 修改为一个loading--------请求应该为异步----------
this.loading = true
let tasks = []
let tasks1 = new Promise((resolve, reject) => {
// BasicParser
let data = {
...this.spaceData,
type: "js",
name: "BasicParser"
}
readResource(data).then((BasicParserRes) => {
if( BasicParserRes.code == 200 ){
let BasicParser = BasicParserRes.data.content
// BasicListener
let data1 = {
...this.spaceData,
type: "js",
name: "BasicListener"
}
readResource(data1).then((BasicListenerRes) => {
if( BasicListenerRes.code == 200 ){
let BasicListener = BasicListenerRes.data.content
// console.log("获取g4生成的js文件_BasicParser_BasicListener", BasicParser, BasicListener)
// 处理 BasicParser
BasicParser = BasicParser.replace("import antlr4 from 'antlr4';", "")
BasicParser = BasicParser.replace("import BasicListener from './BasicListener.js';", "")
BasicParser = BasicParser.replace("export default ", "")
// 处理 BasicListener
BasicListener = BasicListener.replace("import antlr4 from 'antlr4';", "")
BasicListener = BasicListener.replace("export default ", "")
BasicListener = BasicListener + "that.LExprParser = BasicParser"
// 组合 BasicParser 和 BasicListener在一个文件
let contentTwo = BasicParser + BasicListener
new Function('antlr4', 'that', contentTwo)(antlr4, this)
this.contentBasicParser = contentTwo
this.ParseTreeAll(this.orgRule)
resolve(BasicParserRes.code);
}else{
reject(BasicParserRes.code)
}
})
}else{
reject(BasicParserRes.code)
}
// // BasicLexer
// let data2 = {
// ...this.spaceData,
// type: "js",
// name: "BasicLexer"
// }
// readResource(data2).then((response) => {
// // console.log("获取g4生成的js文件", response)
// if( response.code == 200 ){
// let content = response.data.content.replace("import antlr4 from 'antlr4';", "")
// content = content.replace("export default ", "")
// content = content + "that.LExprLexer = BasicLexer"
// new Function('antlr4', 'that', content)(antlr4, this)
// this.contentBasicLexer = content
// }
// })
// }else if( BasicParserRes.code == 5001 ){
// if( timer > 4 ){
// this.loading = false
// this.$message.error("获取资源失败")
// return
// }
// setTimeout(() => {
// timer += 1
// this.getG4File(timer)
// }, 4000)
// }
})
});
// let tasks2 = new Promise((resolve, reject) => {
// // BasicListener
// let data1 = {
// ...this.spaceData,
// type: "js",
// name: "BasicListener"
// }
// readResource(data1).then((BasicListenerRes) => {
// if( BasicListenerRes.code == 200 ){
// resolve(BasicListenerRes.code);
// let BasicListener = BasicListenerRes.data.content
// // console.log("获取g4生成的js文件_BasicParser_BasicListener", BasicParser, BasicListener)
// // 处理 BasicParser
// BasicParser = BasicParser.replace("import antlr4 from 'antlr4';", "")
// BasicParser = BasicParser.replace("import BasicListener from './BasicListener.js';", "")
// BasicParser = BasicParser.replace("export default ", "")
// // 处理 BasicListener
// BasicListener = BasicListener.replace("import antlr4 from 'antlr4';", "")
// BasicListener = BasicListener.replace("export default ", "")
// BasicListener = BasicListener + "that.LExprParser = BasicParser"
// // 组合 BasicParser 和 BasicListener在一个文件
// let contentTwo = BasicParser + BasicListener
// new Function('antlr4', 'that', contentTwo)(antlr4, this)
// this.contentBasicParser = contentTwo
// this.ParseTreeAll(this.orgRule)
// // resolve(BasicListenerRes.code);
// }else{
// reject(BasicListenerRes.code)
// }
// })
// });
let tasks3 = new Promise((resolve, reject) => {
// BasicLexer
let data2 = {
...this.spaceData,
type: "js",
name: "BasicLexer"
}
readResource(data2).then((response) => {
// console.log("获取g4生成的js文件", response)
if( response.code == 200 ){
let content = response.data.content.replace("import antlr4 from 'antlr4';", "")
content = content.replace("export default ", "")
content = content + "that.LExprLexer = BasicLexer"
new Function('antlr4', 'that', content)(antlr4, this)
this.contentBasicLexer = content
resolve(response.code);
}else{
reject(response.code)
}
})
});
tasks = [ tasks1, tasks3 ]
console.log(8544, tasks)
Promise.all(tasks).then((codeList) => {
console.log("全部资源获取", codeList)
// 所有资源获取成功
this.loading = false
this.initData()
}).catch((codeList) => {
console.log("全部资源获取_失败", codeList)
if( timer > 4 ){
this.loading = false
this.$message.error("获取资源失败")
return
}
setTimeout(() => {
timer += 1
this.getG4File(timer)
}, 4000)
})
// 暂时 获取g4文件--------------------------------------------------
let data1 = {
...this.spaceData,
type: "g4",
name: "Basic"
}
readResource(data1).then((response) => {
// console.log("获取g4生成的js文件", response)
if( response.code == 200 ){
this.g4Data = response.data.content
}
})
let data2 = {
...this.spaceData,
type: "tokens",
name: "Basic"
}
readResource(data2).then((response) => {
// console.log("获取g4生成的js文件", response)
if( response.code == 200 ){
this.g4Tokens = response.data.content
}
})
// // BasicParser
// let data = {
// ...this.spaceData,
// type: "js",
// name: "BasicParser"
// }
// readResource(data).then((BasicParserRes) => {
// if( BasicParserRes.code == 200 ){
// this.loading = false
// let BasicParser = BasicParserRes.data.content
// // BasicListener
// let data1 = {
// ...this.spaceData,
// type: "js",
// name: "BasicListener"
// }
// readResource(data1).then((BasicListenerRes) => {
// if( BasicListenerRes.code == 200 ){
// let BasicListener = BasicListenerRes.data.content
// // console.log("获取g4生成的js文件_BasicParser_BasicListener", BasicParser, BasicListener)
// // 处理 BasicParser
// BasicParser = BasicParser.replace("import antlr4 from 'antlr4';", "")
// BasicParser = BasicParser.replace("import BasicListener from './BasicListener.js';", "")
// BasicParser = BasicParser.replace("export default ", "")
// // 处理 BasicListener
// BasicListener = BasicListener.replace("import antlr4 from 'antlr4';", "")
// BasicListener = BasicListener.replace("export default ", "")
// BasicListener = BasicListener + "that.LExprParser = BasicParser"
// // 组合 BasicParser 和 BasicListener在一个文件
// let contentTwo = BasicParser + BasicListener
// new Function('antlr4', 'that', contentTwo)(antlr4, this)
// this.contentBasicParser = contentTwo
// this.ParseTreeAll(this.orgRule)
// }
// })
// // BasicLexer
// let data2 = {
// ...this.spaceData,
// type: "js",
// name: "BasicLexer"
// }
// readResource(data2).then((response) => {
// // console.log("获取g4生成的js文件", response)
// if( response.code == 200 ){
// let content = response.data.content.replace("import antlr4 from 'antlr4';", "")
// content = content.replace("export default ", "")
// content = content + "that.LExprLexer = BasicLexer"
// new Function('antlr4', 'that', content)(antlr4, this)
// this.contentBasicLexer = content
// }
// })
// }else if( BasicParserRes.code == 5001 ){
// if( timer > 4 ){
// this.loading = false
// this.$message.error("获取资源失败")
// return
// }
// setTimeout(() => {
// timer += 1
// this.getG4File(timer)
// }, 4000)
// }
// })
},
// 设置代码提示及语句高亮等
async setLang() {
let root = [
[/".*?"/, 'string'],
[/'.*?'/, 'variable'],
[/[0-9]+/, 'number'],
[/<[^>]*?>(.*?)/gi, 'write'],
[/预定义|如果|那么|否则/, 'keyTitle'],
[/并且|或者|;/, 'linkText'],
[/来自\(in\)/, 'predefineFrom'],
]
// 添加 一个对象/一个文本 的形式的代码高亮
expressionList.一个模型.forEach((v) => {
root.push([new RegExp(v), 'predefineObj'])
})
monaco.languages.register({id: 'myLang'});
monaco.languages.setMonarchTokensProvider('myLang', {
tokenizer: {
root
}
});
this.registerObject.completionItemProvider = monaco.languages.registerCompletionItemProvider('myLang', {
provideCompletionItems: async (model, position, context, token) => {
// antiShaking(async () => {
console.log("代码提示", {
this: this,
'position': position,
'token': token,
'context': context,
'model': model,
"selectToken": this.selectToken,
"文本内容": JSON.stringify(model.getLinesContent())
})
var textUntilPosition = model.getValueInRange({
startLineNumber: 1,
startColumn: 1,
endLineNumber: position.lineNumber,
endColumn: position.column
});
var word = model.getWordUntilPosition(position)
let range = {
startLineNumber: position.lineNumber,
endLineNumber: position.lineNumber,
startColumn: word.startColumn,
endColumn: word.endColumn
};
if( this.selectToken ){
range = {
startLineNumber: this.selectToken.line,
endLineNumber: this.selectToken.line,
startColumn: this.selectToken.column + 1,
endColumn: this.selectToken.column + this.selectToken.text.length + 1
};
}
console.log("替代范围", range, word, "当前内容", textUntilPosition)
// 获取提示语
let suggestions = []
if( this.selectToken ){
console.log("根据点击的token获取下拉列表", this.selectToken, this.tokens)
let text = this.selectToken.text
// 去掉尖括号和一个/一些语句
text = text.replace("<", "")
text = text.replace(">", "")
let quantifier = text.substr(0, 2)
let returnType = text.substr(2)
let dataList = quantifier == "一些"? true: false
// 转换操作为void
if( returnType == "操作" ){
returnType = "void"
}
let data = {
...this.spaceData,
dataList,
returnType
}
let response = await this.handleRequestData(data, range, this.selectToken.text)
suggestions = response
return {suggestions: suggestions}
}else{
let beforeTokenNames = this.beforeTokens.map(v => v.text)
let lastToken = this.beforeTokens[this.beforeTokens.length - 1] && this.beforeTokens[this.beforeTokens.length - 1]
console.log("tokens提示判断", this.beforeTokens, lastToken)
if( !lastToken ){
// 获取规则类型语句
suggestions = this.getTypeSuggestions(null, range)
}else if( lastToken.text == '预定义' ){
// 最后一个token为预定义语句, 提示定义语句
let data = {
...this.spaceData,
dataList: false,
returnType: "定义"
}
let suggestions = await this.handleRequestData(data, range)
return {suggestions: suggestions}
}else if( lastToken.text == '如果' ){
// 最后一个token为如果语句,查询所有变量,提示变量列表和<一个布尔>
// // 获取变量列表提示 ------------------正向 ---------------------------------
// let objList = this.variableList.map((variableItem) => {
// return ({
// label: variableItem.describe,
// kind: monaco.languages.CompletionItemKind.Function,
// documentation: '',
// insertText: `'${variableItem.describe}'`,
// sortText: '1'
// })
// })
// // 获取返回值为布尔的提示
// let data = {
// ...this.spaceData,
// dataList: false,
// returnType: "布尔"
// }
// let response = await this.handleRequestData(data, range)
// // 组合两种提示
// suggestions = [...objList, ...response]
// return {suggestions: suggestions}
// ------------------暂时替代带正向的 ---------------------------------
// 获取返回值为布尔的提示
let data = {
...this.spaceData,
dataList: false,
returnType: "布尔"
}
let response = await this.handleRequestData(data, range)
// 组合两种提示
suggestions = [ ...response]
return {suggestions: suggestions}
}else if( lastToken.text == '那么' ){
// 最后一个token为那么语句, 提示返回为void的操作语句
let data = {
...this.spaceData,
dataList: false,
returnType: "void"
}
let response = await this.handleRequestData(data, range)
suggestions = response
return {suggestions: suggestions}
}else if( this.tokenMap[lastToken.type] == 'VARIABLE' ){
// 最后一个token为变量,
// 1. 查询变量属性
// 2. 查询填空有当前变量的函数
// // ------------------模拟 -----------------------------------------------正向 ---------------------------------
// suggestions = [
// {
// label: '"的名称"',
// kind: monaco.languages.CompletionItemKind.Function,
// documentation: '',
// insertText: '的名称'
// }
// ]
}else if( beforeTokenNames.indexOf("预定义") != -1 && beforeTokenNames.indexOf("如果") == -1 ){
// 预定义语句 1. 一个对象/一个基础数据类型 后面接 来自(in) <一个xx列表>
// console.log("预定义111", lastToken.type, this.tokenMap[lastToken.type], expressionList.一个模型, lastToken.text)
if( this.tokenMap[lastToken.type] == 'ID' && expressionList.一个模型.indexOf(lastToken.text) != -1 ){
let text = `来自(in) <一些${lastToken.text.slice(2)}>;`
suggestions = [
{
label: text,
kind: monaco.languages.CompletionItemKind.Function,
documentation: '',
insertText: text
}
]
}else{
let data = {
...this.spaceData,
dataList: false,
returnType: "定义"
}
let suggestions1 = await this.handleRequestData(data, range)
let suggestions2 = this.getTypeSuggestions("预定义", range)
suggestions = [...suggestions1, ...suggestions2]
}
}else if( beforeTokenNames.indexOf("如果") != -1 && beforeTokenNames.indexOf("那么") == -1 ){
// // 如果语句, ------------------正向 ---------------------------------
// // 1. 根据前面的tokens 获取最终组合出的类型
// // 2. 根据前面的类型获取能接的数据生成代码提示
// // 3. 最后拼接上内置的代码提示(语句、函数)
// let type = "一个文本"
// // 内置语句
// let promptList1 = this.allExpressionList.filter((v) => {
// if( v.indexOf( `<${type}>` ) != -1 ){
// return v
// }
// })
// // 函数 ---------------------- 还未获取 -------------------------
// let promptList2 = []
// let promptList = [...promptList1, ...promptList2]
// suggestions = this.replaceTextByVariableTokens(promptList, type)
// ------------------未完成 前面步骤,先拼接内置提示--------------------
let suggestionsAdd = this.getTypeSuggestions("如果", range)
suggestions = [...suggestions, ...suggestionsAdd]
}else if( beforeTokenNames.indexOf("那么") != -1 ){
let data = {
...this.spaceData,
dataList: false,
returnType: "void"
}
suggestions = await this.handleRequestData(data, range)
}
console.log("suggestions", suggestions)
return {suggestions: suggestions}
}
// }, 'timer3')
},
triggerCharacters: [" "]
});
monaco.editor.defineTheme("myLang-theme", {
//基础
base: "vs",
//继承
inherit: true,
//规则
rules: [
{ token: "write", foreground: "767676", fontStyle: 'italic' },
{ token: "variable", foreground: "757500" },
{ token: "variable", foreground: "757500" },
{ token: "keyTitle", foreground: "00008b", fontStyle: 'bold italic' },
{ token: "linkText", fontStyle: 'italic'},
{ token: "predefineObj", foreground: "8b008b", fontStyle: 'bold' },
{ token: "predefineFrom", foreground: "00008b", fontStyle: 'bold' },
],
colors: {
'editor.foreground': '#000000',
'editor.background': '#ffffff',
'editorCursor.foreground': '#666',
'editor.lineHighlightBackground': '#e8f4ff',
'editorLineNumber.foreground': '#008800',
'editor.selectionBackground': '#88000030',
'editor.inactiveSelectionBackground': '#88000015'
}
});
},
// 获取规则类型语句
getTypeSuggestions(beforeType, range) {
let suggestions
switch (beforeType) {
case null:
suggestions = [
{
label: "预定义",
kind: monaco.languages.CompletionItemKind.Function,
documentation: '定义一个变量',
insertText: '预定义\n\t<一个定义>',
range: range
},
{
label: "如果",
kind: monaco.languages.CompletionItemKind.Function,
documentation: '如果语句',
insertText: '如果\n\t<一个布尔>',
range: range
}
]
break;
case "预定义":
suggestions = [
{
label: "如果",
kind: monaco.languages.CompletionItemKind.Function,
documentation: '如果语句',
insertText: '如果\n\t<一个布尔>',
range: range
}
]
break;
case "如果":
suggestions = [
{
label: "或者",
kind: monaco.languages.CompletionItemKind.Function,
documentation: '或者语句',
insertText: '或者\n\t<一个布尔>',
// command: {
// id: 'vs.editor.ICodeEditor:1:geshihua',
// title: '选中这个建议选项后,触发格式化操作'
// }
},
{
label: "并且",
kind: monaco.languages.CompletionItemKind.Function,
documentation: '并且语句',
insertText: '并且\n\t<一个布尔>',
// command: {
// id: 'vs.editor.ICodeEditor:1:geshihua',
// title: '选中这个建议选项后,触发格式化操作'
// }
},
{
label: "那么",
kind: monaco.languages.CompletionItemKind.Function,
documentation: '如果语句',
insertText: '那么\n\t<一个操作>;',
// command: {
// id: 'vs.editor.ICodeEditor:1:geshihua',
// title: '选中这个建议选项后,触发格式化操作'
// }
}
]
break;
case "那么":
suggestions = []
break;
default:
suggestions = []
break;
}
for(var i = 0; i< suggestions.length; i++){
let v = suggestions[i]
if( this.ruleTypeList.indexOf(v.label) == -1 ){
suggestions.splice(i,1);
i=i-1;
}
}
return suggestions
},
// 根据变量到当前光标的tokens 和 提示语句,生成替换 变量到当前光标 的文本的 suggestions
replaceTextByVariableTokens(promptList, type) {
let suggestions = []
let variableTokens = this.getVariableTokens(this.beforeTokensAll)
let firstVariable = variableTokens[0]
let lastVariable = variableTokens[variableTokens.length - 1]
let variableText = ''
variableTokens.forEach((v) => {
variableText += v.text
})
let range = {
startLineNumber: firstVariable.line,
endLineNumber: lastVariable.line,
startColumn: firstVariable.column + 1,
endColumn: lastVariable.column + lastVariable.text.length + 1,
}
// console.log("变量集到结束的tokens", variableTokens, range)
promptList.forEach((promptItem) => {
let newText = promptItem.replace(new RegExp("<" + type + ">"), variableText)
suggestions.push({
label: newText,
kind: monaco.languages.CompletionItemKind.Function,
documentation: '',
insertText: '',
additionalTextEdits: [
{
range,
text: newText,
forceMoveMarkers: false
}
]
})
})
return suggestions
},
// 获取最近的变量结束处的所有有实际显示的token
getVariableTokens(tokenList) {
let variableTokenList = null
tokenList.forEach((tokenItem) => {
if( this.tokenMap[tokenItem.type] == 'VARIABLE' ){
variableTokenList = [tokenItem]
}else if( variableTokenList ) {
variableTokenList.push(tokenItem)
}
})
return variableTokenList
},
// 处理接口获取数据
async handleRequestData(data, range, filterText) {
let suggestions = []
let returnType = data.returnType
let returnTypeIsList = `${data.dataList? '一些': '一个'}${data.returnType}`
const response = await selectReturnMacheFunction(data)
console.log("获取下拉列表", response)
if( response.code == 200 ){
let beforeTokenNames = this.beforeTokens.map(v => v.text)
if( response.data.functionList.length > 0 ){
suggestions = response.data.functionList.map((dataItem) => {
let string = dataItem
// 去掉获取的语句的单引号转
string.replace(/\\\'/g, "'")
return {
label: string,
kind: monaco.languages.CompletionItemKind.Function,
documentation: string,
insertText: string,
filterText: filterText,
range: range
}
})
}
// 添加静态的方法
if( expressionList[returnTypeIsList] && expressionList[returnTypeIsList].length > 0 ){
let suggestionsAdd = expressionList[returnTypeIsList].map((expressionItem) => {
let string = expressionItem
return {
label: string,
kind: monaco.languages.CompletionItemKind.Constant,
documentation: string,
insertText: string,
filterText: filterText,
range: range
}
})
suggestions.unshift(...suggestionsAdd)
}
// 获取预定义的模型
if( beforeTokenNames.indexOf("如果") != -1 &&
this.predefineMap[returnTypeIsList] &&
this.predefineMap[returnTypeIsList].length > 0 ){
let suggestionsAdd = this.predefineMap[returnTypeIsList].map((expressionItem) => {
let string = expressionItem
return {
label: string,
kind: monaco.languages.CompletionItemKind.Variable,
documentation: string,
insertText: string,
filterText: filterText,
range: range
}
})
suggestions.unshift(...suggestionsAdd)
}
// 获取自定义输入的占位内容
if( ['文本', '变量', 'void', '数字', '变量'].indexOf(returnType) != -1 && !data.dataList ){
let inputText = ''
if( returnType == '文本' ){
inputText = `""`
}else if( returnType == '变量' ){
inputText = `''`
}else if( returnType == '数字' ){
inputText = `0`
}
suggestions.unshift({
label: "自定义输入",
kind: monaco.languages.CompletionItemKind.Text,
documentation: "自定义输入的字符串",
insertText: inputText,
filterText: filterText,
range: range
})
}
console.log("选择列表", suggestions)
return suggestions
// return {suggestions: suggestions}
}
},
initMonaco(){
this.setLang()
this.editMsg = monaco.editor.create(this.$refs.codeContainer, {
language: 'myLang', // 语言,需要引入相应文件
value: this.orgRule,
theme: 'myLang-theme', // 编辑器主题
// readOnly: false, // 是否只读
// lineNumbers: true, // 是否显示行数
// lineHeight: 20, // 行高
// tabSize: 2, // 缩进
// automaticLayout: true, // 是否自适应宽高,设置为true的话会有性能问题
})
let selectToken = null
// 更改光标位置
this.editMsg.onDidChangeCursorPosition((positionData) => {
antiShaking(() => {
let position = positionData.position
let positionColumn = position.column - 1
// 获取到光标为止所有的tokens
this.beforeTokens = this.getTokensByPosition(position.lineNumber, positionColumn, 'list')
console.log("beforeTokens", this.beforeTokens)
}, "timer1")
// let position = positionData.position
// let positionColumn = position.column - 1
// // 获取到光标为止所有的tokens
// this.beforeTokens = this.getTokensByPosition(position.lineNumber, positionColumn, 'list')
// console.log("beforeTokens", this.beforeTokens)
// this.addCodeCompletionCore1(beforeTokens)
})
// 输入值变化
this.editMsg.onDidChangeModelContent((data) => {
// antiShaking(() => {
this.selectToken = null
let value = this.editMsg.getValue()
this.ParseTreeAll(value)
// }, "timer2")
})
// 点击
this.editMsg.onMouseDown((data) => {
// console.log("点击", data)
let position = data.target.position
this.selectToken = null
let textData = this.editMsg.getModel().getValue()
// console.log("光标位置选择", position, textData)
this.ParseTree(textData)
// console.log("所有token", this.tokens)
let positionColumn = position.column - 1
this.selectToken = this.getTokenByPosition(position.lineNumber, positionColumn)
// 点击位置不在token内,直接返回
if( !this.selectToken ){
return
}
let selectTokenText = this.selectToken.text
let selectTokenTextLength = selectTokenText.length
if( selectTokenText[0] == '<' && selectTokenText[selectTokenTextLength - 1] == '>' ){
this.getDropList()
}
})
//绑定快捷键
var myBinding = this.editMsg.addCommand(monaco.KeyCode.F10, () => {
this.selectToken = selectToken
this.getDropList()
});
// var myBindings = this.editMsg.addCommand(monaco.KeyCode.F1, () => {
// // this.editMsg.trigger("anything", "editor.action.formatDocument");
// let textData = this.editMsg.getModel().getValue()
// this.ParseTree(textData)
// });
this.addAction()
},
// 添加菜单事件
addAction() {
this.editMsg.addAction({
id: 'geshihua', // 菜单项 id
label: '格式化', // 菜单项名称
// keybindings: [this.monaco.KeyMod.CtrlCmd | this.monaco.KeyCode.KEY_J], // 绑定快捷键
contextMenuGroupId: '9_cutcopypaste', // 所属菜单的分组
run: (data) => {
this.formatContent()
},
})
},
// 规则内容格式化
formatContent() {
try{
let content = this.editMsg.getModel().getValue()
console.log("格式化数据", content)
let title = ['预定义', '如果', '那么', '否则']
let regTitle = title.map((v) => {
return new RegExp("[\\s\\n\\r]*" + v + "[\\s\\n\\r]*", 'g');
})
let regTitleFirst = title.map((v) => {
return new RegExp("^[\\s\\n\\r]*" + v + "[\\s\\n\\r]*", 'g');
})
let regIfSplit = /[\s\\n\\r]*(并且|或者)[\s\\n\\r]*/g
let regDoSplit = /[\s\\n\\r]*;[\s\\n\\r]*(如果|否则)/g
let regDoSplitInner = /[\s\\n\\r]*;[\s\\n\\r]*/g // -----多余的匹配操作,待修改------------
let msgChina = content
regTitle.forEach((regItem, index) => {
msgChina = msgChina.replace(regItem, (res) => {
return `\n${title[index]}\r\n `
})
let regTitleFirstItem = regTitleFirst[index]
msgChina = msgChina.replace(regTitleFirstItem, (res) => {
return `${title[index]}\r\n `
})
})
msgChina = msgChina.replace(regDoSplitInner, (res) => {
return ';\r\n '
})
msgChina = msgChina.replace(regDoSplit, (res, $1) => {
return `;\r\n${$1}`
})
msgChina = msgChina.replace(regIfSplit, (res, $1) => {
return `\n ${$1}\r\n `
})
// 重新设置编辑器显示内容
this.setRuleData(msgChina)
// var currentModel = this.editMsg.getModel();
// currentModel.setValue(msgChina)
}catch(err){
console.log("规则内容格式化错误", err)
}
},
// 获取下拉列表
getDropList(tokenItem) {
console.log("触发提示", tokenItem)
setTimeout(() => {
this.editMsg.trigger('', 'editor.action.triggerSuggest', {});
})
},
// 对全部输入内容分析
ParseTreeAll(sql){
// 如果编辑器还未生成,半秒后重新尝试调用
if( !this.editMsg ){
setTimeout(() => {
this.ParseTreeAll(sql)
}, 500)
return
}
// 打印树
this.consoleParseTree(sql)
let LExprLexer = this.LExprLexer
let LExprParser = this.LExprParser
console.log("校验内容", sql)
const chars = new antlr4.InputStream(sql);
const lexer = new LExprLexer(chars);
const tokens = new antlr4.CommonTokenStream(lexer);
const parser = new LExprParser(tokens);
this.tokens = tokens.tokens
if( !this.tokenMap || !this.ruleMap ){
// 获取词法map
let tokenMap = parser.symbolicNames.map((symbolicNames, i) => {
if( symbolicNames === null ){
return parser.literalNames[i]
}else{
return symbolicNames
}
})
this.tokenMap = tokenMap
// 获取语法map并传递到父组件
this.ruleMap = parser.ruleNames
this.$emit("update:ruleMapProp", this.ruleMap)
console.log("获取词法和语法的map", this.tokenMap, this.ruleMap)
}
// 添加错误监听器
let ErrorListener = new antlr4.error.ErrorListener
parser.removeErrorListeners()
monaco.editor.setModelMarkers(this.editMsg.getModel(), "owner", []);
// monaco-editor 添加错误标志
let markers = [];
this.errorMsg = []
ErrorListener.syntaxError = (recognizer, offendingSymbol, line, column, msg, e) => {
console.log("错误提示信息", 1, recognizer, 2, offendingSymbol, 3, line, 4, column, 5, msg, 6, e)
let msgChina = this.getMsgChina(msg) || msg
this.errorMsg.push(`${line}:${column} ${msgChina}`)
markers.push({
startLineNumber: line,
endLineNumber: line,
startColumn: offendingSymbol.start + 1,
endColumn: offendingSymbol.stop + 1,
message: msg,
severity: monaco.MarkerSeverity.Error,
});
monaco.editor.setModelMarkers(this.editMsg.getModel(), "owner", markers);
}
parser.addErrorListener(ErrorListener)
// 生成语法树
parser.buildParseTrees = true;
const tree = parser[this.entranceG4]();
// 防抖生成遍历语法树
antiShaking(() => {
console.log("文本tree更新", tree)
if( !tree.children ){
return
}
// 遍历树,获取预定义语句
let DefinitionStatementsContext = []
// 遍历获取所有预定义元素
tree.children.forEach((treeItem) => {
if( treeItem.constructor.name == "PredefineStatementContext" ){
// 遍历获取预定义的语句
treeItem.children.forEach((PredefineElement) => {
if( PredefineElement.constructor.name == "DefinitionStatementsContext" ){
DefinitionStatementsContext = PredefineElement
}
})
}
})
// 获取预定义map
this.getPredefineData(DefinitionStatementsContext)
}, "timer3", 500)
},
// 获取预定义map
getPredefineData(predefineTree) {
this.predefineMap = {}
if( !predefineTree.children ){
return
}
predefineTree.children.forEach((predefineItem) => {
// 获取每一条预定义语句
if( predefineItem.constructor.name == "DefinitionStatementContext" ){
let key
let value
predefineItem.children.forEach((predefineItemElement) => {
let type = predefineItemElement.symbol && predefineItemElement.symbol.type
if( this.tokenMap[type] == 'ID' ){
key = predefineItemElement.symbol.text
}else if(this.tokenMap[type] == 'VARIABLE'){
value = predefineItemElement.symbol.text
}
})
if( !this.predefineMap[key] ){
this.predefineMap[key] = [value]
}else{
this.predefineMap[key].push(value)
}
}
})
console.log("获取预定义map", this.predefineMap)
},
ParseTree(sql){
let LExprLexer = this.LExprLexer
let LExprParser = this.LExprParser
// const inputStream = CharStreams.fromString(sql);
// const lexer = new LExprLexer(inputStream);
// const tokenStream = new CommonTokenStream(lexer);
// const parser = new LExprParser(tokenStream);
// // const errorListener = new ErrorListener();
// // parser.addErrorListener(errorListener);
// parser.numberCompareExpr();
// sql = "SELECT * FROM `adb_mysql_dblink`.`adb_mysql_1124qie`.`courses`"
const chars = new antlr4.InputStream(sql);
const lexer = new LExprLexer(chars);
const tokens = new antlr4.CommonTokenStream(lexer);
const parser = new LExprParser(tokens);
// 生成语法树
parser.buildParseTrees = true;
const tree = parser[this.entranceG4]();
// console.log(78888, tree, 3, antlr4)
return tree
// 添加错误监听器
// let ErrorListener = new antlr4.error.ErrorListener
// parser.removeErrorListeners()
// ErrorListener.syntaxError = (recognizer, offendingSymbol, line, column, msg, e) => {
// console.log("错误提示信息", 1, recognizer, 2, offendingSymbol, 3, line, 4, column, 5, msg, 6, e)
// this.errorMsg = `${line}:${column} ${msg}`
// // monaco-editor 添加错误标志
// let markers = [];
// markers.push({
// startLineNumber: line,
// endLineNumber: line,
// startColumn: offendingSymbol.start,
// endColumn: offendingSymbol.stop,
// message: msg,
// severity: monaco.MarkerSeverity.Error,
// });
// monaco.editor.setModelMarkers(this.editMsg.getModel(), "owner", markers);
// }
// parser.addErrorListener(ErrorListener)
// this.tokens = tokens.tokens
// parser.reset()
// 添加解析器
// this.addCodeCompletionCore(parser)
// class Visitor {
// visitChildren(ctx) {
// if (!ctx) {
// return;
// }
// if (ctx.children) {
// return ctx.children.map(child => {
// if (child.children && child.children.length != 0) {
// return child.accept(this);
// } else {
// return child.getText();
// }
// });
// }
// }
// }
// tree.accept(new Visitor());
// // 自定义侦听器
// class KeyPrinter extends LExprListener {
// // override default listener behavior
// exitKey(ctx) {
// console.log("Oh, a key!");
// }
// }
// const printer = new KeyPrinter();
// antlr4.tree.ParseTreeWalker.DEFAULT.walk(printer, tree);
// const walker = new tree.ParseTreeWalker();
// console.log(8888, walker)
// // 自定义的监听器,采用Listener模式
// const extractor = new LExprListener({
// enterAliasedRelation: this.enterAliasedRelation, // this.enterAliasedRelatio是具体的业务逻辑
// enterQualifiedName: this.enterQualifiedName,
// });
// walker.walk(extractor, tree);
},
addCodeCompletionCore(parser) {
// console.log(43534, parser)
const core = new c3.CodeCompletionCore(parser);
// 1) At the input start.
let candidates = core.collectCandidates(6);
// const core = new c3.CodeCompletionCore(parser);
// // 1) At the input start.
// let candidates = core.collectCandidates(1);
console.log(5454646, candidates)
},
// // 错误分析获取解析
// addCodeCompletionCore1(sql) {
// let LExprLexer = this.LExprLexer
// let LExprParser = this.LExprParser
// console.log("校验内容2", sql)
// const chars = new antlr4.InputStream(sql);
// const lexer = new LExprLexer(chars);
// const tokens = new antlr4.CommonTokenStream(lexer);
// const parser = new LExprParser(tokens);
// // 添加错误监听器
// let ErrorListener1 = new antlr4.error.ErrorListener
// parser.removeErrorListeners()
// // monaco-editor 添加错误标志
// let typeList = [];
// ErrorListener1.syntaxError = (recognizer, offendingSymbol, line, column, msg, e) => {
// console.log("--错误提示信息", 1, recognizer, 2, offendingSymbol, 3, line, 4, column, 5, msg, 6, e)
// let reg1 = /^mismatched input '<EOF>' expecting ([\s\S]*)$/
// if( reg1.test(msg) ){
// msg.replace(reg1, (res, $1) => {
// // console.log("错误的结束", $1)
// typeList = this.gettypeList($1, {}).split(",")
// console.log("错误的结束", typeList)
// this.hintList = typeList
// })
// }
// }
// parser.addErrorListener(ErrorListener1)
// // 生成语法树
// parser.buildParseTrees = true;
// const tree = parser.ruleStatement();
// },
// 根据tokens列表,获取当前光标所选token
getTokenByPosition(line, column) {
// console.log(4534456, this.tokens)
let selectToken
this.tokens.forEach((tokenItem) => {
if( line == tokenItem.line &&
column > tokenItem.column &&
column < (tokenItem.column + tokenItem.text.length) ){
console.log("光标选中token", tokenItem, tokenItem.text)
selectToken = tokenItem
}
})
return selectToken
},
// 根据tokens列表及点击位置,获取点击位置之前的token列表
getTokensByPosition(line, column, type) {
let beforeTokens = ''
let tokenList = []
this.beforeTokensAll = []
this.tokens.forEach((tokenItem) => {
if( line > tokenItem.line || (line == tokenItem.line && column >= (tokenItem.column + tokenItem.text.length)) ){
// console.log("光标之前的token列表", tokenItem, tokenItem.text, line, column)
if( type == "list" ){
this.beforeTokensAll.push(tokenItem)
let tokenItemValue = tokenItem.text.replace(/\s+/g, "")
tokenItemValue = tokenItemValue.replace(/[\r\n]/g, "")
if( tokenItemValue ){
tokenList.push(tokenItem)
}
}else{
beforeTokens += tokenItem.text
}
}
})
if( type == 'list' ) {
return tokenList
}else{
return beforeTokens
}
},
// 翻译错误提示
getMsgChina(msg) {
let typeMap = this.typeMap
let msgChina
// 处理 "mismatched input '等于' expecting COMPARE" 情况
var reg1 = /^mismatched input '([\s\S]*)' expecting ([\s\S]*)$/
// 处理 no viable alternative at input '<一个数字> 小于' 情况
var reg2 = /^no viable alternative at input '([\s\S]*)'$/
// 处理 extraneous input '<一个文本>' expecting {' 的姓名 为 ', STRING, VARIABLE} 情况
var reg3 = /^extraneous input '([\s\S]*)' expecting ([\s\S]*)$/
// 处理 missing ' 的姓名列表' at ';' 情况
var reg4 = /^missing ([\s\S]*) at ([\s\S]*)$/
if( reg1.test(msg) || reg3.test(msg) ){
let reg = reg1.test(msg)? reg1: reg3
msgChina = msg.replace(reg, (res, $1, $2) => {
let cmsg = ''
let test1 = /^\{([\s\S]*)\}$/
let listArrayChina = ''
if( test1.test($2) ){
// 处理 "mismatched input '等于' expecting {'(', '非', '真', '假', STRING, VARIABLE, DIGIT}" 情况
listArrayChina = this.gettypeList($2, typeMap)
}else{
// 处理 "mismatched input '等于' expecting COMPARE" 情况
listArrayChina = typeMap[$2] || $2
}
if( $1 == '<EOF>' ){
cmsg = `错误的结束,期望输入${listArrayChina}`
}else{
cmsg = `'${$1}'输入不匹配,期望输入${listArrayChina}`
}
return cmsg
})
}else if( reg2.test(msg) ){
msgChina = msg.replace(reg2, (res, $1) => {
return `无法识别输入'${$1}'`
})
}else if( reg4.test(msg) ){
msgChina = msg.replace(reg4, (res, $1, $2) => {
if( $2 == "<EOF>" ){
return `缺少结束符'${$1}'`
}else{
return `${$2} 处缺少 '${typeMap[$1] || $1}'`
}
})
}
return msgChina
},
// 获取类型列表
gettypeList($2, typeMap) {
let listData = $2.replace(/\}$/, '')
listData = listData.replace(/^\{/, '')
let listArray = listData.split(',')
// 获取所需输入列表的中文
let listArrayChina = listArray.map((v) => {
let type = v.replace(/(^\s*)|(\s*$)/g, "")
return typeMap[type] || type
})
return listArrayChina.join(",")
},
// 获取规则数据
getRuleData() {
return this.editMsg.getValue()
},
// 设置规则数据
setRuleData(msgChina) {
let firstDecorations = this.tokens[0]
let lastDecorations = this.tokens[this.tokens.length - 1]
let range = {
startLineNumber: firstDecorations.line,
startColumn: firstDecorations.column,
endLineNumber: lastDecorations.line,
endColumn: lastDecorations.column + lastDecorations.text.length + 1,
}
this.editMsg.executeEdits('insert-code', [
{
range,
text: msgChina,
},
])
},
// 控制台打印树
consoleParseTree(data) {
let tree = this.ParseTree(data)
console.log("生成树", tree)
}
},
beforeDestroy() {
this.registerObject.completionItemProvider.dispose()
this.editMsg.dispose()
}
}
</script>
<style lang="scss" scoped>
.container {
position: relative;
height: 100vh;
}
</style>
浙公网安备 33010602011771号