background

Recently, there was a requirement to make an SQL editor in a web page. It required some basic SQL editor functions, and finally selected CodeMirror to develop related functions. The basic functions covered in this article include the introduction of CodeMirror in React, input association, execution of selected SQL and other functions. Because the project is developed based on React, this guide uses React as an example.

The introduction of

  1. Executing the CodeMirror installation command (version 5.40.2)
npm install codemirror --save
Copy the code
  1. CodeMirror is introduced in the React component
import React from 'react';
import codemirror from 'codemirror';
require('codemirror/codemirror.css'); // CodeMirrory native style require('codemirror/mode/sql/sql');
require('codemirror/mode/shell/shell');
require('codemirror/addon/display/placeholder'); 
require('codemirror/addon/hint/show-hint.css'); // require('codemirror/addon/hint/show-hint.js'); // require('codemirror/addon/hint/sql-hint.js'); // for code hintsCopy the code

Develop CodeMirror as a component

CodeMirror components:

class CodeMirror extends React.Component {
  static defaultProps = {
    useFocus: true
  }

  componentDidMount() {
    this.paste = ' ';
    const {
      onChange, onBlur, options, value = ' ', onScroll,
      onCursorActivity, onInputRead,
    } = this.props;

    this.editor = codemirror(this.ref, {
      indentWithTabs: true,
      smartIndent: true,
      lineNumbers: true,
      matchBrackets: true,
      autofocus: true,
      extraKeys: { Tab: 'autocomplete' },
      hintOptions: { completeSingle: false }
      lineWrapping: true,
      value
    });
    const { editor, setCursor } = this;

    setCursor(editor, true);
    const changeDelay = debounce((e) => {
      setCursor(e);
      onChange && onChange(e.getValue());
    }, 300);
    editor.on('change', changeDelay);
    editor.on('blur', (e) => {
      setCursor(e);
      onBlur && onBlur(e.getValue());
    });
    editor.on('cursorActivity', onCursorActivity);
    editor.on('inputRead', (cm, change) => onInputRead(cm, change, editor));
    onScroll && editor.on('scroll', onScroll);
  }

  shouldComponentUpdate({ paste = ' ', value = ' ', }) {
    const { editor } = this;

    if(paste ! == this.paste) { this.focus(); editor.replaceSelection(`${paste}`);
      this.paste = paste;
    } else if(value ! == editor.getValue()) { editor.setOption('value', value);

      editor.setValue(value);
      this.fixBottom();
      this.focus();
    }
    return false;
  }

  setCursor = (editor, toEnd) => {
    const { line, ch } = editor.doc.getCursor();
    this.cursor = { ch, line: toEnd ? line + 1 : line };
  }

  focus() {
    const { editor } = this;
    const { options: { readOnly }, useFocus } = this.props;
    if (readOnly) return;
    if(! useFocus)return; editor.focus(); editor.setCursor({ ... this.cursor },readOnly);
  }

  fixBottom() {
    const { fixBottom } = this.props;
    if(! fixBottom)return;

    const { editor } = this;
    const { height } = editor.getScrollInfo();
    editor.scrollTo(0, height);
  }

  render() {
    const { className, options: { readOnly } } = this.props;
    return (
      <div
        className={`${className} ${readOnly && 'readOnly'}`} ref={(self) => { this.ref = self; }} / >); }}Copy the code

The child component calls the CodeMirror component

class SqlConsole extends Component {
  static defaultProps = {
    value: ' ',
    sqlPaste: ' ',
    onChange: () => {},
  }

  state = {
    showModal: false.source: {}}; uuid =' ';

  onCursorActivity = (cm) => {
    if(! cm.getSelection()) { console.log(cm.getSelection()); }} onInputRead = async (cm, change, editor) => {const {text} = change; const dechars = ['. ',]; const autocomplete = dechars.includes(text[0]);if(autocomplete) { const data = getTableList(); Editor.setoption ('hintOptions', {
        tables: data,
        completeSingle: false
      });
      cm.execCommand('autocomplete');
    } else{ const tableName = getTableList(); Editor.setoption ('hintOptions', {
        tables: tableName,
        completeSingle: false
      });
    }
    cm.execCommand('autocomplete');
  }

  render() {
    const { sqlPaste, onChange, } = this.props;
    return (
      <CodeMirror
        className="sql"value={pane.sql} paste={sqlPaste} onChange={sql => { onChange(sql); }} // SQL change event onCursorActivity={(cm) => this.oncursorActivity (cm)} // To complete the select listener onInputRead={cm, change, editor) => this.onInputRead(cm, change, editor) } /> ); }}Copy the code

Through the above two father-son modules, the basic functions of SQL editor can be realized, and the key part of the code has been annotated. Let’s go into some of the details.

Automatic completion

This is done by setting hintOptions in CodeMirror, and of course importing the dependent hint package first.

const data = { table1: [' '], table2: [' '], table3: [' ']}; cm.on('inputRead', (cm, change) => {
  cm.setOption('hintOptions', {
    tables: data,
    completeSingle: false
  });
cm.execCommand('autocomplete');
});

Copy the code

Cm is the first parameter of the inputRead event in CodeMirror, which is also the CodeMirror instance itself. The process of automatic completion is summarized as follows:

  1. Bind the inputRead method to the CodeMirror using the ON method
  2. In inputRead, hintOptions are set through the setOption method to realize automatic content completion
  3. ExecCommand (‘autocomplete’) to perform automatic completion

Execute the selected part

The key to executing the selected part of the code is to listen for the selected event and get the selected part of the code. The two methods are cursorActivity and getSelection.

cm.on('cursorActivity', (cm) => { cm.getSelection(); // select content});Copy the code

Cm is an instance of CodeMirror, through these two simple methods, you can achieve the selected part of the content. If the selected content is not empty, part of the SQL can be executed.

conclusion

CodeMirror is a fully functional code editing box, which supports many programming languages, the above only shows SQL, the framework document is difficult to read, welcome to rely on the framework to do development partners together. If you have any questions about my summary method after reading this article, please leave a comment and reply accordingly.