CodeMirror实现自定义提示功能

我之前在文章《CodeMirror基本使用及实现关键词高亮、自定义主题》中简单介绍了CodeMirror实现自动提示的功能,但是使用的是CodeMirror中封装好的几种指定语法的提示功能,如css、html、js、sql、xml,对应文件如下列表:

CodeMirror实现自定义提示功能_第1张图片

现在我开发中有需求做自定义语法的自动提示功能,并没有现成的mode可以使用,学习CodeMirror API和上述几个文件的实现方式之后找到了实现方法,记录一下我的实现方式。

本文以${model::point}为例,需求是输入${后直接出现下拉框,提示内容是所有的model,当选择或输入model后,输入::直接出现下拉框,提示内容为${后::前model里所有的point和attribute,在${和::后点击Ctrl,也出现和上面相同的提示信息。

要提示的数据举例如下:

 

{
    "model_a":{
        "points":[
            "point_a1",
            "point_a2",
            "point_a3"
        ],
        "attributes":[
            "attribute_a1",
            "attribute_a2",
            "attribute_a3"
        ]
    },
    "model_b":{
        "points":[
            "point_b1",
            "point_b2",
            "point_b3"
        ],
        "attributes":[
            "attribute_b1",
            "attribute_b2",
            "attribute_b3"
        ]
    }
}

 要实现的效果如下:

CodeMirror实现自定义提示功能_第2张图片

CodeMirror实现自定义提示功能_第3张图片

实现方式:

import React, {Component} from 'react';
import autobind from 'class-autobind';
import {inject, observer} from 'mobx-react';
import CodeMirror from 'react-codemirror';
import 'codemirror/addon/hint/show-hint.css';
import 'codemirror/addon/hint/show-hint.js';
import 'codemirror/addon/hint/anyword-hint.js';
import 'codemirror/lib/codemirror.css';
import './index.less';

@inject('configureStore')
@observer
export default class CodeEditor extends Component {
    constructor(props) {
        super(props);
        autobind(this, CodeEditor.prototype);
        this.options = {
            lineNumbers: false,
            // mode: {name: "text/x-mysql"},
            extraKeys: {"Ctrl": "autocomplete"},
            theme: 'sqlTheme',
            lineWrapping:true,
            hintOptions: {hint: this.handleShowHint, completeSingle: false}
        };
    }
    componentDidMount(){
        this.codeEditor = this.codeEditorRef.getCodeMirror();
    }

    handleShowHint(){
        const codeMirrorInstance = this.codeEditorRef.getCodeMirrorInstance();
        const cur = this.codeEditor.getCursor();
        const curLine = this.codeEditor.getLine(cur.line);
        const end = cur.ch;
        const start = end;
        let list = [];
        // 根据不同情况给list赋值,默认为[],即不显示提示框。
        const cursorTwoCharactersBefore = `${curLine.charAt(start - 2)}${curLine.charAt(start - 1)}`;
        const {activeItem, openedItemsData} = this.props.configureStore;
        const {variablePool} = openedItemsData[activeItem].config;
        const variablePoolKeys = variablePool ? Object.keys(variablePool): [];
        if(cursorTwoCharactersBefore === '${'){
            list = variablePoolKeys;
        }else if(cursorTwoCharactersBefore === '::'){
            const lastIndex = curLine.lastIndexOf('${', start);
            const modelId = curLine.substring(lastIndex + 2, start - 2);
            if(lastIndex !== -1 && modelId && variablePool[modelId]){
                list = variablePool[modelId].attributes.concat(variablePool[modelId].points);
            }else {
                list = [];
            }
        }
        return {list: list, from: codeMirrorInstance.Pos(cur.line, start), to: codeMirrorInstance.Pos(cur.line, end)};
    }
    handleCodeChange(value){
        this.codeEditor.closeHint();
        this.codeEditor.showHint();
        this.props.onChange(value);
    }

    render() {
        return (
             this.codeEditorRef = ref}
                value={this.props.value}
                onChange={this.handleCodeChange}
                options={this.options}
            />
        );
    }
}

demo中使用了mobx管理state,variablePool是从configureStore中读取的。

更新:这里介绍的方式需要提前准备好提示的内容,且不支持搜索,只能选择。在《CodeMirror实现自定义提示功能增强版(支持搜索、调用接口查询提示内容)》里更新了一个增强版,可以支持所有和调用接口查询提示数据。

 

你可能感兴趣的:(codemirror)