Skip to content
This repository was archived by the owner on Dec 23, 2024. It is now read-only.

Commit f751cb1

Browse files
vladimaKevinRansom
authored andcommitted
[WIP] use Layout as a source data of classification related tasks (dotnet#2070)
* use Layout as a source data of classification related tasks * fix indentation * parse xml doc by hand instead of relying on VS service * revert back old API * fix portable build * fix output in FSI * fix printing of operators * update Surface test * internalize new types and modules * tag module/namespace as keywords * fix tooltip formatting for types with hidden representation * fix separator placement
1 parent f5af861 commit f751cb1

File tree

4 files changed

+86
-55
lines changed

4 files changed

+86
-55
lines changed

Common/CommonRoslynHelpers.fs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ namespace Microsoft.VisualStudio.FSharp.Editor
44

55
open System
66
open System.Collections.Immutable
7+
open System.Collections.Generic
78
open System.Threading.Tasks
89
open Microsoft.CodeAnalysis
910
open Microsoft.CodeAnalysis.Text
1011
open Microsoft.FSharp.Compiler
12+
open Microsoft.FSharp.Compiler.Layout
1113
open Microsoft.FSharp.Compiler.SourceCodeServices
1214
open Microsoft.FSharp.Compiler.SourceCodeServices.ItemDescriptionIcons
1315
open Microsoft.FSharp.Compiler.Range
@@ -34,6 +36,44 @@ module internal CommonRoslynHelpers =
3436
Assert.Exception(task.Exception.GetBaseException())
3537
raise(task.Exception.GetBaseException())
3638

39+
let TaggedTextToRoslyn t =
40+
match t with
41+
| TaggedText.ActivePatternCase t
42+
| TaggedText.ActivePatternResult t -> TaggedText(TextTags.Enum, t)
43+
| TaggedText.Alias t -> TaggedText(TextTags.Class, t)
44+
| TaggedText.Class t -> TaggedText(TextTags.Class, t)
45+
| TaggedText.Delegate t -> TaggedText(TextTags.Delegate, t)
46+
| TaggedText.Enum t -> TaggedText(TextTags.Enum, t)
47+
| TaggedText.Event t -> TaggedText(TextTags.Event, t)
48+
| TaggedText.Field t -> TaggedText(TextTags.Field, t)
49+
| TaggedText.Interface t -> TaggedText(TextTags.Interface, t)
50+
| TaggedText.Keyword t -> TaggedText(TextTags.Keyword, t)
51+
| TaggedText.LineBreak t -> TaggedText(TextTags.LineBreak, t)
52+
| TaggedText.Local t -> TaggedText(TextTags.Local, t)
53+
| TaggedText.Member t -> TaggedText(TextTags.Property, t)
54+
| TaggedText.Method t -> TaggedText(TextTags.Method, t)
55+
| TaggedText.Module t -> TaggedText(TextTags.Module, t)
56+
| TaggedText.ModuleBinding t -> TaggedText(TextTags.Property, t)
57+
| TaggedText.Namespace t -> TaggedText(TextTags.Namespace, t)
58+
| TaggedText.NumericLiteral t -> TaggedText(TextTags.NumericLiteral, t)
59+
| TaggedText.Operator t -> TaggedText(TextTags.Operator, t)
60+
| TaggedText.Parameter t -> TaggedText(TextTags.Parameter, t)
61+
| TaggedText.Property t -> TaggedText(TextTags.Property, t)
62+
| TaggedText.Punctuation t -> TaggedText(TextTags.Punctuation, t)
63+
| TaggedText.Record t -> TaggedText(TextTags.Class, t)
64+
| TaggedText.RecordField t -> TaggedText(TextTags.Property, t)
65+
| TaggedText.Space t -> TaggedText(TextTags.Space, t)
66+
| TaggedText.StringLiteral t -> TaggedText(TextTags.StringLiteral, t)
67+
| TaggedText.Struct t -> TaggedText(TextTags.Struct, t)
68+
| TaggedText.Text t -> TaggedText(TextTags.Text, t)
69+
| TaggedText.TypeParameter t -> TaggedText(TextTags.TypeParameter, t)
70+
| TaggedText.Union t -> TaggedText(TextTags.Class, t)
71+
| TaggedText.UnionCase t -> TaggedText(TextTags.Property, t)
72+
| TaggedText.UnknownEntity t -> TaggedText(TextTags.Property, t)
73+
| TaggedText.UnknownType t -> TaggedText(TextTags.Class, t)
74+
75+
let CollectTaggedText (list: List<_>) t = list.Add(TaggedTextToRoslyn t)
76+
3777
let StartAsyncAsTask cancellationToken computation =
3878
let computation =
3979
async {

Completion/CompletionProvider.fs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,9 +149,12 @@ type internal FSharpCompletionProvider
149149
async {
150150
let exists, declarationItem = declarationItemsCache.TryGetValue(completionItem.DisplayText)
151151
if exists then
152-
let! description = declarationItem.DescriptionTextAsync
153-
let datatipText = XmlDocumentation.BuildDataTipText(documentationBuilder, description)
154-
return CompletionDescription.FromText(datatipText)
152+
let! description = declarationItem.StructuredDescriptionTextAsync
153+
let documentation = List()
154+
let collector = CommonRoslynHelpers.CollectTaggedText documentation
155+
// mix main description and xmldoc by using one collector
156+
XmlDocumentation.BuildDataTipText(documentationBuilder, collector, collector, description)
157+
return CompletionDescription.Create(documentation.ToImmutableArray())
155158
else
156159
return CompletionDescription.Empty
157160
} |> CommonRoslynHelpers.StartAsyncAsTask cancellationToken

Completion/SignatureHelp.fs

Lines changed: 13 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ open Microsoft.VisualStudio.Text.Tagging
2222
open Microsoft.VisualStudio.Shell
2323
open Microsoft.VisualStudio.Shell.Interop
2424

25+
open Microsoft.FSharp.Compiler.Layout
2526
open Microsoft.FSharp.Compiler.Parser
2627
open Microsoft.FSharp.Compiler.Range
2728
open Microsoft.FSharp.Compiler.SourceCodeServices
@@ -165,60 +166,28 @@ type internal FSharpSignatureHelpProvider
165166

166167
for method in methods do
167168
// Create the documentation. Note, do this on the background thread, since doing it in the documentationBuild fails to build the XML index
168-
let summaryDoc = XmlDocumentation.BuildMethodOverloadTipText(documentationBuilder, method.Description, false)
169+
let mainDescription = List()
170+
let documentation = List()
171+
XmlDocumentation.BuildMethodOverloadTipText(documentationBuilder, CommonRoslynHelpers.CollectTaggedText mainDescription, CommonRoslynHelpers.CollectTaggedText documentation, method.StructuredDescription, false)
169172

170173
let parameters =
171174
let parameters = if isStaticArgTip then method.StaticParameters else method.Parameters
172175
[| for p in parameters do
176+
let doc = List()
173177
// FSROSLYNTODO: compute the proper help text for parameters, c.f. AppendParameter in XmlDocumentation.fs
174-
let paramDoc = XmlDocumentation.BuildMethodParamText(documentationBuilder, method.XmlDoc, p.ParameterName)
175-
let doc = if String.IsNullOrWhiteSpace(paramDoc) then [||]
176-
else [| TaggedText(TextTags.Text, paramDoc) |]
177-
let parameterParts =
178-
if isStaticArgTip then
179-
[| TaggedText(TextTags.Class, p.Display) |]
180-
else
181-
let str = p.Display
182-
match str.IndexOf(':') with
183-
| -1 -> [| TaggedText(TextTags.Parameter, str) |]
184-
| 0 ->
185-
[| TaggedText(TextTags.Punctuation, ":");
186-
TaggedText(TextTags.Class, str.[1..]) |]
187-
| i ->
188-
[| TaggedText(TextTags.Parameter, str.[..i-1]);
189-
TaggedText(TextTags.Punctuation, ":");
190-
TaggedText(TextTags.Class, str.[i+1..]) |]
191-
yield (p.ParameterName, p.IsOptional, doc, parameterParts)
178+
XmlDocumentation.BuildMethodParamText(documentationBuilder, CommonRoslynHelpers.CollectTaggedText doc, method.XmlDoc, p.ParameterName)
179+
let parts = List()
180+
renderL (taggedTextListR (CommonRoslynHelpers.CollectTaggedText parts)) p.StructuredDisplay |> ignore
181+
yield (p.ParameterName, p.IsOptional, doc, parts)
192182
|]
193183

194-
let hasParamComments (pcs: (string*bool*TaggedText[]*TaggedText[])[]) =
195-
pcs |> Array.exists (fun (_, _, doc, _) -> doc.Length > 0)
196-
197-
let summaryText =
198-
let doc =
199-
if String.IsNullOrWhiteSpace summaryDoc then
200-
String.Empty
201-
elif hasParamComments parameters then
202-
summaryDoc + "\n"
203-
else
204-
summaryDoc
205-
[| TaggedText(TextTags.Text, doc) |]
206-
207-
// Prepare the text to display
208-
let descriptionParts =
209-
let str = method.TypeText
210-
if str.StartsWith(":", StringComparison.OrdinalIgnoreCase) then
211-
[| TaggedText(TextTags.Punctuation, ":");
212-
TaggedText(TextTags.Class, str.[1..]) |]
213-
else
214-
[| TaggedText(TextTags.Text, str) |]
215184
let prefixParts =
216185
[| TaggedText(TextTags.Method, methodGroup.MethodName);
217186
TaggedText(TextTags.Punctuation, (if isStaticArgTip then "<" else "(")) |]
218-
let separatorParts = [| TaggedText(TextTags.Punctuation, ", ") |]
187+
let separatorParts = [| TaggedText(TextTags.Punctuation, ","); TaggedText(TextTags.Space, " ") |]
219188
let suffixParts = [| TaggedText(TextTags.Punctuation, (if isStaticArgTip then ">" else ")")) |]
220189

221-
let completionItem = (method.HasParamArrayArg, summaryText, prefixParts, separatorParts, suffixParts, parameters, descriptionParts)
190+
let completionItem = (method.HasParamArrayArg, documentation, prefixParts, separatorParts, suffixParts, parameters, mainDescription)
222191
// FSROSLYNTODO: Do we need a cache like for completion?
223192
//declarationItemsCache.Remove(completionItem.DisplayText) |> ignore // clear out stale entries if they exist
224193
//declarationItemsCache.Add(completionItem.DisplayText, declarationItem)
@@ -251,9 +220,9 @@ type internal FSharpSignatureHelpProvider
251220
results
252221
|> Array.map (fun (hasParamArrayArg, doc, prefixParts, separatorParts, suffixParts, parameters, descriptionParts) ->
253222
let parameters = parameters
254-
|> Array.map (fun (paramName, isOptional, paramDoc, displayParts) ->
223+
|> Array.map (fun (paramName, isOptional, paramDoc, displayParts) ->
255224
SignatureHelpParameter(paramName,isOptional,documentationFactory=(fun _ -> paramDoc :> seq<_>),displayParts=displayParts))
256-
SignatureHelpItem(isVariadic=hasParamArrayArg ,documentationFactory=(fun _ -> doc :> seq<_>),prefixParts=prefixParts,separatorParts=separatorParts,suffixParts=suffixParts,parameters=parameters,descriptionParts=descriptionParts))
225+
SignatureHelpItem(isVariadic=hasParamArrayArg, documentationFactory=(fun _ -> doc :> seq<_>),prefixParts=prefixParts,separatorParts=separatorParts,suffixParts=suffixParts,parameters=parameters,descriptionParts=descriptionParts))
257226

258227
return SignatureHelpItems(items,applicableSpan,argumentIndex,argumentCount,Option.toObj argumentName)
259228
with ex ->

QuickInfo/QuickInfoProvider.fs

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,10 @@ type internal FSharpQuickInfoProvider
6262
[<System.ComponentModel.Composition.ImportingConstructor>]
6363
(
6464
[<System.ComponentModel.Composition.Import(typeof<SVsServiceProvider>)>] serviceProvider: IServiceProvider,
65-
classificationFormatMapService: IClassificationFormatMapService,
65+
_classificationFormatMapService: IClassificationFormatMapService,
6666
checkerProvider: FSharpCheckerProvider,
67-
projectInfoManager: ProjectInfoManager
67+
projectInfoManager: ProjectInfoManager,
68+
typeMap: Shared.Utilities.ClassificationTypeMap
6869
) =
6970

7071
let xmlMemberIndexService = serviceProvider.GetService(typeof<SVsXMLMemberIndexService>) :?> IVsXMLMemberIndexService
@@ -78,11 +79,11 @@ type internal FSharpQuickInfoProvider
7879
//let qualifyingNames, partialName = QuickParse.GetPartialLongNameEx(textLine.ToString(), textLineColumn - 1)
7980
let defines = CompilerEnvironment.GetCompilationDefinesForEditing(filePath, options.OtherOptions |> Seq.toList)
8081
let! symbol = CommonHelpers.getSymbolAtPosition(documentId, sourceText, position, filePath, defines, SymbolLookupKind.Fuzzy)
81-
let! res = checkFileResults.GetToolTipTextAlternate(textLineNumber, symbol.RightColumn, textLine.ToString(), [symbol.Text], FSharpTokenTag.IDENT) |> liftAsync
82+
let! res = checkFileResults.GetStructuredToolTipTextAlternate(textLineNumber, symbol.RightColumn, textLine.ToString(), [symbol.Text], FSharpTokenTag.IDENT) |> liftAsync
8283
return!
8384
match res with
8485
| FSharpToolTipText []
85-
| FSharpToolTipText [FSharpToolTipElement.None] -> None
86+
| FSharpToolTipText [FSharpStructuredToolTipElement.None] -> None
8687
| _ -> Some(res, CommonRoslynHelpers.FSharpRangeToTextSpan(sourceText, symbol.Range))
8788
}
8889

@@ -95,9 +96,27 @@ type internal FSharpQuickInfoProvider
9596
let! options = projectInfoManager.TryGetOptionsForEditingDocumentOrProject(document)
9697
let! textVersion = document.GetTextVersionAsync(cancellationToken)
9798
let! toolTipElement, textSpan = FSharpQuickInfoProvider.ProvideQuickInfo(checkerProvider.Checker, document.Id, sourceText, document.FilePath, position, options, textVersion.GetHashCode())
98-
let dataTipText = XmlDocumentation.BuildDataTipText(documentationBuilder, toolTipElement)
99-
let textProperties = classificationFormatMapService.GetClassificationFormatMap("tooltip").DefaultTextProperties
100-
return QuickInfoItem(textSpan, FSharpDeferredQuickInfoContent(dataTipText, textProperties))
99+
let mainDescription = Collections.Generic.List()
100+
let documentation = Collections.Generic.List()
101+
XmlDocumentation.BuildDataTipText(
102+
documentationBuilder,
103+
CommonRoslynHelpers.CollectTaggedText mainDescription,
104+
CommonRoslynHelpers.CollectTaggedText documentation,
105+
toolTipElement)
106+
let empty = ClassifiableDeferredContent(Array.Empty<TaggedText>(), typeMap);
107+
let content =
108+
QuickInfoDisplayDeferredContent
109+
(
110+
symbolGlyph = null,//SymbolGlyphDeferredContent(),
111+
warningGlyph = null,
112+
mainDescription = ClassifiableDeferredContent(mainDescription, typeMap),
113+
documentation = ClassifiableDeferredContent(documentation, typeMap),
114+
typeParameterMap = empty,
115+
anonymousTypes = empty,
116+
usageText = empty,
117+
exceptionText = empty
118+
)
119+
return QuickInfoItem(textSpan, content)
101120
}
102121
|> Async.map Option.toObj
103-
|> CommonRoslynHelpers.StartAsyncAsTask(cancellationToken)
122+
|> CommonRoslynHelpers.StartAsyncAsTask(cancellationToken)

0 commit comments

Comments
 (0)