问题是 Scintilla 控件会自动进行折叠,这意味着如果您使用自己的词法分析器,折叠将不起作用。
如果你想看一下代码,我正在使用它来配置控件:
https://github.com/robinrodricks/ScintillaNET.Demo
这解释了如何配置代码文件夹:
https://github.com/jacobslusser/ScintillaNET/wiki/Automatic-Code-Folding
也就是说,我已经制作了自己的词法分析器,这意味着代码文件夹不起作用。有谁知道如何使其与自定义词法分析器一起使用?
我只想在
{
}
时折叠代码。
(.NET 7 Winforms C#)
你问了一个很好的问题,目前可用的信息很少。此外,您提供的链接正是寻找如何实现这一点的线索的地方。
我还建议以下内容,讨论“容器”词法分析器的折叠实现:https://github.com/LuaDist/scintilla/blob/master/doc/Lexer.txt
另一个关键来源是 ScintillaNET 源代码 https://github.com/jacobslusser/ScintillaNET,它提供了干净地实现代码折叠所需的许多变量声明。
我建议类似以下内容:
public class FoldTextControl : ScintillaNET.Scintilla
{
public FoldTextControl() : base()
{
Lexer = Lexer.Container;
SetupFolding();
}
private void SetupFolding()
{
const int FOLD_LEVEL_BASE = 0x400; // Copied from sealed ScintillaNET.NativeMethods class
const int FOLD_MARGIN = 2;
int[] FolderIndices = new int[]
{
Marker.Folder,
Marker.FolderEnd,
Marker.FolderMidTail,
Marker.FolderOpen,
Marker.FolderOpenMid,
Marker.FolderSub,
Marker.FolderTail,
}
Margins[FOLD_MARGIN].Type = MarginType.Symbol;
Margins[FOLD_MARGIN].Mask = Marker.MaskFolders;
Margins[FOLD_MARGIN].Sensitive = true;
Margins[FOLD_MARGIN].Width = 20;
foreach(int index in FolderIndices)
{
Markers[index].SetForeColor(SystemColors.ControlLightLight);
Markers[index].SetBackColor(SystemColors.ControlDark);
}
Markers[Marker.Folder].Symbol = MarkerSymbol.BoxPlus;
Markers[Marker.FolderOpen].Symbol = MarkerSymbol.BoxMinus;
Markers[Marker.FolderEnd].Symbol = MarkerSymbol.BoxPlusConnected;
Markers[Marker.FolderMidTail].Symbol = MarkerSymbol.TCorner;
Markers[Marker.FolderOpenMid].Symbol = MarkerSymbol.BoxMinusConnected;
Markers[Marker.FolderSub].Symbol = MarkerSymbol.VLine;
Markers[Marker.FolderTail].Symbol = MarkerSymbol.LCorner;
AutomaticFold = AutomaticFold.Show | AutomaticFold.Click | AutomaticFold.Change;
StyleNeeded += (sender, e) =>
{
for(int index = 0; index < Lines.Count; index++)
{
string lineText = Lines[index].Text;
Lines[index].FoldLevel = FOLD_LEVEL_BASE;
/*
Your custom code goes here to implement folding by doing the following:
Lines[index].FoldLevel += [Add a score for where this line fits in the heirachy of line folding]
if(lineText.Trim() == "")
Lines[index].FoldLevelFlags = FoldLevel.White; // Line is whitespace within the fold heirachy
if([Line should be a fold point])
Lines[index].FoldLevelFlags = FoldLevel.Header;
*/
}
};
}
}
有文档表明需要 SetProperty("fold", "1") 或 SetProperty("fold.compact", "1") 。如果没有这个,它似乎工作得很好,所以我想知道这个建议是否特定于非“容器”类型的词法分析器。
如果您需要显示正确的折叠标记,则从 FOLD_LEVEL_BASE 开始设置折叠级别至关重要。
对于 ScintillaNET 行折叠的最小可行示例,这是我用于基于空白的行折叠的示例。
StyleNeeded += (sender, e) =>
{
for(int index = 0; index < Lines.Count; index++)
{
string lineText = Lines[index].Text;
Lines[index].FoldLevel = FOLD_LEVEL_BASE;
if(lineText.Trim() == "" && !lineText.Contains(' '))
continue;
int indentLevel = lineText.TakeWhile(char.IsWhiteSpace).Count();
Lines[index].FoldLevel += indentLevel;
if(lineText.Trim() == "")
Lines[index].FoldLevelFlags = FoldLevelFlags.White;
else
Lines[index].FoldLevelFlags = FoldLevelFlags.Header;
}
};
根据您的要求,您可能需要如下内容:
StyleNeeded += (sender, e) =>
{
int indentLevel = 0;
for(int index = 0; index < Lines.Count; index++)
{
Lines[index].FoldLevel = FOLD_LEVEL_BASE + indentLevel;
string lineText = Lines[index].Text;
if(lineText.Trim() == "")
{
Lines[index].FoldLevelFlags = FoldLevelFlags.White;
continue;
}
foreach(char c in line)
{
if(c == '{')
{
indentLevel++;
Lines[index].FoldLevelFlags = FoldLevelFlags.Header;
}
else if(c == '}')
{
indentLevel--;
}
}
}
};