protected static object CreateToolTipContent(Workspace workspace, DiagnosticData diagnostic)
        {
            Action?navigationAction = null;
            string?tooltip          = null;

            if (workspace != null)
            {
                var helpLinkUri = diagnostic.GetValidHelpLinkUri();
                if (helpLinkUri != null)
                {
                    navigationAction = new QuickInfoHyperLink(workspace, helpLinkUri).NavigationAction;
                    tooltip          = diagnostic.HelpLink;
                }
            }

            var diagnosticIdTextRun = navigationAction is null
                ? new ClassifiedTextRun(ClassificationTypeNames.Text, diagnostic.Id)
                : new ClassifiedTextRun(ClassificationTypeNames.Text, diagnostic.Id, navigationAction, tooltip);

            return(new ContainerElement(
                       ContainerElementStyle.Wrapped,
                       new ClassifiedTextElement(
                           diagnosticIdTextRun,
                           new ClassifiedTextRun(ClassificationTypeNames.Punctuation, ":"),
                           new ClassifiedTextRun(ClassificationTypeNames.WhiteSpace, " "),
                           new ClassifiedTextRun(ClassificationTypeNames.Text, diagnostic.Message))));
        }
Exemplo n.º 2
0
        protected static object CreateToolTipContent(Workspace workspace, DiagnosticData diagnostic)
        {
            Action?navigationAction = null;
            string?tooltip          = null;

            if (workspace is object &&
                diagnostic.HelpLink is { } helpLink &&
                Uri.TryCreate(helpLink, UriKind.Absolute, out var helpLinkUri))
            {
                navigationAction = new QuickInfoHyperLink(workspace, helpLinkUri).NavigationAction;
                tooltip          = helpLink;
            }

            var diagnosticIdTextRun = navigationAction is null
                ? new ClassifiedTextRun(ClassificationTypeNames.Text, diagnostic.Id)
                : new ClassifiedTextRun(ClassificationTypeNames.Text, diagnostic.Id, navigationAction, tooltip);

            return(new ContainerElement(
                       ContainerElementStyle.Wrapped,
                       new ClassifiedTextElement(
                           diagnosticIdTextRun,
                           new ClassifiedTextRun(ClassificationTypeNames.Punctuation, ":"),
                           new ClassifiedTextRun(ClassificationTypeNames.WhiteSpace, " "),
                           new ClassifiedTextRun(ClassificationTypeNames.Text, diagnostic.Message))));
        }
Exemplo n.º 3
0
        private static IReadOnlyCollection <object> BuildInteractiveTextElements(
            ImmutableArray <TaggedText> taggedTexts,
            ref int index,
            IntellisenseQuickInfoBuilderContext?context)
        {
            // This method produces a sequence of zero or more paragraphs
            var paragraphs = new List <object>();

            // Each paragraph is constructed from one or more lines
            var currentParagraph = new List <object>();

            // Each line is constructed from one or more inline elements
            var currentRuns = new List <ClassifiedTextRun>();

            while (index < taggedTexts.Length)
            {
                var part = taggedTexts[index];

                // These tags can be ignored - they are for markdown formatting only.
                if (part.Tag is TextTags.CodeBlockStart or TextTags.CodeBlockEnd)
                {
                    index++;
                    continue;
                }

                if (part.Tag == TextTags.ContainerStart)
                {
                    if (currentRuns.Count > 0)
                    {
                        // This line break means the end of a line within a paragraph.
                        currentParagraph.Add(new ClassifiedTextElement(currentRuns));
                        currentRuns.Clear();
                    }

                    index++;
                    var nestedElements = BuildInteractiveTextElements(taggedTexts, ref index, context);
                    if (nestedElements.Count <= 1)
                    {
                        currentParagraph.Add(new ContainerElement(
                                                 ContainerElementStyle.Wrapped,
                                                 new ClassifiedTextElement(new ClassifiedTextRun(ClassificationTypeNames.Text, part.Text)),
                                                 new ContainerElement(ContainerElementStyle.Stacked, nestedElements)));
                    }
                    else
                    {
                        currentParagraph.Add(new ContainerElement(
                                                 ContainerElementStyle.Wrapped,
                                                 new ClassifiedTextElement(new ClassifiedTextRun(ClassificationTypeNames.Text, part.Text)),
                                                 new ContainerElement(
                                                     ContainerElementStyle.Stacked,
                                                     nestedElements.First(),
                                                     new ContainerElement(
                                                         ContainerElementStyle.Stacked | ContainerElementStyle.VerticalPadding,
                                                         nestedElements.Skip(1)))));
                    }

                    index++;
                    continue;
                }
                else if (part.Tag == TextTags.ContainerEnd)
                {
                    // Return the current result and let the caller continue
                    break;
                }

                if (part.Tag is TextTags.ContainerStart
                    or TextTags.ContainerEnd)
                {
                    index++;
                    continue;
                }

                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 <para> 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.
                    var style = GetClassifiedTextRunStyle(part.Style);
                    if (part.NavigationTarget is not null &&
                        context?.ThreadingContext is { } threadingContext&&
                        context?.OperationExecutor is { } operationExecutor&&
                        context?.AsynchronousOperationListener is { } asyncListener&&
                        context?.StreamingPresenter is { } streamingPresenter)
                    {
                        var document = context.Document;
                        if (Uri.TryCreate(part.NavigationTarget, UriKind.Absolute, out var absoluteUri))
                        {
                            var target  = new QuickInfoHyperLink(document.Project.Solution.Workspace, absoluteUri);
                            var tooltip = part.NavigationHint;
                            currentRuns.Add(new ClassifiedTextRun(part.Tag.ToClassificationTypeName(), part.Text, target.NavigationAction, tooltip, style));
                        }
                        else
                        {
                            // ⚠ PERF: avoid capturing Solution (including indirectly through Project or Document
                            // instances) as part of the navigationAction delegate.
                            var target     = part.NavigationTarget;
                            var tooltip    = part.NavigationHint;
                            var documentId = document.Id;
                            var workspace  = document.Project.Solution.Workspace;
                            currentRuns.Add(new ClassifiedTextRun(
                                                part.Tag.ToClassificationTypeName(), part.Text,
                                                () => _ = NavigateToQuickInfoTargetAsync(target, workspace, documentId, threadingContext, operationExecutor, asyncListener, streamingPresenter.Value),
                                                tooltip, style));
                        }
                    }
Exemplo n.º 4
0
        private static IReadOnlyCollection <object> BuildInteractiveTextElements(
            ImmutableArray <TaggedText> taggedTexts,
            ref int index,
            Document document,
            IThreadingContext?threadingContext,
            Lazy <IStreamingFindUsagesPresenter>?streamingPresenter)
        {
            // This method produces a sequence of zero or more paragraphs
            var paragraphs = new List <object>();

            // Each paragraph is constructed from one or more lines
            var currentParagraph = new List <object>();

            // Each line is constructed from one or more inline elements
            var currentRuns = new List <ClassifiedTextRun>();

            while (index < taggedTexts.Length)
            {
                var part = taggedTexts[index];
                if (part.Tag == TextTags.ContainerStart)
                {
                    if (currentRuns.Count > 0)
                    {
                        // This line break means the end of a line within a paragraph.
                        currentParagraph.Add(new ClassifiedTextElement(currentRuns));
                        currentRuns.Clear();
                    }

                    index++;
                    var nestedElements = BuildInteractiveTextElements(taggedTexts, ref index, document, threadingContext, streamingPresenter);
                    if (nestedElements.Count <= 1)
                    {
                        currentParagraph.Add(new ContainerElement(
                                                 ContainerElementStyle.Wrapped,
                                                 new ClassifiedTextElement(new ClassifiedTextRun(ClassificationTypeNames.Text, part.Text)),
                                                 new ContainerElement(ContainerElementStyle.Stacked, nestedElements)));
                    }
                    else
                    {
                        currentParagraph.Add(new ContainerElement(
                                                 ContainerElementStyle.Wrapped,
                                                 new ClassifiedTextElement(new ClassifiedTextRun(ClassificationTypeNames.Text, part.Text)),
                                                 new ContainerElement(
                                                     ContainerElementStyle.Stacked,
                                                     nestedElements.First(),
                                                     new ContainerElement(
                                                         ContainerElementStyle.Stacked | ContainerElementStyle.VerticalPadding,
                                                         nestedElements.Skip(1)))));
                    }

                    index++;
                    continue;
                }
                else if (part.Tag == TextTags.ContainerEnd)
                {
                    // Return the current result and let the caller continue
                    break;
                }

                if (part.Tag == TextTags.ContainerStart ||
                    part.Tag == TextTags.ContainerEnd)
                {
                    index++;
                    continue;
                }

                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 <para> 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.
                    var style = GetClassifiedTextRunStyle(part.Style);
                    if (part.NavigationTarget is object && streamingPresenter != null && threadingContext != null)
                    {
                        if (Uri.TryCreate(part.NavigationTarget, UriKind.Absolute, out var absoluteUri))
                        {
                            var target  = new QuickInfoHyperLink(document.Project.Solution.Workspace, absoluteUri);
                            var tooltip = part.NavigationHint;
                            currentRuns.Add(new ClassifiedTextRun(part.Tag.ToClassificationTypeName(), part.Text, target.NavigationAction, tooltip, style));
                        }
                        else
                        {
                            var target  = part.NavigationTarget;
                            var tooltip = part.NavigationHint;
                            currentRuns.Add(new ClassifiedTextRun(
                                                part.Tag.ToClassificationTypeName(), part.Text,
                                                () => NavigateToQuickInfoTarget(target, document, threadingContext, streamingPresenter.Value), tooltip, style));
                        }
                    }
                    else
                    {
                        currentRuns.Add(new ClassifiedTextRun(part.Tag.ToClassificationTypeName(), part.Text, style));
                    }
                }

                index++;
            }

            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);
        }