public static void GetClassifications(SyntaxNode root, int start, int length, bool clipToRange, List <ClassifiedRange> list, CancellationToken cancellationToken) { var end = start + length; // don't let classification ranges escape the requested bounds. Action <ClassifiedRange> limiter = range => { // only if the classification range overlaps window if (range.End > start && range.Start < end) { // adjust range it if starts before or ends after the window if (clipToRange && (range.Start < start || range.End > end)) { var clipStart = Math.Max(range.Start, start); var clipEnd = Math.Min(range.End, end); range = new ClassifiedRange(range.Kind, clipStart, clipEnd - clipStart); } // merge ranges if this range is adjacent to the last range and the same kind if (list.Count > 0) { var last = list[list.Count - 1]; if (last.Kind == range.Kind && last.End == range.Start) { list[list.Count - 1] = new ClassifiedRange(last.Kind, last.Start, last.Length + range.Length); return; } } list.Add(range); } }; // produce classification ranges for all tokens that coincide with the window root.WalkTokens(start, end, token => { cancellationToken.ThrowIfCancellationRequested(); GetTriviaClassifications(token, limiter); if (token.IsLiteral && token.Prefix.Length > 0) { // special case for literals with prefix limiter(new ClassifiedRange(ClassificationKind.Keyword, token.TextStart, token.Prefix.Length)); limiter(new ClassifiedRange(ClassificationKind.Literal, token.TextStart + token.Prefix.Length, token.Text.Length - token.Prefix.Length)); } else { var kind = GetKind(token); limiter(new ClassifiedRange(kind, token.TextStart, token.Width)); } }); }
/// <summary> /// Add the two classification ranges together. /// If any overlap, classifications from <see cref="P:classifications2"/> take precedence. /// </summary> protected static IReadOnlyList <ClassifiedRange> Add( IReadOnlyList <ClassifiedRange> classifications1, IReadOnlyList <ClassifiedRange> classifications2) { if (classifications2.Count == 0) { return(classifications1); } if (classifications1.Count == 0) { return(classifications2); } var list = new List <ClassifiedRange>(classifications1.Count + classifications2.Count); int index1 = 0; int index2 = 0; ClassifiedRange class1 = null; ClassifiedRange class2 = null; while (true) { if (class1 == null && index1 < classifications1.Count) { class1 = classifications1[index1]; } if (class2 == null && index2 < classifications2.Count) { class2 = classifications2[index2]; } if (class1 == null && class2 == null) { // we are done break; } else if (class1 != null && class2 == null) { // no more class2, just add class1 list.Add(class1); class1 = null; index1++; } else if (class2 != null && class1 == null) { // no more class1, just add class2 list.Add(class2); class2 = null; index2++; } else if (class1.End < class2.Start) { // class1 is entirely before class2, so add class1 and advance it list.Add(class1); class1 = null; index1++; } else if (class2.End < class1.Start) { // class2 is entirely before classs1, so add class2 and advance it list.Add(class2); class2 = null; index2++; } else if (class1.Start >= class2.Start && class1.End <= class2.End) { // class1 is entirely within class2 // drop class1 because class2 takes precedence class1 = null; index1++; } else if (class1.Start < class2.Start) { // class1 starts before class2 var len = class2.Start - class1.Start; // add the first part off class1 list.Add(new ClassifiedRange(class1.Kind, class1.Start, len)); if (class1.Length > len) { // adjust class1 for next time around class1 = new ClassifiedRange(class1.Kind, class1.Start + len, class1.Length - len); } else { // advance class1 if no more class1 = null; index1++; } } else if (class2.Start < class1.Start) { // class2 starts before class1 var len = class1.Start - class2.Start; // add the first part of class2 list.Add(new ClassifiedRange(class2.Kind, class2.Start, len)); if (class2.Length > len) { class2 = new ClassifiedRange(class2.Kind, class2.Start + len, class2.Length - len); } else { // advance class2 if no more class2 = null; index2++; } } else if (class1.End <= class2.End) { // both start at same position, class1 ends first // just drop class1, since class2 takes precedence class1 = null; index1++; } else { // both start at same position, class2 ends first var len = class2.Length; // add class2 since it takes precedence list.Add(class2); class2 = null; index2++; // adjust remainder of class1 class1 = new ClassifiedRange(class1.Kind, class1.Start + len, class1.Length - len); } } return(list); }