巨无敌大坑:设置的文本提示项有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>
 

 

posted on 2023-02-08 10:23  occc  阅读(326)  评论(0编辑  收藏  举报