diff --git a/vsintegration/src/FSharp.Editor/Common/CommonRoslynHelpers.fs b/vsintegration/src/FSharp.Editor/Common/CommonRoslynHelpers.fs index 3f64bf1ea75..e4f88c5f70e 100644 --- a/vsintegration/src/FSharp.Editor/Common/CommonRoslynHelpers.fs +++ b/vsintegration/src/FSharp.Editor/Common/CommonRoslynHelpers.fs @@ -127,6 +127,80 @@ module internal CommonRoslynHelpers = | GlyphMajor.Error -> Glyph.Error | _ -> Glyph.ClassPublic + let inline (|Public|Internal|Protected|Private|) (a: FSharpAccessibility) = + if a.IsPublic then Public + elif a.IsInternal then Internal + elif a.IsPrivate then Private + else Protected + + let GetGlyphForSymbol (symbol: FSharpSymbol) = + match symbol with + | :? FSharpUnionCase as x -> + match x.Accessibility with + | Public -> Glyph.EnumPublic + | Internal -> Glyph.EnumInternal + | Protected -> Glyph.EnumProtected + | Private -> Glyph.EnumPrivate + | :? FSharpActivePatternCase -> Glyph.EnumPublic + | :? FSharpField as x -> + match x.Accessibility with + | Public -> Glyph.FieldPublic + | Internal -> Glyph.FieldInternal + | Protected -> Glyph.FieldProtected + | Private -> Glyph.FieldPrivate + | :? FSharpParameter -> Glyph.Parameter + | :? FSharpMemberOrFunctionOrValue as x -> + if x.IsExtensionMember then + match x.Accessibility with + | Public -> Glyph.ExtensionMethodPublic + | Internal -> Glyph.ExtensionMethodInternal + | Protected -> Glyph.ExtensionMethodProtected + | Private -> Glyph.ExtensionMethodPrivate + elif x.IsProperty || x.IsPropertyGetterMethod || x.IsPropertySetterMethod then + match x.Accessibility with + | Public -> Glyph.PropertyPublic + | Internal -> Glyph.PropertyInternal + | Protected -> Glyph.PropertyProtected + | Private -> Glyph.PropertyPrivate + elif x.IsEvent then + match x.Accessibility with + | Public -> Glyph.EventPublic + | Internal -> Glyph.EventInternal + | Protected -> Glyph.EventProtected + | Private -> Glyph.EventPrivate + else + match x.Accessibility with + | Public -> Glyph.MethodPublic + | Internal -> Glyph.MethodInternal + | Protected -> Glyph.MethodProtected + | Private -> Glyph.MethodPrivate + | :? FSharpEntity as x -> + if x.IsFSharpModule then + match x.Accessibility with + | Public -> Glyph.ModulePublic + | Internal -> Glyph.ModuleInternal + | Protected -> Glyph.ModuleProtected + | Private -> Glyph.ModulePrivate + elif x.IsEnum || x.IsFSharpUnion then + match x.Accessibility with + | Public -> Glyph.EnumPublic + | Internal -> Glyph.EnumInternal + | Protected -> Glyph.EnumProtected + | Private -> Glyph.EnumPrivate + elif x.IsInterface then + match x.Accessibility with + | Public -> Glyph.InterfacePublic + | Internal -> Glyph.InterfaceInternal + | Protected -> Glyph.InterfaceProtected + | Private -> Glyph.InterfacePrivate + else + match x.Accessibility with + | Public -> Glyph.ClassPublic + | Internal -> Glyph.ClassInternal + | Protected -> Glyph.ClassProtected + | Private -> Glyph.ClassPrivate + | _ -> Glyph.None + [] module internal RoslynExtensions = type Project with diff --git a/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs b/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs index 20420d7345a..7683bfd47fe 100644 --- a/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs +++ b/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs @@ -4,57 +4,22 @@ namespace Microsoft.VisualStudio.FSharp.Editor open System open System.Composition -open System.Collections.Concurrent -open System.Collections.Generic -open System.Collections.Immutable open System.Threading open System.Threading.Tasks -open System.Linq -open System.Runtime.CompilerServices -open System.Windows -open System.Windows.Controls -open System.Windows.Media open Microsoft.CodeAnalysis -open Microsoft.CodeAnalysis.Completion open Microsoft.CodeAnalysis.Classification open Microsoft.CodeAnalysis.Editor open Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.QuickInfo -open Microsoft.CodeAnalysis.Editor.Shared.Utilities -open Microsoft.CodeAnalysis.Formatting open Microsoft.CodeAnalysis.Host.Mef -open Microsoft.CodeAnalysis.Options open Microsoft.CodeAnalysis.Text open Microsoft.VisualStudio.FSharp.LanguageService -open Microsoft.VisualStudio.Text -open Microsoft.VisualStudio.Text.Classification -open Microsoft.VisualStudio.Text.Tagging -open Microsoft.VisualStudio.Text.Formatting open Microsoft.VisualStudio.Shell open Microsoft.VisualStudio.Shell.Interop +open Microsoft.VisualStudio.Language.Intellisense -open Microsoft.FSharp.Compiler -open Microsoft.FSharp.Compiler.Parser -open Microsoft.FSharp.Compiler.Range open Microsoft.FSharp.Compiler.SourceCodeServices -open System.Windows.Documents - -// FSROSLYNTODO: with the merge of the below PR, the QuickInfo API should be changed -// to allow for a more flexible syntax for defining the content of the tooltip. -// The below interface should be discarded then or updated accourdingly. -// https://github.com/dotnet/roslyn/pull/13623 -type internal FSharpDeferredQuickInfoContent(content: string, textProperties: TextFormattingRunProperties) = - interface IDeferredQuickInfoContent with - override this.Create() : FrameworkElement = - let textBlock = TextBlock(Run(content), TextWrapping = TextWrapping.Wrap, TextTrimming = TextTrimming.None) - textBlock.SetValue(TextElement.BackgroundProperty, textProperties.BackgroundBrush) - textBlock.SetValue(TextElement.ForegroundProperty, textProperties.ForegroundBrush) - textBlock.SetValue(TextElement.FontFamilyProperty, textProperties.Typeface.FontFamily) - textBlock.SetValue(TextElement.FontSizeProperty, textProperties.FontRenderingEmSize) - textBlock.SetValue(TextElement.FontStyleProperty, if textProperties.Italic then FontStyles.Italic else FontStyles.Normal) - textBlock.SetValue(TextElement.FontWeightProperty, if textProperties.Bold then FontWeights.Bold else FontWeights.Normal) - upcast textBlock [] [] @@ -62,10 +27,10 @@ type internal FSharpQuickInfoProvider [] ( [)>] serviceProvider: IServiceProvider, - _classificationFormatMapService: IClassificationFormatMapService, checkerProvider: FSharpCheckerProvider, projectInfoManager: ProjectInfoManager, - typeMap: Shared.Utilities.ClassificationTypeMap + typeMap: Shared.Utilities.ClassificationTypeMap, + glyphService: IGlyphService ) = let xmlMemberIndexService = serviceProvider.GetService(typeof) :?> IVsXMLMemberIndexService @@ -76,15 +41,15 @@ type internal FSharpQuickInfoProvider let! _, checkFileResults = checker.ParseAndCheckDocument(filePath, textVersionHash, sourceText.ToString(), options) let textLine = sourceText.Lines.GetLineFromPosition(position) let textLineNumber = textLine.LineNumber + 1 // Roslyn line numbers are zero-based - //let qualifyingNames, partialName = QuickParse.GetPartialLongNameEx(textLine.ToString(), textLineColumn - 1) let defines = CompilerEnvironment.GetCompilationDefinesForEditing(filePath, options.OtherOptions |> Seq.toList) let! symbol = CommonHelpers.getSymbolAtPosition(documentId, sourceText, position, filePath, defines, SymbolLookupKind.Fuzzy) let! res = checkFileResults.GetStructuredToolTipTextAlternate(textLineNumber, symbol.RightColumn, textLine.ToString(), [symbol.Text], FSharpTokenTag.IDENT) |> liftAsync - return! - match res with - | FSharpToolTipText [] - | FSharpToolTipText [FSharpStructuredToolTipElement.None] -> None - | _ -> Some(res, CommonRoslynHelpers.FSharpRangeToTextSpan(sourceText, symbol.Range)) + match res with + | FSharpToolTipText [] + | FSharpToolTipText [FSharpStructuredToolTipElement.None] -> return! None + | _ -> + let! symbolUse = checkFileResults.GetSymbolUseAtLocation(textLineNumber, symbol.RightColumn, textLine.ToString(), [symbol.Text]) + return! Some(res, CommonRoslynHelpers.FSharpRangeToTextSpan(sourceText, symbol.Range), symbolUse.Symbol) } interface IQuickInfoProvider with @@ -95,7 +60,8 @@ type internal FSharpQuickInfoProvider let! _ = CommonHelpers.getSymbolAtPosition(document.Id, sourceText, position, document.FilePath, defines, SymbolLookupKind.Fuzzy) let! options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document) let! textVersion = document.GetTextVersionAsync(cancellationToken) - let! toolTipElement, textSpan = FSharpQuickInfoProvider.ProvideQuickInfo(checkerProvider.Checker, document.Id, sourceText, document.FilePath, position, options, textVersion.GetHashCode()) + let! toolTipElement, textSpan, symbol = + FSharpQuickInfoProvider.ProvideQuickInfo(checkerProvider.Checker, document.Id, sourceText, document.FilePath, position, options, textVersion.GetHashCode()) let mainDescription = Collections.Generic.List() let documentation = Collections.Generic.List() XmlDocumentation.BuildDataTipText( @@ -107,7 +73,7 @@ type internal FSharpQuickInfoProvider let content = QuickInfoDisplayDeferredContent ( - symbolGlyph = null,//SymbolGlyphDeferredContent(), + symbolGlyph = SymbolGlyphDeferredContent(CommonRoslynHelpers.GetGlyphForSymbol(symbol), glyphService), warningGlyph = null, mainDescription = ClassifiableDeferredContent(mainDescription, typeMap), documentation = ClassifiableDeferredContent(documentation, typeMap), diff --git a/vsintegration/tests/unittests/QuickInfoProviderTests.fs b/vsintegration/tests/unittests/QuickInfoProviderTests.fs index 108e7ad6c1a..3b2d3b9a736 100644 --- a/vsintegration/tests/unittests/QuickInfoProviderTests.fs +++ b/vsintegration/tests/unittests/QuickInfoProviderTests.fs @@ -101,5 +101,5 @@ Full name: System.Console" FSharpQuickInfoProvider.ProvideQuickInfo(FSharpChecker.Instance, documentId, SourceText.From(fileContents), filePath, caretPosition, options, 0) |> Async.RunSynchronously - let actual = quickInfo |> Option.map (fun (text, _) -> getQuickInfoText text) + let actual = quickInfo |> Option.map (fun (text, _, _) -> getQuickInfoText text) Assert.AreEqual(expected, actual) \ No newline at end of file