Skip to content
Draft
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
29 changes: 27 additions & 2 deletions src/FsAutoComplete.Core/SignatureHelp.fs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ type SignatureHelpInfo =
/// if present, the index of the parameter on the active method (will never be outside the bounds of the Parameters array on the selected method)
ActiveParameter: uint option
SigHelpKind: SignatureHelpKind
/// For FunctionApplication calls, provides (paramName, typeDisplay) for every curried parameter group,
/// flattened across all groups. When present, use instead of Methods[i].Parameters for ParameterInformation.
FunctionApplicationParameters: (string * string)[] option
}

let private getSignatureHelpForFunctionApplication
Expand Down Expand Up @@ -114,11 +117,32 @@ let private getSignatureHelpForFunctionApplication
let methods =
tyRes.GetCheckResults.GetMethods(symbolStart.Line, symbolUse.Range.EndColumn, symbolStartLineText, None)

// Build a (name, typeDisplay) pair per curried group so that editors can highlight
// the correct parameter even for curried functions where GetMethods only returns the
// first group (fixes #744).
let functionAppParams =
definedArgs
|> Array.map (fun group ->
let groupParams = group |> Seq.toArray

match groupParams with
| [| p |] -> p.DisplayName, p.Type.Format(symbolUse.DisplayContext)
| _ ->
let names = groupParams |> Array.map (fun p -> p.DisplayName) |> String.concat ", "

let types =
groupParams
|> Array.map (fun p -> p.Type.Format(symbolUse.DisplayContext))
|> String.concat " * "

sprintf "(%s)" names, sprintf "(%s)" types)

return
{ ActiveParameter = Some(uint argumentIndex)
Methods = methods.Methods
ActiveOverload = None
SigHelpKind = FunctionApplication }
SigHelpKind = FunctionApplication
FunctionApplicationParameters = Some functionAppParams }
| _ -> return! None
}

Expand Down Expand Up @@ -205,7 +229,8 @@ let private getSignatureHelpForMethod
{ ActiveParameter = Some(uint argumentIndex)
Methods = filteredMethods
ActiveOverload = methodCandidate
SigHelpKind = MethodCall }
SigHelpKind = MethodCall
FunctionApplicationParameters = None }
}

let getSignatureHelpFor
Expand Down
18 changes: 14 additions & 4 deletions src/FsAutoComplete/LspServers/AdaptiveFSharpLspServer.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1012,10 +1012,20 @@ type AdaptiveFSharpLspServer
let (signature, comment) = TipFormatter.formatPlainTip m.Description

let parameters =
m.Parameters
|> Array.map (fun p ->
{ ParameterInformation.Label = U2.C1 p.ParameterName
Documentation = Some(U2.C1(p.Display |> Array.map (fun t -> t.Text) |> String.concat "")) })
match sigHelp.FunctionApplicationParameters with
| Some extraParams ->
// For curried function application, GetMethods only returns the first curried
// group; use the full curried parameter list so editors can highlight the
// correct parameter for every argument position (fixes #744).
extraParams
|> Array.map (fun (name, typeDisplay) ->
{ ParameterInformation.Label = U2.C1 name
Documentation = if typeDisplay = "" then None else Some(U2.C1 typeDisplay) })
| None ->
m.Parameters
|> Array.map (fun p ->
{ ParameterInformation.Label = U2.C1 p.ParameterName
Documentation = Some(U2.C1(p.Display |> Array.map (fun t -> t.Text) |> String.concat "")) })

let d =
U2.C2(
Expand Down
45 changes: 25 additions & 20 deletions test/FsAutoComplete.Tests.Lsp/SignatureHelpTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,16 @@ let private functionApplicationEdgeCasesTests server =
f 1 $0 // preserve last space
""" Manual (fun resp ->
match resp with
| Some sigHelp -> Expect.equal sigHelp.ActiveParameter (Some 1u) "should have suggested the second parameter"
| Some sigHelp ->
Expect.equal sigHelp.ActiveParameter (Some 1u) "should have suggested the second parameter"

let sigInfo = sigHelp.Signatures.[0]
Expect.isSome sigInfo.Parameters "should have parameter info"

Expect.equal
sigInfo.Parameters.Value.Length
2
"should report both curried parameters so that editors can highlight the correct one"
| None -> failwithf "There should be sighelp for this position")
ptestCaseAsync "issue 745 - signature help shows tuples in parens"
<| testSignatureHelp server """
Expand Down Expand Up @@ -198,28 +207,24 @@ let issuesTests server =
testCaseAsync "issue #1040" // IndexOutOfRangeException
<| testSignatureHelp server "().ToString(\n\n,$0\n)" Manual (fun sigs -> Expect.isSome sigs "Should have sigs")
testCaseAsync "issue #1029 - parameter documentation should use simplified type names not fully-qualified ones"
<| testSignatureHelp
server
"""
<| testSignatureHelp server """
let f (arr: char[]) = arr

let _ = f $0
"""
Manual
(fun sigs ->
Expect.isSome sigs "Should have sigs for simplified type names check"
let sigInfo = sigs.Value.Signatures.[0]
Expect.isSome sigInfo.Parameters "Should have parameter info"
let param = sigInfo.Parameters.Value.[0]

match param.Documentation with
| Some(U2.C1 doc) ->
Expect.isFalse
(doc.Contains("Microsoft.FSharp.Core"))
$"Parameter documentation should not contain fully-qualified names, but was: {doc}"

Expect.stringContains doc "char" "Parameter documentation should contain simplified type name 'char'"
| _ -> failwith "Expected string documentation for parameter") ]
""" Manual (fun sigs ->
Expect.isSome sigs "Should have sigs for simplified type names check"
let sigInfo = sigs.Value.Signatures.[0]
Expect.isSome sigInfo.Parameters "Should have parameter info"
let param = sigInfo.Parameters.Value.[0]

match param.Documentation with
| Some(U2.C1 doc) ->
Expect.isFalse
(doc.Contains("Microsoft.FSharp.Core"))
$"Parameter documentation should not contain fully-qualified names, but was: {doc}"

Expect.stringContains doc "char" "Parameter documentation should contain simplified type name 'char'"
| _ -> failwith "Expected string documentation for parameter") ]

let tests state =
serverTestList "signature help" state defaultConfigDto None (fun server ->
Expand Down