public void NodeFromRangeTest() { AstRoot ast = RParser.Parse(new TextStream(" x <- a123+b")); IAstNode node = ast.NodeFromRange(new TextRange(2, 5)); node.Should().BeAssignableTo <IOperator>(); node = ast.NodeFromRange(new TextRange(7, 2)); node.Should().BeOfType <Variable>(); }
/// <summary> /// Removes nodes from the tree collection if node range is partially or entirely /// within the deleted region. This is needed since parsing is asynchronous and /// without node removal intellisense and syntax checker may end up processing /// nodes that are out of date. Where possible stops at the nearest scope level /// so scope nodes may still be used in smart indenter. /// </summary> /// <param name="range">Range to invalidate elements in</param> internal bool InvalidateInRange(ITextRange range) { var removedElements = new List <IAstNode>(); int firstToRemove = -1; int lastToRemove = -1; var node = AstRoot.NodeFromRange(range); var scope = node as IScope; while (scope == null || scope.OpenCurlyBrace == null || scope.CloseCurlyBrace == null || TextRange.Intersect(range, scope.OpenCurlyBrace) || TextRange.Intersect(range, scope.CloseCurlyBrace)) { scope = node.GetEnclosingScope(); if (scope is GlobalScope) { break; } node = scope; } for (int i = 0; i < scope.Children.Count; i++) { var child = scope.Children[i]; if (TextRange.Intersect(range, child)) { if (firstToRemove < 0) { firstToRemove = i; } else { lastToRemove = i; } } } if (firstToRemove >= 0) { if (lastToRemove < 0) { lastToRemove = firstToRemove; } for (int i = firstToRemove; i <= lastToRemove; i++) { IAstNode child = scope.Children[i]; removedElements.Add(child); _astRoot.Errors.RemoveInRange(child); } scope.RemoveChildren(firstToRemove, lastToRemove - firstToRemove + 1); } if (removedElements.Count > 0) { FireOnNodesRemoved(removedElements); return(true); } return(false); }