Skip to content

Commit 799bf02

Browse files
zthcristianoc
authored andcommitted
add (mostly working) moving into function arguments
1 parent 30296e7 commit 799bf02

File tree

7 files changed

+166
-21
lines changed

7 files changed

+166
-21
lines changed

analysis/src/Cfg.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
let supportsSnippets = ref false
22

3-
let debugFollowCtxPath = false
3+
let debugFollowCtxPath = ref false

analysis/src/CompletionBackEnd.ml

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,12 +1023,14 @@ and getCompletionsForContextPath ~full ~opens ~rawOpens ~allFiles ~pos ~env
10231023
let targetLabel =
10241024
labels
10251025
|> List.find_opt (fun (label, _) ->
1026-
match argumentLabel with
1027-
| Unlabelled _ -> label = argumentLabel
1028-
| Labelled name | Optional name -> (
1029-
match label with
1030-
| (Labelled n | Optional n) when name = n -> true
1031-
| _ -> false))
1026+
match (argumentLabel, label) with
1027+
| ( Unlabelled {argumentPosition = pos1},
1028+
Completable.Unlabelled {argumentPosition = pos2} ) ->
1029+
pos1 = pos2
1030+
| ( (Labelled name1 | Optional name1),
1031+
(Labelled name2 | Optional name2) ) ->
1032+
name1 = name2
1033+
| _ -> false)
10321034
in
10331035
let expandOption =
10341036
match targetLabel with

analysis/src/CompletionFrontEnd.ml

Lines changed: 89 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,25 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor ~text =
258258
Utils.flattenLongIdent ~cutAtOffset ~jsx lid.txt
259259
in
260260

261+
let currentCtxPath = ref None in
262+
let setCurrentCtxPath ctxPath =
263+
if !Cfg.debugFollowCtxPath then
264+
Printf.printf "setting current ctxPath: %s\n"
265+
(Completable.contextPathToString ctxPath);
266+
currentCtxPath := Some ctxPath
267+
in
268+
let resetCurrentCtxPath ctxPath =
269+
(match (!currentCtxPath, ctxPath) with
270+
| None, None -> ()
271+
| _ ->
272+
if !Cfg.debugFollowCtxPath then
273+
Printf.printf "resetting current ctxPath to: %s\n"
274+
(match ctxPath with
275+
| None -> "None"
276+
| Some ctxPath -> Completable.contextPathToString ctxPath));
277+
currentCtxPath := ctxPath
278+
in
279+
261280
let found = ref false in
262281
let result = ref None in
263282
let scope = ref (Scope.create ()) in
@@ -443,7 +462,7 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor ~text =
443462

444463
let case (iterator : Ast_iterator.iterator) (case : Parsetree.case) =
445464
let oldScope = !scope in
446-
scopePattern case.pc_lhs;
465+
scopePattern ?contextPath:!currentCtxPath case.pc_lhs;
447466
completePattern case.pc_lhs;
448467
Ast_iterator.default_iterator.case iterator case;
449468
scope := oldScope
@@ -619,7 +638,34 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor ~text =
619638
| _ -> ());
620639
Ast_iterator.default_iterator.attribute iterator (id, payload)
621640
in
622-
let expr (iterator : Ast_iterator.iterator) (expr : Parsetree.expression) =
641+
let rec iterateFnArguments ~args ~iterator ~isPipe
642+
(argCompletable : Completable.t option) =
643+
match argCompletable with
644+
| None -> (
645+
match !currentCtxPath with
646+
| None -> ()
647+
| Some functionContextPath ->
648+
let currentUnlabelledCount = ref (if isPipe then 1 else 0) in
649+
args
650+
|> List.iter (fun (arg : arg) ->
651+
let previousCtxPath = !currentCtxPath in
652+
setCurrentCtxPath
653+
(CArgument
654+
{
655+
functionContextPath;
656+
argumentLabel =
657+
(match arg with
658+
| {label = None} ->
659+
let current = !currentUnlabelledCount in
660+
currentUnlabelledCount := current + 1;
661+
Unlabelled {argumentPosition = current}
662+
| {label = Some {name; opt = true}} -> Optional name
663+
| {label = Some {name; opt = false}} -> Labelled name);
664+
});
665+
expr iterator arg.exp;
666+
resetCurrentCtxPath previousCtxPath))
667+
| Some argCompletable -> setResult argCompletable
668+
and expr (iterator : Ast_iterator.iterator) (expr : Parsetree.expression) =
623669
let oldInJsxContext = !inJsxContext in
624670
let processed = ref false in
625671
let setFound () =
@@ -773,7 +819,7 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor ~text =
773819
But it should not fire in foo(~a)<---there *)
774820
not
775821
(Loc.end_ expr.pexp_loc = posCursor
776-
&& charBeforeCursor = Some ')') ->
822+
&& charBeforeCursor = Some ')') -> (
777823
(* Complete fn argument values and named args when the fn call is piped. E.g. someVar->someFn(<com>). *)
778824
let args = extractExpApplyArgs ~args in
779825
let argCompletable =
@@ -786,15 +832,23 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor ~text =
786832
~firstCharBeforeCursorNoWhite
787833
| None -> None
788834
in
789-
790-
setResultOpt argCompletable
835+
match argCompletable with
836+
| None -> (
837+
match exprToContextPath funExpr with
838+
| None -> ()
839+
| Some funCtxPath ->
840+
let oldCtxPath = !currentCtxPath in
841+
setCurrentCtxPath funCtxPath;
842+
argCompletable |> iterateFnArguments ~isPipe:true ~args ~iterator;
843+
resetCurrentCtxPath oldCtxPath)
844+
| Some argCompletable -> setResult argCompletable)
791845
| Pexp_apply ({pexp_desc = Pexp_ident {txt = Lident "|."}}, [_; _]) ->
792846
(* Ignore any other pipe. *)
793847
()
794848
| Pexp_apply (funExpr, args)
795849
when not
796850
(Loc.end_ expr.pexp_loc = posCursor
797-
&& charBeforeCursor = Some ')') ->
851+
&& charBeforeCursor = Some ')') -> (
798852
(* Complete fn argument values and named args when the fn call is _not_ piped. E.g. someFn(<com>). *)
799853
let args = extractExpApplyArgs ~args in
800854
if debug then
@@ -822,8 +876,16 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor ~text =
822876
~firstCharBeforeCursorNoWhite
823877
| None -> None
824878
in
825-
826-
setResultOpt argCompletable
879+
match argCompletable with
880+
| None -> (
881+
match exprToContextPath funExpr with
882+
| None -> ()
883+
| Some funCtxPath ->
884+
let oldCtxPath = !currentCtxPath in
885+
setCurrentCtxPath funCtxPath;
886+
argCompletable |> iterateFnArguments ~isPipe:false ~args ~iterator;
887+
resetCurrentCtxPath oldCtxPath)
888+
| Some argCompletable -> setResult argCompletable)
827889
| Pexp_send (lhs, {txt; loc}) -> (
828890
(* e["txt"]
829891
If the string for txt is not closed, it could go over several lines.
@@ -850,16 +912,33 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor ~text =
850912
match exprToContextPath lhs with
851913
| Some contextPath -> setResult (Cpath (CPObj (contextPath, label)))
852914
| None -> ())
853-
| Pexp_fun (_lbl, defaultExpOpt, pat, e) ->
915+
| Pexp_fun (lbl, defaultExpOpt, pat, e) ->
854916
let oldScope = !scope in
917+
let oldCtxPath = !currentCtxPath in
918+
(* TODO: Haven't figured out how to count unlabelled args here yet... *)
919+
(* TODO: This is broken *)
920+
(match !currentCtxPath with
921+
| None -> ()
922+
| Some ctxPath ->
923+
setCurrentCtxPath
924+
(CArgument
925+
{
926+
functionContextPath = ctxPath;
927+
argumentLabel =
928+
(match lbl with
929+
| Nolabel -> Unlabelled {argumentPosition = 0}
930+
| Optional name -> Optional name
931+
| Labelled name -> Labelled name);
932+
}));
855933
(match defaultExpOpt with
856934
| None -> ()
857935
| Some defaultExp -> iterator.expr iterator defaultExp);
858-
scopePattern pat;
936+
scopePattern ?contextPath:!currentCtxPath pat;
859937
completePattern pat;
860938
iterator.pat iterator pat;
861939
iterator.expr iterator e;
862940
scope := oldScope;
941+
resetCurrentCtxPath oldCtxPath;
863942
processed := true
864943
| Pexp_let (recFlag, bindings, e) ->
865944
let oldScope = !scope in

analysis/src/Scope.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ let addField ~name ~loc x = Field (name, loc) :: x
2626
let addModule ~name ~loc x = Module (name, loc) :: x
2727
let addOpen ~lid x = Open (Utils.flattenLongIdent lid @ ["place holder"]) :: x
2828
let addValue ~name ~loc ?contextPath x =
29-
let showDebug = Cfg.debugFollowCtxPath in
29+
let showDebug = !Cfg.debugFollowCtxPath in
3030
(if showDebug then
3131
match contextPath with
3232
| None -> Printf.printf "adding value '%s', no ctxPath\n" name

analysis/tests/src/CompletionInferValues.res

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ let someFnWithCallback = (cb: (~num: int, ~someRecord: someRecord, ~isOn: bool)
77
let _ = cb
88
}
99

10-
let reactEventFn = (cb: someRecord => unit) => {
10+
let reactEventFn = (cb: ReactEvent.Mouse.t => unit) => {
1111
let _ = cb
1212
}
1313

@@ -21,3 +21,13 @@ let reactEventFn = (cb: someRecord => unit) => {
2121

2222
// let x = getSomeRecord(); let aliased = x; aliased.
2323
// ^com
24+
25+
// someFnWithCallback((~someRecord, ~num, ~isOn) => someRecord.)
26+
// ^com
27+
28+
// Broken because not using the first argument (argument context seems to pile on when they should be plucked off and new one added)
29+
// let aliasedFn = someFnWithCallback; aliasedFn((~num, ~someRecord, ~isOn) => someRecord.)
30+
// ^com
31+
32+
// reactEventFn(event => { event->pr });
33+
// ^com

analysis/tests/src/expected/CompletionInferValues.res.txt

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Completable: Cpath Value[aliased]->f
1717

1818
Complete src/CompletionInferValues.res 18:30
1919
posCursor:[18:30] posNoWhite:[18:29] Found expr:[18:28->18:30]
20-
Pexp_field [18:28->18:29] _:[24:0->18:30]
20+
Pexp_field [18:28->18:29] _:[34:0->18:30]
2121
Completable: Cpath Value[x].""
2222
[{
2323
"label": "name",
@@ -35,7 +35,7 @@ Completable: Cpath Value[x].""
3535

3636
Complete src/CompletionInferValues.res 21:53
3737
posCursor:[21:53] posNoWhite:[21:52] Found expr:[21:45->21:53]
38-
Pexp_field [21:45->21:52] _:[24:0->21:53]
38+
Pexp_field [21:45->21:52] _:[34:0->21:53]
3939
Completable: Cpath Value[aliased].""
4040
[{
4141
"label": "name",
@@ -51,3 +51,51 @@ Completable: Cpath Value[aliased].""
5151
"documentation": null
5252
}]
5353

54+
Complete src/CompletionInferValues.res 24:63
55+
posCursor:[24:63] posNoWhite:[24:62] Found expr:[24:3->24:64]
56+
Pexp_apply ...[24:3->24:21] (...[24:22->24:63])
57+
posCursor:[24:63] posNoWhite:[24:62] Found expr:[24:22->24:63]
58+
posCursor:[24:63] posNoWhite:[24:62] Found expr:[24:36->24:63]
59+
posCursor:[24:63] posNoWhite:[24:62] Found expr:[24:42->24:63]
60+
posCursor:[24:63] posNoWhite:[24:62] Found expr:[24:52->24:63]
61+
Pexp_field [24:52->24:62] _:[24:63->24:63]
62+
Completable: Cpath Value[someRecord].""
63+
[{
64+
"label": "name",
65+
"kind": 5,
66+
"tags": [],
67+
"detail": "name: string\n\ntype someRecord = {name: string, age: int}",
68+
"documentation": null
69+
}, {
70+
"label": "age",
71+
"kind": 5,
72+
"tags": [],
73+
"detail": "age: int\n\ntype someRecord = {name: string, age: int}",
74+
"documentation": null
75+
}]
76+
77+
Complete src/CompletionInferValues.res 28:90
78+
posCursor:[28:90] posNoWhite:[28:89] Found expr:[28:39->28:91]
79+
Pexp_apply ...[28:39->28:48] (...[28:49->28:90])
80+
posCursor:[28:90] posNoWhite:[28:89] Found expr:[28:49->28:90]
81+
posCursor:[28:90] posNoWhite:[28:89] Found expr:[28:56->28:90]
82+
posCursor:[28:90] posNoWhite:[28:89] Found expr:[28:69->28:90]
83+
posCursor:[28:90] posNoWhite:[28:89] Found expr:[28:79->28:90]
84+
Pexp_field [28:79->28:89] _:[28:90->28:90]
85+
Completable: Cpath Value[someRecord].""
86+
[]
87+
88+
Complete src/CompletionInferValues.res 31:36
89+
posCursor:[31:36] posNoWhite:[31:35] Found expr:[31:3->31:39]
90+
Pexp_apply ...[31:3->31:15] (...[31:16->31:38])
91+
posCursor:[31:36] posNoWhite:[31:35] Found expr:[31:16->31:38]
92+
posCursor:[31:36] posNoWhite:[31:35] Found expr:[31:27->31:36]
93+
Completable: Cpath Value[event]->pr
94+
[{
95+
"label": "ReactEvent.Mouse.preventDefault",
96+
"kind": 12,
97+
"tags": [],
98+
"detail": "t => unit",
99+
"documentation": null
100+
}]
101+

analysis/tests/src/expected/Jsx2.res.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,12 @@ posCursor:[80:6] posNoWhite:[80:5] Found expr:[80:5->83:20]
257257
Pexp_construct :::[83:0->83:20] [83:0->83:20]
258258
posCursor:[80:6] posNoWhite:[80:5] Found expr:__ghost__[80:5->83:20]
259259
Pexp_construct []:__ghost__[80:5->83:20] None
260+
posCursor:[80:6] posNoWhite:[80:5] Found expr:[80:4->83:19]
261+
JSX <M:[80:4->80:5] > _children:80:5
262+
posCursor:[80:6] posNoWhite:[80:5] Found expr:[80:5->83:20]
263+
Pexp_construct :::[83:0->83:20] [83:0->83:20]
264+
posCursor:[80:6] posNoWhite:[80:5] Found expr:__ghost__[80:5->83:20]
265+
Pexp_construct []:__ghost__[80:5->83:20] None
260266
[]
261267

262268
Complete src/Jsx2.res 89:16

0 commit comments

Comments
 (0)