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

remove backticks when rendering signature for signaturedata #964

Merged
merged 1 commit into from
Jul 12, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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 ])