@@ -15,21 +15,31 @@ let findArgCompletables ~(args : arg list) ~endPos ~posBeforeCursor
1515 args []
1616 in
1717 let unlabelledCount = ref (if isPipedExpr then 1 else 0 ) in
18+ let someArgHadEmptyExprLoc = ref false in
1819 let rec loop args =
1920 match args with
2021 | {label = Some labelled ; exp} :: rest ->
2122 if
2223 labelled.posStart < = posBeforeCursor
2324 && 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" ;
2734 match
2835 CompletionExpressions. traverseExpr exp ~expr Path:[]
2936 ~pos: posBeforeCursor ~first CharBeforeCursorNoWhite
3037 with
3138 | None -> None
3239 | Some (prefix , nested ) ->
40+ if Debug. verbose () then
41+ print_endline
42+ " [findArgCompletables] Completing for labelled argument value" ;
3343 Some
3444 (Cexpression
3545 {
@@ -41,8 +51,10 @@ let findArgCompletables ~(args : arg list) ~endPos ~posBeforeCursor
4151 };
4252 prefix;
4353 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" ;
4658 Some
4759 (Cexpression
4860 {
@@ -54,18 +66,35 @@ let findArgCompletables ~(args : arg list) ~endPos ~posBeforeCursor
5466 };
5567 prefix = " " ;
5668 nested = [] ;
57- })
69+ }))
5870 else loop rest
5971 | {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+
6080 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" ;
6385 match
6486 CompletionExpressions. traverseExpr exp ~pos: posBeforeCursor
6587 ~first CharBeforeCursorNoWhite ~expr Path:[]
6688 with
67- | None -> None
89+ | None ->
90+ if Debug. verbose () then
91+ print_endline
92+ " [findArgCompletables] found nothing when traversing expr" ;
93+ None
6894 | Some (prefix , nested ) ->
95+ if Debug. verbose () then
96+ print_endline
97+ " [findArgCompletables] completing for unlabelled argument #2" ;
6998 Some
7099 (Cexpression
71100 {
@@ -78,8 +107,10 @@ let findArgCompletables ~(args : arg list) ~endPos ~posBeforeCursor
78107 };
79108 prefix;
80109 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" ;
83114 Some
84115 (Cexpression
85116 {
@@ -92,15 +123,45 @@ let findArgCompletables ~(args : arg list) ~endPos ~posBeforeCursor
92123 };
93124 prefix = " " ;
94125 nested = [] ;
95- })
126+ }))
96127 else (
97128 unlabelledCount := ! unlabelledCount + 1 ;
98129 loop rest)
99130 | [] ->
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" ;
101135 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
103158 | _ ->
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;
104165 Some
105166 (Cexpression
106167 {
@@ -113,7 +174,7 @@ let findArgCompletables ~(args : arg list) ~endPos ~posBeforeCursor
113174 };
114175 prefix = " " ;
115176 nested = [] ;
116- })
177+ }))
117178 else None
118179 in
119180 match args with
@@ -122,6 +183,8 @@ let findArgCompletables ~(args : arg list) ~endPos ~posBeforeCursor
122183 {label = None ; exp = {pexp_desc = Pexp_construct ({txt = Lident " ()" }, _)}};
123184 ]
124185 when fnHasCursor ->
186+ if Debug. verbose () then
187+ print_endline " [findArgCompletables] Completing for unit argument" ;
125188 Some
126189 (Completable. Cexpression
127190 {
@@ -305,8 +368,16 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor
305368 let setResultOpt x =
306369 if ! result = None then
307370 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)
310381 in
311382 let setResult x = setResultOpt (Some x) in
312383 let scopeValueDescription (vd : Parsetree.value_description ) =
@@ -965,13 +1036,13 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor
9651036 (_, {pexp_desc = Pexp_ident {txt = Longident. Lident id; loc}});
9661037 ] )
9671038 when loc |> Loc. hasPos ~pos: posBeforeCursor ->
968- (* Case foo->id *)
1039+ if Debug. verbose () then print_endline " [expr_iter] Case foo->id" ;
9691040 setPipeResult ~lhs ~id |> ignore
9701041 | Pexp_apply
9711042 ( {pexp_desc = Pexp_ident {txt = Lident (" |." | " |.u" ); loc = opLoc}},
9721043 [(_, lhs); _] )
9731044 when Loc. end_ opLoc = posCursor ->
974- (* Case foo-> *)
1045+ if Debug. verbose () then print_endline " [expr_iter] Case foo->" ;
9751046 setPipeResult ~lhs ~id: " " |> ignore
9761047 | Pexp_apply
9771048 ( {pexp_desc = Pexp_ident {txt = Lident (" |." | " |.u" )}},
@@ -983,6 +1054,8 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor
9831054 (Loc. end_ expr.pexp_loc = posCursor
9841055 && charBeforeCursor = Some ')' ) -> (
9851056 (* 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)" ;
9861059 let args = extractExpApplyArgs ~args in
9871060 let funCtxPath = exprToContextPath funExpr in
9881061 let argCompletable =
@@ -1014,6 +1087,8 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor
10141087 (Loc. end_ expr.pexp_loc = posCursor
10151088 && charBeforeCursor = Some ')' ) -> (
10161089 (* 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)" ;
10171092 let args = extractExpApplyArgs ~args in
10181093 if debug then
10191094 Printf. printf " Pexp_apply ...%s (%s)\n "
@@ -1090,6 +1165,8 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor
10901165 match lbl with
10911166 | Nolabel -> Some (ctxPath, currentUnlabelledCount + 1 )
10921167 | _ -> Some (ctxPath, currentUnlabelledCount));
1168+ if Debug. verbose () then
1169+ print_endline " [expr_iter] Completing for argument value" ;
10931170 Some
10941171 (Completable. CArgument
10951172 {
0 commit comments