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

Complete function argument values #665

Merged
merged 29 commits into from
Dec 29, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a1c0595
add base test for what we're looking to complete
zth Dec 22, 2022
f3dbd68
add test cases and identify arguments for completion
zth Dec 22, 2022
1bbb35f
refactor in prep for reuse
zth Dec 22, 2022
3d1a03e
add utils for extracting relevant completion information from type expr
zth Dec 22, 2022
06e25c7
complete bools as arguments
zth Dec 22, 2022
284ecb4
remove things from type extraction that will be added in separate PRs
zth Dec 23, 2022
ecc1693
complete regular variants
zth Dec 23, 2022
8fb62d3
add failing tests for optionals
zth Dec 23, 2022
0546ce4
basic completion for opts
zth Dec 23, 2022
ac348bb
expand options where it makes sense
zth Dec 23, 2022
379dd1a
remove unused test case
zth Dec 23, 2022
7b66a3d
make sure payloads (with any as placeholder) are printed for each con…
zth Dec 23, 2022
840cdb5
add failing test demonstrating issue with parser
zth Dec 23, 2022
8ec981a
include local values and modules in type based completions when there…
zth Dec 23, 2022
8d261be
fix full variant completion item text
zth Dec 25, 2022
6d10c56
add more cases to tests
zth Dec 25, 2022
17832b5
add = as trigger character for completion
zth Dec 25, 2022
f0e894e
cleanup
zth Dec 25, 2022
41191a8
cleanup
zth Dec 25, 2022
8755a92
comment + clarify prop name
zth Dec 25, 2022
aebffa4
polish test output a bit
zth Dec 25, 2022
e5a0950
only pick up regular Lident
zth Dec 25, 2022
8d81bc8
use env where completion started to populate values and module comple…
zth Dec 27, 2022
9856c30
common filter
zth Dec 27, 2022
2216856
fix triggering value completion vs named arg ambiguity
zth Dec 27, 2022
0774fc0
handle piped fn calls properly
zth Dec 27, 2022
619d7ec
move broken parser cases to its own file
zth Dec 28, 2022
5995f45
only expand options on optional arguments, not all labelled arguments
zth Dec 28, 2022
0f62611
add changelog
zth Dec 29, 2022
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
Prev Previous commit
Next Next commit
add test cases and identify arguments for completion
  • Loading branch information
zth committed Dec 29, 2022
commit f3dbd6885fb8c64958e13cebbef117cfaadd7b08
1 change: 1 addition & 0 deletions analysis/src/CompletionBackEnd.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1817,6 +1817,7 @@ Note: The `@react.component` decorator requires the react-jsx config to be set i
in
(dec2, doc))
|> List.map mkDecorator
| Cargument _ -> []
| CnamedArg (cp, prefix, identsSeen) ->
let labels =
match
Expand Down
61 changes: 54 additions & 7 deletions analysis/src/CompletionFrontEnd.ml
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,17 @@ let extractJsxProps ~(compName : Longident.t Location.loc) ~args =
in
args |> processProps ~acc:[]

let findNamedArgCompletable ~(args : arg list) ~endPos ~posBeforeCursor
let extractCompletableArgValueInfo exp =
match exp.Parsetree.pexp_desc with
| Pexp_ident {txt} -> Some (Utils.flattenLongIdent txt |> List.hd)
| _ -> None

let isExprHole exp =
match exp.Parsetree.pexp_desc with
| Pexp_extension ({txt = "rescript.exprhole"}, _) -> true
| _ -> false

let findArgCompletables ~(args : arg list) ~endPos ~posBeforeCursor
~(contextPath : Completable.contextPath) ~posAfterFunExpr =
let allNames =
List.fold_right
Expand All @@ -116,18 +126,55 @@ let findNamedArgCompletable ~(args : arg list) ~endPos ~posBeforeCursor
| {label = None} -> allLabels)
args []
in
let unlabelledCount = ref 0 in
let rec loop args =
match args with
| {label = Some labelled; exp} :: rest ->
if
labelled.posStart <= posBeforeCursor
&& posBeforeCursor < labelled.posEnd
then Some (Completable.CnamedArg (contextPath, labelled.name, allNames))
else if exp.pexp_loc |> Loc.hasPos ~pos:posBeforeCursor then None
else if exp.pexp_loc |> Loc.hasPos ~pos:posBeforeCursor then
(* Completing in the assignment of labelled argument *)
match extractCompletableArgValueInfo exp with
| None -> None
| Some prefix ->
Some
(Cargument
{contextPath; argumentLabel = Labelled labelled.name; prefix})
else if isExprHole exp then
Some
(Cargument
{contextPath; argumentLabel = Labelled labelled.name; prefix = ""})
else loop rest
| {label = None; exp} :: rest ->
if exp.pexp_loc |> Loc.hasPos ~pos:posBeforeCursor then None
else loop rest
(* TODO: Better guard for this... This is so completion does not trigger
inside of template string calls, which are regular calls *)
if Res_parsetree_viewer.isTemplateLiteral exp then None
else if exp.pexp_loc |> Loc.hasPos ~pos:posBeforeCursor then
(* Completing in an unlabelled argument *)
match extractCompletableArgValueInfo exp with
| None -> None
| Some prefix ->
Some
(Cargument
{
contextPath;
argumentLabel =
Unlabelled {argumentPosition = !unlabelledCount};
prefix;
})
else if isExprHole exp then
Some
(Cargument
{
contextPath;
argumentLabel = Unlabelled {argumentPosition = !unlabelledCount};
prefix = "";
})
else (
unlabelledCount := !unlabelledCount + 1;
loop rest)
| [] ->
if posAfterFunExpr <= posBeforeCursor && posBeforeCursor < endPos then
Some (CnamedArg (contextPath, "", allNames))
Expand Down Expand Up @@ -578,16 +625,16 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor ~text =
(Loc.toString exp.pexp_loc))
|> String.concat ", ");

let namedArgCompletable =
let argCompletable =
match exprToContextPath funExpr with
| Some contextPath ->
findNamedArgCompletable ~contextPath ~args
findArgCompletables ~contextPath ~args
~endPos:(Loc.end_ expr.pexp_loc) ~posBeforeCursor
~posAfterFunExpr:(Loc.end_ funExpr.pexp_loc)
| None -> None
in

setResultOpt namedArgCompletable
setResultOpt argCompletable
| Pexp_send (lhs, {txt; loc}) -> (
(* e["txt"]
If the string for txt is not closed, it could go over several lines.
Expand Down
17 changes: 17 additions & 0 deletions analysis/src/SharedTypes.ml
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,10 @@ module Completable = struct
(* Completion context *)
type completionContext = Type | Value | Module | Field

type argumentLabel =
| Unlabelled of {argumentPosition: int}
| Labelled of string

type contextPath =
| CPString
| CPArray
Expand All @@ -526,6 +530,11 @@ module Completable = struct
| Cpath of contextPath
| Cjsx of string list * string * string list
(** E.g. (["M", "Comp"], "id", ["id1", "id2"]) for <M.Comp id1=... id2=... ... id *)
| Cargument of {
contextPath: contextPath;
argumentLabel: argumentLabel;
prefix: string;
}

let toString =
let completionContextToString = function
Expand Down Expand Up @@ -564,6 +573,14 @@ module Completable = struct
| Cnone -> "Cnone"
| Cjsx (sl1, s, sl2) ->
"Cjsx(" ^ (sl1 |> list) ^ ", " ^ str s ^ ", " ^ (sl2 |> list) ^ ")"
| Cargument {contextPath; argumentLabel; prefix} ->
contextPathToString contextPath
^ "("
^ (match argumentLabel with
| Unlabelled {argumentPosition} -> "$" ^ string_of_int argumentPosition
| Labelled name -> "~" ^ name)
^ (if prefix <> "" then "=" ^ prefix else "")
^ ")"
end

module CursorPosition = struct
Expand Down
15 changes: 15 additions & 0 deletions analysis/tests/src/CompletionFunctionArguments.res
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,18 @@ let someFn = (~isOn) => {

// let _ = someFn(~isOn=t)
// ^com

let _ = someFn(
~isOn={
// switch someFn(~isOn=)
// ^com
true
},
)

let someOtherFn = (includeName, age) => {
"Hello" ++ (includeName ? " Some Name" : "") ++ ", you are age " ++ Belt.Int.toString(age)
}

// let _ = someOtherFn(t)
// ^com
23 changes: 18 additions & 5 deletions analysis/tests/src/expected/CompletionFunctionArguments.res.txt
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
Complete src/CompletionFunctionArguments.res 8:24
posCursor:[8:24] posNoWhite:[8:23] Found expr:[8:11->8:25]
Pexp_apply ...[8:11->8:17] (~isOn8:19->8:23=...__ghost__[0:-1->0:-1])
Completable: CnamedArg(Value[someFn], "", [isOn])
Found type for function (~isOn: bool) => string
Completable: Value[someFn](~isOn)
[]

Complete src/CompletionFunctionArguments.res 11:25
posCursor:[11:25] posNoWhite:[11:24] Found expr:[11:11->11:26]
Pexp_apply ...[11:11->11:17] (~isOn11:19->11:23=...[11:24->11:25])
posCursor:[11:25] posNoWhite:[11:24] Found expr:[11:24->11:25]
Pexp_ident t:[11:24->11:25]
Completable: Cpath Value[t]
Completable: Value[someFn](~isOn=t)
[]

Complete src/CompletionFunctionArguments.res 16:27
posCursor:[16:27] posNoWhite:[16:26] Found expr:[14:8->20:1]
Pexp_apply ...[14:8->14:14] (~isOn15:3->15:7=...[16:7->18:8])
posCursor:[16:27] posNoWhite:[16:26] Found expr:[16:7->18:8]
posCursor:[16:27] posNoWhite:[16:26] Found expr:[16:7->16:28]
posCursor:[16:27] posNoWhite:[16:26] Found expr:[16:14->16:28]
Pexp_apply ...[16:14->16:20] (~isOn16:22->16:26=...__ghost__[0:-1->0:-1])
Completable: Value[someFn](~isOn)
[]

Complete src/CompletionFunctionArguments.res 26:24
posCursor:[26:24] posNoWhite:[26:23] Found expr:[26:11->26:25]
Pexp_apply ...[26:11->26:22] (...[26:23->26:24])
Completable: Value[someOtherFn]($0=t)
[]