提交 bca104c3 编写于 作者: S Sam Harwell

Validate Quick Info hyperlinks

上级 23634733
......@@ -8,6 +8,7 @@
using System.Threading;
using Microsoft.CodeAnalysis.Classification;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Shared.TestHooks;
using Microsoft.VisualStudio.Text;
......@@ -59,12 +60,7 @@ protected object CreateToolTipContent(Workspace workspace, DiagnosticData diagno
&& diagnostic.HelpLink is { } helpLink
&& Uri.TryCreate(helpLink, UriKind.Absolute, out var helpLinkUri))
{
navigationAction = () =>
{
var navigateToLinkService = workspace.Services.GetRequiredService<INavigateToLinkService>();
_ = navigateToLinkService.TryNavigateToLinkAsync(helpLinkUri, CancellationToken.None);
};
navigationAction = new QuickInfoHyperLink(workspace, helpLinkUri).NavigationAction;
tooltip = helpLink;
}
......
......@@ -10,6 +10,7 @@
using Microsoft.CodeAnalysis.Classification;
using Microsoft.CodeAnalysis.Editor.GoToDefinition;
using Microsoft.CodeAnalysis.Editor.Host;
using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo;
using Microsoft.VisualStudio.Text.Adornments;
using Roslyn.Utilities;
......@@ -118,9 +119,18 @@ private static IReadOnlyCollection<object> BuildInteractiveTextElements(Immutabl
var style = GetClassifiedTextRunStyle(part.Style);
if (part.NavigationTarget is object)
{
var target = part.NavigationTarget;
var tooltip = part.NavigationHint;
currentRuns.Add(new ClassifiedTextRun(part.Tag.ToClassificationTypeName(), part.Text, () => NavigateToQuickInfoTarget(target, document, streamingPresenter.Value), tooltip, style));
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, streamingPresenter.Value), tooltip, style));
}
}
else
{
......@@ -148,13 +158,6 @@ private static IReadOnlyCollection<object> BuildInteractiveTextElements(Immutabl
private static void NavigateToQuickInfoTarget(string navigationTarget, Document document, IStreamingFindUsagesPresenter streamingPresenter)
{
var navigateToLinkService = document.Project.Solution.Workspace.Services.GetRequiredService<INavigateToLinkService>();
if (Uri.TryCreate(navigationTarget, UriKind.Absolute, out var absoluteUri))
{
navigateToLinkService.TryNavigateToLinkAsync(absoluteUri, CancellationToken.None);
return;
}
SymbolKeyResolution resolvedSymbolKey;
try
{
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable enable
using System;
using System.Collections.Generic;
using System.Threading;
namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo
{
internal sealed class QuickInfoHyperLink : IEquatable<QuickInfoHyperLink?>
{
private readonly Workspace _workspace;
public QuickInfoHyperLink(Workspace workspace, Uri uri)
{
_workspace = workspace;
Uri = uri;
NavigationAction = OpenLink;
}
public Action NavigationAction { get; }
public Uri Uri { get; }
public override bool Equals(object? obj)
{
return Equals(obj as QuickInfoHyperLink);
}
public bool Equals(QuickInfoHyperLink? other)
{
return EqualityComparer<Uri?>.Default.Equals(Uri, other?.Uri);
}
public override int GetHashCode()
{
return Uri.GetHashCode();
}
private void OpenLink()
{
var navigateToLinkService = _workspace.Services.GetRequiredService<INavigateToLinkService>();
_ = navigateToLinkService.TryNavigateToLinkAsync(Uri, CancellationToken.None);
}
internal readonly struct TestAccessor
{
public static Action CreateNavigationAction(Uri uri)
{
// The workspace is not validated by tests
return new QuickInfoHyperLink(null!, uri).NavigationAction;
}
}
}
}
......@@ -3,6 +3,7 @@
' See the LICENSE file in the project root for more information.
Imports Microsoft.CodeAnalysis.Classification
Imports Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo
Imports Microsoft.CodeAnalysis.Test.Utilities.QuickInfo
Imports Microsoft.VisualStudio.Core.Imaging
Imports Microsoft.VisualStudio.Imaging
......@@ -53,7 +54,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense
New ClassifiedTextElement(
New ClassifiedTextRun(ClassificationTypeNames.Text, "This contains a link to"),
New ClassifiedTextRun(ClassificationTypeNames.WhiteSpace, " "),
New ClassifiedTextRun(ClassificationTypeNames.Text, "https://github.com/dotnet/roslyn", navigationAction:=Sub() Return, "https://github.com/dotnet/roslyn"),
New ClassifiedTextRun(ClassificationTypeNames.Text, "https://github.com/dotnet/roslyn", QuickInfoHyperLink.TestAccessor.CreateNavigationAction(New Uri("https://github.com/dotnet/roslyn", UriKind.Absolute)), "https://github.com/dotnet/roslyn"),
New ClassifiedTextRun(ClassificationTypeNames.Text, "."))))
ToolTipAssert.EqualContent(expected, intellisenseQuickInfo.Item)
......@@ -100,7 +101,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense
New ClassifiedTextElement(
New ClassifiedTextRun(ClassificationTypeNames.Text, "This contains a link to"),
New ClassifiedTextRun(ClassificationTypeNames.WhiteSpace, " "),
New ClassifiedTextRun(ClassificationTypeNames.Text, "dotnet/roslyn", navigationAction:=Sub() Return, "https://github.com/dotnet/roslyn"),
New ClassifiedTextRun(ClassificationTypeNames.Text, "dotnet/roslyn", QuickInfoHyperLink.TestAccessor.CreateNavigationAction(New Uri("https://github.com/dotnet/roslyn", UriKind.Absolute)), "https://github.com/dotnet/roslyn"),
New ClassifiedTextRun(ClassificationTypeNames.Text, "."))))
ToolTipAssert.EqualContent(expected, intellisenseQuickInfo.Item)
......
......@@ -8,6 +8,7 @@
using System.Linq;
using System.Text;
using Microsoft.CodeAnalysis.Classification;
using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo;
using Microsoft.VisualStudio.Core.Imaging;
using Microsoft.VisualStudio.Imaging;
using Microsoft.VisualStudio.Text.Adornments;
......@@ -94,6 +95,24 @@ private static void EqualClassifiedTextRun(ClassifiedTextRun expected, Classifie
Assert.Equal(expected.Text, actual.Text);
Assert.Equal(expected.Tooltip, actual.Tooltip);
Assert.Equal(expected.Style, actual.Style);
if (expected.NavigationAction is null)
{
Assert.Equal(expected.NavigationAction, actual.NavigationAction);
}
else if (expected.NavigationAction.Target is QuickInfoHyperLink hyperLink)
{
Assert.Same(expected.NavigationAction, hyperLink.NavigationAction);
var actualTarget = Assert.IsType<QuickInfoHyperLink>(actual.NavigationAction.Target);
Assert.Same(actual.NavigationAction, actualTarget.NavigationAction);
Assert.Equal(hyperLink, actualTarget);
}
else
{
// Cannot validate this navigation action
Assert.NotNull(actual.NavigationAction);
Assert.IsNotType<QuickInfoHyperLink>(actual.NavigationAction.Target);
}
}
private static string ContainerToString(object element)
......@@ -159,7 +178,16 @@ private static void ContainerToString(object element, string indent, StringBuild
if (classifiedTextRun.NavigationAction is object || !string.IsNullOrEmpty(classifiedTextRun.Tooltip))
{
var tooltip = classifiedTextRun.Tooltip is object ? $"\"{classifiedTextRun.Tooltip.Replace("\"", "\"\"")}\"" : "Nothing";
result.Append($", navigationAction:=Sub() Return, {tooltip}");
if (classifiedTextRun.NavigationAction?.Target is QuickInfoHyperLink hyperLink)
{
result.Append($", QuickInfoHyperLink.TestAccessor.CreateNavigationAction(new Uri(\"{hyperLink.Uri}\", UriKind.Absolute))");
}
else
{
result.Append(", navigationAction:=Sub() Return");
}
result.Append($", {tooltip}");
}
if (classifiedTextRun.Style != ClassifiedTextRunStyle.Plain)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册