Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Various improvement around TipFormatter and Documentation #1099

Merged
merged 10 commits into from
Apr 11, 2023
77 changes: 48 additions & 29 deletions src/FsAutoComplete.Core/DocumentationFormatter.fs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,22 @@ module DocumentationFormatter =

let mutable lastDisplayContext: FSharpDisplayContext = FSharpDisplayContext.Empty

let emptyTypeTip = [||], [||], [||], [||], [||], [||]
type EntityInfo =
{ Constructors: string array
Fields: string array
Functions: string array
Interfaces: string array
Attributes: string array
DeclaredTypes: string array }

static member Empty =

{ Constructors = [||]
Fields = [||]
Functions = [||]
Interfaces = [||]
Attributes = [||]
DeclaredTypes = [||] }
Comment on lines +19 to +34
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change alone would be a wonderful PR - thank you for taking the time to make this nicer!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ah, yes having a record instead of the tuple make it so much easier to understand what you have in hand.

I was getting lost with stuff like string * (string * string []) * (string * string * string * string * string * string) etc.


/// Concat two strings with a space between if both a and b are not IsNullOrWhiteSpace
let internal (++) (a: string) (b: string) =
Expand Down Expand Up @@ -719,8 +734,12 @@ module DocumentationFormatter =
++ fst (formatShowDocumentationLink ne.DisplayName ne.XmlDocSig ne.Assembly.SimpleName))
|> Seq.toArray


constrc, fields, funcs, interfaces, attrs, types
{ Constructors = constrc
Fields = fields
Functions = funcs
Interfaces = interfaces
Attributes = attrs
DeclaredTypes = types }

let typeDisplay =
let name =
Expand Down Expand Up @@ -756,9 +775,9 @@ module DocumentationFormatter =
if fse.IsFSharpUnion then
(typeDisplay + uniontip ()), typeTip ()
elif fse.IsEnum then
(typeDisplay + enumtip ()), emptyTypeTip
(typeDisplay + enumtip ()), EntityInfo.Empty
elif fse.IsDelegate then
(typeDisplay + delegateTip ()), emptyTypeTip
(typeDisplay + delegateTip ()), EntityInfo.Empty
else
typeDisplay, typeTip ()

Expand Down Expand Up @@ -867,60 +886,60 @@ module DocumentationFormatter =
| Some ent when ent.IsValueType || ent.IsEnum ->
//ValueTypes
let signature = getFuncSignature symbol.DisplayContext func
Some((signature, emptyTypeTip), footerForType symbol, cn)
Some((signature, EntityInfo.Empty), footerForType symbol, cn)
| _ ->
//ReferenceType constructor
let signature = getFuncSignature symbol.DisplayContext func
Some((signature, emptyTypeTip), footerForType symbol, cn)
Some((signature, EntityInfo.Empty), footerForType symbol, cn)

| SymbolUse.Operator func ->
let signature = getFuncSignature symbol.DisplayContext func
Some((signature, emptyTypeTip), footerForType symbol, cn)
Some((signature, EntityInfo.Empty), footerForType symbol, cn)

| SymbolUse.Pattern func ->
//Active pattern or operator
let signature = getFuncSignature symbol.DisplayContext func
Some((signature, emptyTypeTip), footerForType symbol, cn)
Some((signature, EntityInfo.Empty), footerForType symbol, cn)

| SymbolUse.Property prop ->
let signature = getFuncSignature symbol.DisplayContext prop
Some((signature, emptyTypeTip), footerForType symbol, cn)
Some((signature, EntityInfo.Empty), footerForType symbol, cn)

| SymbolUse.ClosureOrNestedFunction func ->
//represents a closure or nested function
let signature = getFuncSignature symbol.DisplayContext func
Some((signature, emptyTypeTip), footerForType symbol, cn)
Some((signature, EntityInfo.Empty), footerForType symbol, cn)

| SymbolUse.Function func ->
let signature = getFuncSignature symbol.DisplayContext func
Some((signature, emptyTypeTip), footerForType symbol, cn)
Some((signature, EntityInfo.Empty), footerForType symbol, cn)

| SymbolUse.Val func ->
//val name : Type
let signature = getValSignature symbol.DisplayContext func
Some((signature, emptyTypeTip), footerForType symbol, cn)
Some((signature, EntityInfo.Empty), footerForType symbol, cn)

| SymbolUse.Field fsf ->
let signature = getFieldSignature symbol.DisplayContext fsf
Some((signature, emptyTypeTip), footerForType symbol, cn)
Some((signature, EntityInfo.Empty), footerForType symbol, cn)

| SymbolUse.UnionCase uc ->
let signature = getUnioncaseSignature symbol.DisplayContext uc
Some((signature, emptyTypeTip), footerForType symbol, cn)
Some((signature, EntityInfo.Empty), footerForType symbol, cn)

| SymbolUse.ActivePatternCase apc ->
let signature = getAPCaseSignature symbol.DisplayContext apc
Some((signature, emptyTypeTip), footerForType symbol, cn)
Some((signature, EntityInfo.Empty), footerForType symbol, cn)

| SymbolUse.ActivePattern ap ->
let signature = getFuncSignature symbol.DisplayContext ap
Some((signature, emptyTypeTip), footerForType symbol, cn)
Some((signature, EntityInfo.Empty), footerForType symbol, cn)

| SymbolUse.GenericParameter gp ->
let signature =
$"'%s{gp.Name} (requires %s{formatGenericParameter false symbol.DisplayContext gp})"

Some((signature, emptyTypeTip), footerForType symbol, cn)
Some((signature, EntityInfo.Empty), footerForType symbol, cn)

| _ -> None

Expand All @@ -942,51 +961,51 @@ module DocumentationFormatter =
| Some ent when ent.IsValueType || ent.IsEnum ->
//ValueTypes
let signature = getFuncSignature lastDisplayContext func
Some((signature, emptyTypeTip), footerForType' symbol, cn)
Some((signature, EntityInfo.Empty), footerForType' symbol, cn)
| _ ->
//ReferenceType constructor
let signature = getFuncSignature lastDisplayContext func
Some((signature, emptyTypeTip), footerForType' symbol, cn)
Some((signature, EntityInfo.Empty), footerForType' symbol, cn)

| SymbolPatterns.Operator func ->
let signature = getFuncSignature lastDisplayContext func
Some((signature, emptyTypeTip), footerForType' symbol, cn)
Some((signature, EntityInfo.Empty), footerForType' symbol, cn)

| Property prop ->
let signature = getFuncSignature lastDisplayContext prop
Some((signature, emptyTypeTip), footerForType' symbol, cn)
Some((signature, EntityInfo.Empty), footerForType' symbol, cn)

| ClosureOrNestedFunction func ->
//represents a closure or nested function
let signature = getFuncSignature lastDisplayContext func
Some((signature, emptyTypeTip), footerForType' symbol, cn)
Some((signature, EntityInfo.Empty), footerForType' symbol, cn)

| Function func ->
let signature = getFuncSignature lastDisplayContext func
Some((signature, emptyTypeTip), footerForType' symbol, cn)
Some((signature, EntityInfo.Empty), footerForType' symbol, cn)

| Val func ->
//val name : Type
let signature = getValSignature lastDisplayContext func
Some((signature, emptyTypeTip), footerForType' symbol, cn)
Some((signature, EntityInfo.Empty), footerForType' symbol, cn)

| Field(fsf, _) ->
let signature = getFieldSignature lastDisplayContext fsf
Some((signature, emptyTypeTip), footerForType' symbol, cn)
Some((signature, EntityInfo.Empty), footerForType' symbol, cn)

| UnionCase uc ->
let signature = getUnioncaseSignature lastDisplayContext uc
Some((signature, emptyTypeTip), footerForType' symbol, cn)
Some((signature, EntityInfo.Empty), footerForType' symbol, cn)

| ActivePatternCase apc ->
let signature = getAPCaseSignature lastDisplayContext apc
Some((signature, emptyTypeTip), footerForType' symbol, cn)
Some((signature, EntityInfo.Empty), footerForType' symbol, cn)


| GenericParameter gp ->
let signature =
$"'%s{gp.Name} (requires %s{formatGenericParameter false lastDisplayContext gp})"

Some((signature, emptyTypeTip), footerForType' symbol, cn)
Some((signature, EntityInfo.Empty), footerForType' symbol, cn)

| _ -> None
49 changes: 42 additions & 7 deletions src/FsAutoComplete.Core/ParseAndCheckResults.fs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,21 @@ type FindDeclarationResult =
/// The declaration refers to a file.
| File of string

[<RequireQualifiedAccess>]
module TryGetToolTipEnhancedResult =

type SymbolInfo =
| Keyword of string
| Symbol of
{| XmlDocSig: string
Assembly: string |}

type TryGetToolTipEnhancedResult =
{ ToolTipText: ToolTipText
Signature: string
Footer: string
SymbolInfo: TryGetToolTipEnhancedResult.SymbolInfo }

type ParseAndCheckResults
(parseResults: FSharpParseFileResults, checkResults: FSharpCheckFileResults, entityCache: EntityCache) =

Expand Down Expand Up @@ -320,7 +335,10 @@ type ParseAndCheckResults
| _ -> ResultOrString.Error "No tooltip information"
| _ -> Ok(tip)

member x.TryGetToolTipEnhanced (pos: Position) (lineStr: LineStr) =
member x.TryGetToolTipEnhanced
(pos: Position)
(lineStr: LineStr)
: Result<option<TryGetToolTipEnhancedResult>, string> =
let (|EmptyTooltip|_|) (ToolTipText elems) =
match elems with
| [] -> Some()
Expand All @@ -347,21 +365,38 @@ type ParseAndCheckResults
match identIsland with
| [ ident ] ->
match KeywordList.keywordTooltips.TryGetValue ident with
| true, tip -> Ok(Some(tip, ident, "", None))
| true, tip ->
{ ToolTipText = tip
Signature = ident
Footer = ""
SymbolInfo = TryGetToolTipEnhancedResult.Keyword ident }
|> Some
|> Ok
| _ -> Error "No tooltip information"
| _ -> Error "No tooltip information"
| _ ->
match symbol with
| None -> Error "No tooltip information"
| Some symbol ->

// Retrieve the FSharpSymbol instance so we can find the XmlDocSig
// This mimic, the behavior of the Info Panel on hover
// 1. If this is a concrete type it returns that type reference
// 2. If this a type alias, it returns the aliases type reference
let resolvedType = symbol.Symbol.GetAbbreviatedParent()

match SignatureFormatter.getTooltipDetailsFromSymbolUse symbol with
| None -> Error "No tooltip information"
| Some(signature, footer) ->
let typeDoc =
getTypeIfConstructor symbol.Symbol |> Option.map (fun n -> n.XmlDocSig)

Ok(Some(tip, signature, footer, typeDoc))
{ ToolTipText = tip
Signature = signature
Footer = footer
SymbolInfo =
TryGetToolTipEnhancedResult.Symbol
{| XmlDocSig = resolvedType.XmlDocSig
Assembly = symbol.Symbol.Assembly.SimpleName |} }
|> Some
|> Ok

member __.TryGetFormattedDocumentation (pos: Position) (lineStr: LineStr) =
match Lexer.findLongIdents (pos.Column, lineStr) with
Expand All @@ -380,7 +415,7 @@ type ParseAndCheckResults
match identIsland with
| [ ident ] ->
match KeywordList.keywordTooltips.TryGetValue ident with
| true, tip -> Ok(Some tip, None, (ident, (DocumentationFormatter.emptyTypeTip)), "", "")
| true, tip -> Ok(Some tip, None, (ident, DocumentationFormatter.EntityInfo.Empty), "", "")
| _ -> Error "No tooltip information"
| _ -> Error "No documentation information"
| _ ->
Expand Down
Loading