@@ -15,21 +15,31 @@ let findArgCompletables ~(args : arg list) ~endPos ~posBeforeCursor
15
15
args []
16
16
in
17
17
let unlabelledCount = ref (if isPipedExpr then 1 else 0 ) in
18
+ let someArgHadEmptyExprLoc = ref false in
18
19
let rec loop args =
19
20
match args with
20
21
| {label = Some labelled ; exp} :: rest ->
21
22
if
22
23
labelled.posStart < = posBeforeCursor
23
24
&& posBeforeCursor < labelled.posEnd
24
- then Some (Completable. CnamedArg (contextPath, labelled.name, allNames))
25
- else if exp.pexp_loc |> Loc. hasPos ~pos: posBeforeCursor then
26
- (* Completing in the assignment of labelled argument *)
25
+ then (
26
+ if Debug. verbose () then
27
+ print_endline " [findArgCompletables] Completing named arg #2" ;
28
+ Some (Completable. CnamedArg (contextPath, labelled.name, allNames)))
29
+ else if exp.pexp_loc |> Loc. hasPos ~pos: posBeforeCursor then (
30
+ if Debug. verbose () then
31
+ print_endline
32
+ " [findArgCompletables] Completing in the assignment of labelled \
33
+ argument" ;
27
34
match
28
35
CompletionExpressions. traverseExpr exp ~expr Path:[]
29
36
~pos: posBeforeCursor ~first CharBeforeCursorNoWhite
30
37
with
31
38
| None -> None
32
39
| Some (prefix , nested ) ->
40
+ if Debug. verbose () then
41
+ print_endline
42
+ " [findArgCompletables] Completing for labelled argument value" ;
33
43
Some
34
44
(Cexpression
35
45
{
@@ -41,8 +51,10 @@ let findArgCompletables ~(args : arg list) ~endPos ~posBeforeCursor
41
51
};
42
52
prefix;
43
53
nested = List. rev nested;
44
- })
45
- else if CompletionExpressions. isExprHole exp then
54
+ }))
55
+ else if CompletionExpressions. isExprHole exp then (
56
+ if Debug. verbose () then
57
+ print_endline " [findArgCompletables] found exprhole" ;
46
58
Some
47
59
(Cexpression
48
60
{
@@ -54,18 +66,35 @@ let findArgCompletables ~(args : arg list) ~endPos ~posBeforeCursor
54
66
};
55
67
prefix = " " ;
56
68
nested = [] ;
57
- })
69
+ }))
58
70
else loop rest
59
71
| {label = None ; exp} :: rest ->
72
+ if Debug. verbose () then
73
+ Printf. printf " [findArgCompletable] unlabelled arg expr is: %s \n "
74
+ (DumpAst. printExprItem ~pos: posBeforeCursor ~indentation: 0 exp);
75
+
76
+ (* Track whether there was an arg with an empty loc (indicates parser error)*)
77
+ if CursorPosition. locIsEmpty exp.pexp_loc ~pos: posBeforeCursor then
78
+ someArgHadEmptyExprLoc := true ;
79
+
60
80
if Res_parsetree_viewer. isTemplateLiteral exp then None
61
- else if exp.pexp_loc |> Loc. hasPos ~pos: posBeforeCursor then
62
- (* Completing in an unlabelled argument *)
81
+ else if exp.pexp_loc |> Loc. hasPos ~pos: posBeforeCursor then (
82
+ if Debug. verbose () then
83
+ print_endline
84
+ " [findArgCompletables] Completing in an unlabelled argument" ;
63
85
match
64
86
CompletionExpressions. traverseExpr exp ~pos: posBeforeCursor
65
87
~first CharBeforeCursorNoWhite ~expr Path:[]
66
88
with
67
- | None -> None
89
+ | None ->
90
+ if Debug. verbose () then
91
+ print_endline
92
+ " [findArgCompletables] found nothing when traversing expr" ;
93
+ None
68
94
| Some (prefix , nested ) ->
95
+ if Debug. verbose () then
96
+ print_endline
97
+ " [findArgCompletables] completing for unlabelled argument #2" ;
69
98
Some
70
99
(Cexpression
71
100
{
@@ -78,8 +107,10 @@ let findArgCompletables ~(args : arg list) ~endPos ~posBeforeCursor
78
107
};
79
108
prefix;
80
109
nested = List. rev nested;
81
- })
82
- else if CompletionExpressions. isExprHole exp then
110
+ }))
111
+ else if CompletionExpressions. isExprHole exp then (
112
+ if Debug. verbose () then
113
+ print_endline " [findArgCompletables] found an exprhole #2" ;
83
114
Some
84
115
(Cexpression
85
116
{
@@ -92,15 +123,45 @@ let findArgCompletables ~(args : arg list) ~endPos ~posBeforeCursor
92
123
};
93
124
prefix = " " ;
94
125
nested = [] ;
95
- })
126
+ }))
96
127
else (
97
128
unlabelledCount := ! unlabelledCount + 1 ;
98
129
loop rest)
99
130
| [] ->
100
- if fnHasCursor then
131
+ let hadEmptyExpLoc = ! someArgHadEmptyExprLoc in
132
+ if fnHasCursor then (
133
+ if Debug. verbose () then
134
+ print_endline " [findArgCompletables] Function has cursor" ;
101
135
match charBeforeCursor with
102
- | Some '~' -> Some (Completable. CnamedArg (contextPath, " " , allNames))
136
+ | Some '~' ->
137
+ if Debug. verbose () then
138
+ print_endline " [findArgCompletables] '~' is before cursor" ;
139
+ Some (Completable. CnamedArg (contextPath, " " , allNames))
140
+ | _ when hadEmptyExpLoc ->
141
+ (* Special case: `Console.log(arr->)`, completing on the pipe.
142
+ This match branch happens when the fn call has the cursor and:
143
+ - there's no argument label or expr that has the cursor
144
+ - there's an argument expression with an empty loc (indicates parser error)
145
+
146
+ In that case, it's safer to not complete for the unlabelled function
147
+ argument (which we do otherwise), and instead not complete and let the
148
+ completion engine move into the arguments one by one instead to check
149
+ for completions.
150
+
151
+ This can be handled in a more robust way in a future refactor of the
152
+ completion engine logic. *)
153
+ if Debug. verbose () then
154
+ print_endline
155
+ " [findArgCompletables] skipping completion in fn call because \
156
+ arg had empty loc" ;
157
+ None
103
158
| _ ->
159
+ if Debug. verbose () then
160
+ Printf. printf
161
+ " [findArgCompletables] Completing for unlabelled argument value \
162
+ because nothing matched and is not labelled argument name \
163
+ completion. isPipedExpr: %b\n "
164
+ isPipedExpr;
104
165
Some
105
166
(Cexpression
106
167
{
@@ -113,7 +174,7 @@ let findArgCompletables ~(args : arg list) ~endPos ~posBeforeCursor
113
174
};
114
175
prefix = " " ;
115
176
nested = [] ;
116
- })
177
+ }))
117
178
else None
118
179
in
119
180
match args with
@@ -122,6 +183,8 @@ let findArgCompletables ~(args : arg list) ~endPos ~posBeforeCursor
122
183
{label = None ; exp = {pexp_desc = Pexp_construct ({txt = Lident " ()" }, _)}};
123
184
]
124
185
when fnHasCursor ->
186
+ if Debug. verbose () then
187
+ print_endline " [findArgCompletables] Completing for unit argument" ;
125
188
Some
126
189
(Completable. Cexpression
127
190
{
@@ -305,8 +368,16 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor
305
368
let setResultOpt x =
306
369
if ! result = None then
307
370
match x with
308
- | None -> ()
309
- | Some x -> result := Some (x, ! scope)
371
+ | None ->
372
+ if Debug. verbose () then
373
+ print_endline
374
+ " [set_result] did not set new result because result already was set" ;
375
+ ()
376
+ | Some x ->
377
+ if Debug. verbose () then
378
+ Printf. printf " [set_result] set new result to %s\n "
379
+ (Completable. toString x);
380
+ result := Some (x, ! scope)
310
381
in
311
382
let setResult x = setResultOpt (Some x) in
312
383
let scopeValueDescription (vd : Parsetree.value_description ) =
@@ -965,13 +1036,13 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor
965
1036
(_, {pexp_desc = Pexp_ident {txt = Longident. Lident id; loc}});
966
1037
] )
967
1038
when loc |> Loc. hasPos ~pos: posBeforeCursor ->
968
- (* Case foo->id *)
1039
+ if Debug. verbose () then print_endline " [expr_iter] Case foo->id" ;
969
1040
setPipeResult ~lhs ~id |> ignore
970
1041
| Pexp_apply
971
1042
( {pexp_desc = Pexp_ident {txt = Lident (" |." | " |.u" ); loc = opLoc}},
972
1043
[(_, lhs); _] )
973
1044
when Loc. end_ opLoc = posCursor ->
974
- (* Case foo-> *)
1045
+ if Debug. verbose () then print_endline " [expr_iter] Case foo->" ;
975
1046
setPipeResult ~lhs ~id: " " |> ignore
976
1047
| Pexp_apply
977
1048
( {pexp_desc = Pexp_ident {txt = Lident (" |." | " |.u" )}},
@@ -983,6 +1054,8 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor
983
1054
(Loc. end_ expr.pexp_loc = posCursor
984
1055
&& charBeforeCursor = Some ')' ) -> (
985
1056
(* Complete fn argument values and named args when the fn call is piped. E.g. someVar->someFn(<com>). *)
1057
+ if Debug. verbose () then
1058
+ print_endline " [expr_iter] Complete fn arguments (piped)" ;
986
1059
let args = extractExpApplyArgs ~args in
987
1060
let funCtxPath = exprToContextPath funExpr in
988
1061
let argCompletable =
@@ -1014,6 +1087,8 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor
1014
1087
(Loc. end_ expr.pexp_loc = posCursor
1015
1088
&& charBeforeCursor = Some ')' ) -> (
1016
1089
(* Complete fn argument values and named args when the fn call is _not_ piped. E.g. someFn(<com>). *)
1090
+ if Debug. verbose () then
1091
+ print_endline " [expr_iter] Complete fn arguments (not piped)" ;
1017
1092
let args = extractExpApplyArgs ~args in
1018
1093
if debug then
1019
1094
Printf. printf " Pexp_apply ...%s (%s)\n "
@@ -1090,6 +1165,8 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor
1090
1165
match lbl with
1091
1166
| Nolabel -> Some (ctxPath, currentUnlabelledCount + 1 )
1092
1167
| _ -> Some (ctxPath, currentUnlabelledCount));
1168
+ if Debug. verbose () then
1169
+ print_endline " [expr_iter] Completing for argument value" ;
1093
1170
Some
1094
1171
(Completable. CArgument
1095
1172
{
0 commit comments