CodeMirror 是什么

CodeMirror 是通过 JavaScript 实现的文本编辑器。专门用于编辑代码,带有大量的语言模式和实现更高级的插件功能。

拥有丰富的编程 API 和 CSS 主题化系统可用于定制 CodeMirror ,使它更适合你的应用和扩展新功能。

使用 CodeMirror

首先我们来看下一个最基础的示例,展示一个代码编辑器。

首先我们创建一个 index.html,并通过 npm 或直接将 CodeMirror 安装到项目里,这里使用 npm 安装。

  1. npm install --save codemirror

安装完毕,在页面中引入即可,如下代码即可实现一个最基础的代码编辑器。

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Document</title>
  6. <link rel="stylesheet" href="./node_modules/codemirror/lib//codemirror.css">
  7. <script src="./node_modules/codemirror/lib//codemirror.js"></script>
  8. </head>
  9. <body>
  10. <textarea id="root"></textarea>
  11. <script>
  12. var editor = CodeMirror.fromTextArea(document.getElementById('root'), {
  13. lineNumbers: true, // 显示行号
  14. });
  15. </script>
  16. </body>
  17. </html>

支持 SQL

我们的目标是实现支持 SQL 体验的代码编辑器,那么接下来我们就来配置 SQL。

引入 Mode

上述提到 CodeMirror 支持非常多的语言 mode,要让它识别并高亮 SQL 的话,就要引入 sql 的 mode。

  1. <!-- 添加 SQL mode -->
  2. <script src="./node_modules/codemirror/mode/sql/sql.js"></script>

到这里我们在编辑器中输入 SELECT * FROM TABLE; ,可以看到代码编辑器已经可以正确的关键字高亮展示了。

接下来我们再来完善下代码编辑器的体验,让它支持括号匹配、自动补全等。

括号匹配

  1. <!--括号匹配-->
  2. <script src="./node_modules/codemirror/addon/edit/matchbrackets.js"></script>

引入对应的插件之后,在传入的配置项中添加 matchBrackets:true 即可开启括号匹配。

自动补全

引入智能提示相关插件。

  1. <!--自动补全-->
  2. <link rel="stylesheet" href="./node_modules/codemirror/addon/hint/show-hint.css">
  3. <script src="./node_modules/codemirror/addon/hint/show-hint.js"></script>
  4. <script src="./node_modules/codemirror/addon/hint/sql-hint.js"></script>
  1. /**
  2. * 忽略自动提示的 token
  3. */
  4. const ignore = ['', '#', '!', '-', '=', '@', '$', '%', '&', '+', ';', '(', ')', '*'];
  5. const ignoreToken = (text) => {
  6. if (text && text[0]) {
  7. for (const pre in ignore) {
  8. if (ignore[pre] === text[0]) {
  9. return true;
  10. }
  11. }
  12. } else {
  13. return true;
  14. }
  15. return false;
  16. };
  17. editor.on("change", function (editor, change) {
  18. if (change.origin == "+input") {
  19. var text = change.text;
  20. //不提示
  21. if (!ignoreToken(text))
  22. setTimeout(function () {
  23. editor.execCommand("autocomplete");
  24. }, 20);
  25. }
  26. });

完整的代码如下

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Document</title>
  6. <link rel="stylesheet" href="./node_modules/codemirror/lib//codemirror.css">
  7. <script src="./node_modules/codemirror/lib//codemirror.js"></script>
  8. <!-- 添加 SQL mode -->
  9. <script src="./node_modules/codemirror/mode/sql/sql.js"></script>
  10. <!--括号匹配-->
  11. <script src="./node_modules/codemirror/addon/edit/matchbrackets.js"></script>
  12. <!--自动补全-->
  13. <link rel="stylesheet" href="./node_modules/codemirror/addon/hint/show-hint.css">
  14. <script src="./node_modules/codemirror/addon/hint/show-hint.js"></script>
  15. <script src="./node_modules/codemirror/addon/hint/sql-hint.js"></script>
  16. </head>
  17. <body>
  18. <textarea id="root"></textarea>
  19. <script>
  20. var editor = CodeMirror.fromTextArea(document.getElementById('root'), {
  21. mode: 'text/x-mysql',
  22. lineNumbers: true,
  23. matchBrackets: true,
  24. hintOptions: {
  25. tables: {
  26. table1: ['name', 'score', 'birthDate'],
  27. table2: ['name', 'population', 'size']
  28. }
  29. }
  30. });
  31. /**
  32. * 忽略自动提示的token
  33. */
  34. const ignore = ['', '#', '!', '-', '=', '@', '$', '%', '&', '+', ';', '(', ')', '*'];
  35. const ignoreToken = (text) => {
  36. if (text && text[0]) {
  37. for (const pre in ignore) {
  38. if (ignore[pre] === text[0]) {
  39. return true;
  40. }
  41. }
  42. } else {
  43. return true;
  44. }
  45. return false;
  46. };
  47. editor.on("change", function (editor, change) {//任意键触发autocomplete
  48. if (change.origin == "+input") {
  49. var text = change.text;
  50. if (!ignoreToken(text))//不提示
  51. setTimeout(function () { editor.execCommand("autocomplete"); }, 20);
  52. }
  53. });
  54. </script>
  55. </body>
  56. </html>

通过以上的配置,我们在输入 SQL 语句的时候,已经可以看到有自动提示补全代码功能了,那么如果我们一般的 SQL 输入需求是基于相关的数据库信息来进行提示的,以上默认的提示信息已经无法满足我们的需求了。那么接下来我们来看下自定义的智能提示该如何实现。

自定义 hint

CodeMirror 提供的 SQL 提示已经可以满足大部分场景了,但业务的高要求,我们还是要继续提升用户的体验。如支持数据库、表名、字段名的只能提示,默认的 sql-hint 已经无法满足需求了,基于此我们可以替换默认的 sql-hint 或者自定义一个 hint 来满足我们的需求。

CodeMirror 提供了一个静态方法来支持自定义 hint 功能。

  1. CodeMirror.registerHelper('hint', 'custom', function (editor, options) {
  2. return {
  3. list: ['custom-hint'],
  4. from: CodeMirror.Pos(cur.line, curr.start),
  5. to: CodeMirror.Pos(cur.line, curr.end),
  6. };
  7. });

以上可以看到一个最简单的自定义 hint 完成了。基于此,我们可基于editor 提供的 getValue 方法,获取当前的 token,再通过分析返回我们想要的自定义值即可达到更好的智能提示效果了。

参考