Skip to content

Commit 5625b60

Browse files
committed
add test cases and identify arguments for completion
1 parent 7f11744 commit 5625b60

File tree

5 files changed

+105
-12
lines changed

5 files changed

+105
-12
lines changed

analysis/src/CompletionBackEnd.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1817,6 +1817,7 @@ Note: The `@react.component` decorator requires the react-jsx config to be set i
18171817
in
18181818
(dec2, doc))
18191819
|> List.map mkDecorator
1820+
| Cargument _ -> []
18201821
| CnamedArg (cp, prefix, identsSeen) ->
18211822
let labels =
18221823
match

analysis/src/CompletionFrontEnd.ml

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,17 @@ let extractJsxProps ~(compName : Longident.t Location.loc) ~args =
106106
in
107107
args |> processProps ~acc:[]
108108

109-
let findNamedArgCompletable ~(args : arg list) ~endPos ~posBeforeCursor
109+
let extractCompletableArgValueInfo exp =
110+
match exp.Parsetree.pexp_desc with
111+
| Pexp_ident {txt} -> Some (Utils.flattenLongIdent txt |> List.hd)
112+
| _ -> None
113+
114+
let isExprHole exp =
115+
match exp.Parsetree.pexp_desc with
116+
| Pexp_extension ({txt = "rescript.exprhole"}, _) -> true
117+
| _ -> false
118+
119+
let findArgCompletables ~(args : arg list) ~endPos ~posBeforeCursor
110120
~(contextPath : Completable.contextPath) ~posAfterFunExpr =
111121
let allNames =
112122
List.fold_right
@@ -116,18 +126,55 @@ let findNamedArgCompletable ~(args : arg list) ~endPos ~posBeforeCursor
116126
| {label = None} -> allLabels)
117127
args []
118128
in
129+
let unlabelledCount = ref 0 in
119130
let rec loop args =
120131
match args with
121132
| {label = Some labelled; exp} :: rest ->
122133
if
123134
labelled.posStart <= posBeforeCursor
124135
&& posBeforeCursor < labelled.posEnd
125136
then Some (Completable.CnamedArg (contextPath, labelled.name, allNames))
126-
else if exp.pexp_loc |> Loc.hasPos ~pos:posBeforeCursor then None
137+
else if exp.pexp_loc |> Loc.hasPos ~pos:posBeforeCursor then
138+
(* Completing in the assignment of labelled argument *)
139+
match extractCompletableArgValueInfo exp with
140+
| None -> None
141+
| Some prefix ->
142+
Some
143+
(Cargument
144+
{contextPath; argumentLabel = Labelled labelled.name; prefix})
145+
else if isExprHole exp then
146+
Some
147+
(Cargument
148+
{contextPath; argumentLabel = Labelled labelled.name; prefix = ""})
127149
else loop rest
128150
| {label = None; exp} :: rest ->
129-
if exp.pexp_loc |> Loc.hasPos ~pos:posBeforeCursor then None
130-
else loop rest
151+
(* TODO: Better guard for this... This is so completion does not trigger
152+
inside of template string calls, which are regular calls *)
153+
if Res_parsetree_viewer.isTemplateLiteral exp then None
154+
else if exp.pexp_loc |> Loc.hasPos ~pos:posBeforeCursor then
155+
(* Completing in an unlabelled argument *)
156+
match extractCompletableArgValueInfo exp with
157+
| None -> None
158+
| Some prefix ->
159+
Some
160+
(Cargument
161+
{
162+
contextPath;
163+
argumentLabel =
164+
Unlabelled {argumentPosition = !unlabelledCount};
165+
prefix;
166+
})
167+
else if isExprHole exp then
168+
Some
169+
(Cargument
170+
{
171+
contextPath;
172+
argumentLabel = Unlabelled {argumentPosition = !unlabelledCount};
173+
prefix = "";
174+
})
175+
else (
176+
unlabelledCount := !unlabelledCount + 1;
177+
loop rest)
131178
| [] ->
132179
if posAfterFunExpr <= posBeforeCursor && posBeforeCursor < endPos then
133180
Some (CnamedArg (contextPath, "", allNames))
@@ -578,16 +625,16 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor ~text =
578625
(Loc.toString exp.pexp_loc))
579626
|> String.concat ", ");
580627

581-
let namedArgCompletable =
628+
let argCompletable =
582629
match exprToContextPath funExpr with
583630
| Some contextPath ->
584-
findNamedArgCompletable ~contextPath ~args
631+
findArgCompletables ~contextPath ~args
585632
~endPos:(Loc.end_ expr.pexp_loc) ~posBeforeCursor
586633
~posAfterFunExpr:(Loc.end_ funExpr.pexp_loc)
587634
| None -> None
588635
in
589636

590-
setResultOpt namedArgCompletable
637+
setResultOpt argCompletable
591638
| Pexp_send (lhs, {txt; loc}) -> (
592639
(* e["txt"]
593640
If the string for txt is not closed, it could go over several lines.

analysis/src/SharedTypes.ml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,10 @@ module Completable = struct
502502
(* Completion context *)
503503
type completionContext = Type | Value | Module | Field
504504

505+
type argumentLabel =
506+
| Unlabelled of {argumentPosition: int}
507+
| Labelled of string
508+
505509
type contextPath =
506510
| CPString
507511
| CPArray
@@ -526,6 +530,11 @@ module Completable = struct
526530
| Cpath of contextPath
527531
| Cjsx of string list * string * string list
528532
(** E.g. (["M", "Comp"], "id", ["id1", "id2"]) for <M.Comp id1=... id2=... ... id *)
533+
| Cargument of {
534+
contextPath: contextPath;
535+
argumentLabel: argumentLabel;
536+
prefix: string;
537+
}
529538

530539
let toString =
531540
let completionContextToString = function
@@ -564,6 +573,14 @@ module Completable = struct
564573
| Cnone -> "Cnone"
565574
| Cjsx (sl1, s, sl2) ->
566575
"Cjsx(" ^ (sl1 |> list) ^ ", " ^ str s ^ ", " ^ (sl2 |> list) ^ ")"
576+
| Cargument {contextPath; argumentLabel; prefix} ->
577+
contextPathToString contextPath
578+
^ "("
579+
^ (match argumentLabel with
580+
| Unlabelled {argumentPosition} -> "$" ^ string_of_int argumentPosition
581+
| Labelled name -> "~" ^ name)
582+
^ (if prefix <> "" then "=" ^ prefix else "")
583+
^ ")"
567584
end
568585

569586
module CursorPosition = struct

analysis/tests/src/CompletionFunctionArguments.res

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,18 @@ let someFn = (~isOn) => {
1111

1212
// let _ = someFn(~isOn=t)
1313
// ^com
14+
15+
let _ = someFn(
16+
~isOn={
17+
// switch someFn(~isOn=)
18+
// ^com
19+
true
20+
},
21+
)
22+
23+
let someOtherFn = (includeName, age) => {
24+
"Hello" ++ (includeName ? " Some Name" : "") ++ ", you are age " ++ Belt.Int.toString(age)
25+
}
26+
27+
// let _ = someOtherFn(t)
28+
// ^com
Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,28 @@
11
Complete src/CompletionFunctionArguments.res 8:24
22
posCursor:[8:24] posNoWhite:[8:23] Found expr:[8:11->8:25]
33
Pexp_apply ...[8:11->8:17] (~isOn8:19->8:23=...__ghost__[0:-1->0:-1])
4-
Completable: CnamedArg(Value[someFn], "", [isOn])
5-
Found type for function (~isOn: bool) => string
4+
Completable: Value[someFn](~isOn)
65
[]
76

87
Complete src/CompletionFunctionArguments.res 11:25
98
posCursor:[11:25] posNoWhite:[11:24] Found expr:[11:11->11:26]
109
Pexp_apply ...[11:11->11:17] (~isOn11:19->11:23=...[11:24->11:25])
11-
posCursor:[11:25] posNoWhite:[11:24] Found expr:[11:24->11:25]
12-
Pexp_ident t:[11:24->11:25]
13-
Completable: Cpath Value[t]
10+
Completable: Value[someFn](~isOn=t)
11+
[]
12+
13+
Complete src/CompletionFunctionArguments.res 16:27
14+
posCursor:[16:27] posNoWhite:[16:26] Found expr:[14:8->20:1]
15+
Pexp_apply ...[14:8->14:14] (~isOn15:3->15:7=...[16:7->18:8])
16+
posCursor:[16:27] posNoWhite:[16:26] Found expr:[16:7->18:8]
17+
posCursor:[16:27] posNoWhite:[16:26] Found expr:[16:7->16:28]
18+
posCursor:[16:27] posNoWhite:[16:26] Found expr:[16:14->16:28]
19+
Pexp_apply ...[16:14->16:20] (~isOn16:22->16:26=...__ghost__[0:-1->0:-1])
20+
Completable: Value[someFn](~isOn)
21+
[]
22+
23+
Complete src/CompletionFunctionArguments.res 26:24
24+
posCursor:[26:24] posNoWhite:[26:23] Found expr:[26:11->26:25]
25+
Pexp_apply ...[26:11->26:22] (...[26:23->26:24])
26+
Completable: Value[someOtherFn]($0=t)
1427
[]
1528

0 commit comments

Comments
 (0)