diff --git a/CHANGELOG.md b/CHANGELOG.md index e9d7639e04..749f0562a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,7 @@ - Improve error message for pipe (`->`) syntax. https://github.com/rescript-lang/rescript/pull/7520 - Improve a few error messages around various subtyping issues. https://github.com/rescript-lang/rescript/pull/7404 - Refactor the ast for record expressions and patterns. https://github.com/rescript-lang/rescript/pull/7528 +- Editor: add completions from included modules. https://github.com/rescript-lang/rescript/pull/7515 # 12.0.0-alpha.13 diff --git a/analysis/bin/main.ml b/analysis/bin/main.ml index 259b1a3004..f25cb78115 100644 --- a/analysis/bin/main.ml +++ b/analysis/bin/main.ml @@ -209,6 +209,7 @@ let main () = | [_; "format"; path] -> Printf.printf "\"%s\"" (Json.escape (Commands.format ~path)) | [_; "test"; path] -> Commands.test ~path + | [_; "cmt"; rescript_json; cmt_path] -> CmtViewer.dump rescript_json cmt_path | args when List.mem "-h" args || List.mem "--help" args -> prerr_endline help | _ -> prerr_endline help; diff --git a/analysis/src/CmtViewer.ml b/analysis/src/CmtViewer.ml new file mode 100644 index 0000000000..99e71b9537 --- /dev/null +++ b/analysis/src/CmtViewer.ml @@ -0,0 +1,128 @@ +let filter_by_cursor cursor (loc : Warnings.loc) : bool = + match cursor with + | None -> true + | Some (line, col) -> + let start = loc.loc_start and end_ = loc.loc_end in + let line_in = start.pos_lnum <= line && line <= end_.pos_lnum in + let col_in = + if start.pos_lnum = end_.pos_lnum then + start.pos_cnum - start.pos_bol <= col + && col <= end_.pos_cnum - end_.pos_bol + else if line = start.pos_lnum then col >= start.pos_cnum - start.pos_bol + else if line = end_.pos_lnum then col <= end_.pos_cnum - end_.pos_bol + else true + in + line_in && col_in + +type filter = Cursor of (int * int) | Loc of Loc.t + +let dump ?filter rescript_json cmt_path = + let uri = Uri.fromPath (Filename.remove_extension cmt_path ^ ".res") in + let package = + let uri = Uri.fromPath rescript_json in + Packages.getPackage ~uri |> Option.get + in + let moduleName = + BuildSystem.namespacedName package.namespace (FindFiles.getName cmt_path) + in + match Cmt.fullForCmt ~moduleName ~package ~uri cmt_path with + | None -> failwith (Format.sprintf "Could not load cmt for %s" cmt_path) + | Some full -> + let open SharedTypes in + let open SharedTypes.Stamps in + let applyFilter = + match filter with + | None -> fun _ -> true + | Some (Cursor cursor) -> Loc.hasPos ~pos:cursor + | Some (Loc loc) -> Loc.isInside loc + in + (match filter with + | None -> () + | Some (Cursor (line, col)) -> + Printf.printf "Filtering by cursor %d,%d\n" line col + | Some (Loc loc) -> Printf.printf "Filtering by loc %s\n" (Loc.toString loc)); + + Printf.printf "file moduleName: %s\n\n" full.file.moduleName; + + let stamps = + full.file.stamps |> getEntries + |> List.filter (fun (_, stamp) -> applyFilter (locOfKind stamp)) + in + + let total_stamps = List.length stamps in + Printf.printf "Found %d stamps:\n%s" total_stamps + (if total_stamps > 0 then "\n" else ""); + + stamps + |> List.sort (fun (_, a) (_, b) -> + let aLoc = locOfKind a in + let bLoc = locOfKind b in + match compare aLoc.loc_start.pos_lnum bLoc.loc_start.pos_lnum with + | 0 -> compare aLoc.loc_start.pos_cnum bLoc.loc_start.pos_cnum + | c -> c) + |> List.iter (fun (stamp, kind) -> + match kind with + | KType t -> + Printf.printf "%d ktype %s\n" stamp + (Warnings.loc_to_string t.extentLoc) + | KValue t -> + Printf.printf "%d kvalue %s\n" stamp + (Warnings.loc_to_string t.extentLoc) + | KModule t -> + Printf.printf "%d kmodule %s\n" stamp + (Warnings.loc_to_string t.extentLoc) + | KConstructor t -> + Printf.printf "%d kconstructor %s\n" stamp + (Warnings.loc_to_string t.extentLoc)); + + (* dump the structure *) + let rec dump_structure indent (structure : Module.structure) = + if indent > 0 then Printf.printf "%s" (String.make indent ' '); + Printf.printf "Structure %s:\n" structure.name; + structure.items |> List.iter (dump_structure_item (indent + 2)) + and dump_structure_item indent item = + if indent > 0 then Printf.printf "%s" (String.make indent ' '); + let open Module in + match item.kind with + | Value _typedExpr -> + Printf.printf "Value %s %s\n" item.name + (Warnings.loc_to_string item.loc) + | Type _ -> + Printf.printf "Type %s %s\n" item.name (Warnings.loc_to_string item.loc) + | Module {type_ = m} -> + Printf.printf "Module %s %s\n" item.name + (Warnings.loc_to_string item.loc); + dump_module indent m + and dump_module indent (module_ : Module.t) = + match module_ with + | Ident path -> Printf.printf "Module (Ident) %s\n" (Path.name path) + | Structure structure -> dump_structure indent structure + | Constraint (m1, m2) -> + dump_module indent m1; + dump_module indent m2 + in + + print_newline (); + dump_structure 0 full.file.structure; + + (* Dump all locItems (typed nodes) *) + let locItems = + match full.extra with + | {locItems} -> + locItems |> List.filter (fun locItem -> applyFilter locItem.loc) + in + + Printf.printf "\nFound %d locItems (typed nodes):\n\n" + (List.length locItems); + + locItems + |> List.sort (fun a b -> + let aLoc = a.loc.Location.loc_start in + let bLoc = b.loc.Location.loc_start in + match compare aLoc.pos_lnum bLoc.pos_lnum with + | 0 -> compare aLoc.pos_cnum bLoc.pos_cnum + | c -> c) + |> List.iter (fun {loc; locType} -> + let locStr = Warnings.loc_to_string loc in + let kindStr = SharedTypes.locTypeToString locType in + Printf.printf "%s %s\n" locStr kindStr) diff --git a/analysis/src/CompletionBackEnd.ml b/analysis/src/CompletionBackEnd.ml index 96dab722d1..f678d9a6c0 100644 --- a/analysis/src/CompletionBackEnd.ml +++ b/analysis/src/CompletionBackEnd.ml @@ -451,6 +451,30 @@ let processLocalModule name loc ~prefix ~exact ~env (Printf.sprintf "Completion Module Not Found %s loc:%s\n" name (Loc.toString loc)) +let processLocalInclude includePath _loc ~prefix ~exact ~(env : QueryEnv.t) + ~(localTables : LocalTables.t) = + (* process only values for now *) + localTables.includedValueTable + |> Hashtbl.iter + (fun (name, _) (declared : (string * Types.type_expr) Declared.t) -> + (* We check all the values if their origin is the same as the include path. *) + let source_module_path = fst declared.item in + if String.ends_with ~suffix:includePath source_module_path then + (* If this is the case we perform a similar check for the prefix *) + if Utils.checkName name ~prefix ~exact then + if not (Hashtbl.mem localTables.namesUsed name) then ( + Hashtbl.add localTables.namesUsed name (); + localTables.resultRev <- + { + (Completion.create declared.name.txt ~env + ~kind:(Value (snd declared.item))) + with + deprecated = declared.deprecated; + docstring = declared.docstring; + synthetic = true; + } + :: localTables.resultRev)) + let getItemsFromOpens ~opens ~localTables ~prefix ~exact ~completionContext = opens |> List.fold_left @@ -465,8 +489,10 @@ let getItemsFromOpens ~opens ~localTables ~prefix ~exact ~completionContext = let findLocalCompletionsForValuesAndConstructors ~(localTables : LocalTables.t) ~env ~prefix ~exact ~opens ~scope = localTables |> LocalTables.populateValues ~env; + localTables |> LocalTables.populateIncludedValues ~env; localTables |> LocalTables.populateConstructors ~env; localTables |> LocalTables.populateModules ~env; + scope |> Scope.iterValuesBeforeFirstOpen (processLocalValue ~prefix ~exact ~env ~localTables); @@ -491,11 +517,16 @@ let findLocalCompletionsForValuesAndConstructors ~(localTables : LocalTables.t) scope |> Scope.iterModulesAfterFirstOpen (processLocalModule ~prefix ~exact ~env ~localTables); + + scope + |> Scope.iterIncludes (processLocalInclude ~prefix ~exact ~env ~localTables); + List.rev_append localTables.resultRev valuesFromOpens let findLocalCompletionsForValues ~(localTables : LocalTables.t) ~env ~prefix ~exact ~opens ~scope = localTables |> LocalTables.populateValues ~env; + localTables |> LocalTables.populateIncludedValues ~env; localTables |> LocalTables.populateModules ~env; scope |> Scope.iterValuesBeforeFirstOpen @@ -515,6 +546,10 @@ let findLocalCompletionsForValues ~(localTables : LocalTables.t) ~env ~prefix scope |> Scope.iterModulesAfterFirstOpen (processLocalModule ~prefix ~exact ~env ~localTables); + + scope + |> Scope.iterIncludes (processLocalInclude ~prefix ~exact ~env ~localTables); + List.rev_append localTables.resultRev valuesFromOpens let findLocalCompletionsForTypes ~(localTables : LocalTables.t) ~env ~prefix @@ -1049,6 +1084,8 @@ and getCompletionsForContextPath ~debug ~full ~opens ~rawOpens ~pos ~env ~exact | None -> []) | CPPipe {contextPath = cp; id = prefix; lhsLoc; inJsx; synthetic} -> ( if Debug.verbose () then print_endline "[ctx_path]--> CPPipe"; + (* The environment at the cursor is the environment we're completing from. *) + let env_at_cursor = env in match cp |> getCompletionsForContextPath ~debug ~full ~opens ~rawOpens ~pos ~env @@ -1175,8 +1212,8 @@ and getCompletionsForContextPath ~debug ~full ~opens ~rawOpens ~pos ~env ~exact in (* Add completions from the current module. *) let currentModuleCompletions = - completionsForPipeFromCompletionPath ~envCompletionIsMadeFrom - ~opens:[] ~pos ~scope ~debug ~prefix ~env ~rawOpens ~full [] + getCompletionsForPath ~debug ~completionContext:Value ~exact:false + ~opens:[] ~full ~pos ~env:env_at_cursor ~scope [prefix] |> TypeUtils.filterPipeableFunctions ~synthetic:true ~env ~full ~targetTypeId:mainTypeId in diff --git a/analysis/src/CompletionFrontEnd.ml b/analysis/src/CompletionFrontEnd.ml index 41bf47fbde..fb92e81d19 100644 --- a/analysis/src/CompletionFrontEnd.ml +++ b/analysis/src/CompletionFrontEnd.ml @@ -743,6 +743,13 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor mbs |> List.iter scopeModuleBinding; mbs |> List.iter (fun b -> iterator.module_binding iterator b); processed := true + | Pstr_include {pincl_mod = {pmod_desc = med}} -> ( + match med with + | Pmod_ident {txt = lid; loc} + | Pmod_apply ({pmod_desc = Pmod_ident {txt = lid; loc}}, _) -> + let module_name = Longident.flatten lid |> String.concat "." in + scope := !scope |> Scope.addInclude ~name:module_name ~loc + | _ -> ()) | _ -> ()); if not !processed then Ast_iterator.default_iterator.structure_item iterator item diff --git a/analysis/src/Completions.ml b/analysis/src/Completions.ml index 42176bb3b0..c11d51673e 100644 --- a/analysis/src/Completions.ml +++ b/analysis/src/Completions.ml @@ -9,6 +9,14 @@ let getCompletions ~debug ~path ~pos ~currentFile ~forHover = with | None -> None | Some (completable, scope) -> ( + (* uncomment when debugging *) + if false then ( + Printf.printf "\nScope from frontend:\n"; + List.iter + (fun item -> + Printf.printf "%s\n" (SharedTypes.ScopeTypes.item_to_string item)) + scope; + print_newline ()); (* Only perform expensive ast operations if there are completables *) match Cmt.loadFullCmtFromPath ~path with | None -> None diff --git a/analysis/src/Loc.ml b/analysis/src/Loc.ml index 2ab1d8fbd2..635b787128 100644 --- a/analysis/src/Loc.ml +++ b/analysis/src/Loc.ml @@ -21,3 +21,9 @@ let rangeOfLoc (loc : t) = let start = loc |> start |> mkPosition in let end_ = loc |> end_ |> mkPosition in {Protocol.start; end_} + +let isInside (x : t) (y : t) = + x.loc_start.pos_cnum >= y.loc_start.pos_cnum + && x.loc_end.pos_cnum <= y.loc_end.pos_cnum + && x.loc_start.pos_lnum >= y.loc_start.pos_lnum + && x.loc_end.pos_lnum <= y.loc_end.pos_lnum diff --git a/analysis/src/LocalTables.ml b/analysis/src/LocalTables.ml index 5a5bdb0c2c..d690d969d1 100644 --- a/analysis/src/LocalTables.ml +++ b/analysis/src/LocalTables.ml @@ -10,6 +10,7 @@ type t = { modulesTable: Module.t table; typesTable: Type.t table; valueTable: Types.type_expr table; + includedValueTable: (string * Types.type_expr) table; } let create () = @@ -20,6 +21,7 @@ let create () = modulesTable = Hashtbl.create 1; typesTable = Hashtbl.create 1; valueTable = Hashtbl.create 1; + includedValueTable = Hashtbl.create 1; } let populateValues ~env localTables = @@ -29,6 +31,18 @@ let populateValues ~env localTables = (declared.name.txt, declared.name.loc |> Loc.start) declared) +let populateIncludedValues ~env localTables = + env.QueryEnv.file.stamps + |> Stamps.iterValues (fun _ declared -> + match declared.modulePath with + | ModulePath.IncludedModule (source, _) -> + let path = Path.name source in + let declared = {declared with item = (path, declared.item)} in + Hashtbl.replace localTables.includedValueTable + (declared.name.txt, declared.name.loc |> Loc.start) + declared + | _ -> ()) + let populateConstructors ~env localTables = env.QueryEnv.file.stamps |> Stamps.iterConstructors (fun _ declared -> diff --git a/analysis/src/Scope.ml b/analysis/src/Scope.ml index 0e092d2a43..33e850bc02 100644 --- a/analysis/src/Scope.ml +++ b/analysis/src/Scope.ml @@ -14,6 +14,7 @@ let itemToString item = | Module (s, loc) -> "Module " ^ s ^ " " ^ Loc.toString loc | Value (s, loc, _, _) -> "Value " ^ s ^ " " ^ Loc.toString loc | Type (s, loc) -> "Type " ^ s ^ " " ^ Loc.toString loc + | Include (s, loc) -> "Include " ^ s ^ " " ^ Loc.toString loc [@@live] let create () : t = [] @@ -32,6 +33,7 @@ let addValue ~name ~loc ?contextPath x = (SharedTypes.Completable.contextPathToString contextPath)); Value (name, loc, contextPath, x) :: x let addType ~name ~loc x = Type (name, loc) :: x +let addInclude ~name ~loc x = Include (name, loc) :: x let iterValuesBeforeFirstOpen f x = let rec loop items = @@ -129,6 +131,17 @@ let iterModulesAfterFirstOpen f x = in loop false x +let iterIncludes f x = + let rec loop items = + match items with + | [] -> () + | Include (s, loc) :: rest -> + f s loc; + loop rest + | _ :: rest -> loop rest + in + loop x + let getRawOpens x = x |> Utils.filterMap (function diff --git a/analysis/src/SharedTypes.ml b/analysis/src/SharedTypes.ml index 13692e26a6..73d43ffc39 100644 --- a/analysis/src/SharedTypes.ml +++ b/analysis/src/SharedTypes.ml @@ -24,6 +24,16 @@ module ModulePath = struct | NotVisible -> current in loop modulePath [tipName] + + let toPathWithPrefix modulePath prefix : path = + let rec loop modulePath current = + match modulePath with + | File _ -> current + | IncludedModule (_, inner) -> loop inner current + | ExportedModule {name; modulePath = inner} -> loop inner (name :: current) + | NotVisible -> current + in + prefix :: loop modulePath [] end type field = { @@ -155,6 +165,14 @@ module Declared = struct end module Stamps : sig + type kind = + | KType of Type.t Declared.t + | KValue of Types.type_expr Declared.t + | KModule of Module.t Declared.t + | KConstructor of Constructor.t Declared.t + + val locOfKind : kind -> Warnings.loc + type t val addConstructor : t -> int -> Constructor.t Declared.t -> unit @@ -169,6 +187,7 @@ module Stamps : sig val iterModules : (int -> Module.t Declared.t -> unit) -> t -> unit val iterTypes : (int -> Type.t Declared.t -> unit) -> t -> unit val iterValues : (int -> Types.type_expr Declared.t -> unit) -> t -> unit + val getEntries : t -> (int * kind) list end = struct type 't stampMap = (int, 't Declared.t) Hashtbl.t @@ -178,6 +197,12 @@ end = struct | KModule of Module.t Declared.t | KConstructor of Constructor.t Declared.t + let locOfKind = function + | KType declared -> declared.extentLoc + | KValue declared -> declared.extentLoc + | KModule declared -> declared.extentLoc + | KConstructor declared -> declared.extentLoc + type t = (int, kind) Hashtbl.t let init () = Hashtbl.create 10 @@ -239,6 +264,8 @@ end = struct | KConstructor d -> f stamp d | _ -> ()) stamps + + let getEntries t = t |> Hashtbl.to_seq |> List.of_seq end module File = struct @@ -773,6 +800,19 @@ module ScopeTypes = struct | Open of string list | Type of string * Location.t | Value of string * Location.t * Completable.contextPath option * item list + | Include of string * Location.t + + let item_to_string = function + | Constructor (name, loc) -> + "Constructor " ^ name ^ " " ^ Warnings.loc_to_string loc + | Field (name, loc) -> "Field " ^ name ^ " " ^ Warnings.loc_to_string loc + | Module (name, loc) -> "Module " ^ name ^ " " ^ Warnings.loc_to_string loc + | Open path -> "Open " ^ (path |> String.concat ".") + | Type (name, loc) -> "Type " ^ name ^ " " ^ Warnings.loc_to_string loc + | Value (name, loc, _, _) -> + "Value " ^ name ^ " " ^ Warnings.loc_to_string loc + | Include (name, loc) -> + "Include " ^ name ^ " " ^ Warnings.loc_to_string loc end module Completion = struct diff --git a/analysis/src/TypeUtils.ml b/analysis/src/TypeUtils.ml index 4c89a2c117..99ffca3f28 100644 --- a/analysis/src/TypeUtils.ml +++ b/analysis/src/TypeUtils.ml @@ -1,6 +1,20 @@ open SharedTypes -let modulePathFromEnv env = env.QueryEnv.file.moduleName :: List.rev env.pathRev +let modulePathFromEnv env = + let moduleName = env.QueryEnv.file.moduleName in + let transformedModuleName = + (* Transform namespaced module names from internal format (Context-Kaplay) + to user-facing format (Kaplay.Context) *) + match String.rindex_opt moduleName '-' with + | None -> moduleName + | Some i -> + let namespace = + String.sub moduleName (i + 1) (String.length moduleName - i - 1) + in + let module_ = String.sub moduleName 0 i in + namespace ^ "." ^ module_ + in + transformedModuleName :: List.rev env.pathRev let fullTypeIdFromDecl ~env ~name ~modulePath = env.QueryEnv.file.moduleName :: ModulePath.toPath modulePath name diff --git a/compiler/ext/warnings.ml b/compiler/ext/warnings.ml index fd3d506411..f799100a36 100644 --- a/compiler/ext/warnings.ml +++ b/compiler/ext/warnings.ml @@ -676,3 +676,9 @@ let help_warnings () = (String.concat ", " (List.map string_of_int l)) done; exit 0 + +let loc_to_string (loc : loc) : string = + Format.sprintf "(%02d,%02d--%02d,%02d)" loc.loc_start.pos_lnum + (loc.loc_start.pos_cnum - loc.loc_start.pos_bol) + loc.loc_end.pos_lnum + (loc.loc_end.pos_cnum - loc.loc_end.pos_bol) diff --git a/compiler/ext/warnings.mli b/compiler/ext/warnings.mli index 4b96f0f427..59971b94be 100644 --- a/compiler/ext/warnings.mli +++ b/compiler/ext/warnings.mli @@ -126,3 +126,8 @@ val message : t -> string val number : t -> int val reset : unit -> unit + +val loc_to_string : loc -> string +(** +Turn the location into a string with (line,column--line,column) format. +*) diff --git a/tests/analysis_tests/tests/src/DotPipeCompleteFromCurrentModule.res b/tests/analysis_tests/tests/src/DotPipeCompleteFromCurrentModule.res index 819086e35a..e80f4fc0a8 100644 --- a/tests/analysis_tests/tests/src/DotPipeCompleteFromCurrentModule.res +++ b/tests/analysis_tests/tests/src/DotPipeCompleteFromCurrentModule.res @@ -14,4 +14,4 @@ module Y = { } let b = (x:t) => 4 -} \ No newline at end of file +} diff --git a/tests/analysis_tests/tests/src/IncludeModuleCompletion.res b/tests/analysis_tests/tests/src/IncludeModuleCompletion.res new file mode 100644 index 0000000000..081fe0cd81 --- /dev/null +++ b/tests/analysis_tests/tests/src/IncludeModuleCompletion.res @@ -0,0 +1,91 @@ +module Types = { + type comp + + type context + + type vec2 +} + +module PosComp = ( + T: { + type t + }, +) => { + open Types + + @send + external addPos: (context, float, float) => comp = "pos" + + @send + external addPosFromVec2: (context, vec2) => comp = "pos" +} + +module SpriteComp = ( + T: { + type t + }, +) => { + open Types + + @send + external addSprite: (context, string) => comp = "sprite" +} + +external k: Types.context = "k" + +@send +external add: (Types.context, array) => 't = "add" + +module Wall = { + type t + + include PosComp({type t = t}) + + let blah = (k: Types.context) => "" + + let make = () => { + [ + // k. + // ^com + // add + // ^com + ] + } + + let makeWith = x => { + k->add([ + k->addPos(1.0, 2.0), + + // addP + // ^com + ]) + } + + module Poster = { + type t + + include SpriteComp({type t = t}) + + let make = () => { + [ + // k. + // ^com + ] + } + } +} + +module M = { + let lex = (a: int) => "foo" +} + +module N = { + include M + + let a = 4 + // let o = a.l + // ^com + + // let _ = l + // ^com +} diff --git a/tests/analysis_tests/tests/src/expected/IncludeModuleCompletion.res.txt b/tests/analysis_tests/tests/src/expected/IncludeModuleCompletion.res.txt new file mode 100644 index 0000000000..57535091fe --- /dev/null +++ b/tests/analysis_tests/tests/src/expected/IncludeModuleCompletion.res.txt @@ -0,0 +1,243 @@ +Complete src/IncludeModuleCompletion.res 47:11 +posCursor:[47:11] posNoWhite:[47:10] Found expr:[45:13->52:3] +posCursor:[47:11] posNoWhite:[47:10] Found expr:[46:4->51:5] +posCursor:[47:11] posNoWhite:[47:10] Found expr:[47:9->47:11] +Pexp_field [47:9->47:10] _:[51:4->47:11] +Completable: Cpath Value[k]."" +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Value[k]."" +ContextPath Value[k] +Path k +ContextPath Value[k]-> +ContextPath Value[k] +Path k +CPPipe pathFromEnv:Types found:true +Path Types. +Path +[{ + "label": "->blah", + "kind": 12, + "tags": [], + "detail": "Types.context => string", + "documentation": null, + "sortText": "blah", + "insertText": "->blah", + "additionalTextEdits": [{ + "range": {"start": {"line": 47, "character": 10}, "end": {"line": 47, "character": 11}}, + "newText": "" + }] + }, { + "label": "->add", + "kind": 12, + "tags": [], + "detail": "(Types.context, array) => 't", + "documentation": null, + "sortText": "add", + "insertText": "->add", + "additionalTextEdits": [{ + "range": {"start": {"line": 47, "character": 10}, "end": {"line": 47, "character": 11}}, + "newText": "" + }] + }, { + "label": "->addPosFromVec2", + "kind": 12, + "tags": [], + "detail": "(Types.context, Types.vec2) => Types.comp", + "documentation": null, + "sortText": "addPosFromVec2", + "insertText": "->addPosFromVec2", + "additionalTextEdits": [{ + "range": {"start": {"line": 47, "character": 10}, "end": {"line": 47, "character": 11}}, + "newText": "" + }] + }, { + "label": "->addPos", + "kind": 12, + "tags": [], + "detail": "(Types.context, float, float) => Types.comp", + "documentation": null, + "sortText": "addPos", + "insertText": "->addPos", + "additionalTextEdits": [{ + "range": {"start": {"line": 47, "character": 10}, "end": {"line": 47, "character": 11}}, + "newText": "" + }] + }] + +Complete src/IncludeModuleCompletion.res 49:12 +posCursor:[49:12] posNoWhite:[49:11] Found expr:[45:13->52:3] +posCursor:[49:12] posNoWhite:[49:11] Found expr:[46:4->51:5] +posCursor:[49:12] posNoWhite:[49:11] Found expr:[49:9->49:12] +Pexp_ident add:[49:9->49:12] +Completable: Cpath Value[add] +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Value[add] +Path add +[{ + "label": "add", + "kind": 12, + "tags": [], + "detail": "(Types.context, array) => 't", + "documentation": null + }, { + "label": "addPosFromVec2", + "kind": 12, + "tags": [], + "detail": "(Types.context, Types.vec2) => Types.comp", + "documentation": null + }, { + "label": "addPos", + "kind": 12, + "tags": [], + "detail": "(Types.context, float, float) => Types.comp", + "documentation": null + }] + +Complete src/IncludeModuleCompletion.res 58:13 +posCursor:[58:13] posNoWhite:[58:12] Found expr:[54:17->61:3] +posCursor:[58:13] posNoWhite:[58:12] Found expr:[55:4->60:6] +Completable: Cexpression CArgument Value[add]($1)=addP->array +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath CArgument Value[add]($1) +ContextPath Value[add] +Path add +[{ + "label": "addPosFromVec2", + "kind": 12, + "tags": [], + "detail": "(Types.context, Types.vec2) => Types.comp", + "documentation": null + }, { + "label": "addPos", + "kind": 12, + "tags": [], + "detail": "(Types.context, float, float) => Types.comp", + "documentation": null + }] + +Complete src/IncludeModuleCompletion.res 70:13 +posCursor:[70:13] posNoWhite:[70:12] Found expr:[68:15->73:5] +posCursor:[70:13] posNoWhite:[70:12] Found expr:[69:6->72:7] +posCursor:[70:13] posNoWhite:[70:12] Found expr:[70:11->70:13] +Pexp_field [70:11->70:12] _:[72:6->70:13] +Completable: Cpath Value[k]."" +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Value[k]."" +ContextPath Value[k] +Path k +ContextPath Value[k]-> +ContextPath Value[k] +Path k +CPPipe pathFromEnv:Types found:true +Path Types. +Path +[{ + "label": "->blah", + "kind": 12, + "tags": [], + "detail": "Types.context => string", + "documentation": null, + "sortText": "blah", + "insertText": "->blah", + "additionalTextEdits": [{ + "range": {"start": {"line": 70, "character": 12}, "end": {"line": 70, "character": 13}}, + "newText": "" + }] + }, { + "label": "->add", + "kind": 12, + "tags": [], + "detail": "(Types.context, array) => 't", + "documentation": null, + "sortText": "add", + "insertText": "->add", + "additionalTextEdits": [{ + "range": {"start": {"line": 70, "character": 12}, "end": {"line": 70, "character": 13}}, + "newText": "" + }] + }, { + "label": "->addSprite", + "kind": 12, + "tags": [], + "detail": "(Types.context, string) => Types.comp", + "documentation": null, + "sortText": "addSprite", + "insertText": "->addSprite", + "additionalTextEdits": [{ + "range": {"start": {"line": 70, "character": 12}, "end": {"line": 70, "character": 13}}, + "newText": "" + }] + }, { + "label": "->addPosFromVec2", + "kind": 12, + "tags": [], + "detail": "(Types.context, Types.vec2) => Types.comp", + "documentation": null, + "sortText": "addPosFromVec2", + "insertText": "->addPosFromVec2", + "additionalTextEdits": [{ + "range": {"start": {"line": 70, "character": 12}, "end": {"line": 70, "character": 13}}, + "newText": "" + }] + }, { + "label": "->addPos", + "kind": 12, + "tags": [], + "detail": "(Types.context, float, float) => Types.comp", + "documentation": null, + "sortText": "addPos", + "insertText": "->addPos", + "additionalTextEdits": [{ + "range": {"start": {"line": 70, "character": 12}, "end": {"line": 70, "character": 13}}, + "newText": "" + }] + }] + +Complete src/IncludeModuleCompletion.res 85:16 +posCursor:[85:16] posNoWhite:[85:15] Found expr:[85:13->85:16] +Pexp_field [85:13->85:14] l:[85:15->85:16] +Completable: Cpath Value[a].l +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Value[a].l +ContextPath Value[a] +Path a +ContextPath Value[a]->l +ContextPath Value[a] +Path a +Path Stdlib.Int.l +Path l +[{ + "label": "->lex", + "kind": 12, + "tags": [], + "detail": "int => string", + "documentation": null, + "sortText": "lex", + "insertText": "->lex", + "additionalTextEdits": [{ + "range": {"start": {"line": 85, "character": 14}, "end": {"line": 85, "character": 15}}, + "newText": "" + }] + }] + +Complete src/IncludeModuleCompletion.res 88:14 +posCursor:[88:14] posNoWhite:[88:13] Found expr:[88:13->88:14] +Pexp_ident l:[88:13->88:14] +Completable: Cpath Value[l] +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Value[l] +Path l +[{ + "label": "lex", + "kind": 12, + "tags": [], + "detail": "int => string", + "documentation": null + }] +