/// <summary> /// Returns a new <see cref="RegionTree"/> with the specified child added at the end. /// </summary> /// <param name="child">The child to add.</param> /// <returns>The updated <see cref="RegionTree"/>.</returns> private RegionTree AddChild(RegionTree child) { return(new RegionTree( this.Name, this.SpanStart, this.SpanEnd, this.Children.Add(child), this.IsRoot, this.ItemCollection)); }
/// <summary> /// Returns a new <see cref="RegionTree"/> with the specified child removed. /// </summary> /// <param name="childToRemove">The child to remove.</param> /// <returns>The updated <see cref="RegionTree"/>.</returns> private RegionTree RemoveChild(RegionTree childToRemove) { return(new RegionTree( this.Name, this.SpanStart, this.SpanEnd, this.Children.Remove(childToRemove), this.IsRoot, this.ItemCollection)); }
/// <summary> /// Returns a new <see cref="RegionTree"/> with <paramref name="oldChild"/> replaced with /// <paramref name="newChild"/>. /// </summary> /// <param name="oldChild">The child to be replaced.</param> /// <param name="newChild">The replacemend child.</param> /// <returns>The updated <see cref="RegionTree"/>.</returns> private RegionTree UpdateChild(RegionTree oldChild, RegionTree newChild) { return(new RegionTree( this.Name, this.SpanStart, this.SpanEnd, this.Children.Replace(oldChild, newChild), this.IsRoot, this.ItemCollection)); }
/// <summary> /// Builds a region tree from a list of <see cref="RegionDirectiveTriviaSyntax"/> and /// <see cref="EndRegionDirectiveTriviaSyntax"/> elements. Builds up the item collections with only regions. /// </summary> /// <param name="directives">The directives to build the region tree from.</param> /// <returns>The built region tree.</returns> public RegionTree Create(IEnumerator <DirectiveTriviaSyntax> directives) { var result = this; while (directives.MoveNext()) { if (directives.Current is RegionDirectiveTriviaSyntax start) { // A new region is started, so try finding sub-regions inside it. // Note that if there are more start-regions than end-regions, this will result the outermost // region being ended at the same time as the last region that was ended. var item = new TreeViewItem { IsExpanded = true }; var child = new RegionTree(start.ToString(), start.FullSpan, item.Items).Create(directives); result = result.AddChild(child); item.Header = new TreeElement( child.Name.Substring("#region ".Length), new TextSpan(child.SpanStart, child.SpanEnd - child.SpanStart), TreeImages.GetImage(ElementType.Region), regionId: child.Id) { TextColor = "#666" }; this.ItemCollection.Add(item); } else if (directives.Current is EndRegionDirectiveTriviaSyntax end) { // We return the region currently being built up with its span-end filled in. // Note that an additional endregion syntax will exit this method early, resulting in fewer regions // being returned. But that is okay, since the syntax is not correct anyway. return(result.SetSpanEnd(end.FullSpan.End)); } } // For the root, don't update the span end, it was set when creating the region. // Otherwise, there are end-region directives missing, so end the current region at the end of its // child regions (if it has any). var lastChild = result.Children.LastOrDefault(); if (result.IsRoot || lastChild == null) { return(result); } else { return(result.SetSpanEnd(lastChild.SpanEnd)); } }
/// <summary> /// Handles nesting child nodes within regions. While regions are allowed in multiple levels, /// we only use this on second level nodes. /// </summary> private static void HandleChildrenWithRegions(SyntaxNode node, ItemCollection itemCollection) { // Determine regions, so we know whether to put nodes inside the regions, or not. var startRegionDirectives = node.DescendantNodes(descendIntoTrivia: true) .OfType <RegionDirectiveTriviaSyntax>().Cast <DirectiveTriviaSyntax>() .Where(s => node.Span.Contains(s.Span)); var endRegionDirectives = node.DescendantNodes(descendIntoTrivia: true).OfType <EndRegionDirectiveTriviaSyntax>() .Where(s => node.Span.Contains(s.Span)); var regionDirectives = startRegionDirectives.Union(endRegionDirectives).OrderBy(x => x.FullSpan.Start); var regionTree = new RegionTree(node.Span, itemCollection).Create(regionDirectives.GetEnumerator()); // Insert all nodes in the region tree, this will update itemCollection. // Note that this uses an immutable structure to easily recurse over the region structure, while mutating // the mutable itemCollection as the intended side-effect. Hence the return value is not used. node.ChildNodes().Aggregate(regionTree, (current, child) => current.InsertNode(child)); }