美文网首页
Scintilla 自定义代码折叠,让其支持Markdown

Scintilla 自定义代码折叠,让其支持Markdown

作者: 天下第九九八十一 | 来源:发表于2021-05-01 21:36 被阅读0次

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块。

相关文章

网友评论

      本文标题:Scintilla 自定义代码折叠,让其支持Markdown

      本文链接:https://www.haomeiwen.com/subject/fenarltx.html