diff --git a/vsintegration/packages.config b/vsintegration/packages.config
index 5b5d870661f..17f244f2504 100644
--- a/vsintegration/packages.config
+++ b/vsintegration/packages.config
@@ -18,6 +18,7 @@
+
diff --git a/vsintegration/src/FSharp.Editor/Common/CommonHelpers.fs b/vsintegration/src/FSharp.Editor/Common/CommonHelpers.fs
index 4bed68c1602..0ccc490d05f 100644
--- a/vsintegration/src/FSharp.Editor/Common/CommonHelpers.fs
+++ b/vsintegration/src/FSharp.Editor/Common/CommonHelpers.fs
@@ -372,3 +372,92 @@ module internal Extensions =
let! result = input
return f result
}
+
+[]
+module internal TypedAstExtensionHelpers =
+ type FSharpEntity with
+ member this.TryGetFullName() =
+ match (try this.TryFullName with _ -> None) with
+ | Some x -> Some x
+ | None ->
+ try Some (String.Join(".", this.AccessPath, this.DisplayName))
+ with _ -> None
+
+ type FSharpMemberOrFunctionOrValue with
+ // FullType may raise exceptions (see https://github.com/fsharp/fsharp/issues/307).
+ member x.FullTypeSafe = try Some x.FullType with _ -> None
+
+ let (|Public|Internal|Protected|Private|) (a: FSharpAccessibility) =
+ if a.IsPublic then Public
+ elif a.IsInternal then Internal
+ elif a.IsPrivate then Private
+ else Protected
+
+module internal Glyph =
+ let forSymbol (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
diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj
index e39dd58aa40..ec45b88d2e7 100644
--- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj
+++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj
@@ -1,4 +1,4 @@
-
+
@@ -18,7 +18,8 @@
LIBRARY
v4.6
$(NoWarn);75
- false $(OtherFlags) --warnon:1182 --subsystemversion:6.00
+ false
+ $(OtherFlags) --warnon:1182 --subsystemversion:6.00
true
false
false
@@ -85,6 +86,9 @@
+
+
+
@@ -115,6 +119,9 @@
$(FSharpSourcesRoot)\..\packages\Microsoft.VisualStudio.CoreUtility.$(RoslynVSPackagesVersion)\lib\net45\Microsoft.VisualStudio.CoreUtility.dll
+
+ $(FSharpSourcesRoot)\..\packages\Microsoft.VisualStudio.Imaging.$(RoslynVSPackagesVersion)\lib\net45\Microsoft.VisualStudio.Imaging.dll
+
$(FSharpSourcesRoot)\..\packages\Microsoft.VisualStudio.Utilities.$(RoslynVSPackagesVersion)\lib\net45\Microsoft.VisualStudio.Utilities.dll
diff --git a/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs b/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs
index 5abd076bd06..4bdd261d0d9 100644
--- a/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs
+++ b/vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs
@@ -25,7 +25,9 @@ open Microsoft.CodeAnalysis.Formatting
open Microsoft.CodeAnalysis.Host.Mef
open Microsoft.CodeAnalysis.Options
open Microsoft.CodeAnalysis.Text
+open Microsoft.CodeAnalysis.Editor.Shared.Extensions
+open Microsoft.VisualStudio.Language.Intellisense
open Microsoft.VisualStudio.FSharp.LanguageService
open Microsoft.VisualStudio.Text
open Microsoft.VisualStudio.Text.Classification
@@ -33,20 +35,48 @@ open Microsoft.VisualStudio.Text.Tagging
open Microsoft.VisualStudio.Text.Formatting
open Microsoft.VisualStudio.Shell
open Microsoft.VisualStudio.Shell.Interop
+open Microsoft.VisualStudio.Imaging
+open Microsoft.VisualStudio.Imaging.Interop
+open Microsoft.VisualStudio.PlatformUI
open Microsoft.FSharp.Compiler
open Microsoft.FSharp.Compiler.Parser
open Microsoft.FSharp.Compiler.Range
open Microsoft.FSharp.Compiler.SourceCodeServices
+
open System.Windows.Documents
+open System.Windows.Controls
+open System.Windows.Data
+open System.Windows.Media
// 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) =
+type internal FSharpDeferredQuickInfoContent(content: string, textProperties: TextFormattingRunProperties, glyph: Glyph) =
interface IDeferredQuickInfoContent with
override this.Create() : FrameworkElement =
+ let moniker = GlyphExtensions.GetImageMoniker(glyph)
+ let image = new CrispImage()
+ image.Moniker <- (box moniker) :?> _
+
+ // Inform the ImageService of the background color so that images have the correct background.
+ let binding =
+ Binding(
+ "Background",
+ Converter = new BrushToColorConverter(),
+ RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof, 1))
+
+ image.SetBinding(ImageThemingUtilities.ImageBackgroundColorProperty, binding) |> ignore
+
+ image.Margin <- new Thickness(1., 1., 3., 1.)
+ let symbolGlyphBorder =
+ new Border(
+ BorderThickness = new Thickness(0.),
+ BorderBrush = Brushes.Transparent,
+ VerticalAlignment = VerticalAlignment.Top,
+ Child = image)
+
let textBlock = TextBlock(Run(content), TextWrapping = TextWrapping.Wrap, TextTrimming = TextTrimming.None)
textBlock.SetValue(TextElement.BackgroundProperty, textProperties.BackgroundBrush)
textBlock.SetValue(TextElement.ForegroundProperty, textProperties.ForegroundBrush)
@@ -54,7 +84,19 @@ type internal FSharpDeferredQuickInfoContent(content: string, textProperties: Te
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
+
+ let symbolGlyphAndMainDescriptionDock =
+ new DockPanel(
+ LastChildFill = true,
+ HorizontalAlignment = HorizontalAlignment.Stretch,
+ Background = Brushes.Transparent)
+
+ symbolGlyphAndMainDescriptionDock.Children.Add(symbolGlyphBorder) |> ignore
+ symbolGlyphAndMainDescriptionDock.Children.Add(textBlock) |> ignore
+
+ let panel = StackPanel(Orientation = Orientation.Vertical)
+ panel.Children.Add(symbolGlyphAndMainDescriptionDock) |> ignore
+ upcast panel
[]
[]
@@ -70,7 +112,8 @@ type internal FSharpQuickInfoProvider
let xmlMemberIndexService = serviceProvider.GetService(typeof) :?> IVsXMLMemberIndexService
let documentationBuilder = XmlDocumentation.CreateDocumentationBuilder(xmlMemberIndexService, serviceProvider.DTE)
- static member ProvideQuickInfo(checker: FSharpChecker, documentId: DocumentId, sourceText: SourceText, filePath: string, position: int, options: FSharpProjectOptions, textVersionHash: int, cancellationToken: CancellationToken) =
+ static member ProvideQuickInfo(checker: FSharpChecker, documentId: DocumentId, sourceText: SourceText, filePath: string, position: int,
+ options: FSharpProjectOptions, textVersionHash: int, cancellationToken: CancellationToken) =
async {
let! _parseResults, checkResultsAnswer = checker.ParseAndCheckFileInProject(filePath, textVersionHash, sourceText.ToString(), options)
let checkFileResults =
@@ -84,6 +127,7 @@ type internal FSharpQuickInfoProvider
let textLineColumn = textLinePos.Character
//let qualifyingNames, partialName = QuickParse.GetPartialLongNameEx(textLine.ToString(), textLineColumn - 1)
let defines = CompilerEnvironment.GetCompilationDefinesForEditing(filePath, options.OtherOptions |> Seq.toList)
+
let tryClassifyAtPosition position =
CommonHelpers.tryClassifyAtPosition(documentId, sourceText, filePath, defines, position, SymbolSearchKind.DoesNotIncludeRightColumn, cancellationToken)
@@ -95,10 +139,14 @@ type internal FSharpQuickInfoProvider
match quickParseInfo with
| Some (islandColumn, qualifiers, textSpan) ->
let! res = checkFileResults.GetToolTipTextAlternate(textLineNumber, islandColumn, textLine.ToString(), qualifiers, FSharpTokenTag.IDENT)
- return
- match res with
- | FSharpToolTipText [] -> None
- | _ -> Some(res, textSpan)
+ match res with
+ | FSharpToolTipText [] -> return None
+ | _ ->
+ let! symbolUse = checkFileResults.GetSymbolUseAtLocation(textLineNumber, islandColumn, textLine.ToString(), qualifiers)
+ match symbolUse with
+ | Some symbolUse ->
+ return Some(res, textSpan, symbolUse.Symbol)
+ | None -> return None
| None -> return None
}
@@ -117,10 +165,10 @@ type internal FSharpQuickInfoProvider
let! textVersion = document.GetTextVersionAsync(cancellationToken) |> Async.AwaitTask
let! quickInfoResult = FSharpQuickInfoProvider.ProvideQuickInfo(checkerProvider.Checker, document.Id, sourceText, document.FilePath, position, options, textVersion.GetHashCode(), cancellationToken)
match quickInfoResult with
- | Some(toolTipElement, textSpan) ->
+ | Some(toolTipElement, textSpan, symbol) ->
let dataTipText = XmlDocumentation.BuildDataTipText(documentationBuilder, toolTipElement)
let textProperties = classificationFormatMapService.GetClassificationFormatMap("tooltip").DefaultTextProperties
- return QuickInfoItem(textSpan, FSharpDeferredQuickInfoContent(dataTipText, textProperties))
+ return QuickInfoItem(textSpan, FSharpDeferredQuickInfoContent(dataTipText, textProperties, Glyph.forSymbol symbol))
| None -> return null
| None -> return null
| None -> return null
diff --git a/vsintegration/src/FSharp.LanguageService.Base/FSharp.LanguageService.Base.csproj b/vsintegration/src/FSharp.LanguageService.Base/FSharp.LanguageService.Base.csproj
index 3cdd734ab5e..32dae6d49b4 100644
--- a/vsintegration/src/FSharp.LanguageService.Base/FSharp.LanguageService.Base.csproj
+++ b/vsintegration/src/FSharp.LanguageService.Base/FSharp.LanguageService.Base.csproj
@@ -124,6 +124,9 @@
$(FSharpSourcesRoot)\..\packages\Roslyn.Microsoft.VisualStudio.ComponentModelHost.0.0.2\lib\net46\Microsoft.VisualStudio.ComponentModelHost.dll
+
+ $(FSharpSourcesRoot)\..\packages\Microsoft.VisualStudio.Imaging.$(RoslynVSPackagesVersion)\lib\net45\Microsoft.VisualStudio.Imaging.dll
+
{DED3BBD7-53F4-428A-8C9F-27968E768605}
FSharp.Core
diff --git a/vsintegration/src/FSharp.LanguageService/FSharp.LanguageService.fsproj b/vsintegration/src/FSharp.LanguageService/FSharp.LanguageService.fsproj
index 54af1207843..fdbee63438b 100644
--- a/vsintegration/src/FSharp.LanguageService/FSharp.LanguageService.fsproj
+++ b/vsintegration/src/FSharp.LanguageService/FSharp.LanguageService.fsproj
@@ -138,6 +138,9 @@
$(FSharpSourcesRoot)\..\packages\Microsoft.VisualFSharp.Microsoft.VisualStudio.Shell.UI.Internal.14.0.25420\lib\net45\Microsoft.VisualStudio.Shell.UI.Internal.dll
+
+ $(FSharpSourcesRoot)\..\packages\Microsoft.VisualStudio.Imaging.$(RoslynVSPackagesVersion)\lib\net45\Microsoft.VisualStudio.Imaging.dll
+
{DED3BBD7-53F4-428A-8C9F-27968E768605}
diff --git a/vsintegration/tests/Salsa/VisualFSharp.Salsa.fsproj b/vsintegration/tests/Salsa/VisualFSharp.Salsa.fsproj
index 57291e05efe..dd5a33d1512 100644
--- a/vsintegration/tests/Salsa/VisualFSharp.Salsa.fsproj
+++ b/vsintegration/tests/Salsa/VisualFSharp.Salsa.fsproj
@@ -101,6 +101,9 @@
$(FSharpSourcesRoot)\..\packages\Microsoft.VisualStudio.Shell.$(RoslynVSBinariesVersion).$(RoslynVSPackagesVersion)\lib\Microsoft.VisualStudio.Shell.$(RoslynVSBinariesVersion).dll
True
+
+ $(FSharpSourcesRoot)\..\packages\Microsoft.VisualStudio.Imaging.$(RoslynVSPackagesVersion)\lib\net45\Microsoft.VisualStudio.Imaging.dll
+
True
$(NUnitLibDir)\nunit.framework.dll
diff --git a/vsintegration/tests/unittests/QuickInfoProviderTests.fs b/vsintegration/tests/unittests/QuickInfoProviderTests.fs
index d6157fc8317..c57093a5055 100644
--- a/vsintegration/tests/unittests/QuickInfoProviderTests.fs
+++ b/vsintegration/tests/unittests/QuickInfoProviderTests.fs
@@ -100,5 +100,5 @@ Full name: System.Console"
FSharpQuickInfoProvider.ProvideQuickInfo(FSharpChecker.Instance, documentId, SourceText.From(fileContents), filePath, caretPosition, options, 0, CancellationToken.None)
|> 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
diff --git a/vsintegration/tests/unittests/VisualFSharp.Unittests.fsproj b/vsintegration/tests/unittests/VisualFSharp.Unittests.fsproj
index 6f59277cbb1..2b7968ff7f0 100644
--- a/vsintegration/tests/unittests/VisualFSharp.Unittests.fsproj
+++ b/vsintegration/tests/unittests/VisualFSharp.Unittests.fsproj
@@ -207,6 +207,9 @@
$(FSharpSourcesRoot)\..\packages\Microsoft.VisualStudio.Editor.$(RoslynVSPackagesVersion)\lib\net45\Microsoft.VisualStudio.Editor.dll
True
+
+ $(FSharpSourcesRoot)\..\packages\Microsoft.VisualStudio.Imaging.$(RoslynVSPackagesVersion)\lib\net45\Microsoft.VisualStudio.Imaging.dll
+