Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions vsintegration/src/FSharp.Editor/Common/CommonRoslynHelpers.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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

[<AutoOpen>]
module internal RoslynExtensions =
type Project with
Expand Down
58 changes: 12 additions & 46 deletions vsintegration/src/FSharp.Editor/QuickInfo/QuickInfoProvider.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4,68 +4,33 @@ 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

[<Shared>]
[<ExportQuickInfoProvider(PredefinedQuickInfoProviderNames.Semantic, FSharpCommonConstants.FSharpLanguageName)>]
type internal FSharpQuickInfoProvider
[<System.ComponentModel.Composition.ImportingConstructor>]
(
[<System.ComponentModel.Composition.Import(typeof<SVsServiceProvider>)>] serviceProvider: IServiceProvider,
_classificationFormatMapService: IClassificationFormatMapService,
checkerProvider: FSharpCheckerProvider,
projectInfoManager: ProjectInfoManager,
typeMap: Shared.Utilities.ClassificationTypeMap
typeMap: Shared.Utilities.ClassificationTypeMap,
glyphService: IGlyphService
) =

let xmlMemberIndexService = serviceProvider.GetService(typeof<SVsXMLMemberIndexService>) :?> IVsXMLMemberIndexService
Expand All @@ -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
Expand All @@ -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(
Expand All @@ -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),
Expand Down
2 changes: 1 addition & 1 deletion vsintegration/tests/unittests/QuickInfoProviderTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -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)