Skip to content

Commit 3d0a1c8

Browse files
committed
inline pipe completion logic again
1 parent 9ac0817 commit 3d0a1c8

File tree

3 files changed

+109
-112
lines changed

3 files changed

+109
-112
lines changed

analysis/src/CompletionBackEnd.ml

Lines changed: 99 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -664,112 +664,6 @@ let completionsForPipeFromCompletionPath ~envCompletionIsMadeFrom ~opens ~pos
664664
in
665665
completions
666666

667-
let getPipeCompletions ~env ~full ~identifierLoc ?posOfDot ~debug
668-
~envCompletionIsMadeFrom ~opens ~pos ~scope ~prefix ~rawOpens ~inJsx
669-
?(mainCompletionsAreSynthetic = false) ?(formatCompletionsWithPipes = false)
670-
typ =
671-
let env, typ =
672-
typ
673-
|> TypeUtils.resolveTypeForPipeCompletion ~env ~package:full.package ~full
674-
~lhsLoc:identifierLoc
675-
in
676-
let mainTypeId = TypeUtils.findRootTypeId ~full ~env typ in
677-
let typePath = TypeUtils.pathFromTypeExpr typ in
678-
match mainTypeId with
679-
| None ->
680-
if Debug.verbose () then
681-
Printf.printf
682-
"[pipe_completion] Could not find mainTypeId. Aborting pipe completions.\n";
683-
[]
684-
| Some mainTypeId ->
685-
if Debug.verbose () then
686-
Printf.printf "[pipe_completion] mainTypeId: %s\n" mainTypeId;
687-
let pipeCompletions =
688-
(* We now need a completion path from where to look up the module for our dot completion type.
689-
This is from where we pull all of the functions we want to complete for the pipe.
690-
691-
A completion path here could be one of two things:
692-
1. A module path to the main module for the type we've found
693-
2. A module path to a builtin module, like `Int` for `int`, or `Array` for `array`
694-
695-
The below code will deliberately _not_ dig into type aliases for the main type when we're looking
696-
for what _module_ to complete from. This is because you should be able to control where completions
697-
come from even if your type is an alias.
698-
*)
699-
let completeAsBuiltin =
700-
match typePath with
701-
| Some t ->
702-
TypeUtils.completionPathFromMaybeBuiltin t ~package:full.package
703-
| None -> None
704-
in
705-
let completionPath =
706-
match (completeAsBuiltin, typePath) with
707-
| Some completionPathForBuiltin, _ ->
708-
Some (false, completionPathForBuiltin)
709-
| _, Some p -> (
710-
(* If this isn't a builtin, but we have a path, we try to resolve the
711-
module path relative to the env we're completing from. This ensures that
712-
what we get here is a module path we can find completions for regardless of
713-
of the current scope for the position we're at.*)
714-
match
715-
TypeUtils.getModulePathRelativeToEnv ~debug
716-
~env:envCompletionIsMadeFrom ~envFromItem:env (Utils.expandPath p)
717-
with
718-
| None -> Some (true, [env.file.moduleName])
719-
| Some p -> Some (false, p))
720-
| _ -> None
721-
in
722-
match completionPath with
723-
| None -> []
724-
| Some (isFromCurrentModule, completionPath) ->
725-
completionsForPipeFromCompletionPath ~envCompletionIsMadeFrom ~opens
726-
~pos ~scope ~debug ~prefix ~env ~rawOpens ~full completionPath
727-
|> TypeUtils.filterPipeableFunctions ~env ~full
728-
~synthetic:mainCompletionsAreSynthetic ~targetTypeId:mainTypeId
729-
|> List.filter (fun (c : Completion.t) ->
730-
(* If we're completing from the current module then we need to care about scope.
731-
This is automatically taken care of in other cases. *)
732-
if isFromCurrentModule then
733-
match c.kind with
734-
| Value _ ->
735-
scope
736-
|> List.find_opt (fun (item : ScopeTypes.item) ->
737-
match item with
738-
| Value (scopeItemName, _, _, _) ->
739-
scopeItemName = c.name
740-
| _ -> false)
741-
|> Option.is_some
742-
| _ -> false
743-
else true)
744-
in
745-
(* Extra completions can be drawn from the @editor.completeFrom attribute. Here we
746-
find and add those completions as well. *)
747-
let extraCompletions =
748-
TypeUtils.getExtraModulesToCompleteFromForType ~env ~full typ
749-
|> List.map (fun completionPath ->
750-
completionsForPipeFromCompletionPath ~envCompletionIsMadeFrom
751-
~opens ~pos ~scope ~debug ~prefix ~env ~rawOpens ~full
752-
completionPath)
753-
|> List.flatten
754-
|> TypeUtils.filterPipeableFunctions ~synthetic:true ~env ~full
755-
~targetTypeId:mainTypeId
756-
in
757-
(* Add JSX completion items if we're in a JSX context. *)
758-
let jsxCompletions =
759-
if inJsx then
760-
PipeCompletionUtils.addJsxCompletionItems ~env ~mainTypeId ~prefix ~full
761-
~rawOpens typ
762-
else []
763-
in
764-
let allCompletions = jsxCompletions @ pipeCompletions @ extraCompletions in
765-
if formatCompletionsWithPipes then
766-
allCompletions
767-
|> List.filter_map (fun (c : Completion.t) ->
768-
c
769-
|> TypeUtils.transformCompletionToPipeCompletion ~env ?posOfDot
770-
~synthetic:c.synthetic)
771-
else allCompletions
772-
773667
let rec digToRecordFieldsForCompletion ~debug ~package ~opens ~full ~pos ~env
774668
~scope path =
775669
match
@@ -1122,6 +1016,7 @@ and getCompletionsForContextPath ~debug ~full ~opens ~rawOpens ~pos ~env ~exact
11221016
let cpAsPipeCompletion =
11231017
Completable.CPPipe
11241018
{
1019+
synthetic = true;
11251020
contextPath =
11261021
(match cp with
11271022
| CPApply (c, args) -> CPApply (c, args @ [Asttypes.Nolabel])
@@ -1165,7 +1060,7 @@ and getCompletionsForContextPath ~debug ~full ~opens ~rawOpens ~pos ~env ~exact
11651060
else None)
11661061
| None -> [])
11671062
| None -> [])
1168-
| CPPipe {contextPath = cp; id = prefix; lhsLoc; inJsx} -> (
1063+
| CPPipe {contextPath = cp; id = prefix; lhsLoc; inJsx; synthetic} -> (
11691064
if Debug.verbose () then print_endline "[ctx_path]--> CPPipe";
11701065
match
11711066
cp
@@ -1177,10 +1072,103 @@ and getCompletionsForContextPath ~debug ~full ~opens ~rawOpens ~pos ~env ~exact
11771072
if Debug.verbose () then
11781073
print_endline "[CPPipe]--> Could not resolve type env";
11791074
[]
1180-
| Some (typ, env) ->
1181-
getPipeCompletions ~env ~full ~identifierLoc:lhsLoc
1182-
~envCompletionIsMadeFrom ~debug ~opens ~rawOpens ~scope ~pos ~inJsx
1183-
~prefix typ)
1075+
| Some (typ, env) -> (
1076+
let env, typ =
1077+
typ
1078+
|> TypeUtils.resolveTypeForPipeCompletion ~env ~package:full.package
1079+
~full ~lhsLoc
1080+
in
1081+
let mainTypeId = TypeUtils.findRootTypeId ~full ~env typ in
1082+
let typePath = TypeUtils.pathFromTypeExpr typ in
1083+
match mainTypeId with
1084+
| None ->
1085+
if Debug.verbose () then
1086+
Printf.printf
1087+
"[pipe_completion] Could not find mainTypeId. Aborting pipe \
1088+
completions.\n";
1089+
[]
1090+
| Some mainTypeId ->
1091+
if Debug.verbose () then
1092+
Printf.printf "[pipe_completion] mainTypeId: %s\n" mainTypeId;
1093+
let pipeCompletions =
1094+
(* We now need a completion path from where to look up the module for our dot completion type.
1095+
This is from where we pull all of the functions we want to complete for the pipe.
1096+
1097+
A completion path here could be one of two things:
1098+
1. A module path to the main module for the type we've found
1099+
2. A module path to a builtin module, like `Int` for `int`, or `Array` for `array`
1100+
1101+
The below code will deliberately _not_ dig into type aliases for the main type when we're looking
1102+
for what _module_ to complete from. This is because you should be able to control where completions
1103+
come from even if your type is an alias.
1104+
*)
1105+
let completeAsBuiltin =
1106+
match typePath with
1107+
| Some t ->
1108+
TypeUtils.completionPathFromMaybeBuiltin t ~package:full.package
1109+
| None -> None
1110+
in
1111+
let completionPath =
1112+
match (completeAsBuiltin, typePath) with
1113+
| Some completionPathForBuiltin, _ ->
1114+
Some (false, completionPathForBuiltin)
1115+
| _, Some p -> (
1116+
(* If this isn't a builtin, but we have a path, we try to resolve the
1117+
module path relative to the env we're completing from. This ensures that
1118+
what we get here is a module path we can find completions for regardless of
1119+
of the current scope for the position we're at.*)
1120+
match
1121+
TypeUtils.getModulePathRelativeToEnv ~debug
1122+
~env:envCompletionIsMadeFrom ~envFromItem:env
1123+
(Utils.expandPath p)
1124+
with
1125+
| None -> Some (true, [env.file.moduleName])
1126+
| Some p -> Some (false, p))
1127+
| _ -> None
1128+
in
1129+
match completionPath with
1130+
| None -> []
1131+
| Some (isFromCurrentModule, completionPath) ->
1132+
completionsForPipeFromCompletionPath ~envCompletionIsMadeFrom ~opens
1133+
~pos ~scope ~debug ~prefix ~env ~rawOpens ~full completionPath
1134+
|> TypeUtils.filterPipeableFunctions ~env ~full ~synthetic
1135+
~targetTypeId:mainTypeId
1136+
|> List.filter (fun (c : Completion.t) ->
1137+
(* If we're completing from the current module then we need to care about scope.
1138+
This is automatically taken care of in other cases. *)
1139+
if isFromCurrentModule then
1140+
match c.kind with
1141+
| Value _ ->
1142+
scope
1143+
|> List.find_opt (fun (item : ScopeTypes.item) ->
1144+
match item with
1145+
| Value (scopeItemName, _, _, _) ->
1146+
scopeItemName = c.name
1147+
| _ -> false)
1148+
|> Option.is_some
1149+
| _ -> false
1150+
else true)
1151+
in
1152+
(* Extra completions can be drawn from the @editor.completeFrom attribute. Here we
1153+
find and add those completions as well. *)
1154+
let extraCompletions =
1155+
TypeUtils.getExtraModulesToCompleteFromForType ~env ~full typ
1156+
|> List.map (fun completionPath ->
1157+
completionsForPipeFromCompletionPath ~envCompletionIsMadeFrom
1158+
~opens ~pos ~scope ~debug ~prefix ~env ~rawOpens ~full
1159+
completionPath)
1160+
|> List.flatten
1161+
|> TypeUtils.filterPipeableFunctions ~synthetic:true ~env ~full
1162+
~targetTypeId:mainTypeId
1163+
in
1164+
(* Add JSX completion items if we're in a JSX context. *)
1165+
let jsxCompletions =
1166+
if inJsx then
1167+
PipeCompletionUtils.addJsxCompletionItems ~env ~mainTypeId ~prefix
1168+
~full ~rawOpens typ
1169+
else []
1170+
in
1171+
jsxCompletions @ pipeCompletions @ extraCompletions))
11841172
| CTuple ctxPaths ->
11851173
if Debug.verbose () then print_endline "[ctx_path]--> CTuple";
11861174
(* Turn a list of context paths into a list of type expressions. *)

analysis/src/CompletionFrontEnd.ml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1050,6 +1050,7 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor
10501050
(Cpath
10511051
(CPPipe
10521052
{
1053+
synthetic = false;
10531054
contextPath = pipe;
10541055
id;
10551056
lhsLoc = lhs.pexp_loc;
@@ -1060,7 +1061,14 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor
10601061
| Some (pipe, lhsLoc) ->
10611062
setResult
10621063
(Cpath
1063-
(CPPipe {contextPath = pipe; id; lhsLoc; inJsx = !inJsxContext}));
1064+
(CPPipe
1065+
{
1066+
synthetic = false;
1067+
contextPath = pipe;
1068+
id;
1069+
lhsLoc;
1070+
inJsx = !inJsxContext;
1071+
}));
10641072
true
10651073
in
10661074
typedCompletionExpr expr;

analysis/src/SharedTypes.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,7 @@ module Completable = struct
620620
| CPObj of contextPath * string
621621
| CPAwait of contextPath
622622
| CPPipe of {
623+
synthetic: bool; (** Whether this pipe completion is synthetic. *)
623624
contextPath: contextPath;
624625
id: string;
625626
inJsx: bool; (** Whether this pipe was found in a JSX context. *)

0 commit comments

Comments
 (0)