背景
最近遇到一个需求是在 sql-hint提供的自动提示关键词的基础上,需要可以自定义关键词。
解析
在上一篇文章我们知道,实现自动提示的功能,需要引入下面四个js文件
require("codemirror/lib/codemirror");
require("codemirror/mode/sql/sql");
require("codemirror/addon/hint/show-hint");
require("codemirror/addon/hint/sql-hint");
这里面sql-hint是针对sql提示的js文件,我们找到它的位置并查看其源码:
源码里最开始定义的变量:tables
,defaultTable
,keywords
。tables是可以直接在options配置的hintOptions属性设置的,如果我们需要自动提示表名和表的字段:
options:{
hintOptions:{
tables:{
xxx0_table_name:[],
xxx1_table_name:['attribute_1','attribute_2']
}
}
}
而keywords自然和我们需要实现的自定义关键字有关系,搜索这个keywords,发现源码有一个方法:
function getKeywords(editor) {
var mode = editor.doc.modeOption;
if (mode === "sql") mode = "text/x-sql";
return CodeMirror.resolveMode(mode).keywords;
}
然后在registerHelper(这个是提供给外界定义提示模式配置的方法,我们也可以自己调用它)方法中,
CodeMirror.registerHelper("hint", "sql", function(editor, options) {
...
keywords = getKeywords(editor);
...
}
得出结论
这样就明显了,关键词是通过 CodeMirror.resolveMode(mode).keywords得到的。mode我自己设置的是’text/x-mariadb’, 我们打印一下CodeMirror.resolveMode(mode)这个对象看看:
let CodeMirror = require("codemirror/lib/codemirror");
console.log(CodeMirror.resolveMode("text/x-mariadb"));
打印的结果:
keywords 就是关键词的配置,可以看到,它是使用对象格式的。
实现功能
现在我们在一个常量文件里配置我们自己的关键词数组:
SQL_CUSTOM_KEYWORDS: ['xxxxxxxx'],
然后在使用编辑器的地方把它加入关键词:
constant.SQL_CUSTOM_KEYWORDS.forEach(words => {
CodeMirror.resolveMode("text/x-mariadb").keywords[words] = true;
});
附加知识
在stackoverflow有人在js-hint里自定义关键字使用这样的方式:
var orig = CodeMirror.hint.javascript;
CodeMirror.hint.javascript = function(cm) {
var inner = orig(cm) || {from: cm.getCursor(), to: cm.getCursor(), list: []};
inner.list.push("bozo");
return inner;
};
我试着将CodeMirror.hint.javascript切换为sql,自动提示列表确实出现了push的内容,不过并没有和其他关键字一样高亮,结合sql-hint源码
CodeMirror.registerHelper("hint", "sql", function(editor, options) {
......
addMatches(result, search, defaultTable, function(w) {
return objectOrClass(w, "CodeMirror-hint-table CodeMirror-hint-default-table");
});
addMatches(
result,
search,
tables, function(w) {
return objectOrClass(w, "CodeMirror-hint-table");
}
);
if (!disableKeywords)
addMatches(result, search, keywords, function(w) {
return objectOrClass(w.toUpperCase(), "CodeMirror-hint-keyword");
});
return {list: result, from: Pos(cur.line, start), to: Pos(cur.line, end)};
}
CodeMirror.hint.sql的内容看上去和registerHelper的回调方法是一件事情,只是由于直接往list里push字符串,它并不能知道是keyword还是table/default-table,所以没有高亮。