codemirror defineMode自定义高亮

4,300

codemirror
参考文档https://www.cnblogs.com/xmzzp/p/4318265.html

react-codemirror2是对codemirror的二次封装,专用在react中使用
以下就介绍一下react项目中codemirror defineMode的用法,

作用:

Mode的主要作用就是对行文本进行词法分析进而进行文本标识(高亮),当然了主要功能也是基础功能,大部分mode的设计要求远远不止对文本进行高亮,同时,某种语言的复杂程度也影响着mode的复杂程度。

CodeMirror设计了状态对象(state Object),该对象是唯一的,也可以认为是每一行共享的(类似全局变量),它的属性在词法分析函数内部做维护,如此一来不同行之前就有了联系,词法分析函数在分析当前行文本的时候,可以从状态对象获取到自己感兴趣的信息。

在需要使用状态对象的Modes内部,mode对象必须定义一个startState方法,这是一个不带参数的函数,用来生成要在文档开始时使用的状态对象。

mode对象最重要的部分是它的 token(stream, state)方法。所有的modes必须定义这个方法。它应该从它的参数stream中读取一个token,可选的更新它的状态,并返回一个样式字符串,或者为不必样式化的token返回null。鼓励你使用主题(theme)中定义的‘标准’的名称(没有 'cm-'前缀)。如果失败了,也有编写你自己的css主题(theme)文件。

代码规范:

在编写Mode代码的时候,所有代码都要控制在与调用CodeMirror.defineMode接口的同一作用域内,所有函数变量的申明都要写在CodeMirror.defineMode第二个参数(函数)内部。这样可以避免mode变量对全局变量造成污染

使用:

CodeMirror.defineMode('name', fn) 第一个参数是自定义mode的名称(必须小写) 第二个参数类型为函数,该函数也有两个入参:分别是CodeMirror的配置对象(传递给CodeMirror构造函数使用)和mode的配置对象(包含哪些属性由具体的mode决定)。该函数的返回值是mode对象。

使用状态的modes必须在其mode对象上定义一个startState方法。这是一个不带参数的函数,用来生成要在文档开始时使用的状态对象。

Example(自定义关键词高亮)

js

import { Controlled as ReactCodeMirror } from 'react-codemirror2';
import CodeMirror from 'codemirror';

import 'codemirror/lib/codemirror.css';
import 'codemirror/theme/material.css';

CodeMirror.defineMode('cert', () => ({
  token: (stream, state) => {
    const cmCustomCheckStreamFn = streamWrapper => {
      // 自定义关键字和样式
      const customKeyWords = [['BEGIN', 'begin-style'], ['END', 'end-style']];
      for (let i = 0; i < customKeyWords.length; i++) {
        if (streamWrapper.match(customKeyWords[i][0])) { return customKeyWords[i][1]; }
      }
      return '';
    };

    const ret = cmCustomCheckStreamFn(stream);
    if (ret.length > 0) return ret;

    stream.next();
    return null;
  }
}));

// 自定义表单控件
export default class MyCodeMirror extends React.Component {
  handleChange = value => {
    this.triggerChange(value);
  };

  triggerChange = changedValue => {
    const { onChange } = this.props;
    if (onChange) {
      onChange(changedValue);
    }
  };

  render() {
    const { value } = this.props;

    return (
      <ReactCodeMirror
        className={styles.myCodeMirror}
        value={value}
        options={{
          mode: 'cert',
          theme: 'material',
          lineNumbers: true
        }}
        onBeforeChange={(editor, data, newValue) => {
          this.handleChange(newValue);
        }}
      />
    );
  }
}

style

.myCodeMirror {
  .cm-begin-style {
    color: #A6E22E;
  }
  .cm-end-style {
   color: #A6E22E;
  }
}

mode嵌套

modes嵌套可以使一个mode委托工作到另一个mode。这种mode的一个例子是mixed-mode HTML mode。为了实现这种嵌套,通常需要自己创建mode对象和复制状态。创建mode对象, 这里有 CodeMirror.getMode(options, parserConfig), 其中第一个参数是传递给mode构造函数时的配置对象,第二个参数是mode选项中的mode规范。要复制一个state对象,调用 CodeMirror.copyState(mode, state), 其中 mode 是创建给定state的mode。

js

import 'codemirror/addon/mode/multiplex.js';

CodeMirror.defineMode('cert', config =>
  CodeMirror.multiplexingMode(
    CodeMirror.getMode(config, 'text/plain'),
    {
      open: '-----BEGIN CERTIFICATE-----',
      close: '-----END CERTIFICATE-----',
      mode: CodeMirror.getMode(config, 'text/plain'),
      delimStyle: 'delimit'
    },
    {
      open: '-----BEGIN RSA PRIVATE KEY-----',
      close: '-----END RSA PRIVATE KEY-----',
      mode: CodeMirror.getMode(config, 'text/plain'),
      delimStyle: 'delimit'
    }
  )
);

style

.cm-delimit {
  color: #A6E22E;
}