是否有人尝试过按缩进级别创建FoldingStrategy?就像编程语言python一样。
BraceFoldingStrategy没有问题,因为您有一个固定的开始和结束标记。有人有主意为标签缩进创建这个选项卡吗?
发布于 2017-11-30 15:56:28
这里有一个主要是功能性的解决方案。我没有时间测试所有的可能性,但是有了我的几个python脚本,我已经坐着(诚然,这些脚本的格式很好),它表现得很好。我在做它的时候做了一些注释,这样当它折叠时,它就显示了行的内容。基本上,只需缓冲开始行,然后用元组或什么的开始索引将其放在堆栈中。
我确信这段代码不会正确地处理很多情况。这是你必须测试和调整的东西。代码比较幼稚,所以您也可能希望添加关键字检查,而不只是“如果它有冒号,它是一个新的折叠开始”逻辑。而且,由于我以前在折叠方面的经验,它是以一种更复杂的遍历字符的方式完成的。我尝试过其他“更容易”的方法,比如在行上运行regex检查,这可能非常非常慢。
最后,您可能希望实际使用错误偏移项,而不是像我所做的那样仅仅进行救助。这应该很容易加进去。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.AvalonEdit.Highlighting.Xshd;
using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Folding;
using System.Text.RegularExpressions;
namespace Foo.languages
{
public class TabFoldingStrategy : AbstractFoldingStrategy
{
// How many spaces == one tab
private const int SpacesInTab = 4;
/// <summary>
/// Creates a new TabFoldingStrategy.
/// </summary>
public TabFoldingStrategy() {
}
/// <summary>
/// Create <see cref="NewFolding"/>s for the specified document.
/// </summary>
public override IEnumerable<NewFolding> CreateNewFoldings(TextDocument document, out int firstErrorOffset)
{
firstErrorOffset = -1;
return CreateNewFoldingsByLine(document);
}
/// <summary>
/// Create <see cref="NewFolding"/>s for the specified document.
/// </summary>
public IEnumerable<NewFolding> CreateNewFoldingsByLine(ITextSource document)
{
List<NewFolding> newFoldings = new List<NewFolding>();
if (document == null || (document as TextDocument).LineCount <= 1)
{
return newFoldings;
}
//Can keep track of offset ourself and from testing it seems to be accurate
int offsetTracker = 0;
// Keep track of start points since things nest
Stack<int> startOffsets = new Stack<int>();
StringBuilder lineBuffer = new StringBuilder();
foreach (DocumentLine line in (document as TextDocument).Lines)
{
if (offsetTracker >= document.TextLength)
{
break;
}
lineBuffer.Clear();
// First task is to get the line and figure out the spacing in front of it
int spaceCounter = 0;
bool foundText = false;
bool foundColon = false;
//for (int i = 0; i < line.Length; i++)
int i = 0;
//TODO buffer the characters so you can have the line contents on the stack too for the folding name (display text)
while (i < line.Length && !(foundText && foundColon))
{
char c = document.GetCharAt(offsetTracker + i);
switch (c)
{
case ' ': // spaces count as one
if (!foundText) {
spaceCounter++;
}
break;
case '\t': // Tabs count as N
if (!foundText) {
spaceCounter += SpacesInTab;
}
break;
case ':': // Tabs count as N
foundColon = true;
break;
default: // anything else means we encountered not spaces or tabs, so keep making the line but stop counting
foundText = true;
break;
}
i++;
}
// before we continue, we need to make sure its a correct multiple
int remainder = spaceCounter % SpacesInTab;
if (remainder > 0)
{
// Some tabbing isn't correct. ignore this line for folding purposes.
// This may break all foldings below that, but it's a complex problem to address.
continue;
}
// Now we need to figure out if this line is a new folding by checking its tabing
// relative to the current stack count. Convert into virtual tabs and compare to stack level
int numTabs = spaceCounter / SpacesInTab; // we know this will be an int because of the above check
if (numTabs >= startOffsets.Count && foundText && foundColon)
{
// we are starting a new folding
startOffsets.Push(offsetTracker);
}
else // numtabs < offsets
{
// we know that this is the end of a folding. It could be the end of multiple foldings. So pop until it matches.
while (numTabs < startOffsets.Count)
{
int foldingStart = startOffsets.Pop();
NewFolding tempFolding = new NewFolding();
//tempFolding.Name = < could add logic here, possibly by tracking key words when starting the folding, to control what is shown when it's folded >
tempFolding.StartOffset = foldingStart;
tempFolding.EndOffset = offsetTracker - 2;
newFoldings.Add(tempFolding);
}
}
// Increment tracker. Much faster than getting it from the line
offsetTracker += line.TotalLength;
}
// Complete last foldings
while (startOffsets.Count > 0)
{
int foldingStart = startOffsets.Pop();
NewFolding tempFolding = new NewFolding();
//tempFolding.Name = < could add logic here, possibly by tracking key words when starting the folding, to control what is shown when it's folded >
tempFolding.StartOffset = foldingStart;
tempFolding.EndOffset = offsetTracker;
newFoldings.Add(tempFolding);
}
newFoldings.Sort((a, b) => (a.StartOffset.CompareTo(b.StartOffset)));
return newFoldings;
}
}
}发布于 2017-12-01 08:01:19
我认识到,AvalonEdit.TextDocument也可以使用基于行的。所以我创造了我自己的解决方案:
using System;
using System.Collections.Generic;
using ICSharpCode.AvalonEdit.Document;
namespace ICSharpCode.AvalonEdit.Folding
{
/// <summary>
/// Allows producing tab based foldings
/// </summary>
public class TabFoldingStrategy : AbstractFoldingStrategy
{
internal class TabIndent
{
public int IndentSize;
public int LineStart;
public int LineEnd;
public int StartOffset => LineStart + IndentSize - 1;
public int TextLength => LineEnd - StartOffset;
public TabIndent(int i_indentSize, int i_lineStart, int i_lineEnd)
{
IndentSize = i_indentSize;
LineStart = i_lineStart;
LineEnd = i_lineEnd;
}
}
/// <summary>
/// Creates a new TabFoldingStrategy.
/// </summary>
public TabFoldingStrategy()
{
}
/// <summary>
/// Create <see cref="NewFolding"/>s for the specified document.
/// </summary>
public override IEnumerable<NewFolding> CreateNewFoldings(TextDocument document, out int firstErrorOffset)
{
firstErrorOffset = -1;
return CreateNewFoldings(document);
}
/// <summary>
/// Create <see cref="NewFolding"/>s for the specified document.
/// </summary>
public IEnumerable<NewFolding> CreateNewFoldings(TextDocument document)
{
List<NewFolding> newFoldings = new List<NewFolding>();
int documentIndent = 0;
List<TabIndent> tabIndents = new List<TabIndent>();
foreach (DocumentLine line in document.Lines) {
int lineIndent = 0;
for (int i = line.Offset; i < line.EndOffset; i++) {
char c = document.GetCharAt(i);
if (c == '\t') {
lineIndent++;
} else {
break;
}
}
if (lineIndent > documentIndent) {
tabIndents.Add(new TabIndent(lineIndent, line.PreviousLine.Offset, line.PreviousLine.EndOffset));
} else if (lineIndent < documentIndent) {
List<TabIndent> closedIndents = tabIndents.FindAll(x => x.IndentSize > lineIndent);
closedIndents.ForEach(x => {
newFoldings.Add(new NewFolding(x.StartOffset, line.PreviousLine.EndOffset) {
Name = document.GetText(x.StartOffset, x.TextLength)
});
tabIndents.Remove(x);
});
}
documentIndent = lineIndent;
}
tabIndents.ForEach(x => {
newFoldings.Add(new NewFolding(x.StartOffset, document.TextLength));
});
newFoldings.Sort((a, b) => a.StartOffset.CompareTo(b.StartOffset));
return newFoldings;
}
}
}更新:
当有人在AvalonEdit中使用python时,我认为这也是非常有用的。用于暗主题的语法突出显示xshd:
<?xml version="1.0"?>
<SyntaxDefinition name ="Python" extensions = ".py" xmlns="http://icsharpcode.net/sharpdevelop/syntaxdefinition/2008">
<Color name="Comment" foreground="#808080" />
<Color name="String" foreground="#6A8759" />
<Color name="Keywords" foreground="#c75454" fontWeight="bold" />
<Color name="NumAndTypes" foreground="#21b0b0" />
<Color name="FunctionCall" foreground="#38a1d4" />
<Color name="Words" foreground="#8fb1ba" />
<RuleSet>
<Span color="Comment">
<Begin>\#</Begin>
</Span>
<Span color="String" multiline="true">
<Begin>'</Begin>
<End>'</End>
</Span>
<Span color="String" multiline="true">
<Begin>"</Begin>
<End>"</End>
</Span>
<!-- Digits -->
<Rule color="NumAndTypes">
\b0[xX][0-9a-fA-F]+ # hex number
|
\b0[0-9]+ # octal number
|
( \b\d+(\.[0-9]+)? #number with optional floating point
| \.[0-9]+ #or just starting with floating point
)
([eE][+-]?[0-9]+)? # optional exponent
</Rule>
<Keywords color="NumAndTypes">
<Word>False</Word>
<Word>True</Word>
<Word>None</Word>
</Keywords>
<Keywords color="Keywords">
<Word>class</Word>
<Word>finally</Word>
<Word>is</Word>
<Word>return</Word>
<Word>continue</Word>
<Word>for</Word>
<Word>lambda</Word>
<Word>try</Word>
<Word>def</Word>
<Word>from</Word>
<Word>nonlocal</Word>
<Word>while</Word>
<Word>and</Word>
<Word>del</Word>
<Word>global</Word>
<Word>not</Word>
<Word>with</Word>
<Word>as</Word>
<Word>elif</Word>
<Word>if</Word>
<Word>or</Word>
<Word>yield</Word>
<Word>assert</Word>
<Word>else</Word>
<Word>import</Word>
<Word>pass</Word>
<Word>break</Word>
<Word>except</Word>
<Word>in</Word>
<Word>raise</Word>
</Keywords>
<Rule color="FunctionCall">
\b
[\d\w_]+ # an identifier
(?=\s*\() # followed by (
</Rule>
<Rule color="Words">\w+</Rule>
</RuleSet>
</SyntaxDefinition>https://stackoverflow.com/questions/47224064
复制相似问题