<template>
    <div class="code-container" ref="container" :class="cssClass"></div>
</template>
<script>
import * as monaco from "monaco-editor";
let sqlStr =
        "add except percent all exec plan alter execute precision and exists primary any exit print as fetch domain " +
        "proc asc file procedure authorization fillfactor public backup for raiserror begin foreign read between " +
        "freetext readtext break freetexttable reconfigure browse from references bulk full replication by " +
        "function restore cascade goto restrict case grant return check group revoke checkpoint having right " +
        "close holdlock rollback clustered identity rowcount coalesce identity_insert rowguidcol collate identitycol " +
        "rule column if save commit in schema compute index select constraint inner session_user contains insert set " +
        "containstable intersect setuser continue into shutdown convert is some create join statistics cross key " +
        "system_user current kill table current_date left textsize current_time like then current_timestamp lineno " +
        "to current_user load top cursor national tran database nocheck transaction dbcc nonclustered trigger " +
        "deallocate not truncate declare null tsequal default nullif union delete of unique deny off update desc " +
        "offsets updatetext disk on use distinct open user distributed opendatasource values double openquery varying " +
        "drop openrowset view dummy openxml waitfor dump option when else or where end order while errlvl outer " +
        "with escape over writetext recursive limit offset explain prepare describe";
    export default {
        name: "CodeEditor",
        props: {
            disabled: false,
            title: "",
            cssClass:"",
            placeholder: "",
            language:{
                type: String,
                default: "java"
            },
            options: {
                type: Object,
                default() {
                    return {
                      acceptSuggestionOnCommitCharacter: true, // 接受关于提交字符的建议
                      acceptSuggestionOnEnter: 'on', // 接受输入建议 "on" | "off" | "smart"
                      accessibilityPageSize: 10, // 辅助功能页面大小 Number 说明：控制编辑器中可由屏幕阅读器读出的行数。警告：这对大于默认值的数字具有性能含义。
                      accessibilitySupport: 'on', // 辅助功能支持 控制编辑器是否应在为屏幕阅读器优化的模式下运行。
                      autoClosingBrackets: 'always', // 是否自动添加结束括号(包括中括号) "always" | "languageDefined" | "beforeWhitespace" | "never"
                      autoClosingDelete: 'always', // 是否自动删除结束括号(包括中括号) "always" | "never" | "auto"
                      autoClosingOvertype: 'always', // 是否关闭改写 即使用insert模式时是覆盖后面的文字还是不覆盖后面的文字 "always" | "never" | "auto"
                      autoClosingQuotes: 'always', // 是否自动添加结束的单引号 双引号 "always" | "languageDefined" | "beforeWhitespace" | "never"
                      autoIndent: 'None', // 控制编辑器在用户键入、粘贴、移动或缩进行时是否应自动调整缩进
                      automaticLayout: true, // 自动布局
                      codeLens: false, // 是否显示codeLens 通过 CodeLens，你可以在专注于工作的同时了解代码所发生的情况 – 而无需离开编辑器。 可以查找代码引用、代码更改、关联的 Bug、工作项、代码评审和单元测试。
                      codeLensFontFamily: '', // codeLens的字体样式
                      codeLensFontSize: 14, // codeLens的字体大小
                      colorDecorators: false, // 呈现内联色彩装饰器和颜色选择器
                      comments: {
                        ignoreEmptyLines: true, // 插入行注释时忽略空行。默认为真。
                        insertSpace: true // 在行注释标记之后和块注释标记内插入一个空格。默认为真。
                      }, // 注释配置
                      contextmenu: true, // 启用上下文菜单
                      columnSelection: false, // 启用列编辑 按下shift键位然后按↑↓键位可以实现列选择 然后实现列编辑
                      autoSurround: 'never', // 是否应自动环绕选择
                      copyWithSyntaxHighlighting: true, // 是否应将语法突出显示复制到剪贴板中 即 当你复制到word中是否保持文字高亮颜色
                      cursorBlinking: 'Solid', // 光标动画样式
                      cursorSmoothCaretAnimation: true, // 是否启用光标平滑插入动画  当你在快速输入文字的时候 光标是直接平滑的移动还是直接"闪现"到当前文字所处位置
                      cursorStyle: 'UnderlineThin', // "Block"|"BlockOutline"|"Line"|"LineThin"|"Underline"|"UnderlineThin" 光标样式
                      cursorSurroundingLines: 0, // 光标环绕行数 当文字输入超过屏幕时 可以看见右侧滚动条中光标所处位置是在滚动条中间还是顶部还是底部 即光标环绕行数 环绕行数越大 光标在滚动条中位置越居中
                      cursorSurroundingLinesStyle: 'all', // "default" | "all" 光标环绕样式
                      cursorWidth: 2, // <=25 光标宽度
                      minimap: {
                        enabled: false // 是否启用预览图
                      }, // 预览图设置
                      folding: true, // 是否启用代码折叠
                      links: true, // 是否点击链接
                      overviewRulerBorder: false, // 是否应围绕概览标尺绘制边框
                      renderLineHighlight: 'gutter', // 当前行突出显示方式
                      roundedSelection: false, // 选区是否有圆角
                      scrollBeyondLastLine: false, // 设置编辑器是否可以滚动到最后一行之后
                      //readOnly: false, // 是否为只读模式
                      theme: 'vs-dark',// 官方自带三种主题 vs, hc-black, or vs-dark
                      // language: "java", // shell、sql、python
                      selectOnLineNumbers: true,//显示行号
                      lineNumbersMinChars: 3, // 行号最小字符   number
                      glyphMargin: true,  //字形边缘
                      scrollBeyondLastColumn:false,//滚动到最后一列外
                      useTabStops: false,
                      wordWrap: "on",//自动换行
                      wrappingIndent: "indent",
                      fontSize: 12,       //字体大小
                      quickSuggestionsDelay: 100,   //代码提示延时
                      dropIntoEditor: {
                        enabled: true, // 能否把文字拖拽进编辑器
                      },
                      enableSplitViewResizing: true,
                    };
                }
            },
            value: {
                type: String,
                default: ""
            }
        },

        data() {
            return {
                monacoInstance: null,
                provider: null,
                hints: []
            };
        },
        created() {
            this.initHints();
        },
        mounted() {
            this.init();
        },
        beforeDestroy() {
            this.dispose();
        },
        methods: {
            dispose() {
                if (this.monacoInstance) {
                    if (this.monacoInstance.getModel()) {
                        this.monacoInstance.getModel().dispose();
                    }
                    this.monacoInstance.dispose();
                    this.monacoInstance = null;
                    if (this.provider) {
                        this.provider.dispose();
                        this.provider = null
                    }
                }
            },
            initHints() {
               if(this.language==="sql") {
                 let sqlArr = sqlStr.split(" ");
                 this.hints = Array.from(new Set([...sqlArr])).sort();
                 this.$core.debug().log("初始化的sql命中", this.hints);
               }
            },
            init() {
                let that = this;
                this.dispose();
                let createCompleters = textUntilPosition => {
                    //过滤特殊字符
                    let _textUntilPosition = textUntilPosition
                        .replace(/[\*\[\]@\$\(\)]/g, "")
                        .replace(/(\s+|\.)/g, " ");
                    //切割成数组
                    let arr = _textUntilPosition.split(" ");
                    //取当前输入值
                    let activeStr = arr[arr.length - 1];
                    //获得输入值的长度
                    let len = activeStr.length;

                    //获得编辑区域内已经存在的内容
                    let rexp = new RegExp('([^\\w]|^)' + activeStr + '\\w*', "gim");
                    let match = that.value.match(rexp);
                    let _hints = !match ? [] : match.map(ele => {
                        let rexp = new RegExp(activeStr, "gim");
                        let search = ele.search(rexp);
                        return ele.substr(search)
                    })

                    //查找匹配当前输入值的元素
                    let hints = Array.from(new Set([...that.hints, ..._hints])).sort().filter(ele => {
                        let rexp = new RegExp(ele.substr(0, len), "gim");
                        return match && match.length === 1 && ele === activeStr || ele.length === 1
                            ? false
                            : activeStr.match(rexp);
                    });
                    //添加内容提示
                  return hints.map(ele => {
                      return {
                        label: ele,
                        kind: that.hints.indexOf(ele) > -1 ?
                            monaco.languages.CompletionItemKind.Keyword :
                            monaco.languages.CompletionItemKind.Text,
                        documentation: ele,
                        insertText: ele
                      };
                    });
                };
                this.provider = monaco.languages.registerCompletionItemProvider("sql", {
                    provideCompletionItems(model, position) {
                        // this.$core.debug().log("======》智能感知",model,position);
                        let textUntilPosition = model.getValueInRange({
                            startLineNumber: position.lineNumber,
                            startColumn: 1,
                            endLineNumber: position.lineNumber,
                            endColumn: position.column
                        });
                        let suggestions = createCompleters(textUntilPosition);
                        return {
                            suggestions: suggestions
                        };
                    }
                });
                this.$core.debug().log("加载的配置",this.language,this.disabled,this.options);
                // 初始化编辑器实例
                this.monacoInstance = monaco.editor.create(this.$refs["container"], {
                    value: this.value,
                    autoIndex: true,
                    language: this.language,
                    readOnly: this.disabled,
                    ...this.options
                });
                // 监听编辑器content变化事件
                this.monacoInstance.onDidChangeModelContent(() => {
                    this.$emit("change", this.monacoInstance.getValue());
                });
            }
        }
    };
</script>
<style lang="scss" scope>
    .code-container {
        width: 100%;
        height: 100%;
        overflow: hidden;
        border: 1px solid #eaeaea;
        .monaco-editor .scroll-decoration {
            box-shadow: none;
        }
    }
</style>
