Skip to content

Commit

Permalink
remove backticks when rendering signature for signaturedata
Browse files Browse the repository at this point in the history
  • Loading branch information
baronfel committed Jul 12, 2022
1 parent 61e4007 commit 0daaf76
Show file tree
Hide file tree
Showing 3 changed files with 169 additions and 149 deletions.
17 changes: 17 additions & 0 deletions src/FsAutoComplete.Core/TipFormatter.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1048,6 +1048,10 @@ let formatTaggedText (t: TaggedText) : string =
| TextTag.Record
| TextTag.TypeParameter -> $"`{t.Text}`"

let formatUntaggedText (t: TaggedText) = t.Text

let formatUntaggedTexts = Array.map formatUntaggedText >> String.concat ""

let formatTaggedTexts = Array.map formatTaggedText >> String.concat ""

let formatGenericParameters (typeMappings: TaggedText[] list) =
Expand Down Expand Up @@ -1077,6 +1081,19 @@ let formatTip (ToolTipText tips) : (string * string) list list =
| ToolTipElement.CompositionError (error) -> Some [ ("<Note>", error) ]
| _ -> None)

/// Formats a tooltip signature for output as a signatureHelp,
/// which means no markdown formatting.
let formatPlainTip (ToolTipText tips) : (string * string) =
tips
|> List.pick (function
| ToolTipElement.Group items ->
let t = items |> Seq.head
let signature = formatUntaggedTexts t.MainDescription
let description = buildFormatComment t.XmlDoc FormatCommentStyle.Legacy None
Some(signature, description)
| ToolTipElement.CompositionError (error) -> Some("<Note>", error)
| _ -> Some("<Note>", "No signature data"))

let formatTipEnhanced
(ToolTipText tips)
(signature: string)
Expand Down
7 changes: 3 additions & 4 deletions src/FsAutoComplete/FsAutoComplete.Lsp.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1208,18 +1208,17 @@ type FSharpLspServer(state: State, lspClient: FSharpLspClient) =
let sigs =
sigHelp.Methods
|> Array.map (fun m ->
let tip = TipFormatter.formatTip m.Description
let (sign, comm) = tip |> List.head |> List.head
let (signature, comment) = TipFormatter.formatPlainTip m.Description

let parameters =
m.Parameters
|> Array.map (fun p ->
{ ParameterInformation.Label = p.ParameterName
Documentation = Some(Documentation.String p.CanonicalTypeTextForSorting) })

let d = Documentation.Markup(markdown comm)
let d = Documentation.Markup(markdown comment)

{ SignatureInformation.Label = sign
{ SignatureInformation.Label = signature
Documentation = Some d
Parameters = Some parameters })

Expand Down
294 changes: 149 additions & 145 deletions test/FsAutoComplete.Tests.Lsp/SignatureHelpTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -13,126 +13,109 @@ type private TriggerType =
| Manual
| Char of char

let private testSignatureHelp' (server: CachedServer) text pos triggerType checkResp = async {
let! (doc, diags) = server |> Server.createUntitledDocument text
use doc = doc

let sigHelpRequest: SignatureHelpParams =
{ TextDocument = doc.TextDocumentIdentifier
Position = pos
Context =
Some
{ TriggerKind =
match triggerType with
| Manual -> SignatureHelpTriggerKind.Invoked
| Char c -> SignatureHelpTriggerKind.TriggerCharacter
TriggerCharacter =
match triggerType with
| Manual -> None
| Char c -> Some c
IsRetrigger = false
ActiveSignatureHelp = None } }
let! resp =
doc.Server.Server.TextDocumentSignatureHelp sigHelpRequest

checkResp resp
}

let private wantSignatureHelp =
Flip.Expect.wantOk "unexpected request error"

let private testSignatureHelp (server: CachedServer) textWithCursor triggerType checkResp = async {
let (pos, text) =
textWithCursor
|> Text.trimTripleQuotation
|> Cursor.assertExtractPosition
let checkResp =
wantSignatureHelp
>> checkResp
return! testSignatureHelp' server text pos triggerType checkResp
}

let private functionApplicationEdgeCasesTests server = testList "function application edge cases" [
testCaseAsync "issue 742 - signature help on functions counts the prior parameters" <|
testSignatureHelp server
"""
let private testSignatureHelp' (server: CachedServer) text pos triggerType checkResp =
async {
let! (doc, diags) = server |> Server.createUntitledDocument text
use doc = doc

let sigHelpRequest: SignatureHelpParams =
{ TextDocument = doc.TextDocumentIdentifier
Position = pos
Context =
Some
{ TriggerKind =
match triggerType with
| Manual -> SignatureHelpTriggerKind.Invoked
| Char c -> SignatureHelpTriggerKind.TriggerCharacter
TriggerCharacter =
match triggerType with
| Manual -> None
| Char c -> Some c
IsRetrigger = false
ActiveSignatureHelp = None } }

let! resp = doc.Server.Server.TextDocumentSignatureHelp sigHelpRequest

checkResp resp
}

let private wantSignatureHelp = Flip.Expect.wantOk "unexpected request error"

let private testSignatureHelp (server: CachedServer) textWithCursor triggerType checkResp =
async {
let (pos, text) =
textWithCursor
|> Text.trimTripleQuotation
|> Cursor.assertExtractPosition

let checkResp = wantSignatureHelp >> checkResp
return! testSignatureHelp' server text pos triggerType checkResp
}

let private functionApplicationEdgeCasesTests server =
testList
"function application edge cases"
[ testCaseAsync "issue 742 - signature help on functions counts the prior parameters"
<| testSignatureHelp server """
id 12 $0// note: keep the trailing space after '12' on this line
"""
(Char ' ')
(fun resp -> Expect.isNone resp "there should be no sighelp on this location")
testCaseAsync "issue 744 - signature help suggests parameters other than the first" <|
testSignatureHelp server
"""
""" (Char ' ') (fun resp -> Expect.isNone resp "there should be no sighelp on this location")
testCaseAsync "issue 744 - signature help suggests parameters other than the first"
<| testSignatureHelp server """
let f a b = ()
f 1 $0 // preserve last space
"""
Manual
(fun resp ->
""" Manual (fun resp ->
match resp with
| Some sigHelp -> Expect.equal sigHelp.ActiveParameter (Some 1) "should have suggested the second parameter"
| None -> failwithf "There should be sighelp for this position")
ptestCaseAsync "issue 745 - signature help shows tuples in parens" <|
testSignatureHelp server
"""
ptestCaseAsync "issue 745 - signature help shows tuples in parens"
<| testSignatureHelp server """
let f (a, b) = ()
f $0 // preserve last space
"""
Manual
(fun resp ->
match resp with
| Some sigHelp ->
Expect.equal sigHelp.ActiveSignature (Some 0) "should have suggested the first overload"

Expect.equal
sigHelp.Signatures.[0].Label
"val f : (a:'a * b:'b) -> unit"
"should highlight tuples with parens in signature help"
| None -> failwithf "There should be sighelp for this position")
testCaseAsync "issue 746 - signature help understands piping for parameter application" <|
testSignatureHelp server
"""
""" Manual (fun resp ->
match resp with
| Some sigHelp ->
Expect.equal sigHelp.ActiveSignature (Some 0) "should have suggested the first overload"

Expect.equal
sigHelp.Signatures.[0].Label
"val f : (a:'a * b:'b) -> unit"
"should highlight tuples with parens in signature help"
| None -> failwithf "There should be sighelp for this position")
testCaseAsync "issue 746 - signature help understands piping for parameter application"
<| testSignatureHelp server """
[1..10] |> List.map id $0// keep trailing space
"""
Manual
(fun resp ->
""" Manual (fun resp ->
Expect.isNone
resp
"there should be no suggestions at this position, since we've provided all parameters to List.map")
testCaseAsync "issue 747 - signature help is provided for the most inner function" <|
testSignatureHelp server
"""
testCaseAsync "issue 747 - signature help is provided for the most inner function"
<| testSignatureHelp server """
let f a b c = ()
let g a b = ()
f (g $0)
"""
Manual
(fun resp ->
""" Manual (fun resp ->
Expect.isSome resp "should have provided signature help"
let resp = resp.Value
let methodsig = resp.Signatures.[0]
Expect.stringStarts methodsig.Label "val g: " "should have provided signatures for function g")
testCaseAsync "issue 748 - signature help is provided for functions inside CEs" <|
testSignatureHelp server
"""
testCaseAsync "issue 748 - signature help is provided for functions inside CEs"
<| testSignatureHelp server """
let _ =
async {
let x = sqrt $0// trigger here
return ()
}
"""
Manual
(fun resp ->
""" Manual (fun resp ->
Expect.isSome resp "should have provided signature help"
let resp = resp.Value
let methodsig = resp.Signatures.[0]
Expect.stringStarts methodsig.Label "val sqrt: " "should have provided signatures for sqrt")
testCaseAsync "issue 750 - signature help should have tips when triggered on generic type applications" <|
testSignatureHelp server
"""
testCaseAsync "issue 750 - signature help should have tips when triggered on generic type applications"
<| testSignatureHelp server """
open System
/// Tries to cast an object to a given type; throws with the given error message if it fails.
Expand All @@ -146,67 +129,88 @@ let tryConvert<'T> (descriptor: string) (value: obj) : 'T =
// Tooltip does NOT show when the generic argument is present:
let result = (box 123) |> tryConvert<string> $0(* trigger at > char, no sigdata occurs *)
"""
Manual
(fun resp ->
""" Manual (fun resp ->
Expect.isSome resp "should get sigdata when triggered on applications"
let resp = resp.Value
let signatures = resp.Signatures.[0]
Expect.stringStarts signatures.Label "val tryConvert:" "should have given help for tryConvert")
]

let private overloadEdgeCasesTests server = testList "overload edge cases" [
testList "unattached parens" [
let text = "let ___ = new System.IO.MemoryStream ( )"
for c in 37..39 do
let pos = { Line = 0; Character = c }
testCaseAsync $"Can get overloads at whitespace position {c - 37} of unattached parens" <|
testSignatureHelp' server
text pos
Manual
(wantSignatureHelp >> fun resp ->
Expect.isSome resp $"Should get some signature overloads at position %A{pos} on file Overloads.fsx"
Expect.isNonEmpty resp.Value.Signatures "Should have some overloads")
]
testList "attached parens" [
let text = "let _____ = new System.IO.MemoryStream(42)"
for c in 39..41 do
let pos = { Line = 0; Character = c }
testCaseAsync $"Can get overloads at whitespace position {c - 39} of attached parens" <|
testSignatureHelp' server
text pos
Manual
(wantSignatureHelp >> fun resp ->
Expect.isSome resp $"Should get some signature overloads at position %A{pos} on file Overloads.fsx"
Expect.isNonEmpty resp.Value.Signatures "Should have some overloads")
]
]

let issuesTests server = testList "issues" [
testCaseAsync "issue #950 - exception when in first column in first line" <|
testSignatureHelp' server
"Syste" { Line = 0; Character = 0 }
Manual
(fun r ->
let err = Expect.wantError r "No signature help at first position"
Expect.equal err.Message "Couldn't find previous non-whitespace char" "Should fail because no prev char"
)
]
Expect.stringStarts signatures.Label "val tryConvert:" "should have given help for tryConvert") ]

let private overloadEdgeCasesTests server =
testList
"overload edge cases"
[ testList
"unattached parens"
[ let text = "let ___ = new System.IO.MemoryStream ( )"

for c in 37..39 do
let pos = { Line = 0; Character = c }

testCaseAsync $"Can get overloads at whitespace position {c - 37} of unattached parens"
<| testSignatureHelp'
server
text
pos
Manual
(wantSignatureHelp
>> fun resp ->
Expect.isSome
resp
$"Should get some signature overloads at position %A{pos} on file Overloads.fsx"

Expect.isNonEmpty resp.Value.Signatures "Should have some overloads") ]
testList
"attached parens"
[ let text = "let _____ = new System.IO.MemoryStream(42)"

for c in 39..41 do
let pos = { Line = 0; Character = c }

testCaseAsync $"Can get overloads at whitespace position {c - 39} of attached parens"
<| testSignatureHelp'
server
text
pos
Manual
(wantSignatureHelp
>> fun resp ->
Expect.isSome
resp
$"Should get some signature overloads at position %A{pos} on file Overloads.fsx"

Expect.isNonEmpty resp.Value.Signatures "Should have some overloads") ] ]

let issuesTests server =
testList
"issues"
[ testCaseAsync "issue #950 - exception when in first column in first line"
<| testSignatureHelp' server "Syste" { Line = 0; Character = 0 } Manual (fun r ->
let err = Expect.wantError r "No signature help at first position"
Expect.equal err.Message "Couldn't find previous non-whitespace char" "Should fail because no prev char")
testCaseAsync "type names aren't backticked"
<| testSignatureHelp server """
let count (x: int) = x
let _ = count $010
""" TriggerType.Manual (fun sigs ->
Expect.isSome sigs "Should have sigs for backtick check"
let sigText = sigs.Value.Signatures[0].Label

Expect.equal
sigText
"val count: x: int -> int"
"Should have no backticks because signatures are only ever rendered in `code` form") ]

let tests state =
serverTestList "signature help" state defaultConfigDto None (fun server -> [
functionApplicationEdgeCasesTests server
overloadEdgeCasesTests server
testList "parameter position detect" [
testCaseAsync "Can suggest second parameter when on the second parameter" <|
testSignatureHelp server
"""
serverTestList "signature help" state defaultConfigDto None (fun server ->
[ functionApplicationEdgeCasesTests server
overloadEdgeCasesTests server
testList
"parameter position detect"
[ testCaseAsync "Can suggest second parameter when on the second parameter"
<| testSignatureHelp server """
System.IO.Directory.EnumerateDirectories("/var", $0) // signature help triggered at the space after the comma should suggest overload 1, not overload 0
"""
Manual
(fun resp ->
""" Manual (fun resp ->
Expect.isSome resp "should get sigdata when triggered on applications"
Expect.equal (Some 1) resp.Value.ActiveSignature "should have suggested the second overload")
]
issuesTests server
])
Expect.equal (Some 1) resp.Value.ActiveSignature "should have suggested the second overload") ]

issuesTests server ])

0 comments on commit 0daaf76

Please sign in to comment.