diff --git a/build/Targets/Packages.props b/build/Targets/Packages.props index d6bd88e633552..b47c6ade24ab5 100644 --- a/build/Targets/Packages.props +++ b/build/Targets/Packages.props @@ -76,25 +76,25 @@ 15.0.26730-alpha 15.0.26730-alpha 15.5.23 - 15.7.153-preview-g7d0635149a + 15.8.238-preview 15.0.27309-vsucorediag 15.0.27309-vsucorediag 15.0.27309-vsucorediag 10.0.30319 1.1.4322 15.0.26730-alpha - 15.7.153-preview-g7d0635149a + 15.8.238-preview 15.0.26730-alpha 15.0.26730-alpha 15.0.26730-alpha 15.0.25726-Preview5 2.0.0-rc3-61304-01 15.3.1710.203 - 15.7.153-preview-g7d0635149a - 15.7.153-preview-g7d0635149a - 15.7.153-preview-g7d0635149a + 15.8.238-preview + 15.8.238-preview + 15.8.238-preview 7.10.6070 - 15.7.153-preview-g7d0635149a + 15.8.238-preview 15.0.26730-alpha 15.0.26730-alpha 15.0.26730-alpha @@ -120,11 +120,11 @@ 9.0.30729 15.0.26730-alpha 8.0.0.0-alpha - 15.7.153-preview-g7d0635149a - 15.7.153-preview-g7d0635149a - 15.7.153-preview-g7d0635149a - 15.7.153-preview-g7d0635149a - 15.7.153-preview-g7d0635149a + 15.8.238-preview + 15.8.238-preview + 15.8.238-preview + 15.8.238-preview + 15.8.238-preview 7.10.6070 10.0.30319 12.0.30110 diff --git a/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs b/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs index f754d2d8a0b29..73da517dff28f 100644 --- a/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs +++ b/src/EditorFeatures/CSharpTest/QuickInfo/SemanticQuickInfoSourceTests.cs @@ -7,10 +7,10 @@ using System.Threading.Tasks; using System.Xml.Linq; using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.Editor.CSharp.QuickInfo; using Microsoft.CodeAnalysis.Editor.UnitTests.QuickInfo; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.QuickInfo; using Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; @@ -20,7 +20,7 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.QuickInfo { public class SemanticQuickInfoSourceTests : AbstractSemanticQuickInfoSourceTests { - private async Task TestWithOptionsAsync(CSharpParseOptions options, string markup, params Action[] expectedResults) + private async Task TestWithOptionsAsync(CSharpParseOptions options, string markup, params Action[] expectedResults) { using (var workspace = TestWorkspace.CreateCSharp(markup, options)) { @@ -28,16 +28,16 @@ private async Task TestWithOptionsAsync(CSharpParseOptions options, string marku } } - private async Task TestWithOptionsAsync(TestWorkspace workspace, params Action[] expectedResults) + private async Task TestWithOptionsAsync(TestWorkspace workspace, params Action[] expectedResults) { var testDocument = workspace.DocumentWithCursor; var position = testDocument.CursorPosition.GetValueOrDefault(); var documentId = workspace.GetDocumentId(testDocument); var document = workspace.CurrentSolution.GetDocument(documentId); - var provider = new SemanticQuickInfoProvider(); + var service = QuickInfoService.GetService(document); - await TestWithOptionsAsync(document, provider, position, expectedResults); + await TestWithOptionsAsync(document, service, position, expectedResults); // speculative semantic model if (await CanUseSpeculativeSemanticModelAsync(document, position)) @@ -50,34 +50,30 @@ private async Task TestWithOptionsAsync(TestWorkspace workspace, params Action[] expectedResults) + private async Task TestWithOptionsAsync(Document document, QuickInfoService service, int position, Action[] expectedResults) { - var state = await provider.GetItemAsync(document, position, cancellationToken: CancellationToken.None); - if (state != null) - { - WaitForDocumentationComment(state.Content); - } + var info = await service.GetQuickInfoAsync(document, position, cancellationToken: CancellationToken.None); if (expectedResults.Length == 0) { - Assert.Null(state); + Assert.Null(info); } else { - Assert.NotNull(state); + Assert.NotNull(info); foreach (var expected in expectedResults) { - expected(state.Content); + expected(info); } } } - private async Task VerifyWithMscorlib45Async(string markup, Action[] expectedResults) + private async Task VerifyWithMscorlib45Async(string markup, Action[] expectedResults) { var xmlString = string.Format(@" @@ -94,37 +90,33 @@ private async Task VerifyWithMscorlib45Async(string markup, Action[] exp var documentId = workspace.Documents.Where(d => d.Name == "SourceDocument").Single().Id; var document = workspace.CurrentSolution.GetDocument(documentId); - var provider = new SemanticQuickInfoProvider(); + var service = QuickInfoService.GetService(document); - var state = await provider.GetItemAsync(document, position, cancellationToken: CancellationToken.None); - if (state != null) - { - WaitForDocumentationComment(state.Content); - } + var info = await service.GetQuickInfoAsync(document, position, cancellationToken: CancellationToken.None); if (expectedResults.Length == 0) { - Assert.Null(state); + Assert.Null(info); } else { - Assert.NotNull(state); + Assert.NotNull(info); foreach (var expected in expectedResults) { - expected(state.Content); + expected(info); } } } } - protected override async Task TestAsync(string markup, params Action[] expectedResults) + protected override async Task TestAsync(string markup, params Action[] expectedResults) { await TestWithOptionsAsync(Options.Regular, markup, expectedResults); await TestWithOptionsAsync(Options.Script, markup, expectedResults); } - protected async Task TestWithUsingsAsync(string markup, params Action[] expectedResults) + private async Task TestWithUsingsAsync(string markup, params Action[] expectedResults) { var markupWithUsings = @"using System; @@ -135,13 +127,13 @@ protected async Task TestWithUsingsAsync(string markup, params Action[] await TestAsync(markupWithUsings, expectedResults); } - protected Task TestInClassAsync(string markup, params Action[] expectedResults) + private Task TestInClassAsync(string markup, params Action[] expectedResults) { var markupInClass = "class C { " + markup + " }"; return TestWithUsingsAsync(markupInClass, expectedResults); } - protected Task TestInMethodAsync(string markup, params Action[] expectedResults) + private Task TestInMethodAsync(string markup, params Action[] expectedResults) { var markupInMethod = "class C { void M() { " + markup + " } }"; return TestWithUsingsAsync(markupInMethod, expectedResults); @@ -151,7 +143,7 @@ private async Task TestWithReferenceAsync(string sourceCode, string referencedCode, string sourceLanguage, string referencedLanguage, - params Action[] expectedResults) + params Action[] expectedResults) { await TestWithMetadataReferenceHelperAsync(sourceCode, referencedCode, sourceLanguage, referencedLanguage, expectedResults); await TestWithProjectReferenceHelperAsync(sourceCode, referencedCode, sourceLanguage, referencedLanguage, expectedResults); @@ -168,7 +160,7 @@ private async Task TestWithMetadataReferenceHelperAsync( string referencedCode, string sourceLanguage, string referencedLanguage, - params Action[] expectedResults) + params Action[] expectedResults) { var xmlString = string.Format(@" @@ -193,7 +185,7 @@ private async Task TestWithProjectReferenceHelperAsync( string referencedCode, string sourceLanguage, string referencedLanguage, - params Action[] expectedResults) + params Action[] expectedResults) { var xmlString = string.Format(@" @@ -219,7 +211,7 @@ private async Task TestInSameProjectHelperAsync( string sourceCode, string referencedCode, string sourceLanguage, - params Action[] expectedResults) + params Action[] expectedResults) { var xmlString = string.Format(@" @@ -236,7 +228,7 @@ private async Task TestInSameProjectHelperAsync( await VerifyWithReferenceWorkerAsync(xmlString, expectedResults); } - private async Task VerifyWithReferenceWorkerAsync(string xmlString, params Action[] expectedResults) + private async Task VerifyWithReferenceWorkerAsync(string xmlString, params Action[] expectedResults) { using (var workspace = TestWorkspace.Create(xmlString)) { @@ -244,25 +236,21 @@ private async Task VerifyWithReferenceWorkerAsync(string xmlString, params Actio var documentId = workspace.Documents.First(d => d.Name == "SourceDocument").Id; var document = workspace.CurrentSolution.GetDocument(documentId); - var provider = new SemanticQuickInfoProvider(); + var service = QuickInfoService.GetService(document); - var state = await provider.GetItemAsync(document, position, cancellationToken: CancellationToken.None); - if (state != null) - { - WaitForDocumentationComment(state.Content); - } + var info = await service.GetQuickInfoAsync(document, position, cancellationToken: CancellationToken.None); if (expectedResults.Length == 0) { - Assert.Null(state); + Assert.Null(info); } else { - Assert.NotNull(state); + Assert.NotNull(info); foreach (var expected in expectedResults) { - expected(state.Content); + expected(info); } } } diff --git a/src/EditorFeatures/CSharpTest/QuickInfo/SyntacticQuickInfoSourceTests.cs b/src/EditorFeatures/CSharpTest/QuickInfo/SyntacticQuickInfoSourceTests.cs index 911c26dc7cf51..ff2cef22f2149 100644 --- a/src/EditorFeatures/CSharpTest/QuickInfo/SyntacticQuickInfoSourceTests.cs +++ b/src/EditorFeatures/CSharpTest/QuickInfo/SyntacticQuickInfoSourceTests.cs @@ -4,11 +4,10 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.Editor.CSharp.QuickInfo; -using Microsoft.CodeAnalysis.Editor.QuickInfo; -using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.CSharp.QuickInfo; using Microsoft.CodeAnalysis.Editor.UnitTests.QuickInfo; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; +using Microsoft.CodeAnalysis.QuickInfo; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; @@ -260,9 +259,9 @@ await TestInMethodAndScriptAsync( {"); } - private IQuickInfoProvider CreateProvider(TestWorkspace workspace) + private QuickInfoProvider CreateProvider(TestWorkspace workspace) { - return new SyntacticQuickInfoProvider(); + return new CSharpSyntacticQuickInfoProvider(); } protected override async Task AssertNoContentAsync( @@ -271,7 +270,7 @@ protected override async Task AssertNoContentAsync( int position) { var provider = CreateProvider(workspace); - Assert.Null(await provider.GetItemAsync(document, position, CancellationToken.None)); + Assert.Null(await provider.GetQuickInfoAsync(new QuickInfoContext(document, position, CancellationToken.None))); } protected override async Task AssertContentIsAsync( @@ -282,14 +281,15 @@ protected override async Task AssertContentIsAsync( string expectedDocumentationComment = null) { var provider = CreateProvider(workspace); - var state = await provider.GetItemAsync(document, position, cancellationToken: CancellationToken.None); - Assert.NotNull(state); - - var hostingControlFactory = workspace.GetService(); - - var viewHostingControl = (ViewHostingControl)hostingControlFactory.CreateElement(state.Content); - var actualContent = viewHostingControl.GetText_TestOnly(); - Assert.Equal(expectedContent, actualContent); + var info = await provider.GetQuickInfoAsync(new QuickInfoContext(document, position, CancellationToken.None)); + Assert.NotNull(info); + + Assert.NotEqual(0, info.RelatedSpans.Length); + var tabSize = document.Project.Solution.Workspace.Options.GetOption(Microsoft.CodeAnalysis.Formatting.FormattingOptions.TabSize, document.Project.Language); + var text = await document.GetTextAsync(); + var spans = IndentationHelper.GetSpansWithAlignedIndentation(text, info.RelatedSpans, tabSize); + var actualText = string.Concat(spans.Select(s => text.GetSubText(s).ToString())); + Assert.Equal(expectedContent, actualText); } protected override Task TestInMethodAsync(string code, string expectedContent, string expectedDocumentationComment = null) diff --git a/src/EditorFeatures/CSharpTest2/Recommendations/UnmanagedKeywordRecommenderTests.cs b/src/EditorFeatures/CSharpTest2/Recommendations/UnmanagedKeywordRecommenderTests.cs index d9c0696d3d23a..d79f512925f90 100644 --- a/src/EditorFeatures/CSharpTest2/Recommendations/UnmanagedKeywordRecommenderTests.cs +++ b/src/EditorFeatures/CSharpTest2/Recommendations/UnmanagedKeywordRecommenderTests.cs @@ -24,7 +24,7 @@ public async Task TestAtRoot_Interactive() await VerifyAbsenceAsync(SourceCodeKind.Script, @"$$"); } - + [Fact, Trait(Traits.Feature, Traits.Features.KeywordRecommending)] public async Task TestNotInUsingAlias() { diff --git a/src/EditorFeatures/Core.Wpf/Completion/Presentation/CustomCommitCompletion.cs b/src/EditorFeatures/Core.Wpf/Completion/Presentation/CustomCommitCompletion.cs index f571d8379891e..e8dc0653dcea6 100644 --- a/src/EditorFeatures/Core.Wpf/Completion/Presentation/CustomCommitCompletion.cs +++ b/src/EditorFeatures/Core.Wpf/Completion/Presentation/CustomCommitCompletion.cs @@ -6,6 +6,8 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Editor.Wpf; +using Microsoft.CodeAnalysis.Tags; +using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Imaging.Interop; using Microsoft.VisualStudio.Language.Intellisense; using Roslyn.Utilities; @@ -30,7 +32,7 @@ public CustomCommitCompletion( // extra allocation is avoided. _completionPresenterSession = completionPresenterSession; this.CompletionItem = completionItem; - _imageMoniker = ImageMonikers.GetImageMoniker(CompletionItem.Tags); + _imageMoniker = ImageMonikers.GetFirstImageMoniker(CompletionItem.Tags); } public void Commit() @@ -73,7 +75,7 @@ public override IEnumerable AttributeIcons { get { - if (this.CompletionItem.Tags.Contains(CompletionTags.Warning)) + if (this.CompletionItem.Tags.Contains(WellKnownTags.Warning)) { return new[] { new CompletionIcon2(Glyph.CompletionWarning.GetImageMoniker(), s_glyphCompletionWarning, s_glyphCompletionWarning) }; } diff --git a/src/EditorFeatures/Core.Wpf/Completion/Presentation/ImageMonikers.cs b/src/EditorFeatures/Core.Wpf/Completion/Presentation/ImageMonikers.cs index 219bc6992ee08..02d8269218d8f 100644 --- a/src/EditorFeatures/Core.Wpf/Completion/Presentation/ImageMonikers.cs +++ b/src/EditorFeatures/Core.Wpf/Completion/Presentation/ImageMonikers.cs @@ -1,7 +1,6 @@ // 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.Immutable; -using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Wpf; using Microsoft.VisualStudio.Imaging.Interop; @@ -9,9 +8,9 @@ namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.Completion.P { internal static class ImageMonikers { - public static ImageMoniker GetImageMoniker(ImmutableArray tags) + public static ImageMoniker GetFirstImageMoniker(ImmutableArray tags) { - return tags.GetGlyph().GetImageMoniker(); + return tags.GetFirstGlyph().GetImageMoniker(); } } } diff --git a/src/EditorFeatures/Core.Wpf/Completion/Presentation/RoslynIntellisenseFilter.cs b/src/EditorFeatures/Core.Wpf/Completion/Presentation/RoslynIntellisenseFilter.cs index 30dbb9de33787..de2cc9b987fda 100644 --- a/src/EditorFeatures/Core.Wpf/Completion/Presentation/RoslynIntellisenseFilter.cs +++ b/src/EditorFeatures/Core.Wpf/Completion/Presentation/RoslynIntellisenseFilter.cs @@ -10,7 +10,7 @@ internal class IntellisenseFilter2 : IntellisenseFilter public IntellisenseFilter2( RoslynCompletionSet completionSet, CompletionItemFilter filter) - : base(ImageMonikers.GetImageMoniker(filter.Tags), GetToolTip(filter), + : base(ImageMonikers.GetFirstImageMoniker(filter.Tags), GetToolTip(filter), filter.AccessKey.ToString(), automationText: filter.Tags[0]) { _completionSet = completionSet; diff --git a/src/EditorFeatures/Core.Wpf/QuickInfo/Converters/ClassifiableDeferredContentConverter.cs b/src/EditorFeatures/Core.Wpf/QuickInfo/Converters/ClassifiableDeferredContentConverter.cs deleted file mode 100644 index 1a5c28fe5bea7..0000000000000 --- a/src/EditorFeatures/Core.Wpf/QuickInfo/Converters/ClassifiableDeferredContentConverter.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.Composition; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo; -using Microsoft.CodeAnalysis.Editor.Shared.Extensions; -using Microsoft.CodeAnalysis.Editor.Shared.Utilities; -using Microsoft.VisualStudio.Text.Classification; - -namespace Microsoft.CodeAnalysis.Editor.QuickInfo -{ - [Export(typeof(IDeferredQuickInfoContentToFrameworkElementConverter))] - [QuickInfoConverterMetadata(typeof(ClassifiableDeferredContent))] - class ClassifiableDeferredContentConverter : IDeferredQuickInfoContentToFrameworkElementConverter - { - private readonly ClassificationTypeMap _typeMap; - private readonly IClassificationFormatMapService _classificationFormatMapService; - - [ImportingConstructor] - public ClassifiableDeferredContentConverter( - ClassificationTypeMap typeMap, - IClassificationFormatMapService classificationFormatMapService) - { - _typeMap = typeMap; - _classificationFormatMapService = classificationFormatMapService; - } - - public FrameworkElement CreateFrameworkElement(IDeferredQuickInfoContent deferredContent, DeferredContentFrameworkElementFactory factory) - { - var classifiableContent = (ClassifiableDeferredContent)deferredContent; - var formatMap = _classificationFormatMapService.GetClassificationFormatMap("tooltip"); - var classifiedTextBlock = classifiableContent.ClassifiableContent.ToTextBlock(formatMap, _typeMap); - - if (classifiedTextBlock.Inlines.Count == 0) - { - classifiedTextBlock.Visibility = Visibility.Collapsed; - } - - return classifiedTextBlock; - } - - public Type GetApplicableType() - { - return typeof(ClassifiableDeferredContent); - } - } -} diff --git a/src/EditorFeatures/Core.Wpf/QuickInfo/Converters/DocumentationCommentDeferredContentConverter.cs b/src/EditorFeatures/Core.Wpf/QuickInfo/Converters/DocumentationCommentDeferredContentConverter.cs deleted file mode 100644 index 2f7a6dbf84443..0000000000000 --- a/src/EditorFeatures/Core.Wpf/QuickInfo/Converters/DocumentationCommentDeferredContentConverter.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.Composition; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo; -using Microsoft.CodeAnalysis.Editor.Shared.Extensions; -using Microsoft.CodeAnalysis.Editor.Shared.Utilities; -using Microsoft.VisualStudio.Text.Classification; - -namespace Microsoft.CodeAnalysis.Editor.QuickInfo.Converters -{ - [Export(typeof(IDeferredQuickInfoContentToFrameworkElementConverter))] - [QuickInfoConverterMetadata(typeof(DocumentationCommentDeferredContent))] - internal sealed class DocumentationCommentDeferredContentConverter : IDeferredQuickInfoContentToFrameworkElementConverter - { - private readonly ClassificationTypeMap _typeMap; - private readonly IClassificationFormatMapService _classificationFormatMapService; - - [ImportingConstructor] - public DocumentationCommentDeferredContentConverter(ClassificationTypeMap typeMap, IClassificationFormatMapService classificationFormatMapService) - { - _typeMap = typeMap; - _classificationFormatMapService = classificationFormatMapService; - } - - public FrameworkElement CreateFrameworkElement(IDeferredQuickInfoContent deferredContent, DeferredContentFrameworkElementFactory factory) - { - var documentationCommentContent = (DocumentationCommentDeferredContent)deferredContent; - - var documentationTextBlock = new TextBlock() - { - TextWrapping = TextWrapping.Wrap - }; - - var formatMap = _classificationFormatMapService.GetClassificationFormatMap("tooltip"); - documentationTextBlock.SetDefaultTextProperties(formatMap); - - // If we have already computed the symbol documentation by now, update - - UpdateDocumentationTextBlock(documentationCommentContent, documentationTextBlock); - return documentationTextBlock; - } - - private void UpdateDocumentationTextBlock(DocumentationCommentDeferredContent deferredContent, TextBlock documentationTextBlock) - { - if (!string.IsNullOrEmpty(deferredContent.DocumentationComment)) - { - documentationTextBlock.Text = deferredContent.DocumentationComment; - } - else - { - documentationTextBlock.Text = string.Empty; - documentationTextBlock.Visibility = Visibility.Collapsed; - } - } - - public Type GetApplicableType() - { - return typeof(DocumentationCommentDeferredContent); - } - } -} diff --git a/src/EditorFeatures/Core.Wpf/QuickInfo/Converters/IDeferredQuickInfoContentToFrameworkElementConverter.cs b/src/EditorFeatures/Core.Wpf/QuickInfo/Converters/IDeferredQuickInfoContentToFrameworkElementConverter.cs deleted file mode 100644 index b46fcbf88b43e..0000000000000 --- a/src/EditorFeatures/Core.Wpf/QuickInfo/Converters/IDeferredQuickInfoContentToFrameworkElementConverter.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; - -namespace Microsoft.CodeAnalysis.Editor.QuickInfo -{ - interface IDeferredQuickInfoContentToFrameworkElementConverter - { - Type GetApplicableType(); - FrameworkElement CreateFrameworkElement(IDeferredQuickInfoContent deferredContent, DeferredContentFrameworkElementFactory factory); - } -} diff --git a/src/EditorFeatures/Core.Wpf/QuickInfo/Converters/ProjectionBufferDeferredContentConverter.cs b/src/EditorFeatures/Core.Wpf/QuickInfo/Converters/ProjectionBufferDeferredContentConverter.cs deleted file mode 100644 index 70b75866815e9..0000000000000 --- a/src/EditorFeatures/Core.Wpf/QuickInfo/Converters/ProjectionBufferDeferredContentConverter.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System; -using System.ComponentModel.Composition; -using System.Windows; -using System.Windows.Media; -using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo; -using Microsoft.CodeAnalysis.Editor.Shared.Extensions; -using Microsoft.CodeAnalysis.Editor.Shared.Utilities; -using Microsoft.VisualStudio.Text; -using Microsoft.VisualStudio.Text.Editor; -using Microsoft.VisualStudio.Text.Projection; -using Microsoft.VisualStudio.Utilities; - -namespace Microsoft.CodeAnalysis.Editor.QuickInfo -{ - [Export(typeof(IDeferredQuickInfoContentToFrameworkElementConverter))] - [QuickInfoConverterMetadata(typeof(ProjectionBufferDeferredContent))] - class ProjectionBufferDeferredContentConverter : IDeferredQuickInfoContentToFrameworkElementConverter - { - private readonly IProjectionBufferFactoryService _projectionBufferFactoryService; - private readonly IEditorOptionsFactoryService _editorOptionsFactoryService; - private readonly ITextEditorFactoryService _textEditorFactoryService; - - [ImportingConstructor] - public ProjectionBufferDeferredContentConverter( - IProjectionBufferFactoryService projectionBufferFactoryService, - IEditorOptionsFactoryService editorOptionsFactoryService, - ITextEditorFactoryService textEditorFactoryService) - { - _projectionBufferFactoryService = projectionBufferFactoryService; - _editorOptionsFactoryService = editorOptionsFactoryService; - _textEditorFactoryService = textEditorFactoryService; - } - - public FrameworkElement CreateFrameworkElement(IDeferredQuickInfoContent deferredContent, DeferredContentFrameworkElementFactory factory) - { - var projectionBufferDeferredContent = (ProjectionBufferDeferredContent)deferredContent; - return new ViewHostingControl(buffer => CreateView(projectionBufferDeferredContent, buffer), () => CreateBuffer(projectionBufferDeferredContent)); - } - - private IWpfTextView CreateView(ProjectionBufferDeferredContent deferredContent, ITextBuffer buffer) - { - var view = _textEditorFactoryService.CreateTextView( - buffer, deferredContent.RoleSet ?? _textEditorFactoryService.NoRoles); - - view.SizeToFit(); - view.Background = Brushes.Transparent; - - // Zoom out a bit to shrink the text. - view.ZoomLevel *= 0.75; - - return view; - } - - private IProjectionBuffer CreateBuffer(ProjectionBufferDeferredContent deferredContent) - { - return _projectionBufferFactoryService.CreateProjectionBufferWithoutIndentation( - _editorOptionsFactoryService.GlobalOptions, deferredContent.ContentType, deferredContent.Span); - } - - public Type GetApplicableType() - { - return typeof(ProjectionBufferDeferredContent); - } - } -} diff --git a/src/EditorFeatures/Core.Wpf/QuickInfo/Converters/QuickInfoConverterMetadataAttribute.cs b/src/EditorFeatures/Core.Wpf/QuickInfo/Converters/QuickInfoConverterMetadataAttribute.cs deleted file mode 100644 index 1537f9bf4c730..0000000000000 --- a/src/EditorFeatures/Core.Wpf/QuickInfo/Converters/QuickInfoConverterMetadataAttribute.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.ComponentModel.Composition; - -namespace Microsoft.CodeAnalysis.Editor.QuickInfo -{ - [MetadataAttribute] - internal sealed class QuickInfoConverterMetadataAttribute : Attribute - { - public QuickInfoConverterMetadataAttribute(Type deferredType) - { - DeferredTypeFullName = deferredType.FullName; - } - - public string DeferredTypeFullName { get; } - } -} diff --git a/src/EditorFeatures/Core.Wpf/QuickInfo/Converters/QuickInfoDisplayDeferredContentConverter.cs b/src/EditorFeatures/Core.Wpf/QuickInfo/Converters/QuickInfoDisplayDeferredContentConverter.cs deleted file mode 100644 index 8695bf4954ddc..0000000000000 --- a/src/EditorFeatures/Core.Wpf/QuickInfo/Converters/QuickInfoDisplayDeferredContentConverter.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.Composition; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo; - -namespace Microsoft.CodeAnalysis.Editor.QuickInfo -{ - [Export(typeof(IDeferredQuickInfoContentToFrameworkElementConverter))] - [QuickInfoConverterMetadata(typeof(QuickInfoDisplayDeferredContent))] - class QuickInfoDisplayDeferredContentConverter : IDeferredQuickInfoContentToFrameworkElementConverter - { - public FrameworkElement CreateFrameworkElement(IDeferredQuickInfoContent deferredContent, DeferredContentFrameworkElementFactory factory) - { - var quickInfoDisplay = (QuickInfoDisplayDeferredContent)deferredContent; - FrameworkElement warningGlyphElement = null; - if (quickInfoDisplay.WarningGlyph != null) - { - warningGlyphElement = factory.CreateElement(quickInfoDisplay.WarningGlyph); - } - - FrameworkElement symbolGlyphElement = null; - if (quickInfoDisplay.SymbolGlyph != null) - { - symbolGlyphElement = factory.CreateElement(quickInfoDisplay.SymbolGlyph); - } - - return new QuickInfoDisplayPanel( - symbolGlyphElement, - warningGlyphElement, - factory.CreateElement(quickInfoDisplay.MainDescription), - factory.CreateElement(quickInfoDisplay.Documentation), - factory.CreateElement(quickInfoDisplay.TypeParameterMap), - factory.CreateElement(quickInfoDisplay.AnonymousTypes), - factory.CreateElement(quickInfoDisplay.UsageText), - factory.CreateElement(quickInfoDisplay.ExceptionText), - factory.CreateElement(quickInfoDisplay.CapturesText)); - } - - public Type GetApplicableType() - { - return typeof(QuickInfoDisplayDeferredContent); - } - } -} diff --git a/src/EditorFeatures/Core.Wpf/QuickInfo/Converters/SymbolGlyphDeferredContentConverter.cs b/src/EditorFeatures/Core.Wpf/QuickInfo/Converters/SymbolGlyphDeferredContentConverter.cs deleted file mode 100644 index cad17e81ce528..0000000000000 --- a/src/EditorFeatures/Core.Wpf/QuickInfo/Converters/SymbolGlyphDeferredContentConverter.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.ComponentModel.Composition; -using System.Windows; -using System.Windows.Data; -using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo; -using Microsoft.CodeAnalysis.Editor.Shared.Extensions; -using Microsoft.CodeAnalysis.Editor.Wpf; -using Microsoft.VisualStudio.Imaging; -using Microsoft.VisualStudio.PlatformUI; - -namespace Microsoft.CodeAnalysis.Editor.QuickInfo -{ - [Export(typeof(IDeferredQuickInfoContentToFrameworkElementConverter))] - [QuickInfoConverterMetadata(typeof(SymbolGlyphDeferredContent))] - class SymbolGlyphDeferredContentConverter : IDeferredQuickInfoContentToFrameworkElementConverter - { - public FrameworkElement CreateFrameworkElement(IDeferredQuickInfoContent deferredContent, DeferredContentFrameworkElementFactory factory) - { - var symbolDeferredContent = (SymbolGlyphDeferredContent)deferredContent; - - var image = new CrispImage - { - Moniker = symbolDeferredContent.Glyph.GetImageMoniker(), - }; - - // Inform the ImageService of the background color so that images have the correct background. - var binding = new Binding("Background") - { - Converter = new BrushToColorConverter(), - RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(QuickInfoDisplayPanel), 1) - }; - - image.SetBinding(ImageThemingUtilities.ImageBackgroundColorProperty, binding); - return image; - } - - public Type GetApplicableType() - { - return typeof(SymbolGlyphDeferredContent); - } - } -} diff --git a/src/EditorFeatures/Core.Wpf/QuickInfo/DeferredContentFrameworkElementFactory.cs b/src/EditorFeatures/Core.Wpf/QuickInfo/DeferredContentFrameworkElementFactory.cs deleted file mode 100644 index d0a3a2ef0c4bc..0000000000000 --- a/src/EditorFeatures/Core.Wpf/QuickInfo/DeferredContentFrameworkElementFactory.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.Composition; -using System.Linq; -using System.Windows; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.Editor.QuickInfo -{ - [Export] - internal class DeferredContentFrameworkElementFactory - { - private readonly Dictionary> _convertersByTypeFullName - = new Dictionary>(); - private readonly IEnumerable> _convertersWithoutMetadata; - - [ImportingConstructor] - public DeferredContentFrameworkElementFactory( - [ImportMany] IEnumerable> converters, - [ImportMany] IEnumerable> convertersWithoutMetadata) - { - _convertersByTypeFullName = converters - .Where(i => !string.IsNullOrEmpty(i.Metadata.DeferredTypeFullName)) - .ToDictionary( - lazy => lazy.Metadata.DeferredTypeFullName, - lazy => (Lazy)lazy); - - _convertersWithoutMetadata = convertersWithoutMetadata; - } - - internal FrameworkElement CreateElement(IDeferredQuickInfoContent deferredContent) - { - var deferredContentFullName = deferredContent.GetType().FullName; - Lazy converter; - - if (!_convertersByTypeFullName.TryGetValue(deferredContentFullName, out converter)) - { - // The content must be of a type we didn't have MEF deferred metadata for. Realize the - // ones without MEF metadata, forcing everything to load. - foreach (var converterWithoutMetadata in _convertersWithoutMetadata) - { - _convertersByTypeFullName[converterWithoutMetadata.Value.GetApplicableType().FullName] = - new Lazy(() => converterWithoutMetadata.Value); - } - - Contract.ThrowIfFalse(_convertersByTypeFullName.TryGetValue(deferredContentFullName, out converter)); - } - - return converter.Value.CreateFrameworkElement(deferredContent, this); - } - - internal class QuickInfoConverterMetadata - { - public QuickInfoConverterMetadata(IDictionary data) - { - DeferredTypeFullName = (string)data.GetValueOrDefault(nameof(QuickInfoConverterMetadataAttribute.DeferredTypeFullName)); - } - - public string DeferredTypeFullName { get; set; } - } - } -} diff --git a/src/EditorFeatures/Core.Wpf/QuickInfo/Presentation/QuickInfoPresenter.QuickInfoPresenterSession.cs b/src/EditorFeatures/Core.Wpf/QuickInfo/Presentation/QuickInfoPresenter.QuickInfoPresenterSession.cs deleted file mode 100644 index d4d6e3878da2f..0000000000000 --- a/src/EditorFeatures/Core.Wpf/QuickInfo/Presentation/QuickInfoPresenter.QuickInfoPresenterSession.cs +++ /dev/null @@ -1,113 +0,0 @@ -// 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; -using System.Collections.Generic; -using Microsoft.CodeAnalysis.Editor.QuickInfo; -using Microsoft.CodeAnalysis.Editor.Shared.Extensions; -using Microsoft.CodeAnalysis.Editor.Shared.Utilities; -using Microsoft.VisualStudio.Language.Intellisense; -using Microsoft.VisualStudio.Text; -using Microsoft.VisualStudio.Text.Editor; - -#pragma warning disable CS0618 // IQuickInfo* is obsolete, tracked by https://github.com/dotnet/roslyn/issues/24094 -namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo.Presentation -{ - internal partial class QuickInfoPresenter - { - private class QuickInfoPresenterSession : ForegroundThreadAffinitizedObject, IQuickInfoPresenterSession - { - private readonly IQuickInfoBroker _quickInfoBroker; - private readonly DeferredContentFrameworkElementFactory _elementFactory; - private readonly ITextView _textView; - private readonly ITextBuffer _subjectBuffer; - - private IQuickInfoSession _editorSessionOpt; - - private QuickInfoItem _item; - private ITrackingSpan _triggerSpan; - - public event EventHandler Dismissed; - - public QuickInfoPresenterSession(IQuickInfoBroker quickInfoBroker, DeferredContentFrameworkElementFactory elementFactory, ITextView textView, ITextBuffer subjectBuffer) - : this(quickInfoBroker, elementFactory, textView, subjectBuffer, null) - { - } - - public QuickInfoPresenterSession(IQuickInfoBroker quickInfoBroker, DeferredContentFrameworkElementFactory elementFactory, ITextView textView, ITextBuffer subjectBuffer, IQuickInfoSession sessionOpt) - { - _quickInfoBroker = quickInfoBroker; - _elementFactory = elementFactory; - _textView = textView; - _subjectBuffer = subjectBuffer; - _editorSessionOpt = sessionOpt; - } - - public void PresentItem(ITrackingSpan triggerSpan, QuickInfoItem item, bool trackMouse) - { - AssertIsForeground(); - - _triggerSpan = triggerSpan; - _item = item; - - // It's a new list of items. Either create the editor session if this is the first time, or ask the - // editor session that we already have to recalculate. - if (_editorSessionOpt == null || _editorSessionOpt.IsDismissed) - { - // We're tracking the caret. Don't have the editor do it. - var triggerPoint = triggerSpan.GetStartTrackingPoint(PointTrackingMode.Negative); - - _editorSessionOpt = _quickInfoBroker.CreateQuickInfoSession(_textView, triggerPoint, trackMouse: trackMouse); - _editorSessionOpt.Dismissed += (s, e) => OnEditorSessionDismissed(); - } - - // So here's the deal. We cannot create the editor session and give it the right - // signatures (even though we know what they are). Instead, the session with - // call back into the ISignatureHelpSourceProvider (which is us) to get those - // values. It will pass itself along with the calls back into - // ISignatureHelpSourceProvider. So, in order to make that connection work, we - // add properties to the session so that we can call back into ourselves, get - // the signatures and add it to the session. - if (!_editorSessionOpt.Properties.ContainsProperty(s_augmentSessionKey)) - { - _editorSessionOpt.Properties.AddProperty(s_augmentSessionKey, this); - } - - _editorSessionOpt.Recalculate(); - } - - public void Dismiss() - { - AssertIsForeground(); - - if (_editorSessionOpt == null) - { - // No editor session, nothing to do here. - return; - } - - if (_item == null) - { - // We don't have an item, so we're being asked to augment a session. - // Since we didn't put anything in the session, don't dismiss it either. - return; - } - - _editorSessionOpt.Dismiss(); - _editorSessionOpt = null; - } - - private void OnEditorSessionDismissed() - { - AssertIsForeground(); - this.Dismissed?.Invoke(this, new EventArgs()); - } - - internal void AugmentQuickInfoSession(IList quickInfoContent, out ITrackingSpan applicableToSpan) - { - applicableToSpan = _triggerSpan; - quickInfoContent.Add(_elementFactory.CreateElement(_item.Content)); - } - } - } -} -#pragma warning restore CS0618 // IQuickInfo* is obsolete, tracked by https://github.com/dotnet/roslyn/issues/24094 diff --git a/src/EditorFeatures/Core.Wpf/QuickInfo/Presentation/QuickInfoPresenter.QuickInfoSource.cs b/src/EditorFeatures/Core.Wpf/QuickInfo/Presentation/QuickInfoPresenter.QuickInfoSource.cs deleted file mode 100644 index ecccc53db6d66..0000000000000 --- a/src/EditorFeatures/Core.Wpf/QuickInfo/Presentation/QuickInfoPresenter.QuickInfoSource.cs +++ /dev/null @@ -1,34 +0,0 @@ -// 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 Microsoft.CodeAnalysis.Editor.Shared.Utilities; -using Microsoft.VisualStudio.Language.Intellisense; -using Microsoft.VisualStudio.Text; - -#pragma warning disable CS0618 // IQuickInfo* is obsolete, tracked by https://github.com/dotnet/roslyn/issues/24094 -namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo.Presentation -{ - internal partial class QuickInfoPresenter - { - private class QuickInfoSource : ForegroundThreadAffinitizedObject, IQuickInfoSource - { - public void AugmentQuickInfoSession(IQuickInfoSession session, IList quickInfoContent, out ITrackingSpan applicableToSpan) - { - AssertIsForeground(); - if (!session.Properties.TryGetProperty(s_augmentSessionKey, out var presenterSession)) - { - applicableToSpan = session.ApplicableToSpan; - return; - } - - session.Properties.RemoveProperty(s_augmentSessionKey); - presenterSession.AugmentQuickInfoSession(quickInfoContent, out applicableToSpan); - } - - public void Dispose() - { - } - } - } -} -#pragma warning restore CS0618 // IQuickInfo* is obsolete, tracked by https://github.com/dotnet/roslyn/issues/24094 diff --git a/src/EditorFeatures/Core.Wpf/QuickInfo/Presentation/QuickInfoPresenter.cs b/src/EditorFeatures/Core.Wpf/QuickInfo/Presentation/QuickInfoPresenter.cs deleted file mode 100644 index 5919a8a84718d..0000000000000 --- a/src/EditorFeatures/Core.Wpf/QuickInfo/Presentation/QuickInfoPresenter.cs +++ /dev/null @@ -1,46 +0,0 @@ -// 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.ComponentModel.Composition; -using Microsoft.CodeAnalysis.Editor.QuickInfo; -using Microsoft.CodeAnalysis.Editor.Shared.Utilities; -using Microsoft.VisualStudio.Language.Intellisense; -using Microsoft.VisualStudio.Text; -using Microsoft.VisualStudio.Text.Editor; -using Microsoft.VisualStudio.Utilities; - -#pragma warning disable CS0618 // IQuickInfo* is obsolete, tracked by https://github.com/dotnet/roslyn/issues/24094 -namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo.Presentation -{ - [Export(typeof(IQuickInfoSourceProvider))] - [Export(typeof(IIntelliSensePresenter))] - [Order] - [Name(PredefinedQuickInfoPresenterNames.RoslynQuickInfoPresenter)] - [ContentType(ContentTypeNames.RoslynContentType)] - internal partial class QuickInfoPresenter : ForegroundThreadAffinitizedObject, IIntelliSensePresenter, IQuickInfoSourceProvider - { - private static readonly object s_augmentSessionKey = new object(); - - private readonly IQuickInfoBroker _quickInfoBroker; - private readonly DeferredContentFrameworkElementFactory _elementFactory; - - [ImportingConstructor] - public QuickInfoPresenter(IQuickInfoBroker quickInfoBroker, DeferredContentFrameworkElementFactory elementFactory) - { - _quickInfoBroker = quickInfoBroker; - _elementFactory = elementFactory; - } - - IQuickInfoPresenterSession IIntelliSensePresenter.CreateSession(ITextView textView, ITextBuffer subjectBuffer, IQuickInfoSession sessionOpt) - { - AssertIsForeground(); - return new QuickInfoPresenterSession(_quickInfoBroker, _elementFactory, textView, subjectBuffer, sessionOpt); - } - - IQuickInfoSource IQuickInfoSourceProvider.TryCreateQuickInfoSource(ITextBuffer textBuffer) - { - AssertIsForeground(); - return new QuickInfoSource(); - } - } -} -#pragma warning restore CS0618 // IQuickInfo* is obsolete, tracked by https://github.com/dotnet/roslyn/issues/24094 diff --git a/src/EditorFeatures/Core.Wpf/QuickInfo/ProjectionBufferContent.cs b/src/EditorFeatures/Core.Wpf/QuickInfo/ProjectionBufferContent.cs new file mode 100644 index 0000000000000..bfc9455ce11fc --- /dev/null +++ b/src/EditorFeatures/Core.Wpf/QuickInfo/ProjectionBufferContent.cs @@ -0,0 +1,95 @@ +// 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; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Controls; +using System.Windows.Media; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; +using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Editor; +using Microsoft.VisualStudio.Text.Projection; +using Microsoft.VisualStudio.Utilities; + +namespace Microsoft.CodeAnalysis.Editor.QuickInfo +{ + /// + /// Creates quick info content out of the span of an existing snapshot. The span will be + /// used to create a projection buffer out that will then be displayed in the quick info + /// window. + /// + internal class ProjectionBufferContent : ForegroundThreadAffinitizedObject + { + private readonly ImmutableArray _spans; + private readonly IProjectionBufferFactoryService _projectionBufferFactoryService; + private readonly IEditorOptionsFactoryService _editorOptionsFactoryService; + private readonly ITextEditorFactoryService _textEditorFactoryService; + private readonly IContentType _contentType; + private readonly ITextViewRoleSet _roleSet; + + private ProjectionBufferContent( + ImmutableArray spans, + IProjectionBufferFactoryService projectionBufferFactoryService, + IEditorOptionsFactoryService editorOptionsFactoryService, + ITextEditorFactoryService textEditorFactoryService, + IContentType contentType = null, + ITextViewRoleSet roleSet = null) + { + _spans = spans; + _projectionBufferFactoryService = projectionBufferFactoryService; + _editorOptionsFactoryService = editorOptionsFactoryService; + _textEditorFactoryService = textEditorFactoryService; + _contentType = contentType; + _roleSet = roleSet ?? _textEditorFactoryService.NoRoles; + } + + public static ContentControl Create( + ImmutableArray spans, + IProjectionBufferFactoryService projectionBufferFactoryService, + IEditorOptionsFactoryService editorOptionsFactoryService, + ITextEditorFactoryService textEditorFactoryService, + IContentType contentType = null, + ITextViewRoleSet roleSet = null) + { + var content = new ProjectionBufferContent( + spans, + projectionBufferFactoryService, + editorOptionsFactoryService, + textEditorFactoryService, + contentType, + roleSet); + + return content.Create(); + } + + private ContentControl Create() + { + AssertIsForeground(); + + return new ViewHostingControl(CreateView, CreateBuffer); + } + + private IWpfTextView CreateView(ITextBuffer buffer) + { + var view = _textEditorFactoryService.CreateTextView(buffer, _roleSet); + + view.SizeToFit(); + view.Background = Brushes.Transparent; + + // Zoom out a bit to shrink the text. + view.ZoomLevel *= 0.75; + + return view; + } + + private IProjectionBuffer CreateBuffer() + { + return _projectionBufferFactoryService.CreateProjectionBufferWithoutIndentation( + _editorOptionsFactoryService.GlobalOptions, _contentType, _spans.ToArray()); + } + } +} diff --git a/src/EditorFeatures/Core.Wpf/QuickInfo/QuickInfoDisplayPanel.cs b/src/EditorFeatures/Core.Wpf/QuickInfo/QuickInfoDisplayPanel.cs deleted file mode 100644 index 09c8fe0ec2c32..0000000000000 --- a/src/EditorFeatures/Core.Wpf/QuickInfo/QuickInfoDisplayPanel.cs +++ /dev/null @@ -1,179 +0,0 @@ -// 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; -using System.Text; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Documents; -using System.Windows.Media; - -namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo -{ - internal class QuickInfoDisplayPanel : StackPanel - { - internal TextBlock MainDescription { get; } - internal TextBlock Documentation { get; } - internal TextBlock TypeParameterMap { get; } - internal TextBlock AnonymousTypes { get; } - internal TextBlock UsageText { get; } - internal TextBlock ExceptionText { get; } - internal TextBlock CapturesText { get; } - - public QuickInfoDisplayPanel( - FrameworkElement symbolGlyph, - FrameworkElement warningGlyph, - FrameworkElement mainDescription, - FrameworkElement documentation, - FrameworkElement typeParameterMap, - FrameworkElement anonymousTypes, - FrameworkElement usageText, - FrameworkElement exceptionText, - FrameworkElement capturesText) - { - this.MainDescription = (TextBlock)mainDescription; - this.Documentation = (TextBlock)documentation; - this.TypeParameterMap = (TextBlock)typeParameterMap; - this.AnonymousTypes = (TextBlock)anonymousTypes; - this.UsageText = (TextBlock)usageText; - this.ExceptionText = (TextBlock)exceptionText; - this.CapturesText = (TextBlock)capturesText; - - this.Orientation = Orientation.Vertical; - - Border symbolGlyphBorder = null; - if (symbolGlyph != null) - { - symbolGlyph.Margin = new Thickness(1, 1, 3, 1); - symbolGlyphBorder = new Border() - { - BorderThickness = new Thickness(0), - BorderBrush = Brushes.Transparent, - VerticalAlignment = VerticalAlignment.Top, - Child = symbolGlyph - }; - } - - mainDescription.Margin = new Thickness(1); - var mainDescriptionBorder = new Border() - { - BorderThickness = new Thickness(0), - BorderBrush = Brushes.Transparent, - VerticalAlignment = VerticalAlignment.Center, - Child = mainDescription - }; - - var symbolGlyphAndMainDescriptionDock = new DockPanel() - { - LastChildFill = true, - HorizontalAlignment = HorizontalAlignment.Stretch, - Background = Brushes.Transparent - }; - - if (symbolGlyphBorder != null) - { - symbolGlyphAndMainDescriptionDock.Children.Add(symbolGlyphBorder); - } - - symbolGlyphAndMainDescriptionDock.Children.Add(mainDescriptionBorder); - - if (warningGlyph != null) - { - warningGlyph.Margin = new Thickness(1, 1, 3, 1); - var warningGlyphBorder = new Border() - { - BorderThickness = new Thickness(0), - BorderBrush = Brushes.Transparent, - VerticalAlignment = VerticalAlignment.Center, - HorizontalAlignment = HorizontalAlignment.Right, - Child = warningGlyph - }; - - symbolGlyphAndMainDescriptionDock.Children.Add(warningGlyphBorder); - } - - this.Children.Add(symbolGlyphAndMainDescriptionDock); - this.Children.Add(documentation); - this.Children.Add(usageText); - this.Children.Add(typeParameterMap); - this.Children.Add(anonymousTypes); - this.Children.Add(exceptionText); - this.Children.Add(capturesText); - } - - public override string ToString() - { - var sb = new StringBuilder(); - - BuildStringFromInlineCollection(this.MainDescription.Inlines, sb); - - if (this.Documentation.Inlines.Count > 0) - { - sb.AppendLine(); - BuildStringFromInlineCollection(this.Documentation.Inlines, sb); - } - - if (this.TypeParameterMap.Inlines.Count > 0) - { - sb.AppendLine(); - BuildStringFromInlineCollection(this.TypeParameterMap.Inlines, sb); - } - - if (this.AnonymousTypes.Inlines.Count > 0) - { - sb.AppendLine(); - BuildStringFromInlineCollection(this.AnonymousTypes.Inlines, sb); - } - - if (this.UsageText.Inlines.Count > 0) - { - sb.AppendLine(); - BuildStringFromInlineCollection(this.UsageText.Inlines, sb); - } - - if (this.ExceptionText.Inlines.Count > 0) - { - sb.AppendLine(); - BuildStringFromInlineCollection(this.ExceptionText.Inlines, sb); - } - - if (this.CapturesText.Inlines.Count > 0) - { - sb.AppendLine(); - BuildStringFromInlineCollection(this.CapturesText.Inlines, sb); - } - - return sb.ToString(); - } - - private static void BuildStringFromInlineCollection(InlineCollection inlines, StringBuilder sb) - { - foreach (var inline in inlines) - { - if (inline != null) - { - var inlineText = GetStringFromInline(inline); - if (!string.IsNullOrEmpty(inlineText)) - { - sb.Append(inlineText); - } - } - } - } - - private static string GetStringFromInline(Inline currentInline) - { - if (currentInline is LineBreak lineBreak) - { - return Environment.NewLine; - } - - var run = currentInline as Run; - if (run == null) - { - return null; - } - - return run.Text; - } - } -} diff --git a/src/EditorFeatures/Core.Wpf/Tags/DefaultImageMonikerService.cs b/src/EditorFeatures/Core.Wpf/Tags/DefaultImageMonikerService.cs index 338a74ea2fecb..7a2d5824040ac 100644 --- a/src/EditorFeatures/Core.Wpf/Tags/DefaultImageMonikerService.cs +++ b/src/EditorFeatures/Core.Wpf/Tags/DefaultImageMonikerService.cs @@ -2,7 +2,6 @@ using System.Collections.Immutable; using System.Composition; -using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Wpf; using Microsoft.VisualStudio.Imaging; using Microsoft.VisualStudio.Imaging.Interop; @@ -16,7 +15,7 @@ internal class DefaultImageMonikerService : IImageMonikerService public bool TryGetImageMoniker(ImmutableArray tags, out ImageMoniker imageMoniker) { - var glyph = tags.GetGlyph(); + var glyph = tags.GetFirstGlyph(); // We can't do the compositing of these glyphs at the editor layer. So just map them // to the non-add versions. diff --git a/src/EditorFeatures/Core.Wpf/WpfClassificationExtensions.cs b/src/EditorFeatures/Core.Wpf/WpfClassificationExtensions.cs index fa3429ca14ce2..2de70c5af65d2 100644 --- a/src/EditorFeatures/Core.Wpf/WpfClassificationExtensions.cs +++ b/src/EditorFeatures/Core.Wpf/WpfClassificationExtensions.cs @@ -8,7 +8,6 @@ using System.Windows.Documents; using Microsoft.CodeAnalysis.Classification; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; -using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Classification; using Roslyn.Utilities; @@ -78,12 +77,12 @@ public static TextBlock ToTextBlock( string classificationFormatMap = null, bool wrap = true) { - var textBlock = new TextBlock { TextWrapping = wrap ? TextWrapping.Wrap : TextWrapping.NoWrap, TextTrimming = wrap ? TextTrimming.None : TextTrimming.CharacterEllipsis }; + textBlock.SetDefaultTextProperties(formatMap); textBlock.Inlines.AddRange(inlines); diff --git a/src/EditorFeatures/Core/CommandHandlers/AbstractIntelliSenseCommandHandler.cs b/src/EditorFeatures/Core/CommandHandlers/AbstractIntelliSenseCommandHandler.cs index bb3ddea75faae..c3e634b140adf 100644 --- a/src/EditorFeatures/Core/CommandHandlers/AbstractIntelliSenseCommandHandler.cs +++ b/src/EditorFeatures/Core/CommandHandlers/AbstractIntelliSenseCommandHandler.cs @@ -29,19 +29,16 @@ internal abstract class AbstractIntelliSenseCommandHandler : IChainedCommandHandler { private readonly CompletionCommandHandler _completionCommandHandler; - private readonly SignatureHelpCommandHandler _signatureHelpCommandHandler; - private readonly QuickInfoCommandHandlerAndSourceProvider _quickInfoCommandHandler; + private readonly SignatureHelpCommandHandler _signatureHelpCommandHandler; public string DisplayName => EditorFeaturesResources.IntelliSense; protected AbstractIntelliSenseCommandHandler( CompletionCommandHandler completionCommandHandler, - SignatureHelpCommandHandler signatureHelpCommandHandler, - QuickInfoCommandHandlerAndSourceProvider quickInfoCommandHandler) + SignatureHelpCommandHandler signatureHelpCommandHandler) { _completionCommandHandler = completionCommandHandler; - _signatureHelpCommandHandler = signatureHelpCommandHandler; - _quickInfoCommandHandler = quickInfoCommandHandler; + _signatureHelpCommandHandler = signatureHelpCommandHandler; } public VSCommanding.CommandState GetCommandState(EscapeKeyCommandArgs args, Func nextHandler) @@ -62,8 +59,7 @@ public VSCommanding.CommandState GetCommandState(DownKeyCommandArgs args, Func quickInfoContent, out ITrackingSpan applicableToSpan) - { - applicableToSpan = null; - if (quickInfoContent.Count != 0 || - session.Properties.TryGetProperty(QuickInfoUtilities.EventHookupKey, out object eventHookupValue)) - { - // No quickinfo if it's the event hookup popup. - return; - } - - var position = session.GetTriggerPoint(_subjectBuffer.CurrentSnapshot); - if (position.HasValue) - { - var textView = session.TextView; - var args = new InvokeQuickInfoCommandArgs(textView, _subjectBuffer); - if (_commandHandler.TryGetController(args, out var controller)) - { - controller.InvokeQuickInfo(position.Value, trackMouse: session.TrackMouse, augmentSession: session); - } - } - } - - public void Dispose() - { - } - } - } -} -#pragma warning restore CS0618 // IQuickInfo* is obsolete, tracked by https://github.com/dotnet/roslyn/issues/24094 diff --git a/src/EditorFeatures/Core/CommandHandlers/QuickInfoCommandHandlerAndSourceProvider.cs b/src/EditorFeatures/Core/CommandHandlers/QuickInfoCommandHandlerAndSourceProvider.cs deleted file mode 100644 index 412ea944ac401..0000000000000 --- a/src/EditorFeatures/Core/CommandHandlers/QuickInfoCommandHandlerAndSourceProvider.cs +++ /dev/null @@ -1,98 +0,0 @@ -// 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; -using System.Collections.Generic; -using System.ComponentModel.Composition; -using System.Linq; -using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo; -using Microsoft.CodeAnalysis.Editor.Shared.Extensions; -using Microsoft.CodeAnalysis.Editor.Shared.Options; -using Microsoft.CodeAnalysis.Editor.Shared.Utilities; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Shared.TestHooks; -using Microsoft.CodeAnalysis.Shared.Utilities; -using Microsoft.VisualStudio.Language.Intellisense; -using Microsoft.VisualStudio.Text; -using Microsoft.VisualStudio.Text.Editor.Commanding; -using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; -using Microsoft.VisualStudio.Utilities; - -#pragma warning disable CS0618 // IQuickInfo* is obsolete, tracked by https://github.com/dotnet/roslyn/issues/24094 -namespace Microsoft.CodeAnalysis.Editor.CommandHandlers -{ - [Export] - [Order(After = PredefinedQuickInfoPresenterNames.RoslynQuickInfoPresenter)] - [ContentType(ContentTypeNames.RoslynContentType)] - [Export(typeof(IQuickInfoSourceProvider))] - [Name("RoslynQuickInfoProvider")] - internal partial class QuickInfoCommandHandlerAndSourceProvider : - ForegroundThreadAffinitizedObject, - IQuickInfoSourceProvider - { - private readonly IAsynchronousOperationListener _listener; - private readonly IIntelliSensePresenter _presenter; - private readonly IList> _providers; - - [ImportingConstructor] - public QuickInfoCommandHandlerAndSourceProvider( - [ImportMany] IEnumerable, OrderableMetadata>> presenters, - [ImportMany] IEnumerable> providers, - IAsynchronousOperationListenerProvider listenerProvider) - : this(ExtensionOrderer.Order(presenters).Select(lazy => lazy.Value).FirstOrDefault(), - providers, listenerProvider) - { - } - - // For testing purposes. - public QuickInfoCommandHandlerAndSourceProvider( - IIntelliSensePresenter presenter, - [ImportMany] IEnumerable> providers, - IAsynchronousOperationListenerProvider listenerProvider) - { - _providers = ExtensionOrderer.Order(providers); - _listener = listenerProvider.GetListener(FeatureAttribute.QuickInfo); - _presenter = presenter; - } - - private bool TryGetController(EditorCommandArgs args, out Controller controller) - { - AssertIsForeground(); - - // check whether this feature is on. - if (!args.SubjectBuffer.GetFeatureOnOffOption(InternalFeatureOnOffOptions.QuickInfo)) - { - controller = null; - return false; - } - - // If we don't have a presenter, then there's no point in us even being involved. Just - // defer to the next handler in the chain. - if (_presenter == null) - { - controller = null; - return false; - } - - // TODO(cyrusn): If there are no presenters then we should not create a controller. - // Otherwise we'll be affecting the user's typing and they'll have no idea why :) - controller = Controller.GetInstance(args, _presenter, _listener, _providers); - return true; - } - - public IQuickInfoSource TryCreateQuickInfoSource(ITextBuffer textBuffer) - { - return new QuickInfoSource(this, textBuffer); - } - - internal bool TryHandleEscapeKey(EscapeKeyCommandArgs commandArgs) - { - if (!TryGetController(commandArgs, out var controller)) - { - return false; - } - - return controller.TryHandleEscapeKey(); - } - } -} -#pragma warning restore CS0618 // IQuickInfo* is obsolete, tracked by https://github.com/dotnet/roslyn/issues/24094 diff --git a/src/EditorFeatures/Core/Commands/InvokeQuickInfoCommandArgs.cs b/src/EditorFeatures/Core/Commands/InvokeQuickInfoCommandArgs.cs deleted file mode 100644 index 01108defbefed..0000000000000 --- a/src/EditorFeatures/Core/Commands/InvokeQuickInfoCommandArgs.cs +++ /dev/null @@ -1,17 +0,0 @@ -// 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.Diagnostics.CodeAnalysis; -using Microsoft.VisualStudio.Text; -using Microsoft.VisualStudio.Text.Editor; - -namespace Microsoft.CodeAnalysis.Editor.Commands -{ - [ExcludeFromCodeCoverage] - internal class InvokeQuickInfoCommandArgs : CommandArgs - { - public InvokeQuickInfoCommandArgs(ITextView textView, ITextBuffer subjectBuffer) - : base(textView, subjectBuffer) - { - } - } -} diff --git a/src/EditorFeatures/Core/Extensibility/QuickInfo/IDeferredQuickInfoContent.cs b/src/EditorFeatures/Core/Extensibility/QuickInfo/IDeferredQuickInfoContent.cs deleted file mode 100644 index 69ad57188d27c..0000000000000 --- a/src/EditorFeatures/Core/Extensibility/QuickInfo/IDeferredQuickInfoContent.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -namespace Microsoft.CodeAnalysis.Editor -{ - /// - /// Interface to allow providers to return some sort of quick info content whose creation can be - /// deferred to a later point (and on the UI thread) - /// - internal interface IDeferredQuickInfoContent - { - } -} diff --git a/src/EditorFeatures/Core/Extensibility/QuickInfo/IQuickInfoPresenterSession.cs b/src/EditorFeatures/Core/Extensibility/QuickInfo/IQuickInfoPresenterSession.cs deleted file mode 100644 index fc35c9ef96080..0000000000000 --- a/src/EditorFeatures/Core/Extensibility/QuickInfo/IQuickInfoPresenterSession.cs +++ /dev/null @@ -1,11 +0,0 @@ -// 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 Microsoft.VisualStudio.Text; - -namespace Microsoft.CodeAnalysis.Editor -{ - internal interface IQuickInfoPresenterSession : IIntelliSensePresenterSession - { - void PresentItem(ITrackingSpan triggerSpan, QuickInfoItem item, bool trackMouse); - } -} diff --git a/src/EditorFeatures/Core/Extensibility/QuickInfo/IQuickInfoProvider.cs b/src/EditorFeatures/Core/Extensibility/QuickInfo/IQuickInfoProvider.cs deleted file mode 100644 index 367f8dc890cab..0000000000000 --- a/src/EditorFeatures/Core/Extensibility/QuickInfo/IQuickInfoProvider.cs +++ /dev/null @@ -1,12 +0,0 @@ -// 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.Threading; -using System.Threading.Tasks; - -namespace Microsoft.CodeAnalysis.Editor -{ - internal interface IQuickInfoProvider - { - Task GetItemAsync(Document document, int position, CancellationToken cancellationToken); - } -} diff --git a/src/EditorFeatures/Core/Extensibility/QuickInfo/PredefinedQuickInfoPresenterNames.cs b/src/EditorFeatures/Core/Extensibility/QuickInfo/PredefinedQuickInfoPresenterNames.cs deleted file mode 100644 index 9081428a3cb9c..0000000000000 --- a/src/EditorFeatures/Core/Extensibility/QuickInfo/PredefinedQuickInfoPresenterNames.cs +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -namespace Microsoft.CodeAnalysis.Editor -{ - internal static class PredefinedQuickInfoPresenterNames - { - public const string RoslynQuickInfoPresenter = "Roslyn Quick Info Presenter"; - } -} diff --git a/src/EditorFeatures/Core/Extensibility/QuickInfo/PredefinedQuickInfoProviderNames.cs b/src/EditorFeatures/Core/Extensibility/QuickInfo/PredefinedQuickInfoProviderNames.cs deleted file mode 100644 index 342eb1643e978..0000000000000 --- a/src/EditorFeatures/Core/Extensibility/QuickInfo/PredefinedQuickInfoProviderNames.cs +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -namespace Microsoft.CodeAnalysis.Editor -{ - internal static class PredefinedQuickInfoProviderNames - { - public const string EventHookup = "Event Hookup QuickInfo Source"; - public const string Semantic = "Semantic Quick Info Provider"; - public const string Syntactic = "Syntactic Quick Info Provider"; - } -} diff --git a/src/EditorFeatures/Core/Extensibility/QuickInfo/QuickInfoItem.cs b/src/EditorFeatures/Core/Extensibility/QuickInfo/QuickInfoItem.cs deleted file mode 100644 index 6a280fbd70bf2..0000000000000 --- a/src/EditorFeatures/Core/Extensibility/QuickInfo/QuickInfoItem.cs +++ /dev/null @@ -1,18 +0,0 @@ -// 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 Microsoft.CodeAnalysis.Text; - -namespace Microsoft.CodeAnalysis.Editor -{ - internal class QuickInfoItem - { - public TextSpan TextSpan { get; } - public IDeferredQuickInfoContent Content { get; } - - public QuickInfoItem(TextSpan textSpan, IDeferredQuickInfoContent content) - { - this.TextSpan = textSpan; - this.Content = content; - } - } -} diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/ModelComputation.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/ModelComputation.cs index 708d1a6de4228..6c91c888442d4 100644 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/ModelComputation.cs +++ b/src/EditorFeatures/Core/Implementation/IntelliSense/ModelComputation.cs @@ -121,6 +121,7 @@ public void ChainTaskAndNotifyControllerWhenFinished( bool updateController = true) { AssertIsForeground(); + Contract.ThrowIfTrue(_stopCancellationToken.IsCancellationRequested, "should not chain tasks after we've been cancelled"); // Mark that an async operation has begun. This way tests know to wait until the diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/Controller.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/Controller.cs deleted file mode 100644 index 4a76a11142e64..0000000000000 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/Controller.cs +++ /dev/null @@ -1,171 +0,0 @@ -// 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; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.Shared.Extensions; -using Microsoft.CodeAnalysis.ErrorReporting; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.Shared.TestHooks; -using Microsoft.CodeAnalysis.Text; -using Microsoft.VisualStudio.Language.Intellisense; -using Microsoft.VisualStudio.Text; -using Microsoft.VisualStudio.Text.Editor; -using Microsoft.VisualStudio.Text.Editor.Commanding; -using Roslyn.Utilities; - -#pragma warning disable CS0618 // IQuickInfo* is obsolete, tracked by https://github.com/dotnet/roslyn/issues/24094 -namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo -{ - internal partial class Controller : - AbstractController, Model, IQuickInfoPresenterSession, IQuickInfoSession> - { - private static readonly object s_quickInfoPropertyKey = new object(); - - private readonly IList> _allProviders; - private IList _providers; - - public Controller( - ITextView textView, - ITextBuffer subjectBuffer, - IIntelliSensePresenter presenter, - IAsynchronousOperationListener asyncListener, - IDocumentProvider documentProvider, - IList> allProviders) - : base(textView, subjectBuffer, presenter, asyncListener, documentProvider, "QuickInfo") - { - _allProviders = allProviders; - } - - // For testing purposes - internal Controller( - ITextView textView, - ITextBuffer subjectBuffer, - IIntelliSensePresenter presenter, - IAsynchronousOperationListener asyncListener, - IDocumentProvider documentProvider, - IList providers) - : base(textView, subjectBuffer, presenter, asyncListener, documentProvider, "QuickInfo") - { - _providers = providers; - } - - internal static Controller GetInstance( - EditorCommandArgs args, - IIntelliSensePresenter presenter, - IAsynchronousOperationListener asyncListener, - IList> allProviders) - { - var textView = args.TextView; - var subjectBuffer = args.SubjectBuffer; - return textView.GetOrCreatePerSubjectBufferProperty(subjectBuffer, s_quickInfoPropertyKey, - (v, b) => new Controller(v, b, - presenter, - asyncListener, - new DocumentProvider(), - allProviders)); - } - - internal override void OnModelUpdated(Model modelOpt) - { - AssertIsForeground(); - if (modelOpt == null || modelOpt.TextVersion != this.SubjectBuffer.CurrentSnapshot.Version) - { - this.StopModelComputation(); - } - else - { - var quickInfoItem = modelOpt.Item; - - // We want the span to actually only go up to the caret. So get the expected span - // and then update its end point accordingly. - var triggerSpan = modelOpt.GetCurrentSpanInSnapshot(quickInfoItem.TextSpan, this.SubjectBuffer.CurrentSnapshot); - var trackingSpan = triggerSpan.CreateTrackingSpan(SpanTrackingMode.EdgeInclusive); - - sessionOpt.PresenterSession.PresentItem(trackingSpan, quickInfoItem, modelOpt.TrackMouse); - } - } - - public void StartSession( - int position, - bool trackMouse, - IQuickInfoSession augmentSession = null) - { - AssertIsForeground(); - - var providers = GetProviders(); - if (providers == null) - { - return; - } - - var snapshot = this.SubjectBuffer.CurrentSnapshot; - this.sessionOpt = new Session(this, new ModelComputation(this, TaskScheduler.Default), - this.Presenter.CreateSession(this.TextView, this.SubjectBuffer, augmentSession)); - - this.sessionOpt.Computation.ChainTaskAndNotifyControllerWhenFinished( - (model, cancellationToken) => ComputeModelInBackgroundAsync(position, snapshot, providers, trackMouse, cancellationToken)); - } - - public IList GetProviders() - { - this.AssertIsForeground(); - - if (_providers == null) - { - var snapshot = this.SubjectBuffer.CurrentSnapshot; - var document = snapshot.GetOpenDocumentInCurrentContextWithChanges(); - if (document != null) - { - _providers = document.Project.LanguageServices.WorkspaceServices.SelectMatchingExtensionValues(_allProviders, this.SubjectBuffer.ContentType); - } - } - - return _providers; - } - - private async Task ComputeModelInBackgroundAsync( - int position, - ITextSnapshot snapshot, - IList providers, - bool trackMouse, - CancellationToken cancellationToken) - { - try - { - AssertIsBackground(); - - using (Logger.LogBlock(FunctionId.QuickInfo_ModelComputation_ComputeModelInBackground, cancellationToken)) - { - cancellationToken.ThrowIfCancellationRequested(); - - var document = await DocumentProvider.GetDocumentAsync(snapshot, cancellationToken).ConfigureAwait(false); - if (document == null) - { - return null; - } - - foreach (var provider in providers) - { - // TODO(cyrusn): We're calling into extensions, we need to make ourselves resilient - // to the extension crashing. - var item = await provider.GetItemAsync(document, position, cancellationToken).ConfigureAwait(false); - if (item != null) - { - return new Model(snapshot.Version, item, provider, trackMouse); - } - } - - return null; - } - } - catch (Exception e) when (FatalError.ReportUnlessCanceled(e)) - { - throw ExceptionUtilities.Unreachable; - } - } - } -} -#pragma warning restore CS0618 // IQuickInfo* is obsolete, tracked by https://github.com/dotnet/roslyn/issues/24094 diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/Controller_InvokeQuickInfo.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/Controller_InvokeQuickInfo.cs deleted file mode 100644 index 7a92afb718617..0000000000000 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/Controller_InvokeQuickInfo.cs +++ /dev/null @@ -1,18 +0,0 @@ -// 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 Microsoft.VisualStudio.Language.Intellisense; - -namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo -{ - internal partial class Controller - { -#pragma warning disable CS0618 // IQuickInfo* is obsolete, tracked by https://github.com/dotnet/roslyn/issues/24094 - public void InvokeQuickInfo(int position, bool trackMouse, IQuickInfoSession augmentSession) - { - AssertIsForeground(); - DismissSessionIfActive(); - StartSession(position, trackMouse, augmentSession); - } -#pragma warning restore CS0618 // IQuickInfo* is obsolete, tracked by https://github.com/dotnet/roslyn/issues/24094 - } -} diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/Controller_OnCaretPositionChanged.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/Controller_OnCaretPositionChanged.cs deleted file mode 100644 index 26ac2cd7b94e6..0000000000000 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/Controller_OnCaretPositionChanged.cs +++ /dev/null @@ -1,16 +0,0 @@ -// 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; - -namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo -{ - internal partial class Controller - { - internal override void OnCaretPositionChanged(object sender, EventArgs args) - { - // Any time the caret moves or text changes, we stop what we're doing. - AssertIsForeground(); - DismissSessionIfActive(); - } - } -} diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/Controller_OnTextViewBufferPostChanged.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/Controller_OnTextViewBufferPostChanged.cs deleted file mode 100644 index cc469dfde3345..0000000000000 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/Controller_OnTextViewBufferPostChanged.cs +++ /dev/null @@ -1,16 +0,0 @@ -// 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; - -namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo -{ - internal partial class Controller - { - internal override void OnTextViewBufferPostChanged(object sender, EventArgs args) - { - // Any time the caret moves or text changes, we stop what we're doing. - AssertIsForeground(); - DismissSessionIfActive(); - } - } -} diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/DeferredContent/ClassifiableDeferredContent.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/DeferredContent/ClassifiableDeferredContent.cs deleted file mode 100644 index 3acc7484a20fc..0000000000000 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/DeferredContent/ClassifiableDeferredContent.cs +++ /dev/null @@ -1,17 +0,0 @@ -// 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; - -namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo -{ - internal class ClassifiableDeferredContent : IDeferredQuickInfoContent - { - internal readonly IList ClassifiableContent; - - public ClassifiableDeferredContent( - IList content) - { - this.ClassifiableContent = content; - } - } -} diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/DeferredContent/ProjectionBufferDeferredContent.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/DeferredContent/ProjectionBufferDeferredContent.cs deleted file mode 100644 index 92b4388b6d945..0000000000000 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/DeferredContent/ProjectionBufferDeferredContent.cs +++ /dev/null @@ -1,30 +0,0 @@ -// 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 Microsoft.VisualStudio.Text; -using Microsoft.VisualStudio.Text.Editor; -using Microsoft.VisualStudio.Utilities; - -namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo -{ - /// - /// Creates quick info content out of the span of an existing snapshot. The span will be - /// used to create an projection buffer out that will then be displayed in the quick info - /// window. - /// - internal class ProjectionBufferDeferredContent : IDeferredQuickInfoContent - { - internal SnapshotSpan Span { get; } - internal IContentType ContentType { get; } - internal ITextViewRoleSet RoleSet { get; } - - public ProjectionBufferDeferredContent( - SnapshotSpan span, - IContentType contentType = null, - ITextViewRoleSet roleSet = null) - { - Span = span; - ContentType = contentType; - RoleSet = roleSet; - } - } -} diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/DeferredContent/QuickInfoDisplayDeferredContent.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/DeferredContent/QuickInfoDisplayDeferredContent.cs deleted file mode 100644 index 50581f5601090..0000000000000 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/DeferredContent/QuickInfoDisplayDeferredContent.cs +++ /dev/null @@ -1,64 +0,0 @@ -// 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; - -namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo -{ - internal class QuickInfoDisplayDeferredContent : IDeferredQuickInfoContent - { - public IDeferredQuickInfoContent SymbolGlyph { get; } - public IDeferredQuickInfoContent MainDescription { get; } - public IDeferredQuickInfoContent Documentation { get; } - public IDeferredQuickInfoContent TypeParameterMap { get; } - public IDeferredQuickInfoContent AnonymousTypes { get; } - public IDeferredQuickInfoContent UsageText { get; } - public IDeferredQuickInfoContent ExceptionText { get; } - public IDeferredQuickInfoContent CapturesText { get; } - public IDeferredQuickInfoContent WarningGlyph { get; } - - // DO NOT REMOVE: compat for Typescript - public QuickInfoDisplayDeferredContent( - IDeferredQuickInfoContent symbolGlyph, - IDeferredQuickInfoContent warningGlyph, - IDeferredQuickInfoContent mainDescription, - IDeferredQuickInfoContent documentation, - IDeferredQuickInfoContent typeParameterMap, - IDeferredQuickInfoContent anonymousTypes, - IDeferredQuickInfoContent usageText, - IDeferredQuickInfoContent exceptionText) - : this( - symbolGlyph, - warningGlyph, - mainDescription, - documentation, - typeParameterMap, - anonymousTypes, - usageText, - exceptionText, - capturesText: new ClassifiableDeferredContent(new List())) - { - } - - public QuickInfoDisplayDeferredContent( - IDeferredQuickInfoContent symbolGlyph, - IDeferredQuickInfoContent warningGlyph, - IDeferredQuickInfoContent mainDescription, - IDeferredQuickInfoContent documentation, - IDeferredQuickInfoContent typeParameterMap, - IDeferredQuickInfoContent anonymousTypes, - IDeferredQuickInfoContent usageText, - IDeferredQuickInfoContent exceptionText, - IDeferredQuickInfoContent capturesText) - { - SymbolGlyph = symbolGlyph; - WarningGlyph = warningGlyph; - MainDescription = mainDescription; - Documentation = documentation; - TypeParameterMap = typeParameterMap; - AnonymousTypes = anonymousTypes; - UsageText = usageText; - ExceptionText = exceptionText; - CapturesText = capturesText; - } - } -} diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/DeferredContent/SymbolGlyphDeferredContent.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/DeferredContent/SymbolGlyphDeferredContent.cs deleted file mode 100644 index 2c550383f1a6d..0000000000000 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/DeferredContent/SymbolGlyphDeferredContent.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo -{ - internal class SymbolGlyphDeferredContent : IDeferredQuickInfoContent - { - internal Glyph Glyph { get; } - - public SymbolGlyphDeferredContent(Glyph glyph) - { - Glyph = glyph; - } - } -} diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/IntellisenseQuickInfoBuilder.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/IntellisenseQuickInfoBuilder.cs new file mode 100644 index 0000000000000..5ab0493cd82aa --- /dev/null +++ b/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/IntellisenseQuickInfoBuilder.cs @@ -0,0 +1,64 @@ +// 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.Linq; +using Microsoft.CodeAnalysis.Editor.Shared.Extensions; +using Microsoft.CodeAnalysis.QuickInfo; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Adornments; + +using CodeAnalysisQuickInfoItem = Microsoft.CodeAnalysis.QuickInfo.QuickInfoItem; +using IntellisenseQuickInfoItem = Microsoft.VisualStudio.Language.Intellisense.QuickInfoItem; + +namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo +{ + internal static class IntellisenseQuickInfoBuilder + { + internal static IntellisenseQuickInfoItem BuildItem(ITrackingSpan trackingSpan, CodeAnalysisQuickInfoItem quickInfoItem) + { + // Build the first line of QuickInfo item, the images and the Description section should be on the first line with Wrapped style + var glyphs = quickInfoItem.Tags.GetGlyphs(); + var symbolGlyph = glyphs.FirstOrDefault(g => g != Glyph.CompletionWarning); + var warningGlyph = glyphs.FirstOrDefault(g => g == Glyph.CompletionWarning); + var firstLineElements = new List(); + if (symbolGlyph != Glyph.None) + { + firstLineElements.Add(new ImageElement(symbolGlyph.GetImageId())); + } + + if (warningGlyph != Glyph.None) + { + firstLineElements.Add(new ImageElement(warningGlyph.GetImageId())); + } + + var descSection = quickInfoItem.Sections.FirstOrDefault(s => s.Kind == QuickInfoSectionKinds.Description); + if (descSection != null) + { + firstLineElements.Add(BuildClassifiedTextElement(descSection)); + } + + var elements = new List + { + new ContainerElement(ContainerElementStyle.Wrapped, firstLineElements) + }; + + // Add the remaining sections as Stacked style + elements.AddRange( + quickInfoItem.Sections.Where(s => s.Kind != QuickInfoSectionKinds.Description) + .Select(BuildClassifiedTextElement)); + + var content = new ContainerElement( + ContainerElementStyle.Stacked, + elements); + + return new IntellisenseQuickInfoItem(trackingSpan, content); + } + + private static ClassifiedTextElement BuildClassifiedTextElement(QuickInfoSection section) + { + return new ClassifiedTextElement(section.TaggedParts.Select( + part => new ClassifiedTextRun(part.Tag.ToClassificationTypeName(), part.Text))); + } + + } +} diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/Model.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/Model.cs index ba37c6ced2a6c..deeb51e7a1a0d 100644 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/Model.cs +++ b/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/Model.cs @@ -1,5 +1,6 @@ // 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 Microsoft.CodeAnalysis.QuickInfo; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text.Shared.Extensions; using Microsoft.VisualStudio.Text; @@ -11,20 +12,17 @@ internal class Model { public ITextVersion TextVersion { get; } public QuickInfoItem Item { get; } - public IQuickInfoProvider Provider { get; } public bool TrackMouse { get; } public Model( ITextVersion textVersion, QuickInfoItem item, - IQuickInfoProvider provider, bool trackMouse) { Contract.ThrowIfNull(item); this.TextVersion = textVersion; this.Item = item; - this.Provider = provider; this.TrackMouse = trackMouse; } diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/Providers/AbstractQuickInfoProvider.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/Providers/AbstractQuickInfoProvider.cs deleted file mode 100644 index c6f4fc31cf406..0000000000000 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/Providers/AbstractQuickInfoProvider.cs +++ /dev/null @@ -1,143 +0,0 @@ -// 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.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.Shared.Utilities; -using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.VisualStudio.Language.Intellisense; -using Microsoft.VisualStudio.Text; -using Microsoft.VisualStudio.Text.Editor; -using Microsoft.VisualStudio.Text.Projection; -using Microsoft.VisualStudio.Utilities; - -namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo -{ - internal abstract partial class AbstractQuickInfoProvider : IQuickInfoProvider - { - public async Task GetItemAsync( - Document document, - int position, - CancellationToken cancellationToken) - { - var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); - var token = await tree.GetTouchingTokenAsync(position, cancellationToken, findInsideTrivia: true).ConfigureAwait(false); - - var state = await GetQuickInfoItemAsync(document, token, position, cancellationToken).ConfigureAwait(false); - if (state != null) - { - return state; - } - - if (ShouldCheckPreviousToken(token)) - { - var previousToken = token.GetPreviousToken(); - - if ((state = await GetQuickInfoItemAsync(document, previousToken, position, cancellationToken).ConfigureAwait(false)) != null) - { - return state; - } - } - - return null; - } - - protected virtual bool ShouldCheckPreviousToken(SyntaxToken token) - { - return true; - } - - private async Task GetQuickInfoItemAsync( - Document document, - SyntaxToken token, - int position, - CancellationToken cancellationToken) - { - if (token != default && - token.Span.IntersectsWith(position)) - { - var deferredContent = await BuildContentAsync(document, token, cancellationToken).ConfigureAwait(false); - if (deferredContent != null) - { - return new QuickInfoItem(token.Span, deferredContent); - } - } - - return null; - } - - protected abstract Task BuildContentAsync(Document document, SyntaxToken token, CancellationToken cancellationToken); - - protected IDeferredQuickInfoContent CreateQuickInfoDisplayDeferredContent( - ISymbol symbol, - bool showWarningGlyph, - bool showSymbolGlyph, - IList mainDescription, - IDeferredQuickInfoContent documentation, - IList typeParameterMap, - IList anonymousTypes, - IList usageText, - IList exceptionText, - IList capturesText) - { - return new QuickInfoDisplayDeferredContent( - symbolGlyph: showSymbolGlyph ? CreateGlyphDeferredContent(symbol) : null, - warningGlyph: showWarningGlyph ? CreateWarningGlyph() : null, - mainDescription: CreateClassifiableDeferredContent(mainDescription), - documentation: documentation, - typeParameterMap: CreateClassifiableDeferredContent(typeParameterMap), - anonymousTypes: CreateClassifiableDeferredContent(anonymousTypes), - usageText: CreateClassifiableDeferredContent(usageText), - exceptionText: CreateClassifiableDeferredContent(exceptionText), - capturesText: CreateClassifiableDeferredContent(capturesText)); - } - - private IDeferredQuickInfoContent CreateWarningGlyph() - { - return new SymbolGlyphDeferredContent(Glyph.CompletionWarning); - } - - protected IDeferredQuickInfoContent CreateQuickInfoDisplayDeferredContent( - Glyph glyph, - IList mainDescription, - IDeferredQuickInfoContent documentation, - IList typeParameterMap, - IList anonymousTypes, - IList usageText, - IList exceptionText) - { - return new QuickInfoDisplayDeferredContent( - symbolGlyph: new SymbolGlyphDeferredContent(glyph), - warningGlyph: null, - mainDescription: CreateClassifiableDeferredContent(mainDescription), - documentation: documentation, - typeParameterMap: CreateClassifiableDeferredContent(typeParameterMap), - anonymousTypes: CreateClassifiableDeferredContent(anonymousTypes), - usageText: CreateClassifiableDeferredContent(usageText), - exceptionText: CreateClassifiableDeferredContent(exceptionText), - capturesText: null); - } - - protected IDeferredQuickInfoContent CreateGlyphDeferredContent(ISymbol symbol) - { - return new SymbolGlyphDeferredContent(symbol.GetGlyph()); - } - - protected IDeferredQuickInfoContent CreateClassifiableDeferredContent( - IList content) - { - return new ClassifiableDeferredContent(content); - } - - protected IDeferredQuickInfoContent CreateDocumentationCommentDeferredContent( - string documentationComment) - { - return new DocumentationCommentDeferredContent(documentationComment); - } - - protected IDeferredQuickInfoContent CreateProjectionBufferDeferredContent(SnapshotSpan span) - { - return new ProjectionBufferDeferredContent(span); - } - } -} diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/Providers/DocumentationCommentDeferredContent.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/Providers/DocumentationCommentDeferredContent.cs deleted file mode 100644 index 87ab72481da85..0000000000000 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/Providers/DocumentationCommentDeferredContent.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo -{ - internal class DocumentationCommentDeferredContent : IDeferredQuickInfoContent - { - internal string DocumentationComment { get; } - - internal void WaitForDocumentationCommentTask_ForTestingPurposesOnly() - { - } - - public DocumentationCommentDeferredContent( - string documentationComment) - { - DocumentationComment = documentationComment; - } - - } -} diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/QuickInfoSourceProvider.QuickInfoSource.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/QuickInfoSourceProvider.QuickInfoSource.cs new file mode 100644 index 0000000000000..5df2906d2610f --- /dev/null +++ b/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/QuickInfoSourceProvider.QuickInfoSource.cs @@ -0,0 +1,79 @@ +// 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; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.ErrorReporting; +using Microsoft.CodeAnalysis.Internal.Log; +using Microsoft.CodeAnalysis.QuickInfo; +using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.Text.Shared.Extensions; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using Roslyn.Utilities; + +using IntellisenseQuickInfoItem = Microsoft.VisualStudio.Language.Intellisense.QuickInfoItem; + +namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo +{ + internal partial class QuickInfoSourceProvider + { + private class QuickInfoSource : IAsyncQuickInfoSource + { + private readonly ITextBuffer _subjectBuffer; + + public QuickInfoSource(ITextBuffer subjectBuffer) + { + _subjectBuffer = subjectBuffer; + } + + public async Task GetQuickInfoItemAsync(IAsyncQuickInfoSession session, CancellationToken cancellationToken) + { + var triggerPoint = session.GetTriggerPoint(_subjectBuffer.CurrentSnapshot); + if (!triggerPoint.HasValue) + { + return null; + } + + var snapshot = triggerPoint.Value.Snapshot; + var document = snapshot.GetOpenDocumentInCurrentContextWithChanges(); + if (document == null) + { + return null; + } + + var service = QuickInfoService.GetService(document); + if (service == null) + { + return null; + } + + try + { + using (Internal.Log.Logger.LogBlock(FunctionId.Get_QuickInfo_Async, cancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + + var item = await service.GetQuickInfoAsync(document, triggerPoint.Value, cancellationToken).ConfigureAwait(false); + if (item != null) + { + var textVersion = snapshot.Version; + var trackingSpan = textVersion.CreateTrackingSpan(item.Span.ToSpan(), SpanTrackingMode.EdgeInclusive); + return IntellisenseQuickInfoBuilder.BuildItem(trackingSpan, item); + } + + return null; + } + } + catch (Exception e) when (FatalError.ReportUnlessCanceled(e)) + { + throw ExceptionUtilities.Unreachable; + } + } + + public void Dispose() + { + } + } + } +} diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/QuickInfoSourceProvider.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/QuickInfoSourceProvider.cs new file mode 100644 index 0000000000000..c9080ac2b3fa9 --- /dev/null +++ b/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/QuickInfoSourceProvider.cs @@ -0,0 +1,20 @@ +// 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.ComponentModel.Composition; +using Microsoft.VisualStudio.Language.Intellisense; +using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Utilities; + +namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo +{ + [ContentType(ContentTypeNames.RoslynContentType)] + [Export(typeof(IAsyncQuickInfoSourceProvider))] + [Name("RoslynQuickInfoProvider")] + internal partial class QuickInfoSourceProvider : IAsyncQuickInfoSourceProvider + { + public IAsyncQuickInfoSource TryCreateQuickInfoSource(ITextBuffer textBuffer) + { + return new QuickInfoSource(textBuffer); + } + } +} diff --git a/src/EditorFeatures/Core/Shared/Extensions/GlyphExtensions.cs b/src/EditorFeatures/Core/Shared/Extensions/GlyphExtensions.cs index 7e00ee897a7c2..b391a3371676f 100644 --- a/src/EditorFeatures/Core/Shared/Extensions/GlyphExtensions.cs +++ b/src/EditorFeatures/Core/Shared/Extensions/GlyphExtensions.cs @@ -206,279 +206,5 @@ public static ImageId GetImageId(this Glyph glyph) throw new ArgumentException(nameof(glyph)); } } - - public static Glyph GetGlyph(this ImmutableArray tags) - { - foreach (var tag in tags) - { - switch (tag) - { - case WellKnownTags.Assembly: - return Glyph.Assembly; - - case WellKnownTags.File: - return tags.Contains(LanguageNames.VisualBasic) ? Glyph.BasicFile : Glyph.CSharpFile; - - case WellKnownTags.Project: - return tags.Contains(LanguageNames.VisualBasic) ? Glyph.BasicProject : Glyph.CSharpProject; - - case WellKnownTags.Class: - switch (GetAccessibility(tags)) - { - case Accessibility.Protected: - return Glyph.ClassProtected; - case Accessibility.Private: - return Glyph.ClassPrivate; - case Accessibility.Internal: - return Glyph.ClassInternal; - case Accessibility.Public: - default: - return Glyph.ClassPublic; - } - - case WellKnownTags.Constant: - switch (GetAccessibility(tags)) - { - case Accessibility.Protected: - return Glyph.ConstantProtected; - case Accessibility.Private: - return Glyph.ConstantPrivate; - case Accessibility.Internal: - return Glyph.ConstantInternal; - case Accessibility.Public: - default: - return Glyph.ConstantPublic; - } - - case WellKnownTags.Delegate: - switch (GetAccessibility(tags)) - { - case Accessibility.Protected: - return Glyph.DelegateProtected; - case Accessibility.Private: - return Glyph.DelegatePrivate; - case Accessibility.Internal: - return Glyph.DelegateInternal; - case Accessibility.Public: - default: - return Glyph.DelegatePublic; - } - - case WellKnownTags.Enum: - switch (GetAccessibility(tags)) - { - case Accessibility.Protected: - return Glyph.EnumProtected; - case Accessibility.Private: - return Glyph.EnumPrivate; - case Accessibility.Internal: - return Glyph.EnumInternal; - case Accessibility.Public: - default: - return Glyph.EnumPublic; - } - - case WellKnownTags.EnumMember: - switch (GetAccessibility(tags)) - { - case Accessibility.Protected: - return Glyph.EnumMemberProtected; - case Accessibility.Private: - return Glyph.EnumMemberPrivate; - case Accessibility.Internal: - return Glyph.EnumMemberInternal; - case Accessibility.Public: - default: - return Glyph.EnumMemberPublic; - } - - case WellKnownTags.Error: - return Glyph.Error; - - case WellKnownTags.Event: - switch (GetAccessibility(tags)) - { - case Accessibility.Protected: - return Glyph.EventProtected; - case Accessibility.Private: - return Glyph.EventPrivate; - case Accessibility.Internal: - return Glyph.EventInternal; - case Accessibility.Public: - default: - return Glyph.EventPublic; - } - - case WellKnownTags.ExtensionMethod: - switch (GetAccessibility(tags)) - { - case Accessibility.Protected: - return Glyph.ExtensionMethodProtected; - case Accessibility.Private: - return Glyph.ExtensionMethodPrivate; - case Accessibility.Internal: - return Glyph.ExtensionMethodInternal; - case Accessibility.Public: - default: - return Glyph.ExtensionMethodPublic; - } - - case WellKnownTags.Field: - switch (GetAccessibility(tags)) - { - case Accessibility.Protected: - return Glyph.FieldProtected; - case Accessibility.Private: - return Glyph.FieldPrivate; - case Accessibility.Internal: - return Glyph.FieldInternal; - case Accessibility.Public: - default: - return Glyph.FieldPublic; - } - - case WellKnownTags.Interface: - switch (GetAccessibility(tags)) - { - case Accessibility.Protected: - return Glyph.InterfaceProtected; - case Accessibility.Private: - return Glyph.InterfacePrivate; - case Accessibility.Internal: - return Glyph.InterfaceInternal; - case Accessibility.Public: - default: - return Glyph.InterfacePublic; - } - - case WellKnownTags.Intrinsic: - return Glyph.Intrinsic; - - case WellKnownTags.Keyword: - return Glyph.Keyword; - - case WellKnownTags.Label: - return Glyph.Label; - - case WellKnownTags.Local: - return Glyph.Local; - - case WellKnownTags.Namespace: - return Glyph.Namespace; - - case WellKnownTags.Method: - switch (GetAccessibility(tags)) - { - case Accessibility.Protected: - return Glyph.MethodProtected; - case Accessibility.Private: - return Glyph.MethodPrivate; - case Accessibility.Internal: - return Glyph.MethodInternal; - case Accessibility.Public: - default: - return Glyph.MethodPublic; - } - - case WellKnownTags.Module: - switch (GetAccessibility(tags)) - { - case Accessibility.Protected: - return Glyph.ModulePublic; - case Accessibility.Private: - return Glyph.ModulePrivate; - case Accessibility.Internal: - return Glyph.ModuleInternal; - case Accessibility.Public: - default: - return Glyph.ModulePublic; - } - - case WellKnownTags.Folder: - return Glyph.OpenFolder; - - case WellKnownTags.Operator: - return Glyph.Operator; - - case WellKnownTags.Parameter: - return Glyph.Parameter; - - case WellKnownTags.Property: - switch (GetAccessibility(tags)) - { - case Accessibility.Protected: - return Glyph.PropertyProtected; - case Accessibility.Private: - return Glyph.PropertyPrivate; - case Accessibility.Internal: - return Glyph.PropertyInternal; - case Accessibility.Public: - default: - return Glyph.PropertyPublic; - } - - case WellKnownTags.RangeVariable: - return Glyph.RangeVariable; - - case WellKnownTags.Reference: - return Glyph.Reference; - - case WellKnownTags.NuGet: - return Glyph.NuGet; - - case WellKnownTags.Structure: - switch (GetAccessibility(tags)) - { - case Accessibility.Protected: - return Glyph.StructureProtected; - case Accessibility.Private: - return Glyph.StructurePrivate; - case Accessibility.Internal: - return Glyph.StructureInternal; - case Accessibility.Public: - default: - return Glyph.StructurePublic; - } - - case WellKnownTags.TypeParameter: - return Glyph.TypeParameter; - - case WellKnownTags.Snippet: - return Glyph.Snippet; - - case WellKnownTags.Warning: - return Glyph.CompletionWarning; - - case WellKnownTags.StatusInformation: - return Glyph.StatusInformation; - } - } - - return Glyph.None; - } - - private static Accessibility GetAccessibility(ImmutableArray tags) - { - if (tags.Contains(WellKnownTags.Public)) - { - return Accessibility.Public; - } - else if (tags.Contains(WellKnownTags.Protected)) - { - return Accessibility.Protected; - } - else if (tags.Contains(WellKnownTags.Internal)) - { - return Accessibility.Internal; - } - else if (tags.Contains(WellKnownTags.Private)) - { - return Accessibility.Private; - } - else - { - return Accessibility.NotApplicable; - } - } } } diff --git a/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb b/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb index 77c2ed8f95a19..1586e8131e31c 100644 --- a/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb +++ b/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb @@ -10,6 +10,7 @@ Imports Microsoft.CodeAnalysis.Editor.CSharp.Formatting Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions Imports Microsoft.CodeAnalysis.Editor.UnitTests.Utilities Imports Microsoft.CodeAnalysis.Options +Imports Microsoft.CodeAnalysis.Tags Imports Microsoft.CodeAnalysis.Text Imports Microsoft.VisualStudio.Text Imports Microsoft.VisualStudio.Text.Editor @@ -2396,7 +2397,7 @@ class C state.SendTypeChars("Thing1") Await state.WaitForAsynchronousOperationsAsync() Await state.AssertSelectedCompletionItem("Thing1") - Assert.True(state.CurrentCompletionPresenterSession.SelectedItem.Tags.Contains(CompletionTags.Warning)) + Assert.True(state.CurrentCompletionPresenterSession.SelectedItem.Tags.Contains(WellKnownTags.Warning)) state.SendBackspace() state.SendBackspace() state.SendBackspace() @@ -2406,7 +2407,7 @@ class C state.SendTypeChars("M") Await state.WaitForAsynchronousOperationsAsync() Await state.AssertSelectedCompletionItem("M") - Assert.False(state.CurrentCompletionPresenterSession.SelectedItem.Tags.Contains(CompletionTags.Warning)) + Assert.False(state.CurrentCompletionPresenterSession.SelectedItem.Tags.Contains(WellKnownTags.Warning)) End Using End Function diff --git a/src/EditorFeatures/Test2/IntelliSense/IntellisenseQuickInfoBuilderTests.vb b/src/EditorFeatures/Test2/IntelliSense/IntellisenseQuickInfoBuilderTests.vb new file mode 100644 index 0000000000000..8133bb7960fb7 --- /dev/null +++ b/src/EditorFeatures/Test2/IntelliSense/IntellisenseQuickInfoBuilderTests.vb @@ -0,0 +1,98 @@ +' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +Imports System.Collections.Immutable +Imports Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo +Imports Microsoft.CodeAnalysis.QuickInfo +Imports Microsoft.VisualStudio.Imaging +Imports Microsoft.VisualStudio.Text +Imports Microsoft.VisualStudio.Text.Adornments +Imports Moq +Imports QuickInfoItem = Microsoft.CodeAnalysis.QuickInfo.QuickInfoItem + +Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense + + Public Class IntellisenseQuickInfoBuilderTests + + + Public Sub BuildQuickInfoItem() + + Dim codeAnalysisQuickInfoItem _ + = QuickInfoItem.Create(New Text.TextSpan(0, 0), ImmutableArray.Create({"Method", "Public"}), + ImmutableArray.Create _ + ({QuickInfoSection.Create("Description", + ImmutableArray.Create({ + New TaggedText("Keyword", "void"), + New TaggedText("Space", " "), + New TaggedText("Class", "Console"), + New TaggedText("Punctuation", "."), + New TaggedText("Method", "WriteLine"), + New TaggedText("Punctuation", "("), + New TaggedText("Keyword", "string"), + New TaggedText("Space", " "), + New TaggedText("Parameter", "value"), + New TaggedText("Punctuation", ")"), + New TaggedText("Space", " "), + New TaggedText("Punctuation", "("), + New TaggedText("Punctuation", "+"), + New TaggedText("Space", " "), + New TaggedText("Text", "18"), + New TaggedText("Space", " "), + New TaggedText("Text", "overloads"), + New TaggedText("Punctuation", ")")})), + QuickInfoSection.Create("DocumentationComments", + ImmutableArray.Create({New TaggedText("Text", "Writes the specified string value, followed by the current line terminator, to the standard output stream.")})), + QuickInfoSection.Create("Exception", + ImmutableArray.Create({ + New TaggedText("Text", "Exceptions"), + New TaggedText("LineBreak", "\r\n"), + New TaggedText("Space", " "), + New TaggedText("Namespace", "System"), + New TaggedText("Punctuation", "."), + New TaggedText("Namespace", "IO"), + New TaggedText("Punctuation", "."), + New TaggedText("Class", "IOException")}))})) + + Dim trackingSpan = New Mock(Of ITrackingSpan) With { + .DefaultValue = DefaultValue.Mock + } + + Dim intellisenseQuickInfo = IntellisenseQuickInfoBuilder.BuildItem(trackingSpan.Object, codeAnalysisQuickInfoItem) + + Assert.NotNull(intellisenseQuickInfo) + + Dim container = Assert.IsType(Of Adornments.ContainerElement)(intellisenseQuickInfo.Item) + Assert.Equal(3, container.Elements.Count()) + Assert.Equal(ContainerElementStyle.Stacked, container.Style) + + Assert.Collection(container.Elements, + New Action(Of Object)() { + Sub(row0 As Object) + Dim firstRowContainer = Assert.IsType(Of Adornments.ContainerElement)(row0) + Assert.Equal(2, firstRowContainer.Elements.Count()) + Assert.Equal(ContainerElementStyle.Wrapped, firstRowContainer.Style) + + Assert.Collection(firstRowContainer.Elements, + New Action(Of Object)() { + Sub(row0col0 As Object) + Dim element00 = Assert.IsType(Of ImageElement)(row0col0) + Assert.Equal(KnownImageIds.ImageCatalogGuid, element00.ImageId.Guid) + Assert.Equal(KnownImageIds.MethodPublic, element00.ImageId.Id) + End Sub, + Sub(row0col1 As Object) + Dim element01 = Assert.IsType(Of ClassifiedTextElement)(row0col1) + Assert.Equal(18, element01.Runs.Count()) + End Sub}) + End Sub, + Sub(row1 As Object) + Dim element1 = Assert.IsType(Of ClassifiedTextElement)(row1) + Assert.Equal(1, element1.Runs.Count()) + End Sub, + Sub(row2 As Object) + Dim element2 = Assert.IsType(Of ClassifiedTextElement)(row2) + Assert.Equal(8, element2.Runs.Count()) + End Sub}) + + End Sub + + End Class +End Namespace diff --git a/src/EditorFeatures/Test2/IntelliSense/QuickInfoControllerTests.vb b/src/EditorFeatures/Test2/IntelliSense/QuickInfoControllerTests.vb deleted file mode 100644 index c0f5916585431..0000000000000 --- a/src/EditorFeatures/Test2/IntelliSense/QuickInfoControllerTests.vb +++ /dev/null @@ -1,250 +0,0 @@ -' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -Imports System.Runtime.CompilerServices -Imports System.Threading -Imports System.Threading.Tasks -Imports Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense -Imports Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo -Imports Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo.Presentation -Imports Microsoft.CodeAnalysis.Editor.QuickInfo -Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces -Imports Microsoft.CodeAnalysis.Shared.TestHooks -Imports Microsoft.VisualStudio.Language.Intellisense -Imports Microsoft.VisualStudio.Text -Imports Microsoft.VisualStudio.Text.Editor -Imports Microsoft.VisualStudio.Utilities -Imports Moq - -#Disable Warning BC40000 ' IQuickInfo* is obsolete -Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense - - <[UseExportProvider]> - Public Class QuickInfoControllerTests - - Public Sub New() - TestWorkspace.ResetThreadAffinity() - End Sub - - - Public Sub InvokeQuickInfoWithoutDocumentShouldNotQueryProviders() - Dim emptyProvider = New Mock(Of IDocumentProvider) - emptyProvider.Setup(Function(p) p.GetDocumentAsync(It.IsAny(Of ITextSnapshot), It.IsAny(Of CancellationToken))).Returns(Task.FromResult(DirectCast(Nothing, Document))) - Dim controller As Controller = CreateController(documentProvider:=emptyProvider, triggerQuickInfo:=True) - controller.WaitForController() - - GetMocks(controller).Provider.Verify(Function(p) p.GetItemAsync(It.IsAny(Of Document), It.IsAny(Of Integer), It.IsAny(Of CancellationToken)), Times.Never) - End Sub - - - Public Sub InvokeQuickInfoWithDocumentShouldStartNewSession() - Dim controller = CreateController(triggerQuickInfo:=True) - - GetMocks(controller).Presenter.Verify(Function(p) p.CreateSession(It.IsAny(Of ITextView), It.IsAny(Of ITextBuffer), It.IsAny(Of IQuickInfoSession)), Times.Once) - End Sub - - - Public Sub InactiveQuickInfoShouldNotHandleEscape() - Dim controller As Controller = CreateController() - - Dim handled = controller.TryHandleEscapeKey() - - Assert.False(handled) - End Sub - - - Public Sub ActiveQuickInfoShouldHandleEscape() - Dim presenter = New Mock(Of IIntelliSensePresenter(Of IQuickInfoPresenterSession, IQuickInfoSession)) - Dim presenterSession = New Mock(Of IQuickInfoPresenterSession) - presenter.Setup(Function(p) p.CreateSession(It.IsAny(Of ITextView), It.IsAny(Of ITextBuffer), It.IsAny(Of IQuickInfoSession))).Returns(presenterSession.Object) - - Dim controller As Controller = CreateController(presenter:=presenter, triggerQuickInfo:=True) - controller.WaitForController() - - Dim handled = controller.TryHandleEscapeKey() - - Assert.True(handled) - presenterSession.Verify(Sub(p) p.Dismiss(), Times.Once) - End Sub - - - Public Sub SlowQuickInfoShouldDismissSessionButNotHandleEscape() - Dim checkpoint As New Checkpoint - Dim presenter = New Mock(Of IIntelliSensePresenter(Of IQuickInfoPresenterSession, IQuickInfoSession)) - Dim presenterSession = New Mock(Of IQuickInfoPresenterSession) - presenter.Setup(Function(p) p.CreateSession(It.IsAny(Of ITextView), It.IsAny(Of ITextBuffer), It.IsAny(Of IQuickInfoSession))).Returns(presenterSession.Object) - Dim provider = New Mock(Of IQuickInfoProvider) - provider.Setup(Function(p) p.GetItemAsync(It.IsAny(Of Document), It.IsAny(Of Integer), It.IsAny(Of CancellationToken))) _ - .Returns(Async Function() - Await checkpoint.Task.ConfigureAwait(False) - Return New QuickInfoItem(Nothing, Nothing) - End Function) - - Dim controller As Controller = CreateController(presenter:=presenter, provider:=provider, triggerQuickInfo:=True) - - Dim handled = controller.TryHandleEscapeKey() - - Assert.False(handled) - presenterSession.Verify(Sub(p) p.Dismiss(), Times.Once) - End Sub - - - Public Sub CaretPositionChangedShouldDismissSession() - Dim presenter = New Mock(Of IIntelliSensePresenter(Of IQuickInfoPresenterSession, IQuickInfoSession)) - Dim presenterSession = New Mock(Of IQuickInfoPresenterSession) - presenter.Setup(Function(p) p.CreateSession(It.IsAny(Of ITextView), It.IsAny(Of ITextBuffer), It.IsAny(Of IQuickInfoSession))).Returns(presenterSession.Object) - Dim controller = CreateController(presenter:=presenter, triggerQuickInfo:=True) - - Mock.Get(GetMocks(controller).View.Object.Caret).Raise(Sub(c) AddHandler c.PositionChanged, Nothing, New CaretPositionChangedEventArgs(Nothing, Nothing, Nothing)) - - presenterSession.Verify(Sub(p) p.Dismiss(), Times.Once) - End Sub - - - Public Sub SubjectBufferPostChangedShouldDismissSession() - Dim presenter = New Mock(Of IIntelliSensePresenter(Of IQuickInfoPresenterSession, IQuickInfoSession)) - Dim presenterSession = New Mock(Of IQuickInfoPresenterSession) - presenter.Setup(Function(p) p.CreateSession(It.IsAny(Of ITextView), It.IsAny(Of ITextBuffer), It.IsAny(Of IQuickInfoSession))).Returns(presenterSession.Object) - Dim controller = CreateController(presenter:=presenter, triggerQuickInfo:=True) - - Mock.Get(GetMocks(controller).View.Object.TextBuffer).Raise(Sub(b) AddHandler b.PostChanged, Nothing, New EventArgs()) - - presenterSession.Verify(Sub(p) p.Dismiss(), Times.Once) - End Sub - - - Public Sub PresenterUpdatesExistingSessionIfNotDismissed() - Dim broker = New Mock(Of IQuickInfoBroker)() - Dim frameworkElementFactory = New DeferredContentFrameworkElementFactory({}, {}) - Dim presenter As IIntelliSensePresenter(Of IQuickInfoPresenterSession, IQuickInfoSession) = New QuickInfoPresenter(broker.Object, frameworkElementFactory) - Dim mockEditorSession = New Mock(Of IQuickInfoSession) - mockEditorSession.Setup(Function(m) m.IsDismissed).Returns(False) - mockEditorSession.Setup(Sub(m) m.Recalculate()) - mockEditorSession.Setup(Function(m) m.Properties).Returns(New PropertyCollection()) - - Dim presenterSession = presenter.CreateSession(It.IsAny(Of ITextView), It.IsAny(Of ITextBuffer), mockEditorSession.Object) - presenterSession.PresentItem(Nothing, Nothing, False) - mockEditorSession.Verify(Sub(m) m.Recalculate()) - End Sub - - - Public Sub PresenterDoesNotRecalculateDismissedSession() - Dim broker = New Mock(Of IQuickInfoBroker)() - Dim brokerSession = New Mock(Of IQuickInfoSession)() - brokerSession.Setup(Function(m) m.Properties).Returns(New PropertyCollection()) - broker.Setup(Function(m) m.CreateQuickInfoSession(It.IsAny(Of ITextView), It.IsAny(Of ITrackingPoint), It.IsAny(Of Boolean))).Returns(brokerSession.Object) - - Dim frameworkElementFactory = New DeferredContentFrameworkElementFactory({}, {}) - Dim presenter As IIntelliSensePresenter(Of IQuickInfoPresenterSession, IQuickInfoSession) = New QuickInfoPresenter(broker.Object, frameworkElementFactory) - Dim mockEditorSession = New Mock(Of IQuickInfoSession) - mockEditorSession.Setup(Function(m) m.IsDismissed).Returns(True) - mockEditorSession.Setup(Sub(m) m.Recalculate()) - mockEditorSession.Setup(Function(m) m.Properties).Returns(New PropertyCollection()) - - Dim mockTextBuffer = New Mock(Of ITextBuffer)() - mockTextBuffer.Setup(Function(m) m.CurrentSnapshot).Returns(It.IsAny(Of ITextSnapshot)) - - Dim mockTrackingSpan = New Mock(Of ITrackingSpan) - mockTrackingSpan.Setup(Function(m) m.TextBuffer).Returns(mockTextBuffer.Object) - mockTrackingSpan.Setup(Function(m) m.GetSpan(It.IsAny(Of ITextSnapshot))).Returns(New SnapshotSpan()) - mockTrackingSpan.Setup(Function(m) m.GetStartPoint(It.IsAny(Of ITextSnapshot))).Returns(New SnapshotPoint(New Mock(Of ITextSnapshot)().Object, 0)) - - Dim presenterSession = presenter.CreateSession(It.IsAny(Of ITextView), It.IsAny(Of ITextBuffer), mockEditorSession.Object) - presenterSession.PresentItem(mockTrackingSpan.Object, Nothing, False) - mockEditorSession.Verify(Sub(m) m.Recalculate(), Times.Never) - End Sub - - Private Shared ReadOnly s_controllerMocksMap As New ConditionalWeakTable(Of Controller, ControllerMocks) - Private Shared Function GetMocks(controller As Controller) As ControllerMocks - Dim result As ControllerMocks = Nothing - Roslyn.Utilities.Contract.ThrowIfFalse(s_controllerMocksMap.TryGetValue(controller, result)) - Return result - End Function - - Private Shared Function CreateController(Optional documentProvider As Mock(Of IDocumentProvider) = Nothing, - Optional presenter As Mock(Of IIntelliSensePresenter(Of IQuickInfoPresenterSession, IQuickInfoSession)) = Nothing, - Optional provider As Mock(Of IQuickInfoProvider) = Nothing, - Optional triggerQuickInfo As Boolean = False, - Optional augmentSession As IQuickInfoSession = Nothing) As Controller - Dim document As Document = - (Function() - Dim workspace = TestWorkspace.CreateWorkspace( - - - - - - ) - Return workspace.CurrentSolution.GetDocument(workspace.Documents.Single().Id) - End Function)() - Dim bufferFactory As ITextBufferFactoryService = DirectCast(document.Project.Solution.Workspace, TestWorkspace).GetService(Of ITextBufferFactoryService) - - Dim view = New Mock(Of ITextView) With {.DefaultValue = DefaultValue.Mock} - Dim asyncListener = New Mock(Of IAsynchronousOperationListener) - Dim buffer = bufferFactory.CreateTextBuffer() - - presenter = If(presenter, New Mock(Of IIntelliSensePresenter(Of IQuickInfoPresenterSession, IQuickInfoSession)) With {.DefaultValue = DefaultValue.Mock}) - If documentProvider Is Nothing Then - documentProvider = New Mock(Of IDocumentProvider) - documentProvider.Setup(Function(p) p.GetDocumentAsync(It.IsAny(Of ITextSnapshot), It.IsAny(Of CancellationToken))).Returns(Task.FromResult(document)) - End If - - If provider Is Nothing Then - provider = New Mock(Of IQuickInfoProvider) - provider.Setup(Function(p) p.GetItemAsync(It.IsAny(Of Document), It.IsAny(Of Integer), It.IsAny(Of CancellationToken))) _ - .Returns(Task.FromResult(New QuickInfoItem(Nothing, Nothing))) - End If - - Dim controller = New Controller( - view.Object, - buffer, - presenter.Object, - asyncListener.Object, - documentProvider.Object, - {provider.Object}) - - s_controllerMocksMap.Add(controller, New ControllerMocks( - view, - buffer, - presenter, - asyncListener, - documentProvider, - provider)) - - If triggerQuickInfo Then - controller.InvokeQuickInfo(position:=0, trackMouse:=False, augmentSession:=augmentSession) - End If - - Return controller - End Function - - Private Shared Function CreateMock(Of T As Class)() As T - Dim mock = New Mock(Of T) - Return mock.Object - End Function - - Private Class ControllerMocks - Public ReadOnly View As Mock(Of ITextView) - Public ReadOnly Buffer As ITextBuffer - Public ReadOnly Presenter As Mock(Of IIntelliSensePresenter(Of IQuickInfoPresenterSession, IQuickInfoSession)) - Public ReadOnly AsyncListener As Mock(Of IAsynchronousOperationListener) - Public ReadOnly DocumentProvider As Mock(Of IDocumentProvider) - Public ReadOnly Provider As Mock(Of IQuickInfoProvider) - - Public Sub New(view As Mock(Of ITextView), - buffer As ITextBuffer, - presenter As Mock(Of IIntelliSensePresenter(Of IQuickInfoPresenterSession, IQuickInfoSession)), - asyncListener As Mock(Of IAsynchronousOperationListener), - documentProvider As Mock(Of IDocumentProvider), provider As Mock(Of IQuickInfoProvider)) - Me.View = view - Me.Buffer = buffer - Me.Presenter = presenter - Me.AsyncListener = asyncListener - Me.DocumentProvider = documentProvider - Me.Provider = provider - End Sub - - - End Class - End Class -End Namespace -#Enable Warning BC40000 ' IQuickInfo* is obsolete diff --git a/src/EditorFeatures/Test2/IntelliSense/VisualBasicCompletionCommandHandlerTests.vb b/src/EditorFeatures/Test2/IntelliSense/VisualBasicCompletionCommandHandlerTests.vb index 5a9d7114e2370..6d97fa5306e82 100644 --- a/src/EditorFeatures/Test2/IntelliSense/VisualBasicCompletionCommandHandlerTests.vb +++ b/src/EditorFeatures/Test2/IntelliSense/VisualBasicCompletionCommandHandlerTests.vb @@ -6,6 +6,7 @@ Imports Microsoft.CodeAnalysis.Completion Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions Imports Microsoft.CodeAnalysis.Host.Mef Imports Microsoft.CodeAnalysis.Snippets +Imports Microsoft.CodeAnalysis.Tags Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.VisualStudio.Text Imports Microsoft.VisualStudio.Text.Operations @@ -2142,7 +2143,7 @@ End Class Await state.WaitForAsynchronousOperationsAsync() ' Should only have one item called 'Double' and it should have a keyword glyph Dim doubleItem = state.CurrentCompletionPresenterSession.CompletionItems.Single(Function(c) c.DisplayText = "Double") - Assert.True(doubleItem.Tags.Contains(CompletionTags.Keyword)) + Assert.True(doubleItem.Tags.Contains(WellKnownTags.Keyword)) End Using End Function @@ -2163,8 +2164,8 @@ End Class ' We should have gotten the item corresponding to [Double] and the item for the Double keyword Dim doubleItems = state.CurrentCompletionPresenterSession.CompletionItems.Where(Function(c) c.DisplayText = "Double") Assert.Equal(2, doubleItems.Count()) - Assert.True(doubleItems.Any(Function(c) c.Tags.Contains(CompletionTags.Keyword))) - Assert.True(doubleItems.Any(Function(c) c.Tags.Contains(CompletionTags.Class) AndAlso c.Tags.Contains(CompletionTags.Internal))) + Assert.True(doubleItems.Any(Function(c) c.Tags.Contains(WellKnownTags.Keyword))) + Assert.True(doubleItems.Any(Function(c) c.Tags.Contains(WellKnownTags.Class) AndAlso c.Tags.Contains(WellKnownTags.Internal))) End Using End Function diff --git a/src/EditorFeatures/TestUtilities/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs b/src/EditorFeatures/TestUtilities/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs index a4eb55177063f..ebeb904a4547f 100644 --- a/src/EditorFeatures/TestUtilities/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs +++ b/src/EditorFeatures/TestUtilities/CodeActions/AbstractCodeActionOrUserDiagnosticTest.cs @@ -208,7 +208,7 @@ protected async Task TestAddDocument( { var codeActions = await GetCodeActionsAsync(workspace, parameters); await TestAddDocument( - workspace, expectedMarkup, index, expectedContainers, + workspace, expectedMarkup, index, expectedContainers, expectedDocumentName, codeActions); } } @@ -352,7 +352,7 @@ private async Task TestAsync( TestParameters parameters) { MarkupTestFile.GetSpans( - expectedMarkup.NormalizeLineEndings(), + expectedMarkup.NormalizeLineEndings(), out var expected, out IDictionary> spanMap); var conflictSpans = spanMap.GetOrAdd("Conflict", _ => ImmutableArray.Empty); diff --git a/src/EditorFeatures/TestUtilities/QuickInfo/AbstractSemanticQuickInfoSourceTests.cs b/src/EditorFeatures/TestUtilities/QuickInfo/AbstractSemanticQuickInfoSourceTests.cs index bc9ac7bd7b7f1..783484085f780 100644 --- a/src/EditorFeatures/TestUtilities/QuickInfo/AbstractSemanticQuickInfoSourceTests.cs +++ b/src/EditorFeatures/TestUtilities/QuickInfo/AbstractSemanticQuickInfoSourceTests.cs @@ -1,10 +1,13 @@ // 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; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Linq; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo; using Microsoft.CodeAnalysis.Editor.UnitTests.Classification; using Microsoft.CodeAnalysis.LanguageServices; +using Microsoft.CodeAnalysis.QuickInfo; using Microsoft.CodeAnalysis.Test.Utilities; using Xunit; @@ -13,8 +16,6 @@ namespace Microsoft.CodeAnalysis.Editor.UnitTests.QuickInfo [UseExportProvider] public abstract class AbstractSemanticQuickInfoSourceTests { - protected AbstractSemanticQuickInfoSourceTests() { } - protected FormattedClassification Text(string text) => FormattedClassifications.Text(text); @@ -29,145 +30,105 @@ protected FormattedClassification[] ExpectedClassifications( return expectedClassifications; } - protected FormattedClassification[] NoClassifications() + protected Tuple[] NoClassifications() { return null; } - private static void AssertTextAndClassifications(string expectedText, FormattedClassification[] expectedClassifications, IDeferredQuickInfoContent actualContent) + internal Action SymbolGlyph(Glyph expectedGlyph) { - var actualClassifications = ((ClassifiableDeferredContent)actualContent).ClassifiableContent; - - ClassificationTestHelper.VerifyTextAndClassifications(expectedText, expectedClassifications, actualClassifications); + return qi => + { + Assert.Contains(expectedGlyph, qi.Tags.GetGlyphs()); + }; } - protected void WaitForDocumentationComment(object content) + internal Action WarningGlyph(Glyph expectedGlyph) { - if (content is QuickInfoDisplayDeferredContent deferredContent) - { - if (deferredContent.Documentation is DocumentationCommentDeferredContent docCommentDeferredContent) - { - docCommentDeferredContent.WaitForDocumentationCommentTask_ForTestingPurposesOnly(); - } - } + return SymbolGlyph(expectedGlyph); } - internal Action SymbolGlyph(Glyph expectedGlyph) + internal void AssertSection( + string expectedText, + ImmutableArray sections, + string textBlockKind, + FormattedClassification[] expectedClassifications = null) { - return content => - { - var actualIcon = (SymbolGlyphDeferredContent)((QuickInfoDisplayDeferredContent)content).SymbolGlyph; - Assert.Equal(expectedGlyph, actualIcon.Glyph); - }; + var textBlock = sections.FirstOrDefault(tb => tb.Kind == textBlockKind); + var text = textBlock != null ? textBlock.TaggedParts : ImmutableArray.Empty; + AssertTaggedText(expectedText, text, expectedClassifications); } - protected Action MainDescription( + protected void AssertTaggedText( string expectedText, + ImmutableArray taggedText, FormattedClassification[] expectedClassifications = null) { - return content => - { - switch (content) - { - case QuickInfoDisplayDeferredContent qiContent: - { - AssertTextAndClassifications(expectedText, expectedClassifications, (ClassifiableDeferredContent)qiContent.MainDescription); - } - break; - - case ClassifiableDeferredContent classifiable: - { - var actualContent = classifiable.ClassifiableContent; - ClassificationTestHelper.VerifyTextAndClassifications(expectedText, expectedClassifications, actualContent); - } - break; - } - }; + var actualText = string.Concat(taggedText.Select(tt => tt.Text)); + Assert.Equal(expectedText, actualText); } - protected Action Documentation( + protected Action MainDescription( string expectedText, FormattedClassification[] expectedClassifications = null) { - return content => - { - var documentationCommentContent = ((QuickInfoDisplayDeferredContent)content).Documentation; - switch (documentationCommentContent) - { - case DocumentationCommentDeferredContent docComment: - { - Assert.Equal(expectedText, docComment.DocumentationComment); - } - break; - - case ClassifiableDeferredContent classifiable: - { - var actualContent = classifiable.ClassifiableContent; - Assert.Equal(expectedText, actualContent.GetFullText()); - ClassificationTestHelper.VerifyTextAndClassifications(expectedText, expectedClassifications, actualContent); - } - break; - } - }; + return item => AssertSection(expectedText, item.Sections, QuickInfoSectionKinds.Description, expectedClassifications); } - protected Action TypeParameterMap( + protected Action Documentation( string expectedText, FormattedClassification[] expectedClassifications = null) { - return content => - { - AssertTextAndClassifications(expectedText, expectedClassifications, ((QuickInfoDisplayDeferredContent)content).TypeParameterMap); - }; + return item => AssertSection(expectedText, item.Sections, QuickInfoSectionKinds.DocumentationComments, expectedClassifications); } - protected Action AnonymousTypes( + protected Action TypeParameterMap( string expectedText, FormattedClassification[] expectedClassifications = null) { - return content => - { - AssertTextAndClassifications(expectedText, expectedClassifications, ((QuickInfoDisplayDeferredContent)content).AnonymousTypes); - }; + return item => AssertSection(expectedText, item.Sections, QuickInfoSectionKinds.TypeParameters, expectedClassifications); } + protected Action AnonymousTypes( + string expectedText, + FormattedClassification[] expectedClassifications = null) + { + return item => AssertSection(expectedText, item.Sections, QuickInfoSectionKinds.AnonymousTypes, expectedClassifications); + } - protected Action NoTypeParameterMap + protected Action NoTypeParameterMap { get { - return content => - { - AssertTextAndClassifications("", NoClassifications(), ((QuickInfoDisplayDeferredContent)content).TypeParameterMap); - }; + return item => AssertSection(string.Empty, item.Sections, QuickInfoSectionKinds.TypeParameters); } } - protected Action Usage(string expectedText, bool expectsWarningGlyph = false) + protected Action Usage(string expectedText, bool expectsWarningGlyph = false) { - return content => + return item => { - var quickInfoContent = (QuickInfoDisplayDeferredContent)content; - Assert.Equal(expectedText, ((ClassifiableDeferredContent)quickInfoContent.UsageText).ClassifiableContent.GetFullText()); - var warningGlyph = quickInfoContent.WarningGlyph as SymbolGlyphDeferredContent; - Assert.Equal(expectsWarningGlyph, warningGlyph != null && warningGlyph.Glyph == Glyph.CompletionWarning); + AssertSection(expectedText, item.Sections, QuickInfoSectionKinds.Usage); + + if (expectsWarningGlyph) + { + WarningGlyph(Glyph.CompletionWarning)(item); + } + else + { + Assert.DoesNotContain(Glyph.CompletionWarning, item.Tags.GetGlyphs()); + } }; } - protected Action Exceptions(string expectedText) + protected Action Exceptions(string expectedText) { - return content => - { - AssertTextAndClassifications(expectedText, expectedClassifications: null, actualContent: ((QuickInfoDisplayDeferredContent)content).ExceptionText); - }; + return item => AssertSection(expectedText, item.Sections, QuickInfoSectionKinds.Exception); } - protected Action Captures(string expectedText) + protected Action Captures(string capturesText) { - return content => - { - AssertTextAndClassifications(expectedText, expectedClassifications: null, actualContent: ((QuickInfoDisplayDeferredContent)content).CapturesText); - }; + return item => AssertSection(capturesText, item.Sections, QuickInfoSectionKinds.Captures); } protected static async Task CanUseSpeculativeSemanticModelAsync(Document document, int position) @@ -178,6 +139,6 @@ protected static async Task CanUseSpeculativeSemanticModelAsync(Document d return !service.GetMemberBodySpanForSpeculativeBinding(node).IsEmpty; } - protected abstract Task TestAsync(string markup, params Action[] expectedResults); + protected abstract Task TestAsync(string markup, params Action[] expectedResults); } } diff --git a/src/EditorFeatures/TestUtilities2/Intellisense/TestState.vb b/src/EditorFeatures/TestUtilities2/Intellisense/TestState.vb index d6274f126ad0b..bfd0abd5c19d9 100644 --- a/src/EditorFeatures/TestUtilities2/Intellisense/TestState.vb +++ b/src/EditorFeatures/TestUtilities2/Intellisense/TestState.vb @@ -78,7 +78,7 @@ Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense GetExports(Of ISignatureHelpProvider, OrderableLanguageMetadata)().Concat(extraSignatureHelpProviders), GetExportedValue(Of IAsynchronousOperationListenerProvider)()) - Me.IntelliSenseCommandHandler = New IntelliSenseCommandHandler(CompletionCommandHandler, SignatureHelpCommandHandler, Nothing) + Me.IntelliSenseCommandHandler = New IntelliSenseCommandHandler(CompletionCommandHandler, SignatureHelpCommandHandler) Me.FormatCommandHandler = If(includeFormatCommandHandler, New FormatCommandHandler( diff --git a/src/EditorFeatures/VisualBasic/VBEditorResources.Designer.vb b/src/EditorFeatures/VisualBasic/VBEditorResources.Designer.vb index 3bebcbb15a747..335caf12597cf 100644 --- a/src/EditorFeatures/VisualBasic/VBEditorResources.Designer.vb +++ b/src/EditorFeatures/VisualBasic/VBEditorResources.Designer.vb @@ -195,15 +195,6 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.VBEditorResources End Get End Property - ''' - ''' Looks up a localized string similar to <Multiple Types>. - ''' - Friend ReadOnly Property Multiple_Types() As String - Get - Return ResourceManager.GetString("Multiple_Types", resourceCulture) - End Get - End Property - ''' ''' Looks up a localized string similar to New. ''' diff --git a/src/EditorFeatures/VisualBasic/VBEditorResources.resx b/src/EditorFeatures/VisualBasic/VBEditorResources.resx index 69fbd33ec491b..4766b13d19381 100644 --- a/src/EditorFeatures/VisualBasic/VBEditorResources.resx +++ b/src/EditorFeatures/VisualBasic/VBEditorResources.resx @@ -168,9 +168,6 @@ Visual Basic Pretty List - - <Multiple Types> - not supported diff --git a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.cs.xlf b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.cs.xlf index a631e41c61da7..6e670f43ef2aa 100644 --- a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.cs.xlf +++ b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.cs.xlf @@ -87,11 +87,6 @@ Visual Basic formátování typu Pretty List - - <Multiple Types> - <Víc typů> - - not supported nepodporované diff --git a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.de.xlf b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.de.xlf index 775c0515f1e39..3b0665fdbf556 100644 --- a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.de.xlf +++ b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.de.xlf @@ -87,11 +87,6 @@ Visual Basic - Automatische Strukturierung - - <Multiple Types> - <Mehrere Typen> - - not supported nicht unterstützt diff --git a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.es.xlf b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.es.xlf index 1ff39d61622a2..3228e13eed6a7 100644 --- a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.es.xlf +++ b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.es.xlf @@ -87,11 +87,6 @@ Lista descriptiva de Visual Basic - - <Multiple Types> - <Varios tipos> - - not supported no compatible diff --git a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.fr.xlf b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.fr.xlf index f387d97bd7d2c..659f754c5d0f1 100644 --- a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.fr.xlf +++ b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.fr.xlf @@ -87,11 +87,6 @@ Liste automatique Visual Basic - - <Multiple Types> - <Plusieurs types> - - not supported non pris en charge diff --git a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.it.xlf b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.it.xlf index 3414e733b8185..0d536c01d3de8 100644 --- a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.it.xlf +++ b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.it.xlf @@ -87,11 +87,6 @@ Elenco Visual Basic - - <Multiple Types> - <Più tipi> - - not supported non supportato diff --git a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.ja.xlf b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.ja.xlf index 8b1892443c683..786e466ae9977 100644 --- a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.ja.xlf +++ b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.ja.xlf @@ -87,11 +87,6 @@ Visual Basic の再フォーマット - - <Multiple Types> - <複数の種類> - - not supported サポートされていません diff --git a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.ko.xlf b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.ko.xlf index a097e7223f0e6..08b9ca15c7477 100644 --- a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.ko.xlf +++ b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.ko.xlf @@ -87,11 +87,6 @@ Visual Basic 서식 다시 적용 - - <Multiple Types> - <여러 형식> - - not supported 지원되지 않음 diff --git a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.pl.xlf b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.pl.xlf index bfa1305e66466..3871f85210761 100644 --- a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.pl.xlf +++ b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.pl.xlf @@ -87,11 +87,6 @@ Lista Pretty języka Visual Basic - - <Multiple Types> - <Wiele typów> - - not supported nieobsługiwane diff --git a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.pt-BR.xlf b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.pt-BR.xlf index 08550419b0b82..d8823dc0a626c 100644 --- a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.pt-BR.xlf +++ b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.pt-BR.xlf @@ -87,11 +87,6 @@ Reformatação Automática do Visual Basic - - <Multiple Types> - <Vários Tipos> - - not supported não suportado diff --git a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.ru.xlf b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.ru.xlf index c2cc620bf887b..740def5287fdf 100644 --- a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.ru.xlf +++ b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.ru.xlf @@ -87,11 +87,6 @@ Изящный список Visual Basic - - <Multiple Types> - <Несколько типов> - - not supported не поддерживается diff --git a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.tr.xlf b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.tr.xlf index e6df38b81c564..3c7d0c05119c8 100644 --- a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.tr.xlf +++ b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.tr.xlf @@ -87,11 +87,6 @@ Visual Basic Düzgün Listesi - - <Multiple Types> - <Multiple Types> - - not supported Desteklenmiyor diff --git a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.zh-Hans.xlf b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.zh-Hans.xlf index ca091ca56e572..d10565af637ff 100644 --- a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.zh-Hans.xlf +++ b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.zh-Hans.xlf @@ -87,11 +87,6 @@ Visual Basic 整齐列表 - - <Multiple Types> - <多种类型> - - not supported 不支持 diff --git a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.zh-Hant.xlf b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.zh-Hant.xlf index 0d92e09ff28ff..83b1c3d4cdc1c 100644 --- a/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.zh-Hant.xlf +++ b/src/EditorFeatures/VisualBasic/xlf/VBEditorResources.zh-Hant.xlf @@ -87,11 +87,6 @@ Visual Basic 美化清單 - - <Multiple Types> - <多項類型> - - not supported 不支援 diff --git a/src/EditorFeatures/VisualBasicTest/QuickInfo/SemanticQuickInfoSourceTests.vb b/src/EditorFeatures/VisualBasicTest/QuickInfo/SemanticQuickInfoSourceTests.vb index 42eb617599cad..1ef393eda43cc 100644 --- a/src/EditorFeatures/VisualBasicTest/QuickInfo/SemanticQuickInfoSourceTests.vb +++ b/src/EditorFeatures/VisualBasicTest/QuickInfo/SemanticQuickInfoSourceTests.vb @@ -5,20 +5,22 @@ Imports Microsoft.CodeAnalysis.Editor.UnitTests.Classification.FormattedClassifi Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions Imports Microsoft.CodeAnalysis.Editor.UnitTests.QuickInfo Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces -Imports Microsoft.CodeAnalysis.Editor.VisualBasic.QuickInfo +Imports Microsoft.CodeAnalysis.QuickInfo Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.QuickInfo Public Class SemanticQuickInfoSourceTests Inherits AbstractSemanticQuickInfoSourceTests - Protected Overrides Function TestAsync(markup As String, ParamArray expectedResults() As Action(Of Object)) As Task + Protected Overrides Function TestAsync(markup As String, ParamArray expectedResults() As Action(Of QuickInfoItem)) As Task Return TestWithReferencesAsync(markup, Array.Empty(Of String)(), expectedResults) End Function - Protected Async Function TestSharedAsync(workspace As TestWorkspace, position As Integer, ParamArray expectedResults() As Action(Of Object)) As Task - Dim provider = New SemanticQuickInfoProvider() + Protected Async Function TestSharedAsync(workspace As TestWorkspace, position As Integer, ParamArray expectedResults() As Action(Of QuickInfoItem)) As Task + Dim service = workspace.Services _ + .GetLanguageServices(LanguageNames.VisualBasic) _ + .GetService(Of QuickInfoService) - Await TestSharedAsync(workspace, provider, position, expectedResults) + Await TestSharedAsync(workspace, service, position, expectedResults) ' speculative semantic model Dim document = workspace.CurrentSolution.Projects.First().Documents.First() @@ -29,36 +31,33 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.QuickInfo edit.Apply() End Using - Await TestSharedAsync(workspace, provider, position, expectedResults) + Await TestSharedAsync(workspace, service, position, expectedResults) End If End Function - Private Async Function TestSharedAsync(workspace As TestWorkspace, provider As SemanticQuickInfoProvider, position As Integer, expectedResults() As Action(Of Object)) As Task - Dim state = Await provider.GetItemAsync(workspace.CurrentSolution.Projects.First().Documents.First(), - position, cancellationToken:=CancellationToken.None) - - If state IsNot Nothing Then - WaitForDocumentationComment(state.Content) - End If + Private Async Function TestSharedAsync(workspace As TestWorkspace, service As QuickInfoService, position As Integer, expectedResults() As Action(Of QuickInfoItem)) As Task + Dim info = Await service.GetQuickInfoAsync( + workspace.CurrentSolution.Projects.First().Documents.First(), + position, cancellationToken:=CancellationToken.None) If expectedResults Is Nothing Then - Assert.Null(state) + Assert.Null(info) Else - Assert.NotNull(state) + Assert.NotNull(info) For Each expected In expectedResults - expected(state.Content) + expected(info) Next End If End Function - Protected Async Function TestFromXmlAsync(markup As String, ParamArray expectedResults As Action(Of Object)()) As Task + Private Async Function TestFromXmlAsync(markup As String, ParamArray expectedResults As Action(Of QuickInfoItem)()) As Task Using workspace = TestWorkspace.Create(markup) Await TestSharedAsync(workspace, workspace.Documents.First().CursorPosition.Value, expectedResults) End Using End Function - Protected Async Function TestWithReferencesAsync(markup As String, metadataReferences As String(), ParamArray expectedResults() As Action(Of Object)) As Task + Private Async Function TestWithReferencesAsync(markup As String, metadataReferences As String(), ParamArray expectedResults() As Action(Of QuickInfoItem)) As Task Dim code As String = Nothing Dim position As Integer = Nothing MarkupTestFile.GetPosition(markup, code, position) @@ -68,7 +67,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.QuickInfo End Using End Function - Protected Async Function TestWithImportsAsync(markup As String, ParamArray expectedResults() As Action(Of Object)) As Task + Private Async Function TestWithImportsAsync(markup As String, ParamArray expectedResults() As Action(Of QuickInfoItem)) As Task Dim markupWithImports = "Imports System" & vbCrLf & "Imports System.Collections.Generic" & vbCrLf & @@ -78,7 +77,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.QuickInfo Await TestAsync(markupWithImports, expectedResults) End Function - Protected Async Function TestInClassAsync(markup As String, ParamArray expectedResults() As Action(Of Object)) As Task + Private Async Function TestInClassAsync(markup As String, ParamArray expectedResults() As Action(Of QuickInfoItem)) As Task Dim markupInClass = "Class C" & vbCrLf & markup & vbCrLf & @@ -87,7 +86,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.QuickInfo Await TestWithImportsAsync(markupInClass, expectedResults) End Function - Protected Async Function TestInMethodAsync(markup As String, ParamArray expectedResults() As Action(Of Object)) As Task + Private Async Function TestInMethodAsync(markup As String, ParamArray expectedResults() As Action(Of QuickInfoItem)) As Task Dim markupInClass = "Class C" & vbCrLf & "Sub M()" & vbCrLf & @@ -511,7 +510,7 @@ End Class End Function - + Public Async Function TestOverriddenMethod() As Task Await TestAsync( Class A @@ -584,7 +583,7 @@ End class Public Async Function TestDimMultipleInFieldDeclaration() As Task - Await TestInClassAsync("$$Dim x As Integer, y As String", MainDescription(VBEditorResources.Multiple_Types)) + Await TestInClassAsync("$$Dim x As Integer, y As String", MainDescription(VBFeaturesResources.Multiple_Types)) End Function @@ -606,7 +605,7 @@ End Module Public Async Function TestDimMultipleInLocalDeclaration() As Task - Await TestInMethodAsync("$$Dim x As Integer, y As String", MainDescription(VBEditorResources.Multiple_Types)) + Await TestInMethodAsync("$$Dim x As Integer, y As String", MainDescription(VBFeaturesResources.Multiple_Types)) End Function @@ -1414,7 +1413,7 @@ Class C go$$o() End Function End Class - + .ToString() @@ -1755,9 +1754,10 @@ End Class]]>.NormalizedValue(), Public Async Function TestAwaitKeywordOnTaskReturningAsync() As Task - Dim markup = - - + Dim markup = + + + Imports System.Threading.Tasks Class C @@ -1766,8 +1766,8 @@ Class C End Function End Class - - .ToString() + + .ToString() Dim description = <%= FeaturesResources.Awaited_task_returns %><%= " " %><%= FeaturesResources.no_value %>.ConvertTestSourceTag() @@ -1788,7 +1788,7 @@ Class C Return 42 End Function End Class - + .ToString() diff --git a/src/Features/CSharp/Portable/QuickInfo/CSharpQuickInfoSevice.cs b/src/Features/CSharp/Portable/QuickInfo/CSharpQuickInfoSevice.cs new file mode 100644 index 0000000000000..e26e2e051a092 --- /dev/null +++ b/src/Features/CSharp/Portable/QuickInfo/CSharpQuickInfoSevice.cs @@ -0,0 +1,27 @@ +// 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.Composition; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.QuickInfo; + +namespace Microsoft.CodeAnalysis.CSharp.QuickInfo +{ + [ExportLanguageServiceFactory(typeof(QuickInfoService), LanguageNames.CSharp), Shared] + internal class CSharpQuickInfoServiceFactory : ILanguageServiceFactory + { + public ILanguageService CreateLanguageService(HostLanguageServices languageServices) + { + return new CSharpQuickInfoService(languageServices.WorkspaceServices.Workspace); + } + } + + internal class CSharpQuickInfoService : QuickInfoServiceWithProviders + { + internal CSharpQuickInfoService(Workspace workspace) + : base(workspace, LanguageNames.CSharp) + { + } + } +} + diff --git a/src/EditorFeatures/CSharp/QuickInfo/SemanticQuickInfoProvider.cs b/src/Features/CSharp/Portable/QuickInfo/CSharpSemanticQuickInfoProvider.cs similarity index 79% rename from src/EditorFeatures/CSharp/QuickInfo/SemanticQuickInfoProvider.cs rename to src/Features/CSharp/Portable/QuickInfo/CSharpSemanticQuickInfoProvider.cs index fff8e5e2cdd16..7af284a033b87 100644 --- a/src/EditorFeatures/CSharp/QuickInfo/SemanticQuickInfoProvider.cs +++ b/src/Features/CSharp/Portable/QuickInfo/CSharpSemanticQuickInfoProvider.cs @@ -1,13 +1,13 @@ // 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 Microsoft.CodeAnalysis.CSharp; +using System.Composition; using Microsoft.CodeAnalysis.CSharp.Extensions; -using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo; +using Microsoft.CodeAnalysis.QuickInfo; -namespace Microsoft.CodeAnalysis.Editor.CSharp.QuickInfo +namespace Microsoft.CodeAnalysis.CSharp.QuickInfo { - [ExportQuickInfoProvider(PredefinedQuickInfoProviderNames.Semantic, LanguageNames.CSharp)] - internal class SemanticQuickInfoProvider : AbstractSemanticQuickInfoProvider + [ExportQuickInfoProvider(QuickInfoProviderNames.Semantic, LanguageNames.CSharp), Shared] + internal class CSharpSemanticQuickInfoProvider : CommonSemanticQuickInfoProvider { /// /// If the token is the '=>' in a lambda, or the 'delegate' in an anonymous function, diff --git a/src/EditorFeatures/CSharp/QuickInfo/SyntacticQuickInfoProvider.cs b/src/Features/CSharp/Portable/QuickInfo/CSharpSyntacticQuickInfoProvider.cs similarity index 75% rename from src/EditorFeatures/CSharp/QuickInfo/SyntacticQuickInfoProvider.cs rename to src/Features/CSharp/Portable/QuickInfo/CSharpSyntacticQuickInfoProvider.cs index 14c22107f7c97..fe83607ababaa 100644 --- a/src/EditorFeatures/CSharp/QuickInfo/SyntacticQuickInfoProvider.cs +++ b/src/Features/CSharp/Portable/QuickInfo/CSharpSyntacticQuickInfoProvider.cs @@ -1,27 +1,23 @@ // 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.ComponentModel.Composition; +using System.Collections.Immutable; +using System.Composition; using System.Linq; using System.Threading; using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Extensions; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo; -using Microsoft.CodeAnalysis.Editor.Shared.Utilities; +using Microsoft.CodeAnalysis.QuickInfo; using Microsoft.CodeAnalysis.Text; -using Microsoft.VisualStudio.Language.Intellisense; -using Microsoft.VisualStudio.Text; -using Microsoft.VisualStudio.Text.Editor; -using Microsoft.VisualStudio.Text.Projection; -namespace Microsoft.CodeAnalysis.Editor.CSharp.QuickInfo +namespace Microsoft.CodeAnalysis.CSharp.QuickInfo { - [ExportQuickInfoProvider(PredefinedQuickInfoProviderNames.Syntactic, LanguageNames.CSharp)] - internal class SyntacticQuickInfoProvider : AbstractQuickInfoProvider + [ExportQuickInfoProvider(QuickInfoProviderNames.Syntactic, LanguageNames.CSharp), Shared] + [ExtensionOrder(After = QuickInfoProviderNames.Semantic)] + internal class CSharpSyntacticQuickInfoProvider : CommonQuickInfoProvider { - protected override async Task BuildContentAsync( + protected override async Task BuildQuickInfoAsync( Document document, SyntaxToken token, CancellationToken cancellationToken) @@ -62,17 +58,10 @@ protected override async Task BuildContentAsync( spanStart = parent.Parent.SpanStart; } - // Now that we know what we want to display, create a small elision buffer with that - // span, jam it in a view and show that to the user. + // encode document spans that correspond to the text to show var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); - var textSnapshot = text.FindCorrespondingEditorTextSnapshot(); - if (textSnapshot == null) - { - return null; - } - - var span = new SnapshotSpan(textSnapshot, Span.FromBounds(spanStart, spanEnd)); - return this.CreateProjectionBufferDeferredContent(span); + var spans = ImmutableArray.Create(TextSpan.FromBounds(spanStart, spanEnd)); + return QuickInfoItem.Create(token.Span, relatedSpans: spans); } private static bool IsScopeBlock(SyntaxNode node) @@ -105,7 +94,7 @@ private static void MarkInterestedSpanNearbyScopeBlock(SyntaxNode block, SyntaxT private static bool TryFindFurthestNearbyComment(ref T triviaSearchList, out SyntaxTrivia nearbyTrivia) where T : IEnumerable { - nearbyTrivia = default(SyntaxTrivia); + nearbyTrivia = default; foreach (var trivia in triviaSearchList) { diff --git a/src/Features/Core/Portable/Common/GlyphExtensions.cs b/src/Features/Core/Portable/Common/GlyphExtensions.cs new file mode 100644 index 0000000000000..ca08a524f5e7f --- /dev/null +++ b/src/Features/Core/Portable/Common/GlyphExtensions.cs @@ -0,0 +1,302 @@ +// 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.Immutable; +using Microsoft.CodeAnalysis.Tags; + +namespace Microsoft.CodeAnalysis +{ + internal static class GlyphExtensions + { + public static ImmutableArray GetGlyphs(this ImmutableArray tags) + { + var builder = ImmutableArray.CreateBuilder(initialCapacity: tags.Length); + + foreach (var tag in tags) + { + var glyph = GetGlyph(tag, tags); + if (glyph != Glyph.None) + { + builder.Add(glyph); + } + } + + return builder.ToImmutable(); + } + + public static Glyph GetFirstGlyph(this ImmutableArray tags) + { + var glyphs = GetGlyphs(tags); + + return !glyphs.IsEmpty + ? glyphs[0] + : Glyph.None; + } + + private static Glyph GetGlyph(string tag, ImmutableArray allTags) + { + switch (tag) + { + case WellKnownTags.Assembly: + return Glyph.Assembly; + + case WellKnownTags.File: + return allTags.Contains(LanguageNames.VisualBasic) ? Glyph.BasicFile : Glyph.CSharpFile; + + case WellKnownTags.Project: + return allTags.Contains(LanguageNames.VisualBasic) ? Glyph.BasicProject : Glyph.CSharpProject; + + case WellKnownTags.Class: + switch (GetAccessibility(allTags)) + { + case Accessibility.Protected: + return Glyph.ClassProtected; + case Accessibility.Private: + return Glyph.ClassPrivate; + case Accessibility.Internal: + return Glyph.ClassInternal; + case Accessibility.Public: + default: + return Glyph.ClassPublic; + } + + case WellKnownTags.Constant: + switch (GetAccessibility(allTags)) + { + case Accessibility.Protected: + return Glyph.ConstantProtected; + case Accessibility.Private: + return Glyph.ConstantPrivate; + case Accessibility.Internal: + return Glyph.ConstantInternal; + case Accessibility.Public: + default: + return Glyph.ConstantPublic; + } + + case WellKnownTags.Delegate: + switch (GetAccessibility(allTags)) + { + case Accessibility.Protected: + return Glyph.DelegateProtected; + case Accessibility.Private: + return Glyph.DelegatePrivate; + case Accessibility.Internal: + return Glyph.DelegateInternal; + case Accessibility.Public: + default: + return Glyph.DelegatePublic; + } + + case WellKnownTags.Enum: + switch (GetAccessibility(allTags)) + { + case Accessibility.Protected: + return Glyph.EnumProtected; + case Accessibility.Private: + return Glyph.EnumPrivate; + case Accessibility.Internal: + return Glyph.EnumInternal; + case Accessibility.Public: + default: + return Glyph.EnumPublic; + } + + case WellKnownTags.EnumMember: + switch (GetAccessibility(allTags)) + { + case Accessibility.Protected: + return Glyph.EnumMemberProtected; + case Accessibility.Private: + return Glyph.EnumMemberPrivate; + case Accessibility.Internal: + return Glyph.EnumMemberInternal; + case Accessibility.Public: + default: + return Glyph.EnumMemberPublic; + } + + case WellKnownTags.Error: + return Glyph.Error; + + case WellKnownTags.Event: + switch (GetAccessibility(allTags)) + { + case Accessibility.Protected: + return Glyph.EventProtected; + case Accessibility.Private: + return Glyph.EventPrivate; + case Accessibility.Internal: + return Glyph.EventInternal; + case Accessibility.Public: + default: + return Glyph.EventPublic; + } + + case WellKnownTags.ExtensionMethod: + switch (GetAccessibility(allTags)) + { + case Accessibility.Protected: + return Glyph.ExtensionMethodProtected; + case Accessibility.Private: + return Glyph.ExtensionMethodPrivate; + case Accessibility.Internal: + return Glyph.ExtensionMethodInternal; + case Accessibility.Public: + default: + return Glyph.ExtensionMethodPublic; + } + + case WellKnownTags.Field: + switch (GetAccessibility(allTags)) + { + case Accessibility.Protected: + return Glyph.FieldProtected; + case Accessibility.Private: + return Glyph.FieldPrivate; + case Accessibility.Internal: + return Glyph.FieldInternal; + case Accessibility.Public: + default: + return Glyph.FieldPublic; + } + + case WellKnownTags.Interface: + switch (GetAccessibility(allTags)) + { + case Accessibility.Protected: + return Glyph.InterfaceProtected; + case Accessibility.Private: + return Glyph.InterfacePrivate; + case Accessibility.Internal: + return Glyph.InterfaceInternal; + case Accessibility.Public: + default: + return Glyph.InterfacePublic; + } + + case WellKnownTags.Intrinsic: + return Glyph.Intrinsic; + + case WellKnownTags.Keyword: + return Glyph.Keyword; + + case WellKnownTags.Label: + return Glyph.Label; + + case WellKnownTags.Local: + return Glyph.Local; + + case WellKnownTags.Namespace: + return Glyph.Namespace; + + case WellKnownTags.Method: + switch (GetAccessibility(allTags)) + { + case Accessibility.Protected: + return Glyph.MethodProtected; + case Accessibility.Private: + return Glyph.MethodPrivate; + case Accessibility.Internal: + return Glyph.MethodInternal; + case Accessibility.Public: + default: + return Glyph.MethodPublic; + } + + case WellKnownTags.Module: + switch (GetAccessibility(allTags)) + { + case Accessibility.Protected: + return Glyph.ModulePublic; + case Accessibility.Private: + return Glyph.ModulePrivate; + case Accessibility.Internal: + return Glyph.ModuleInternal; + case Accessibility.Public: + default: + return Glyph.ModulePublic; + } + + case WellKnownTags.Folder: + return Glyph.OpenFolder; + + case WellKnownTags.Operator: + return Glyph.Operator; + + case WellKnownTags.Parameter: + return Glyph.Parameter; + + case WellKnownTags.Property: + switch (GetAccessibility(allTags)) + { + case Accessibility.Protected: + return Glyph.PropertyProtected; + case Accessibility.Private: + return Glyph.PropertyPrivate; + case Accessibility.Internal: + return Glyph.PropertyInternal; + case Accessibility.Public: + default: + return Glyph.PropertyPublic; + } + + case WellKnownTags.RangeVariable: + return Glyph.RangeVariable; + + case WellKnownTags.Reference: + return Glyph.Reference; + + case WellKnownTags.NuGet: + return Glyph.NuGet; + + case WellKnownTags.Structure: + switch (GetAccessibility(allTags)) + { + case Accessibility.Protected: + return Glyph.StructureProtected; + case Accessibility.Private: + return Glyph.StructurePrivate; + case Accessibility.Internal: + return Glyph.StructureInternal; + case Accessibility.Public: + default: + return Glyph.StructurePublic; + } + + case WellKnownTags.TypeParameter: + return Glyph.TypeParameter; + + case WellKnownTags.Snippet: + return Glyph.Snippet; + + case WellKnownTags.Warning: + return Glyph.CompletionWarning; + + case WellKnownTags.StatusInformation: + return Glyph.StatusInformation; + } + + return Glyph.None; + } + + private static Accessibility GetAccessibility(ImmutableArray tags) + { + foreach (var tag in tags) + { + switch (tag) + { + case WellKnownTags.Public: + return Accessibility.Public; + case WellKnownTags.Protected: + return Accessibility.Protected; + case WellKnownTags.Internal: + return Accessibility.Internal; + case WellKnownTags.Private: + return Accessibility.Private; + } + } + + return Accessibility.NotApplicable; + } + } +} diff --git a/src/Features/Core/Portable/Completion/GlyphTags.cs b/src/Features/Core/Portable/Common/GlyphTags.cs similarity index 99% rename from src/Features/Core/Portable/Completion/GlyphTags.cs rename to src/Features/Core/Portable/Common/GlyphTags.cs index 0f9f84d5a8b8f..428aecc536bd1 100644 --- a/src/Features/Core/Portable/Completion/GlyphTags.cs +++ b/src/Features/Core/Portable/Common/GlyphTags.cs @@ -3,7 +3,7 @@ using System.Collections.Immutable; using Microsoft.CodeAnalysis.Tags; -namespace Microsoft.CodeAnalysis.Completion +namespace Microsoft.CodeAnalysis { internal static class GlyphTags { diff --git a/src/Features/Core/Portable/Completion/CommonCompletionItem.cs b/src/Features/Core/Portable/Completion/CommonCompletionItem.cs index 6972d5cfcf5c1..493b592c7ba22 100644 --- a/src/Features/Core/Portable/Completion/CommonCompletionItem.cs +++ b/src/Features/Core/Portable/Completion/CommonCompletionItem.cs @@ -2,6 +2,7 @@ using System.Collections.Immutable; using System.Linq; +using Microsoft.CodeAnalysis.Tags; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Completion @@ -29,7 +30,7 @@ public static CompletionItem Create( if (showsWarningIcon) { - tags = tags.Add(CompletionTags.Warning); + tags = tags.Add(WellKnownTags.Warning); } properties = properties ?? ImmutableDictionary.Empty; diff --git a/src/Features/Core/Portable/Completion/CommonCompletionService.cs b/src/Features/Core/Portable/Completion/CommonCompletionService.cs index d9128324c0666..207c83117adcd 100644 --- a/src/Features/Core/Portable/Completion/CommonCompletionService.cs +++ b/src/Features/Core/Portable/Completion/CommonCompletionService.cs @@ -1,6 +1,7 @@ // 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.Immutable; +using Microsoft.CodeAnalysis.Tags; namespace Microsoft.CodeAnalysis.Completion { @@ -33,12 +34,12 @@ protected override CompletionItem GetBetterItem(CompletionItem item, CompletionI protected static bool IsKeywordItem(CompletionItem item) { - return item.Tags.Contains(CompletionTags.Keyword); + return item.Tags.Contains(WellKnownTags.Keyword); } protected static bool IsSnippetItem(CompletionItem item) { - return item.Tags.Contains(CompletionTags.Snippet); + return item.Tags.Contains(WellKnownTags.Snippet); } } } diff --git a/src/Features/Core/Portable/Completion/CompletionHelper.cs b/src/Features/Core/Portable/Completion/CompletionHelper.cs index 4c5cf8c4b0896..f63dad22497c8 100644 --- a/src/Features/Core/Portable/Completion/CompletionHelper.cs +++ b/src/Features/Core/Portable/Completion/CompletionHelper.cs @@ -6,6 +6,7 @@ using System.Globalization; using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.PatternMatching; +using Microsoft.CodeAnalysis.Tags; using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Completion @@ -183,7 +184,7 @@ private static bool TagsEqual(ImmutableArray tags1, ImmutableArray public ImmutableDictionary Properties { get; } /// - /// Descriptive tags from . + /// Descriptive tags from . /// These tags may influence how the item is displayed. /// public ImmutableArray Tags { get; } diff --git a/src/Features/Core/Portable/Completion/CompletionItemFilter.cs b/src/Features/Core/Portable/Completion/CompletionItemFilter.cs index bf0645fd3a2b0..e13131fef4e5f 100644 --- a/src/Features/Core/Portable/Completion/CompletionItemFilter.cs +++ b/src/Features/Core/Portable/Completion/CompletionItemFilter.cs @@ -1,4 +1,5 @@ using System.Collections.Immutable; +using Microsoft.CodeAnalysis.Tags; namespace Microsoft.CodeAnalysis.Completion { @@ -61,22 +62,22 @@ public static bool ShouldBeFilteredOutOfCompletionList( return true; } - public static readonly CompletionItemFilter NamespaceFilter = new CompletionItemFilter(FeaturesResources.Namespaces, CompletionTags.Namespace, 'n'); - public static readonly CompletionItemFilter ClassFilter = new CompletionItemFilter(FeaturesResources.Classes, CompletionTags.Class, 'c'); - public static readonly CompletionItemFilter ModuleFilter = new CompletionItemFilter(FeaturesResources.Modules, CompletionTags.Module, 'u'); - public static readonly CompletionItemFilter StructureFilter = new CompletionItemFilter(FeaturesResources.Structures, CompletionTags.Structure, 's'); - public static readonly CompletionItemFilter InterfaceFilter = new CompletionItemFilter(FeaturesResources.Interfaces, CompletionTags.Interface, 'i'); - public static readonly CompletionItemFilter EnumFilter = new CompletionItemFilter(FeaturesResources.Enums, CompletionTags.Enum, 'e'); - public static readonly CompletionItemFilter DelegateFilter = new CompletionItemFilter(FeaturesResources.Delegates, CompletionTags.Delegate, 'd'); - public static readonly CompletionItemFilter ConstantFilter = new CompletionItemFilter(FeaturesResources.Constants, CompletionTags.Constant, 'o'); - public static readonly CompletionItemFilter FieldFilter = new CompletionItemFilter(FeaturesResources.Fields, CompletionTags.Field, 'f'); - public static readonly CompletionItemFilter EventFilter = new CompletionItemFilter(FeaturesResources.Events, CompletionTags.Event, 'v'); - public static readonly CompletionItemFilter PropertyFilter = new CompletionItemFilter(FeaturesResources.Properties, CompletionTags.Property, 'p'); - public static readonly CompletionItemFilter MethodFilter = new CompletionItemFilter(FeaturesResources.Methods, CompletionTags.Method, 'm'); - public static readonly CompletionItemFilter ExtensionMethodFilter = new CompletionItemFilter(FeaturesResources.Extension_methods, CompletionTags.ExtensionMethod, 'x'); - public static readonly CompletionItemFilter LocalAndParameterFilter = new CompletionItemFilter(FeaturesResources.Locals_and_parameters, ImmutableArray.Create(CompletionTags.Local, CompletionTags.Parameter), 'l'); - public static readonly CompletionItemFilter KeywordFilter = new CompletionItemFilter(FeaturesResources.Keywords, ImmutableArray.Create(CompletionTags.Keyword), 'k'); - public static readonly CompletionItemFilter SnippetFilter = new CompletionItemFilter(FeaturesResources.Snippets, ImmutableArray.Create(CompletionTags.Snippet), 't'); + public static readonly CompletionItemFilter NamespaceFilter = new CompletionItemFilter(FeaturesResources.Namespaces, WellKnownTags.Namespace, 'n'); + public static readonly CompletionItemFilter ClassFilter = new CompletionItemFilter(FeaturesResources.Classes, WellKnownTags.Class, 'c'); + public static readonly CompletionItemFilter ModuleFilter = new CompletionItemFilter(FeaturesResources.Modules, WellKnownTags.Module, 'u'); + public static readonly CompletionItemFilter StructureFilter = new CompletionItemFilter(FeaturesResources.Structures, WellKnownTags.Structure, 's'); + public static readonly CompletionItemFilter InterfaceFilter = new CompletionItemFilter(FeaturesResources.Interfaces, WellKnownTags.Interface, 'i'); + public static readonly CompletionItemFilter EnumFilter = new CompletionItemFilter(FeaturesResources.Enums, WellKnownTags.Enum, 'e'); + public static readonly CompletionItemFilter DelegateFilter = new CompletionItemFilter(FeaturesResources.Delegates, WellKnownTags.Delegate, 'd'); + public static readonly CompletionItemFilter ConstantFilter = new CompletionItemFilter(FeaturesResources.Constants, WellKnownTags.Constant, 'o'); + public static readonly CompletionItemFilter FieldFilter = new CompletionItemFilter(FeaturesResources.Fields, WellKnownTags.Field, 'f'); + public static readonly CompletionItemFilter EventFilter = new CompletionItemFilter(FeaturesResources.Events, WellKnownTags.Event, 'v'); + public static readonly CompletionItemFilter PropertyFilter = new CompletionItemFilter(FeaturesResources.Properties, WellKnownTags.Property, 'p'); + public static readonly CompletionItemFilter MethodFilter = new CompletionItemFilter(FeaturesResources.Methods, WellKnownTags.Method, 'm'); + public static readonly CompletionItemFilter ExtensionMethodFilter = new CompletionItemFilter(FeaturesResources.Extension_methods, WellKnownTags.ExtensionMethod, 'x'); + public static readonly CompletionItemFilter LocalAndParameterFilter = new CompletionItemFilter(FeaturesResources.Locals_and_parameters, ImmutableArray.Create(WellKnownTags.Local, WellKnownTags.Parameter), 'l'); + public static readonly CompletionItemFilter KeywordFilter = new CompletionItemFilter(FeaturesResources.Keywords, ImmutableArray.Create(WellKnownTags.Keyword), 'k'); + public static readonly CompletionItemFilter SnippetFilter = new CompletionItemFilter(FeaturesResources.Snippets, ImmutableArray.Create(WellKnownTags.Snippet), 't'); public static readonly ImmutableArray NamespaceFilters = ImmutableArray.Create(NamespaceFilter); public static readonly ImmutableArray ClassFilters = ImmutableArray.Create(ClassFilter); diff --git a/src/Features/Core/Portable/Completion/CompletionTags.cs b/src/Features/Core/Portable/Completion/CompletionTags.cs index 158a446073ea1..a09a4680220ea 100644 --- a/src/Features/Core/Portable/Completion/CompletionTags.cs +++ b/src/Features/Core/Portable/Completion/CompletionTags.cs @@ -1,5 +1,7 @@ // 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; +using System.ComponentModel; using Microsoft.CodeAnalysis.Tags; namespace Microsoft.CodeAnalysis.Completion @@ -8,6 +10,8 @@ namespace Microsoft.CodeAnalysis.Completion /// The set of well known tags used for the property. /// These tags influence the presentation of items in the list. /// + [Obsolete("Use Microsoft.CodeAnalysis.Tags.WellKnownTags instead.")] + [EditorBrowsable(EditorBrowsableState.Never)] public static class CompletionTags { // accessibility diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractKeywordCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractKeywordCompletionProvider.cs index fd5e6cdaf3d41..bea06ed941039 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractKeywordCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractKeywordCompletionProvider.cs @@ -8,6 +8,7 @@ using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Tags; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; @@ -68,7 +69,7 @@ private async Task> RecommendCompletionItemsAsync(Do return keywords?.Select(k => CreateItem(k, syntaxContext)); } - protected static ImmutableArray s_Tags = ImmutableArray.Create(CompletionTags.Intrinsic); + protected static ImmutableArray s_Tags = ImmutableArray.Create(WellKnownTags.Intrinsic); protected static CompletionItemRules s_keywordRules = CompletionItemRules.Default; diff --git a/src/Features/Core/Portable/FindUsages/DefinitionItem.cs b/src/Features/Core/Portable/FindUsages/DefinitionItem.cs index 740e8a67d2eac..41f805a35d5e6 100644 --- a/src/Features/Core/Portable/FindUsages/DefinitionItem.cs +++ b/src/Features/Core/Portable/FindUsages/DefinitionItem.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Immutable; using Microsoft.CodeAnalysis.Completion; +using Microsoft.CodeAnalysis.Tags; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.FindUsages @@ -43,7 +44,7 @@ internal abstract partial class DefinitionItem private const string NonNavigable = nameof(NonNavigable); /// - /// Descriptive tags from . These tags may influence how the + /// Descriptive tags from . These tags may influence how the /// item is displayed. /// public ImmutableArray Tags { get; } diff --git a/src/Features/Core/Portable/PublicAPI.Unshipped.txt b/src/Features/Core/Portable/PublicAPI.Unshipped.txt index 8b137891791fe..d7b2e353e2f3b 100644 --- a/src/Features/Core/Portable/PublicAPI.Unshipped.txt +++ b/src/Features/Core/Portable/PublicAPI.Unshipped.txt @@ -1 +1,24 @@ - +Microsoft.CodeAnalysis.QuickInfo.QuickInfoItem +Microsoft.CodeAnalysis.QuickInfo.QuickInfoItem.RelatedSpans.get -> System.Collections.Immutable.ImmutableArray +Microsoft.CodeAnalysis.QuickInfo.QuickInfoItem.Sections.get -> System.Collections.Immutable.ImmutableArray +Microsoft.CodeAnalysis.QuickInfo.QuickInfoItem.Span.get -> Microsoft.CodeAnalysis.Text.TextSpan +Microsoft.CodeAnalysis.QuickInfo.QuickInfoItem.Tags.get -> System.Collections.Immutable.ImmutableArray +Microsoft.CodeAnalysis.QuickInfo.QuickInfoSection +Microsoft.CodeAnalysis.QuickInfo.QuickInfoSection.Kind.get -> string +Microsoft.CodeAnalysis.QuickInfo.QuickInfoSection.TaggedParts.get -> System.Collections.Immutable.ImmutableArray +Microsoft.CodeAnalysis.QuickInfo.QuickInfoSection.Text.get -> string +Microsoft.CodeAnalysis.QuickInfo.QuickInfoSectionKinds +Microsoft.CodeAnalysis.QuickInfo.QuickInfoService +Microsoft.CodeAnalysis.QuickInfo.QuickInfoService.QuickInfoService() -> void +const Microsoft.CodeAnalysis.QuickInfo.QuickInfoSectionKinds.AnonymousTypes = "AnonymousTypes" -> string +const Microsoft.CodeAnalysis.QuickInfo.QuickInfoSectionKinds.Captures = "Captures" -> string +const Microsoft.CodeAnalysis.QuickInfo.QuickInfoSectionKinds.Description = "Description" -> string +const Microsoft.CodeAnalysis.QuickInfo.QuickInfoSectionKinds.DocumentationComments = "DocumentationComments" -> string +const Microsoft.CodeAnalysis.QuickInfo.QuickInfoSectionKinds.Exception = "Exception" -> string +const Microsoft.CodeAnalysis.QuickInfo.QuickInfoSectionKinds.Text = "Text" -> string +const Microsoft.CodeAnalysis.QuickInfo.QuickInfoSectionKinds.TypeParameters = "TypeParameters" -> string +const Microsoft.CodeAnalysis.QuickInfo.QuickInfoSectionKinds.Usage = "Usage" -> string +static Microsoft.CodeAnalysis.QuickInfo.QuickInfoItem.Create(Microsoft.CodeAnalysis.Text.TextSpan span, System.Collections.Immutable.ImmutableArray tags = default(System.Collections.Immutable.ImmutableArray), System.Collections.Immutable.ImmutableArray sections = default(System.Collections.Immutable.ImmutableArray), System.Collections.Immutable.ImmutableArray relatedSpans = default(System.Collections.Immutable.ImmutableArray)) -> Microsoft.CodeAnalysis.QuickInfo.QuickInfoItem +static Microsoft.CodeAnalysis.QuickInfo.QuickInfoSection.Create(string kind, System.Collections.Immutable.ImmutableArray taggedParts) -> Microsoft.CodeAnalysis.QuickInfo.QuickInfoSection +static Microsoft.CodeAnalysis.QuickInfo.QuickInfoService.GetService(Microsoft.CodeAnalysis.Document document) -> Microsoft.CodeAnalysis.QuickInfo.QuickInfoService +virtual Microsoft.CodeAnalysis.QuickInfo.QuickInfoService.GetQuickInfoAsync(Microsoft.CodeAnalysis.Document document, int position, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task diff --git a/src/Features/Core/Portable/QuickInfo/CommonQuickInfoProvider.cs b/src/Features/Core/Portable/QuickInfo/CommonQuickInfoProvider.cs new file mode 100644 index 0000000000000..667d8ea0d4e94 --- /dev/null +++ b/src/Features/Core/Portable/QuickInfo/CommonQuickInfoProvider.cs @@ -0,0 +1,53 @@ +// 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.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Shared.Extensions; + +namespace Microsoft.CodeAnalysis.QuickInfo +{ + internal abstract class CommonQuickInfoProvider : QuickInfoProvider + { + public override async Task GetQuickInfoAsync(QuickInfoContext context) + { + var document = context.Document; + var position = context.Position; + var cancellationToken = context.CancellationToken; + + var tree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); + var token = await tree.GetTouchingTokenAsync(position, cancellationToken, findInsideTrivia: true).ConfigureAwait(false); + + var info = await GetQuickInfoAsync(document, token, position, cancellationToken).ConfigureAwait(false); + + if (info == null && ShouldCheckPreviousToken(token)) + { + var previousToken = token.GetPreviousToken(); + info = await GetQuickInfoAsync(document, previousToken, position, cancellationToken).ConfigureAwait(false); + } + + return info; + } + + protected virtual bool ShouldCheckPreviousToken(SyntaxToken token) + { + return true; + } + + private async Task GetQuickInfoAsync( + Document document, + SyntaxToken token, + int position, + CancellationToken cancellationToken) + { + if (token != default && + token.Span.IntersectsWith(position)) + { + return await BuildQuickInfoAsync(document, token, cancellationToken).ConfigureAwait(false); + } + + return null; + } + + protected abstract Task BuildQuickInfoAsync(Document document, SyntaxToken token, CancellationToken cancellationToken); + } +} diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/Providers/AbstractSemanticQuickInfoProvider.ErrorVisitor.cs b/src/Features/Core/Portable/QuickInfo/CommonSemanticQuickInfoProvider.ErrorVisitor.cs similarity index 94% rename from src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/Providers/AbstractSemanticQuickInfoProvider.ErrorVisitor.cs rename to src/Features/Core/Portable/QuickInfo/CommonSemanticQuickInfoProvider.ErrorVisitor.cs index f51f2460880f7..204cd10199d9e 100644 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/Providers/AbstractSemanticQuickInfoProvider.ErrorVisitor.cs +++ b/src/Features/Core/Portable/QuickInfo/CommonSemanticQuickInfoProvider.ErrorVisitor.cs @@ -2,10 +2,11 @@ using System.Linq; using Microsoft.CodeAnalysis.Shared.Extensions; +using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo +namespace Microsoft.CodeAnalysis.QuickInfo { - internal abstract partial class AbstractSemanticQuickInfoProvider + internal abstract partial class CommonSemanticQuickInfoProvider { private class ErrorVisitor : SymbolVisitor { diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/Providers/AbstractSemanticQuickInfoProvider.SymbolComparer.cs b/src/Features/Core/Portable/QuickInfo/CommonSemanticQuickInfoProvider.SymbolComparer.cs similarity index 88% rename from src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/Providers/AbstractSemanticQuickInfoProvider.SymbolComparer.cs rename to src/Features/Core/Portable/QuickInfo/CommonSemanticQuickInfoProvider.SymbolComparer.cs index e11ff28bb6c2e..06947ba71f035 100644 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/Providers/AbstractSemanticQuickInfoProvider.SymbolComparer.cs +++ b/src/Features/Core/Portable/QuickInfo/CommonSemanticQuickInfoProvider.SymbolComparer.cs @@ -3,9 +3,9 @@ using System.Collections.Generic; using Microsoft.CodeAnalysis.Shared.Utilities; -namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo +namespace Microsoft.CodeAnalysis.QuickInfo { - internal abstract partial class AbstractSemanticQuickInfoProvider + internal abstract partial class CommonSemanticQuickInfoProvider { private class SymbolComparer : IEqualityComparer { diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/Providers/AbstractSemanticQuickInfoProvider.cs b/src/Features/Core/Portable/QuickInfo/CommonSemanticQuickInfoProvider.cs similarity index 56% rename from src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/Providers/AbstractSemanticQuickInfoProvider.cs rename to src/Features/Core/Portable/QuickInfo/CommonSemanticQuickInfoProvider.cs index b18bf616b46a5..0ff368607a39e 100644 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/Providers/AbstractSemanticQuickInfoProvider.cs +++ b/src/Features/Core/Portable/QuickInfo/CommonSemanticQuickInfoProvider.cs @@ -7,88 +7,98 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.DocumentationComments; -using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.ErrorReporting; using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Shared.Utilities; -using Microsoft.VisualStudio.Language.Intellisense; -using Microsoft.VisualStudio.Text; -using Microsoft.VisualStudio.Text.Editor; -using Microsoft.VisualStudio.Text.Projection; -using Microsoft.VisualStudio.Utilities; +using Microsoft.CodeAnalysis.Tags; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo +namespace Microsoft.CodeAnalysis.QuickInfo { - internal abstract partial class AbstractSemanticQuickInfoProvider : AbstractQuickInfoProvider + internal abstract partial class CommonSemanticQuickInfoProvider : CommonQuickInfoProvider { - protected override async Task BuildContentAsync( + protected override async Task BuildQuickInfoAsync( Document document, SyntaxToken token, CancellationToken cancellationToken) { - var linkedDocumentIds = document.GetLinkedDocumentIds(); + var (model, symbols, supportedPlatforms) = await ComputeQuickInfoDataAsync(document, token, cancellationToken).ConfigureAwait(false); - var modelAndSymbols = await this.BindTokenAsync(document, token, cancellationToken).ConfigureAwait(false); - if (modelAndSymbols.Item2.Length == 0 && !linkedDocumentIds.Any()) + if (symbols.IsDefaultOrEmpty) { return null; } - if (!linkedDocumentIds.Any()) + return await CreateContentAsync(document.Project.Solution.Workspace, + token, model, symbols, supportedPlatforms, + cancellationToken).ConfigureAwait(false); + } + + private async Task<(SemanticModel model, ImmutableArray symbols, SupportedPlatformData supportedPlatforms)> ComputeQuickInfoDataAsync( + Document document, + SyntaxToken token, + CancellationToken cancellationToken) + { + var linkedDocumentIds = document.GetLinkedDocumentIds(); + if (linkedDocumentIds.Any()) { - return await CreateContentAsync(document.Project.Solution.Workspace, - token, - modelAndSymbols.Item1, - modelAndSymbols.Item2, - supportedPlatforms: null, - cancellationToken: cancellationToken).ConfigureAwait(false); + return await ComputeFromLinkedDocumentsAsync(document, linkedDocumentIds, token, cancellationToken).ConfigureAwait(false); } + var (model, symbols) = await BindTokenAsync(document, token, cancellationToken).ConfigureAwait(false); + + return (model, symbols, supportedPlatforms: null); + } + + private async Task<(SemanticModel model, ImmutableArray symbols, SupportedPlatformData supportedPlatforms)> ComputeFromLinkedDocumentsAsync( + Document document, + ImmutableArray linkedDocumentIds, + SyntaxToken token, + CancellationToken cancellationToken) + { // Linked files/shared projects: imagine the following when GOO is false // #if GOO // int x = 3; - // #endif + // #endif // var y = x$$; // // 'x' will bind as an error type, so we'll show incorrect information. - // Instead, we need to find the head in which we get the best binding, + // Instead, we need to find the head in which we get the best binding, // which in this case is the one with no errors. + var (model, symbols) = await BindTokenAsync(document, token, cancellationToken).ConfigureAwait(false); + var candidateProjects = new List() { document.Project.Id }; var invalidProjects = new List(); - var candidateResults = new List>>(); - candidateResults.Add(Tuple.Create(document.Id, modelAndSymbols.Item1, modelAndSymbols.Item2)); + var candidateResults = new List<(DocumentId docId, SemanticModel model, ImmutableArray symbols)> + { + (document.Id, model, symbols) + }; - foreach (var link in linkedDocumentIds) + foreach (var linkedDocumentId in linkedDocumentIds) { - var linkedDocument = document.Project.Solution.GetDocument(link); - var linkedToken = await FindTokenInLinkedDocument(token, document, linkedDocument, cancellationToken).ConfigureAwait(false); + var linkedDocument = document.Project.Solution.GetDocument(linkedDocumentId); + var linkedToken = await FindTokenInLinkedDocumentAsync(token, document, linkedDocument, cancellationToken).ConfigureAwait(false); if (linkedToken != default) { // Not in an inactive region, so this file is a candidate. - candidateProjects.Add(link.ProjectId); - var linkedModelAndSymbols = await this.BindTokenAsync(linkedDocument, linkedToken, cancellationToken).ConfigureAwait(false); - candidateResults.Add(Tuple.Create(link, linkedModelAndSymbols.Item1, linkedModelAndSymbols.Item2)); + candidateProjects.Add(linkedDocumentId.ProjectId); + var (linkedModel, linkedSymbols) = await BindTokenAsync(linkedDocument, linkedToken, cancellationToken).ConfigureAwait(false); + candidateResults.Add((linkedDocumentId, linkedModel, linkedSymbols)); } } // Take the first result with no errors. - var bestBinding = candidateResults.FirstOrDefault( - c => c.Item3.Length > 0 && !ErrorVisitor.ContainsError(c.Item3.FirstOrDefault())); + // If every file binds with errors, take the first candidate, which is from the current file. + var bestBinding = candidateResults.FirstOrNullable(c => HasNoErrors(c.symbols)) + ?? candidateResults.First(); - // Every file binds with errors. Take the first candidate, which is from the current file. - if (bestBinding == null) + if (bestBinding.symbols.IsDefaultOrEmpty) { - bestBinding = candidateResults.First(); - } - - if (bestBinding.Item3 == null || !bestBinding.Item3.Any()) - { - return null; + return default; } // We calculate the set of supported projects @@ -96,17 +106,26 @@ protected override async Task BuildContentAsync( foreach (var candidate in candidateResults) { // Does the candidate have anything remotely equivalent? - if (!candidate.Item3.Intersect(bestBinding.Item3, LinkedFilesSymbolEquivalenceComparer.Instance).Any()) + if (!candidate.symbols.Intersect(bestBinding.symbols, LinkedFilesSymbolEquivalenceComparer.Instance).Any()) { - invalidProjects.Add(candidate.Item1.ProjectId); + invalidProjects.Add(candidate.docId.ProjectId); } } var supportedPlatforms = new SupportedPlatformData(invalidProjects, candidateProjects, document.Project.Solution.Workspace); - return await CreateContentAsync(document.Project.Solution.Workspace, token, bestBinding.Item2, bestBinding.Item3, supportedPlatforms, cancellationToken).ConfigureAwait(false); + + return (bestBinding.model, bestBinding.symbols, supportedPlatforms); } - private async Task FindTokenInLinkedDocument(SyntaxToken token, Document originalDocument, Document linkedDocument, CancellationToken cancellationToken) + private static bool HasNoErrors(ImmutableArray symbols) + => symbols.Length > 0 + && !ErrorVisitor.ContainsError(symbols.FirstOrDefault()); + + private async Task FindTokenInLinkedDocumentAsync( + SyntaxToken token, + Document originalDocument, + Document linkedDocument, + CancellationToken cancellationToken) { if (!linkedDocument.SupportsSyntaxTree) { @@ -142,7 +161,7 @@ private async Task FindTokenInLinkedDocument(SyntaxToken token, Doc return default; } - protected async Task CreateContentAsync( + protected async Task CreateContentAsync( Workspace workspace, SyntaxToken token, SemanticModel semanticModel, @@ -151,43 +170,59 @@ protected async Task CreateContentAsync( CancellationToken cancellationToken) { var descriptionService = workspace.Services.GetLanguageServices(token.Language).GetService(); + var formatter = workspace.Services.GetLanguageServices(semanticModel.Language).GetService(); + var syntaxFactsService = workspace.Services.GetLanguageServices(semanticModel.Language).GetService(); + var showWarningGlyph = supportedPlatforms != null && supportedPlatforms.HasValidAndInvalidProjects(); + var showSymbolGlyph = true; - var sections = await descriptionService.ToDescriptionGroupsAsync(workspace, semanticModel, token.SpanStart, symbols.AsImmutable(), cancellationToken).ConfigureAwait(false); + var groups = await descriptionService.ToDescriptionGroupsAsync(workspace, semanticModel, token.SpanStart, symbols.AsImmutable(), cancellationToken).ConfigureAwait(false); + bool TryGetGroupText(SymbolDescriptionGroups group, out ImmutableArray taggedParts) + => groups.TryGetValue(group, out taggedParts) && !taggedParts.IsDefaultOrEmpty; - var mainDescriptionBuilder = new List(); - if (sections.TryGetValue(SymbolDescriptionGroups.MainDescription, out var parts)) + var sections = ImmutableArray.CreateBuilder(initialCapacity: groups.Count); + + void AddSection(string kind, ImmutableArray taggedParts) + => sections.Add(QuickInfoSection.Create(kind, taggedParts)); + + if (TryGetGroupText(SymbolDescriptionGroups.MainDescription, out var mainDescriptionTaggedParts)) { - mainDescriptionBuilder.AddRange(parts); + AddSection(QuickInfoSectionKinds.Description, mainDescriptionTaggedParts); } - var typeParameterMapBuilder = new List(); - if (sections.TryGetValue(SymbolDescriptionGroups.TypeParameterMap, out parts)) + var documentationContent = GetDocumentationContent(symbols, groups, semanticModel, token, formatter, syntaxFactsService, cancellationToken); + if (syntaxFactsService.IsAwaitKeyword(token) && + (symbols.First() as INamedTypeSymbol)?.SpecialType == SpecialType.System_Void) { - if (!parts.IsDefaultOrEmpty) - { - typeParameterMapBuilder.AddLineBreak(); - typeParameterMapBuilder.AddRange(parts); - } + documentationContent = default; + showSymbolGlyph = false; } - var anonymousTypesBuilder = new List(); - if (sections.TryGetValue(SymbolDescriptionGroups.AnonymousTypes, out parts)) + if (!documentationContent.IsDefaultOrEmpty) { - if (!parts.IsDefaultOrEmpty) - { - anonymousTypesBuilder.AddLineBreak(); - anonymousTypesBuilder.AddRange(parts); - } + AddSection(QuickInfoSectionKinds.DocumentationComments, documentationContent); } - var usageTextBuilder = new List(); - if (sections.TryGetValue(SymbolDescriptionGroups.AwaitableUsageText, out parts)) + if (TryGetGroupText(SymbolDescriptionGroups.TypeParameterMap, out var typeParameterMapText)) { - if (!parts.IsDefaultOrEmpty) - { - usageTextBuilder.AddRange(parts); - } + var builder = ImmutableArray.CreateBuilder(); + builder.AddLineBreak(); + builder.AddRange(typeParameterMapText); + AddSection(QuickInfoSectionKinds.TypeParameters, builder.ToImmutable()); + } + + if (TryGetGroupText(SymbolDescriptionGroups.AnonymousTypes, out var anonymousTypesText)) + { + var builder = ImmutableArray.CreateBuilder(); + builder.AddLineBreak(); + builder.AddRange(anonymousTypesText); + AddSection(QuickInfoSectionKinds.AnonymousTypes, builder.ToImmutable()); + } + + var usageTextBuilder = ImmutableArray.CreateBuilder(); + if (TryGetGroupText(SymbolDescriptionGroups.AwaitableUsageText, out var awaitableUsageText)) + { + usageTextBuilder.AddRange(awaitableUsageText); } if (supportedPlatforms != null) @@ -195,48 +230,36 @@ protected async Task CreateContentAsync( usageTextBuilder.AddRange(supportedPlatforms.ToDisplayParts().ToTaggedText()); } - var exceptionsTextBuilder = new List(); - if (sections.TryGetValue(SymbolDescriptionGroups.Exceptions, out parts)) + if (usageTextBuilder.Count > 0) { - if (!parts.IsDefaultOrEmpty) - { - exceptionsTextBuilder.AddRange(parts); - } + AddSection(QuickInfoSectionKinds.Usage, usageTextBuilder.ToImmutable()); } - var capturesTextBuilder = new List(); - if (sections.TryGetValue(SymbolDescriptionGroups.Captures, out parts) && !parts.IsDefaultOrEmpty) + if (TryGetGroupText(SymbolDescriptionGroups.Exceptions, out var exceptionsText)) { - capturesTextBuilder.AddRange(parts); + AddSection(QuickInfoSectionKinds.Exception, exceptionsText); } - var formatter = workspace.Services.GetLanguageServices(semanticModel.Language).GetService(); - var syntaxFactsService = workspace.Services.GetLanguageServices(semanticModel.Language).GetService(); - var documentationContent = GetDocumentationContent(symbols, sections, semanticModel, token, formatter, syntaxFactsService, cancellationToken); - var showWarningGlyph = supportedPlatforms != null && supportedPlatforms.HasValidAndInvalidProjects(); - var showSymbolGlyph = true; + if (TryGetGroupText(SymbolDescriptionGroups.Captures, out var capturesText)) + { + AddSection(QuickInfoSectionKinds.Captures, capturesText); + } - if (workspace.Services.GetLanguageServices(semanticModel.Language).GetService().IsAwaitKeyword(token) && - (symbols.First() as INamedTypeSymbol)?.SpecialType == SpecialType.System_Void) + var tags = ImmutableArray.Empty; + if (showSymbolGlyph) { - documentationContent = CreateDocumentationCommentDeferredContent(null); - showSymbolGlyph = false; + tags = tags.AddRange(GlyphTags.GetTags(symbols.First().GetGlyph())); + } + + if (showWarningGlyph) + { + tags = tags.Add(WellKnownTags.Warning); } - return this.CreateQuickInfoDisplayDeferredContent( - symbol: symbols.First(), - showWarningGlyph: showWarningGlyph, - showSymbolGlyph: showSymbolGlyph, - mainDescription: mainDescriptionBuilder, - documentation: documentationContent, - typeParameterMap: typeParameterMapBuilder, - anonymousTypes: anonymousTypesBuilder, - usageText: usageTextBuilder, - exceptionText: exceptionsTextBuilder, - capturesText: capturesTextBuilder); + return QuickInfoItem.Create(token.Span, tags, sections.ToImmutable()); } - private IDeferredQuickInfoContent GetDocumentationContent( + private ImmutableArray GetDocumentationContent( IEnumerable symbols, IDictionary> sections, SemanticModel semanticModel, @@ -248,8 +271,8 @@ private IDeferredQuickInfoContent GetDocumentationContent( if (sections.TryGetValue(SymbolDescriptionGroups.Documentation, out var parts)) { var documentationBuilder = new List(); - documentationBuilder.AddRange(parts); - return CreateClassifiableDeferredContent(documentationBuilder); + documentationBuilder.AddRange(sections[SymbolDescriptionGroups.Documentation]); + return documentationBuilder.ToImmutableArray(); } else if (symbols.Any()) { @@ -266,19 +289,17 @@ private IDeferredQuickInfoContent GetDocumentationContent( if (documentation != null) { - return CreateClassifiableDeferredContent(documentation.ToList()); + return documentation.ToImmutableArray(); } } - return CreateDocumentationCommentDeferredContent(null); + return default; } protected abstract bool GetBindableNodeForTokenIndicatingLambda(SyntaxToken token, out SyntaxNode found); - private async Task>> BindTokenAsync( - Document document, - SyntaxToken token, - CancellationToken cancellationToken) + private async Task<(SemanticModel semanticModel, ImmutableArray symbols)> BindTokenAsync( + Document document, SyntaxToken token, CancellationToken cancellationToken) { var syntaxFacts = document.Project.LanguageServices.GetService(); var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false); @@ -325,13 +346,10 @@ private async Task>> BindToken } private static bool IsOk(ISymbol symbol) - { - return symbol != null && !symbol.IsErrorType(); - } + => symbol != null && !symbol.IsErrorType(); private static bool IsAccessible(ISymbol symbol, INamedTypeSymbol within) - { - return within == null || symbol.IsAccessibleWithin(within); - } + => within == null + || symbol.IsAccessibleWithin(within); } } diff --git a/src/EditorFeatures/Core/Extensibility/QuickInfo/ExportQuickInfoProviderAttribute.cs b/src/Features/Core/Portable/QuickInfo/ExportQuickInfoProviderAttribute.cs similarity index 60% rename from src/EditorFeatures/Core/Extensibility/QuickInfo/ExportQuickInfoProviderAttribute.cs rename to src/Features/Core/Portable/QuickInfo/ExportQuickInfoProviderAttribute.cs index 594cb8265a61e..7565629b3bd03 100644 --- a/src/EditorFeatures/Core/Extensibility/QuickInfo/ExportQuickInfoProviderAttribute.cs +++ b/src/Features/Core/Portable/QuickInfo/ExportQuickInfoProviderAttribute.cs @@ -1,19 +1,23 @@ // 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; -using System.ComponentModel.Composition; +using System.Composition; -namespace Microsoft.CodeAnalysis.Editor +namespace Microsoft.CodeAnalysis.QuickInfo { + /// + /// Use this attribute to export a so that it will + /// be found and used by the per language associated . + /// [MetadataAttribute] [AttributeUsage(AttributeTargets.Class)] - internal class ExportQuickInfoProviderAttribute : ExportAttribute + internal sealed class ExportQuickInfoProviderAttribute : ExportAttribute { public string Name { get; } public string Language { get; } public ExportQuickInfoProviderAttribute(string name, string language) - : base(typeof(IQuickInfoProvider)) + : base(typeof(QuickInfoProvider)) { this.Name = name ?? throw new ArgumentNullException(nameof(name)); this.Language = language ?? throw new ArgumentNullException(nameof(language)); diff --git a/src/Features/Core/Portable/QuickInfo/IndentationHelper.cs b/src/Features/Core/Portable/QuickInfo/IndentationHelper.cs new file mode 100644 index 0000000000000..2f8571e11cd5f --- /dev/null +++ b/src/Features/Core/Portable/QuickInfo/IndentationHelper.cs @@ -0,0 +1,127 @@ +// 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; +using System.Collections.Generic; +using System.Collections.Immutable; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.QuickInfo +{ + // Reproduces logic in IProjectionBufferFactoryServiceExtensions (editor layer) + // Used for tests currenty, but probably needed for other non-vs-editor API consumers. + internal static class IndentationHelper + { + /// + /// Recomputes span segments so that all text lines appear to have the same reduction in indentation. + /// This operation is typically used to align text for display when the initial span does not include all of the first line's identation. + /// This operation will potentially split spans that cover multiple lines into separate spans. + /// + /// + /// The initial set of spans to align. + /// The number of spaces to + /// + public static ImmutableArray GetSpansWithAlignedIndentation( + SourceText text, + ImmutableArray spans, + int tabSize) + { + if (!spans.IsDefault && spans.Length > 0) + { + // We need to figure out the shortest indentation level of the exposed lines. We'll + // then remove that indentation from all lines. + var indentationColumn = DetermineIndentationColumn(text, spans, tabSize); + + var adjustedSpans = new List(); + + for (var i = 0; i < spans.Length; i++) + { + var span = spans[i]; + var startLineNumber = text.Lines.GetLineFromPosition(span.Start).LineNumber; + var endLineNumber = text.Lines.GetLineFromPosition(span.End).LineNumber; + + for (var lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) + { + var line = text.Lines[lineNumber]; + var lineOffsetOfColumn = line.GetLineOffsetFromColumn(indentationColumn, tabSize); + + var deletion = TextSpan.FromBounds(line.Start, line.Start + lineOffsetOfColumn); + + if (deletion.Start > span.Start) + { + var spanBeforeDeletion = TextSpan.FromBounds(span.Start, Math.Min(span.End, deletion.Start)); + if (spanBeforeDeletion.Length > 0) + { + adjustedSpans.Add(spanBeforeDeletion); + } + } + + if (deletion.End > span.Start) + { + span = TextSpan.FromBounds(Math.Min(deletion.End, span.End), span.End); + } + } + + if (span.Length > 0) + { + adjustedSpans.Add(span); + } + } + + return adjustedSpans.ToImmutableArray(); + } + else + { + return ImmutableArray.Empty; + } + } + + private static int DetermineIndentationColumn( + SourceText text, + ImmutableArray spans, + int tabSize) + { + int? indentationColumn = null; + foreach (var span in spans) + { + var startLineNumber = text.Lines.GetLineFromPosition(span.Start).LineNumber; + var endLineNumber = text.Lines.GetLineFromPosition(span.End).LineNumber; + + // If the span starts after the first non-whitespace of the first line, we'll + // exclude that line to avoid throwing off the calculation. Otherwise, the + // incorrect indentation will be returned for lambda cases like so: + // + // void M() + // { + // Func f = () => + // { + // return 1; + // }; + // } + // + // Without throwing out the first line in the example above, the indentation column + // used will be 4, rather than 8. + var startLineFirstNonWhitespace = text.Lines[startLineNumber].GetFirstNonWhitespacePosition(); + if (startLineFirstNonWhitespace.HasValue && startLineFirstNonWhitespace.Value < span.Start) + { + startLineNumber++; + } + + for (var lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) + { + var line = text.Lines[lineNumber]; + if (line.IsEmptyOrWhitespace()) + { + continue; + } + + indentationColumn = indentationColumn.HasValue + ? Math.Min(indentationColumn.Value, line.GetColumnOfFirstNonWhitespaceCharacterOrEndOfLine(tabSize)) + : line.GetColumnOfFirstNonWhitespaceCharacterOrEndOfLine(tabSize); + } + } + + return indentationColumn ?? 0; + } + } +} diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/Providers/LinkedFileDiscrepancyException.cs b/src/Features/Core/Portable/QuickInfo/LinkedFileDiscrepancyException.cs similarity index 90% rename from src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/Providers/LinkedFileDiscrepancyException.cs rename to src/Features/Core/Portable/QuickInfo/LinkedFileDiscrepancyException.cs index 396a015688c0e..9cc3ddebf79df 100644 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/QuickInfo/Providers/LinkedFileDiscrepancyException.cs +++ b/src/Features/Core/Portable/QuickInfo/LinkedFileDiscrepancyException.cs @@ -2,7 +2,7 @@ using System; -namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo +namespace Microsoft.CodeAnalysis.QuickInfo { // Used to aid the investigation of https://devdiv.visualstudio.com/DevDiv/_workitems?id=209299 internal class LinkedFileDiscrepancyException : Exception diff --git a/src/Features/Core/Portable/QuickInfo/QuickInfoContext.cs b/src/Features/Core/Portable/QuickInfo/QuickInfoContext.cs new file mode 100644 index 0000000000000..134e5b0d31eb0 --- /dev/null +++ b/src/Features/Core/Portable/QuickInfo/QuickInfoContext.cs @@ -0,0 +1,41 @@ +// 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; +using System.Threading; + +namespace Microsoft.CodeAnalysis.QuickInfo +{ + /// + /// The context presented to a when providing quick info. + /// + internal sealed class QuickInfoContext + { + /// + /// The document that quick info was requested within. + /// + public Document Document { get; } + + /// + /// The caret position where quick info was requested from. + /// + public int Position { get; } + + /// + /// The cancellation token to use for this operation. + /// + public CancellationToken CancellationToken { get; } + + /// + /// Creates a instance. + /// + public QuickInfoContext( + Document document, + int position, + CancellationToken cancellationToken) + { + this.Document = document ?? throw new ArgumentNullException(nameof(document)); + this.Position = position; + this.CancellationToken = cancellationToken; + } + } +} diff --git a/src/Features/Core/Portable/QuickInfo/QuickInfoItem.cs b/src/Features/Core/Portable/QuickInfo/QuickInfoItem.cs new file mode 100644 index 0000000000000..27bb52320c061 --- /dev/null +++ b/src/Features/Core/Portable/QuickInfo/QuickInfoItem.cs @@ -0,0 +1,52 @@ +// 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.Immutable; +using Microsoft.CodeAnalysis.Text; + +namespace Microsoft.CodeAnalysis.QuickInfo +{ + public sealed class QuickInfoItem + { + /// + /// The span of the document that the item is based on. + /// + public TextSpan Span { get; } + + /// + /// Descriptive tags from the type. + /// These tags may influence how the item is displayed. + /// + public ImmutableArray Tags { get; } + + /// + /// One or more describing the item. + /// + public ImmutableArray Sections { get; } + + /// + /// Alternate regions of the document that help describe the item. + /// + public ImmutableArray RelatedSpans { get; } + + private QuickInfoItem( + TextSpan span, + ImmutableArray tags, + ImmutableArray sections, + ImmutableArray relatedSpans) + { + this.Span = span; + this.Tags = tags.IsDefault ? ImmutableArray.Empty : tags; + this.Sections = sections.IsDefault ? ImmutableArray.Empty : sections; + this.RelatedSpans = relatedSpans.IsDefault ? ImmutableArray.Empty : relatedSpans; + } + + public static QuickInfoItem Create( + TextSpan span, + ImmutableArray tags = default, + ImmutableArray sections = default, + ImmutableArray relatedSpans = default) + { + return new QuickInfoItem(span, tags, sections, relatedSpans); + } + } +} diff --git a/src/Features/Core/Portable/QuickInfo/QuickInfoProvider.cs b/src/Features/Core/Portable/QuickInfo/QuickInfoProvider.cs new file mode 100644 index 0000000000000..579d87f4cfae8 --- /dev/null +++ b/src/Features/Core/Portable/QuickInfo/QuickInfoProvider.cs @@ -0,0 +1,19 @@ +// 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.Threading.Tasks; + +namespace Microsoft.CodeAnalysis.QuickInfo +{ + /// + /// A provider that produces 's. + /// Providers are used with some implementations. + /// + internal abstract class QuickInfoProvider + { + /// + /// Gets the for the position. + /// + /// The or null if no item is available. + public abstract Task GetQuickInfoAsync(QuickInfoContext context); + } +} diff --git a/src/Features/Core/Portable/QuickInfo/QuickInfoProviderMetadata.cs b/src/Features/Core/Portable/QuickInfo/QuickInfoProviderMetadata.cs new file mode 100644 index 0000000000000..de0df15bbd52d --- /dev/null +++ b/src/Features/Core/Portable/QuickInfo/QuickInfoProviderMetadata.cs @@ -0,0 +1,15 @@ +// 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 Microsoft.CodeAnalysis.Host.Mef; +using System.Collections.Generic; + +namespace Microsoft.CodeAnalysis.QuickInfo +{ + internal class QuickInfoProviderMetadata : OrderableLanguageMetadata + { + public QuickInfoProviderMetadata(IDictionary data) + : base(data) + { + } + } +} \ No newline at end of file diff --git a/src/Features/Core/Portable/QuickInfo/QuickInfoProviderNames.cs b/src/Features/Core/Portable/QuickInfo/QuickInfoProviderNames.cs new file mode 100644 index 0000000000000..ba09d851c00fa --- /dev/null +++ b/src/Features/Core/Portable/QuickInfo/QuickInfoProviderNames.cs @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.CodeAnalysis.QuickInfo +{ + /// + /// Some of the known names in use. + /// Names are used for ordering providers with the . + /// + internal static class QuickInfoProviderNames + { + public const string Semantic = nameof(Semantic); + public const string Syntactic = nameof(Syntactic); + } +} diff --git a/src/Features/Core/Portable/QuickInfo/QuickInfoSection.cs b/src/Features/Core/Portable/QuickInfo/QuickInfoSection.cs new file mode 100644 index 0000000000000..8630557205547 --- /dev/null +++ b/src/Features/Core/Portable/QuickInfo/QuickInfoSection.cs @@ -0,0 +1,65 @@ +// 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.Immutable; +using System.Linq; +using System.Threading; + +namespace Microsoft.CodeAnalysis.QuickInfo +{ + /// + /// Sections are used to make up a . + /// + public sealed class QuickInfoSection + { + /// + /// The kind of this section. Use for the most common kinds. + /// + public string Kind { get; } + + /// + /// The individual tagged parts of this section. + /// + public ImmutableArray TaggedParts { get; } + + private QuickInfoSection(string kind, ImmutableArray taggedParts) + { + this.Kind = kind ?? string.Empty; + this.TaggedParts = taggedParts.NullToEmpty(); + } + + /// + /// Creates a new instance of . + /// + /// The kind of the section. Use for the most common kinds. + /// The individual tagged parts of the section. + public static QuickInfoSection Create(string kind, ImmutableArray taggedParts) + { + return new QuickInfoSection(kind, taggedParts); + } + + private string _text; + + /// + /// The text of the section without tags. + /// + public string Text + { + get + { + if (_text == null) + { + if (this.TaggedParts.Length == 0) + { + _text = string.Empty; + } + else + { + Interlocked.CompareExchange(ref _text, string.Concat(this.TaggedParts.Select(t => t.Text)), null); + } + } + + return _text; + } + } + } +} diff --git a/src/Features/Core/Portable/QuickInfo/QuickInfoSectionKinds.cs b/src/Features/Core/Portable/QuickInfo/QuickInfoSectionKinds.cs new file mode 100644 index 0000000000000..331908c0e702b --- /dev/null +++ b/src/Features/Core/Portable/QuickInfo/QuickInfoSectionKinds.cs @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.CodeAnalysis.QuickInfo +{ + /// + /// The set of well known kinds used for the property. + /// These tags influence the presentation of quick info section. + /// + public static class QuickInfoSectionKinds + { + public const string Description = nameof(Description); + public const string DocumentationComments = nameof(DocumentationComments); + public const string TypeParameters = nameof(TypeParameters); + public const string AnonymousTypes = nameof(AnonymousTypes); + public const string Usage = nameof(Usage); + public const string Exception = nameof(Exception); + public const string Text = nameof(Text); + public const string Captures = nameof(Captures); + } +} diff --git a/src/Features/Core/Portable/QuickInfo/QuickInfoService.cs b/src/Features/Core/Portable/QuickInfo/QuickInfoService.cs new file mode 100644 index 0000000000000..dd14b0bb3d2ab --- /dev/null +++ b/src/Features/Core/Portable/QuickInfo/QuickInfoService.cs @@ -0,0 +1,33 @@ +// 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 Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Shared.Extensions; +using Roslyn.Utilities; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.CodeAnalysis.QuickInfo +{ + /// + /// A service that is used to determine the appropriate quick info for a position in a document. + /// + public abstract class QuickInfoService : ILanguageService + { + /// + /// Gets the appropriate for the specified document. + /// + public static QuickInfoService GetService(Document document) + => document?.GetLanguageService(); + + /// + /// Gets the associated with position in the document. + /// + public virtual Task GetQuickInfoAsync( + Document document, + int position, + CancellationToken cancellationToken = default) + { + return SpecializedTasks.Default(); + } + } +} diff --git a/src/Features/Core/Portable/QuickInfo/QuickInfoServiceWithProviders.cs b/src/Features/Core/Portable/QuickInfo/QuickInfoServiceWithProviders.cs new file mode 100644 index 0000000000000..1f6b42798d140 --- /dev/null +++ b/src/Features/Core/Portable/QuickInfo/QuickInfoServiceWithProviders.cs @@ -0,0 +1,80 @@ +// 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; +using System.Collections.Immutable; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Extensions; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Shared.Utilities; + +namespace Microsoft.CodeAnalysis.QuickInfo +{ + /// + /// Base class for 's that delegate to 's. + /// + internal abstract class QuickInfoServiceWithProviders : QuickInfoService + { + private readonly Workspace _workspace; + private readonly string _language; + private ImmutableArray _providers; + + protected QuickInfoServiceWithProviders(Workspace workspace, string language) + { + _workspace = workspace; + _language = language; + } + + private ImmutableArray GetProviders() + { + if (_providers.IsDefault) + { + var mefExporter = (IMefHostExportProvider)_workspace.Services.HostServices; + + var providers = ExtensionOrderer + .Order(mefExporter.GetExports() + .Where(lz => lz.Metadata.Language == _language)) + .Select(lz => lz.Value) + .ToImmutableArray(); + + ImmutableInterlocked.InterlockedCompareExchange(ref _providers, providers, default(ImmutableArray)); + } + + return _providers; + } + + public override async Task GetQuickInfoAsync(Document document, int position, CancellationToken cancellationToken) + { + var extensionManager = _workspace.Services.GetService(); + + // returns the first non-empty quick info found (based on provider order) + foreach (var provider in GetProviders()) + { + try + { + if (!extensionManager.IsDisabled(provider)) + { + var context = new QuickInfoContext(document, position, cancellationToken); + + var info = await provider.GetQuickInfoAsync(context).ConfigureAwait(false); + if (info != null) + { + return info; + } + } + } + catch (OperationCanceledException) + { + throw; + } + catch (Exception e) when (extensionManager.CanHandleException(provider, e)) + { + extensionManager.HandleException(provider, e); + } + } + + return null; + } + } +} diff --git a/src/Features/Core/Portable/QuickInfo/QuickInfoUtilities.cs b/src/Features/Core/Portable/QuickInfo/QuickInfoUtilities.cs deleted file mode 100644 index 3d260c9c9e7f9..0000000000000 --- a/src/Features/Core/Portable/QuickInfo/QuickInfoUtilities.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - - -namespace Microsoft.CodeAnalysis.QuickInfo -{ - internal class QuickInfoUtilities - { - public static string EventHookupKey = "EventHookup"; - } -} diff --git a/src/Features/VisualBasic/Portable/Completion/VisualBasicCompletionService.vb b/src/Features/VisualBasic/Portable/Completion/VisualBasicCompletionService.vb index 848dc08292b35..9868c05825702 100644 --- a/src/Features/VisualBasic/Portable/Completion/VisualBasicCompletionService.vb +++ b/src/Features/VisualBasic/Portable/Completion/VisualBasicCompletionService.vb @@ -10,6 +10,7 @@ Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Completion.Providers Imports Microsoft.CodeAnalysis.VisualBasic.Completion.SuggestionMode Imports Microsoft.CodeAnalysis.Host +Imports Microsoft.CodeAnalysis.Tags Namespace Microsoft.CodeAnalysis.VisualBasic.Completion @@ -45,7 +46,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion Private ReadOnly _workspace As Workspace Public Sub New(workspace As Workspace, - Optional exclusiveProviders As ImmutableArray(Of CompletionProvider) ? = Nothing) + Optional exclusiveProviders As ImmutableArray(Of CompletionProvider)? = Nothing) MyBase.New(workspace, exclusiveProviders) _workspace = workspace End Sub @@ -114,7 +115,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Completion ' the glyph when matching. Dim keywordCompletionItem = If(IsKeywordItem(existingItem), existingItem, If(IsKeywordItem(item), item, Nothing)) - If keywordCompletionItem IsNot Nothing AndAlso keywordCompletionItem.Tags.Contains(CompletionTags.Intrinsic) Then + If keywordCompletionItem IsNot Nothing AndAlso keywordCompletionItem.Tags.Contains(WellKnownTags.Intrinsic) Then Dim otherItem = If(keywordCompletionItem Is item, existingItem, item) Dim changeText = GetChangeText(otherItem) If changeText = keywordCompletionItem.DisplayText Then diff --git a/src/Features/VisualBasic/Portable/QuickInfo/VisualBasicQuickInfoService.vb b/src/Features/VisualBasic/Portable/QuickInfo/VisualBasicQuickInfoService.vb new file mode 100644 index 0000000000000..883c199b84c39 --- /dev/null +++ b/src/Features/VisualBasic/Portable/QuickInfo/VisualBasicQuickInfoService.vb @@ -0,0 +1,26 @@ +' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +Imports System.Composition +Imports Microsoft.CodeAnalysis.Host +Imports Microsoft.CodeAnalysis.Host.Mef +Imports Microsoft.CodeAnalysis.QuickInfo + +Namespace Microsoft.CodeAnalysis.VisualBasic.QuickInfo + + Friend Class VisualBasicQuickInfoServiceFactory + Implements ILanguageServiceFactory + + Public Function CreateLanguageService(languageServices As HostLanguageServices) As ILanguageService Implements ILanguageServiceFactory.CreateLanguageService + Return New VisualBasicQuickInfoService(languageServices.WorkspaceServices.Workspace) + End Function + + End Class + + Friend Class VisualBasicQuickInfoService + Inherits QuickInfoServiceWithProviders + + Public Sub New(workspace As Workspace) + MyBase.New(workspace, LanguageNames.VisualBasic) + End Sub + End Class +End Namespace diff --git a/src/EditorFeatures/VisualBasic/QuickInfo/SemanticQuickInfoProvider.vb b/src/Features/VisualBasic/Portable/QuickInfo/VisualBasicSemanticQuickInfoProvider.vb similarity index 65% rename from src/EditorFeatures/VisualBasic/QuickInfo/SemanticQuickInfoProvider.vb rename to src/Features/VisualBasic/Portable/QuickInfo/VisualBasicSemanticQuickInfoProvider.vb index 87d996db769a3..62847b15d9d96 100644 --- a/src/EditorFeatures/VisualBasic/QuickInfo/SemanticQuickInfoProvider.vb +++ b/src/Features/VisualBasic/Portable/QuickInfo/VisualBasicSemanticQuickInfoProvider.vb @@ -1,41 +1,37 @@ ' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -Imports System.ComponentModel.Composition +Imports System.Collections.Immutable +Imports System.Composition Imports System.Runtime.InteropServices Imports System.Threading -Imports System.Threading.Tasks Imports Microsoft.CodeAnalysis -Imports Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo -Imports Microsoft.CodeAnalysis.Editor.Shared.Utilities +Imports Microsoft.CodeAnalysis.QuickInfo Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Microsoft.CodeAnalysis.VisualBasic.Utilities.IntrinsicOperators -Imports Microsoft.VisualStudio.Language.Intellisense -Imports Microsoft.VisualStudio.Text.Editor -Imports Microsoft.VisualStudio.Text.Projection -Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.QuickInfo +Namespace Microsoft.CodeAnalysis.VisualBasic.QuickInfo + + Friend Class VisualBasicSemanticQuickInfoProvider + Inherits CommonSemanticQuickInfoProvider - - Friend Class SemanticQuickInfoProvider - Inherits AbstractSemanticQuickInfoProvider + Protected Overrides Async Function BuildQuickInfoAsync( + document As Document, + token As SyntaxToken, + cancellationToken As CancellationToken) As Task(Of QuickInfoItem) - Protected Overrides Async Function BuildContentAsync(document As Document, - token As SyntaxToken, - cancellationToken As CancellationToken) As Task(Of IDeferredQuickInfoContent) - Dim vbToken = CType(token, SyntaxToken) - Dim parent = vbToken.Parent + Dim parent = token.Parent Dim predefinedCastExpression = TryCast(parent, PredefinedCastExpressionSyntax) - If predefinedCastExpression IsNot Nothing AndAlso vbToken = predefinedCastExpression.Keyword Then + If predefinedCastExpression IsNot Nothing AndAlso token = predefinedCastExpression.Keyword Then Dim compilation = Await document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(False) Dim documentation = New PredefinedCastExpressionDocumentation(predefinedCastExpression.Keyword.Kind, compilation) - Return Await BuildContentForIntrinsicOperatorAsync(document, parent, documentation, Glyph.MethodPublic, cancellationToken).ConfigureAwait(False) + Return Await BuildContentForIntrinsicOperatorAsync(document, token, parent, documentation, Glyph.MethodPublic, cancellationToken).ConfigureAwait(False) End If - Select Case vbToken.Kind + Select Case token.Kind Case SyntaxKind.AddHandlerKeyword If TypeOf parent Is AddRemoveHandlerStatementSyntax Then - Return Await BuildContentForIntrinsicOperatorAsync(document, parent, New AddHandlerStatementDocumentation(), Glyph.Keyword, cancellationToken).ConfigureAwait(False) + Return Await BuildContentForIntrinsicOperatorAsync(document, token, parent, New AddHandlerStatementDocumentation(), Glyph.Keyword, cancellationToken).ConfigureAwait(False) End If Case SyntaxKind.DimKeyword @@ -47,50 +43,50 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.QuickInfo Case SyntaxKind.CTypeKeyword If TypeOf parent Is CTypeExpressionSyntax Then - Return Await BuildContentForIntrinsicOperatorAsync(document, parent, New CTypeCastExpressionDocumentation(), Glyph.MethodPublic, cancellationToken).ConfigureAwait(False) + Return Await BuildContentForIntrinsicOperatorAsync(document, token, parent, New CTypeCastExpressionDocumentation(), Glyph.MethodPublic, cancellationToken).ConfigureAwait(False) End If Case SyntaxKind.DirectCastKeyword If TypeOf parent Is DirectCastExpressionSyntax Then - Return Await BuildContentForIntrinsicOperatorAsync(document, parent, New DirectCastExpressionDocumentation(), Glyph.MethodPublic, cancellationToken).ConfigureAwait(False) + Return Await BuildContentForIntrinsicOperatorAsync(document, token, parent, New DirectCastExpressionDocumentation(), Glyph.MethodPublic, cancellationToken).ConfigureAwait(False) End If Case SyntaxKind.GetTypeKeyword If TypeOf parent Is GetTypeExpressionSyntax Then - Return Await BuildContentForIntrinsicOperatorAsync(document, parent, New GetTypeExpressionDocumentation(), Glyph.MethodPublic, cancellationToken).ConfigureAwait(False) + Return Await BuildContentForIntrinsicOperatorAsync(document, token, parent, New GetTypeExpressionDocumentation(), Glyph.MethodPublic, cancellationToken).ConfigureAwait(False) End If Case SyntaxKind.GetXmlNamespaceKeyword If TypeOf parent Is GetXmlNamespaceExpressionSyntax Then - Return Await BuildContentForIntrinsicOperatorAsync(document, parent, New GetXmlNamespaceExpressionDocumentation(), Glyph.MethodPublic, cancellationToken).ConfigureAwait(False) + Return Await BuildContentForIntrinsicOperatorAsync(document, token, parent, New GetXmlNamespaceExpressionDocumentation(), Glyph.MethodPublic, cancellationToken).ConfigureAwait(False) End If Case SyntaxKind.IfKeyword If parent.Kind = SyntaxKind.BinaryConditionalExpression Then - Return Await BuildContentForIntrinsicOperatorAsync(document, parent, New BinaryConditionalExpressionDocumentation(), Glyph.MethodPublic, cancellationToken).ConfigureAwait(False) + Return Await BuildContentForIntrinsicOperatorAsync(document, token, parent, New BinaryConditionalExpressionDocumentation(), Glyph.MethodPublic, cancellationToken).ConfigureAwait(False) ElseIf parent.Kind = SyntaxKind.TernaryConditionalExpression Then - Return Await BuildContentForIntrinsicOperatorAsync(document, parent, New TernaryConditionalExpressionDocumentation(), Glyph.MethodPublic, cancellationToken).ConfigureAwait(False) + Return Await BuildContentForIntrinsicOperatorAsync(document, token, parent, New TernaryConditionalExpressionDocumentation(), Glyph.MethodPublic, cancellationToken).ConfigureAwait(False) End If Case SyntaxKind.RemoveHandlerKeyword If TypeOf parent Is AddRemoveHandlerStatementSyntax Then - Return Await BuildContentForIntrinsicOperatorAsync(document, parent, New RemoveHandlerStatementDocumentation(), Glyph.Keyword, cancellationToken).ConfigureAwait(False) + Return Await BuildContentForIntrinsicOperatorAsync(document, token, parent, New RemoveHandlerStatementDocumentation(), Glyph.Keyword, cancellationToken).ConfigureAwait(False) End If Case SyntaxKind.TryCastKeyword If TypeOf parent Is TryCastExpressionSyntax Then - Return Await BuildContentForIntrinsicOperatorAsync(document, parent, New TryCastExpressionDocumentation(), Glyph.MethodPublic, cancellationToken).ConfigureAwait(False) + Return Await BuildContentForIntrinsicOperatorAsync(document, token, parent, New TryCastExpressionDocumentation(), Glyph.MethodPublic, cancellationToken).ConfigureAwait(False) End If Case SyntaxKind.IdentifierToken If SyntaxFacts.GetContextualKeywordKind(token.ToString()) = SyntaxKind.MidKeyword Then If parent.Kind = SyntaxKind.MidExpression Then - Return Await BuildContentForIntrinsicOperatorAsync(document, parent, New MidAssignmentDocumentation(), Glyph.MethodPublic, cancellationToken).ConfigureAwait(False) + Return Await BuildContentForIntrinsicOperatorAsync(document, token, parent, New MidAssignmentDocumentation(), Glyph.MethodPublic, cancellationToken).ConfigureAwait(False) End If End If End Select - Return Await MyBase.BuildContentAsync(document, token, cancellationToken).ConfigureAwait(False) + Return Await MyBase.BuildQuickInfoAsync(document, token, cancellationToken).ConfigureAwait(False) End Function ''' @@ -106,10 +102,11 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.QuickInfo Return False End Function - Private Overloads Async Function BuildContentAsync(document As Document, - token As SyntaxToken, - declarators As SeparatedSyntaxList(Of VariableDeclaratorSyntax), - cancellationToken As CancellationToken) As Task(Of IDeferredQuickInfoContent) + Private Overloads Async Function BuildContentAsync( + document As Document, + token As SyntaxToken, + declarators As SeparatedSyntaxList(Of VariableDeclaratorSyntax), + cancellationToken As CancellationToken) As Task(Of QuickInfoItem) If declarators.Count = 0 Then Return Nothing @@ -138,19 +135,18 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.QuickInfo End If If types.Count > 1 Then - Dim contentBuilder = New List(Of TaggedText) - contentBuilder.AddText(VBEditorResources.Multiple_Types) - Return Me.CreateClassifiableDeferredContent(contentBuilder) + Return QuickInfoItem.Create(token.Span, sections:=ImmutableArray.Create(QuickInfoSection.Create(QuickInfoSectionKinds.Description, ImmutableArray.Create(New TaggedText(TextTags.Text, VBFeaturesResources.Multiple_Types))))) End If Return Await CreateContentAsync(document.Project.Solution.Workspace, token, semantics, types, supportedPlatforms:=Nothing, cancellationToken:=cancellationToken).ConfigureAwait(False) End Function Private Async Function BuildContentForIntrinsicOperatorAsync(document As Document, + token As SyntaxToken, expression As SyntaxNode, documentation As AbstractIntrinsicOperatorDocumentation, glyph As Glyph, - cancellationToken As CancellationToken) As Task(Of IDeferredQuickInfoContent) + cancellationToken As CancellationToken) As Task(Of QuickInfoItem) Dim builder = New List(Of SymbolDisplayPart) builder.AddRange(documentation.PrefixParts) @@ -168,7 +164,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.QuickInfo Dim typeNameToBind = documentation.TryGetTypeNameParameter(expression, i) If typeNameToBind IsNot Nothing Then - ' We'll try to bind the type name + ' We'll try to bind the type name Dim typeInfo = semanticModel.GetTypeInfo(typeNameToBind, cancellationToken) If typeInfo.Type IsNot Nothing Then @@ -182,14 +178,13 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.QuickInfo builder.AddRange(documentation.GetSuffix(semanticModel, position, expression, cancellationToken)) - Return CreateQuickInfoDisplayDeferredContent( - glyph, - builder.ToTaggedText(), - CreateDocumentationCommentDeferredContent(documentation.DocumentationText), - SpecializedCollections.EmptyList(Of TaggedText), - SpecializedCollections.EmptyList(Of TaggedText), - SpecializedCollections.EmptyList(Of TaggedText), - SpecializedCollections.EmptyList(Of TaggedText)) + Return QuickInfoItem.Create( + token.Span, + tags:=GlyphTags.GetTags(glyph), + sections:=ImmutableArray.Create( + QuickInfoSection.Create(QuickInfoSectionKinds.Description, builder.ToTaggedText()), + QuickInfoSection.Create(QuickInfoSectionKinds.DocumentationComments, ImmutableArray.Create(New TaggedText(TextTags.Text, documentation.DocumentationText))))) End Function End Class End Namespace + diff --git a/src/Features/VisualBasic/Portable/VBFeaturesResources.Designer.vb b/src/Features/VisualBasic/Portable/VBFeaturesResources.Designer.vb index d3fca22a29cd9..3501957c8d3a8 100644 --- a/src/Features/VisualBasic/Portable/VBFeaturesResources.Designer.vb +++ b/src/Features/VisualBasic/Portable/VBFeaturesResources.Designer.vb @@ -1601,6 +1601,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.VBFeaturesResources End Get End Property + ''' + ''' Looks up a localized string similar to <Multiple Types>. + ''' + Friend ReadOnly Property Multiple_Types() As String + Get + Return ResourceManager.GetString("Multiple_Types", resourceCulture) + End Get + End Property + ''' ''' Looks up a localized string similar to Multiplies two numbers and returns the product.. ''' diff --git a/src/Features/VisualBasic/Portable/VBFeaturesResources.resx b/src/Features/VisualBasic/Portable/VBFeaturesResources.resx index 73ef1bf0e7092..4d48572d728f8 100644 --- a/src/Features/VisualBasic/Portable/VBFeaturesResources.resx +++ b/src/Features/VisualBasic/Portable/VBFeaturesResources.resx @@ -1235,6 +1235,9 @@ Sub(<parameterList>) <statement> Make Async Sub + + <Multiple Types> + Add 'Me.' diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.cs.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.cs.xlf index e0dbe7ad1723f..c1cb1bde13906 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.cs.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.cs.xlf @@ -52,6 +52,11 @@ Odstraní příkaz {0}. + + <Multiple Types> + <Multiple Types> + + Remove Unnecessary Imports Odebrat nepotřebné importy diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.de.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.de.xlf index 92b344108b09c..4351efd487615 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.de.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.de.xlf @@ -52,6 +52,11 @@ Löschen der "{0}"-Anweisung. + + <Multiple Types> + <Multiple Types> + + Remove Unnecessary Imports Unnötige Import-Direktiven entfernen diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.es.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.es.xlf index dfe5663a817a6..d83e248347907 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.es.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.es.xlf @@ -52,6 +52,11 @@ Elimine la instrucción '{0}'. + + <Multiple Types> + <Multiple Types> + + Remove Unnecessary Imports Quitar instrucciones Import innecesarias diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.fr.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.fr.xlf index 58be65b9d111c..2cd6dc74c9480 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.fr.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.fr.xlf @@ -52,6 +52,11 @@ Supprimez l'instruction '{0}'. + + <Multiple Types> + <Multiple Types> + + Remove Unnecessary Imports Supprimer les importations superflues diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.it.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.it.xlf index 9c7cf80e29821..db43ba6692f49 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.it.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.it.xlf @@ -52,6 +52,11 @@ Eliminare l'istruzione '{0}'. + + <Multiple Types> + <Multiple Types> + + Remove Unnecessary Imports Rimuovi istruzioni Imports non necessarie diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ja.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ja.xlf index 8dd9d5eaa0104..0adeb3e05ef60 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ja.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ja.xlf @@ -52,6 +52,11 @@ {0}' ステートメントを削除します。 + + <Multiple Types> + <Multiple Types> + + Remove Unnecessary Imports 不要なインポートの削除 diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ko.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ko.xlf index 6f8a382862f06..4ada3f5c86fa4 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ko.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ko.xlf @@ -52,6 +52,11 @@ {0}' 문을 삭제합니다. + + <Multiple Types> + <Multiple Types> + + Remove Unnecessary Imports 불필요한 Imports 제거 diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pl.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pl.xlf index 8e0ac037420f0..cf0d92fbeb6e0 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pl.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pl.xlf @@ -52,6 +52,11 @@ Usuń instrukcję „{0}”. + + <Multiple Types> + <Multiple Types> + + Remove Unnecessary Imports Usuń niepotrzebne importy diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pt-BR.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pt-BR.xlf index 0880f129090a6..7da55efac8c13 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pt-BR.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.pt-BR.xlf @@ -52,6 +52,11 @@ Exclua a instrução "{0}". + + <Multiple Types> + <Multiple Types> + + Remove Unnecessary Imports Remover Importações Desnecessárias diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ru.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ru.xlf index bb1f6ace4df87..cb9cd8a558a25 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ru.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.ru.xlf @@ -52,6 +52,11 @@ Удалить оператор "{0}". + + <Multiple Types> + <Multiple Types> + + Remove Unnecessary Imports Удалить ненужные импорты diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.tr.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.tr.xlf index 161958c5c1b68..2804f3dce9940 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.tr.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.tr.xlf @@ -52,6 +52,11 @@ {0}' deyimini silin. + + <Multiple Types> + <Multiple Types> + + Remove Unnecessary Imports Gereksiz İçeri Aktarmaları Kaldır diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hans.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hans.xlf index f98fb4e21bdfc..e97495f75cfca 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hans.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hans.xlf @@ -52,6 +52,11 @@ 删除“{0}”语句。 + + <Multiple Types> + <Multiple Types> + + Remove Unnecessary Imports 删除不必要的导入 diff --git a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hant.xlf b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hant.xlf index e219785543500..c2a6e02e16cd3 100644 --- a/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hant.xlf +++ b/src/Features/VisualBasic/Portable/xlf/VBFeaturesResources.zh-Hant.xlf @@ -52,6 +52,11 @@ 刪除 '{0}' 陳述式。 + + <Multiple Types> + <Multiple Types> + + Remove Unnecessary Imports 移除不必要的匯入 diff --git a/src/Interactive/EditorFeatures/Core/CommandHandlers/InteractiveIntelliSenseCommandHandler.cs b/src/Interactive/EditorFeatures/Core/CommandHandlers/InteractiveIntelliSenseCommandHandler.cs index cb4bc4368c30a..a09c5988d92f4 100644 --- a/src/Interactive/EditorFeatures/Core/CommandHandlers/InteractiveIntelliSenseCommandHandler.cs +++ b/src/Interactive/EditorFeatures/Core/CommandHandlers/InteractiveIntelliSenseCommandHandler.cs @@ -15,11 +15,9 @@ internal sealed class InteractiveIntelliSenseCommandHandler : AbstractIntelliSen [ImportingConstructor] public InteractiveIntelliSenseCommandHandler( CompletionCommandHandler completionCommandHandler, - SignatureHelpCommandHandler signatureHelpCommandHandler, - QuickInfoCommandHandlerAndSourceProvider quickInfoCommandHandler) + SignatureHelpCommandHandler signatureHelpCommandHandler) : base(completionCommandHandler, - signatureHelpCommandHandler, - quickInfoCommandHandler) + signatureHelpCommandHandler) { } } diff --git a/src/VisualStudio/CSharp/Impl/EventCompletion/HACK_EventHookupDismissalOnBufferChangePreventerService.cs b/src/VisualStudio/CSharp/Impl/EventCompletion/HACK_EventHookupDismissalOnBufferChangePreventerService.cs deleted file mode 100644 index 6ca6b6329354c..0000000000000 --- a/src/VisualStudio/CSharp/Impl/EventCompletion/HACK_EventHookupDismissalOnBufferChangePreventerService.cs +++ /dev/null @@ -1,165 +0,0 @@ -// 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; -using System.Collections.Generic; -using System.ComponentModel.Composition; -using System.Linq; -using System.Reflection; -using Microsoft.CodeAnalysis.Editor; -using Microsoft.CodeAnalysis.Editor.CSharp.EventHookup; -using Microsoft.VisualStudio.Language.Intellisense; -using Microsoft.VisualStudio.Text.Editor; -using Microsoft.VisualStudio.TextManager.Interop; -using Microsoft.VisualStudio.Utilities; - -namespace Microsoft.VisualStudio.LanguageServices.CSharp.EventHookup -{ - /// - /// Need to trick ShimQuickInfoController into leaving Quick Info Sessions created by - /// EventHookupCommandHandler visible even through buffer changed events. We must set its - /// private _session field via reflection. - /// - [Export(typeof(IHACK_EventHookupDismissalOnBufferChangePreventerService))] - internal sealed class HACK_EventHookupDismissalOnBufferChangePreventerService : IHACK_EventHookupDismissalOnBufferChangePreventerService - { - public void HACK_EnsureQuickInfoSessionNotDismissedPrematurely(ITextView textView) - { - // Need an IQuickInfoSession with Properties containing an IVsTextTipData - HACK_SetShimQuickInfoSessionWorker(textView, new HACK_QuickInfoSession()); - } - - public void HACK_OnQuickInfoSessionDismissed(ITextView textView) - { - HACK_SetShimQuickInfoSessionWorker(textView, null); - } - -#pragma warning disable CS0618 // IQuickInfo* is obsolete, tracked by https://github.com/dotnet/roslyn/issues/24094 - private void HACK_SetShimQuickInfoSessionWorker(ITextView textView, IQuickInfoSession quickInfoSession) - { - var properties = textView.Properties.PropertyList; - var shimController = properties.Single(p => p.Value != null && p.Value.GetType().Name == "ShimQuickInfoController").Value; - var sessionField = shimController.GetType().GetField("_session", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); - sessionField.SetValue(shimController, quickInfoSession); - } - - /// - /// The Properties property must contain an IVsTextTipData (which is never used), but no - /// other methods need to be implemented. - /// - private class HACK_QuickInfoSession : IQuickInfoSession - { -#pragma warning disable 67 - public event EventHandler Dismissed; - public event EventHandler Recalculated; - public event EventHandler ApplicableToSpanChanged; - public event EventHandler PresenterChanged; -#pragma warning restore 67 -#pragma warning restore CS0618 // IQuickInfo* is obsolete, tracked by https://github.com/dotnet/roslyn/issues/24094 - public PropertyCollection Properties - { - get - { - var collection = new PropertyCollection(); - collection.AddProperty(typeof(IVsTextTipData), new HACK_VsTextTipData()); - return collection; - } - } - - public Microsoft.VisualStudio.Text.ITrackingSpan ApplicableToSpan - { - get { throw new NotImplementedException(); } - } - - public BulkObservableCollection QuickInfoContent - { - get { throw new NotImplementedException(); } - } - - public bool TrackMouse - { - get { throw new NotImplementedException(); } - } - - public void Collapse() - { - throw new NotImplementedException(); - } - - public void Dismiss() - { - throw new NotImplementedException(); - } - - public Microsoft.VisualStudio.Text.SnapshotPoint? GetTriggerPoint(Microsoft.VisualStudio.Text.ITextSnapshot textSnapshot) - { - throw new NotImplementedException(); - } - - public Microsoft.VisualStudio.Text.ITrackingPoint GetTriggerPoint(Microsoft.VisualStudio.Text.ITextBuffer textBuffer) - { - throw new NotImplementedException(); - } - - public bool IsDismissed - { - get { throw new NotImplementedException(); } - } - - public bool Match() - { - throw new NotImplementedException(); - } - - public IIntellisensePresenter Presenter - { - get { throw new NotImplementedException(); } - } - - public void Recalculate() - { - throw new NotImplementedException(); - } - - public void Start() - { - throw new NotImplementedException(); - } - - public ITextView TextView - { - get { throw new NotImplementedException(); } - } - } - - /// - /// None of the methods need to be implemented. - /// - private class HACK_VsTextTipData : IVsTextTipData - { - public int GetContextStream(out int pos, out int length) - { - throw new NotImplementedException(); - } - - public int GetTipFontInfo(int chars, uint[] pdwFontAttr) - { - throw new NotImplementedException(); - } - - public int GetTipText(string[] pbstrText, out int getFontInfo) - { - throw new NotImplementedException(); - } - - public void OnDismiss() - { - throw new NotImplementedException(); - } - - public void UpdateView() - { - throw new NotImplementedException(); - } - } - } -} diff --git a/src/VisualStudio/CSharp/Impl/EventHookup/EventHookupCommandHandler.cs b/src/VisualStudio/CSharp/Impl/EventHookup/EventHookupCommandHandler.cs index 79176c8776b1a..ff264fccdeaf5 100644 --- a/src/VisualStudio/CSharp/Impl/EventHookup/EventHookupCommandHandler.cs +++ b/src/VisualStudio/CSharp/Impl/EventHookup/EventHookupCommandHandler.cs @@ -1,12 +1,9 @@ // 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; -using System.Collections.Generic; using System.ComponentModel.Composition; using System.Threading; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.Shared.TestHooks; -using Microsoft.VisualStudio.Language.Intellisense; using Microsoft.VisualStudio.Utilities; using VSCommanding = Microsoft.VisualStudio.Commanding; @@ -16,18 +13,18 @@ namespace Microsoft.CodeAnalysis.Editor.CSharp.EventHookup /// Ignores commands until '=' is pressed, at which point we determine if the '=' is part of a /// "+=" that is used to attach an event handler to an event. Once we determine that it is a /// "+=" attaching an event handler to an event, we show a UI that tells the user they can hit - /// tab to generate a handler method. - /// - /// Once we receive the '=' we watch all actions within the buffer. Anything (including use of + /// tab to generate a handler method. + /// + /// Once we receive the '=' we watch all actions within the buffer. Anything (including use of /// directional arrows) other than a typed space removes the UI or cancels any background /// computation. - /// + /// /// The determination of whether the "+=" is being used to attach an event handler to an event /// can be costly, so it operates on a background thread. After the '=' of a "+=" is typed, - /// only a tab will cause the UI thread to block while it determines whether we should - /// intercept the tab and generate an event handler or just let the tab through to other + /// only a tab will cause the UI thread to block while it determines whether we should + /// intercept the tab and generate an event handler or just let the tab through to other /// handlers. - /// + /// /// Because we are explicitly asking the user to tab, so we should handle the tab command before /// Automatic Completion. /// @@ -42,26 +39,19 @@ internal partial class EventHookupCommandHandler : ForegroundThreadAffinitizedOb internal readonly EventHookupSessionManager EventHookupSessionManager; - // This can be null! It is only needed for VS and is thus only exported for VS scenarios. - private readonly IHACK_EventHookupDismissalOnBufferChangePreventerService _prematureDismissalPreventer; - // For testing purposes only! Will always be null except in certain tests. internal Mutex TESTSessionHookupMutex; [ImportingConstructor] public EventHookupCommandHandler( IInlineRenameService inlineRenameService, -#pragma warning disable CS0618 // IQuickInfo* is obsolete, tracked by https://github.com/dotnet/roslyn/issues/24094 - IQuickInfoBroker quickInfoBroker, -#pragma warning restore CS0618 // IQuickInfo* is obsolete, tracked by https://github.com/dotnet/roslyn/issues/24094 - [Import(AllowDefault = true)] IHACK_EventHookupDismissalOnBufferChangePreventerService prematureDismissalPreventer, - IAsynchronousOperationListenerProvider listenerProvider) + IAsynchronousOperationListenerProvider listenerProvider, + EventHookupSessionManager eventHookupSessionManager) { _inlineRenameService = inlineRenameService; - _prematureDismissalPreventer = prematureDismissalPreventer; _asyncListener = listenerProvider.GetListener(FeatureAttribute.EventHookup); - this.EventHookupSessionManager = new EventHookupSessionManager(prematureDismissalPreventer, quickInfoBroker); + this.EventHookupSessionManager = eventHookupSessionManager; } } } diff --git a/src/VisualStudio/CSharp/Impl/EventHookup/EventHookupCommandHandler_ShadowedCommands.cs b/src/VisualStudio/CSharp/Impl/EventHookup/EventHookupCommandHandler_ShadowedCommands.cs deleted file mode 100644 index 491b934746288..0000000000000 --- a/src/VisualStudio/CSharp/Impl/EventHookup/EventHookupCommandHandler_ShadowedCommands.cs +++ /dev/null @@ -1,29 +0,0 @@ -// 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; -using Microsoft.VisualStudio.Commanding; -using Microsoft.VisualStudio.Text.Editor.Commanding.Commands; -using VSCommanding = Microsoft.VisualStudio.Commanding; - -namespace Microsoft.CodeAnalysis.Editor.CSharp.EventHookup -{ - internal partial class EventHookupCommandHandler : VSCommanding.ICommandHandler - { - public bool ExecuteCommand(InvokeCompletionListCommandArgs args, CommandExecutionContext context) - { - AssertIsForeground(); - if (EventHookupSessionManager.QuickInfoSession == null || EventHookupSessionManager.QuickInfoSession.IsDismissed) - { - return false; - } - - return true; - } - - public VSCommanding.CommandState GetCommandState(InvokeCompletionListCommandArgs args) - { - AssertIsForeground(); - return VSCommanding.CommandState.Unspecified; - } - } -} diff --git a/src/VisualStudio/CSharp/Impl/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs b/src/VisualStudio/CSharp/Impl/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs index 0285f62c2be43..46eaccc31e14c 100644 --- a/src/VisualStudio/CSharp/Impl/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs +++ b/src/VisualStudio/CSharp/Impl/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs @@ -95,14 +95,6 @@ private void HandleTabWorker(ITextView textView, ITextBuffer subjectBuffer, Acti return; } - // If QuickInfoSession is null, then Tab was pressed before the background task - // finished (that is, the Wait call above actually needed to wait). Since we know an - // event hookup was found, we should set everything up now because the background task - // will not have a chance to set things up until after this Tab has been handled, and - // by then it's too late. When the background task alerts that it found an event hookup - // nothing will change because QuickInfoSession will already be set. - EventHookupSessionManager.EventHookupFoundInSession(EventHookupSessionManager.CurrentSession); - // This tab means we should generate the event handler method. Begin the code // generation process. GenerateAndAddEventHandler(textView, subjectBuffer, eventHandlerMethodName, nextHandler, cancellationToken); diff --git a/src/VisualStudio/CSharp/Impl/EventHookup/EventHookupQuickInfoSource.cs b/src/VisualStudio/CSharp/Impl/EventHookup/EventHookupQuickInfoSource.cs deleted file mode 100644 index 2947ce96151ba..0000000000000 --- a/src/VisualStudio/CSharp/Impl/EventHookup/EventHookupQuickInfoSource.cs +++ /dev/null @@ -1,105 +0,0 @@ -// 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.Threading; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Documents; -using Microsoft.CodeAnalysis.Editor.Shared.Extensions; -using Microsoft.CodeAnalysis.Editor.Shared.Utilities; -using Microsoft.VisualStudio.Language.Intellisense; -using Microsoft.VisualStudio.Text; -using Microsoft.VisualStudio.Text.Classification; - -#pragma warning disable CS0618 // IQuickInfo* is obsolete, tracked by https://github.com/dotnet/roslyn/issues/24094 -namespace Microsoft.CodeAnalysis.Editor.CSharp.EventHookup -{ - internal sealed class EventHookupQuickInfoSource : IQuickInfoSource - { - private readonly ClassificationTypeMap _classificationTypeMap; - private readonly IClassificationFormatMapService _classificationFormatMapService; - private readonly ITextBuffer _textBuffer; - - public EventHookupQuickInfoSource(ITextBuffer textBuffer, ClassificationTypeMap classificationTypeMap, IClassificationFormatMapService classificationFormatMapService) - { - _textBuffer = textBuffer; - _classificationTypeMap = classificationTypeMap; - _classificationFormatMapService = classificationFormatMapService; - } - - void IQuickInfoSource.AugmentQuickInfoSession(IQuickInfoSession existingQuickInfoSession, IList quickInfoContent, out ITrackingSpan applicableToSpan) - { - // Augmenting quick info isn't cancellable. - var cancellationToken = CancellationToken.None; - - // Ensure this is a quick info session created by event hookup - if (!existingQuickInfoSession.Properties.TryGetProperty(typeof(EventHookupSessionManager), out EventHookupSessionManager eventHookupSessionManager)) - { - applicableToSpan = null; - return; - } - - if (!eventHookupSessionManager.IsTrackingSession()) - { - existingQuickInfoSession.Dismiss(); - applicableToSpan = null; - return; - } - - string eventHandlerName = null; - - // Get the event handler method name. The name was calculated when the quick info - // session was created, so we do not need to wait for the task here. - if (eventHookupSessionManager.CurrentSession.GetEventNameTask.Status == TaskStatus.RanToCompletion) - { - eventHandlerName = eventHookupSessionManager.CurrentSession.GetEventNameTask.Result; - } - - if (eventHandlerName == null) - { - existingQuickInfoSession.Dismiss(); - applicableToSpan = null; - return; - } - - // We should show the quick info session. Calculate the span and create the content. - var currentSnapshot = _textBuffer.CurrentSnapshot; - applicableToSpan = currentSnapshot.CreateTrackingSpan( - start: eventHookupSessionManager.CurrentSession.TrackingPoint.GetPosition(currentSnapshot), - length: 0, - trackingMode: SpanTrackingMode.EdgeInclusive); - - // Clear any existing quick info content. This ensures that the event hookup text is - // the only text in the quick info. - quickInfoContent.Clear(); - - var content = CreateContent(eventHandlerName, _classificationTypeMap); - - quickInfoContent.Add(content); - - // For test purposes only! - eventHookupSessionManager.TEST_MostRecentQuickInfoContent = content; - } - - private FrameworkElement CreateContent(string eventName, ClassificationTypeMap classificationTypeMap) - { - var textBlock = new TextBlock { TextWrapping = TextWrapping.NoWrap }; - textBlock.SetDefaultTextProperties(_classificationFormatMapService.GetClassificationFormatMap("tooltip")); - - var eventNameRun = new Run(eventName + ";"); - eventNameRun.FontWeight = FontWeights.Bold; - textBlock.Inlines.Add(eventNameRun); - - var pressTabRun = new Run(CSharpEditorResources.Press_TAB_to_insert); - textBlock.Inlines.Add(pressTabRun); - - return textBlock; - } - - public void Dispose() - { - } - } -} -#pragma warning restore CS0618 // IQuickInfo* is obsolete, tracked by https://github.com/dotnet/roslyn/issues/24094 diff --git a/src/VisualStudio/CSharp/Impl/EventHookup/EventHookupQuickInfoSourceProvider.cs b/src/VisualStudio/CSharp/Impl/EventHookup/EventHookupQuickInfoSourceProvider.cs deleted file mode 100644 index 9b5acd1e80e5c..0000000000000 --- a/src/VisualStudio/CSharp/Impl/EventHookup/EventHookupQuickInfoSourceProvider.cs +++ /dev/null @@ -1,42 +0,0 @@ -// 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.ComponentModel.Composition; -using Microsoft.CodeAnalysis.Editor.Shared.Utilities; -using Microsoft.VisualStudio.Language.Intellisense; -using Microsoft.VisualStudio.Text; -using Microsoft.VisualStudio.Text.Classification; -using Microsoft.VisualStudio.Utilities; - -#pragma warning disable CS0618 // IQuickInfo* is obsolete, tracked by https://github.com/dotnet/roslyn/issues/24094 -namespace Microsoft.CodeAnalysis.Editor.CSharp.EventHookup -{ - /// - /// Order after "squiggle" so that we have the opportunity to remove any quick info content - /// added due to errors in the code (which happen right after "eventName +=") - /// - [Export(typeof(IQuickInfoSourceProvider))] - [Name(PredefinedQuickInfoProviderNames.EventHookup)] - [Order(After = PredefinedQuickInfoProviderNames.Semantic)] - [Order(After = PredefinedQuickInfoProviderNames.Syntactic)] - [Order(After = "squiggle")] - [ContentType(ContentTypeNames.CSharpContentType)] - internal sealed class EventHookupQuickInfoSourceProvider : IQuickInfoSourceProvider - { - private readonly ClassificationTypeMap _classificationTypeMap; - private readonly IClassificationFormatMapService _classificationFormatMapService; - - [ImportingConstructor] - public EventHookupQuickInfoSourceProvider(ClassificationTypeMap classificationTypeMap, IClassificationFormatMapService classificationFormatMapService) - { - _classificationTypeMap = classificationTypeMap; - _classificationFormatMapService = classificationFormatMapService; - } - - public IQuickInfoSource TryCreateQuickInfoSource(ITextBuffer textBuffer) - { - return textBuffer.Properties.GetOrCreateSingletonProperty( - () => new EventHookupQuickInfoSource(textBuffer, _classificationTypeMap, _classificationFormatMapService)); - } - } -} -#pragma warning restore CS0618 // IQuickInfo* is obsolete, tracked by https://github.com/dotnet/roslyn/issues/24094 diff --git a/src/VisualStudio/CSharp/Impl/EventHookup/EventHookupSessionManager.cs b/src/VisualStudio/CSharp/Impl/EventHookup/EventHookupSessionManager.cs index a8a6d0bda89a6..4d45866d346c1 100644 --- a/src/VisualStudio/CSharp/Impl/EventHookup/EventHookupSessionManager.cs +++ b/src/VisualStudio/CSharp/Impl/EventHookup/EventHookupSessionManager.cs @@ -1,37 +1,36 @@ // 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; +using System.ComponentModel.Composition; +using System.Diagnostics; using System.Linq; using System.Threading; -using System.Windows; +using Microsoft.CodeAnalysis.Classification; using Microsoft.CodeAnalysis.Editor.Shared.Extensions; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; -using Microsoft.CodeAnalysis.QuickInfo; using Microsoft.CodeAnalysis.Shared.TestHooks; -using Microsoft.VisualStudio.Language.Intellisense; using Microsoft.VisualStudio.Text; +using Microsoft.VisualStudio.Text.Adornments; using Microsoft.VisualStudio.Text.Editor; namespace Microsoft.CodeAnalysis.Editor.CSharp.EventHookup { + [Export] internal sealed partial class EventHookupSessionManager : ForegroundThreadAffinitizedObject { - private readonly IHACK_EventHookupDismissalOnBufferChangePreventerService _prematureDismissalPreventer; -#pragma warning disable CS0618 // IQuickInfo* is obsolete, tracked by https://github.com/dotnet/roslyn/issues/24094 - private readonly IQuickInfoBroker _quickInfoBroker; + private readonly IToolTipService _toolTipService; + private IToolTipPresenter _toolTipPresenter; internal EventHookupSession CurrentSession { get; set; } - internal IQuickInfoSession QuickInfoSession { get; set; } // For test purposes only! - internal FrameworkElement TEST_MostRecentQuickInfoContent { get; set; } + internal ClassifiedTextElement[] TEST_MostRecentToolTipContent { get; set; } - internal EventHookupSessionManager(IHACK_EventHookupDismissalOnBufferChangePreventerService prematureDismissalPreventer, IQuickInfoBroker quickInfoBroker) + [ImportingConstructor] + internal EventHookupSessionManager(IToolTipService toolTipService) { - _prematureDismissalPreventer = prematureDismissalPreventer; - _quickInfoBroker = quickInfoBroker; + _toolTipService = toolTipService; } -#pragma warning restore CS0618 // IQuickInfo* is obsolete, tracked by https://github.com/dotnet/roslyn/issues/24094 internal void EventHookupFoundInSession(EventHookupSession analyzedSession) { @@ -39,39 +38,36 @@ internal void EventHookupFoundInSession(EventHookupSession analyzedSession) var caretPoint = analyzedSession.TextView.GetCaretPoint(analyzedSession.SubjectBuffer); + // only generate tooltip if it is not already shown (_toolTipPresenter == null) // Ensure the analyzed session matches the current session and that the caret is still // in the session's tracking span. - if (CurrentSession == analyzedSession && - QuickInfoSession == null && + if (_toolTipPresenter == null && + CurrentSession == analyzedSession && caretPoint.HasValue && analyzedSession.TrackingSpan.GetSpan(CurrentSession.TextView.TextSnapshot).Contains(caretPoint.Value)) { - QuickInfoSession = _quickInfoBroker.CreateQuickInfoSession(analyzedSession.TextView, - analyzedSession.TrackingPoint, - trackMouse: false); + // Create a tooltip presenter that stays alive, even when the user types, without tracking the mouse. + _toolTipPresenter = this._toolTipService.CreatePresenter(analyzedSession.TextView, + new ToolTipParameters(trackMouse: false, ignoreBufferChange: true)); - // Special indicator that this quick info session was created by event hookup, - // which is used when deciding whether and how to display the session - QuickInfoSession.Properties.AddProperty(typeof(EventHookupSessionManager), this); - QuickInfoSession.Properties.AddProperty(QuickInfoUtilities.EventHookupKey, "EventHookup"); + // tooltips text is: Program_MyEvents; (Press TAB to insert) + // GetEventNameTask() gets back the event name, only needs to add a semicolon after it. + var eventText = analyzedSession.GetEventNameTask.Result + ";"; + var texts = new[] { eventText, CSharpEditorResources.Press_TAB_to_insert }; + var textRuns = texts.Select(s => new ClassifiedTextRun(ClassificationTypeNames.Text, s)); + var content = new[] { new ClassifiedTextElement(textRuns) }; - // Watch all text buffer changes & caret moves while this quick info session is - // active + _toolTipPresenter.StartOrUpdate(analyzedSession.TrackingSpan, content); + + // For test purposes only! + TEST_MostRecentToolTipContent = content; + + // Watch all text buffer changes & caret moves while this event hookup session is active analyzedSession.TextView.TextSnapshot.TextBuffer.Changed += TextBuffer_Changed; CurrentSession.Dismissed += () => { analyzedSession.TextView.TextSnapshot.TextBuffer.Changed -= TextBuffer_Changed; }; analyzedSession.TextView.Caret.PositionChanged += Caret_PositionChanged; CurrentSession.Dismissed += () => { analyzedSession.TextView.Caret.PositionChanged -= Caret_PositionChanged; }; - - QuickInfoSession.Start(); - - // HACK! Workaround for VS dismissing quick info sessions on buffer changed events. - // This must happen after the QuickInfoSession is started. - if (_prematureDismissalPreventer != null) - { - _prematureDismissalPreventer.HACK_EnsureQuickInfoSessionNotDismissedPrematurely(analyzedSession.TextView); - QuickInfoSession.Dismissed += (s, e) => { _prematureDismissalPreventer.HACK_OnQuickInfoSessionDismissed(analyzedSession.TextView); }; - } } } @@ -95,12 +91,14 @@ internal void CancelAndDismissExistingSessions() CurrentSession = null; } - if (QuickInfoSession != null) + if (_toolTipPresenter != null) { - QuickInfoSession.Dismiss(); - QuickInfoSession = null; - TEST_MostRecentQuickInfoContent = null; + _toolTipPresenter.Dismiss(); + _toolTipPresenter = null; } + + // For test purposes only! + TEST_MostRecentToolTipContent = null; } /// @@ -149,7 +147,7 @@ private void Caret_PositionChanged(object sender, EventArgs e) internal bool IsTrackingSession() { - return CurrentSession != null && QuickInfoSession != null; + return CurrentSession != null; } } } diff --git a/src/VisualStudio/CSharp/Impl/EventHookup/IHACK_EventHookupDismissalOnBufferChangePreventerService.cs b/src/VisualStudio/CSharp/Impl/EventHookup/IHACK_EventHookupDismissalOnBufferChangePreventerService.cs deleted file mode 100644 index 14310e4b79969..0000000000000 --- a/src/VisualStudio/CSharp/Impl/EventHookup/IHACK_EventHookupDismissalOnBufferChangePreventerService.cs +++ /dev/null @@ -1,12 +0,0 @@ -// 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 Microsoft.VisualStudio.Text.Editor; - -namespace Microsoft.CodeAnalysis.Editor.CSharp.EventHookup -{ - internal interface IHACK_EventHookupDismissalOnBufferChangePreventerService - { - void HACK_EnsureQuickInfoSessionNotDismissedPrematurely(ITextView textView); - void HACK_OnQuickInfoSessionDismissed(ITextView textView); - } -} diff --git a/src/VisualStudio/CSharp/Test/EventHookup/EventHookupTestState.cs b/src/VisualStudio/CSharp/Test/EventHookup/EventHookupTestState.cs index df58c0510f207..dec77f8560b1d 100644 --- a/src/VisualStudio/CSharp/Test/EventHookup/EventHookupTestState.cs +++ b/src/VisualStudio/CSharp/Test/EventHookup/EventHookupTestState.cs @@ -1,6 +1,5 @@ // 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; using System.Collections.Generic; using System.Linq; using System.Threading; @@ -12,7 +11,6 @@ using Microsoft.CodeAnalysis.Shared.TestHooks; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.VisualStudio.Composition; -using Microsoft.VisualStudio.Language.Intellisense; using Roslyn.Utilities; using Xunit; @@ -26,10 +24,9 @@ internal sealed class EventHookupTestState : AbstractCommandHandlerTestState public EventHookupTestState(XElement workspaceElement, IDictionary options) : base(workspaceElement, GetExtraParts(), false) { -#pragma warning disable CS0618 // IQuickInfo* is obsolete, tracked by https://github.com/dotnet/roslyn/issues/24094 - _commandHandler = new EventHookupCommandHandler(Workspace.GetService(), Workspace.GetService(), - prematureDismissalPreventer: null, Workspace.ExportProvider.GetExportedValue()); -#pragma warning restore CS0618 // IQuickInfo* is obsolete, tracked by https://github.com/dotnet/roslyn/issues/24094 + _commandHandler = new EventHookupCommandHandler(Workspace.GetService(), + Workspace.ExportProvider.GetExportedValue(), + Workspace.ExportProvider.GetExportedValue()); _testSessionHookupMutex = new Mutex(false); _commandHandler.TESTSessionHookupMutex = _testSessionHookupMutex; @@ -38,7 +35,7 @@ public EventHookupTestState(XElement workspaceElement, IDictionary options = null) @@ -55,18 +52,17 @@ public static EventHookupTestState CreateTestState(string markup, IDictionary tags, out ImageMoniker ima private ImageMoniker GetImageMoniker(ImmutableArray tags) { - var glyph = tags.GetGlyph(); + var glyph = tags.GetFirstGlyph(); switch (glyph) { case Glyph.AddReference: diff --git a/src/VisualStudio/Core/Test/DebuggerIntelliSense/TestState.vb b/src/VisualStudio/Core/Test/DebuggerIntelliSense/TestState.vb index 4c885744366db..3361d1bdb3955 100644 --- a/src/VisualStudio/Core/Test/DebuggerIntelliSense/TestState.vb +++ b/src/VisualStudio/Core/Test/DebuggerIntelliSense/TestState.vb @@ -77,7 +77,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.DebuggerIntelliSense GetExports(Of ISignatureHelpProvider, OrderableLanguageMetadata)().Concat(extraSignatureHelpProviders), GetExportedValue(Of IAsynchronousOperationListenerProvider)()) - Me.IntelliSenseCommandHandler = New IntelliSenseCommandHandler(CompletionCommandHandler, SignatureHelpCommandHandler, Nothing) + Me.IntelliSenseCommandHandler = New IntelliSenseCommandHandler(CompletionCommandHandler, SignatureHelpCommandHandler) Dim spanDocument = Workspace.Documents.First(Function(x) x.SelectedSpans.Any()) Dim statementSpan = spanDocument.SelectedSpans.First() diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/QuickInfoToStringConverter.cs b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/QuickInfoToStringConverter.cs index f31f0fe627264..8576aa2ae5a3f 100644 --- a/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/QuickInfoToStringConverter.cs +++ b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/QuickInfoToStringConverter.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Controls; @@ -10,7 +11,7 @@ namespace Microsoft.VisualStudio.IntegrationTest.Utilities.InProcess { public static class QuickInfoToStringConverter { - public static string GetStringFromBulkContent(BulkObservableCollection content) + public static string GetStringFromBulkContent(IEnumerable content) { return string.Join(Environment.NewLine, content.Select(item => GetStringFromItem(item) ?? string.Empty)); } diff --git a/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/TextViewWindow_InProc.cs b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/TextViewWindow_InProc.cs index d688d87c8d0d9..d8d7e81cc4ce0 100644 --- a/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/TextViewWindow_InProc.cs +++ b/src/VisualStudio/IntegrationTest/TestUtilities/InProcess/TextViewWindow_InProc.cs @@ -230,17 +230,10 @@ protected Action GetExecuteOnActionViewCallback(Action action) public string GetQuickInfo() => ExecuteOnActiveView(view => { -#pragma warning disable CS0618 // IQuickInfo* is obsolete, tracked by https://github.com/dotnet/roslyn/issues/24094 - var broker = GetComponentModelService(); -#pragma warning restore CS0618 // IQuickInfo* is obsolete, tracked by https://github.com/dotnet/roslyn/issues/24094 + var broker = GetComponentModelService(); - var sessions = broker.GetSessions(view); - if (sessions.Count != 1) - { - throw new InvalidOperationException($"Expected exactly one QuickInfo session, but found {sessions.Count}"); - } - - return QuickInfoToStringConverter.GetStringFromBulkContent(sessions[0].QuickInfoContent); + var session = broker.GetSession(view); + return QuickInfoToStringConverter.GetStringFromBulkContent(session.Content); }); public void VerifyTags(string tagTypeName, int expectedCount) diff --git a/src/Workspaces/Core/Portable/Log/FunctionId.cs b/src/Workspaces/Core/Portable/Log/FunctionId.cs index e3ddc164c33c8..8e859bb5c0e77 100644 --- a/src/Workspaces/Core/Portable/Log/FunctionId.cs +++ b/src/Workspaces/Core/Portable/Log/FunctionId.cs @@ -147,7 +147,7 @@ internal enum FunctionId TPLTask_TaskStarted, TPLTask_TaskCompleted, - QuickInfo_ModelComputation_ComputeModelInBackground, + Get_QuickInfo_Async, Completion_ModelComputer_DoInBackground, Completion_ModelComputation_FilterModelInBackground, diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/TextLineExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/TextLineExtensions.cs index 4efd7797ecd9a..12e0ec4a70068 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/TextLineExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/TextLineExtensions.cs @@ -55,7 +55,16 @@ public static string GetLeadingWhitespace(this TextLine line) /// public static bool IsEmptyOrWhitespace(this TextLine line) { - return string.IsNullOrWhiteSpace(line.ToString()); + var text = line.Text; + for (var i = line.Span.Start; i < line.Span.End; i++) + { + if (!char.IsWhiteSpace(text[i])) + { + return false; + } + } + + return true; } public static int GetColumnOfFirstNonWhitespaceCharacterOrEndOfLine(this TextLine line, int tabSize)