Пример #1
0
        private int?DesiredIndentation(int position, Builder.Node root)
        {
            var nodes = FlatPath(root, position - 1).Where(a => !(a is null))
                        .ToList();

            if (nodes.Count == 0)
            {
                return(null);
            }

            // Near the closing token.
            if (nodes.Count > 1)
            {
                var parentOfLast = nodes[nodes.Count - 2];
                var children     = parentOfLast.children;
                if (children.Count > 1)
                {
                    var last = nodes.Last();
                    if (IsClosingBracket(children.Last()) && ReferenceEquals(children[children.Count - 2], last))
                    {
                        return(IndentationLevel(nodes) - IndentationSize);
                    }
                }
            }

            // In the middle of scope.
            return(IndentationLevel(nodes));
        }
Пример #2
0
        private bool IsStringOrComment()
        {
            Builder.Node root = ParseTree.Tree.Root();
            var          notStringOrComment = true;
            var          notReached         = true;
            var          point = TextView.Caret.Position.BufferPosition;

            void Traverse(Builder.Node node)
            {
                if (node.children == null)
                {
                    if (notReached && node.begin < point.Position && node.end >= point.Position)
                    {
                        if (node.name == "Comment" || (node.name == "String" && node.end != point.Position))
                        {
                            notStringOrComment = false;
                        }

                        notReached = false;
                        return;
                    }

                    return;
                }

                foreach (var child in node.children)
                {
                    Traverse(child);
                }
            }

            Traverse(root);

            return(!notStringOrComment);
        }
Пример #3
0
        private void Notify(Builder.Node node)
        {
            this.last = node;

            var snapshot = new SnapshotSpan(textView.TextBuffer.CurrentSnapshot, 0, textView.TextBuffer.CurrentSnapshot.Length);

            TagsChanged?.Invoke(this, new SnapshotSpanEventArgs(snapshot));
        }
Пример #4
0
        public static bool IsName(this Builder.Node node)
        {
            if (node is null)
            {
                throw new ArgumentNullException(nameof(node));
            }

            return(node.name == "Name");
        }
Пример #5
0
        // [Figure.1] Example structure of nodes, SelectSets and ExpressionParsingContext (EPC)
        //=============================================================================================================================================================
        // Node                 | SelectSet                  | Node 0     | Node 0_0      | Node 0_0_0    | Node 0_0_1    | Node 0_1      | Node 0_1_0    | Node 0_1_1
        //-------------------------------------------------------------------------------------------------------------------------------------------------------------
        //   + Node 0
        //   |                    localSelectSet               EPC.row=-1   EPC.row=-1      EPC.row=-1      EPC.row-1       EPC.row=-1      EPC.row=-1      EPC.row=-1
        //   |                                                  /|\          /|\             /|\             /|\             /|\             /|\             /|\
        //   |                                                   |            |               |               |               |               |               |
        //   |                    dataSelectSet                EPC.row=-1   EPC.row=0       EPC.row=0       EPC.row=0       EPC.row=1       EPC.row=1       EPC.row=1
        //   |                                                               /|\             /|\             /|\             /|\             /|\             /|\
        //   |-+ Node 0_0                                                     |               |               |               |               |               |
        //   | |                  localSelectSet                            EPC.row=-1      EPC.row=-1      EPC.row=-1        |               |               |
        //   | |                                                             /|\             /|\             /|\              |               |               |
        //   | |                                                              |               |               |               |               |               |
        //   | |                  dataSelectSet                             EPC.row=-1      EPC.row=0       EPC.row=1         |               |               |
        //   | |                                                                             /|\             /|\              |               |               |
        //   | |- Node 0_0_0                                                                  |               |               |               |               |
        //   | |                  localSelectSet                                            EPC.row=-1        |               |               |               |
        //   | |                                                                             /|\              |               |               |               |
        //   | |                                                                              |               |               |               |               |
        //   | |                  dataSelectSet                                             EPC.row=-1        |               |               |               |
        //   | |                                                                                              |               |               |               |
        //   | |- Node 0_0_1                                                                                  |               |               |               |
        //   |                                                                                                |               |               |               |
        //   |                    localSelectSet                                                            EPC.row=-1        |               |               |
        //   |                                                                                               /|\              |               |               |
        //   |                                                                                                |               |               |               |
        //   |                    dataSelectSet                                                             EPC.row=-1        |               |               |
        //   |                                                                                                                |               |               |
        //   |-+ Node 0_1                                                                                                     |               |               |
        //     |                  localSelectSet                                                                            EPC.row=-1      EPC.row=-1      EPC.row=-1
        //     |                                                                                                             /|\             /|\             /|\
        //     |                                                                                                              |               |               |
        //     |                  dataSelectSet                                                                             EPC.row=-1      EPC.row=0       EPC.row=1
        //     |                                                                                                                             /|\             /|\
        //     |- Node 0_1_0                                                                                                                  |               |
        //     |                  localSelectSet                                                                                              |               |
        //     |                                                                                                                            EPC.row=-1        |
        //     |                                                                                                                             /|\              |
        //     |                  dataSelectSet                                                                                               |               |
        //     |                                                                                                                            EPC.row=-1        |
        //     |- Node 0_1_1                                                                                                                                  |
        //                        localSelectSet                                                                                                              |
        //                                                                                                                                                  EPC.row=-1
        //                                                                                                                                                   /|\
        //                        dataSelectSet                                                                                                               |
        //                                                                                                                                                  EPC.row=-1
        //=============================================================================================================================================================
        //
        //  Using this structure, name look-up are prioritized in this order:
        //==========================================================================
        //    Node         |  Select Set               |  Data used from select set
        //--------------------------------------------------------------------------
        //    Node 0
        //                    Node0.dataSelectSet         all
        //                    Node0.localSelectSet        all
        //    Node 0_0
        //                    Node0_0.dataSelectSet       all
        //                    Node0_0.localSelectSet      all
        //                    Node0.dataSelectSet         row 0
        //                    Node0.localSelectSet        all
        //    Node 0_1:
        //                    Node0_1.dataSelectSet       all
        //                    Node0_1.localSelectSet      all
        //                    Node0.dataSelectSet         row 1
        //                    Node0.localSelectSet        all
        //    Node 0_0_0
        //                    Node0_0_0.dataSelectSet     all
        //                    Node0_0_0.localSelectSet    all
        //                    Node0_0.dataSelectSet       row 0
        //                    Node0_0.localSelectSet      all
        //                    Node0.dataSelectSet         row 0
        //                    Node0.localSelectSet        all
        //    Node 0_0_1
        //                    Node0_0_1.dataSelectSet     all
        //                    Node0_0_1.localSelectSet    all
        //                    Node0_0.dataSelectSet       row 1
        //                    Node0_0.localSelectSet      all
        //                    Node0.dataSelectSet         row 0
        //                    Node0.localSelectSet        all
        //    Node 0_1_0
        //                    Node0_1_0.dataSelectSet     all
        //                    Node0_1_0.localSelectSet    all
        //                    Node0_1.dataSelectSet       row 0
        //                    Node0_1.localSelectSet      all
        //                    Node0.dataSelectSet         row 1
        //                    Node0.localSelectSet        all
        //    Node 0_1_1
        //                    Node0_1_1.dataSelectSet     all
        //                    Node0_1_1.localSelectSet    all
        //                    Node0_1.dataSelectSet       row 1
        //                    Node0_1.localSelectSet      all
        //                    Node0.dataSelectSet         row 1
        //                    Node0.localSelectSet        all
        //==========================================================================


        public ViewTable(ViewSchema viewSchema, Schema baseSchema, Builder.Node node, ExpressionParsingContext parentExpressionParsingContext)
            : base(viewSchema)
        {
            this.ViewSchema                = viewSchema;
            this.BaseSchema                = baseSchema;
            this.node                      = node;
            ExpressionParsingContext       = parentExpressionParsingContext;
            ParentExpressionParsingContext = parentExpressionParsingContext;
        }
Пример #6
0
        private void TraverseEdit(Builder.Node node)
        {
            if (node.children == null)
            {
                AddDelimeter(node);
                return;
            }

            foreach (var child in node.children)
            {
                TraverseEdit(child);
            }
        }
Пример #7
0
        // Gives {parent-of-the-next-item, ..., parent-of-the-last-item, last-item}
        public static IEnumerable <Builder.Node> FlatPath(Builder.Node node, int position)
        {
            var tree = node;

            while (!(tree is null) && !IsEmpty(tree.children))
            {
                // We do not check the result of Parent, so the last item can be null, or terminal.
                tree = Parent(tree, position);
                yield return(tree);
            }

            bool IsEmpty(IEnumerable <Builder.Node> a) =>
            a is null || !a.Any();
        }
Пример #8
0
        public static Builder.Node LabelName(this Builder.Node node)
        {
            if (node is null)
            {
                throw new ArgumentNullException(nameof(node));
            }

            Debug.Assert(node.children.Any());

            var name = node.children.First();

            Debug.Assert(name.name == "Name");

            return(name);
        }
Пример #9
0
        /// <summary> Searches the node which holds a text at given position. </summary>
        /// <param name="node"></param>
        /// <param name="position"></param>
        /// <returns>
        /// Returns the child of the node, which contains the text,
        /// or contains other sub-node which contains the text, or other sub-node which...
        /// </returns>
        public static Builder.Node Parent(Builder.Node node, int position)
        {
            // Standard binary search works only with the items with the same type,
            // i.e. collection and item must have the same base type.
            // So, we workaround it by wrapping our item in the type of the collection's elements.
            // And then we use comparer specially prepared for the workaround.
            var idx = node.children.BinarySearch(new Builder.Node {
                begin = position
            },
                                                 new Comparer());

            return(idx < 0
             ? null
             : node.children[idx]);
        }
Пример #10
0
 private void AddIndentation(Builder.Node currentToken)
 {
     if (lastToken.end <= selectionEnd && currentToken.begin >= selectionBegin && (lastToken.name == "CRLF" || lastToken.name == "LF" || isFirstToken))
     {
         var    beginLine       = TextView.TextBuffer.CurrentSnapshot.GetLineFromPosition(selectionBegin);
         var    changeSpanBegin = Math.Max(lastToken.end, beginLine.Start.Position);
         var    endLine         = TextView.TextBuffer.CurrentSnapshot.GetLineFromPosition(selectionEnd - 1);
         var    changeSpanEnd   = Math.Min(currentToken.begin, endLine.End.Position);
         string oldDelimeter    = rawSource.Substring(changeSpanBegin, Math.Abs(changeSpanEnd - changeSpanBegin));
         var    newDelimeter    = new string(indentationCharacter, bracketsStack.Count *indentationSize);
         if (newDelimeter != oldDelimeter)
         {
             EditInsert(changeSpanBegin, oldDelimeter, newDelimeter);
         }
     }
 }
Пример #11
0
        /// <summary>Gives an outermost node which holds a text at given position.</summary>
        /// <returns>
        /// The sub-node which holds a text at the <paramref name="position"/>.
        /// <para/>
        /// Or <c>null</c>, if the <paramref name="node"/> has no such a sub-node.
        /// </returns>
        public static Builder.Node OldestAncestor(this Builder.Node node, int position)
        {
            if (node is null)
            {
                throw new ArgumentNullException(nameof(node));
            }

            var idx = node.children.BinarySearch(new Builder.Node {
                begin = position
            },
                                                 new Comparer());

            return
                (idx < 0
        ? null
        : node.children[idx]);
        }
Пример #12
0
        private bool findDefinition()
        {
            ParseTree.Builder.Node root = ParseTree.Tree.Root();
            bool definitionFound        = false;

            void Traverse(Builder.Node node)
            {
                if (node.children == null)
                {
                    return;
                }

                if ((node.name == "Code" || node.name == "Object" || node.name == "List") && node.end < selectionEnd)
                {
                    return;
                }

                if (node.name == "Label")
                {
                    Builder.Node child = node.children[0];
                    currName = TextView.TextBuffer.CurrentSnapshot.GetText(child.begin, child.end - child.begin);
                    if (currName == selectedName)
                    {
                        definitionBegin = child.begin;
                        definitionEnd   = child.end;
                        definitionFound = true;
                    }
                }

                foreach (var child in node.children)
                {
                    if (child.begin < selectionEnd)
                    {
                        Traverse(child);
                    }
                }
            }

            Traverse(root);

            return(definitionFound);
        }
Пример #13
0
        /// <summary>Gives <c>(oldest-ancestor ... ancestor-of-youngest-ancestor youngest-ancestor)</c>.</summary>
        /// <param name="node">Node which holds the text at the <paramref name="position"/>.</param>
        /// <param name="position">Position in a text for which is needed to find the ancestors.</param>
        /// <returns>An empty generator if the <paramref name="node"/> holds no such a sub-nodes.</returns>
        public static IEnumerable <Builder.Node> AllAncestors(this Builder.Node node, int position)
        {
            Debug.Assert(position >= 0);

            var tree = node ?? throw new ArgumentNullException(nameof(node));

            while (IsNotEmpty(tree))
            {
                tree = tree.OldestAncestor(position);

                if (tree is null)
                {
                    yield break;
                }

                yield return(tree);
            }

            bool IsNotEmpty(Builder.Node treeNode) =>
            !(treeNode.children is null) && treeNode.children.Any();
        }
Пример #14
0
 public static bool IsScopeEnd(this Builder.Node node) =>
 node.name == "']'" || node.name == "'}'" || node.name == "')'" || node.name == "';'";
Пример #15
0
 public static bool IsScopeStart(this Builder.Node node) =>
 node.name == "'['" || node.name == "'{'" || node.name == "'('" || node.name == "':'";
Пример #16
0
 public static bool IsScope(this Builder.Node node) =>
 node.name == "Object" || node.name == "Code" || node.name == "List" || node.IsLabel();
Пример #17
0
 public static Builder.Node OldestAncestor(this Builder.Node node, int start, int end) =>
 node.AllAncestors(start, end).FirstOrDefault();
Пример #18
0
 public static IEnumerable <Builder.Node> AllAncestors(this Builder.Node node, int start, int end) =>
 node.AllAncestors(start).TakeWhile(a => a.end >= end);
Пример #19
0
        protected override bool Execute(VSConstants.VSStd2KCmdID command, uint options, IntPtr pvaIn, IntPtr pvaOut)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            lastToken = new Builder.Node {
                line = 0
            };
            currentLevelBrackets = new Stack <Builder.Node>();
            bracketsStack        = new Stack <Stack <Builder.Node> >();
            edit     = TextView.TextBuffer.CreateEdit();
            wasPoped = false;
            switch (MplPackage.Options.LineEndings)
            {
            case Options.LineEnding.Unix:
                leaveAsIs  = false;
                lineEnding = "\n";
                break;

            case Options.LineEnding.Windows:
                leaveAsIs  = false;
                lineEnding = "\r\n";
                break;

            case Options.LineEnding.Document:
                leaveAsIs = true;
                break;
            }

            if (TextView.Options.IsConvertTabsToSpacesEnabled())
            {
                indentationCharacter = ' ';
                indentationSize      = TextView.Options.GetIndentSize();
            }
            else
            {
                indentationCharacter = '\t';
                indentationSize      = 1;
            }

            selectionBegin = 0;
            selectionEnd   = TextView.TextBuffer.CurrentSnapshot.Length;
            rawSource      = TextView.TextBuffer.CurrentSnapshot.GetText();
            caretPoint     = TextView.Caret.Position.Point.GetPoint(TextView.TextBuffer, TextView.Caret.Position.Affinity);
            switch (command)
            {
            case VSConstants.VSStd2KCmdID.FORMATDOCUMENT:
                break;

            case VSConstants.VSStd2KCmdID.FORMATSELECTION:
                if (!TextView.Selection.IsEmpty && caretPoint != null)
                {
                    selectionBegin = TextView.Selection.Start.Position.Position;
                    selectionEnd   = TextView.Selection.End.Position.Position;
                }
                else if (TextView.Selection.IsEmpty && caretPoint != null)
                {
                    var line = TextView.TextBuffer.CurrentSnapshot.GetLineFromPosition(caretPoint.Value.Position);
                    selectionBegin = line.Start.Position;
                    selectionEnd   = line.End.Position;
                }

                break;
            }

            GetFormattedProgram();
            if (valid)
            {
                edit.Apply();
            }

            edit.Dispose();
            return(true);
        }
Пример #20
0
 public static Builder.Node YongestAncestor(this Builder.Node node, int position) =>
 node.AllAncestors(position).LastOrDefault();
Пример #21
0
 private static bool IsOpeningBracket(Builder.Node a) => starts.Contains(a.name);
Пример #22
0
        private int?DesiredIndentation(int position, Builder.Node root)
        {
            var ancestors = Utils.AllAncestors(root, position - 1).ToList();

            if (!ancestors.Any())
            {
                return(null);
            }

            // TODO: Revise this explanation.
            // If at the right side of a caret is a closing symbol ) ; ] }
            // then indentation must be less than indentation of current block.
            //
            // In the beginning of this method, in the left side of a caret always will be a new-line character.
            // But it doesn't mean that it will be a new-line symbol.
            // For example, if caret placed inside a string, then this new-line character will be a part of a string,
            // but not the new-line symbol like LF or CRLF.
            // So, there are two possible situations:
            //   a) \n caret a-closing-symbol
            //   b) \n caret not-a-closing-symbol
            // And the \n can be: the part of a string; a new-line symbol.
            // So finally we can have 4 different situations:
            // 1) Code: \n|      Parse-tree: \n       Ancestors: (\n)
            //
            // 2) Code: (\n|)    Parse-tree: list     Ancestors: (list \n)
            //                               / | \
            //                              ( \n  )
            //
            // 3) Code: ("\n|")  Parse-tree:  list    Ancestors: (list string)
            //                              /   |  \
            //                             ( string )
            //
            // 4) Code: (\n|...) Parse-tree: list     Ancestors: (list \n)
            //                              / | | \
            //                             ( \n ... )
            //
            // Here, we interested only in 2nd case (\n|).
            // For it, Ancestors will return (list \n) and for much complicated code it will return (... list \n).
            // In this sequence of symbols (list \n), the list will contain the closing bracket as the last child.
            // And instead of the list, there can be object, code, or label.
            // But the Ancestors will return similar elements for 2nd and 4th cases, it will be (list \n),
            // so we must check the parse-tree, if it is contains something between caret and closing brace.
            if (ancestors.Count > 1)
            {
                var last         = ancestors.Last();
                var parentOfLast = ancestors[ancestors.Count - 2];
                var children     = parentOfLast.children;
                if (last.IsEol())
                {
                    if (children.Count > 1)
                    {
                        if (children.Last().IsScopeEnd())
                        {
                            // Check if the closing bracket and a caret at the same line,
                            // and between them stands nothing except tabs/spaces.
                            if (ReferenceEquals(children[children.Count - 2], last))
                            {
                                return(IndentationLevel(ancestors) - IndentationSize);
                            }
                        }
                    }
                }

                // If it is not the end-of-line, then it should be a string.
                // TODO: What should we do if a caret placed inside of a string?
            }

            // In the middle of scope.
            return(IndentationLevel(ancestors));
        }
Пример #23
0
 public static bool IsLabel(this Builder.Node node) =>
 node.name == "Label";
Пример #24
0
 public static bool IsEol(this Builder.Node node) =>
 node.name == "LF" || node.name == "CRLF" || node.name == "CR";
Пример #25
0
 private bool IsClosingBracket(Builder.Node a) => ends.Contains(a.name);
Пример #26
0
 public static bool IsEof(this Builder.Node node) =>
 node.name == "EOF";
Пример #27
0
        private void AddDelimeter(Builder.Node currentToken)
        {
            switch (currentToken.name)
            {
            case "EOF":
                if (lastToken.name != "CRLF" && lastToken.name != "LF")
                {
                    if (rawSource.Substring(lastToken.end) != lineEnding && currentToken.end == selectionEnd)
                    {
                        edit.Delete(lastToken.end, rawSource.Length - lastToken.end);
                        edit.Insert(lastToken.end, lineEnding);
                    }
                }
                else
                {
                    if (rawSource.Substring(lastToken.end) != lineEnding && currentToken.end == selectionEnd)
                    {
                        edit.Delete(lastToken.end, rawSource.Length - lastToken.end);
                    }
                }

                return;

            case "']'":
            case "'}'":
            case "')'":
            case "';'":
                if (currentLevelBrackets.Count == 0 && bracketsStack.Count > 0 && bracketsStack.Peek().Count != 0)
                {
                    if (currentToken.line == bracketsStack.Peek().Peek().line)
                    {
                        bracketsStack.Peek().Pop();
                        if (wasPoped)
                        {
                            currentLevelBrackets = bracketsStack.Pop();
                            wasPoped             = false;
                        }
                        else if (bracketsStack.Peek().Count == 0)
                        {
                            bracketsStack.Pop();
                        }
                    }
                    else
                    {
                        currentLevelBrackets = bracketsStack.Pop();
                        currentLevelBrackets.Pop();
                    }
                }
                else if (currentLevelBrackets.Count > 0)
                {
                    currentLevelBrackets.Pop();
                }
                else if (bracketsStack.Count > 0 && bracketsStack.Peek().Count == 0)
                {
                    bracketsStack.Pop();
                }

                AddIndentation(currentToken);
                break;

            case "CRLF":
                if (currentToken.end <= selectionEnd && currentToken.end >= selectionBegin)
                {
                    if (lastToken.end != currentToken.begin)
                    {
                        edit.Delete(lastToken.end, currentToken.begin - lastToken.end);
                    }

                    if (lineEnding != "\r\n" && !leaveAsIs)
                    {
                        EditInsert(currentToken.begin, "\r\n", lineEnding);
                    }
                }

                break;

            case "LF":
                if (currentToken.end <= selectionEnd && currentToken.end >= selectionBegin)
                {
                    if (lastToken.end != currentToken.begin)
                    {
                        edit.Delete(lastToken.end, currentToken.begin - lastToken.end);
                    }

                    if (lineEnding != "\n" && !leaveAsIs)
                    {
                        EditInsert(currentToken.begin, "\n", lineEnding);
                    }
                }

                break;

            default:
                AddIndentation(currentToken);
                break;
            }

            if (currentToken.IsScopeStart())
            {
                if (bracketsStack.Count == 0 && currentLevelBrackets.Count == 0)
                {
                    bracketsStack.Push(new Stack <Builder.Node>());
                    bracketsStack.Peek().Push(currentToken);
                }
                else if (bracketsStack.Count != 0 && bracketsStack.Peek().Peek().line == currentToken.line)
                {
                    bracketsStack.Peek().Push(currentToken);
                }
                else if (currentLevelBrackets.Count != 0)
                {
                    bracketsStack.Push(new Stack <Builder.Node>(currentLevelBrackets));
                    currentLevelBrackets.Clear();
                    bracketsStack.Peek().Push(currentToken);
                    wasPoped = true;
                }
                else
                {
                    bracketsStack.Push(new Stack <Builder.Node>());
                    bracketsStack.Peek().Push(currentToken);
                }
            }

            lastToken = currentToken;

            if (isFirstToken)
            {
                isFirstToken = !isFirstToken;
            }
        }