Scintilla 是跨平台的编辑器组件,拥有代码着色、代码折叠两大功能。该组件使用广泛,配置复杂,文档繁多。
Scintilla 允许用户自定义代码语言,通过布置关键词与样式的方式。一般可将各种配置写入xml文件,运行时读给 Scintilla ,动态创建由用户自定义的代码着色和折叠规则,无需修改底层代码。
但上述功能功效有限,无法定义类似于 Markdown 或 Python 的代码折叠规则,只好从源代码入手,自定义代码折叠。
Scintilla 有一源码名为 Lex_Markdown.cxx,虽然其中定义了一些 Markdown 的着色规则,但完全没有折叠功能。一些编辑器外壳(Notepad++、Notepad2)甚至抛弃了这个源码,致其无内置的Markdown高亮支持。
从源码入手为 Scintilla 写着色规则是痛苦的。LexHTML.cxx 行数多达两千多行,理解困难。于是暂时决定完全不理睬代码中的着色规则,先从代码中的折叠规则入手,结合用户自定义语言中的着色规则。由此简化二次开发流程。
LexNull.cxx 顾名思义就是一个空的 Lexer。LexIndent.cxx 则处理类似于 Python 的缩进语法。LexIndent.cxx 文件小,代码行数少,适合用于入门学习。
LexIndent.cxx :
static void FoldIndentDoc(Sci_PositionU startPos, Sci_Position length, int /* initStyle */, WordList *[], Accessor &styler) {
//...
===> 参数含义:startPos 当前起始位置,length 当前处理代码折叠的终末位置。
===> 通过 styler.SetLevel(哪一行, 折叠级别); 为当前处理的所有行分别设置折叠级别
}
===> 申明 Lexer 模块。参数中传入两个函数指针,
===> ColouriseIndentDoc,与 FoldIndentDoc。分别用于处理代码着色和代码折叠。
LexerModule lmIndent(SCLEX_INDENT, ColouriseIndentDoc, "indent", FoldIndentDoc);
文档 :https://www.scintilla.org/Lexer.txt
用户自定义语言的通用 Lexer 位于 LexUser.cxx:
static void FoldUserDoc(Sci_PositionU /* startPos */, Sci_Position /* length */, int /*initStyle*/, WordList *[], Accessor & /* styler */)
{
===> FoldUserDoc 完全为空。运行的时候是通过
===> 匹配配置中的关键词(比如“{”、“}”)实现代码折叠的。
}
LexerModule lmUserDefine(SCLEX_USER, ColouriseUserDoc, "user", FoldUserDoc, userDefineWordLists);
LexUser 的折叠函数完全为空。如果在其中写入与 LexIndent 的 FoldIndentDoc 函数一模一样的代码,则相关代码生效。所以,只需在这个地方调试,参考 FoldIndentDoc 函数,写出 Markdown 语法的代码折叠规则不难。
原注释:
this function will not be used in final version of the code.
it should remain commented out as it is useful for debugging purposes !!!
此函数(FoldUserDoc)不会在代码的最终版本中使用。
它应该被注释掉,因为它仅对于调试是有用的!!!
static void FoldUserDocMarkdown(Sci_PositionU startPos, Sci_Position length, int /* initStyle */
, WordList *[], Accessor &styler)
{
Sci_PositionU position=startPos
, lnEd
, lenDoc = startPos+length;
Sci_Position ln = styler.GetLine(position);
int LevelPrev=0;
int markedLevel=0;
int prevLevelMarked=styler.GetLevel(ln-1)-SC_FOLDLEVELBASE;
// 迭代所有行
for(; position<lenDoc; ln++) {
position = styler.LineStart(ln+0); // 行首
lnEd = styler.LineStart(ln+1)-1; // 行末
if(lnEd>=lenDoc) lnEd = lenDoc-1; // sanity check
markedLevel=0;
// 从行首开始,数 #
for(int i=position; i<=lnEd; i++){
if (styler[i]!='#') {
break;
}
else {
markedLevel++;
}
}
int lv = (prevLevelMarked) + SC_FOLDLEVELBASE;
if(markedLevel) lv |= SC_FOLDLEVELHEADERFLAG;
//TCHAR buffer[100]={0};
//wsprintf(buffer,TEXT("line=%d=%d"), ln, markedLevel?markedLevel:prevLevelMarked);
//::MessageBox(NULL, buffer, TEXT(""), MB_OK);
styler.SetLevel(ln, lv);
LevelPrev = markedLevel?markedLevel:prevLevelMarked;
if (markedLevel>0)
{
prevLevelMarked = markedLevel;
}
}
}

最后发现 LexUser.cxx 是notepad++的代码,原版没有。
修改后,只能说,勉强支持markdown的折叠功能。只能在标题处,即以#开始的地方折叠。能够绕过Python代码块中同样以#开始的注释行。
对比下来,果然vscode才是编辑器之王。vscode的markdown高亮、折叠功能都更加强大,支持高亮不同语言的代码块,也可以折叠代码或HTML块。
网友评论