// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Generic; using System.Collections.Immutable; using Microsoft.VisualStudio.Text.Adornments; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense { internal static class Helpers { internal static IEnumerable BuildClassifiedTextElements(ImmutableArray taggedTexts) { // This method produces a sequence of zero or more paragraphs var paragraphs = new List(); // Each paragraph is constructed from one or more lines var currentParagraph = new List(); // Each line is constructed from one or more inline elements var currentRuns = new List(); foreach (var part in taggedTexts) { if (part.Tag == TextTags.LineBreak) { if (currentRuns.Count > 0) { // This line break means the end of a line within a paragraph. currentParagraph.Add(new ClassifiedTextElement(currentRuns)); currentRuns.Clear(); } else { // This line break means the end of a paragraph. Empty paragraphs are ignored, but could appear // in the input to this method: // // * Empty elements // * Explicit line breaks at the start of a comment // * Multiple line breaks between paragraphs if (currentParagraph.Count > 0) { // The current paragraph is not empty, so add it to the result collection paragraphs.Add(CreateParagraphFromLines(currentParagraph)); currentParagraph.Clear(); } else { // The current paragraph is empty, so we simply ignore it. } } } else { // This is tagged text getting added to the current line we are building. currentRuns.Add(new ClassifiedTextRun(part.Tag.ToClassificationTypeName(), part.Text)); } } if (currentRuns.Count > 0) { // Add the final line to the final paragraph. currentParagraph.Add(new ClassifiedTextElement(currentRuns)); } if (currentParagraph.Count > 0) { // Add the final paragraph to the result. paragraphs.Add(CreateParagraphFromLines(currentParagraph)); } return paragraphs; } internal static object CreateParagraphFromLines(IReadOnlyList lines) { Contract.ThrowIfFalse(lines.Count > 0); if (lines.Count == 1) { // The paragraph contains only one line, so it doesn't need to be added to a container. Avoiding the // wrapping container here also avoids a wrapping element in the WPF elements used for rendering, // improving efficiency. return lines[0]; } else { // The lines of a multi-line paragraph are stacked to produce the full paragraph. return new ContainerElement(ContainerElementStyle.Stacked, lines); } } } }