static IEnumerable <TextSpan> GetCommentSpans(this XContainer node, IEnumerable <TextSpan> selectedSpans, bool returnComments) { var commentSpans = new List <TextSpan> (); // First unify, normalize and deduplicate syntactic spans since multiple selections can result // in a single syntactic span to be commented var regions = new List <Span> (); foreach (var selectedSpan in selectedSpans) { var region = node.GetValidCommentRegion(selectedSpan); regions.Add(region.ToSpan()); } var normalizedRegions = new NormalizedSpanCollection(regions); // Then for each region cut out the existing comments that may be inside foreach (var currentRegion in normalizedRegions) { int currentStart = currentRegion.Start; // Creates comments such that current comments are excluded var parentNode = node.GetNodeContainingRange(currentRegion.ToTextSpan()); parentNode.VisitSelfAndDescendents(child => { if (child is XComment comment) { // ignore comments outside our range if (!currentRegion.IntersectsWith(comment.Span.ToSpan())) { return; } var commentNodeSpan = comment.Span; if (returnComments) { commentSpans.Add(commentNodeSpan); } else { var validCommentSpan = TextSpan.FromBounds(currentStart, commentNodeSpan.Start); if (validCommentSpan.Length != 0) { commentSpans.Add(validCommentSpan); } currentStart = commentNodeSpan.End; } } }); if (!returnComments) { if (currentStart <= currentRegion.End) { var remainingCommentSpan = TextSpan.FromBounds(currentStart, currentRegion.End); if (remainingCommentSpan.Equals(currentRegion) || remainingCommentSpan.Length != 0) { // Comment any remaining uncommented area commentSpans.Add(remainingCommentSpan); } } } } return(commentSpans.Distinct()); }