首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >缩进AvalonEdit FoldingStrategy (Python)

缩进AvalonEdit FoldingStrategy (Python)
EN

Stack Overflow用户
提问于 2017-11-10 13:37:23
回答 2查看 1.1K关注 0票数 3

是否有人尝试过按缩进级别创建FoldingStrategy?就像编程语言python一样。

BraceFoldingStrategy没有问题,因为您有一个固定的开始和结束标记。有人有主意为标签缩进创建这个选项卡吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-11-30 15:56:28

这里有一个主要是功能性的解决方案。我没有时间测试所有的可能性,但是有了我的几个python脚本,我已经坐着(诚然,这些脚本的格式很好),它表现得很好。我在做它的时候做了一些注释,这样当它折叠时,它就显示了行的内容。基本上,只需缓冲开始行,然后用元组或什么的开始索引将其放在堆栈中。

我确信这段代码不会正确地处理很多情况。这是你必须测试和调整的东西。代码比较幼稚,所以您也可能希望添加关键字检查,而不只是“如果它有冒号,它是一个新的折叠开始”逻辑。而且,由于我以前在折叠方面的经验,它是以一种更复杂的遍历字符的方式完成的。我尝试过其他“更容易”的方法,比如在行上运行regex检查,这可能非常非常慢。

最后,您可能希望实际使用错误偏移项,而不是像我所做的那样仅仅进行救助。这应该很容易加进去。

代码语言:javascript
复制
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;
        }

    }

}
票数 7
EN

Stack Overflow用户

发布于 2017-12-01 08:01:19

我认识到,AvalonEdit.TextDocument也可以使用基于行的。所以我创造了我自己的解决方案:

代码语言:javascript
复制
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:

代码语言:javascript
复制
<?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>
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47224064

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档