diff --git a/.vscode/settings.json b/.vscode/settings.json index a0dfd585e..a7024256f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,5 +5,9 @@ "typescript.preferences.quoteStyle": "single", "editor.codeActionsOnSave": { "source.fixAll.eslint": true + }, + "ocaml.sandbox": { + "kind": "opam", + "switch": "4.12.1" } } \ No newline at end of file diff --git a/analysis/src/Cli.ml b/analysis/src/Cli.ml index 90b82b1c8..3e71a6acf 100644 --- a/analysis/src/Cli.ml +++ b/analysis/src/Cli.ml @@ -3,7 +3,7 @@ let help = **Private CLI For rescript-vscode usage only** API examples: - ./rescript-editor-analysis.exe completion src/MyFile.res 0 4 currentContent.res + ./rescript-editor-analysis.exe completion src/MyFile.res 0 4 currentContent.res true ./rescript-editor-analysis.exe definition src/MyFile.res 9 3 ./rescript-editor-analysis.exe typeDefinition src/MyFile.res 9 3 ./rescript-editor-analysis.exe documentSymbol src/Foo.res @@ -24,8 +24,9 @@ https://microsoft.github.io/language-server-protocol/specification#position Options: completion: compute autocomplete for MyFile.res at line 0 and column 4, where MyFile.res is being edited and the editor content is in file current.res. + The final boolean indicates whether the completion should return snippets or not. - ./rescript-editor-analysis.exe completion src/MyFile.res 0 4 current.res + ./rescript-editor-analysis.exe completion src/MyFile.res 0 4 current.res true definition: get definition for item in MyFile.res at line 10 column 2: @@ -82,10 +83,14 @@ Options: let main () = match Array.to_list Sys.argv with - | [_; "completion"; path; line; col; currentFile] -> + | [_; "completion"; path; line; col; currentFile; supportsSnippets] -> Commands.completion ~debug:false ~path ~pos:(int_of_string line, int_of_string col) ~currentFile + ~supportsSnippets: + (match supportsSnippets with + | "true" -> true + | _ -> false) | [_; "definition"; path; line; col] -> Commands.definition ~path ~pos:(int_of_string line, int_of_string col) diff --git a/analysis/src/Commands.ml b/analysis/src/Commands.ml index ad9ad4a89..3f5fe9ed0 100644 --- a/analysis/src/Commands.ml +++ b/analysis/src/Commands.ml @@ -21,10 +21,18 @@ let getCompletions ~debug ~path ~pos ~currentFile ~forHover = |> CompletionBackEnd.processCompletable ~debug ~package ~pos ~scope ~env ~forHover)) -let completion ~debug ~path ~pos ~currentFile = +let completion ~debug ~path ~pos ~currentFile ~supportsSnippets = print_endline (getCompletions ~debug ~path ~pos ~currentFile ~forHover:false |> List.map CompletionBackEnd.completionToItem + |> List.map (fun completionItem -> + if supportsSnippets then completionItem + else + { + completionItem with + Protocol.insertText = None; + insertTextFormat = None; + }) |> List.map Protocol.stringifyCompletionItem |> Protocol.array) @@ -320,7 +328,8 @@ let test ~path = ("Complete " ^ path ^ " " ^ string_of_int line ^ ":" ^ string_of_int col); let currentFile = createCurrentFile () in - completion ~debug:true ~path ~pos:(line, col) ~currentFile; + completion ~debug:true ~path ~pos:(line, col) ~currentFile + ~supportsSnippets:true; Sys.remove currentFile | "dce" -> print_endline ("DCE " ^ path); @@ -390,14 +399,24 @@ let test ~path = (Protocol.stringifyRange range) indent indent newText))) | "dia" -> diagnosticSyntax ~path - | "hin" -> ( + | "hin" -> let line_start = 0 in let line_end = 6 in - print_endline ("Inlay Hint " ^ path ^ " " ^ string_of_int line_start ^ ":" ^ string_of_int line_end); - inlayhint ~path ~pos:(line_start, line_end) ~maxLength:"25" ~debug:false) + print_endline + ("Inlay Hint " ^ path ^ " " ^ string_of_int line_start ^ ":" + ^ string_of_int line_end); + inlayhint ~path ~pos:(line_start, line_end) ~maxLength:"25" + ~debug:false | "cle" -> print_endline ("Code Lens " ^ path); codeLens ~path ~debug:false + | "ast" -> + print_endline + ("Dump AST " ^ path ^ " " ^ string_of_int line ^ ":" + ^ string_of_int col); + let currentFile = createCurrentFile () in + DumpAst.dump ~pos:(line, col) ~currentFile; + Sys.remove currentFile | _ -> ()); print_newline ()) in diff --git a/analysis/src/CompletionBackEnd.ml b/analysis/src/CompletionBackEnd.ml index 387abd6b8..19bbd64ea 100644 --- a/analysis/src/CompletionBackEnd.ml +++ b/analysis/src/CompletionBackEnd.ml @@ -558,7 +558,8 @@ let completionForExporteds iterExported getDeclared ~prefix ~exact ~env res := { (Completion.create ~name:declared.name.txt ~env - ~kind:(transformContents declared.item)) + ~kind:(transformContents declared.item) + ()) with deprecated = declared.deprecated; docstring = declared.docstring; @@ -600,7 +601,8 @@ let completionsForExportedConstructors ~(env : QueryEnv.t) ~prefix ~exact (Completion.create ~name ~env ~kind: (Completion.Constructor - (c, t.item.decl |> Shared.declToString t.name.txt))) + (c, t.item.decl |> Shared.declToString t.name.txt)) + ()) else None)) @ !res | _ -> ()); @@ -622,7 +624,8 @@ let completionForExportedFields ~(env : QueryEnv.t) ~prefix ~exact ~namesUsed = (Completion.create ~name ~env ~kind: (Completion.Field - (f, t.item.decl |> Shared.declToString t.name.txt))) + (f, t.item.decl |> Shared.declToString t.name.txt)) + ()) else None)) @ !res | _ -> ()); @@ -711,6 +714,17 @@ let detail name (kind : Completion.kind) = | FileModule _ -> "file module" | Field ({typ}, s) -> name ^ ": " ^ (typ |> Shared.typeToString) ^ "\n\n" ^ s | Constructor (c, s) -> showConstructor c ^ "\n\n" ^ s + | OptionNone -> "None\n\n" + | OptionSome -> "Some(_)\n\n" + | Bool -> "boolean\n\n" + | PolyvariantConstructor {name; payload} -> ( + "#" ^ name + ^ + match payload with + | None -> "" + | Some ({desc = Types.Ttuple _} as typeExpr) -> + typeExpr |> Shared.typeToString + | Some typeExpr -> "(" ^ (typeExpr |> Shared.typeToString) ^ ")") let findAllCompletions ~(env : QueryEnv.t) ~prefix ~exact ~namesUsed ~(completionContext : Completable.completionContext) = @@ -790,7 +804,7 @@ let processLocalValue name loc ~prefix ~exact ~env localTables.resultRev <- { (Completion.create ~name:declared.name.txt ~env - ~kind:(Value declared.item)) + ~kind:(Value declared.item) ()) with deprecated = declared.deprecated; docstring = declared.docstring; @@ -807,6 +821,7 @@ let processLocalValue name loc ~prefix ~exact ~env (Ctype.newconstr (Path.Pident (Ident.create "Type Not Known")) [])) + () :: localTables.resultRev let processLocalConstructor name loc ~prefix ~exact ~env @@ -825,7 +840,8 @@ let processLocalConstructor name loc ~prefix ~exact ~env (Constructor ( declared.item, snd declared.item.typeDecl - |> Shared.declToString (fst declared.item.typeDecl) ))) + |> Shared.declToString (fst declared.item.typeDecl) )) + ()) with deprecated = declared.deprecated; docstring = declared.docstring; @@ -846,7 +862,7 @@ let processLocalType name loc ~prefix ~exact ~env ~(localTables : LocalTables.t) localTables.resultRev <- { (Completion.create ~name:declared.name.txt ~env - ~kind:(Type declared.item)) + ~kind:(Type declared.item) ()) with deprecated = declared.deprecated; docstring = declared.docstring; @@ -867,7 +883,7 @@ let processLocalModule name loc ~prefix ~exact ~env localTables.resultRev <- { (Completion.create ~name:declared.name.txt ~env - ~kind:(Module declared.item)) + ~kind:(Module declared.item) ()) with deprecated = declared.deprecated; docstring = declared.docstring; @@ -889,17 +905,55 @@ let getItemsFromOpens ~opens ~localTables ~prefix ~exact ~completionContext = completionsFromThisOpen @ results) [] +(* This is a dedicated function for finding local completions for a specific type expr (as in filtered to match only the type expr). + Filtering is commented out for now though, since the strategy I used did not work out. + The idea here is that _values_ can be filtered on the type, but we still need to complete for modules just like we normally do, + to support using values from other modules. *) +let findLocalCompletionsForTypeExpr ~(localTables : LocalTables.t) ~env ~prefix + ~exact ~opens ~scope typeExpr = + let _targetId = typeExpr.Types.id in + localTables |> LocalTables.populateValues ~env; + localTables |> LocalTables.populateModules ~env; + scope + |> Scope.iterValuesBeforeFirstOpen + (processLocalValue ~prefix ~exact ~env ~localTables); + scope + |> Scope.iterModulesBeforeFirstOpen + (processLocalModule ~prefix ~exact ~env ~localTables); + + let valuesFromOpens = + getItemsFromOpens ~opens ~localTables ~prefix ~exact + ~completionContext:Value + in + + scope + |> Scope.iterValuesAfterFirstOpen + (processLocalValue ~prefix ~exact ~env ~localTables); + scope + |> Scope.iterModulesAfterFirstOpen + (processLocalModule ~prefix ~exact ~env ~localTables); + List.rev_append localTables.resultRev valuesFromOpens +(* TODO: Re-enable/make this work - filtering by type |> List.filter (fun completion -> + match completion.Completion.kind with + | Module _ -> true + | Value {id} when id = targetId -> true + | Value {id} -> + Printf.printf "compared %s with id %i to target %i\n" completion.name + id targetId; + false + | _ -> false) *) + let findLocalCompletionsForValuesAndConstructors ~(localTables : LocalTables.t) ~env ~prefix ~exact ~opens ~scope = localTables |> LocalTables.populateValues ~env; - localTables |> LocalTables.populateConstructors ~env; + (*localTables |> LocalTables.populateConstructors ~env;*) localTables |> LocalTables.populateModules ~env; scope |> Scope.iterValuesBeforeFirstOpen (processLocalValue ~prefix ~exact ~env ~localTables); - scope - |> Scope.iterConstructorsBeforeFirstOpen - (processLocalConstructor ~prefix ~exact ~env ~localTables); + (*scope + |> Scope.iterConstructorsBeforeFirstOpen + (processLocalConstructor ~prefix ~exact ~env ~localTables);*) scope |> Scope.iterModulesBeforeFirstOpen (processLocalModule ~prefix ~exact ~env ~localTables); @@ -912,9 +966,9 @@ let findLocalCompletionsForValuesAndConstructors ~(localTables : LocalTables.t) scope |> Scope.iterValuesAfterFirstOpen (processLocalValue ~prefix ~exact ~env ~localTables); - scope - |> Scope.iterConstructorsAfterFirstOpen - (processLocalConstructor ~prefix ~exact ~env ~localTables); + (*scope + |> Scope.iterConstructorsAfterFirstOpen + (processLocalConstructor ~prefix ~exact ~env ~localTables);*) scope |> Scope.iterModulesAfterFirstOpen (processLocalModule ~prefix ~exact ~env ~localTables); @@ -980,6 +1034,14 @@ let findLocalCompletionsWithOpens ~pos ~(env : QueryEnv.t) ~prefix ~exact ~opens (* There's no local completion for fields *) [] +let findLocalCompletionsForTypeExprWithOpens ~(env : QueryEnv.t) ~prefix ~exact + ~opens ~scope typeExpr = + (* TODO: handle arbitrary interleaving of opens and local bindings correctly *) + let localTables = LocalTables.create () in + typeExpr + |> findLocalCompletionsForTypeExpr ~localTables ~env ~exact ~opens ~scope + ~prefix + let rec extractRecordType ~env ~package (t : Types.type_expr) = match t.desc with | Tlink t1 | Tsubst t1 | Tpoly (t1, []) -> extractRecordType ~env ~package t1 @@ -992,6 +1054,57 @@ let rec extractRecordType ~env ~package (t : Types.type_expr) = | _ -> None) | _ -> None +(* Had to add another type level here to cover that polyvariants are inlined into to the type system. Mostly a temporary solution. *) +(* TODO: This has overlap with Declared, which is confusing. *) +type extractedType = + | Declared of QueryEnv.t * Type.t Declared.t + | Polyvariant of QueryEnv.t * SharedTypes.polyVariantConstructor list + | Tuple of QueryEnv.t * Types.type_expr list + | Toption of QueryEnv.t * Types.type_expr + | Tbool of QueryEnv.t + +(* This is a more general extraction function for pulling out the type of a type_expr. We already have other similar functions, but they are all specialized on something (variants, records, etc). *) +let rec extractType ~env ~package (t : Types.type_expr) = + match t.desc with + | Tlink t1 | Tsubst t1 | Tpoly (t1, []) -> extractType ~env ~package t1 + | Tconstr (Path.Pident {name = "option"}, [payloadTypeExpr], _) -> + (* Handle option. TODO: Look up how the compiler does this and copy that behavior. *) + Some (Toption (env, payloadTypeExpr)) + | Tconstr (Path.Pident {name = "bool"}, [], _) -> + (* Handle bool. TODO: Look up how the compiler does this and copy that behavior. *) + Some (Tbool env) + | Tconstr (path, _, _) -> ( + match References.digConstructor ~env ~package path with + | Some (env, {item = {decl = {type_manifest = Some t1}}}) -> + extractType ~env ~package t1 + | Some (env, typ) -> Some (Declared (env, typ)) + | None -> None) + | Tvariant {row_fields} -> + (* Since polyvariants are strutural, they're "inlined". So, we extract just + what we need for completion from that definition here. *) + let constructors = + row_fields + |> List.map (fun (label, field) -> + { + name = label; + payload = + (match field with + | Types.Rpresent maybeTypeExpr -> maybeTypeExpr + | _ -> None); + args = + (* Multiple arguments are represented as a Ttuple, while a single argument is just the type expression itself. *) + (match field with + | Types.Rpresent (Some typeExpr) -> ( + match typeExpr.desc with + | Ttuple args -> args + | _ -> [typeExpr]) + | _ -> []); + }) + in + Some (Polyvariant (env, constructors)) + | Ttuple expressions -> Some (Tuple (env, expressions)) + | _ -> None + let rec extractObjectType ~env ~package (t : Types.type_expr) = match t.desc with | Tlink t1 | Tsubst t1 | Tpoly (t1, []) -> extractObjectType ~env ~package t1 @@ -1037,7 +1150,7 @@ let getCompletionsForPath ~package ~opens ~allFiles ~pos ~exact ~scope then Some (Completion.create ~name ~env - ~kind:(Completion.FileModule name)) + ~kind:(Completion.FileModule name) ()) else None) in localCompletionsWithOpens @ fileModules @@ -1050,7 +1163,8 @@ let getCompletionsForPath ~package ~opens ~allFiles ~pos ~exact ~scope findAllCompletions ~env ~prefix ~exact ~namesUsed ~completionContext | None -> []) -let mkItem ~name ~kind ~detail ~deprecated ~docstring = +let mkItem ~name ~sortText ~insertText ~insertTextFormat ~kind ~detail + ~deprecated ~docstring = let docContent = (match deprecated with | None -> "" @@ -1074,10 +1188,22 @@ let mkItem ~name ~kind ~detail ~deprecated ~docstring = documentation = (if docContent = "" then None else Some {kind = "markdown"; value = docContent}); + sortText; + insertText; + insertTextFormat; } -let completionToItem {Completion.name; deprecated; docstring; kind} = - mkItem ~name +let completionToItem + { + Completion.name; + deprecated; + docstring; + kind; + sortText; + insertText; + insertTextFormat; + } = + mkItem ~name ~sortText ~insertText ~insertTextFormat ~kind:(Completion.kindToInt kind) ~deprecated ~detail:(detail name kind) ~docstring @@ -1095,14 +1221,16 @@ let rec getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos Completion.create ~name:"string" ~env ~kind: (Completion.Value - (Ctype.newconstr (Path.Pident (Ident.create "string")) [])); + (Ctype.newconstr (Path.Pident (Ident.create "string")) [])) + (); ] | CPArray -> [ Completion.create ~name:"array" ~env ~kind: (Completion.Value - (Ctype.newconstr (Path.Pident (Ident.create "array")) [])); + (Ctype.newconstr (Path.Pident (Ident.create "array")) [])) + (); ] | CPId (path, completionContext) -> path @@ -1146,9 +1274,40 @@ let rec getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos | args, tRet when args <> [] -> let args = processApply args labels in let retType = reconstructFunctionType args tRet in - [Completion.create ~name:"dummy" ~env ~kind:(Completion.Value retType)] + [ + Completion.create ~name:"dummy" ~env ~kind:(Completion.Value retType) + (); + ] | _ -> []) | None -> []) + | CTuple ctxPaths -> + (* Turn a list of context paths into a list of type expressions. *) + let typeExrps = + ctxPaths + |> List.map (fun contextPath -> + contextPath + |> getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles + ~pos ~env ~exact:true ~scope) + |> List.filter_map (fun completionItems -> + match completionItems with + | completionItem :: _ -> ( + match completionItem.Completion.kind with + | Value typ -> Some typ + | _ -> None) + | _ -> None) + in + if List.length ctxPaths = List.length typeExrps then + (* We return a "dummy" completion here with a dummy made-up type. + This completion and type is never meant to be used for anything but looking up _other_ types, + which is why this is presumably OK to do. *) + [ + Completion.create ~name:"dummy" ~env + ~kind: + (Completion.Value + Types.{level = 0; id = -1; desc = Ttuple typeExrps}) + (); + ] + else [] | CPField (CPId (path, Module), fieldName) -> (* M.field *) path @ [fieldName] @@ -1173,7 +1332,8 @@ let rec getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos (Completion.Field ( field, typDecl.item.decl - |> Shared.declToString typDecl.name.txt ))) + |> Shared.declToString typDecl.name.txt )) + ()) else None) | None -> []) | None -> []) @@ -1201,7 +1361,7 @@ let rec getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos if checkName field ~prefix:label ~exact then Some (Completion.create ~name:field ~env - ~kind:(Completion.ObjLabel typ)) + ~kind:(Completion.ObjLabel typ) ()) else None) | None -> []) | None -> []) @@ -1324,17 +1484,269 @@ let getOpens ~rawOpens ~package ~env = (* Last open takes priority *) List.rev resolvedOpens -let processCompletable ~debug ~package ~scope ~env ~pos ~forHover - (completable : Completable.t) = - let rawOpens = Scope.getRawOpens scope in - let opens = getOpens ~rawOpens ~package ~env in - let allFiles = FileSet.union package.projectFiles package.dependenciesFiles in +(* Temporary while I figure things out. This should be merged with the completable we already have. *) +type completable = + | CRecord of { + fields: field list; + decl: Types.type_declaration; + name: string Location.loc; + } + | CInlineRecord of field list + | CVariant of {constructors: Constructor.t list} + | CPolyVariant of {constructors: polyVariantConstructor list} + | COptional of completable + | CTuple of {types: Types.type_expr list} + | CBool + +let rec typeExprToCompletable typ ~env ~package = + match typ |> extractType ~env ~package with + | Some (Declared (_, {name; item = {kind = Record fields; decl}})) -> + Some (CRecord {fields; decl; name}) + | Some (Declared (_, {item = {kind = Variant constructors}})) -> + Some (CVariant {constructors}) + | Some (Polyvariant (_, constructors)) -> Some (CPolyVariant {constructors}) + | Some (Tbool _) -> Some CBool + | Some (Toption (env, typ)) -> ( + match typ |> typeExprToCompletable ~env ~package with + | None -> None + | Some typ -> Some (COptional typ)) + | Some (Declared (_, {item = {kind = Abstract _}})) -> None + | Some (Tuple (_, types)) -> Some (CTuple {types}) + | _ -> None + +let findInlineRecordInConstructor constructor = + let _, typeDecl = constructor.Constructor.typeDecl in + match typeDecl.type_kind with + | Type_variant constructors -> ( + match + constructors + |> List.find_opt (fun constr -> + constr.Types.cd_id.Ident.name == constructor.cname.txt) + with + | Some {cd_args = Cstr_record fields} -> + Some (fields |> List.map ProcessCmt.mapRecordField) + | _ -> None) + | _ -> None + +(* Takes a type_expr and figures out what completable it corresponds to, if any. If the target type is nested somewhere inside of the type_expr, + nestedContextPath will be populated with instructions on how to reach that part. This is primarily used in patterns, + where the cursor can be deep into the pattern. *) +let findTypeInContext (typ : Types.type_expr) ~env ~nestedContextPath ~package = + let rec digToType (currentType : Types.type_expr) ~env ~nestedContextPath + ~package = + (* Check the current context path item *) + match nestedContextPath with + | [] -> + (* If there's no context path, complete the current type *) + typeExprToCompletable currentType ~env ~package + | targetItem :: nestedContextPath -> ( + match (targetItem, currentType |> extractType ~env ~package) with + | ( Completable.RField {fieldName}, + Some (Declared (env, {item = {kind = Record fields}})) ) -> ( + match + fields |> List.find_opt (fun field -> field.fname.txt = fieldName) + with + | None -> None + | Some targetField -> + if List.length nestedContextPath > 0 then + targetField.typ |> digToType ~env ~nestedContextPath ~package + else typeExprToCompletable targetField.typ ~env ~package) + | ( Variant {constructorName; payloadNum}, + Some (Declared (env, {item = {kind = Variant constructors}})) ) -> ( + match + constructors + |> List.find_opt (fun constructor -> + constructor.Constructor.cname.txt = constructorName) + with + | Some constructor -> ( + (* payloadNum tells us whether there's also a payload we should descend into. *) + match payloadNum with + | None -> Some (CVariant {constructors}) + | Some argNum -> ( + (* If we find the argument/payload requested, descend into that *) + match List.nth_opt constructor.args argNum with + | None -> ( + (* If we can't find the arg, it might be an inline record *) + match findInlineRecordInConstructor constructor with + | Some inlineRecordFields -> + Some (CInlineRecord inlineRecordFields) + | _ -> None) + | Some (argType, _) -> + argType |> digToType ~env ~nestedContextPath ~package)) + | None -> None) + | Polyvariant {name; payloadNum}, Some (Polyvariant (env, constructors)) + -> ( + match + constructors + |> List.find_opt (fun (constructor : polyVariantConstructor) -> + constructor.name = name) + with + | Some constructor -> ( + match payloadNum with + | None -> Some (CPolyVariant {constructors}) + | Some argNum -> ( + match List.nth_opt constructor.args argNum with + | None -> None + | Some argType -> + argType |> digToType ~env ~nestedContextPath ~package)) + | None -> None) + | PTuple {itemNumber}, Some (Tuple (env, exprs)) -> ( + match List.nth_opt exprs itemNumber with + | None -> None + | Some typeExpr -> + typeExpr |> digToType ~env ~nestedContextPath ~package) + | Variant {constructorName = "Some"}, Some (Toption (env, typeExpr)) -> + typeExpr |> digToType ~env ~nestedContextPath ~package + | _ -> None) + in + typ |> digToType ~env ~nestedContextPath ~package + +(* Takes a context and a component path (SomeModule.SomeComponent) and extracts all labels *) +let getLabelsForComponent ~package ~opens ~allFiles ~pos ~env ~scope + componentPath = let findTypeOfValue path = path |> getCompletionsForPath ~completionContext:Value ~exact:true ~package ~opens ~allFiles ~pos ~env ~scope |> completionsGetTypeEnv in + + match componentPath @ ["make"] |> findTypeOfValue with + | Some (typ, _env) -> + let rec getFields (texp : Types.type_expr) = + match texp.desc with + | Tfield (name, _, t1, t2) -> + let fields = t2 |> getFields in + if name = "children" then fields else (name, t1) :: fields + | Tlink te | Tsubst te | Tpoly (te, []) -> te |> getFields + | Tvar None -> [] + | _ -> [] + in + let rec getLabels (t : Types.type_expr) = + match t.desc with + | Tlink t1 | Tsubst t1 | Tpoly (t1, []) -> getLabels t1 + | Tarrow + ( Nolabel, + { + desc = + ( Tconstr (* Js.t *) (_, [{desc = Tobject (tObj, _)}], _) + | Tobject (tObj, _) ); + }, + _, + _ ) -> + getFields tObj + | Tconstr + ( path, + [ + { + desc = + ( Tconstr (* Js.t *) (_, [{desc = Tobject (tObj, _)}], _) + | Tobject (tObj, _) ); + }; + _; + ], + _ ) + when Path.name path = "React.componentLike" -> + getFields tObj + | _ -> [] + in + typ |> getLabels + | None -> [] + +(* This pulls out the type we want to do type based completion based on, using an instruction. + This instruction can be "the type that the jsx prop X wants in component Y". *) +let rec findSourceType sourceType ~package ~opens ~rawOpens ~allFiles ~env + ~scope ~pos = + match sourceType with + | Completable.NamedArg {label; contextPath} -> ( + (* TODO: Should probably share this with the branch handling CnamedArg... *) + let labels = + match + (* This just hijacks getCompletionsForContextPath and completionsGetTypeEnv because they + already kind of do what I need. Should break this out to its own, dedicated thing later. *) + contextPath + |> getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos + ~env ~exact:true ~scope + |> completionsGetTypeEnv + with + | Some (typ, env) -> + let rec getLabels ~env (t : Types.type_expr) = + match t.desc with + | Tlink t1 | Tsubst t1 | Tpoly (t1, []) -> getLabels ~env t1 + | Tarrow ((Labelled l | Optional l), tArg, tRet, _) -> + (l, tArg) :: getLabels ~env tRet + | Tarrow (Nolabel, _, tRet, _) -> getLabels ~env tRet + | Tconstr (path, _, _) -> ( + match References.digConstructor ~env ~package path with + | Some (env, {item = {decl = {type_manifest = Some t1}}}) -> + getLabels ~env t1 + | _ -> []) + | _ -> [] + in + typ |> getLabels ~env + | None -> [] + in + let targetLabel = + labels |> List.find_opt (fun (name, _t) -> name = label) + in + match targetLabel with + | Some (_, typeExpr) -> Some (typeExpr, env) + | _ -> None) + | JsxProp {componentPath; propName} -> ( + match + componentPath + |> getLabelsForComponent ~package ~opens ~allFiles ~pos ~env ~scope + |> List.find_opt (fun (label, _typeExpr) -> label = propName) + with + | None -> None + | Some (_label, typeExpr) -> Some (typeExpr, env)) + | CtxPath typeSourceContextPath -> ( + match + typeSourceContextPath + |> getCompletionsForContextPath ~package ~opens ~rawOpens ~allFiles ~pos + ~env ~exact:true ~scope + |> completionsGetTypeEnv + with + | Some (typ, env) -> Some (typ, env) + | None -> None) + | FunctionArgument {howToFindFunctionType; arg} -> ( + match + howToFindFunctionType + |> findSourceType ~package ~opens ~rawOpens ~allFiles ~env ~scope ~pos + with + | Some (typ, env) -> ( + let labels, _ = typ |> extractFunctionType ~env ~package in + match arg with + | Unlabelled argNum -> + let idx = ref 0 in + labels + |> List.find_map (fun (label, typExpr) -> + match label with + | Asttypes.Nolabel -> + if argNum = !idx then Some (typExpr, env) + else ( + idx := !idx + 1; + None) + | _ -> None) + | Labelled lookingForLabel -> + labels + |> List.find_map (fun (label, typExpr) -> + match label with + | (Asttypes.Labelled labelName | Optional labelName) + when labelName = lookingForLabel -> + Some (typExpr, env) + | _ -> None)) + | _ -> None) + +let constructorHasArgs constructor = + constructor.Constructor.args |> List.length > 0 + || findInlineRecordInConstructor constructor |> Option.is_some + +let processCompletable ~debug ~package ~scope ~env ~pos ~forHover + (completable : Completable.t) = + let rawOpens = Scope.getRawOpens scope in + let opens = getOpens ~rawOpens ~package ~env in + let allFiles = FileSet.union package.projectFiles package.dependenciesFiles in match completable with | Cnone -> [] | Cpath contextPath -> @@ -1343,7 +1755,7 @@ let processCompletable ~debug ~package ~scope ~env ~pos ~forHover ~env ~exact:forHover ~scope | Cjsx ([id], prefix, identsSeen) when String.uncapitalize_ascii id = id -> let mkLabel (name, typString) = - Completion.create ~name ~kind:(Label typString) ~env + Completion.create ~name ~kind:(Label typString) ~env () in let keyLabels = if Utils.startsWith "key" prefix then [mkLabel ("key", "string")] else [] @@ -1356,50 +1768,11 @@ let processCompletable ~debug ~package ~scope ~env ~pos ~forHover @ keyLabels | Cjsx (componentPath, prefix, identsSeen) -> let labels = - match componentPath @ ["make"] |> findTypeOfValue with - | Some (typ, _env) -> - let rec getFields (texp : Types.type_expr) = - match texp.desc with - | Tfield (name, _, t1, t2) -> - let fields = t2 |> getFields in - if name = "children" then fields else (name, t1) :: fields - | Tlink te | Tsubst te | Tpoly (te, []) -> te |> getFields - | Tvar None -> [] - | _ -> [] - in - let rec getLabels (t : Types.type_expr) = - match t.desc with - | Tlink t1 | Tsubst t1 | Tpoly (t1, []) -> getLabels t1 - | Tarrow - ( Nolabel, - { - desc = - ( Tconstr (* Js.t *) (_, [{desc = Tobject (tObj, _)}], _) - | Tobject (tObj, _) ); - }, - _, - _ ) -> - getFields tObj - | Tconstr - ( path, - [ - { - desc = - ( Tconstr (* Js.t *) (_, [{desc = Tobject (tObj, _)}], _) - | Tobject (tObj, _) ); - }; - _; - ], - _ ) - when Path.name path = "React.componentLike" -> - getFields tObj - | _ -> [] - in - typ |> getLabels - | None -> [] + componentPath + |> getLabelsForComponent ~package ~opens ~allFiles ~pos ~env ~scope in let mkLabel_ name typString = - Completion.create ~name ~kind:(Label typString) ~env + Completion.create ~name ~kind:(Label typString) ~env () in let mkLabel (name, typ) = mkLabel_ name (typ |> Shared.typeToString) in let keyLabels = @@ -1415,7 +1788,7 @@ let processCompletable ~debug ~package ~scope ~env ~pos ~forHover @ keyLabels | Cdecorator prefix -> let mkDecorator (name, docstring) = - {(Completion.create ~name ~kind:(Label "") ~env) with docstring} + {(Completion.create ~name ~kind:(Label "") ~env ()) with docstring} in [ ( "as", @@ -1679,10 +2052,454 @@ Note: The `@react.component` decorator requires the react-jsx config to be set i | None -> [] in let mkLabel (name, typ) = - Completion.create ~name ~kind:(Label (typ |> Shared.typeToString)) ~env + Completion.create ~name ~kind:(Label (typ |> Shared.typeToString)) ~env () in labels |> List.filter (fun (name, _t) -> Utils.startsWith name prefix && (forHover || not (List.mem name identsSeen))) |> List.map mkLabel + | CtypedPattern + { + howToRetrieveSourceType; + patternPath; + lookingToComplete; + prefix; + alreadySeenIdents; + } -> ( + let prefix = if prefix = "_" then "" else prefix in + let sourceType = + howToRetrieveSourceType + |> findSourceType ~package ~opens ~rawOpens ~allFiles ~env ~pos ~scope + in + match sourceType with + | None -> [] + | Some (typ, env) -> ( + match + ( typ |> findTypeInContext ~env ~nestedContextPath:patternPath ~package, + lookingToComplete ) + with + | None, _ -> [] + | Some (CTuple {types}), _ -> + (* Completing a tuple itself, like `{someFieldWithTuple: }` *) + [ + Completion.create + ~name: + ("(" + ^ (types |> List.map (fun _t -> "_") |> String.concat ", ") + ^ ")") + ~insertText: + ("(" + ^ (types + |> List.mapi (fun index _t -> + Printf.sprintf "${%i:_}" (index + 1)) + |> String.concat ", ") + ^ ")") + ~insertTextFormat:Snippet ~env ~sortText:"a" + ~kind:(Completion.Label "Full tuple match") (); + Completion.create ~name:"()" ~env ~sortText:"b" ~insertText:"($1)" + ~insertTextFormat:Snippet + ~kind:(Completion.Label "Empty tuple match for single element") (); + ] + | Some CBool, _ -> + (* Completing booleans - doesn't matter what we're looking to complete, since there's only one thing to complete (the bool values themselves). *) + ["false"; "true"] + |> List.filter (fun boolEntry -> + Utils.startsWith boolEntry prefix + && not + (alreadySeenIdents + |> List.exists (fun seenIdent -> seenIdent = boolEntry))) + |> List.map (fun boolEntry -> + Completion.create ~name:boolEntry ~kind:Bool ~env ()) + | Some (COptional completable), _lookingToComplete -> ( + (* TODO: Account for lookingToComplete? *) + match completable with + | CVariant {constructors} -> + (* TOOD: Unify with other variant completion handler *) + let constructorCompletions = + constructors + |> List.filter (fun constructor -> + Utils.startsWith + ("Some(" ^ constructor.Constructor.cname.txt ^ ")") + prefix + && not + (alreadySeenIdents + |> List.exists (fun alreadySeenConstructorName -> + alreadySeenConstructorName + = constructor.Constructor.cname.txt))) + |> List.map (fun (constructor : Constructor.t) -> + (* TODO: Can we leverage snippets here for automatically moving the cursor when there are multiple payloads? + Eg. Some($1) as completion item. *) + Completion.create + ~name: + ("Some(" ^ constructor.cname.txt + ^ + if constructor.args |> List.length > 0 then "(_))" + else ")") + ~insertText: + ("Some(" ^ constructor.cname.txt + ^ + if constructor.args |> List.length > 0 then "(${1:_}))" + else ")") + ~insertTextFormat:Snippet + ~kind:(Constructor (constructor, "")) + ~env ()) + in + (* TODO: Patterns should not include local completions *) + let _localCompletions = + typ + |> findLocalCompletionsForTypeExprWithOpens ~env ~prefix + ~exact:false ~opens ~scope + in + [Completion.create ~name:"None" ~kind:OptionNone ~env ()] + @ constructorCompletions + | CPolyVariant {constructors} -> + (* TOOD: Unify with other variant completion handler *) + let constructorCompletions = + constructors + |> List.filter (fun (constructor : polyVariantConstructor) -> + Utils.startsWith ("Some(#" ^ constructor.name ^ ")") prefix) + |> List.map (fun (constructor : polyVariantConstructor) -> + (* TODO: Can we leverage snippets here for automatically moving the cursor when there are multiple payloads? + Eg. Some($1) as completion item. *) + Completion.create + ~name: + ("Some(#" ^ constructor.name + ^ + if constructor.payload |> Option.is_some then "(_))" + else ")") + ~insertTextFormat:Snippet + ~insertText: + ("Some(#" ^ constructor.name + ^ + if constructor.payload |> Option.is_some then "(${1:_}))" + else ")") + ~kind:(PolyvariantConstructor constructor) ~env ()) + in + (* TODO: Patterns should not include local completions *) + let _localCompletions = + typ + |> findLocalCompletionsForTypeExprWithOpens ~env ~prefix + ~exact:false ~opens ~scope + in + [Completion.create ~name:"None" ~kind:OptionNone ~env ()] + @ constructorCompletions + | _ -> + [ + Completion.create ~name:"None" ~kind:OptionNone ~env (); + Completion.create ~name:"Some(_)" ~insertText:"Some(${1:_})" + ~insertTextFormat:Snippet ~kind:OptionSome ~env (); + ]) + | Some (CPolyVariant {constructors}), _ -> + let constructorCompletions = + constructors + |> List.filter (fun (constructor : polyVariantConstructor) -> + Utils.startsWith constructor.name prefix) + |> List.map (fun (constructor : polyVariantConstructor) -> + (* TODO: Can we leverage snippets here for automatically moving the cursor when there are multiple payloads? + Eg. Some($1) as completion item. *) + Completion.create + ~name: + ("#" ^ constructor.name + ^ + if constructor.payload |> Option.is_some then "(_)" else "" + ) + ~insertText: + ("#" ^ constructor.name + ^ + if constructor.payload |> Option.is_some then "(${1:_})" + else "") + ~insertTextFormat:Snippet + ~kind:(PolyvariantConstructor constructor) ~env ()) + in + let _localCompletions = + typ + |> findLocalCompletionsForTypeExprWithOpens ~env ~prefix ~exact:false + ~opens ~scope + in + constructorCompletions + | Some (CVariant {constructors}), _ -> + let constructorCompletions = + constructors + |> List.filter (fun constructor -> + Utils.startsWith constructor.Constructor.cname.txt prefix + && not + (alreadySeenIdents + |> List.exists (fun alreadySeenConstructorName -> + alreadySeenConstructorName + = constructor.Constructor.cname.txt))) + |> List.map (fun (constructor : Constructor.t) -> + let hasArgs = constructorHasArgs constructor in + Completion.create + ~name:(constructor.cname.txt ^ if hasArgs then "(_)" else "") + ~insertTextFormat:Snippet + ~insertText: + (constructor.cname.txt ^ if hasArgs then "(${1:_})" else "") + ~kind:(Constructor (constructor, "")) + ~env ()) + in + let _localCompletions = + typ + |> findLocalCompletionsForTypeExprWithOpens ~env ~prefix ~exact:false + ~opens ~scope + in + constructorCompletions + | Some (CRecord {fields; decl; name}), CRecordField -> + fields + |> List.filter (fun (field : field) -> + not + (alreadySeenIdents + |> List.exists (fun fieldName -> fieldName = field.fname.txt))) + |> Utils.filterMap (fun (field : field) -> + if prefix = "" || checkName field.fname.txt ~prefix ~exact:false + then + Some + (Completion.create ~name:field.fname.txt ~env + ~kind: + (Completion.Field + (field, decl |> Shared.declToString name.txt)) + ()) + else None) + | Some (CInlineRecord fields), CRecordField -> + fields + |> List.filter (fun (field : field) -> + not + (alreadySeenIdents + |> List.exists (fun fieldName -> fieldName = field.fname.txt))) + |> Utils.filterMap (fun (field : field) -> + if prefix = "" || checkName field.fname.txt ~prefix ~exact:false + then + Some + (Completion.create ~name:field.fname.txt ~env + ~kind: + (Completion.Field + (field, field.typ |> Shared.typeToString)) + ()) + else None) + | Some (CRecord _ | CInlineRecord _), _ -> + [ + Completion.create ~name:"{}" ~insertText:"{${1}}" + ~insertTextFormat:Snippet ~env ~sortText:"a" + ~kind:(Completion.Label "Empty record") (); + ])) + | CtypedExpression + { + howToRetrieveSourceType; + expressionPath; + lookingToComplete; + prefix; + alreadySeenIdents; + } -> ( + let sourceType = + howToRetrieveSourceType + |> findSourceType ~package ~opens ~rawOpens ~allFiles ~env ~pos ~scope + in + match sourceType with + | None -> [] + | Some (typ, env) -> ( + match + ( typ + |> findTypeInContext ~env ~nestedContextPath:expressionPath ~package, + lookingToComplete ) + with + | None, _ -> [] + | Some (CTuple {types}), _ -> + (* Completing a tuple itself, like `{someFieldWithTuple: }` *) + [ + Completion.create + ~name: + ("(" + ^ (types |> List.map (fun _t -> "_") |> String.concat ", ") + ^ ")") + ~insertText: + ("(" + ^ (types + |> List.mapi (fun index _t -> + Printf.sprintf "${%i:_}" (index + 1)) + |> String.concat ", ") + ^ ")") + ~insertTextFormat:Snippet ~env ~sortText:"a" + ~kind:(Completion.Label "Tuple") (); + ] + | Some CBool, _ -> + (* Completing booleans - doesn't matter what we're looking to complete, since there's only one thing to complete (the bool values themselves). *) + ["false"; "true"] + |> List.filter (fun boolEntry -> Utils.startsWith boolEntry prefix) + |> List.map (fun boolEntry -> + Completion.create ~name:boolEntry ~kind:Bool ~env ()) + | Some (COptional completable), _lookingToComplete -> ( + match completable with + | CVariant {constructors} -> + (* TOOD: Unify with other variant completion handler *) + let constructorCompletions = + constructors + |> List.filter (fun constructor -> + Utils.startsWith + ("Some(" ^ constructor.Constructor.cname.txt ^ ")") + prefix) + |> List.map (fun (constructor : Constructor.t) -> + Completion.create + ~name: + ("Some(" ^ constructor.cname.txt + ^ + if constructor.args |> List.length > 0 then "(_))" + else ")") + ~insertText: + ("Some(" ^ constructor.cname.txt + ^ + if constructor.args |> List.length > 0 then "($1))" + else ")") + ~insertTextFormat:Snippet + ~kind:(Constructor (constructor, "")) + ~env ()) + in + (* TODO: Patterns should not include local completions *) + let _localCompletions = + typ + |> findLocalCompletionsForTypeExprWithOpens ~env ~prefix + ~exact:false ~opens ~scope + in + [Completion.create ~name:"None" ~kind:OptionNone ~env ()] + @ constructorCompletions + | CPolyVariant {constructors} -> + (* TOOD: Unify with other variant completion handler *) + let constructorCompletions = + constructors + |> List.filter (fun (constructor : polyVariantConstructor) -> + Utils.startsWith ("Some(#" ^ constructor.name ^ ")") prefix) + |> List.map (fun (constructor : polyVariantConstructor) -> + Completion.create + ~name: + ("Some(#" ^ constructor.name + ^ + if constructor.payload |> Option.is_some then "(_))" + else ")") + ~insertTextFormat:Snippet + ~insertText: + ("Some(#" ^ constructor.name + ^ + if constructor.payload |> Option.is_some then "($1))" + else ")") + ~kind:(PolyvariantConstructor constructor) ~env ()) + in + (* TODO: Patterns should not include local completions *) + let _localCompletions = + typ + |> findLocalCompletionsForTypeExprWithOpens ~env ~prefix + ~exact:false ~opens ~scope + in + [Completion.create ~name:"None" ~kind:OptionNone ~env ()] + @ constructorCompletions + | _ -> + [ + Completion.create ~name:"None" ~kind:OptionNone ~env (); + Completion.create ~name:"Some()" ~insertText:"Some($1)" + ~insertTextFormat:Snippet ~kind:OptionSome ~env (); + ]) + | Some (CPolyVariant {constructors}), _ -> + let constructorCompletions = + constructors + |> List.filter (fun (constructor : polyVariantConstructor) -> + Utils.startsWith constructor.name prefix) + |> List.map (fun (constructor : polyVariantConstructor) -> + Completion.create + ~name: + ("#" ^ constructor.name + ^ + if constructor.payload |> Option.is_some then "(_)" else "" + ) + ~insertText: + ("#" ^ constructor.name + ^ + if constructor.payload |> Option.is_some then "($1)" + else "") + ~insertTextFormat:Snippet + ~kind:(PolyvariantConstructor constructor) ~env ()) + in + let _localCompletions = + typ + |> findLocalCompletionsForTypeExprWithOpens ~env ~prefix ~exact:false + ~opens ~scope + in + constructorCompletions + | Some (CVariant {constructors}), _ -> + let constructorCompletions = + constructors + |> List.filter (fun constructor -> + Utils.startsWith constructor.Constructor.cname.txt prefix) + |> List.map (fun (constructor : Constructor.t) -> + Completion.create + ~name: + (constructor.cname.txt + ^ if constructor.args |> List.length > 0 then "(_)" else "" + ) + ~insertTextFormat:Snippet + ~insertText: + (constructor.cname.txt + ^ + if constructor.args |> List.length > 0 then "($1)" else "" + ) + ~kind:(Constructor (constructor, "")) + ~env ()) + in + let _localCompletions = + typ + |> findLocalCompletionsForTypeExprWithOpens ~env ~prefix ~exact:false + ~opens ~scope + in + constructorCompletions + | Some (CRecord {fields; decl; name}), CRecordField -> + fields + |> List.filter (fun (field : field) -> + not + (alreadySeenIdents + |> List.exists (fun fieldName -> fieldName = field.fname.txt))) + |> Utils.filterMap (fun (field : field) -> + if prefix = "" || checkName field.fname.txt ~prefix ~exact:false + then + Some + (Completion.create ~name:field.fname.txt ~env + ~kind: + (Completion.Field + (field, decl |> Shared.declToString name.txt)) + ()) + else None) + | Some (CInlineRecord fields), CRecordField -> + fields + |> List.filter (fun (field : field) -> + not + (alreadySeenIdents + |> List.exists (fun fieldName -> fieldName = field.fname.txt))) + |> Utils.filterMap (fun (field : field) -> + if prefix = "" || checkName field.fname.txt ~prefix ~exact:false + then + Some + (Completion.create ~name:field.fname.txt ~env + ~kind: + (Completion.Field + (field, field.typ |> Shared.typeToString)) + ()) + else None) + | Some (CRecord {fields} | CInlineRecord fields), _ -> + [ + Completion.create + ~name: + ("{" + ^ (fields + |> List.map (fun field -> field.fname.txt) + |> String.concat ", ") + ^ "}") + ~insertText: + ("{\n" + ^ (fields + |> List.mapi (fun index field -> + Printf.sprintf " %s: ${%i:%s}" field.fname.txt + (index + 1) "assert false") + |> String.concat ", \n") + ^ "\n}") + ~insertTextFormat:Snippet ~env ~sortText:"a" + ~kind:(Completion.Label "Complete record props") (); + Completion.create ~name:"{}" ~insertText:"{$1}" + ~insertTextFormat:Snippet ~env ~sortText:"b" + ~kind:(Completion.Label "Empty record") (); + ])) diff --git a/analysis/src/CompletionFrontEnd.ml b/analysis/src/CompletionFrontEnd.ml index 2bb5ab2de..27d1fd6ef 100644 --- a/analysis/src/CompletionFrontEnd.ml +++ b/analysis/src/CompletionFrontEnd.ml @@ -7,25 +7,660 @@ let rec skipWhite text i = | ' ' | '\n' | '\r' | '\t' -> skipWhite text (i - 1) | _ -> i -let offsetOfLine text line = - let ln = String.length text in - let rec loop i lno = - if i >= ln then None - else - match text.[i] with - | '\n' -> if lno = line - 1 then Some (i + 1) else loop (i + 1) (lno + 1) - | _ -> loop (i + 1) lno - in - match line with - | 0 -> Some 0 - | _ -> loop 0 0 - -let positionToOffset text (line, character) = - match offsetOfLine text line with - | None -> None - | Some bol -> - if bol + character <= String.length text then Some (bol + character) +let rec getSimpleFieldName txt = + match txt with + | Longident.Lident fieldName -> fieldName + | Ldot (t, _) -> getSimpleFieldName t + | _ -> "" + +(* Variants can have payloads. We need to figure out which of the payloads we're in, so we can find the type at that position as we try to do completion. + We also need to continue descending into the pattern of the argument under the cursor to find any inner type. *) +let findVariantPayloadItemNumWithCursor pat ~pos = + match pat.Parsetree.ppat_desc with + | Ppat_tuple patterns -> + let res = ref None in + patterns + |> List.iteri (fun index tuplePat -> + match pat.Parsetree.ppat_loc |> CursorPosition.classifyLoc ~pos with + | HasCursor -> res := Some (index, tuplePat) + | _ -> ()); + !res + | _ -> Some (0, pat) + +let identFromPat pat = + match pat.Parsetree.ppat_desc with + | Ppat_var loc -> Some loc.txt + | Ppat_construct (loc, _) -> Some (getSimpleFieldName loc.txt) + | Ppat_variant (label, _) -> Some label + | _ -> None + +let rec identListFromPat pat = + match pat.Parsetree.ppat_desc with + | Ppat_var loc -> [loc.txt] + (* Allow moving one level into variants, just to be able to complete Some(One) etc successfully *) + (* E.g. Some(One)*) + | Ppat_construct (loc, Some {ppat_desc = Ppat_construct (innerLoc, _)}) -> + [getSimpleFieldName loc.txt ^ "(" ^ getSimpleFieldName innerLoc.txt ^ ")"] + (* E.g. Some(#One)*) + | Ppat_construct (loc, Some {ppat_desc = Ppat_variant (innerLabel, _)}) -> + [getSimpleFieldName loc.txt ^ "(" ^ innerLabel ^ ")"] + (* E.g. #Whatever(One)*) + | Ppat_variant (label, Some {ppat_desc = Ppat_construct (innerLoc, _)}) -> + [label ^ "(" ^ getSimpleFieldName innerLoc.txt ^ ")"] + (* E.g. #Whatever(#One)*) + | Ppat_variant (label, Some {ppat_desc = Ppat_variant (innerLabel, _)}) -> + [label ^ "(" ^ innerLabel ^ ")"] + | Ppat_construct (loc, _) -> [getSimpleFieldName loc.txt] + | Ppat_variant (label, _) -> [label] + | Ppat_or (pat1, pat2) -> identListFromPat pat1 @ identListFromPat pat2 + | _ -> [] + +let rec findAllOrBranches pat ~branches = + match pat.Parsetree.ppat_desc with + | Ppat_or (pat1, pat2) -> + pat1 |> findAllOrBranches ~branches:([pat2] @ branches) + | _ -> [pat] @ branches + +(* Extracted for reuse. *) +let rec exprToContextPath (e : Parsetree.expression) = + match e.pexp_desc with + | Pexp_constant (Pconst_string _) -> Some Completable.CPString + | Pexp_array _ -> Some CPArray + | Pexp_ident {txt} -> Some (CPId (Utils.flattenLongIdent txt, Value)) + | Pexp_field (e1, {txt = Lident name}) -> ( + match exprToContextPath e1 with + | Some contextPath -> Some (CPField (contextPath, name)) + | _ -> None) + | Pexp_field (_, {txt = Ldot (lid, name)}) -> + (* Case x.M.field ignore the x part *) + Some (CPField (CPId (Utils.flattenLongIdent lid, Module), name)) + | Pexp_send (e1, {txt}) -> ( + match exprToContextPath e1 with + | None -> None + | Some contexPath -> Some (CPObj (contexPath, txt))) + | Pexp_apply (e1, args) -> ( + match exprToContextPath e1 with + | None -> None + | Some contexPath -> Some (CPApply (contexPath, args |> List.map fst))) + | Pexp_tuple exprs -> + let exprsAsContextPaths = exprs |> List.filter_map exprToContextPath in + if List.length exprs = List.length exprsAsContextPaths then + Some (CTuple exprsAsContextPaths) else None + | _ -> None + +let rec findPatternTupleItemWithCursor items ~index ~pos = + match items with + | [] -> None + | item :: rest -> + if CursorPosition.classifyLoc item.Parsetree.ppat_loc ~pos = HasCursor then + Some (Some item, index) + else findPatternTupleItemWithCursor rest ~index:(index + 1) ~pos + +let rec findExprTupleItemWithCursor items ~index ~pos = + match items with + | [] -> None + | item :: rest -> + if CursorPosition.classifyLoc item.Parsetree.pexp_loc ~pos = HasCursor then + Some (Some item, index) + else findExprTupleItemWithCursor rest ~index:(index + 1) ~pos + +type findContextInExprRes = { + lookingToComplete: Completable.lookingToComplete; + expressionPath: Completable.patternPathItem list; + prefix: string; + alreadySeenIdents: string list; +} + +let hasBraces attributes = + attributes |> List.exists (fun (loc, _) -> loc.Location.txt = "ns.braces") + +let rec findContextInExpr expr ~pos ~expressionPath ~debug + ~firstCharBeforeCursorNoWhite = + match expr.Parsetree.pexp_desc with + (* In expressions, there's ambiguity between an empty record and an empty expression block. There's simply no way to express a record with 0 fields, like there is in patterns. + The heuristic below matches `{}` and interprets it as an empty record rather than an expression block with braces + unit, which is what the parser parses it as. *) + | Pexp_construct ({txt = Lident "()"}, None) + when hasBraces expr.Parsetree.pexp_attributes + && CursorPosition.classifyLoc expr.pexp_loc ~pos = HasCursor -> + Some + { + lookingToComplete = CRecordField; + expressionPath = expressionPath |> List.rev; + prefix = ""; + alreadySeenIdents = []; + } + (* Handles `Some({})`, with the same logic as above for handling the empty record ambiguity. *) + | Pexp_construct + ( {txt}, + Some + { + pexp_loc; + pexp_attributes; + pexp_desc = Pexp_construct ({txt = Lident "()"}, _); + } ) + when hasBraces pexp_attributes -> ( + match CursorPosition.classifyLoc pexp_loc ~pos with + | HasCursor -> + Some + { + lookingToComplete = CRecordField; + expressionPath = + [ + Completable.Variant + {constructorName = getSimpleFieldName txt; payloadNum = Some 0}; + ] + @ expressionPath + |> List.rev; + prefix = ""; + alreadySeenIdents = []; + } + | NoCursor | EmptyLoc -> None) + (* This mmeans parser recovery has been made, which typically means the expr was an empty assignment of some sort. *) + | Pexp_extension ({txt = "rescript.exprhole"}, _) -> + Some + { + lookingToComplete = CNoContext; + expressionPath = expressionPath |> List.rev; + prefix = ""; + alreadySeenIdents = []; + } + (* Variants etc *) + | Pexp_construct + ( {txt}, + Some {pexp_loc; pexp_desc = Pexp_construct ({txt = Lident "()"}, _)} ) + -> ( + (* A variant like SomeVariant(). Interpret as completing the payload of the variant *) + match CursorPosition.classifyLoc pexp_loc ~pos with + | HasCursor -> + Some + { + lookingToComplete = CNoContext; + expressionPath = + [ + Completable.Variant + {constructorName = getSimpleFieldName txt; payloadNum = Some 0}; + ] + @ expressionPath + |> List.rev; + prefix = ""; + alreadySeenIdents = []; + } + | NoCursor | EmptyLoc -> None) + | Pexp_variant + ( label, + Some {pexp_loc; pexp_desc = Pexp_construct ({txt = Lident "()"}, _)} ) + -> ( + (* A polyvariant like #SomeVariant(). Interpret as completing the payload of the variant *) + match CursorPosition.classifyLoc pexp_loc ~pos with + | HasCursor -> + Some + { + lookingToComplete = CNoContext; + expressionPath = + [Completable.Polyvariant {name = label; payloadNum = Some 0}] + @ expressionPath + |> List.rev; + prefix = ""; + alreadySeenIdents = []; + } + | NoCursor | EmptyLoc -> None) + | Pexp_construct ({txt}, Some payload) + when CursorPosition.classifyLoc payload.pexp_loc ~pos = HasCursor -> + (* When there's a variant with a payload, and the cursor is in the pattern. Some(S) for example. *) + let payloadNum = + match payload.pexp_desc with + | Pexp_tuple items -> + (* Find the tuple item that has the cursor, so we can add that as payload num for the variant.*) + findExprTupleItemWithCursor items ~index:0 ~pos + | _ -> Some (None, 0) + in + let exprToContinueFrom = + match payloadNum with + | Some (Some pat, _) -> pat + | _ -> payload + in + findContextInExpr exprToContinueFrom ~pos ~debug + ~firstCharBeforeCursorNoWhite + ~expressionPath: + ([ + Completable.Variant + { + constructorName = getSimpleFieldName txt; + payloadNum = + (match payloadNum with + | Some (_, payloadNum) -> Some payloadNum + | _ -> None); + }; + ] + @ expressionPath) + | Pexp_variant (constructorName, Some exp) + when CursorPosition.classifyLoc exp.pexp_loc ~pos = HasCursor -> ( + (* When there's a polyvariant with a payload, and the cursor is in the pattern. Some(S) for example. *) + match exp.pexp_desc with + | Pexp_tuple _ -> + (* Continue down here too, but let us discover the tuple in the next step. *) + findContextInExpr exp ~firstCharBeforeCursorNoWhite ~pos ~expressionPath + ~debug + | _ -> + findContextInExpr exp ~firstCharBeforeCursorNoWhite ~pos ~debug + ~expressionPath: + ([Completable.Variant {constructorName; payloadNum = Some 0}] + @ expressionPath)) + | Pexp_construct ({txt}, None) -> ( + (* Payload-less variant *) + match CursorPosition.classifyLoc expr.pexp_loc ~pos with + | HasCursor -> + Some + { + lookingToComplete = CVariant; + expressionPath = expressionPath |> List.rev; + prefix = getSimpleFieldName txt; + alreadySeenIdents = []; + } + | NoCursor -> None + | EmptyLoc -> None) + | Pexp_variant (label, None) -> ( + (* Payload-less polyvariant *) + match CursorPosition.classifyLoc expr.pexp_loc ~pos with + | HasCursor -> + Some + { + lookingToComplete = CPolyvariant; + expressionPath; + prefix = label; + alreadySeenIdents = []; + } + | NoCursor -> None + | EmptyLoc -> None) + | Pexp_record (fields, _) -> ( + let seenFields = + fields |> List.map (fun ({Location.txt}, _) -> getSimpleFieldName txt) + in + let fieldWithCursorExists = + fields + |> List.exists (fun (_, fieldPat) -> + CursorPosition.classifyLoc fieldPat.Parsetree.pexp_loc ~pos + = HasCursor) + in + let completableFromField = + fields + |> List.find_map (fun (loc, fieldExpr) -> + match + CursorPosition.classifyLoc fieldExpr.Parsetree.pexp_loc ~pos + with + | HasCursor -> ( + match fieldExpr.pexp_desc with + | Pexp_ident loc -> + Some + { + lookingToComplete = CRecordField; + expressionPath = expressionPath |> List.rev; + prefix = getSimpleFieldName loc.txt; + alreadySeenIdents = seenFields; + } + | _ -> + (* We can continue down into anything else *) + findContextInExpr fieldExpr ~pos ~firstCharBeforeCursorNoWhite + ~debug + ~expressionPath: + ([ + Completable.RField + {fieldName = getSimpleFieldName loc.Location.txt}; + ] + @ expressionPath)) + | NoCursor -> None + | EmptyLoc -> + if + (* We only care about empty locations if there's no field with the cursor *) + fieldWithCursorExists + then None + else + findContextInExpr fieldExpr ~pos ~debug + ~firstCharBeforeCursorNoWhite + ~expressionPath: + ([ + Completable.RField + {fieldName = getSimpleFieldName loc.txt}; + ] + @ expressionPath)) + in + match + (completableFromField, fieldWithCursorExists, firstCharBeforeCursorNoWhite) + with + | None, false, Some ',' -> + (* If there's no field with the cursor, and we found no completable, and the first char before the + cursor is ',' we can assume that this is a pattern like `{someField, }`. + The parser discards any unecessary commas, so we can't leverage the parser to figure out that + we're looking to complete for a new field. *) + Some + { + lookingToComplete = CRecordField; + expressionPath = expressionPath |> List.rev; + prefix = ""; + alreadySeenIdents = seenFields; + } + | completableFromField, _, _ -> completableFromField) + | Pexp_tuple items -> ( + match findExprTupleItemWithCursor items ~pos ~index:0 with + | Some (Some tupleExprWithCursor, itemNumber) -> + findContextInExpr tupleExprWithCursor ~pos ~debug + ~firstCharBeforeCursorNoWhite + ~expressionPath:([Completable.PTuple {itemNumber}] @ expressionPath) + | None -> + (* TODO: No tuple item had the cursor, but we might still be able to complete + for the next tuple item. We just need to figure out where in the pattern + we are. E.g. `(_, , A)` is parsed the same as `(_, A, )` or `(_, A, ,)`. + Figuring out exactly which tuple item we're in is problematic because of that. *) + None + | _ -> None) + | _v -> None + +type findContextInPatternRes = { + lookingToComplete: Completable.lookingToComplete; + patternPath: Completable.patternPathItem list; + prefix: string; + alreadySeenIdents: string list; +} + +let rec findContextInPattern pattern ~pos ~patternPath ~debug + ~seenIdentsFromParent ~firstCharBeforeCursorNoWhite = + match pattern.Parsetree.ppat_desc with + | Ppat_any -> + (* E.g. something: _ *) + (* We hijack the any pattern some here, and interpret that as an "empty" completion. *) + Some + { + lookingToComplete = CNoContext; + patternPath = patternPath |> List.rev; + prefix = ""; + alreadySeenIdents = seenIdentsFromParent; + } + | Ppat_extension ({txt = "rescript.patternhole"}, _) -> + (* This is printed when the parser has made recovery. + E.g. `| Something => () | ` *) + Some + { + (* We're completing vars as variants for now, since bool (which is a variant) is the only thing + I can think of that needs completion here. *) + lookingToComplete = CNoContext; + patternPath = patternPath |> List.rev; + prefix = ""; + alreadySeenIdents = seenIdentsFromParent; + } + | Ppat_var loc when CursorPosition.classifyLoc loc.loc ~pos = HasCursor -> + (* E.g. something: someVar *) + Some + { + (* We're completing vars as variants for now, since bool (which is a variant) is the only thing + I can think of that needs completion here. *) + lookingToComplete = CVariant; + patternPath = patternPath |> List.rev; + prefix = loc.txt; + alreadySeenIdents = []; + } + (* Variants etc *) + | Ppat_construct + ( {txt}, + Some {ppat_loc; ppat_desc = Ppat_construct ({txt = Lident "()"}, _)} ) + -> ( + (* A variant like SomeVariant(). Interpret as completing the payload of the variant *) + match CursorPosition.classifyLoc ppat_loc ~pos with + | HasCursor -> + Some + { + lookingToComplete = CNoContext; + patternPath = + [ + Completable.Variant + {constructorName = getSimpleFieldName txt; payloadNum = Some 0}; + ] + @ patternPath + |> List.rev; + prefix = ""; + alreadySeenIdents = []; + } + | NoCursor -> None + | EmptyLoc -> None) + | Ppat_variant + ( label, + Some {ppat_loc; ppat_desc = Ppat_construct ({txt = Lident "()"}, _)} ) + -> ( + (* A polyvariant like #SomeVariant(). Interpret as completing the payload of the variant *) + match CursorPosition.classifyLoc ppat_loc ~pos with + | HasCursor -> + Some + { + lookingToComplete = CNoContext; + patternPath = + [Completable.Polyvariant {name = label; payloadNum = Some 0}] + @ patternPath + |> List.rev; + prefix = ""; + alreadySeenIdents = []; + } + | NoCursor -> None + | EmptyLoc -> None) + | Ppat_construct ({txt}, Some payload) + when CursorPosition.classifyLoc payload.ppat_loc ~pos = HasCursor -> + (* When there's a variant with a payload, and the cursor is in the pattern. Some(S) for example. *) + let payloadNum = + match payload.ppat_desc with + | Ppat_tuple items -> + (* Find the tuple item that has the cursor, so we can add that as payload num for the variant.*) + findPatternTupleItemWithCursor items ~index:0 ~pos + | _ -> Some (None, 0) + in + let patternToContinueFrom = + match payloadNum with + | Some (Some pat, _) -> pat + | _ -> payload + in + findContextInPattern patternToContinueFrom ~pos ~debug + ~firstCharBeforeCursorNoWhite ~seenIdentsFromParent:[] + ~patternPath: + ([ + Completable.Variant + { + constructorName = getSimpleFieldName txt; + payloadNum = + (match payloadNum with + | Some (_, payloadNum) -> Some payloadNum + | _ -> None); + }; + ] + @ patternPath) + | Ppat_variant (constructorName, Some pat) + when CursorPosition.classifyLoc pat.ppat_loc ~pos = HasCursor -> ( + (* When there's a polyvariant with a payload, and the cursor is in the pattern. Some(S) for example. *) + match pat.ppat_desc with + | Ppat_tuple _ -> + (* Continue down here too, but let us discover the tuple in the next step. *) + findContextInPattern pat ~firstCharBeforeCursorNoWhite ~pos ~patternPath + ~debug ~seenIdentsFromParent:[] + | _ -> + findContextInPattern pat ~firstCharBeforeCursorNoWhite ~pos ~debug + ~seenIdentsFromParent:[] + ~patternPath: + ([Completable.Variant {constructorName; payloadNum = Some 0}] + @ patternPath)) + | Ppat_construct ({txt}, None) -> ( + (* Payload-less variant *) + match CursorPosition.classifyLoc pattern.ppat_loc ~pos with + | HasCursor -> + Some + { + lookingToComplete = CVariant; + patternPath = patternPath |> List.rev; + prefix = getSimpleFieldName txt; + alreadySeenIdents = seenIdentsFromParent; + } + | NoCursor -> None + | EmptyLoc -> None) + | Ppat_variant (label, None) -> ( + (* Payload-less polyvariant *) + match CursorPosition.classifyLoc pattern.ppat_loc ~pos with + | HasCursor -> + Some + { + lookingToComplete = CPolyvariant; + patternPath = patternPath |> List.rev; + prefix = label; + alreadySeenIdents = seenIdentsFromParent; + } + | NoCursor -> None + | EmptyLoc -> None) + (* Records *) + | Ppat_record ([], _) -> + (* No fields mean we're in an empty record body. We can complete for that. *) + Some + { + lookingToComplete = CRecordField; + patternPath = patternPath |> List.rev; + prefix = ""; + alreadySeenIdents = []; + } + | Ppat_record (fields, _) -> ( + let seenFields = + fields |> List.map (fun ({Location.txt}, _) -> getSimpleFieldName txt) + in + let fieldWithCursorExists = + fields + |> List.exists (fun (_, fieldPat) -> + CursorPosition.classifyLoc fieldPat.Parsetree.ppat_loc ~pos + = HasCursor) + in + let completableFromField = + fields + |> List.find_map (fun (loc, fieldPat) -> + match + CursorPosition.classifyLoc fieldPat.Parsetree.ppat_loc ~pos + with + | HasCursor -> ( + (* handle `{something}`, which is parsed as `{something: something}` because of punning *) + match (loc, fieldPat.Parsetree.ppat_desc) with + | ( {Location.txt = Longident.Lident fieldName}, + Ppat_var {txt = varName} ) + when fieldName = varName -> + Some + { + lookingToComplete = CRecordField; + patternPath = patternPath |> List.rev; + prefix = varName; + alreadySeenIdents = seenFields; + } + | _ -> + (* We can continue down into anything else *) + findContextInPattern fieldPat ~pos + ~firstCharBeforeCursorNoWhite ~debug ~seenIdentsFromParent:[] + ~patternPath: + ([ + Completable.RField + {fieldName = getSimpleFieldName loc.txt}; + ] + @ patternPath)) + | NoCursor -> None + | EmptyLoc -> + if + (* We only care about empty locations if there's no field with the cursor *) + fieldWithCursorExists + then None + else + findContextInPattern fieldPat ~pos ~debug + ~firstCharBeforeCursorNoWhite ~seenIdentsFromParent:[] + ~patternPath: + ([ + Completable.RField + {fieldName = getSimpleFieldName loc.txt}; + ] + @ patternPath)) + in + match + (completableFromField, fieldWithCursorExists, firstCharBeforeCursorNoWhite) + with + | None, false, Some ',' -> + (* If there's no field with the cursor, and we found no completable, and the first char before the + cursor is ',' we can assume that this is a pattern like `{someField, }`. + The parser discards any unecessary commas, so we can't leverage the parser to figure out that + we're looking to complete for a new field. *) + Some + { + lookingToComplete = CRecordField; + patternPath = patternPath |> List.rev; + prefix = ""; + alreadySeenIdents = seenFields; + } + | completableFromField, _, _ -> completableFromField) + | Ppat_tuple items -> ( + match findPatternTupleItemWithCursor items ~pos ~index:0 with + | Some (Some tuplePatternWithCursor, itemNumber) -> + findContextInPattern tuplePatternWithCursor ~pos ~debug + ~seenIdentsFromParent:[] ~firstCharBeforeCursorNoWhite + ~patternPath:([Completable.PTuple {itemNumber}] @ patternPath) + | None -> + (* TODO: No tuple item had the cursor, but we might still be able to complete + for the next tuple item. We just need to figure out where in the pattern + we are. E.g. `(_, , A)` is parsed the same as `(_, A, )` or `(_, A, ,)`. + Figuring out exactly which tuple item we're in is problematic because of that. *) + None + | _ -> None) + | Ppat_or (pat1, pat2) -> ( + (* There's a few things that can happen as we're looking for or patterns. + a. First off, we can find an or pattern with the cursor, in which case we should try to descend into it. + E.g. `One | Two | Three({someField: s})` + b. Secondly, if there's no pattern with the cursor, there might be a or pattern with parser recovery in it. + That means the user has written an empty or pattern, in which case we should complete for the current type. + E.g. `One | Two | ` *) + let branches = + pat1 + |> findAllOrBranches ~branches:[pat2] + |> List.filter (fun pat -> + match pat.Parsetree.ppat_desc with + | Ppat_or _ -> false + | _ -> true) + in + let branchAtCursor = + branches + |> List.find_opt (fun pat -> + pat.Parsetree.ppat_loc + |> CursorPosition.classifyLoc ~pos + = HasCursor) + in + let identsFromBranches = + branches + |> List.map (fun branch -> branch |> identListFromPat) + |> List.flatten + in + match branchAtCursor with + | None -> ( + let branchWithEmptyLoc = + branches + |> List.find_opt (fun pat -> + pat.Parsetree.ppat_loc + |> CursorPosition.classifyLoc ~pos + = EmptyLoc) + in + (* If we found no branch with the cursor, look for one with an empty loc + that's a patternhole (error recovery done by the parser). *) + match branchWithEmptyLoc with + | Some {ppat_desc = Ppat_extension ({txt = "rescript.patternhole"}, _)} -> + Some + { + lookingToComplete = CNoContext; + patternPath = patternPath |> List.rev; + prefix = ""; + alreadySeenIdents = identsFromBranches; + } + | _ -> None) + | Some pattern -> + pattern + |> findContextInPattern ~pos ~patternPath ~debug + ~firstCharBeforeCursorNoWhite + ~seenIdentsFromParent:identsFromBranches) + | _v -> + (* if debug then + Printf.printf "warning: unhandled pattern %s\n" (Utils.identifyPpat v);*) + None type prop = { name: string; @@ -64,10 +699,12 @@ let findJsxPropsCompletable ~jsxProps ~endPos ~posBeforeCursor ~posAfterCompName None else if prop.exp.pexp_loc |> Loc.hasPos ~pos:posBeforeCursor then (* Cursor on expr assigned *) + (* TODO: Add expr completion *) None else if prop.exp.pexp_loc |> Loc.end_ = (Location.none |> Loc.end_) then (* Expr assigned presumably is "rescript.exprhole" after parser recovery. - To be on the safe side, don't do label completion. *) + Complete for the value. *) + (* TODO: Add expr completion *) None else loop rest | [] -> @@ -126,18 +763,9 @@ let extractJsxProps ~(compName : Longident.t Location.loc) ~args = in args |> processProps ~acc:[] -type labelled = { - name: string; - opt: bool; - posStart: int * int; - posEnd: int * int; -} - -type label = labelled option -type arg = {label: label; exp: Parsetree.expression} - let findNamedArgCompletable ~(args : arg list) ~endPos ~posBeforeCursor - ~(contextPath : Completable.contextPath) ~posAfterFunExpr = + ~(contextPath : Completable.contextPath) ~posAfterFunExpr + ~firstCharBeforeCursorNoWhite ~debug = let allNames = List.fold_right (fun arg allLabels -> @@ -149,11 +777,73 @@ let findNamedArgCompletable ~(args : arg list) ~endPos ~posBeforeCursor let rec loop args = match args with | {label = Some labelled; exp} :: rest -> + (* Figure out if we're completing the labelled argument name, or assigning to the labelled argument *) if labelled.posStart <= posBeforeCursor && posBeforeCursor < labelled.posEnd then Some (Completable.CnamedArg (contextPath, labelled.name, allNames)) - else if exp.pexp_loc |> Loc.hasPos ~pos:posBeforeCursor then None + else if exp.pexp_loc |> Loc.hasPos ~pos:posBeforeCursor then + (* Ok, were completing in the expression. Inspect what the expression is. *) + (* TODO: Apply the same thing to JSX *) + match exp.pexp_desc with + | Pexp_fun _ -> ( + (* If this is a function expression, there might be function argument patterns we can + complete (like the record destructuring in `someFunc(~someArg=({}) => {...})`) *) + let idx = ref 0 in + let rec findTargetArg exp = + match exp.Parsetree.pexp_desc with + | Pexp_fun (label, _, fnArgPattern, nextFunExpr) -> ( + let currentUnlabelledArgIdx = !idx in + (match label with + | Nolabel -> idx := !idx + 1 + | _ -> ()); + (* Check if the cursor is inside this args pattern. *) + match + ( fnArgPattern.ppat_loc + |> CursorPosition.classifyLoc ~pos:posBeforeCursor, + label ) + with + | (EmptyLoc | HasCursor), Nolabel -> + Some + (Completable.Unlabelled currentUnlabelledArgIdx, fnArgPattern) + | (EmptyLoc | HasCursor), (Labelled label | Optional label) -> + Some (Completable.Labelled label, fnArgPattern) + | NoCursor, _ -> findTargetArg nextFunExpr) + | _ -> None + in + match findTargetArg exp with + | None -> None + | Some (_arg, _argPattern) -> (* TODO: Add expr completion *) None) + | _ -> ( + match + findContextInExpr exp ~debug ~pos:posBeforeCursor ~expressionPath:[] + ~firstCharBeforeCursorNoWhite + with + | None -> None + | Some res -> + Some + (CtypedExpression + { + prefix = res.prefix; + lookingToComplete = res.lookingToComplete; + expressionPath = res.expressionPath; + alreadySeenIdents = res.alreadySeenIdents; + howToRetrieveSourceType = + NamedArg {label = labelled.name; contextPath}; + })) + else if exp.pexp_loc |> Loc.end_ = (Location.none |> Loc.end_) then + (* Expr assigned presumably is "rescript.exprhole" after parser recovery. + Assume this is an empty expression. *) + Some + (CtypedExpression + { + prefix = ""; + lookingToComplete = CNoContext; + expressionPath = []; + alreadySeenIdents = []; + howToRetrieveSourceType = + NamedArg {label = labelled.name; contextPath}; + }) else loop rest | {label = None; exp} :: rest -> if exp.pexp_loc |> Loc.hasPos ~pos:posBeforeCursor then None @@ -165,68 +855,24 @@ let findNamedArgCompletable ~(args : arg list) ~endPos ~posBeforeCursor in loop args -let extractExpApplyArgs ~args = - let rec processArgs ~acc args = - match args with - | (((Asttypes.Labelled s | Optional s) as label), (e : Parsetree.expression)) - :: rest -> ( - let namedArgLoc = - e.pexp_attributes - |> List.find_opt (fun ({Asttypes.txt}, _) -> txt = "ns.namedArgLoc") - in - match namedArgLoc with - | Some ({loc}, _) -> - let labelled = - { - name = s; - opt = - (match label with - | Optional _ -> true - | _ -> false); - posStart = Loc.start loc; - posEnd = Loc.end_ loc; - } - in - processArgs ~acc:({label = Some labelled; exp = e} :: acc) rest - | None -> processArgs ~acc rest) - | (Asttypes.Nolabel, (e : Parsetree.expression)) :: rest -> - if e.pexp_loc.loc_ghost then processArgs ~acc rest - else processArgs ~acc:({label = None; exp = e} :: acc) rest - | [] -> List.rev acc - in - args |> processArgs ~acc:[] - -let rec exprToContextPath (e : Parsetree.expression) = - match e.pexp_desc with - | Pexp_constant (Pconst_string _) -> Some Completable.CPString - | Pexp_array _ -> Some CPArray - | Pexp_ident {txt} -> Some (CPId (Utils.flattenLongIdent txt, Value)) - | Pexp_field (e1, {txt = Lident name}) -> ( - match exprToContextPath e1 with - | Some contextPath -> Some (CPField (contextPath, name)) - | _ -> None) - | Pexp_field (_, {txt = Ldot (lid, name)}) -> - (* Case x.M.field ignore the x part *) - Some (CPField (CPId (Utils.flattenLongIdent lid, Module), name)) - | Pexp_send (e1, {txt}) -> ( - match exprToContextPath e1 with - | None -> None - | Some contexPath -> Some (CPObj (contexPath, txt))) - | Pexp_apply (e1, args) -> ( - match exprToContextPath e1 with - | None -> None - | Some contexPath -> Some (CPApply (contexPath, args |> List.map fst))) - | _ -> None - let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor ~text = let offsetNoWhite = skipWhite text (offset - 1) in let posNoWhite = let line, col = posCursor in (line, max 0 col - offset + offsetNoWhite) in + (* Identifies the first character before the cursor that's not white space. + Should be used very sparingly, but can be used to drive completion triggering + in scenarios where the parser eats things we'd need to complete. + Example: let {whatever, }, char is ','. *) + let firstCharBeforeCursorNoWhite = + if offsetNoWhite < String.length text && offsetNoWhite >= 0 then + Some text.[offsetNoWhite] + else None + in let posBeforeCursor = (fst posCursor, max 0 (snd posCursor - 1)) in let charBeforeCursor, blankAfterCursor = - match positionToOffset text posCursor with + match Pos.positionToOffset text posCursor with | Some offset when offset > 0 -> ( let charBeforeCursor = text.[offset - 1] in let charAtCursor = @@ -264,6 +910,8 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor ~text = | Some x -> result := Some (x, !scope) in let setResult x = setResultOpt (Some x) in + (* `setResultForced` is mostly an experiment as I figure things out *) + let setResultForced x = result := Some (x, !scope) in let scopeValueDescription (vd : Parsetree.value_description) = scope := !scope |> Scope.addValue ~name:vd.pval_name.txt ~loc:vd.pval_name.loc @@ -346,11 +994,119 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor ~text = | Pstr_open {popen_lid} -> scope := !scope |> Scope.addOpen ~lid:popen_lid.txt | Pstr_primitive vd -> scopeValueDescription vd - | Pstr_value (recFlag, bindings) -> + | Pstr_value (recFlag, bindings) -> ( if recFlag = Recursive then bindings |> List.iter scopeValueBinding; bindings |> List.iter (fun vb -> iterator.value_binding iterator vb); if recFlag = Nonrecursive then bindings |> List.iter scopeValueBinding; - processed := true + processed := true; + + if + item.pstr_loc + |> CursorPosition.classifyLoc ~pos:posBeforeCursor + = HasCursor + then + match bindings with + (* TODO: This is currently broken, as we need to support using a type_decl, which is what a type annotation gives us, + to look up types (currently only support type_expr). *) + (* E.g let expr: someType = ... *) + | [ + { + pvb_pat = + { + ppat_desc = + ( Ppat_var loc + (* Handles the `let someVar: someType = ...` case until we've refactored so we can do proper completion via + the type annotation. *) + | Ppat_constraint ({ppat_desc = Ppat_var loc}, _) ); + }; + pvb_expr = expr; + }; + ] + when expr.pexp_loc + |> CursorPosition.classifyLoc ~pos:posBeforeCursor + = HasCursor -> ( + (* E.g `let something = {someVal: 123}` + This handles the case when the assignment of `something` might not be complete (missing record fields for example), + but where even if compilation has failed the compiler might know enough about the value of `something` to use it + for expression based completion. *) + match + findContextInExpr expr ~firstCharBeforeCursorNoWhite + ~pos:posBeforeCursor ~expressionPath:[] ~debug + with + | None -> () + | Some res -> + setResultForced + (Completable.CtypedExpression + { + howToRetrieveSourceType = CtxPath (CPId ([loc.txt], Value)); + expressionPath = res.expressionPath; + lookingToComplete = res.lookingToComplete; + prefix = res.prefix; + alreadySeenIdents = res.alreadySeenIdents; + })) + | [{pvb_pat; pvb_expr = expr}] + when pvb_pat.ppat_loc + |> CursorPosition.classifyLoc ~pos:posBeforeCursor + = HasCursor -> ( + (* Check for: let {destructuringSomething} = someIdentifier *) + (* TODO: Handle let {SomeModule.recordField} = ...*) + + (* The contextPath is what we'll use to look up the root record type for this completion. + Depending on if the destructure is nested or not, we may or may not use that directly.*) + match exprToContextPath expr with + | None -> () + | Some contextPath -> ( + match + findContextInPattern pvb_pat ~firstCharBeforeCursorNoWhite + ~pos:posBeforeCursor ~patternPath:[] ~seenIdentsFromParent:[] + ~debug + with + | None -> () + | Some res -> + setResultForced + (Completable.CtypedPattern + { + howToRetrieveSourceType = CtxPath contextPath; + patternPath = res.patternPath; + patternType = Destructure; + lookingToComplete = res.lookingToComplete; + prefix = res.prefix; + alreadySeenIdents = res.alreadySeenIdents; + }))) + | [ + { + pvb_pat = + { + ppat_loc; + ppat_desc = + Ppat_constraint + (_, {ptyp_desc = Ptyp_constr (typIdentifier, [])}); + }; + pvb_expr = expr; + }; + ] -> ( + match expr with + (* E.g let expr: someType = + Produces a "broken" source *) + | { + pexp_desc = Pexp_extension ({Location.txt = "rescript.exprhole"}, _); + } + when ppat_loc + |> CursorPosition.classifyLoc ~pos:posBeforeCursor + = NoCursor -> + setResultForced + (Completable.CtypedExpression + { + howToRetrieveSourceType = + CtxPath + (CPId (Utils.flattenLongIdent typIdentifier.txt, Type)); + expressionPath = []; + alreadySeenIdents = []; + lookingToComplete = CNoContext; + prefix = ""; + }) + | _ -> ()) + | _ -> ()) | Pstr_type (recFlag, decls) -> if recFlag = Recursive then decls |> List.iter scopeTypeDeclaration; decls |> List.iter (fun td -> iterator.type_declaration iterator td); @@ -405,7 +1161,9 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor ~text = else if id.loc.loc_ghost then () else if id.loc |> Loc.hasPos ~pos:posBeforeCursor then let posStart, posEnd = Loc.range id.loc in - match (positionToOffset text posStart, positionToOffset text posEnd) with + match + (Pos.positionToOffset text posStart, Pos.positionToOffset text posEnd) + with | Some offsetStart, Some offsetEnd -> (* Can't trust the parser's location E.g. @foo. let x... gives as label @foo.let *) @@ -591,6 +1349,7 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor ~text = match exprToContextPath funExpr with | Some contextPath -> findNamedArgCompletable ~contextPath ~args + ~firstCharBeforeCursorNoWhite ~debug ~endPos:(Loc.end_ expr.pexp_loc) ~posBeforeCursor ~posAfterFunExpr:(Loc.end_ funExpr.pexp_loc) | None -> None @@ -656,6 +1415,58 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor ~text = iterator.expr iterator e; scope := oldScope; processed := true + | Pexp_match (expr, cases) -> ( + (* Completes switch case destructuring + Example: switch someIdentifier { | {completeRecordFieldsHere} => ...}*) + let rec findCaseWithCursor cases ~typ ~identsFromCases = + match cases with + | case :: nextCases -> + if + case.Parsetree.pc_lhs.ppat_loc + |> CursorPosition.classifyLoc ~pos:posBeforeCursor + = typ + then + case.pc_lhs + |> findContextInPattern ~firstCharBeforeCursorNoWhite + ~pos:posBeforeCursor ~patternPath:[] ~debug + ~seenIdentsFromParent:identsFromCases + else findCaseWithCursor nextCases ~typ ~identsFromCases + | [] -> None + in + match exprToContextPath expr with + | None -> () + | Some contextPath -> ( + (* Collect all of the seen idents from the cases themselves. *) + let identsFromCases = + cases + |> List.map (fun case -> + case.Parsetree.pc_lhs |> identListFromPat) + |> List.flatten + in + (* First, look for a case with the cursor. *) + let res = + match + findCaseWithCursor cases ~typ:HasCursor ~identsFromCases + with + | None -> + (* If there's no case with the cursor, look for a case with a broken loc. That means parser recovery has happened somewhere. *) + findCaseWithCursor cases ~typ:EmptyLoc ~identsFromCases + | v -> v + in + match res with + | None -> () + | Some res -> + setResultOpt + (Some + (CtypedPattern + { + howToRetrieveSourceType = CtxPath contextPath; + patternPath = res.patternPath; + patternType = Switch; + lookingToComplete = res.lookingToComplete; + prefix = res.prefix; + alreadySeenIdents = res.alreadySeenIdents; + })))) | _ -> ()); if not !processed then Ast_iterator.default_iterator.expr iterator expr in @@ -788,7 +1599,7 @@ let completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor ~text = else None let completionWithParser ~debug ~path ~posCursor ~currentFile ~text = - match positionToOffset text posCursor with + match Pos.positionToOffset text posCursor with | Some offset -> completionWithParser1 ~currentFile ~debug ~offset ~path ~posCursor ~text | None -> None diff --git a/analysis/src/DumpAst.ml b/analysis/src/DumpAst.ml new file mode 100644 index 000000000..1ed85cd82 --- /dev/null +++ b/analysis/src/DumpAst.ml @@ -0,0 +1,317 @@ +open SharedTypes +(* This is intended to be a debug tool. It's by no means complete. Rather, you're encouraged to extend this with printing whatever types you need printing. *) + +let emptyLocDenom = "" +let hasCursorDenom = "<*>" +let noCursorDenom = "" + +let printLocDenominator loc ~pos = + match loc |> CursorPosition.classifyLoc ~pos with + | EmptyLoc -> emptyLocDenom + | HasCursor -> hasCursorDenom + | NoCursor -> noCursorDenom + +let printLocDenominatorLoc loc ~pos = + match loc |> CursorPosition.classifyLocationLoc ~pos with + | CursorPosition.EmptyLoc -> emptyLocDenom + | HasCursor -> hasCursorDenom + | NoCursor -> noCursorDenom + +let printLocDenominatorPos pos ~posStart ~posEnd = + match CursorPosition.classifyPositions pos ~posStart ~posEnd with + | CursorPosition.EmptyLoc -> emptyLocDenom + | HasCursor -> hasCursorDenom + | NoCursor -> noCursorDenom + +let addIndentation indentation = + let rec indent str indentation = + if indentation < 1 then str else indent (str ^ " ") (indentation - 1) + in + indent "" indentation + +let printAttributes attributes = + match List.length attributes with + | 0 -> "" + | _ -> + "[" + ^ (attributes + |> List.map (fun ({Location.txt}, _payload) -> "@" ^ txt) + |> String.concat ",") + ^ "]" + +let printConstant const = + match const with + | Parsetree.Pconst_integer (s, _) -> "Pconst_integer(" ^ s ^ ")" + | Pconst_char c -> "Pconst_char(" ^ String.make 1 c ^ ")" + | Pconst_string (s, delim) -> + let delim = + match delim with + | None -> "" + | Some delim -> delim ^ " " + in + "Pconst_string(" ^ delim ^ s ^ delim ^ ")" + | Pconst_float (s, _) -> "Pconst_float(" ^ s ^ ")" + +let printCoreType typ ~pos = + printAttributes typ.Parsetree.ptyp_attributes + ^ (typ.ptyp_loc |> printLocDenominator ~pos) + ^ + match typ.ptyp_desc with + | Ptyp_any -> "Ptyp_any" + | Ptyp_var name -> "Ptyp_var(" ^ Completable.str name ^ ")" + | Ptyp_constr (loc, _types) -> + "Ptyp_constr(" + ^ (loc |> printLocDenominatorLoc ~pos) + ^ (Utils.flattenLongIdent loc.txt |> Completable.ident |> Completable.str) + ^ ")" + | Ptyp_variant _ -> "Ptyp_variant()" + | _ -> "" + +let rec printPattern pattern ~pos ~indentation = + printAttributes pattern.Parsetree.ppat_attributes + ^ (pattern.ppat_loc |> printLocDenominator ~pos) + ^ + match pattern.Parsetree.ppat_desc with + | Ppat_or (pat1, pat2) -> + "Ppat_or(\n" + ^ addIndentation (indentation + 1) + ^ printPattern pat1 ~pos ~indentation:(indentation + 2) + ^ ",\n" + ^ addIndentation (indentation + 1) + ^ printPattern pat2 ~pos ~indentation:(indentation + 2) + ^ "\n" ^ addIndentation indentation ^ ")" + | Ppat_extension (({txt} as loc), _) -> + "Ppat_extension(%" ^ (loc |> printLocDenominatorLoc ~pos) ^ txt ^ ")" + | Ppat_var ({txt} as loc) -> + "Ppat_var(" ^ (loc |> printLocDenominatorLoc ~pos) ^ txt ^ ")" + | Ppat_constant const -> "Ppat_constant(" ^ printConstant const ^ ")" + | Ppat_construct (({txt} as loc), maybePat) -> + "Ppat_construct(" + ^ (loc |> printLocDenominatorLoc ~pos) + ^ (Utils.flattenLongIdent txt |> Completable.ident |> Completable.str) + ^ (match maybePat with + | None -> "" + | Some pat -> "," ^ printPattern pat ~pos ~indentation) + ^ ")" + | Ppat_variant (label, maybePat) -> + "Ppat_variant(" ^ Completable.str label + ^ (match maybePat with + | None -> "" + | Some pat -> "," ^ printPattern pat ~pos ~indentation) + ^ ")" + | Ppat_record (fields, _) -> + "Ppat_record(\n" + ^ addIndentation (indentation + 1) + ^ "fields:\n" + ^ (fields + |> List.map (fun ((Location.{txt} as loc), pat) -> + addIndentation (indentation + 2) + ^ (loc |> printLocDenominatorLoc ~pos) + ^ (Utils.flattenLongIdent txt |> Completable.ident + |> Completable.str) + ^ ": " + ^ printPattern pat ~pos ~indentation:(indentation + 2)) + |> String.concat "\n") + ^ "\n" ^ addIndentation indentation ^ ")" + | Ppat_tuple patterns -> + "Ppat_tuple(\n" + ^ (patterns + |> List.map (fun pattern -> + addIndentation (indentation + 2) + ^ (pattern |> printPattern ~pos ~indentation:(indentation + 2))) + |> String.concat ",\n") + ^ "\n" ^ addIndentation indentation ^ ")" + | Ppat_any -> "Ppat_any" + | Ppat_constraint (pattern, typ) -> + "Ppat_constraint(\n" + ^ addIndentation (indentation + 1) + ^ printCoreType typ ~pos ^ ",\n" + ^ addIndentation (indentation + 1) + ^ (pattern |> printPattern ~pos ~indentation:(indentation + 1)) + ^ "\n" ^ addIndentation indentation ^ ")" + | v -> Printf.sprintf "" (Utils.identifyPpat v) + +and printCase case ~pos ~indentation ~caseNum = + addIndentation indentation + ^ Printf.sprintf "case %i:\n" caseNum + ^ addIndentation (indentation + 1) + ^ "pattern" + ^ (case.Parsetree.pc_lhs.ppat_loc |> printLocDenominator ~pos) + ^ ":\n" + ^ addIndentation (indentation + 2) + ^ printPattern case.Parsetree.pc_lhs ~pos ~indentation + ^ "\n" + ^ addIndentation (indentation + 1) + ^ "expr" + ^ (case.Parsetree.pc_rhs.pexp_loc |> printLocDenominator ~pos) + ^ ":\n" + ^ addIndentation (indentation + 2) + ^ printExprItem case.pc_rhs ~pos ~indentation:(indentation + 2) + +and printExprItem expr ~pos ~indentation = + printAttributes expr.Parsetree.pexp_attributes + ^ (expr.pexp_loc |> printLocDenominator ~pos) + ^ + match expr.Parsetree.pexp_desc with + | Pexp_match (matchExpr, cases) -> + "Pexp_match(" + ^ printExprItem matchExpr ~pos ~indentation:0 + ^ ")\n" + ^ (cases + |> List.mapi (fun caseNum case -> + printCase case ~pos ~caseNum:(caseNum + 1) + ~indentation:(indentation + 1)) + |> String.concat "\n") + | Pexp_ident {txt} -> + "Pexp_ident:" ^ (Utils.flattenLongIdent txt |> SharedTypes.Completable.ident) + | Pexp_apply (expr, args) -> + let printLabel labelled ~pos = + match labelled with + | None -> "" + | Some labelled -> + printLocDenominatorPos pos ~posStart:labelled.posStart + ~posEnd:labelled.posEnd + ^ "~" + ^ if labelled.opt then "?" else "" ^ labelled.name + in + let args = extractExpApplyArgs ~args in + "Pexp_apply(\n" + ^ addIndentation (indentation + 1) + ^ "expr:\n" + ^ addIndentation (indentation + 2) + ^ printExprItem expr ~pos ~indentation:(indentation + 2) + ^ "\n" + ^ addIndentation (indentation + 1) + ^ "args:\n" + ^ (args + |> List.map (fun arg -> + addIndentation (indentation + 2) + ^ printLabel arg.label ~pos ^ "=\n" + ^ addIndentation (indentation + 3) + ^ printExprItem arg.exp ~pos ~indentation:(indentation + 3)) + |> String.concat ",\n") + ^ "\n" ^ addIndentation indentation ^ ")" + | Pexp_constant constant -> "Pexp_constant(" ^ printConstant constant ^ ")" + | Pexp_construct (({txt} as loc), maybeExpr) -> + "Pexp_construct(" + ^ (loc |> printLocDenominatorLoc ~pos) + ^ (Utils.flattenLongIdent txt |> Completable.ident |> Completable.str) + ^ (match maybeExpr with + | None -> "" + | Some expr -> ", " ^ printExprItem expr ~pos ~indentation) + ^ ")" + | Pexp_variant (label, maybeExpr) -> + "Pexp_variant(" ^ Completable.str label + ^ (match maybeExpr with + | None -> "" + | Some expr -> "," ^ printExprItem expr ~pos ~indentation) + ^ ")" + | Pexp_fun (arg, _maybeDefaultArgExpr, pattern, nextExpr) -> + "Pexp_fun(\n" + ^ addIndentation (indentation + 1) + ^ "arg: " + ^ (match arg with + | Nolabel -> "Nolabel" + | Labelled name -> "Labelled(" ^ name ^ ")" + | Optional name -> "Optional(" ^ name ^ ")") + ^ ",\n" + ^ addIndentation (indentation + 2) + ^ "pattern: " + ^ printPattern pattern ~pos ~indentation:(indentation + 2) + ^ ",\n" + ^ addIndentation (indentation + 1) + ^ "next expr:\n" + ^ addIndentation (indentation + 2) + ^ printExprItem nextExpr ~pos ~indentation:(indentation + 2) + ^ "\n" ^ addIndentation indentation ^ ")" + | Pexp_extension (({txt} as loc), _) -> + "Pexp_extension(%" ^ (loc |> printLocDenominatorLoc ~pos) ^ txt ^ ")" + | Pexp_assert expr -> + "Pexp_assert(" ^ printExprItem expr ~pos ~indentation ^ ")" + | Pexp_field (exp, loc) -> + "Pexp_field(" + ^ (loc |> printLocDenominatorLoc ~pos) + ^ printExprItem exp ~pos ~indentation + ^ ")" + | Pexp_record (fields, _) -> + "Pexp_record(\n" + ^ addIndentation (indentation + 1) + ^ "fields:\n" + ^ (fields + |> List.map (fun ((Location.{txt} as loc), expr) -> + addIndentation (indentation + 2) + ^ (loc |> printLocDenominatorLoc ~pos) + ^ (Utils.flattenLongIdent txt |> Completable.ident + |> Completable.str) + ^ ": " + ^ printExprItem expr ~pos ~indentation:(indentation + 2)) + |> String.concat "\n") + ^ "\n" ^ addIndentation indentation ^ ")" + | Pexp_tuple exprs -> + "Pexp_tuple(\n" + ^ (exprs + |> List.map (fun expr -> + addIndentation (indentation + 2) + ^ (expr |> printExprItem ~pos ~indentation:(indentation + 2))) + |> String.concat ",\n") + ^ "\n" ^ addIndentation indentation ^ ")" + | v -> Printf.sprintf "" (Utils.identifyPexp v) + +let printValueBinding value ~pos ~indentation = + printAttributes value.Parsetree.pvb_attributes + ^ "value" ^ ":\n" + ^ addIndentation (indentation + 1) + ^ (value.pvb_pat |> printPattern ~pos ~indentation:(indentation + 1)) + ^ "\n" ^ addIndentation indentation ^ "expr:\n" + ^ addIndentation (indentation + 1) + ^ printExprItem value.pvb_expr ~pos ~indentation:(indentation + 1) + +let printStructItem structItem ~pos ~source = + match structItem.Parsetree.pstr_loc |> CursorPosition.classifyLoc ~pos with + | HasCursor -> ( + let startOffset = + match Pos.positionToOffset source (structItem.pstr_loc |> Loc.start) with + | None -> 0 + | Some offset -> offset + in + let endOffset = + (* Include the next line of the source since that will hold the ast comment pointing to the position. + Caveat: this only works for single line sources with a comment on the next line. Will need to be + adapted if that's not the only use case.*) + let line, _col = structItem.pstr_loc |> Loc.end_ in + match Pos.positionToOffset source (line + 2, 0) with + | None -> 0 + | Some offset -> offset + in + + ("\nSource:\n// " + ^ String.sub source startOffset (endOffset - startOffset) + ^ "\n") + ^ printLocDenominator structItem.pstr_loc ~pos + ^ + match structItem.pstr_desc with + | Pstr_eval (expr, _attributes) -> + "Pstr_eval(\n" ^ printExprItem expr ~pos ~indentation:1 ^ "\n)" + | Pstr_value (recFlag, values) -> + "Pstr_value(\n" + ^ (match recFlag with + | Recursive -> " rec,\n" + | Nonrecursive -> "") + ^ (values + |> List.map (fun value -> + addIndentation 1 ^ printValueBinding value ~pos ~indentation:1) + |> String.concat ",\n") + ^ "\n)" + | _ -> "") + | _ -> "" + +let dump ~currentFile ~pos = + let {Res_driver.parsetree = structure; source} = + Res_driver.parsingEngine.parseImplementation ~forPrinter:true + ~filename:currentFile + in + + print_endline + (structure + |> List.map (fun structItem -> printStructItem structItem ~pos ~source) + |> String.concat "") diff --git a/analysis/src/Pos.ml b/analysis/src/Pos.ml index cfcf6b7b6..818178d28 100644 --- a/analysis/src/Pos.ml +++ b/analysis/src/Pos.ml @@ -4,3 +4,23 @@ let ofLexing {Lexing.pos_lnum; pos_cnum; pos_bol} = (pos_lnum - 1, pos_cnum - pos_bol) let toString (loc, col) = Printf.sprintf "%d:%d" loc col + +let offsetOfLine text line = + let ln = String.length text in + let rec loop i lno = + if i >= ln then None + else + match text.[i] with + | '\n' -> if lno = line - 1 then Some (i + 1) else loop (i + 1) (lno + 1) + | _ -> loop (i + 1) lno + in + match line with + | 0 -> Some 0 + | _ -> loop 0 0 + +let positionToOffset text (line, character) = + match offsetOfLine text line with + | None -> None + | Some bol -> + if bol + character <= String.length text then Some (bol + character) + else None \ No newline at end of file diff --git a/analysis/src/ProcessCmt.ml b/analysis/src/ProcessCmt.ml index fd53e58df..cbced9e53 100644 --- a/analysis/src/ProcessCmt.ml +++ b/analysis/src/ProcessCmt.ml @@ -10,6 +10,12 @@ let addDeclared ~(name : string Location.loc) ~extent ~stamp ~(env : Env.t) addStamp env.stamps stamp declared; declared +let mapRecordField field = + let {Types.ld_id; ld_type} = field in + let astamp = Ident.binding_time ld_id in + let name = Ident.name ld_id in + {stamp = astamp; fname = Location.mknoloc name; typ = ld_type} + let rec forTypeSignatureItem ~env ~(exported : Exported.t) (item : Types.signature_item) = match item with @@ -75,16 +81,7 @@ let rec forTypeSignatureItem ~env ~(exported : Exported.t) Stamps.addConstructor env.stamps stamp declared; item)) | Type_record (fields, _) -> - Record - (fields - |> List.map (fun {Types.ld_id; ld_type} -> - let astamp = Ident.binding_time ld_id in - let name = Ident.name ld_id in - { - stamp = astamp; - fname = Location.mknoloc name; - typ = ld_type; - }))); + Record (fields |> List.map mapRecordField)); } ~name ~stamp:(Ident.binding_time ident) ~env type_attributes (Exported.add exported Exported.Type) diff --git a/analysis/src/Protocol.ml b/analysis/src/Protocol.ml index a1440aa85..82b13026f 100644 --- a/analysis/src/Protocol.ml +++ b/analysis/src/Protocol.ml @@ -16,11 +16,22 @@ type inlayHint = { paddingRight: bool; } +(* https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#insertTextFormat *) +type insertTextFormat = PlainText | Snippet + +let insertTextFormatToInt f = + match f with + | PlainText -> 1 + | Snippet -> 2 + type completionItem = { label: string; kind: int; tags: int list; detail: string; + sortText: string option; + insertTextFormat: insertTextFormat option; + insertText: string option; documentation: markupContent option; } @@ -71,7 +82,10 @@ let stringifyCompletionItem c = "kind": %i, "tags": %s, "detail": "%s", - "documentation": %s + "documentation": %s, + "sortText": %s, + "insertText": %s, + "insertTextFormat": %s }|} (Json.escape c.label) c.kind (c.tags |> List.map string_of_int |> array) @@ -79,6 +93,16 @@ let stringifyCompletionItem c = (match c.documentation with | None -> null | Some doc -> stringifyMarkupContent doc) + (match c.sortText with + | None -> null + | Some sortText -> Printf.sprintf "\"%s\"" (Json.escape sortText)) + (match c.insertText with + | None -> null + | Some insertText -> Printf.sprintf "\"%s\"" (Json.escape insertText)) + (match c.insertTextFormat with + | None -> null + | Some insertTextFormat -> + Printf.sprintf "%i" (insertTextFormatToInt insertTextFormat)) let stringifyHover s = Printf.sprintf {|{"contents": "%s"}|} (Json.escape s) diff --git a/analysis/src/SharedTypes.ml b/analysis/src/SharedTypes.ml index 314f7670b..0bd94b464 100644 --- a/analysis/src/SharedTypes.ml +++ b/analysis/src/SharedTypes.ml @@ -216,6 +216,12 @@ module QueryEnv = struct let fromFile file = {file; exported = file.structure.exported} end +type polyVariantConstructor = { + name: string; + payload: Types.type_expr option; + args: Types.type_expr list; +} + module Completion = struct type kind = | Module of Module.t @@ -224,19 +230,35 @@ module Completion = struct | Label of string | Type of Type.t | Constructor of Constructor.t * string + | PolyvariantConstructor of polyVariantConstructor | Field of field * string | FileModule of string + | OptionNone + | OptionSome + | Bool type t = { name: string; + sortText: string option; + insertText: string option; + insertTextFormat: Protocol.insertTextFormat option; env: QueryEnv.t; deprecated: string option; docstring: string list; kind: kind; } - let create ~name ~kind ~env = - {name; env; deprecated = None; docstring = []; kind} + let create ~name ?sortText ?insertText ?insertTextFormat ~kind ~env () = + { + name; + env; + deprecated = None; + docstring = []; + kind; + sortText; + insertText; + insertTextFormat; + } (* https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion *) (* https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#completionItemKind *) @@ -244,12 +266,12 @@ module Completion = struct match kind with | Module _ -> 9 | FileModule _ -> 9 - | Constructor (_, _) -> 4 + | PolyvariantConstructor _ | Constructor _ | OptionNone | OptionSome -> 4 | ObjLabel _ -> 4 | Label _ -> 4 | Field (_, _) -> 5 | Type _ -> 22 - | Value _ -> 12 + | Value _ | Bool -> 12 end module Env = struct @@ -424,6 +446,126 @@ module Completable = struct | CPField of contextPath * string | CPObj of contextPath * string | CPPipe of contextPath * string + (* A tuple containing a bunch of context paths (which are what we really want to complete). *) + | CTuple of contextPath list + + (* How to move through a nested type context, like from a root record to the type of one of its fields, and beyond. *) + type patternPathItem = + | RField of {fieldName: string} + | Variant of {constructorName: string; payloadNum: int option} + | Polyvariant of {name: string; payloadNum: int option} + | PTuple of {itemNumber: int} + + let str s = if s = "" then "\"\"" else s + let list l = "[" ^ (l |> List.map str |> String.concat ", ") ^ "]" + let ident l = l |> List.map str |> String.concat "." + + let pathItemToString item = + match item with + | RField {fieldName} -> "RecordField:" ^ fieldName + | Variant {constructorName; payloadNum} -> ( + "Variant:" ^ constructorName + ^ + match payloadNum with + | None -> "" + | Some payloadNum -> "(" ^ string_of_int payloadNum ^ ")") + | Polyvariant {name; payloadNum} -> ( + "Polyvariant:" ^ name + ^ + match payloadNum with + | None -> "" + | Some payloadNum -> "(" ^ string_of_int payloadNum ^ ")") + | PTuple {itemNumber} -> "Tuple:" ^ string_of_int itemNumber + + let patternContextPathToString pathItems = + pathItems |> List.map (fun item -> pathItemToString item) |> list + + let completionContextToString = function + | Value -> "Value" + | Type -> "Type" + | Module -> "Module" + | Field -> "Field" + + let rec contextPathToString = function + | CPString -> "string" + | CPApply (cp, labels) -> + contextPathToString cp ^ "(" + ^ (labels + |> List.map (function + | Asttypes.Nolabel -> "Nolabel" + | Labelled s -> "~" ^ s + | Optional s -> "?" ^ s) + |> String.concat ", ") + ^ ")" + | CPArray -> "array" + | CPId (sl, completionContext) -> + completionContextToString completionContext ^ list sl + | CPField (cp, s) -> contextPathToString cp ^ "." ^ str s + | CPObj (cp, s) -> contextPathToString cp ^ "[\"" ^ s ^ "\"]" + | CPPipe (cp, s) -> contextPathToString cp ^ "->" ^ s + | CTuple contextPaths -> + contextPaths |> List.map contextPathToString |> list + + type lookingToComplete = CRecordField | CVariant | CPolyvariant | CNoContext + + let lookingToCompleteToString l = + match l with + | CRecordField -> "CRecordField" + | CVariant -> "CVariant" + | CPolyvariant -> "CPolyvariant" + | CNoContext -> "CNoContext" + + type patternCompletionType = Destructure | Switch + + let patternCompletionTypeToString p = + match p with + | Destructure -> "Destructure" + | Switch -> "Switch" + + type functionArgument = Labelled of string | Unlabelled of int + + let functionArgumentToString arg = + match arg with + | Labelled name -> "~" ^ name + | Unlabelled argNum -> "unlabelled(" ^ string_of_int argNum ^ ")" + + (* Temporary while I figure things. Pretty sure this should be integrated into contextPath when this is all finished *) + type howToRetrieveSourceType = + | CtxPath of contextPath + (* A JSX prop assignment, eg. *) + | JsxProp of { + (* Path to the target component *) + componentPath: string list; + (* The target prop name *) + propName: string; + } + | NamedArg of { + (* The context path where the completion was found *) + contextPath: contextPath; + (* Name of the argument *) + label: string; + } + (* An argument to a function, like when completing in: someFunc(~someArg=({^com}) => {...})*) + | FunctionArgument of { + (* How to find the type of the function with the argument. *) + howToFindFunctionType: howToRetrieveSourceType; + (* Where the argument itself is located. *) + arg: functionArgument; + } + + let rec howToRetrieveSourceTypeToString howToRetrieveSourceType = + match howToRetrieveSourceType with + | CtxPath contextPath -> contextPath |> contextPathToString + | JsxProp {propName; componentPath} -> + "JsxProp(<" ^ (componentPath |> ident) ^ " " ^ propName ^ "=" ^ " />)" + | NamedArg {label; contextPath} -> + "NamedArg(" ^ label ^ ", " ^ (contextPath |> contextPathToString) ^ ")" + | FunctionArgument {howToFindFunctionType; arg} -> + "FunctionArgument(fnSource:" + ^ howToRetrieveSourceTypeToString howToFindFunctionType + ^ ", arg:" + ^ (arg |> functionArgumentToString) + ^ ")" type t = | Cdecorator of string (** e.g. @module *) @@ -433,35 +575,28 @@ module Completable = struct | Cpath of contextPath | Cjsx of string list * string * string list (** E.g. (["M", "Comp"], "id", ["id1", "id2"]) for List.map str |> String.concat ", ") ^ "]" in - let completionContextToString = function - | Value -> "Value" - | Type -> "Type" - | Module -> "Module" - | Field -> "Field" - in - let rec contextPathToString = function - | CPString -> "string" - | CPApply (cp, labels) -> - contextPathToString cp ^ "(" - ^ (labels - |> List.map (function - | Asttypes.Nolabel -> "Nolabel" - | Labelled s -> "~" ^ s - | Optional s -> "?" ^ s) - |> String.concat ", ") - ^ ")" - | CPArray -> "array" - | CPId (sl, completionContext) -> - completionContextToString completionContext ^ list sl - | CPField (cp, s) -> contextPathToString cp ^ "." ^ str s - | CPObj (cp, s) -> contextPathToString cp ^ "[\"" ^ s ^ "\"]" - | CPPipe (cp, s) -> contextPathToString cp ^ "->" ^ s - in - function + | CtypedPattern of { + howToRetrieveSourceType: howToRetrieveSourceType; + patternPath: patternPathItem list; + patternType: patternCompletionType; + lookingToComplete: lookingToComplete; + (* What the user has already started writing, if anything. *) + prefix: string; + (* Record fields already written by the user, etc. + This is contextual of course, but putting it here in the general type to simplify things. *) + alreadySeenIdents: string list; + } + | CtypedExpression of { + howToRetrieveSourceType: howToRetrieveSourceType; + expressionPath: patternPathItem list; + lookingToComplete: lookingToComplete; + (* What the user has already started writing, if anything. *) + prefix: string; + (* This is only really relevant for constructing records/objects in expressions. *) + alreadySeenIdents: string list; + } + + let toString = function | Cpath cp -> "Cpath " ^ contextPathToString cp | Cdecorator s -> "Cdecorator(" ^ str s ^ ")" | CnamedArg (cp, s, sl2) -> @@ -471,4 +606,103 @@ module Completable = struct | Cnone -> "Cnone" | Cjsx (sl1, s, sl2) -> "Cjsx(" ^ (sl1 |> list) ^ ", " ^ str s ^ ", " ^ (sl2 |> list) ^ ")" + | CtypedPattern + { + howToRetrieveSourceType; + prefix; + alreadySeenIdents; + patternPath; + lookingToComplete; + patternType; + } -> + ("CtypedPattern(sourceType:" + ^ (howToRetrieveSourceType |> howToRetrieveSourceTypeToString) + ^ ", lookingToComplete:" + ^ lookingToCompleteToString lookingToComplete + ^ ", patternType:" + ^ patternCompletionTypeToString patternType + ^ ", prefix:" ^ str prefix) + ^ ", pattern: " + ^ (patternPath |> patternContextPathToString) + ^ ", seenIdents: " ^ list alreadySeenIdents ^ ")" + | CtypedExpression + { + howToRetrieveSourceType; + prefix; + expressionPath; + lookingToComplete; + alreadySeenIdents; + } -> + ("CtypedExpression(sourceType:" + ^ (howToRetrieveSourceType |> howToRetrieveSourceTypeToString) + ^ ", lookingToComplete:" + ^ lookingToCompleteToString lookingToComplete + ^ ", prefix:" ^ str prefix) + ^ ", pattern: " + ^ (expressionPath |> patternContextPathToString) + ^ + if List.length alreadySeenIdents > 0 then + ", seenIdents: " ^ list alreadySeenIdents ^ ")" + else "" end + +module CursorPosition = struct + type t = NoCursor | HasCursor | EmptyLoc + + let classifyLoc loc ~pos = + if loc |> Loc.hasPos ~pos then HasCursor + else if loc |> Loc.end_ = (Location.none |> Loc.end_) then EmptyLoc + else NoCursor + + let classifyLocationLoc (loc : 'a Location.loc) ~pos = + if Loc.start loc.Location.loc <= pos && pos <= Loc.end_ loc.loc then + HasCursor + else if loc.loc |> Loc.end_ = (Location.none |> Loc.end_) then EmptyLoc + else NoCursor + + let classifyPositions pos ~posStart ~posEnd = + if posStart <= pos && pos <= posEnd then HasCursor + else if posEnd = (Location.none |> Loc.end_) then EmptyLoc + else NoCursor +end + +type labelled = { + name: string; + opt: bool; + posStart: int * int; + posEnd: int * int; +} + +type label = labelled option +type arg = {label: label; exp: Parsetree.expression} + +let extractExpApplyArgs ~args = + let rec processArgs ~acc args = + match args with + | (((Asttypes.Labelled s | Optional s) as label), (e : Parsetree.expression)) + :: rest -> ( + let namedArgLoc = + e.pexp_attributes + |> List.find_opt (fun ({Asttypes.txt}, _) -> txt = "ns.namedArgLoc") + in + match namedArgLoc with + | Some ({loc}, _) -> + let labelled = + { + name = s; + opt = + (match label with + | Optional _ -> true + | _ -> false); + posStart = Loc.start loc; + posEnd = Loc.end_ loc; + } + in + processArgs ~acc:({label = Some labelled; exp = e} :: acc) rest + | None -> processArgs ~acc rest) + | (Asttypes.Nolabel, (e : Parsetree.expression)) :: rest -> + if e.pexp_loc.loc_ghost then processArgs ~acc rest + else processArgs ~acc:({label = None; exp = e} :: acc) rest + | [] -> List.rev acc + in + args |> processArgs ~acc:[] \ No newline at end of file diff --git a/analysis/src/Utils.ml b/analysis/src/Utils.ml index c785d54f1..ff4299c7b 100644 --- a/analysis/src/Utils.ml +++ b/analysis/src/Utils.ml @@ -71,3 +71,79 @@ let flattenLongIdent ?(jsx = false) ?(cutAtOffset = None) lid = in let path, _ = loop lid in List.rev path + +let identifyPexp pexp = + match pexp with + | Parsetree.Pexp_ident _ -> "Pexp_ident" + | Pexp_constant _ -> "Pexp_constant" + | Pexp_let _ -> "Pexp_let" + | Pexp_function _ -> "Pexp_function" + | Pexp_fun _ -> "Pexp_fun" + | Pexp_apply _ -> "Pexp_apply" + | Pexp_match _ -> "Pexp_match" + | Pexp_try _ -> "Pexp_try" + | Pexp_tuple _ -> "Pexp_tuple" + | Pexp_construct _ -> "Pexp_construct" + | Pexp_variant _ -> "Pexp_variant" + | Pexp_record _ -> "Pexp_record" + | Pexp_field _ -> "Pexp_field" + | Pexp_setfield _ -> "Pexp_setfield" + | Pexp_array _ -> "Pexp_array" + | Pexp_ifthenelse _ -> "Pexp_ifthenelse" + | Pexp_sequence _ -> "Pexp_sequence" + | Pexp_while _ -> "Pexp_while" + | Pexp_for _ -> "Pexp_for" + | Pexp_constraint _ -> "Pexp_constraint" + | Pexp_coerce _ -> "Pexp_coerce" + | Pexp_send _ -> "Pexp_send" + | Pexp_new _ -> "Pexp_new" + | Pexp_setinstvar _ -> "Pexp_setinstvar" + | Pexp_override _ -> "Pexp_override" + | Pexp_letmodule _ -> "Pexp_letmodule" + | Pexp_letexception _ -> "Pexp_letexception" + | Pexp_assert _ -> "Pexp_assert" + | Pexp_lazy _ -> "Pexp_lazy" + | Pexp_poly _ -> "Pexp_poly" + | Pexp_object _ -> "Pexp_object" + | Pexp_newtype _ -> "Pexp_newtype" + | Pexp_pack _ -> "Pexp_pack" + | Pexp_extension _ -> "Pexp_extension" + | Pexp_open _ -> "Pexp_open" + | Pexp_unreachable -> "Pexp_unreachable" + +let identifyPpat pat = + match pat with + | Parsetree.Ppat_any -> "Ppat_any" + | Ppat_var _ -> "Ppat_var" + | Ppat_alias _ -> "Ppat_alias" + | Ppat_constant _ -> "Ppat_constant" + | Ppat_interval _ -> "Ppat_interval" + | Ppat_tuple _ -> "Ppat_tuple" + | Ppat_construct _ -> "Ppat_construct" + | Ppat_variant _ -> "Ppat_variant" + | Ppat_record _ -> "Ppat_record" + | Ppat_array _ -> "Ppat_array" + | Ppat_or _ -> "Ppat_or" + | Ppat_constraint _ -> "Ppat_constraint" + | Ppat_type _ -> "Ppat_type" + | Ppat_lazy _ -> "Ppat_lazy" + | Ppat_unpack _ -> "Ppat_unpack" + | Ppat_exception _ -> "Ppat_exception" + | Ppat_extension _ -> "Ppat_extension" + | Ppat_open _ -> "Ppat_open" + +let identifyType type_desc = + match type_desc with + | Types.Tvar _ -> "Tvar" + | Tarrow _ -> "Tarrow" + | Ttuple _ -> "Ttuple" + | Tconstr _ -> "Tconstr" + | Tobject _ -> "Tobject" + | Tfield _ -> "Tfield" + | Tnil -> "Tnil" + | Tlink _ -> "Tlink" + | Tsubst _ -> "Tsubst" + | Tvariant _ -> "Tvariant" + | Tunivar _ -> "Tunivar" + | Tpoly _ -> "Tpoly" + | Tpackage _ -> "Tpackage" diff --git a/analysis/tests/src/BrokenParserCases.res b/analysis/tests/src/BrokenParserCases.res new file mode 100644 index 000000000..0e5c9495c --- /dev/null +++ b/analysis/tests/src/BrokenParserCases.res @@ -0,0 +1,16 @@ +// I would want this to recover to {someProp: %rescript.exprhole, ...}, but it currently eats the tuple + parses to {someProp: otherProp} +// let _ = ({someProp: , otherProp: 123}, 123) +// ^ast + +// Same problem here, does not recover from the missing prop, and ends up eating the rest of the record declaration while only parsing {firstProp: secondProp} +// let _ = someFunc({firstProp: , secondProp: 123, thirdProp: 123}) +// ^ast + +// I'd like the commas to be parsed as (broken) tuple "members" too. There's currently no robust way to derive _where_ in that tuple the cursor is, or even how many members the tuple has, because there's no pos match, and the empty comma item is just discarded. +// switch v { | (_, , _) => () } +// ^ast + +// Same problem here, does not recover from the missing prop, and ends up eating the rest of the record declaration while only parsing {firstProp: secondProp} +// let {someField, , otherField, } = someVal +// ^ast + diff --git a/analysis/tests/src/Completion.res b/analysis/tests/src/Completion.res index 4f3f46c04..4ad191100 100644 --- a/analysis/tests/src/Completion.res +++ b/analysis/tests/src/Completion.res @@ -51,7 +51,7 @@ let fa: ForAuto.t = 34 module O = { module Comp = { @react.component - let make = (~first="", ~zoo=3, ~second) => React.string(first ++ second ++ string_of_int(zoo)) + let make = (~first="", ~zoo=3, ~second) => React.string(first ++ string_of_int(second) ++ string_of_int(zoo)) } } diff --git a/analysis/tests/src/Jsx.res b/analysis/tests/src/Jsx.res index b49174d22..6b9e7f46c 100644 --- a/analysis/tests/src/Jsx.res +++ b/analysis/tests/src/Jsx.res @@ -168,3 +168,6 @@ let _ = { <> {<> } // ^hov } + +// let _ = +// ^com \ No newline at end of file diff --git a/analysis/tests/src/TypeContextCompletion_Jsx.res b/analysis/tests/src/TypeContextCompletion_Jsx.res new file mode 100644 index 000000000..8a9fff01c --- /dev/null +++ b/analysis/tests/src/TypeContextCompletion_Jsx.res @@ -0,0 +1,49 @@ +type someVariant = One | Two | Three | Four | Five(int) | Six(option, int) + +type otherVariant = [#one | #two | #three | #four | #five(int) | #six(option, int)] + +let someValue = Two + +module SomeComponent = { + @react.component + let make = ( + ~someVariant: someVariant, + ~anotherThing: TypeDefinition.variant, + ~thirdThing: otherVariant, + ) => { + ignore(someVariant) + ignore(anotherThing) + ignore(thirdThing) + React.null + } +} + +// let x = , int) + +type otherVariant = [#one | #two | #three | #four | #five(int) | #six(option, int)] + +let thisIsAValue = Two + +let someVariantToString = ( + ~someVariant, + ~anotherThing: TypeDefinition.variant, + ~thirdThing: otherVariant, +) => { + ignore(anotherThing) + ignore(thirdThing) + switch someVariant { + | One => "One" + | Two => "Two" + | Three => "Three" + | Four => "Four" + | _ => "-" + } +} + +// let x = someVariantToString(~someVaria +// ^com + +// let x = someVariantToString(~someVariant= +// ^com + +// let x = someVariantToString(~someVariant= +// ^com + +// let x = someVariantToString(~someVariant=T +// ^com + +// let x = someVariantToString(~someVariant=t +// ^com + +// let x = someVariantToString(~someVariant=TypeDefinition. +// ^com + +// let x = someVariantToString(~anotherThing= +// ^com + +// let x = someVariantToString(~thirdThing= +// ^com + +// let x = someVariantToString(~thirdThing= +// ^com + +// let x = someVariantToString(~thirdThing=#t +// ^com + +// let x = someVariantToString(~thirdThing=#T +// ^com + +type someRecord = { + age: int, + name: string, + maybeVariant: option, + definitivelyVariant: someVariant, + someTup: (string, someVariant), +} + +let doStuff = (~doThing: someRecord => unit) => { + ignore( + doThing({ + age: 123, + name: "hello", + maybeVariant: None, + definitivelyVariant: One, + someTup: ("123", One), + }), + ) +} + +// let _ = doStuff(~doThing=({age, n}) => {()}) +// ^com + +let doMoreStuff = (~someRecord: someRecord): someRecord => someRecord + +// doMoreStuff(~someRecord={someTup: ("123", O)}) +// ^com + +// let _ = doMoreStuff(~someRecord={age: 123, name: "123", }) +// ^com diff --git a/analysis/tests/src/TypeContextCompletion_Records.res b/analysis/tests/src/TypeContextCompletion_Records.res new file mode 100644 index 000000000..2bbf711db --- /dev/null +++ b/analysis/tests/src/TypeContextCompletion_Records.res @@ -0,0 +1,149 @@ +type anotherLevel = {level: int, someOtherArg: bool} +type someRecord = {somethingElse: int, whatIsThis: bool, anotherLevel: anotherLevel} + +type anotherRecord = {something: someRecord, anotherThing: option, thirdThing: string} + +let someVal = { + something: { + somethingElse: 123, + whatIsThis: false, + anotherLevel: {level: 123, someOtherArg: true}, + }, + anotherThing: None, + thirdThing: "test", +} + +// Simple destructuring +// let {another} = someVal +// ^com + +// let {anotherThing, s} = someVal +// ^com + +// let {} = someVal +// ^com + +let getSomeVal = (~irrelevant: int) => { + ignore(irrelevant) + someVal +} + +// Via function +// let {} = getSomeVal(~irrelevant=123) +// ^com + +// Nested destructuring +// let {something: {}} = someVal +// ^com + +// let {something: {whatIsThis, anotherLevel: {}}} = someVal +// ^com + +// let {something: {whatIsThis, anotherLevel: {l}}} = someVal +// ^com + +// let {something: {whatIsThis, anotherLevel, }} = someVal +// ^com + +// let {something: {whatIsThis, ,anotherLevel}} = someVal +// ^com + +// switch someVal { | {thirdThing: "123", som} => () } +// ^com + +// switch someVal { | {thirdThing: "1234"} => () | {} => () } +// ^com + +// switch someVal { | {thirdThing: "1234"} => () | {something: {whatIsThis, anotherLevel, }} => () } +// ^com + +type someOtherVariant = TwentyFive | SixtyTwo +type rec someVariant = + One | Two | Three(int) | Four(someOtherVariant) | Five(someOtherVariant, someVariant) + +type someRecordWithVariant = { + other: someRecord, + other2: option, + something: someVariant, + otherThing: option, + thirdStuff: (someRecord, someVariant, option, int), + fourthStuff: (option<[#WithPayload(someVariant)]>, someVariant), +} + +let someOtherValue: someRecordWithVariant = { + other: someVal.something, + other2: None, + something: Two, + otherThing: None, + thirdStuff: (someVal.something, One, None, 1), + fourthStuff: (None, One), +} + +// switch someOtherValue { | {something: Two | T} => () } +// ^com + +// switch someOtherValue { | {otherThing: Some(T)} => () } +// ^com + +// switch someOtherValue { | {thirdStuff: (_, T)} => () } +// ^com + +// switch someOtherValue { | {thirdStuff: (_, Four())} => () } +// ^com + +// switch someOtherValue { | {thirdStuff: (_, Five(_, O))} => () } +// ^com + +// switch someOtherValue { | {fourthStuff: (Some(#WithPayload(O)), _)} => () } +// ^com + +// switch someOtherValue { | {thirdStuff: (_, Five(_, One | Two | T))} => () } +// ^com + +// switch someOtherValue { | {otherThing: S} => () } +// ^com + +// switch someOtherValue { | {other2: S} => () } +// ^com + +// switch someOtherValue { | {thirdStuff: (_, Four(TwentyFive | ))} => () } +// ^com + +// switch someOtherValue { | {other2: } => () } +// ^com + +// switch someVal { | {something: {whatIsThis: false | } } => () } +// ^com + +// switch someVal { | {something: {whatIsThis: } } => () } +// ^com + +// switch someVal { | {something: {whatIsThis: fa } } => () } +// ^com + +let x = Some(One) + +// switch x { | } +// ^com + +// switch x { +// ^com + +let y = One + +// switch y { | } +// ^com + +// switch y { | One | Two | Three | } +// ^com + +// Should not complete because the record has no braces +// switch someVal { | {something: } => () } +// ^com + +// Should complete because the record has braces +// switch someVal { | {something: {} } => () } +// ^com + +// switch someOtherValue { | {fourthStuff: (_, _)} => () } +// ^com diff --git a/analysis/tests/src/TypedContextCompletionSpec.res b/analysis/tests/src/TypedContextCompletionSpec.res new file mode 100644 index 000000000..408f9d49d --- /dev/null +++ b/analysis/tests/src/TypedContextCompletionSpec.res @@ -0,0 +1,282 @@ +type anotherLevel = {level: int, someOtherArg: bool} +type someRecord = {somethingElse: int, whatIsThis: bool, anotherLevel: anotherLevel} + +type anotherRecord = {something: someRecord, anotherThing: option, thirdThing: string} + +let someVal = { + something: { + somethingElse: 123, + whatIsThis: false, + anotherLevel: {level: 123, someOtherArg: true}, + }, + anotherThing: None, + thirdThing: "test", +} + +let getSomeVal = (~irrelevant: int) => { + ignore(irrelevant) + someVal +} + +type someOtherVariant = TwentyFive | SixtyTwo +type rec someVariant = + One | Two | Three(int) | Four(someOtherVariant) | Five(someOtherVariant, someVariant) + +type someRecordWithVariant = { + other: someRecord, + other2: option, + something: someVariant, + otherThing: option, + thirdStuff: (someRecord, someVariant, option, int), + fourthStuff: (option<[#WithPayload(someVariant)]>, someVariant), +} + +let someOtherValue: someRecordWithVariant = { + other: someVal.something, + other2: None, + something: Two, + otherThing: None, + thirdStuff: (someVal.something, One, None, 1), + fourthStuff: (None, One), +} + +let x = Some(One) + +let y = One + +// --- Labelled arguments start --- + +// Should complete the labelled argument name +// let x = someVariantToString(~someVaria +// ^ast + +// Should complete the value for the someVariant arg +// let x = someVariantToString(~someVariant= +// ^ast + +// Same as above but with additional space +// let x = someVariantToString(~someVariant= +// ^^ast + +// Complete for variant T +// let x = someVariantToString(~someVariant=T +// ^ast + +// Complete for identifier t +// let x = someVariantToString(~someVariant=t +// ^ast + +// Complete for things in TypeDefinition. Factor in type? +// let x = someVariantToString(~someVariant=TypeDefinition. +// ^ast + +// Complete for arg anotherThing's type +// let x = someVariantToString(~anotherThing= +// ^ast + +// Complete for thirdThing's type +// let x = someVariantToString(~thirdThing= +// ^ast + +// Complete for polyvariant #t +// let x = someVariantToString(~thirdThing=#t +// ^ast + +// Complete for polyvariant #t +// let x = someVariantToString(~thirdThing=#T +// ^ast + +// --- Labelled arguments end --- + +// --- Record destructuring start --- + +// Complete for destructured record field starting with n +// let _ = doStuff(~doThing=({age, n}) => {()}) +// ^com + +// Complete for record field another +// let {another} = someVal +// ^com + +// Complete for record field s +// let {anotherThing, s} = someVal +// ^com + +// Complete for record fields of someVal +// let {} = someVal +// ^com + +// Complete for record fields of fn invocation +// let {} = getSomeVal(~irrelevant=123) +// ^com + +// Complete for record fields on record field something +// let {something: {}} = someVal +// ^com + +// Complete for record fields of type for anotherLevel +// let {something: {whatIsThis, anotherLevel: {}}} = someVal +// ^com + +// Complete for record fields of type for anotherLevel, with prefix "l" +// let {something: {whatIsThis, anotherLevel: {l}}} = someVal +// ^com + +// Complete for record fields of type for something, with seen idents whatIsThis, anotherLevel +// let {something: {whatIsThis, anotherLevel, }} = someVal +// ^com + +// Complete for record fields of type for something, with seen idents whatIsThis, anotherLevel +// let {something: {whatIsThis, ,anotherLevel}} = someVal +// ^com + +// --- Record destructuring end --- + +// --- Pattern matching start --- + +// Complete for record field som in root record +// switch someVal { | {thirdThing: "123", som} => () } +// ^com + +// Complete for any record field in root record +// switch someVal { | {thirdThing: "1234"} => () | {} => () } +// ^com + +// Complete for record field in type of root record->something +// switch someVal { | {thirdThing: "1234"} => () | {something: {whatIsThis, anotherLevel, }} => () } +// ^com + +// Complete for variant starting with T in rfield something of root record +// switch someOtherValue { | {something: Two | T} => () } +// ^com + +// switch someOtherValue { | {otherThing: Some(T)} => () } +// ^com + +// switch someOtherValue { | {thirdStuff: (_, T)} => () } +// ^com + +// switch someOtherValue { | {thirdStuff: (_, Four())} => () } +// ^com + +// switch someOtherValue { | {thirdStuff: (_, Five(_, O))} => () } +// ^com + +// switch someOtherValue { | {fourthStuff: (Some(#WithPayload(O)), _)} => () } +// ^com + +// switch someOtherValue { | {thirdStuff: (_, Five(_, One | Two | T))} => () } +// ^com + +// switch someOtherValue { | {otherThing: S} => () } +// ^com + +// switch someOtherValue { | {other2: S} => () } +// ^com + +// switch someOtherValue { | {thirdStuff: (_, Four(TwentyFive | ))} => () } +// ^com + +// switch someOtherValue { | {other2: } => () } +// ^com + +// switch someVal { | {something: {whatIsThis: false | } } => () } +// ^com + +// switch someVal { | {something: {whatIsThis: } } => () } +// ^com + +// switch someVal { | {something: {whatIsThis: fa } } => () } +// ^com + +// Complete for root type of x +// switch x { | } +// ^com + +// Incomplete switch, no completion +// switch x { +// ^com + +// switch y { | } +// ^com + +// switch y { | One | Two | Three | } +// ^com + +// Should not complete because the record has no braces +// switch someVal { | {something: } => () } +// ^com + +// Should not complete because the record has no braces +// switch someVal { | => () } +// ^com + +// No path, looking for record field +// switch someVal { | {} => () } +// ^com + +// Should complete because the record has braces +// switch someVal { | {something} => () } +// ^com + +// switch someVal { | {something: {}} => () } +// ^com + +// Should not complete because the record has no braces +// switch someVal { | {something: {el: } } => () } +// ^com + +// switch someOtherValue { | {other2: #S()} => () } +// ^com + +// switch someOtherValue { | {thirdStuff: Some(_, {something: t})} => () } +// ^com + +// switch someOtherValue { | {thirdStuff: (_, {something: t})} => () } +// ^com + +// Mixing matches in branches is still picked up as seen idents +// switch y { | One | Two => () | Three => () | T } +// ^com + +// switch someVal { | {something: {whatIsThis: false | } } => () } +// ^com + +// Mixing matches in branches is still picked up as seen idents +// switch y { | One | Two => () | Three => () | } +// ^com + +// switch someOtherValue { | {thirdStuff: } => () | } +// ^com + +// --- Pattern matching end --- + +// let someVar: Completion.r = +// ^com + +// let x: user = {age: 123, } +// ^com + +// --- Inline records --- +type withInlineRecords = One({first: bool, second: option}) | TTwo | TThree + +let withInlineRecords: withInlineRecords = TTwo + +// switch withInlineRecords { | One({}) } +// ^com + +// switch withInlineRecords { | } +// ^com + +// -- Nested optionals --- +type locationState = {shallow: option} + +type location = {state: locationState} + +let location = {state: {shallow: None}} + +// let isShallow = switch location.state { | {shallow: Some()} => true | _ => false } +// ^com + +// let isShallow = switch location.state { | {shallow: } => true | _ => false } +// ^com diff --git a/analysis/tests/src/expected/BrokenParserCases.res.txt b/analysis/tests/src/expected/BrokenParserCases.res.txt new file mode 100644 index 000000000..e8c6e2e37 --- /dev/null +++ b/analysis/tests/src/expected/BrokenParserCases.res.txt @@ -0,0 +1,79 @@ +Dump AST src/BrokenParserCases.res 1:22 + +Source: +// let _ = ({someProp: , otherProp: 123}, 123) +// ^ast + +<*>Pstr_value( + value: + Ppat_any + expr: + <*>Pexp_record( + fields: + someProp: Pexp_ident:otherProp + ) +) + +Dump AST src/BrokenParserCases.res 5:31 + +Source: +// let _ = someFunc({firstProp: , secondProp: 123, thirdProp: 123}) +// ^ast + +<*>Pstr_value( + value: + Ppat_any + expr: + <*>Pexp_apply( + expr: + Pexp_ident:someFunc + args: + = + <*>Pexp_record( + fields: + firstProp: Pexp_ident:secondProp + ), + = + Pexp_constant(Pconst_integer(123)), + = + , + = + Pexp_constant(Pconst_integer(123)) + ) +) + +Dump AST src/BrokenParserCases.res 9:19 + +Source: +// switch v { | (_, , _) => () } +// ^ast + +<*>Pstr_eval( +<*>Pexp_match(Pexp_ident:v) + case 1: + pattern<*>: + <*>Ppat_tuple( + Ppat_any, + Ppat_any + ) + expr: + Pexp_construct(()) +) + +Dump AST src/BrokenParserCases.res 13:18 + +Source: +// let {someField, , otherField, } = someVal +// ^ast + +<*>Pstr_value( + value: + <*>Ppat_record( + fields: + someField: Ppat_var(someField) + otherField: Ppat_var(otherField) + ) + expr: + Pexp_ident:someVal +) + diff --git a/analysis/tests/src/expected/CompletePrioritize1.res.txt b/analysis/tests/src/expected/CompletePrioritize1.res.txt index 3f5485410..eced522e2 100644 --- a/analysis/tests/src/expected/CompletePrioritize1.res.txt +++ b/analysis/tests/src/expected/CompletePrioritize1.res.txt @@ -6,6 +6,9 @@ Completable: Cpath Value[a]-> "kind": 12, "tags": [], "detail": "float => float", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] diff --git a/analysis/tests/src/expected/CompletePrioritize2.res.txt b/analysis/tests/src/expected/CompletePrioritize2.res.txt index b3b9674e1..378e7411c 100644 --- a/analysis/tests/src/expected/CompletePrioritize2.res.txt +++ b/analysis/tests/src/expected/CompletePrioritize2.res.txt @@ -6,7 +6,10 @@ Completable: Cpath Value[ax]-> "kind": 12, "tags": [], "detail": "t => int", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/CompletePrioritize2.res 12:5 @@ -18,6 +21,9 @@ Completable: Cpath Value[ax] "kind": 12, "tags": [], "detail": "Test.t", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] diff --git a/analysis/tests/src/expected/Completion.res.txt b/analysis/tests/src/expected/Completion.res.txt index a32963ef6..287652a32 100644 --- a/analysis/tests/src/expected/Completion.res.txt +++ b/analysis/tests/src/expected/Completion.res.txt @@ -7,67 +7,100 @@ Completable: Cpath Value[MyList, m] "kind": 12, "tags": [], "detail": "(t<'a>, 'a => 'b) => t<'b>", - "documentation": {"kind": "markdown", "value": "\n Equivalent to:\n\n ```res\n map(someList, f)->reverse\n ```\n\n ```res example\n list{3, 4, 5}->Belt.List.mapReverse(x => x * x) /* list{25, 16, 9} */\n ```\n"} + "documentation": {"kind": "markdown", "value": "\n Equivalent to:\n\n ```res\n map(someList, f)->reverse\n ```\n\n ```res example\n list{3, 4, 5}->Belt.List.mapReverse(x => x * x) /* list{25, 16, 9} */\n ```\n"}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "makeBy", "kind": 12, "tags": [], "detail": "(int, int => 'a) => t<'a>", - "documentation": {"kind": "markdown", "value": "\nReturn a list of length `numItems` with element `i` initialized with `f(i)`.\nReturns an empty list if `numItems` is negative.\n\n```res example\nBelt.List.makeBy(5, i => i) // list{0, 1, 2, 3, 4}\n\nBelt.List.makeBy(5, i => i * i) // list{0, 1, 4, 9, 16}\n```\n"} + "documentation": {"kind": "markdown", "value": "\nReturn a list of length `numItems` with element `i` initialized with `f(i)`.\nReturns an empty list if `numItems` is negative.\n\n```res example\nBelt.List.makeBy(5, i => i) // list{0, 1, 2, 3, 4}\n\nBelt.List.makeBy(5, i => i * i) // list{0, 1, 4, 9, 16}\n```\n"}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "make", "kind": 12, "tags": [], "detail": "(int, 'a) => t<'a>", - "documentation": {"kind": "markdown", "value": "\n Returns a list of length `numItems` with each element filled with value `v`. Returns an empty list if `numItems` is negative.\n\n ```res example\n Belt.List.make(3, 1) // list{1, 1, 1}\n ```\n"} + "documentation": {"kind": "markdown", "value": "\n Returns a list of length `numItems` with each element filled with value `v`. Returns an empty list if `numItems` is negative.\n\n ```res example\n Belt.List.make(3, 1) // list{1, 1, 1}\n ```\n"}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "mapReverse2U", "kind": 12, "tags": [], "detail": "(t<'a>, t<'b>, (. 'a, 'b) => 'c) => t<'c>", - "documentation": {"kind": "markdown", "value": " Uncurried version of [mapReverse2](#mapReverse2). "} + "documentation": {"kind": "markdown", "value": " Uncurried version of [mapReverse2](#mapReverse2). "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "map", "kind": 12, "tags": [], "detail": "(t<'a>, 'a => 'b) => t<'b>", - "documentation": {"kind": "markdown", "value": "\n Returns a new list with `f` applied to each element of `someList`.\n\n ```res example\n list{1, 2}->Belt.List.map(x => x + 1) // list{3, 4}\n ```\n"} + "documentation": {"kind": "markdown", "value": "\n Returns a new list with `f` applied to each element of `someList`.\n\n ```res example\n list{1, 2}->Belt.List.map(x => x + 1) // list{3, 4}\n ```\n"}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "mapWithIndexU", "kind": 12, "tags": [], "detail": "(t<'a>, (. int, 'a) => 'b) => t<'b>", - "documentation": {"kind": "markdown", "value": " Uncurried version of [mapWithIndex](#mapWithIndex). "} + "documentation": {"kind": "markdown", "value": " Uncurried version of [mapWithIndex](#mapWithIndex). "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "mapU", "kind": 12, "tags": [], "detail": "(t<'a>, (. 'a) => 'b) => t<'b>", - "documentation": {"kind": "markdown", "value": " Uncurried version of [map](#map). "} + "documentation": {"kind": "markdown", "value": " Uncurried version of [map](#map). "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "makeByU", "kind": 12, "tags": [], "detail": "(int, (. int) => 'a) => t<'a>", - "documentation": {"kind": "markdown", "value": " Uncurried version of [makeBy](#makeBy) "} + "documentation": {"kind": "markdown", "value": " Uncurried version of [makeBy](#makeBy) "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "mapReverse2", "kind": 12, "tags": [], "detail": "(t<'a>, t<'b>, ('a, 'b) => 'c) => t<'c>", - "documentation": {"kind": "markdown", "value": "\n Equivalent to: `zipBy(xs, ys, f)->reverse`\n\n ```res example\n\n Belt.List.mapReverse2(list{1, 2, 3}, list{1, 2}, (a, b) => a + b) // list{4, 2}\n ```\n"} + "documentation": {"kind": "markdown", "value": "\n Equivalent to: `zipBy(xs, ys, f)->reverse`\n\n ```res example\n\n Belt.List.mapReverse2(list{1, 2, 3}, list{1, 2}, (a, b) => a + b) // list{4, 2}\n ```\n"}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "mapWithIndex", "kind": 12, "tags": [], "detail": "(t<'a>, (int, 'a) => 'b) => t<'b>", - "documentation": {"kind": "markdown", "value": "\n Applies `f` to each element of `someList`.\n Function `f` takes two arguments: the index starting from 0 and the element from `someList`, in that order.\n\n ```res example\n list{1, 2, 3}->Belt.List.mapWithIndex((index, x) => index + x) // list{1, 3, 5}\n ```\n"} + "documentation": {"kind": "markdown", "value": "\n Applies `f` to each element of `someList`.\n Function `f` takes two arguments: the index starting from 0 and the element from `someList`, in that order.\n\n ```res example\n list{1, 2, 3}->Belt.List.mapWithIndex((index, x) => index + x) // list{1, 3, 5}\n ```\n"}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "mapReverseU", "kind": 12, "tags": [], "detail": "(t<'a>, (. 'a) => 'b) => t<'b>", - "documentation": {"kind": "markdown", "value": " Uncurried version of [mapReverse](#mapReverse). "} + "documentation": {"kind": "markdown", "value": " Uncurried version of [mapReverse](#mapReverse). "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 3:9 @@ -79,217 +112,325 @@ Completable: Cpath Value[Array, ""] "kind": 12, "tags": [], "detail": "(('a, 'b) => 'a, 'a, array<'b>) => 'a", - "documentation": {"kind": "markdown", "value": " [Array.fold_left f x a] computes\n [f (... (f (f x a.(0)) a.(1)) ...) a.(n-1)],\n where [n] is the length of the array [a]. "} + "documentation": {"kind": "markdown", "value": " [Array.fold_left f x a] computes\n [f (... (f (f x a.(0)) a.(1)) ...) a.(n-1)],\n where [n] is the length of the array [a]. "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "concat", "kind": 12, "tags": [], "detail": "list> => array<'a>", - "documentation": {"kind": "markdown", "value": " Same as {!Array.append}, but concatenates a list of arrays. "} + "documentation": {"kind": "markdown", "value": " Same as {!Array.append}, but concatenates a list of arrays. "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "mapi", "kind": 12, "tags": [], "detail": "((int, 'a) => 'b, array<'a>) => array<'b>", - "documentation": {"kind": "markdown", "value": " Same as {!Array.map}, but the\n function is applied to the index of the element as first argument,\n and the element itself as second argument. "} + "documentation": {"kind": "markdown", "value": " Same as {!Array.map}, but the\n function is applied to the index of the element as first argument,\n and the element itself as second argument. "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "exists", "kind": 12, "tags": [], "detail": "('a => bool, array<'a>) => bool", - "documentation": {"kind": "markdown", "value": " [Array.exists p [|a1; ...; an|]] checks if at least one element of\n the array satisfies the predicate [p]. That is, it returns\n [(p a1) || (p a2) || ... || (p an)].\n @since 4.03.0 "} + "documentation": {"kind": "markdown", "value": " [Array.exists p [|a1; ...; an|]] checks if at least one element of\n the array satisfies the predicate [p]. That is, it returns\n [(p a1) || (p a2) || ... || (p an)].\n @since 4.03.0 "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "for_all", "kind": 12, "tags": [], "detail": "('a => bool, array<'a>) => bool", - "documentation": {"kind": "markdown", "value": " [Array.for_all p [|a1; ...; an|]] checks if all elements of the array\n satisfy the predicate [p]. That is, it returns\n [(p a1) && (p a2) && ... && (p an)].\n @since 4.03.0 "} + "documentation": {"kind": "markdown", "value": " [Array.for_all p [|a1; ...; an|]] checks if all elements of the array\n satisfy the predicate [p]. That is, it returns\n [(p a1) && (p a2) && ... && (p an)].\n @since 4.03.0 "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "copy", "kind": 12, "tags": [], "detail": "array<'a> => array<'a>", - "documentation": {"kind": "markdown", "value": " [Array.copy a] returns a copy of [a], that is, a fresh array\n containing the same elements as [a]. "} + "documentation": {"kind": "markdown", "value": " [Array.copy a] returns a copy of [a], that is, a fresh array\n containing the same elements as [a]. "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "iter2", "kind": 12, "tags": [], "detail": "(('a, 'b) => unit, array<'a>, array<'b>) => unit", - "documentation": {"kind": "markdown", "value": " [Array.iter2 f a b] applies function [f] to all the elements of [a]\n and [b].\n Raise [Invalid_argument] if the arrays are not the same size.\n @since 4.03.0 "} + "documentation": {"kind": "markdown", "value": " [Array.iter2 f a b] applies function [f] to all the elements of [a]\n and [b].\n Raise [Invalid_argument] if the arrays are not the same size.\n @since 4.03.0 "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "to_list", "kind": 12, "tags": [], "detail": "array<'a> => list<'a>", - "documentation": {"kind": "markdown", "value": " [Array.to_list a] returns the list of all the elements of [a]. "} + "documentation": {"kind": "markdown", "value": " [Array.to_list a] returns the list of all the elements of [a]. "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "stable_sort", "kind": 12, "tags": [], "detail": "(('a, 'a) => int, array<'a>) => unit", - "documentation": {"kind": "markdown", "value": " Same as {!Array.sort}, but the sorting algorithm is stable (i.e.\n elements that compare equal are kept in their original order) and\n not guaranteed to run in constant heap space.\n\n The current implementation uses Merge Sort. It uses [n/2]\n words of heap space, where [n] is the length of the array.\n It is usually faster than the current implementation of {!Array.sort}.\n"} + "documentation": {"kind": "markdown", "value": " Same as {!Array.sort}, but the sorting algorithm is stable (i.e.\n elements that compare equal are kept in their original order) and\n not guaranteed to run in constant heap space.\n\n The current implementation uses Merge Sort. It uses [n/2]\n words of heap space, where [n] is the length of the array.\n It is usually faster than the current implementation of {!Array.sort}.\n"}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "iteri", "kind": 12, "tags": [], "detail": "((int, 'a) => unit, array<'a>) => unit", - "documentation": {"kind": "markdown", "value": " Same as {!Array.iter}, but the\n function is applied with the index of the element as first argument,\n and the element itself as second argument. "} + "documentation": {"kind": "markdown", "value": " Same as {!Array.iter}, but the\n function is applied with the index of the element as first argument,\n and the element itself as second argument. "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "memq", "kind": 12, "tags": [], "detail": "('a, array<'a>) => bool", - "documentation": {"kind": "markdown", "value": " Same as {!Array.mem}, but uses physical equality instead of structural\n equality to compare array elements.\n @since 4.03.0 "} + "documentation": {"kind": "markdown", "value": " Same as {!Array.mem}, but uses physical equality instead of structural\n equality to compare array elements.\n @since 4.03.0 "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "map2", "kind": 12, "tags": [], "detail": "(('a, 'b) => 'c, array<'a>, array<'b>) => array<'c>", - "documentation": {"kind": "markdown", "value": " [Array.map2 f a b] applies function [f] to all the elements of [a]\n and [b], and builds an array with the results returned by [f]:\n [[| f a.(0) b.(0); ...; f a.(Array.length a - 1) b.(Array.length b - 1)|]].\n Raise [Invalid_argument] if the arrays are not the same size.\n @since 4.03.0 "} + "documentation": {"kind": "markdown", "value": " [Array.map2 f a b] applies function [f] to all the elements of [a]\n and [b], and builds an array with the results returned by [f]:\n [[| f a.(0) b.(0); ...; f a.(Array.length a - 1) b.(Array.length b - 1)|]].\n Raise [Invalid_argument] if the arrays are not the same size.\n @since 4.03.0 "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "set", "kind": 12, "tags": [], "detail": "(array<'a>, int, 'a) => unit", - "documentation": {"kind": "markdown", "value": " [Array.set a n x] modifies array [a] in place, replacing\n element number [n] with [x].\n You can also write [a.(n) <- x] instead of [Array.set a n x].\n\n Raise [Invalid_argument \"index out of bounds\"]\n if [n] is outside the range 0 to [Array.length a - 1]. "} + "documentation": {"kind": "markdown", "value": " [Array.set a n x] modifies array [a] in place, replacing\n element number [n] with [x].\n You can also write [a.(n) <- x] instead of [Array.set a n x].\n\n Raise [Invalid_argument \"index out of bounds\"]\n if [n] is outside the range 0 to [Array.length a - 1]. "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "make", "kind": 12, "tags": [], "detail": "(int, 'a) => array<'a>", - "documentation": {"kind": "markdown", "value": " [Array.make n x] returns a fresh array of length [n],\n initialized with [x].\n All the elements of this new array are initially\n physically equal to [x] (in the sense of the [==] predicate).\n Consequently, if [x] is mutable, it is shared among all elements\n of the array, and modifying [x] through one of the array entries\n will modify all other entries at the same time.\n\n Raise [Invalid_argument] if [n < 0] or [n > Sys.max_array_length].\n If the value of [x] is a floating-point number, then the maximum\n size is only [Sys.max_array_length / 2]."} + "documentation": {"kind": "markdown", "value": " [Array.make n x] returns a fresh array of length [n],\n initialized with [x].\n All the elements of this new array are initially\n physically equal to [x] (in the sense of the [==] predicate).\n Consequently, if [x] is mutable, it is shared among all elements\n of the array, and modifying [x] through one of the array entries\n will modify all other entries at the same time.\n\n Raise [Invalid_argument] if [n < 0] or [n > Sys.max_array_length].\n If the value of [x] is a floating-point number, then the maximum\n size is only [Sys.max_array_length / 2]."}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "make_float", "kind": 12, "tags": [], "detail": "int => array", - "documentation": {"kind": "markdown", "value": " @deprecated [Array.make_float] is an alias for {!Array.create_float}. "} + "documentation": {"kind": "markdown", "value": " @deprecated [Array.make_float] is an alias for {!Array.create_float}. "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "fold_right", "kind": 12, "tags": [], "detail": "(('b, 'a) => 'a, array<'b>, 'a) => 'a", - "documentation": {"kind": "markdown", "value": " [Array.fold_right f a x] computes\n [f a.(0) (f a.(1) ( ... (f a.(n-1) x) ...))],\n where [n] is the length of the array [a]. "} + "documentation": {"kind": "markdown", "value": " [Array.fold_right f a x] computes\n [f a.(0) (f a.(1) ( ... (f a.(n-1) x) ...))],\n where [n] is the length of the array [a]. "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "sort", "kind": 12, "tags": [], "detail": "(('a, 'a) => int, array<'a>) => unit", - "documentation": {"kind": "markdown", "value": " Sort an array in increasing order according to a comparison\n function. The comparison function must return 0 if its arguments\n compare as equal, a positive integer if the first is greater,\n and a negative integer if the first is smaller (see below for a\n complete specification). For example, {!Pervasives.compare} is\n a suitable comparison function, provided there are no floating-point\n NaN values in the data. After calling [Array.sort], the\n array is sorted in place in increasing order.\n [Array.sort] is guaranteed to run in constant heap space\n and (at most) logarithmic stack space.\n\n The current implementation uses Heap Sort. It runs in constant\n stack space.\n\n Specification of the comparison function:\n Let [a] be the array and [cmp] the comparison function. The following\n must be true for all x, y, z in a :\n- [cmp x y] > 0 if and only if [cmp y x] < 0\n- if [cmp x y] >= 0 and [cmp y z] >= 0 then [cmp x z] >= 0\n\n When [Array.sort] returns, [a] contains the same elements as before,\n reordered in such a way that for all i and j valid indices of [a] :\n- [cmp a.(i) a.(j)] >= 0 if and only if i >= j\n"} + "documentation": {"kind": "markdown", "value": " Sort an array in increasing order according to a comparison\n function. The comparison function must return 0 if its arguments\n compare as equal, a positive integer if the first is greater,\n and a negative integer if the first is smaller (see below for a\n complete specification). For example, {!Pervasives.compare} is\n a suitable comparison function, provided there are no floating-point\n NaN values in the data. After calling [Array.sort], the\n array is sorted in place in increasing order.\n [Array.sort] is guaranteed to run in constant heap space\n and (at most) logarithmic stack space.\n\n The current implementation uses Heap Sort. It runs in constant\n stack space.\n\n Specification of the comparison function:\n Let [a] be the array and [cmp] the comparison function. The following\n must be true for all x, y, z in a :\n- [cmp x y] > 0 if and only if [cmp y x] < 0\n- if [cmp x y] >= 0 and [cmp y z] >= 0 then [cmp x z] >= 0\n\n When [Array.sort] returns, [a] contains the same elements as before,\n reordered in such a way that for all i and j valid indices of [a] :\n- [cmp a.(i) a.(j)] >= 0 if and only if i >= j\n"}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "length", "kind": 12, "tags": [], "detail": "array<'a> => int", - "documentation": {"kind": "markdown", "value": " Return the length (number of elements) of the given array. "} + "documentation": {"kind": "markdown", "value": " Return the length (number of elements) of the given array. "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "sub", "kind": 12, "tags": [], "detail": "(array<'a>, int, int) => array<'a>", - "documentation": {"kind": "markdown", "value": " [Array.sub a start len] returns a fresh array of length [len],\n containing the elements number [start] to [start + len - 1]\n of array [a].\n\n Raise [Invalid_argument \"Array.sub\"] if [start] and [len] do not\n designate a valid subarray of [a]; that is, if\n [start < 0], or [len < 0], or [start + len > Array.length a]. "} + "documentation": {"kind": "markdown", "value": " [Array.sub a start len] returns a fresh array of length [len],\n containing the elements number [start] to [start + len - 1]\n of array [a].\n\n Raise [Invalid_argument \"Array.sub\"] if [start] and [len] do not\n designate a valid subarray of [a]; that is, if\n [start < 0], or [len < 0], or [start + len > Array.length a]. "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "of_list", "kind": 12, "tags": [], "detail": "list<'a> => array<'a>", - "documentation": {"kind": "markdown", "value": " [Array.of_list l] returns a fresh array containing the elements\n of [l]. "} + "documentation": {"kind": "markdown", "value": " [Array.of_list l] returns a fresh array containing the elements\n of [l]. "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "iter", "kind": 12, "tags": [], "detail": "('a => unit, array<'a>) => unit", - "documentation": {"kind": "markdown", "value": " [Array.iter f a] applies function [f] in turn to all\n the elements of [a]. It is equivalent to\n [f a.(0); f a.(1); ...; f a.(Array.length a - 1); ()]. "} + "documentation": {"kind": "markdown", "value": " [Array.iter f a] applies function [f] in turn to all\n the elements of [a]. It is equivalent to\n [f a.(0); f a.(1); ...; f a.(Array.length a - 1); ()]. "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "map", "kind": 12, "tags": [], "detail": "('a => 'b, array<'a>) => array<'b>", - "documentation": {"kind": "markdown", "value": " [Array.map f a] applies function [f] to all the elements of [a],\n and builds an array with the results returned by [f]:\n [[| f a.(0); f a.(1); ...; f a.(Array.length a - 1) |]]. "} + "documentation": {"kind": "markdown", "value": " [Array.map f a] applies function [f] to all the elements of [a],\n and builds an array with the results returned by [f]:\n [[| f a.(0); f a.(1); ...; f a.(Array.length a - 1) |]]. "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "unsafe_get", "kind": 12, "tags": [], "detail": "(array<'a>, int) => 'a", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "make_matrix", "kind": 12, "tags": [], "detail": "(int, int, 'a) => array>", - "documentation": {"kind": "markdown", "value": " [Array.make_matrix dimx dimy e] returns a two-dimensional array\n (an array of arrays) with first dimension [dimx] and\n second dimension [dimy]. All the elements of this new matrix\n are initially physically equal to [e].\n The element ([x,y]) of a matrix [m] is accessed\n with the notation [m.(x).(y)].\n\n Raise [Invalid_argument] if [dimx] or [dimy] is negative or\n greater than {!Sys.max_array_length}.\n If the value of [e] is a floating-point number, then the maximum\n size is only [Sys.max_array_length / 2]. "} + "documentation": {"kind": "markdown", "value": " [Array.make_matrix dimx dimy e] returns a two-dimensional array\n (an array of arrays) with first dimension [dimx] and\n second dimension [dimy]. All the elements of this new matrix\n are initially physically equal to [e].\n The element ([x,y]) of a matrix [m] is accessed\n with the notation [m.(x).(y)].\n\n Raise [Invalid_argument] if [dimx] or [dimy] is negative or\n greater than {!Sys.max_array_length}.\n If the value of [e] is a floating-point number, then the maximum\n size is only [Sys.max_array_length / 2]. "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "mem", "kind": 12, "tags": [], "detail": "('a, array<'a>) => bool", - "documentation": {"kind": "markdown", "value": " [mem a l] is true if and only if [a] is equal\n to an element of [l].\n @since 4.03.0 "} + "documentation": {"kind": "markdown", "value": " [mem a l] is true if and only if [a] is equal\n to an element of [l].\n @since 4.03.0 "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "get", "kind": 12, "tags": [], "detail": "(array<'a>, int) => 'a", - "documentation": {"kind": "markdown", "value": " [Array.get a n] returns the element number [n] of array [a].\n The first element has number 0.\n The last element has number [Array.length a - 1].\n You can also write [a.(n)] instead of [Array.get a n].\n\n Raise [Invalid_argument \"index out of bounds\"]\n if [n] is outside the range 0 to [(Array.length a - 1)]. "} + "documentation": {"kind": "markdown", "value": " [Array.get a n] returns the element number [n] of array [a].\n The first element has number 0.\n The last element has number [Array.length a - 1].\n You can also write [a.(n)] instead of [Array.get a n].\n\n Raise [Invalid_argument \"index out of bounds\"]\n if [n] is outside the range 0 to [(Array.length a - 1)]. "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "append", "kind": 12, "tags": [], "detail": "(array<'a>, array<'a>) => array<'a>", - "documentation": {"kind": "markdown", "value": " [Array.append v1 v2] returns a fresh array containing the\n concatenation of the arrays [v1] and [v2]. "} + "documentation": {"kind": "markdown", "value": " [Array.append v1 v2] returns a fresh array containing the\n concatenation of the arrays [v1] and [v2]. "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "unsafe_set", "kind": 12, "tags": [], "detail": "(array<'a>, int, 'a) => unit", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "create_matrix", "kind": 12, "tags": [], "detail": "(int, int, 'a) => array>", - "documentation": {"kind": "markdown", "value": " @deprecated [Array.create_matrix] is an alias for {!Array.make_matrix}. "} + "documentation": {"kind": "markdown", "value": " @deprecated [Array.create_matrix] is an alias for {!Array.make_matrix}. "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "create_float", "kind": 12, "tags": [], "detail": "int => array", - "documentation": {"kind": "markdown", "value": " [Array.create_float n] returns a fresh float array of length [n],\n with uninitialized data.\n @since 4.03 "} + "documentation": {"kind": "markdown", "value": " [Array.create_float n] returns a fresh float array of length [n],\n with uninitialized data.\n @since 4.03 "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "create", "kind": 12, "tags": [], "detail": "(int, 'a) => array<'a>", - "documentation": {"kind": "markdown", "value": " @deprecated [Array.create] is an alias for {!Array.make}. "} + "documentation": {"kind": "markdown", "value": " @deprecated [Array.create] is an alias for {!Array.make}. "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "init", "kind": 12, "tags": [], "detail": "(int, int => 'a) => array<'a>", - "documentation": {"kind": "markdown", "value": " [Array.init n f] returns a fresh array of length [n],\n with element number [i] initialized to the result of [f i].\n In other terms, [Array.init n f] tabulates the results of [f]\n applied to the integers [0] to [n-1].\n\n Raise [Invalid_argument] if [n < 0] or [n > Sys.max_array_length].\n If the return type of [f] is [float], then the maximum\n size is only [Sys.max_array_length / 2]."} + "documentation": {"kind": "markdown", "value": " [Array.init n f] returns a fresh array of length [n],\n with element number [i] initialized to the result of [f i].\n In other terms, [Array.init n f] tabulates the results of [f]\n applied to the integers [0] to [n-1].\n\n Raise [Invalid_argument] if [n < 0] or [n > Sys.max_array_length].\n If the return type of [f] is [float], then the maximum\n size is only [Sys.max_array_length / 2]."}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "fast_sort", "kind": 12, "tags": [], "detail": "(('a, 'a) => int, array<'a>) => unit", - "documentation": {"kind": "markdown", "value": " Same as {!Array.sort} or {!Array.stable_sort}, whichever is faster\n on typical input.\n"} + "documentation": {"kind": "markdown", "value": " Same as {!Array.sort} or {!Array.stable_sort}, whichever is faster\n on typical input.\n"}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "fill", "kind": 12, "tags": [], "detail": "(array<'a>, int, int, 'a) => unit", - "documentation": {"kind": "markdown", "value": " [Array.fill a ofs len x] modifies the array [a] in place,\n storing [x] in elements number [ofs] to [ofs + len - 1].\n\n Raise [Invalid_argument \"Array.fill\"] if [ofs] and [len] do not\n designate a valid subarray of [a]. "} + "documentation": {"kind": "markdown", "value": " [Array.fill a ofs len x] modifies the array [a] in place,\n storing [x] in elements number [ofs] to [ofs + len - 1].\n\n Raise [Invalid_argument \"Array.fill\"] if [ofs] and [len] do not\n designate a valid subarray of [a]. "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "blit", "kind": 12, "tags": [], "detail": "(array<'a>, int, array<'a>, int, int) => unit", - "documentation": {"kind": "markdown", "value": " [Array.blit v1 o1 v2 o2 len] copies [len] elements\n from array [v1], starting at element number [o1], to array [v2],\n starting at element number [o2]. It works correctly even if\n [v1] and [v2] are the same array, and the source and\n destination chunks overlap.\n\n Raise [Invalid_argument \"Array.blit\"] if [o1] and [len] do not\n designate a valid subarray of [v1], or if [o2] and [len] do not\n designate a valid subarray of [v2]. "} + "documentation": {"kind": "markdown", "value": " [Array.blit v1 o1 v2 o2 len] copies [len] elements\n from array [v1], starting at element number [o1], to array [v2],\n starting at element number [o2]. It works correctly even if\n [v1] and [v2] are the same array, and the source and\n destination chunks overlap.\n\n Raise [Invalid_argument \"Array.blit\"] if [o1] and [len] do not\n designate a valid subarray of [v1], or if [o2] and [len] do not\n designate a valid subarray of [v2]. "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "Floatarray", "kind": 9, "tags": [], "detail": "module", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 5:10 @@ -301,49 +442,73 @@ Completable: Cpath Value[Array, m] "kind": 12, "tags": [], "detail": "((int, 'a) => 'b, array<'a>) => array<'b>", - "documentation": {"kind": "markdown", "value": " Same as {!Array.map}, but the\n function is applied to the index of the element as first argument,\n and the element itself as second argument. "} + "documentation": {"kind": "markdown", "value": " Same as {!Array.map}, but the\n function is applied to the index of the element as first argument,\n and the element itself as second argument. "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "memq", "kind": 12, "tags": [], "detail": "('a, array<'a>) => bool", - "documentation": {"kind": "markdown", "value": " Same as {!Array.mem}, but uses physical equality instead of structural\n equality to compare array elements.\n @since 4.03.0 "} + "documentation": {"kind": "markdown", "value": " Same as {!Array.mem}, but uses physical equality instead of structural\n equality to compare array elements.\n @since 4.03.0 "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "map2", "kind": 12, "tags": [], "detail": "(('a, 'b) => 'c, array<'a>, array<'b>) => array<'c>", - "documentation": {"kind": "markdown", "value": " [Array.map2 f a b] applies function [f] to all the elements of [a]\n and [b], and builds an array with the results returned by [f]:\n [[| f a.(0) b.(0); ...; f a.(Array.length a - 1) b.(Array.length b - 1)|]].\n Raise [Invalid_argument] if the arrays are not the same size.\n @since 4.03.0 "} + "documentation": {"kind": "markdown", "value": " [Array.map2 f a b] applies function [f] to all the elements of [a]\n and [b], and builds an array with the results returned by [f]:\n [[| f a.(0) b.(0); ...; f a.(Array.length a - 1) b.(Array.length b - 1)|]].\n Raise [Invalid_argument] if the arrays are not the same size.\n @since 4.03.0 "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "make", "kind": 12, "tags": [], "detail": "(int, 'a) => array<'a>", - "documentation": {"kind": "markdown", "value": " [Array.make n x] returns a fresh array of length [n],\n initialized with [x].\n All the elements of this new array are initially\n physically equal to [x] (in the sense of the [==] predicate).\n Consequently, if [x] is mutable, it is shared among all elements\n of the array, and modifying [x] through one of the array entries\n will modify all other entries at the same time.\n\n Raise [Invalid_argument] if [n < 0] or [n > Sys.max_array_length].\n If the value of [x] is a floating-point number, then the maximum\n size is only [Sys.max_array_length / 2]."} + "documentation": {"kind": "markdown", "value": " [Array.make n x] returns a fresh array of length [n],\n initialized with [x].\n All the elements of this new array are initially\n physically equal to [x] (in the sense of the [==] predicate).\n Consequently, if [x] is mutable, it is shared among all elements\n of the array, and modifying [x] through one of the array entries\n will modify all other entries at the same time.\n\n Raise [Invalid_argument] if [n < 0] or [n > Sys.max_array_length].\n If the value of [x] is a floating-point number, then the maximum\n size is only [Sys.max_array_length / 2]."}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "make_float", "kind": 12, "tags": [], "detail": "int => array", - "documentation": {"kind": "markdown", "value": " @deprecated [Array.make_float] is an alias for {!Array.create_float}. "} + "documentation": {"kind": "markdown", "value": " @deprecated [Array.make_float] is an alias for {!Array.create_float}. "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "map", "kind": 12, "tags": [], "detail": "('a => 'b, array<'a>) => array<'b>", - "documentation": {"kind": "markdown", "value": " [Array.map f a] applies function [f] to all the elements of [a],\n and builds an array with the results returned by [f]:\n [[| f a.(0); f a.(1); ...; f a.(Array.length a - 1) |]]. "} + "documentation": {"kind": "markdown", "value": " [Array.map f a] applies function [f] to all the elements of [a],\n and builds an array with the results returned by [f]:\n [[| f a.(0); f a.(1); ...; f a.(Array.length a - 1) |]]. "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "make_matrix", "kind": 12, "tags": [], "detail": "(int, int, 'a) => array>", - "documentation": {"kind": "markdown", "value": " [Array.make_matrix dimx dimy e] returns a two-dimensional array\n (an array of arrays) with first dimension [dimx] and\n second dimension [dimy]. All the elements of this new matrix\n are initially physically equal to [e].\n The element ([x,y]) of a matrix [m] is accessed\n with the notation [m.(x).(y)].\n\n Raise [Invalid_argument] if [dimx] or [dimy] is negative or\n greater than {!Sys.max_array_length}.\n If the value of [e] is a floating-point number, then the maximum\n size is only [Sys.max_array_length / 2]. "} + "documentation": {"kind": "markdown", "value": " [Array.make_matrix dimx dimy e] returns a two-dimensional array\n (an array of arrays) with first dimension [dimx] and\n second dimension [dimy]. All the elements of this new matrix\n are initially physically equal to [e].\n The element ([x,y]) of a matrix [m] is accessed\n with the notation [m.(x).(y)].\n\n Raise [Invalid_argument] if [dimx] or [dimy] is negative or\n greater than {!Sys.max_array_length}.\n If the value of [e] is a floating-point number, then the maximum\n size is only [Sys.max_array_length / 2]. "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "mem", "kind": 12, "tags": [], "detail": "('a, array<'a>) => bool", - "documentation": {"kind": "markdown", "value": " [mem a l] is true if and only if [a] is equal\n to an element of [l].\n @since 4.03.0 "} + "documentation": {"kind": "markdown", "value": " [mem a l] is true if and only if [a] is equal\n to an element of [l].\n @since 4.03.0 "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 15:17 @@ -355,7 +520,10 @@ Completable: Cpath Value[Dep, c] "kind": 12, "tags": [1], "detail": "int => int", - "documentation": {"kind": "markdown", "value": "Deprecated: Use customDouble instead\n\nSome doc comment"} + "documentation": {"kind": "markdown", "value": "Deprecated: Use customDouble instead\n\nSome doc comment"}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 23:20 @@ -368,13 +536,19 @@ Found type for function (~age: int, ~name: string) => string "kind": 4, "tags": [], "detail": "int", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "name", "kind": 4, "tags": [], "detail": "string", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 26:13 @@ -385,13 +559,19 @@ Completable: Cpath array->m "kind": 12, "tags": [], "detail": "(t<'a>, ('a, int) => 'b) => t<'b>", - "documentation": {"kind": "markdown", "value": "\nApplies the function (the second argument) to each item in the array, returning\na new array. The function acceps two arguments: an item from the array and its\nindex number. The result array does not have to have elements of the same type\nas the input array. See\n[`Array.map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)\non MDN.\n\n```res example\n// multiply each item in array by its position\nlet product = (item, index) => item * index\nJs.Array2.mapi([10, 11, 12], product) == [0, 11, 24]\n```\n"} + "documentation": {"kind": "markdown", "value": "\nApplies the function (the second argument) to each item in the array, returning\na new array. The function acceps two arguments: an item from the array and its\nindex number. The result array does not have to have elements of the same type\nas the input array. See\n[`Array.map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)\non MDN.\n\n```res example\n// multiply each item in array by its position\nlet product = (item, index) => item * index\nJs.Array2.mapi([10, 11, 12], product) == [0, 11, 24]\n```\n"}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "Js.Array2.map", "kind": 12, "tags": [], "detail": "(t<'a>, 'a => 'b) => t<'b>", - "documentation": {"kind": "markdown", "value": "\nApplies the function (the second argument) to each item in the array, returning\na new array. The result array does not have to have elements of the same type\nas the input array. See\n[`Array.map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)\non MDN.\n\n```res example\nJs.Array2.map([12, 4, 8], x => x * x) == [144, 16, 64]\nJs.Array2.map([\"animal\", \"vegetable\", \"mineral\"], Js.String.length) == [6, 9, 7]\n```\n"} + "documentation": {"kind": "markdown", "value": "\nApplies the function (the second argument) to each item in the array, returning\na new array. The result array does not have to have elements of the same type\nas the input array. See\n[`Array.map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)\non MDN.\n\n```res example\nJs.Array2.map([12, 4, 8], x => x * x) == [144, 16, 64]\nJs.Array2.map([\"animal\", \"vegetable\", \"mineral\"], Js.String.length) == [6, 9, 7]\n```\n"}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 29:13 @@ -402,7 +582,10 @@ Completable: Cpath string->toU "kind": 12, "tags": [], "detail": "t => t", - "documentation": {"kind": "markdown", "value": "\n`toUpperCase(str)` converts `str` to upper case using the locale-insensitive\ncase mappings in the Unicode Character Database. Notice that the conversion can\nexpand the number of letters in the result; for example the German ß\ncapitalizes to two Ses in a row.\n\nSee [`String.toUpperCase`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase)\non MDN.\n\n```res example\nJs.String2.toUpperCase(\"abc\") == \"ABC\"\nJs.String2.toUpperCase(`Straße`) == `STRASSE`\nJs.String2.toUpperCase(`πς`) == `ΠΣ`\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`toUpperCase(str)` converts `str` to upper case using the locale-insensitive\ncase mappings in the Unicode Character Database. Notice that the conversion can\nexpand the number of letters in the result; for example the German ß\ncapitalizes to two Ses in a row.\n\nSee [`String.toUpperCase`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase)\non MDN.\n\n```res example\nJs.String2.toUpperCase(\"abc\") == \"ABC\"\nJs.String2.toUpperCase(`Straße`) == `STRASSE`\nJs.String2.toUpperCase(`πς`) == `ΠΣ`\n```\n"}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 34:8 @@ -413,13 +596,19 @@ Completable: Cpath Value[op]->e "kind": 12, "tags": [], "detail": "(option<'a>, option<'b>, (. 'a, 'b) => bool) => bool", - "documentation": {"kind": "markdown", "value": "\n Uncurried version of `eq`\n"} + "documentation": {"kind": "markdown", "value": "\n Uncurried version of `eq`\n"}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "Belt.Option.eq", "kind": 12, "tags": [], "detail": "(option<'a>, option<'b>, ('a, 'b) => bool) => bool", - "documentation": {"kind": "markdown", "value": "\n Evaluates two optional values for equality with respect to a predicate\n function. If both `optValue1` and `optValue2` are `None`, returns `true`.\n If one of the arguments is `Some(value)` and the other is `None`, returns\n `false`.\n\n If arguments are `Some(value1)` and `Some(value2)`, returns the result of\n `predicate(value1, value2)`; the predicate function must return a bool.\n\n ```res example\n let clockEqual = (a, b) => mod(a, 12) == mod(b, 12)\n\n open Belt.Option\n\n eq(Some(3), Some(15), clockEqual) /* true */\n\n eq(Some(3), None, clockEqual) /* false */\n\n eq(None, Some(3), clockEqual) /* false */\n\n eq(None, None, clockEqual) /* true */\n ```\n"} + "documentation": {"kind": "markdown", "value": "\n Evaluates two optional values for equality with respect to a predicate\n function. If both `optValue1` and `optValue2` are `None`, returns `true`.\n If one of the arguments is `Some(value)` and the other is `None`, returns\n `false`.\n\n If arguments are `Some(value1)` and `Some(value2)`, returns the result of\n `predicate(value1, value2)`; the predicate function must return a bool.\n\n ```res example\n let clockEqual = (a, b) => mod(a, 12) == mod(b, 12)\n\n open Belt.Option\n\n eq(Some(3), Some(15), clockEqual) /* true */\n\n eq(Some(3), None, clockEqual) /* false */\n\n eq(None, Some(3), clockEqual) /* false */\n\n eq(None, None, clockEqual) /* true */\n ```\n"}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 44:7 @@ -432,13 +621,19 @@ Completable: Cpath Value[fa]-> "kind": 12, "tags": [], "detail": "(t, int) => t", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "ForAuto.abd", "kind": 12, "tags": [], "detail": "(t, int) => t", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 47:21 @@ -451,13 +646,19 @@ Completable: Cpath Value[Js, Dict, u] "kind": 12, "tags": [], "detail": "(t<'a>, key) => 'a", - "documentation": {"kind": "markdown", "value": "\n`Js.Dict.unsafeGet(key)` returns the value if the key exists, otherwise an `undefined` value is returned. Use this only when you are sure the key exists (i.e. when having used the `keys()` function to check that the key is valid).\n\n```res example\nJs.Dict.unsafeGet(ages, \"Fred\") == 49\nJs.Dict.unsafeGet(ages, \"Paul\") // returns undefined\n```\n"} + "documentation": {"kind": "markdown", "value": "\n`Js.Dict.unsafeGet(key)` returns the value if the key exists, otherwise an `undefined` value is returned. Use this only when you are sure the key exists (i.e. when having used the `keys()` function to check that the key is valid).\n\n```res example\nJs.Dict.unsafeGet(ages, \"Fred\") == 49\nJs.Dict.unsafeGet(ages, \"Paul\") // returns undefined\n```\n"}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "unsafeDeleteKey", "kind": 12, "tags": [], "detail": "(. t, string) => unit", - "documentation": {"kind": "markdown", "value": " Experimental internal function "} + "documentation": {"kind": "markdown", "value": " Experimental internal function "}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 59:30 @@ -471,7 +672,10 @@ Completable: Cpath Value[z] "kind": 12, "tags": [], "detail": "int", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 62:23 @@ -483,7 +687,10 @@ Completable: Cjsx([O, Comp], z, [z]) "kind": 4, "tags": [], "detail": "option", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 65:8 @@ -494,7 +701,10 @@ Completable: Cdecorator(reac) "kind": 4, "tags": [], "detail": "", - "documentation": {"kind": "markdown", "value": "The `@react.component` decorator is used to annotate functions that are RescriptReact components.\n\nYou will need this decorator whenever you want to use a ReScript / React component in ReScript JSX expressions.\n\nNote: The `@react.component` decorator requires the react-jsx config to be set in your `bsconfig.json` to enable the required React transformations.\n\n[Read more and see examples in the documentation](https://rescript-lang.org/syntax-lookup#react-component-decorator)."} + "documentation": {"kind": "markdown", "value": "The `@react.component` decorator is used to annotate functions that are RescriptReact components.\n\nYou will need this decorator whenever you want to use a ReScript / React component in ReScript JSX expressions.\n\nNote: The `@react.component` decorator requires the react-jsx config to be set in your `bsconfig.json` to enable the required React transformations.\n\n[Read more and see examples in the documentation](https://rescript-lang.org/syntax-lookup#react-component-decorator)."}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 68:10 @@ -507,7 +717,10 @@ Completable: Cdecorator(react.) "kind": 4, "tags": [], "detail": "", - "documentation": {"kind": "markdown", "value": "The `@react.component` decorator is used to annotate functions that are RescriptReact components.\n\nYou will need this decorator whenever you want to use a ReScript / React component in ReScript JSX expressions.\n\nNote: The `@react.component` decorator requires the react-jsx config to be set in your `bsconfig.json` to enable the required React transformations.\n\n[Read more and see examples in the documentation](https://rescript-lang.org/syntax-lookup#react-component-decorator)."} + "documentation": {"kind": "markdown", "value": "The `@react.component` decorator is used to annotate functions that are RescriptReact components.\n\nYou will need this decorator whenever you want to use a ReScript / React component in ReScript JSX expressions.\n\nNote: The `@react.component` decorator requires the react-jsx config to be set in your `bsconfig.json` to enable the required React transformations.\n\n[Read more and see examples in the documentation](https://rescript-lang.org/syntax-lookup#react-component-decorator)."}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 71:27 @@ -520,7 +733,10 @@ Found type for function (~age: int, ~name: string) => string "kind": 4, "tags": [], "detail": "int", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 74:26 @@ -533,7 +749,10 @@ Found type for function (~age: int, ~name: string) => string "kind": 4, "tags": [], "detail": "string", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 77:32 @@ -546,7 +765,10 @@ Found type for function (~age: int, ~name: string) => string "kind": 4, "tags": [], "detail": "string", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 82:5 @@ -565,7 +787,10 @@ Completable: Cpath Value[someObj]["a"] "kind": 4, "tags": [], "detail": "int", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 95:24 @@ -577,13 +802,19 @@ Completable: Cpath Value[nestedObj]["x"]["y"][""] "kind": 4, "tags": [], "detail": "int", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "name", "kind": 4, "tags": [], "detail": "string", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 99:7 @@ -595,7 +826,10 @@ Completable: Cpath Value[o]["a"] "kind": 4, "tags": [], "detail": "int", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 104:17 @@ -607,13 +841,19 @@ Completable: Cpath Value[no]["x"]["y"][""] "kind": 4, "tags": [], "detail": "string", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "age", "kind": 4, "tags": [], "detail": "int", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 110:5 @@ -625,13 +865,19 @@ Completable: Cpath Value[r]."" "kind": 5, "tags": [], "detail": "x: int\n\ntype r = {x: int, y: string}", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "y", "kind": 5, "tags": [], "detail": "y: string\n\ntype r = {x: int, y: string}", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 113:24 @@ -643,13 +889,19 @@ Completable: Cpath Value[Object, Rec, recordVal]."" "kind": 5, "tags": [], "detail": "xx: int\n\ntype recordt = {xx: int, ss: string}", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "ss", "kind": 5, "tags": [], "detail": "ss: string\n\ntype recordt = {xx: int, ss: string}", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 120:7 @@ -663,7 +915,10 @@ Completable: Cpath Value[my] "kind": 12, "tags": [], "detail": "(int, int) => int", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 125:18 @@ -675,13 +930,19 @@ Completable: Cpath Value[Object, object][""] "kind": 4, "tags": [], "detail": "string", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "age", "kind": 4, "tags": [], "detail": "int", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 151:6 @@ -693,7 +954,10 @@ Completable: Cpath Module[O, ""] "kind": 9, "tags": [], "detail": "module", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 157:8 @@ -705,13 +969,19 @@ Completable: Cpath Value[q].aa."" "kind": 5, "tags": [], "detail": "x: int\n\ntype aa = {x: int, name: string}", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "name", "kind": 5, "tags": [], "detail": "name: string\n\ntype aa = {x: int, name: string}", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 159:9 @@ -723,7 +993,10 @@ Completable: Cpath Value[q].aa.n "kind": 5, "tags": [], "detail": "name: string\n\ntype aa = {x: int, name: string}", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 162:6 @@ -735,13 +1008,19 @@ Completable: Cpath Value[Lis] "kind": 9, "tags": [], "detail": "file module", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "ListLabels", "kind": 9, "tags": [], "detail": "file module", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 169:16 @@ -753,7 +1032,10 @@ Completable: Cpath Module[WithChildren] "kind": 9, "tags": [], "detail": "module", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 172:16 @@ -765,19 +1047,28 @@ Completable: Cpath Type[Js, n] "kind": 22, "tags": [], "detail": "type null_undefined<'a> = nullable<'a>", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "nullable", "kind": 22, "tags": [], "detail": "type nullable<+'a>", - "documentation": {"kind": "markdown", "value": "\n A value of this type can be undefined, null or 'a. This type is equivalent to Js.Null_undefined.t.\n"} + "documentation": {"kind": "markdown", "value": "\n A value of this type can be undefined, null or 'a. This type is equivalent to Js.Null_undefined.t.\n"}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "null", "kind": 22, "tags": [], "detail": "type null<+'a>", - "documentation": {"kind": "markdown", "value": "\n Nullable value of this type can be either null or 'a. This type is equivalent to Js.Null.t.\n"} + "documentation": {"kind": "markdown", "value": "\n Nullable value of this type can be either null or 'a. This type is equivalent to Js.Null.t.\n"}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 174:20 @@ -789,20 +1080,17 @@ Completable: Cpath Type[ForAuto, ""] "kind": 22, "tags": [], "detail": "type t = int", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 179:13 posCursor:[179:13] posNoWhite:[179:12] Found expr:[179:11->179:13] Pexp_construct As:[179:11->179:13] None -Completable: Cpath Value[As] -[{ - "label": "Asterix", - "kind": 4, - "tags": [], - "detail": "Asterix\n\ntype z = Allo | Asterix | Baba", - "documentation": null - }] +Completable: CtypedExpression(sourceType:Value[q], lookingToComplete:CVariant, prefix:As, pattern: [] +[] Complete src/Completion.res 182:17 Pmod_ident For:[182:14->182:17] @@ -812,7 +1100,10 @@ Completable: Cpath Module[For] "kind": 9, "tags": [], "detail": "module", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 190:11 @@ -824,7 +1115,10 @@ Completable: Cpath Value[Private, ""] "kind": 12, "tags": [], "detail": "int", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 202:6 @@ -842,7 +1136,10 @@ Completable: Cpath Value[sha] "kind": 12, "tags": [], "detail": "int", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 208:6 @@ -854,7 +1151,10 @@ Completable: Cpath Value[sha] "kind": 12, "tags": [], "detail": "string", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 221:22 @@ -866,13 +1166,19 @@ Completable: Cpath Value[FAO, forAutoObject][""] "kind": 4, "tags": [], "detail": "int", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "forAutoLabel", "kind": 4, "tags": [], "detail": "FAR.forAutoRecord", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 224:37 @@ -884,13 +1190,19 @@ Completable: Cpath Value[FAO, forAutoObject]["forAutoLabel"]."" "kind": 5, "tags": [], "detail": "forAuto: ForAuto.t\n\ntype forAutoRecord = {\n forAuto: ForAuto.t,\n something: option,\n}", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "something", "kind": 5, "tags": [], "detail": "something: option\n\ntype forAutoRecord = {\n forAuto: ForAuto.t,\n something: option,\n}", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 227:46 @@ -901,13 +1213,19 @@ Completable: Cpath Value[FAO, forAutoObject]["forAutoLabel"].forAuto-> "kind": 12, "tags": [], "detail": "(t, int) => t", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "ForAuto.abd", "kind": 12, "tags": [], "detail": "(t, int) => t", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 230:55 @@ -920,13 +1238,19 @@ Completable: Cpath Value[ForAuto, a] "kind": 12, "tags": [], "detail": "(t, int) => t", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "abd", "kind": 12, "tags": [], "detail": "(t, int) => t", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 234:34 @@ -942,7 +1266,10 @@ Completable: Cpath Value[na] "kind": 12, "tags": [], "detail": "string", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 237:17 @@ -962,13 +1289,19 @@ Completable: Cpath Value[_z]."" "kind": 5, "tags": [], "detail": "x: int\n\ntype r = {x: int, y: string}", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "y", "kind": 5, "tags": [], "detail": "y: string\n\ntype r = {x: int, y: string}", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 254:17 @@ -980,7 +1313,10 @@ Completable: Cpath Value[SomeLo] "kind": 9, "tags": [], "detail": "module", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 256:29 @@ -992,7 +1328,10 @@ Completable: Cpath Type[SomeLocalModule, ""] "kind": 22, "tags": [], "detail": "type zz = int", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 261:33 @@ -1004,24 +1343,24 @@ Completable: Cpath Type[SomeLocalModule, ""] "kind": 22, "tags": [], "detail": "type zz = int", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 268:21 Ptype_variant unary SomeLocal:[268:12->268:21] Completable: Cpath Value[SomeLocal] [{ - "label": "SomeLocalVariantItem", - "kind": 4, - "tags": [], - "detail": "SomeLocalVariantItem\n\ntype someLocalVariant = SomeLocalVariantItem", - "documentation": null - }, { "label": "SomeLocalModule", "kind": 9, "tags": [], "detail": "module", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 271:20 @@ -1034,7 +1373,10 @@ Completable: Cpath Type[SomeLocal] "kind": 9, "tags": [], "detail": "module", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 275:15 @@ -1048,7 +1390,10 @@ Completable: Cpath Value[_w] "kind": 12, "tags": [], "detail": "'a", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 281:22 @@ -1060,13 +1405,19 @@ Completable: Cpath Type[s] "kind": 22, "tags": [], "detail": "type someType = {hello: string}", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "someLocalVariant", "kind": 22, "tags": [], "detail": "type someLocalVariant = SomeLocalVariantItem", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 291:30 @@ -1079,7 +1430,10 @@ Found type for function (~name: string) => unit "kind": 4, "tags": [], "detail": "string", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 296:11 @@ -1091,13 +1445,19 @@ Completable: Cpath Value[retAA](Nolabel)."" "kind": 5, "tags": [], "detail": "x: int\n\ntype aa = {x: int, name: string}", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "name", "kind": 5, "tags": [], "detail": "name: string\n\ntype aa = {x: int, name: string}", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 301:13 @@ -1117,25 +1477,37 @@ Found type for function ( "kind": 4, "tags": [], "detail": "option", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "a", "kind": 4, "tags": [], "detail": "int", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "b", "kind": 4, "tags": [], "detail": "int", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "opt2", "kind": 4, "tags": [], "detail": "option", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 304:15 @@ -1148,19 +1520,28 @@ Found type for function (~a: int, ~b: int, ~opt2: int=?, unit) => int "kind": 4, "tags": [], "detail": "int", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "b", "kind": 4, "tags": [], "detail": "int", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "opt2", "kind": 4, "tags": [], "detail": "option", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 307:17 @@ -1173,19 +1554,28 @@ Found type for function (~a: int, ~b: int, ~opt2: int=?, unit) => int "kind": 4, "tags": [], "detail": "int", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "b", "kind": 4, "tags": [], "detail": "int", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "opt2", "kind": 4, "tags": [], "detail": "option", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 310:21 @@ -1198,13 +1588,19 @@ Found type for function (~a: int, ~b: int) => int "kind": 4, "tags": [], "detail": "int", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "b", "kind": 4, "tags": [], "detail": "int", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 313:23 @@ -1217,13 +1613,19 @@ Found type for function (~a: int, ~opt2: int=?, unit) => int "kind": 4, "tags": [], "detail": "int", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "opt2", "kind": 4, "tags": [], "detail": "option", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 316:16 @@ -1236,25 +1638,37 @@ Found type for function (~opt1: int=?, ~a: int, ~b: int, unit, unit, ~c: int) => "kind": 4, "tags": [], "detail": "option", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "a", "kind": 4, "tags": [], "detail": "int", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "b", "kind": 4, "tags": [], "detail": "int", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "c", "kind": 4, "tags": [], "detail": "int", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 323:17 @@ -1267,13 +1681,19 @@ Found type for function (~b: int) => callback "kind": 4, "tags": [], "detail": "int", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "a", "kind": 4, "tags": [], "detail": "int", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 326:21 @@ -1286,7 +1706,10 @@ Found type for function (~b: int) => int "kind": 4, "tags": [], "detail": "int", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 329:21 @@ -1299,7 +1722,10 @@ Found type for function (~a: int) => int "kind": 4, "tags": [], "detail": "int", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 336:26 @@ -1318,13 +1744,19 @@ Completable: Cpath Type[Res] "kind": 9, "tags": [], "detail": "file module", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "RescriptReactRouter", "kind": 9, "tags": [], "detail": "file module", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 343:57 @@ -1338,7 +1770,10 @@ Completable: Cpath Value[this] "kind": 12, "tags": [], "detail": "\\\"Type Not Known\"", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Hover src/Completion.res 346:14 @@ -1384,32 +1819,8 @@ posCursor:[362:8] posNoWhite:[362:7] Found expr:[361:2->365:3] posCursor:[362:8] posNoWhite:[362:7] Found pattern:[362:7->364:5] posCursor:[362:8] posNoWhite:[362:7] Found pattern:[362:7->362:8] Ppat_construct T:[362:7->362:8] -Completable: Cpath Value[T] -[{ - "label": "That", - "kind": 4, - "tags": [], - "detail": "That\n\ntype v = This | That", - "documentation": null - }, { - "label": "This", - "kind": 4, - "tags": [], - "detail": "This\n\ntype v = This | That", - "documentation": null - }, { - "label": "TableclothMap", - "kind": 9, - "tags": [], - "detail": "file module", - "documentation": null - }, { - "label": "TypeDefinition", - "kind": 9, - "tags": [], - "detail": "file module", - "documentation": null - }] +Completable: CtypedPattern(sourceType:Value[x], lookingToComplete:CVariant, patternType:Switch, prefix:T, pattern: [], seenIdents: [T]) +[] Complete src/Completion.res 373:21 posCursor:[373:21] posNoWhite:[373:20] Found expr:[371:8->376:3] @@ -1417,14 +1828,8 @@ posCursor:[373:21] posNoWhite:[373:20] Found expr:[372:2->376:3] posCursor:[373:21] posNoWhite:[373:20] Found pattern:[373:7->375:5] posCursor:[373:21] posNoWhite:[373:20] Found pattern:[373:7->373:21] Ppat_construct AndThatOther.T:[373:7->373:21] -Completable: Cpath Value[AndThatOther, T] -[{ - "label": "ThatOther", - "kind": 4, - "tags": [], - "detail": "ThatOther\n\ntype v = And | ThatOther", - "documentation": null - }] +Completable: CtypedPattern(sourceType:Value[x], lookingToComplete:CVariant, patternType:Switch, prefix:AndThatOther, pattern: [], seenIdents: [AndThatOther]) +[] Complete src/Completion.res 378:24 posCursor:[378:24] posNoWhite:[378:23] Found expr:[378:12->378:26] @@ -1439,13 +1844,19 @@ Completable: Cpath Value[ForAuto, ""] "kind": 12, "tags": [], "detail": "(t, int) => t", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "abd", "kind": 12, "tags": [], "detail": "(t, int) => t", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 381:38 @@ -1461,13 +1872,19 @@ Completable: Cpath Value[FAO, forAutoObject][""] "kind": 4, "tags": [], "detail": "int", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "forAutoLabel", "kind": 4, "tags": [], "detail": "FAR.forAutoRecord", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 384:24 @@ -1483,13 +1900,19 @@ Completable: Cpath Value[funRecord]."" "kind": 5, "tags": [], "detail": "someFun: (~name: string) => unit\n\ntype funRecord = {\n someFun: (~name: string) => unit,\n stuff: string,\n}", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "stuff", "kind": 5, "tags": [], "detail": "stuff: string\n\ntype funRecord = {\n someFun: (~name: string) => unit,\n stuff: string,\n}", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 389:12 @@ -1503,13 +1926,19 @@ Completable: Cpath array->ma "kind": 12, "tags": [], "detail": "(t<'a>, ('a, int) => 'b) => t<'b>", - "documentation": {"kind": "markdown", "value": "\nApplies the function (the second argument) to each item in the array, returning\na new array. The function acceps two arguments: an item from the array and its\nindex number. The result array does not have to have elements of the same type\nas the input array. See\n[`Array.map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)\non MDN.\n\n```res example\n// multiply each item in array by its position\nlet product = (item, index) => item * index\nJs.Array2.mapi([10, 11, 12], product) == [0, 11, 24]\n```\n"} + "documentation": {"kind": "markdown", "value": "\nApplies the function (the second argument) to each item in the array, returning\na new array. The function acceps two arguments: an item from the array and its\nindex number. The result array does not have to have elements of the same type\nas the input array. See\n[`Array.map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)\non MDN.\n\n```res example\n// multiply each item in array by its position\nlet product = (item, index) => item * index\nJs.Array2.mapi([10, 11, 12], product) == [0, 11, 24]\n```\n"}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "Array2.map", "kind": 12, "tags": [], "detail": "(t<'a>, 'a => 'b) => t<'b>", - "documentation": {"kind": "markdown", "value": "\nApplies the function (the second argument) to each item in the array, returning\na new array. The result array does not have to have elements of the same type\nas the input array. See\n[`Array.map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)\non MDN.\n\n```res example\nJs.Array2.map([12, 4, 8], x => x * x) == [144, 16, 64]\nJs.Array2.map([\"animal\", \"vegetable\", \"mineral\"], Js.String.length) == [6, 9, 7]\n```\n"} + "documentation": {"kind": "markdown", "value": "\nApplies the function (the second argument) to each item in the array, returning\na new array. The result array does not have to have elements of the same type\nas the input array. See\n[`Array.map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)\non MDN.\n\n```res example\nJs.Array2.map([12, 4, 8], x => x * x) == [144, 16, 64]\nJs.Array2.map([\"animal\", \"vegetable\", \"mineral\"], Js.String.length) == [6, 9, 7]\n```\n"}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 397:14 @@ -1525,7 +1954,10 @@ Completable: Cpath Value[red] "kind": 12, "tags": [], "detail": "string", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 402:25 @@ -1541,7 +1973,10 @@ Completable: Cpath Value[red] "kind": 12, "tags": [], "detail": "string", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Completion.res 405:22 @@ -1557,18 +1992,27 @@ Completable: Cpath Value[r] "kind": 12, "tags": [], "detail": "string", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "retAA", "kind": 12, "tags": [], "detail": "unit => aa", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "r", "kind": 12, "tags": [], "detail": "rAlias", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] diff --git a/analysis/tests/src/expected/Dce.res.txt b/analysis/tests/src/expected/Dce.res.txt index 9e47ef48c..2d5dea86d 100644 --- a/analysis/tests/src/expected/Dce.res.txt +++ b/analysis/tests/src/expected/Dce.res.txt @@ -1,3 +1,3 @@ DCE src/Dce.res -issues:249 +issues:322 diff --git a/analysis/tests/src/expected/Debug.res.txt b/analysis/tests/src/expected/Debug.res.txt index a95597eae..492bb7311 100644 --- a/analysis/tests/src/expected/Debug.res.txt +++ b/analysis/tests/src/expected/Debug.res.txt @@ -4,8 +4,9 @@ Dependencies: @rescript/react Source directories: ./node_modules/@rescript/react/src ./node_modules/@rescript/react/src/legacy Source files: ./node_modules/@rescript/react/src/React.res ./node_modules/@rescript/react/src/ReactDOM.res ./node_modules/@rescript/react/src/ReactDOMServer.res ./node_modules/@rescript/react/src/ReactDOMStyle.res ./node_modules/@rescript/react/src/ReactEvent.res ./node_modules/@rescript/react/src/ReactEvent.resi ./node_modules/@rescript/react/src/ReactTestUtils.res ./node_modules/@rescript/react/src/ReactTestUtils.resi ./node_modules/@rescript/react/src/RescriptReactErrorBoundary.res ./node_modules/@rescript/react/src/RescriptReactErrorBoundary.resi ./node_modules/@rescript/react/src/RescriptReactRouter.res ./node_modules/@rescript/react/src/RescriptReactRouter.resi ./node_modules/@rescript/react/src/legacy/ReactDOMRe.res ./node_modules/@rescript/react/src/legacy/ReasonReact.res Source directories: ./src ./src/expected -Source files: ./src/Auto.res ./src/CodeLens.res ./src/CompletePrioritize1.res ./src/CompletePrioritize2.res ./src/Completion.res ./src/Component.res ./src/Component.resi ./src/CreateInterface.res ./src/Cross.res ./src/Dce.res ./src/Debug.res ./src/Definition.res ./src/DefinitionWithInterface.res ./src/DefinitionWithInterface.resi ./src/Div.res ./src/DocumentSymbol.res ./src/Fragment.res ./src/Highlight.res ./src/Hover.res ./src/InlayHint.res ./src/Jsx.res ./src/Jsx.resi ./src/LongIdentTest.res ./src/Object.res ./src/Patterns.res ./src/RecModules.res ./src/RecordCompletion.res ./src/RecoveryOnProp.res ./src/References.res ./src/ReferencesWithInterface.res ./src/ReferencesWithInterface.resi ./src/Rename.res ./src/RenameWithInterface.res ./src/RenameWithInterface.resi ./src/TableclothMap.ml ./src/TableclothMap.mli ./src/TypeDefinition.res ./src/Xform.res +Source files: ./src/Auto.res ./src/BrokenParserCases.res ./src/CodeLens.res ./src/CompletePrioritize1.res ./src/CompletePrioritize2.res ./src/Completion.res ./src/Component.res ./src/Component.resi ./src/CreateInterface.res ./src/Cross.res ./src/Dce.res ./src/Debug.res ./src/Definition.res ./src/DefinitionWithInterface.res ./src/DefinitionWithInterface.resi ./src/Div.res ./src/DocumentSymbol.res ./src/Fragment.res ./src/Highlight.res ./src/Hover.res ./src/InlayHint.res ./src/Jsx.res ./src/Jsx.resi ./src/LongIdentTest.res ./src/Object.res ./src/Patterns.res ./src/RecModules.res ./src/RecordCompletion.res ./src/RecoveryOnProp.res ./src/References.res ./src/ReferencesWithInterface.res ./src/ReferencesWithInterface.resi ./src/Rename.res ./src/RenameWithInterface.res ./src/RenameWithInterface.resi ./src/TableclothMap.ml ./src/TableclothMap.mli ./src/TypeContextCompletion_Jsx.res ./src/TypeContextCompletion_LabelledArguments.res ./src/TypeContextCompletion_Records.res ./src/TypeDefinition.res ./src/TypedContextCompletionSpec.res ./src/Xform.res Impl cmt:./lib/bs/src/Auto.cmt res:./src/Auto.res +Impl cmt:./lib/bs/src/BrokenParserCases.cmt res:./src/BrokenParserCases.res Impl cmt:./lib/bs/src/CodeLens.cmt res:./src/CodeLens.res Impl cmt:./lib/bs/src/CompletePrioritize1.cmt res:./src/CompletePrioritize1.res Impl cmt:./lib/bs/src/CompletePrioritize2.cmt res:./src/CompletePrioritize2.res @@ -35,7 +36,11 @@ IntfAndImpl cmti:./lib/bs/src/ReferencesWithInterface.cmti resi:./src/References Impl cmt:./lib/bs/src/Rename.cmt res:./src/Rename.res IntfAndImpl cmti:./lib/bs/src/RenameWithInterface.cmti resi:./src/RenameWithInterface.resi cmt:./lib/bs/src/RenameWithInterface.cmt res:./src/RenameWithInterface.res IntfAndImpl cmti:./lib/bs/src/TableclothMap.cmti resi:./src/TableclothMap.mli cmt:./lib/bs/src/TableclothMap.cmt res:./src/TableclothMap.ml +Impl cmt:./lib/bs/src/TypeContextCompletion_Jsx.cmt res:./src/TypeContextCompletion_Jsx.res +Impl cmt:./lib/bs/src/TypeContextCompletion_LabelledArguments.cmt res:./src/TypeContextCompletion_LabelledArguments.res +Impl cmt:./lib/bs/src/TypeContextCompletion_Records.cmt res:./src/TypeContextCompletion_Records.res Impl cmt:./lib/bs/src/TypeDefinition.cmt res:./src/TypeDefinition.res +Impl cmt:./lib/bs/src/TypedContextCompletionSpec.cmt res:./src/TypedContextCompletionSpec.res Impl cmt:./lib/bs/src/Xform.cmt res:./src/Xform.res Dependency dirs: ./node_modules/@rescript/react/lib/bs/src ./node_modules/@rescript/react/lib/bs/src/legacy Opens from bsconfig: @@ -84,13 +89,19 @@ findAllCompletions uri:js.ml "kind": 12, "tags": [], "detail": "('a, nullable<'a>) => bool", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "eqNull", "kind": 12, "tags": [], "detail": "('a, null<'a>) => bool", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] diff --git a/analysis/tests/src/expected/Div.res.txt b/analysis/tests/src/expected/Div.res.txt index aeb25d150..44e3b35a9 100644 --- a/analysis/tests/src/expected/Div.res.txt +++ b/analysis/tests/src/expected/Div.res.txt @@ -11,6 +11,9 @@ Completable: Cjsx([div], dangerous, [dangerous]) "kind": 4, "tags": [], "detail": "{\"__html\": string}", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] diff --git a/analysis/tests/src/expected/Jsx.res.txt b/analysis/tests/src/expected/Jsx.res.txt index 041c8d867..614e4a28c 100644 --- a/analysis/tests/src/expected/Jsx.res.txt +++ b/analysis/tests/src/expected/Jsx.res.txt @@ -20,13 +20,19 @@ Completable: Cjsx([M], f, [second, f]) "kind": 4, "tags": [], "detail": "string", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "fun", "kind": 4, "tags": [], "detail": "option", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Jsx.res 14:13 @@ -38,25 +44,37 @@ Completable: Cpath Module[M] "kind": 9, "tags": [], "detail": "module", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "Map", "kind": 9, "tags": [], "detail": "file module", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "MapLabels", "kind": 9, "tags": [], "detail": "file module", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "MoreLabels", "kind": 9, "tags": [], "detail": "file module", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Jsx.res 22:19 @@ -68,7 +86,10 @@ Completable: Cjsx([M], k, [prop, k]) "kind": 4, "tags": [], "detail": "string", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Jsx.res 25:17 @@ -80,7 +101,10 @@ Completable: Cjsx([M], k, [prop, k]) "kind": 4, "tags": [], "detail": "string", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Jsx.res 28:21 @@ -92,7 +116,10 @@ Completable: Cjsx([M], k, [prop, k]) "kind": 4, "tags": [], "detail": "string", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Jsx.res 31:24 @@ -104,7 +131,10 @@ Completable: Cjsx([M], k, [prop, k]) "kind": 4, "tags": [], "detail": "string", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Jsx.res 34:18 @@ -116,7 +146,10 @@ Completable: Cjsx([M], k, [prop, k]) "kind": 4, "tags": [], "detail": "string", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Jsx.res 37:16 @@ -128,7 +161,10 @@ Completable: Cjsx([M], k, [prop, k]) "kind": 4, "tags": [], "detail": "string", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Jsx.res 40:17 @@ -140,7 +176,10 @@ Completable: Cjsx([M], k, [prop, k]) "kind": 4, "tags": [], "detail": "string", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Jsx.res 43:18 @@ -152,7 +191,10 @@ Completable: Cjsx([M], k, [prop, k]) "kind": 4, "tags": [], "detail": "string", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Jsx.res 46:16 @@ -164,7 +206,10 @@ Completable: Cjsx([M], k, [prop, k]) "kind": 4, "tags": [], "detail": "string", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Jsx.res 49:27 @@ -176,7 +221,10 @@ Completable: Cjsx([M], k, [prop, k]) "kind": 4, "tags": [], "detail": "string", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Jsx.res 52:38 @@ -188,7 +236,10 @@ Completable: Cjsx([M], k, [prop, k]) "kind": 4, "tags": [], "detail": "string", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Jsx.res 55:25 @@ -200,7 +251,10 @@ Completable: Cjsx([M], k, [prop, k]) "kind": 4, "tags": [], "detail": "string", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Definition src/Jsx.res 58:11 @@ -217,7 +271,10 @@ Completable: Cjsx([Ext], al, [al]) "kind": 4, "tags": [], "detail": "option", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Jsx.res 71:11 @@ -235,7 +292,10 @@ Completable: Cjsx([M], k, [first, k]) "kind": 4, "tags": [], "detail": "string", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Jsx.res 77:23 @@ -247,7 +307,10 @@ Completable: Cjsx([M], k, [first, k]) "kind": 4, "tags": [], "detail": "string", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Jsx.res 80:6 @@ -270,7 +333,10 @@ Completable: Cpath Module[WithChildren] "kind": 9, "tags": [], "detail": "module", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Jsx.res 91:18 @@ -282,7 +348,10 @@ Completable: Cjsx([WithChildren], n, [n]) "kind": 4, "tags": [], "detail": "string", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Jsx.res 94:18 @@ -295,7 +364,10 @@ Completable: Cpath Type[React, e] "kind": 22, "tags": [], "detail": "type element", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Jsx.res 96:20 @@ -308,7 +380,10 @@ Completable: Cpath Type[ReactDOMR] "kind": 9, "tags": [], "detail": "file module", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Jsx.res 102:21 @@ -328,7 +403,10 @@ Completable: Cpath Value[DefineSomeFields, ""] "kind": 12, "tags": [], "detail": "int", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Jsx.res 108:36 @@ -342,13 +420,19 @@ Completable: Cpath Module[DefineSomeFields].th "kind": 5, "tags": [], "detail": "thisField: int\n\ntype r = {thisField: int, thatField: string}", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "thatField", "kind": 5, "tags": [], "detail": "thatField: string\n\ntype r = {thisField: int, thatField: string}", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Jsx.res 122:20 @@ -362,7 +446,10 @@ Completable: Cpath Value[Outer, Inner, h] "kind": 12, "tags": [], "detail": "int", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Jsx.res 129:19 @@ -376,7 +463,10 @@ Completable: Cpath Value[Outer, Inner, ""] "kind": 12, "tags": [], "detail": "int", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Jsx.res 136:7 @@ -393,7 +483,10 @@ Completable: Cpath Module[Nested, Co] "kind": 9, "tags": [], "detail": "module", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Jsx.res 153:19 @@ -405,7 +498,10 @@ Completable: Cpath Module[Nested, ""] "kind": 9, "tags": [], "detail": "module", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Hover src/Jsx.res 162:12 @@ -431,3 +527,45 @@ JSX 167:14] age[167:15->167:18]=...[167:19->167:21]> _children:16 Completable: Cjsx([Comp], age, [age]) {"contents": "```rescript\nint\n```"} +Complete src/Jsx.res 171:30 +posCursor:[171:30] posNoWhite:[171:28] Found expr:[171:12->171:33] +JSX 171:29] > _children:171:31 +Completable: Cjsx([Completion, O, Comp], "", []) +[{ + "label": "first", + "kind": 4, + "tags": [], + "detail": "option", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "second", + "kind": 4, + "tags": [], + "detail": "int", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "zoo", + "kind": 4, + "tags": [], + "detail": "option", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "key", + "kind": 4, + "tags": [], + "detail": "string", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + diff --git a/analysis/tests/src/expected/Jsx.resi.txt b/analysis/tests/src/expected/Jsx.resi.txt index b0b987154..b012794d4 100644 --- a/analysis/tests/src/expected/Jsx.resi.txt +++ b/analysis/tests/src/expected/Jsx.resi.txt @@ -15,7 +15,10 @@ Completable: Cpath Type[React, e] "kind": 22, "tags": [], "detail": "type element", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/Jsx.resi 10:18 @@ -27,6 +30,9 @@ Completable: Cpath Type[React, e] "kind": 22, "tags": [], "detail": "type element", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] diff --git a/analysis/tests/src/expected/RecordCompletion.res.txt b/analysis/tests/src/expected/RecordCompletion.res.txt index d5d0b47dc..567c549d0 100644 --- a/analysis/tests/src/expected/RecordCompletion.res.txt +++ b/analysis/tests/src/expected/RecordCompletion.res.txt @@ -6,13 +6,19 @@ Completable: Cpath Value[t].n->m "kind": 12, "tags": [], "detail": "(t<'a>, ('a, int) => 'b) => t<'b>", - "documentation": {"kind": "markdown", "value": "\nApplies the function (the second argument) to each item in the array, returning\na new array. The function acceps two arguments: an item from the array and its\nindex number. The result array does not have to have elements of the same type\nas the input array. See\n[`Array.map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)\non MDN.\n\n```res example\n// multiply each item in array by its position\nlet product = (item, index) => item * index\nJs.Array2.mapi([10, 11, 12], product) == [0, 11, 24]\n```\n"} + "documentation": {"kind": "markdown", "value": "\nApplies the function (the second argument) to each item in the array, returning\na new array. The function acceps two arguments: an item from the array and its\nindex number. The result array does not have to have elements of the same type\nas the input array. See\n[`Array.map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)\non MDN.\n\n```res example\n// multiply each item in array by its position\nlet product = (item, index) => item * index\nJs.Array2.mapi([10, 11, 12], product) == [0, 11, 24]\n```\n"}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "Js.Array2.map", "kind": 12, "tags": [], "detail": "(t<'a>, 'a => 'b) => t<'b>", - "documentation": {"kind": "markdown", "value": "\nApplies the function (the second argument) to each item in the array, returning\na new array. The result array does not have to have elements of the same type\nas the input array. See\n[`Array.map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)\non MDN.\n\n```res example\nJs.Array2.map([12, 4, 8], x => x * x) == [144, 16, 64]\nJs.Array2.map([\"animal\", \"vegetable\", \"mineral\"], Js.String.length) == [6, 9, 7]\n```\n"} + "documentation": {"kind": "markdown", "value": "\nApplies the function (the second argument) to each item in the array, returning\na new array. The result array does not have to have elements of the same type\nas the input array. See\n[`Array.map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)\non MDN.\n\n```res example\nJs.Array2.map([12, 4, 8], x => x * x) == [144, 16, 64]\nJs.Array2.map([\"animal\", \"vegetable\", \"mineral\"], Js.String.length) == [6, 9, 7]\n```\n"}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/RecordCompletion.res 11:13 @@ -23,13 +29,19 @@ Completable: Cpath Value[t2].n2.n->m "kind": 12, "tags": [], "detail": "(t<'a>, ('a, int) => 'b) => t<'b>", - "documentation": {"kind": "markdown", "value": "\nApplies the function (the second argument) to each item in the array, returning\na new array. The function acceps two arguments: an item from the array and its\nindex number. The result array does not have to have elements of the same type\nas the input array. See\n[`Array.map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)\non MDN.\n\n```res example\n// multiply each item in array by its position\nlet product = (item, index) => item * index\nJs.Array2.mapi([10, 11, 12], product) == [0, 11, 24]\n```\n"} + "documentation": {"kind": "markdown", "value": "\nApplies the function (the second argument) to each item in the array, returning\na new array. The function acceps two arguments: an item from the array and its\nindex number. The result array does not have to have elements of the same type\nas the input array. See\n[`Array.map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)\non MDN.\n\n```res example\n// multiply each item in array by its position\nlet product = (item, index) => item * index\nJs.Array2.mapi([10, 11, 12], product) == [0, 11, 24]\n```\n"}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "Js.Array2.map", "kind": 12, "tags": [], "detail": "(t<'a>, 'a => 'b) => t<'b>", - "documentation": {"kind": "markdown", "value": "\nApplies the function (the second argument) to each item in the array, returning\na new array. The result array does not have to have elements of the same type\nas the input array. See\n[`Array.map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)\non MDN.\n\n```res example\nJs.Array2.map([12, 4, 8], x => x * x) == [144, 16, 64]\nJs.Array2.map([\"animal\", \"vegetable\", \"mineral\"], Js.String.length) == [6, 9, 7]\n```\n"} + "documentation": {"kind": "markdown", "value": "\nApplies the function (the second argument) to each item in the array, returning\na new array. The result array does not have to have elements of the same type\nas the input array. See\n[`Array.map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)\non MDN.\n\n```res example\nJs.Array2.map([12, 4, 8], x => x * x) == [144, 16, 64]\nJs.Array2.map([\"animal\", \"vegetable\", \"mineral\"], Js.String.length) == [6, 9, 7]\n```\n"}, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/RecordCompletion.res 19:7 @@ -41,7 +53,10 @@ Completable: Cpath Module[R]."" "kind": 5, "tags": [], "detail": "name: string\n\ntype t = {name: string}", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] Complete src/RecordCompletion.res 22:7 @@ -53,6 +68,9 @@ Completable: Cpath Module[R]."" "kind": 5, "tags": [], "detail": "name: string\n\ntype t = {name: string}", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] diff --git a/analysis/tests/src/expected/RecoveryOnProp.res.txt b/analysis/tests/src/expected/RecoveryOnProp.res.txt index fe509d768..90005826d 100644 --- a/analysis/tests/src/expected/RecoveryOnProp.res.txt +++ b/analysis/tests/src/expected/RecoveryOnProp.res.txt @@ -13,12 +13,18 @@ Completable: Cpath Type[Res] "kind": 9, "tags": [], "detail": "file module", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }, { "label": "RescriptReactRouter", "kind": 9, "tags": [], "detail": "file module", - "documentation": null + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null }] diff --git a/analysis/tests/src/expected/TypeContextCompletion.res.txt b/analysis/tests/src/expected/TypeContextCompletion.res.txt new file mode 100644 index 000000000..3c5b665ef --- /dev/null +++ b/analysis/tests/src/expected/TypeContextCompletion.res.txt @@ -0,0 +1,194 @@ +Complete src/TypeContextCompletion.res 18:41 +posCursor:[18:41] posNoWhite:[18:40] Found expr:[18:11->18:41] +Pexp_apply ...[18:11->18:30] (~someVaria18:32->18:41=...[18:32->18:41]) +Completable: CnamedArg(Value[someVariantToString], someVaria, [someVaria]) +Found type for function (~someVariant: someVariant) => string +[{ + "label": "someVariant", + "kind": 4, + "tags": [], + "detail": "someVariant", + "documentation": null + }] + +Complete src/TypeContextCompletion.res 21:44 +posCursor:[21:44] posNoWhite:[21:43] Found expr:[21:11->21:44] +Pexp_apply ...[21:11->21:30] (~someVariant21:32->21:43=...__ghost__[0:-1->0:-1]) +found typed context +Completable: CtypedContext(Value[someVariantToString], NamedArg(someVariant)) +Found variant type for NamedArg typed context someVariant +[{ + "label": "One", + "kind": 4, + "tags": [], + "detail": "One\n\n", + "documentation": null + }, { + "label": "Two", + "kind": 4, + "tags": [], + "detail": "Two\n\n", + "documentation": null + }, { + "label": "Three", + "kind": 4, + "tags": [], + "detail": "Three\n\n", + "documentation": null + }, { + "label": "Four", + "kind": 4, + "tags": [], + "detail": "Four\n\n", + "documentation": null + }, { + "label": "Five(_)", + "kind": 4, + "tags": [], + "detail": "Five(int)\n\n", + "documentation": null + }, { + "label": "Six(_)", + "kind": 4, + "tags": [], + "detail": "Six(option)\n\n", + "documentation": null + }] + +Complete src/TypeContextCompletion.res 24:45 +posCursor:[24:45] posNoWhite:[24:43] Found expr:[24:11->24:44] +Pexp_apply ...[24:11->24:30] (~someVariant24:32->24:43=...__ghost__[0:-1->0:-1]) +found typed context +Completable: CtypedContext(Value[someVariantToString], NamedArg(someVariant)) +Found variant type for NamedArg typed context someVariant +[{ + "label": "One", + "kind": 4, + "tags": [], + "detail": "One\n\n", + "documentation": null + }, { + "label": "Two", + "kind": 4, + "tags": [], + "detail": "Two\n\n", + "documentation": null + }, { + "label": "Three", + "kind": 4, + "tags": [], + "detail": "Three\n\n", + "documentation": null + }, { + "label": "Four", + "kind": 4, + "tags": [], + "detail": "Four\n\n", + "documentation": null + }, { + "label": "Five(_)", + "kind": 4, + "tags": [], + "detail": "Five(int)\n\n", + "documentation": null + }, { + "label": "Six(_)", + "kind": 4, + "tags": [], + "detail": "Six(option)\n\n", + "documentation": null + }] + +Complete src/TypeContextCompletion.res 27:45 +posCursor:[27:45] posNoWhite:[27:44] Found expr:[27:11->27:45] +Pexp_apply ...[27:11->27:30] (~someVariant27:32->27:43=...[27:44->27:45]) +found typed context +Completable: CtypedContext(Value[someVariantToString], NamedArg(someVariant)) +Found variant type for NamedArg typed context someVariant +[{ + "label": "One", + "kind": 4, + "tags": [], + "detail": "One\n\n", + "documentation": null + }, { + "label": "Two", + "kind": 4, + "tags": [], + "detail": "Two\n\n", + "documentation": null + }, { + "label": "Three", + "kind": 4, + "tags": [], + "detail": "Three\n\n", + "documentation": null + }, { + "label": "Four", + "kind": 4, + "tags": [], + "detail": "Four\n\n", + "documentation": null + }, { + "label": "Five(_)", + "kind": 4, + "tags": [], + "detail": "Five(int)\n\n", + "documentation": null + }, { + "label": "Six(_)", + "kind": 4, + "tags": [], + "detail": "Six(option)\n\n", + "documentation": null + }] + +Complete src/TypeContextCompletion.res 30:45 +posCursor:[30:45] posNoWhite:[30:44] Found expr:[30:11->30:45] +Pexp_apply ...[30:11->30:30] (~someVariant30:32->30:43=...[30:44->30:45]) +found typed context +Completable: CtypedContext(Value[someVariantToString], NamedArg(someVariant)) +Found variant type for NamedArg typed context someVariant +[{ + "label": "One", + "kind": 4, + "tags": [], + "detail": "One\n\n", + "documentation": null + }, { + "label": "Two", + "kind": 4, + "tags": [], + "detail": "Two\n\n", + "documentation": null + }, { + "label": "Three", + "kind": 4, + "tags": [], + "detail": "Three\n\n", + "documentation": null + }, { + "label": "Four", + "kind": 4, + "tags": [], + "detail": "Four\n\n", + "documentation": null + }, { + "label": "Five(_)", + "kind": 4, + "tags": [], + "detail": "Five(int)\n\n", + "documentation": null + }, { + "label": "Six(_)", + "kind": 4, + "tags": [], + "detail": "Six(option)\n\n", + "documentation": null + }] + +Complete src/TypeContextCompletion.res 33:37 +posCursor:[33:37] posNoWhite:[33:36] Found expr:[33:14->33:37] +JSX 33:27] whatever[33:28->33:36]=...__ghost__[0:-1->0:-1]> _children:None +[] + diff --git a/analysis/tests/src/expected/TypeContextCompletion_Jsx.res.txt b/analysis/tests/src/expected/TypeContextCompletion_Jsx.res.txt new file mode 100644 index 000000000..f4cb773bb --- /dev/null +++ b/analysis/tests/src/expected/TypeContextCompletion_Jsx.res.txt @@ -0,0 +1,122 @@ +Complete src/TypeContextCompletion_Jsx.res 20:35 +posCursor:[20:35] posNoWhite:[20:34] Found expr:[20:12->20:35] +JSX 20:25] someVaria[20:26->20:35]=...[20:26->20:35]> _children:None +Completable: Cjsx([SomeComponent], someVaria, [someVaria]) +[{ + "label": "someVariant", + "kind": 4, + "tags": [], + "detail": "someVariant", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypeContextCompletion_Jsx.res 23:38 +posCursor:[23:38] posNoWhite:[23:37] Found expr:[23:12->23:38] +JSX 23:25] someVariant[23:26->23:37]=...__ghost__[0:-1->0:-1]> _children:None +[] + +Complete src/TypeContextCompletion_Jsx.res 26:39 +posCursor:[26:39] posNoWhite:[26:37] Found expr:[26:12->26:38] +JSX 26:25] someVariant[26:26->26:37]=...__ghost__[0:-1->0:-1]> _children:None +[] + +Complete src/TypeContextCompletion_Jsx.res 29:39 +posCursor:[29:39] posNoWhite:[29:38] Found expr:[29:12->29:39] +JSX 29:25] someVariant[29:26->29:37]=...[29:38->29:39]> _children:None +posCursor:[29:39] posNoWhite:[29:38] Found expr:[29:38->29:39] +Pexp_construct T:[29:38->29:39] None +Completable: Cpath Value[T] +[{ + "label": "TableclothMap", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "TypeContextCompletion_Jsx", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "TypeContextCompletion_LabelledArguments", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "TypeContextCompletion_Records", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "TypeDefinition", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "TypedContextCompletionSpec", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypeContextCompletion_Jsx.res 32:39 +posCursor:[32:39] posNoWhite:[32:38] Found expr:[32:12->32:39] +JSX 32:25] someVariant[32:26->32:37]=...[32:38->32:39]> _children:None +posCursor:[32:39] posNoWhite:[32:38] Found expr:[32:38->32:39] +Pexp_ident t:[32:38->32:39] +Completable: Cpath Value[t] +[] + +Complete src/TypeContextCompletion_Jsx.res 35:39 +posCursor:[35:39] posNoWhite:[35:38] Found expr:[35:12->35:39] +JSX 35:25] anotherThing[35:26->35:38]=...__ghost__[0:-1->0:-1]> _children:None +[] + +Complete src/TypeContextCompletion_Jsx.res 38:37 +posCursor:[38:37] posNoWhite:[38:36] Found expr:[38:12->38:37] +JSX 38:25] thirdThing[38:26->38:36]=...__ghost__[0:-1->0:-1]> _children:None +[] + +Complete src/TypeContextCompletion_Jsx.res 41:38 +posCursor:[41:38] posNoWhite:[41:36] Found expr:[41:12->41:37] +JSX 41:25] thirdThing[41:26->41:36]=...__ghost__[0:-1->0:-1]> _children:None +[] + +Complete src/TypeContextCompletion_Jsx.res 44:39 +posCursor:[44:39] posNoWhite:[44:38] Found expr:[44:12->44:39] +JSX 44:25] thirdThing[44:26->44:36]=...[44:37->44:39]> _children:None +posCursor:[44:39] posNoWhite:[44:38] Found expr:[44:37->44:39] +[] + +Complete src/TypeContextCompletion_Jsx.res 47:39 +posCursor:[47:39] posNoWhite:[47:38] Found expr:[47:12->47:39] +JSX 47:25] thirdThing[47:26->47:36]=...[47:37->47:39]> _children:None +posCursor:[47:39] posNoWhite:[47:38] Found expr:[47:37->47:39] +[] + diff --git a/analysis/tests/src/expected/TypeContextCompletion_LabelledArguments.res.txt b/analysis/tests/src/expected/TypeContextCompletion_LabelledArguments.res.txt new file mode 100644 index 000000000..379129b68 --- /dev/null +++ b/analysis/tests/src/expected/TypeContextCompletion_LabelledArguments.res.txt @@ -0,0 +1,482 @@ +Complete src/TypeContextCompletion_LabelledArguments.res 22:41 +posCursor:[22:41] posNoWhite:[22:40] Found expr:[22:11->22:41] +Pexp_apply ...[22:11->22:30] (~someVaria22:32->22:41=...[22:32->22:41]) +Completable: CnamedArg(Value[someVariantToString], someVaria, [someVaria]) +Found type for function ( + ~someVariant: someVariant, + ~anotherThing: TypeDefinition.variant, + ~thirdThing: otherVariant, +) => string +[{ + "label": "someVariant", + "kind": 4, + "tags": [], + "detail": "someVariant", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypeContextCompletion_LabelledArguments.res 25:44 +posCursor:[25:44] posNoWhite:[25:43] Found expr:[25:11->25:44] +Pexp_apply ...[25:11->25:30] (~someVariant25:32->25:43=...__ghost__[0:-1->0:-1]) +Completable: CtypedExpression(sourceType:NamedArg(someVariant, Value[someVariantToString]), lookingToComplete:CNoContext, prefix:"", pattern: [] +[{ + "label": "One", + "kind": 4, + "tags": [], + "detail": "One\n\n", + "documentation": null, + "sortText": null, + "insertText": "One", + "insertTextFormat": 2 + }, { + "label": "Two", + "kind": 4, + "tags": [], + "detail": "Two\n\n", + "documentation": null, + "sortText": null, + "insertText": "Two", + "insertTextFormat": 2 + }, { + "label": "Three", + "kind": 4, + "tags": [], + "detail": "Three\n\n", + "documentation": null, + "sortText": null, + "insertText": "Three", + "insertTextFormat": 2 + }, { + "label": "Four", + "kind": 4, + "tags": [], + "detail": "Four\n\n", + "documentation": null, + "sortText": null, + "insertText": "Four", + "insertTextFormat": 2 + }, { + "label": "Five(_)", + "kind": 4, + "tags": [], + "detail": "Five(int)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Five($1)", + "insertTextFormat": 2 + }, { + "label": "Six(_)", + "kind": 4, + "tags": [], + "detail": "Six(option, int)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Six($1)", + "insertTextFormat": 2 + }] + +Complete src/TypeContextCompletion_LabelledArguments.res 28:45 +posCursor:[28:45] posNoWhite:[28:43] Found expr:[28:11->28:44] +Pexp_apply ...[28:11->28:30] (~someVariant28:32->28:43=...__ghost__[0:-1->0:-1]) +Completable: CtypedExpression(sourceType:NamedArg(someVariant, Value[someVariantToString]), lookingToComplete:CNoContext, prefix:"", pattern: [] +[{ + "label": "One", + "kind": 4, + "tags": [], + "detail": "One\n\n", + "documentation": null, + "sortText": null, + "insertText": "One", + "insertTextFormat": 2 + }, { + "label": "Two", + "kind": 4, + "tags": [], + "detail": "Two\n\n", + "documentation": null, + "sortText": null, + "insertText": "Two", + "insertTextFormat": 2 + }, { + "label": "Three", + "kind": 4, + "tags": [], + "detail": "Three\n\n", + "documentation": null, + "sortText": null, + "insertText": "Three", + "insertTextFormat": 2 + }, { + "label": "Four", + "kind": 4, + "tags": [], + "detail": "Four\n\n", + "documentation": null, + "sortText": null, + "insertText": "Four", + "insertTextFormat": 2 + }, { + "label": "Five(_)", + "kind": 4, + "tags": [], + "detail": "Five(int)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Five($1)", + "insertTextFormat": 2 + }, { + "label": "Six(_)", + "kind": 4, + "tags": [], + "detail": "Six(option, int)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Six($1)", + "insertTextFormat": 2 + }] + +Complete src/TypeContextCompletion_LabelledArguments.res 31:45 +posCursor:[31:45] posNoWhite:[31:44] Found expr:[31:11->31:45] +Pexp_apply ...[31:11->31:30] (~someVariant31:32->31:43=...[31:44->31:45]) +Completable: CtypedExpression(sourceType:NamedArg(someVariant, Value[someVariantToString]), lookingToComplete:CVariant, prefix:T, pattern: [] +[{ + "label": "Two", + "kind": 4, + "tags": [], + "detail": "Two\n\n", + "documentation": null, + "sortText": null, + "insertText": "Two", + "insertTextFormat": 2 + }, { + "label": "Three", + "kind": 4, + "tags": [], + "detail": "Three\n\n", + "documentation": null, + "sortText": null, + "insertText": "Three", + "insertTextFormat": 2 + }] + +Complete src/TypeContextCompletion_LabelledArguments.res 34:45 +posCursor:[34:45] posNoWhite:[34:44] Found expr:[34:11->34:45] +Pexp_apply ...[34:11->34:30] (~someVariant34:32->34:43=...[34:44->34:45]) +posCursor:[34:45] posNoWhite:[34:44] Found expr:[34:44->34:45] +Pexp_ident t:[34:44->34:45] +Completable: Cpath Value[t] +[{ + "label": "thisIsAValue", + "kind": 12, + "tags": [], + "detail": "someVariant", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypeContextCompletion_LabelledArguments.res 37:59 +posCursor:[37:59] posNoWhite:[37:58] Found expr:[37:11->37:59] +Pexp_apply ...[37:11->37:30] (~someVariant37:32->37:43=...[37:44->37:59]) +posCursor:[37:59] posNoWhite:[37:58] Found expr:[37:44->37:59] +Pexp_ident TypeDefinition.:[37:44->37:59] +Completable: Cpath Value[TypeDefinition, ""] +[{ + "label": "g", + "kind": 12, + "tags": [], + "detail": "variant => string", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "x", + "kind": 12, + "tags": [], + "detail": "variant", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "y", + "kind": 12, + "tags": [], + "detail": "record", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "obj", + "kind": 12, + "tags": [], + "detail": "obj", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "f", + "kind": 12, + "tags": [], + "detail": "record => string", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Foo", + "kind": 4, + "tags": [], + "detail": "Foo\n\ntype variant = Foo | Bar", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Bar", + "kind": 4, + "tags": [], + "detail": "Bar\n\ntype variant = Foo | Bar", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypeContextCompletion_LabelledArguments.res 40:45 +posCursor:[40:45] posNoWhite:[40:44] Found expr:[40:11->40:45] +Pexp_apply ...[40:11->40:30] (~anotherThing40:32->40:44=...__ghost__[0:-1->0:-1]) +Completable: CtypedExpression(sourceType:NamedArg(anotherThing, Value[someVariantToString]), lookingToComplete:CNoContext, prefix:"", pattern: [] +[{ + "label": "Foo", + "kind": 4, + "tags": [], + "detail": "Foo\n\n", + "documentation": null, + "sortText": null, + "insertText": "Foo", + "insertTextFormat": 2 + }, { + "label": "Bar", + "kind": 4, + "tags": [], + "detail": "Bar\n\n", + "documentation": null, + "sortText": null, + "insertText": "Bar", + "insertTextFormat": 2 + }] + +Complete src/TypeContextCompletion_LabelledArguments.res 43:43 +posCursor:[43:43] posNoWhite:[43:42] Found expr:[43:11->43:43] +Pexp_apply ...[43:11->43:30] (~thirdThing43:32->43:42=...__ghost__[0:-1->0:-1]) +Completable: CtypedExpression(sourceType:NamedArg(thirdThing, Value[someVariantToString]), lookingToComplete:CNoContext, prefix:"", pattern: [] +[{ + "label": "#one", + "kind": 4, + "tags": [], + "detail": "#one", + "documentation": null, + "sortText": null, + "insertText": "#one", + "insertTextFormat": 2 + }, { + "label": "#six(_)", + "kind": 4, + "tags": [], + "detail": "#six(option, int)", + "documentation": null, + "sortText": null, + "insertText": "#six($1)", + "insertTextFormat": 2 + }, { + "label": "#three", + "kind": 4, + "tags": [], + "detail": "#three", + "documentation": null, + "sortText": null, + "insertText": "#three", + "insertTextFormat": 2 + }, { + "label": "#two", + "kind": 4, + "tags": [], + "detail": "#two", + "documentation": null, + "sortText": null, + "insertText": "#two", + "insertTextFormat": 2 + }, { + "label": "#five(_)", + "kind": 4, + "tags": [], + "detail": "#five(int)", + "documentation": null, + "sortText": null, + "insertText": "#five($1)", + "insertTextFormat": 2 + }, { + "label": "#four", + "kind": 4, + "tags": [], + "detail": "#four", + "documentation": null, + "sortText": null, + "insertText": "#four", + "insertTextFormat": 2 + }] + +Complete src/TypeContextCompletion_LabelledArguments.res 46:44 +posCursor:[46:44] posNoWhite:[46:42] Found expr:[46:11->46:43] +Pexp_apply ...[46:11->46:30] (~thirdThing46:32->46:42=...__ghost__[0:-1->0:-1]) +Completable: CtypedExpression(sourceType:NamedArg(thirdThing, Value[someVariantToString]), lookingToComplete:CNoContext, prefix:"", pattern: [] +[{ + "label": "#one", + "kind": 4, + "tags": [], + "detail": "#one", + "documentation": null, + "sortText": null, + "insertText": "#one", + "insertTextFormat": 2 + }, { + "label": "#six(_)", + "kind": 4, + "tags": [], + "detail": "#six(option, int)", + "documentation": null, + "sortText": null, + "insertText": "#six($1)", + "insertTextFormat": 2 + }, { + "label": "#three", + "kind": 4, + "tags": [], + "detail": "#three", + "documentation": null, + "sortText": null, + "insertText": "#three", + "insertTextFormat": 2 + }, { + "label": "#two", + "kind": 4, + "tags": [], + "detail": "#two", + "documentation": null, + "sortText": null, + "insertText": "#two", + "insertTextFormat": 2 + }, { + "label": "#five(_)", + "kind": 4, + "tags": [], + "detail": "#five(int)", + "documentation": null, + "sortText": null, + "insertText": "#five($1)", + "insertTextFormat": 2 + }, { + "label": "#four", + "kind": 4, + "tags": [], + "detail": "#four", + "documentation": null, + "sortText": null, + "insertText": "#four", + "insertTextFormat": 2 + }] + +Complete src/TypeContextCompletion_LabelledArguments.res 49:45 +posCursor:[49:45] posNoWhite:[49:44] Found expr:[49:11->49:45] +Pexp_apply ...[49:11->49:30] (~thirdThing49:32->49:42=...[49:43->49:45]) +Completable: CtypedExpression(sourceType:NamedArg(thirdThing, Value[someVariantToString]), lookingToComplete:CPolyvariant, prefix:t, pattern: [] +[{ + "label": "#three", + "kind": 4, + "tags": [], + "detail": "#three", + "documentation": null, + "sortText": null, + "insertText": "#three", + "insertTextFormat": 2 + }, { + "label": "#two", + "kind": 4, + "tags": [], + "detail": "#two", + "documentation": null, + "sortText": null, + "insertText": "#two", + "insertTextFormat": 2 + }] + +Complete src/TypeContextCompletion_LabelledArguments.res 52:45 +posCursor:[52:45] posNoWhite:[52:44] Found expr:[52:11->52:45] +Pexp_apply ...[52:11->52:30] (~thirdThing52:32->52:42=...[52:43->52:45]) +Completable: CtypedExpression(sourceType:NamedArg(thirdThing, Value[someVariantToString]), lookingToComplete:CPolyvariant, prefix:T, pattern: [] +[] + +Complete src/TypeContextCompletion_LabelledArguments.res 75:36 +posCursor:[75:36] posNoWhite:[75:35] Found expr:[75:11->75:47] +Pexp_apply ...[75:11->75:18] (~doThing75:20->75:27=...[75:28->75:46]) +posCursor:[75:36] posNoWhite:[75:35] Found expr:[75:28->75:46] +posCursor:[75:36] posNoWhite:[75:35] Found pattern:[75:29->75:37] +posCursor:[75:36] posNoWhite:[75:35] Found pattern:[75:35->75:36] +[] + +Complete src/TypeContextCompletion_LabelledArguments.res 80:46 +posCursor:[80:46] posNoWhite:[80:45] Found expr:[80:3->80:49] +Pexp_apply ...[80:3->80:14] (~someRecord80:16->80:26=...[80:27->80:48]) +Completable: CtypedExpression(sourceType:NamedArg(someRecord, Value[doMoreStuff]), lookingToComplete:CVariant, prefix:O, pattern: [RecordField:someTup, Tuple:1] +[{ + "label": "One", + "kind": 4, + "tags": [], + "detail": "One\n\n", + "documentation": null, + "sortText": null, + "insertText": "One", + "insertTextFormat": 2 + }] + +Complete src/TypeContextCompletion_LabelledArguments.res 83:60 +posCursor:[83:60] posNoWhite:[83:58] Found expr:[83:12->83:62] +Pexp_apply ...[83:12->83:23] (~someRecord83:25->83:35=...[83:36->83:61]) +Completable: CtypedExpression(sourceType:NamedArg(someRecord, Value[doMoreStuff]), lookingToComplete:CRecordField, prefix:"", pattern: [], seenIdents: [age, name]) +[{ + "label": "maybeVariant", + "kind": 5, + "tags": [], + "detail": "maybeVariant: option\n\ntype someRecord = {\n age: int,\n name: string,\n maybeVariant: option,\n definitivelyVariant: someVariant,\n someTup: (string, someVariant),\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "definitivelyVariant", + "kind": 5, + "tags": [], + "detail": "definitivelyVariant: someVariant\n\ntype someRecord = {\n age: int,\n name: string,\n maybeVariant: option,\n definitivelyVariant: someVariant,\n someTup: (string, someVariant),\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "someTup", + "kind": 5, + "tags": [], + "detail": "someTup: (string, someVariant)\n\ntype someRecord = {\n age: int,\n name: string,\n maybeVariant: option,\n definitivelyVariant: someVariant,\n someTup: (string, someVariant),\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + diff --git a/analysis/tests/src/expected/TypeContextCompletion_Records.res.txt b/analysis/tests/src/expected/TypeContextCompletion_Records.res.txt new file mode 100644 index 000000000..77142a785 --- /dev/null +++ b/analysis/tests/src/expected/TypeContextCompletion_Records.res.txt @@ -0,0 +1,811 @@ +Complete src/TypeContextCompletion_Records.res 16:15 +posCursor:[16:15] posNoWhite:[16:14] Found pattern:[16:7->16:16] +posCursor:[16:15] posNoWhite:[16:14] Found pattern:[16:8->16:15] +Completable: CtypedPattern(sourceType:Value[someVal], lookingToComplete:CRecordField, patternType:Destructure, prefix:another, pattern: [], seenIdents: [another]) +[{ + "label": "anotherThing", + "kind": 5, + "tags": [], + "detail": "anotherThing: option\n\ntype anotherRecord = {\n something: someRecord,\n anotherThing: option,\n thirdThing: string,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypeContextCompletion_Records.res 19:23 +posCursor:[19:23] posNoWhite:[19:22] Found pattern:[19:7->19:24] +posCursor:[19:23] posNoWhite:[19:22] Found pattern:[19:22->19:23] +Completable: CtypedPattern(sourceType:Value[someVal], lookingToComplete:CRecordField, patternType:Destructure, prefix:s, pattern: [], seenIdents: [anotherThing, s]) +[{ + "label": "something", + "kind": 5, + "tags": [], + "detail": "something: someRecord\n\ntype anotherRecord = {\n something: someRecord,\n anotherThing: option,\n thirdThing: string,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypeContextCompletion_Records.res 22:8 +posCursor:[22:8] posNoWhite:[22:7] Found pattern:[22:7->22:9] +Completable: CtypedPattern(sourceType:Value[someVal], lookingToComplete:CRecordField, patternType:Destructure, prefix:"", pattern: [], seenIdents: []) +[{ + "label": "something", + "kind": 5, + "tags": [], + "detail": "something: someRecord\n\ntype anotherRecord = {\n something: someRecord,\n anotherThing: option,\n thirdThing: string,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "anotherThing", + "kind": 5, + "tags": [], + "detail": "anotherThing: option\n\ntype anotherRecord = {\n something: someRecord,\n anotherThing: option,\n thirdThing: string,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "thirdThing", + "kind": 5, + "tags": [], + "detail": "thirdThing: string\n\ntype anotherRecord = {\n something: someRecord,\n anotherThing: option,\n thirdThing: string,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypeContextCompletion_Records.res 31:8 +posCursor:[31:8] posNoWhite:[31:7] Found pattern:[31:7->31:9] +Completable: CtypedPattern(sourceType:Value[getSomeVal](~irrelevant), lookingToComplete:CRecordField, patternType:Destructure, prefix:"", pattern: [], seenIdents: []) +[{ + "label": "something", + "kind": 5, + "tags": [], + "detail": "something: someRecord\n\ntype anotherRecord = {\n something: someRecord,\n anotherThing: option,\n thirdThing: string,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "anotherThing", + "kind": 5, + "tags": [], + "detail": "anotherThing: option\n\ntype anotherRecord = {\n something: someRecord,\n anotherThing: option,\n thirdThing: string,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "thirdThing", + "kind": 5, + "tags": [], + "detail": "thirdThing: string\n\ntype anotherRecord = {\n something: someRecord,\n anotherThing: option,\n thirdThing: string,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypeContextCompletion_Records.res 35:20 +posCursor:[35:20] posNoWhite:[35:19] Found pattern:[35:7->35:22] +posCursor:[35:20] posNoWhite:[35:19] Found pattern:[35:19->35:21] +Completable: CtypedPattern(sourceType:Value[someVal], lookingToComplete:CRecordField, patternType:Destructure, prefix:"", pattern: [RecordField:something], seenIdents: []) +[{ + "label": "somethingElse", + "kind": 5, + "tags": [], + "detail": "somethingElse: int\n\ntype someRecord = {\n somethingElse: int,\n whatIsThis: bool,\n anotherLevel: anotherLevel,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "whatIsThis", + "kind": 5, + "tags": [], + "detail": "whatIsThis: bool\n\ntype someRecord = {\n somethingElse: int,\n whatIsThis: bool,\n anotherLevel: anotherLevel,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "anotherLevel", + "kind": 5, + "tags": [], + "detail": "anotherLevel: anotherLevel\n\ntype someRecord = {\n somethingElse: int,\n whatIsThis: bool,\n anotherLevel: anotherLevel,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypeContextCompletion_Records.res 38:47 +posCursor:[38:47] posNoWhite:[38:46] Found pattern:[38:7->38:50] +posCursor:[38:47] posNoWhite:[38:46] Found pattern:[38:19->38:49] +posCursor:[38:47] posNoWhite:[38:46] Found pattern:[38:46->38:48] +Completable: CtypedPattern(sourceType:Value[someVal], lookingToComplete:CRecordField, patternType:Destructure, prefix:"", pattern: [RecordField:something, RecordField:anotherLevel], seenIdents: []) +[{ + "label": "level", + "kind": 5, + "tags": [], + "detail": "level: int\n\ntype anotherLevel = {level: int, someOtherArg: bool}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "someOtherArg", + "kind": 5, + "tags": [], + "detail": "someOtherArg: bool\n\ntype anotherLevel = {level: int, someOtherArg: bool}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypeContextCompletion_Records.res 41:48 +posCursor:[41:48] posNoWhite:[41:47] Found pattern:[41:7->41:51] +posCursor:[41:48] posNoWhite:[41:47] Found pattern:[41:19->41:50] +posCursor:[41:48] posNoWhite:[41:47] Found pattern:[41:46->41:49] +posCursor:[41:48] posNoWhite:[41:47] Found pattern:[41:47->41:48] +Completable: CtypedPattern(sourceType:Value[someVal], lookingToComplete:CRecordField, patternType:Destructure, prefix:l, pattern: [RecordField:something, RecordField:anotherLevel], seenIdents: [l]) +[{ + "label": "level", + "kind": 5, + "tags": [], + "detail": "level: int\n\ntype anotherLevel = {level: int, someOtherArg: bool}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypeContextCompletion_Records.res 44:47 +posCursor:[44:47] posNoWhite:[44:44] Found pattern:[44:7->44:49] +posCursor:[44:47] posNoWhite:[44:44] Found pattern:[44:19->44:48] +Completable: CtypedPattern(sourceType:Value[someVal], lookingToComplete:CRecordField, patternType:Destructure, prefix:"", pattern: [RecordField:something], seenIdents: [whatIsThis, anotherLevel]) +[{ + "label": "somethingElse", + "kind": 5, + "tags": [], + "detail": "somethingElse: int\n\ntype someRecord = {\n somethingElse: int,\n whatIsThis: bool,\n anotherLevel: anotherLevel,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypeContextCompletion_Records.res 47:31 +posCursor:[47:31] posNoWhite:[47:30] Found pattern:[47:7->47:47] +posCursor:[47:31] posNoWhite:[47:30] Found pattern:[47:19->47:46] +Completable: CtypedPattern(sourceType:Value[someVal], lookingToComplete:CRecordField, patternType:Destructure, prefix:"", pattern: [RecordField:something], seenIdents: [whatIsThis, anotherLevel]) +[{ + "label": "somethingElse", + "kind": 5, + "tags": [], + "detail": "somethingElse: int\n\ntype someRecord = {\n somethingElse: int,\n whatIsThis: bool,\n anotherLevel: anotherLevel,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypeContextCompletion_Records.res 50:44 +posCursor:[50:44] posNoWhite:[50:43] Found expr:[50:3->50:54] +posCursor:[50:44] posNoWhite:[50:43] Found pattern:[50:22->50:46] +posCursor:[50:44] posNoWhite:[50:43] Found pattern:[50:42->50:45] +Completable: CtypedPattern(sourceType:Value[someVal], lookingToComplete:CRecordField, patternType:Switch, prefix:som, pattern: [], seenIdents: [thirdThing, som]) +[{ + "label": "something", + "kind": 5, + "tags": [], + "detail": "something: someRecord\n\ntype anotherRecord = {\n something: someRecord,\n anotherThing: option,\n thirdThing: string,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypeContextCompletion_Records.res 53:52 +posCursor:[53:52] posNoWhite:[53:51] Found expr:[53:3->53:61] +posCursor:[53:52] posNoWhite:[53:51] Found pattern:[53:51->53:53] +Completable: CtypedPattern(sourceType:Value[someVal], lookingToComplete:CRecordField, patternType:Switch, prefix:"", pattern: [], seenIdents: []) +[{ + "label": "something", + "kind": 5, + "tags": [], + "detail": "something: someRecord\n\ntype anotherRecord = {\n something: someRecord,\n anotherThing: option,\n thirdThing: string,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "anotherThing", + "kind": 5, + "tags": [], + "detail": "anotherThing: option\n\ntype anotherRecord = {\n something: someRecord,\n anotherThing: option,\n thirdThing: string,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "thirdThing", + "kind": 5, + "tags": [], + "detail": "thirdThing: string\n\ntype anotherRecord = {\n something: someRecord,\n anotherThing: option,\n thirdThing: string,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypeContextCompletion_Records.res 56:89 +posCursor:[56:89] posNoWhite:[56:88] Found expr:[56:3->56:100] +posCursor:[56:89] posNoWhite:[56:88] Found pattern:[56:51->56:92] +posCursor:[56:89] posNoWhite:[56:88] Found pattern:[56:63->56:91] +Completable: CtypedPattern(sourceType:Value[someVal], lookingToComplete:CRecordField, patternType:Switch, prefix:"", pattern: [RecordField:something], seenIdents: [whatIsThis, anotherLevel]) +[{ + "label": "somethingElse", + "kind": 5, + "tags": [], + "detail": "somethingElse: int\n\ntype someRecord = {\n somethingElse: int,\n whatIsThis: bool,\n anotherLevel: anotherLevel,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypeContextCompletion_Records.res 81:48 +posCursor:[81:48] posNoWhite:[81:47] Found expr:[81:3->81:57] +posCursor:[81:48] posNoWhite:[81:47] Found pattern:[81:29->81:49] +posCursor:[81:48] posNoWhite:[81:47] Found pattern:[81:41->81:48] +posCursor:[81:48] posNoWhite:[81:47] Found pattern:[81:47->81:48] +Ppat_construct T:[81:47->81:48] +Completable: CtypedPattern(sourceType:Value[someOtherValue], lookingToComplete:CVariant, patternType:Switch, prefix:T, pattern: [RecordField:something], seenIdents: [Two, T]) +[{ + "label": "Three(_)", + "kind": 4, + "tags": [], + "detail": "Three(int)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Three(${1:_})", + "insertTextFormat": 2 + }] + +Complete src/TypeContextCompletion_Records.res 84:48 +posCursor:[84:48] posNoWhite:[84:47] Found expr:[84:3->84:58] +posCursor:[84:48] posNoWhite:[84:47] Found pattern:[84:29->84:50] +posCursor:[84:48] posNoWhite:[84:47] Found pattern:[84:42->84:49] +Ppat_construct Some:[84:42->84:46] +posCursor:[84:48] posNoWhite:[84:47] Found pattern:[84:47->84:48] +Ppat_construct T:[84:47->84:48] +Completable: CtypedPattern(sourceType:Value[someOtherValue], lookingToComplete:CVariant, patternType:Switch, prefix:T, pattern: [RecordField:otherThing, Variant:Some(0)], seenIdents: []) +[{ + "label": "Two", + "kind": 4, + "tags": [], + "detail": "Two\n\n", + "documentation": null, + "sortText": null, + "insertText": "Two", + "insertTextFormat": 2 + }, { + "label": "Three(_)", + "kind": 4, + "tags": [], + "detail": "Three(int)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Three(${1:_})", + "insertTextFormat": 2 + }] + +Complete src/TypeContextCompletion_Records.res 87:47 +posCursor:[87:47] posNoWhite:[87:46] Found expr:[87:3->87:57] +posCursor:[87:47] posNoWhite:[87:46] Found pattern:[87:29->87:49] +posCursor:[87:47] posNoWhite:[87:46] Found pattern:[87:42->87:48] +posCursor:[87:47] posNoWhite:[87:46] Found pattern:[87:46->87:47] +Ppat_construct T:[87:46->87:47] +Completable: CtypedPattern(sourceType:Value[someOtherValue], lookingToComplete:CVariant, patternType:Switch, prefix:T, pattern: [RecordField:thirdStuff, Tuple:1], seenIdents: []) +[{ + "label": "Two", + "kind": 4, + "tags": [], + "detail": "Two\n\n", + "documentation": null, + "sortText": null, + "insertText": "Two", + "insertTextFormat": 2 + }, { + "label": "Three(_)", + "kind": 4, + "tags": [], + "detail": "Three(int)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Three(${1:_})", + "insertTextFormat": 2 + }] + +Complete src/TypeContextCompletion_Records.res 90:51 +posCursor:[90:51] posNoWhite:[90:50] Found expr:[90:3->90:62] +posCursor:[90:51] posNoWhite:[90:50] Found pattern:[90:29->90:54] +posCursor:[90:51] posNoWhite:[90:50] Found pattern:[90:42->90:53] +posCursor:[90:51] posNoWhite:[90:50] Found pattern:[90:46->90:52] +Ppat_construct Four:[90:46->90:50] +posCursor:[90:51] posNoWhite:[90:50] Found pattern:[90:50->90:52] +Ppat_construct ():[90:50->90:52] +Completable: CtypedPattern(sourceType:Value[someOtherValue], lookingToComplete:CNoContext, patternType:Switch, prefix:"", pattern: [RecordField:thirdStuff, Tuple:1, Variant:Four(0)], seenIdents: []) +[{ + "label": "TwentyFive", + "kind": 4, + "tags": [], + "detail": "TwentyFive\n\n", + "documentation": null, + "sortText": null, + "insertText": "TwentyFive", + "insertTextFormat": 2 + }, { + "label": "SixtyTwo", + "kind": 4, + "tags": [], + "detail": "SixtyTwo\n\n", + "documentation": null, + "sortText": null, + "insertText": "SixtyTwo", + "insertTextFormat": 2 + }] + +Complete src/TypeContextCompletion_Records.res 93:55 +posCursor:[93:55] posNoWhite:[93:54] Found expr:[93:3->93:66] +posCursor:[93:55] posNoWhite:[93:54] Found pattern:[93:29->93:58] +posCursor:[93:55] posNoWhite:[93:54] Found pattern:[93:42->93:57] +posCursor:[93:55] posNoWhite:[93:54] Found pattern:[93:46->93:56] +Ppat_construct Five:[93:46->93:50] +posCursor:[93:55] posNoWhite:[93:54] Found pattern:[93:50->93:57] +posCursor:[93:55] posNoWhite:[93:54] Found pattern:[93:54->93:55] +Ppat_construct O:[93:54->93:55] +Completable: CtypedPattern(sourceType:Value[someOtherValue], lookingToComplete:CVariant, patternType:Switch, prefix:O, pattern: [RecordField:thirdStuff, Tuple:1, Variant:Five(1)], seenIdents: []) +[{ + "label": "One", + "kind": 4, + "tags": [], + "detail": "One\n\n", + "documentation": null, + "sortText": null, + "insertText": "One", + "insertTextFormat": 2 + }] + +Complete src/TypeContextCompletion_Records.res 96:63 +posCursor:[96:63] posNoWhite:[96:62] Found expr:[96:3->96:78] +posCursor:[96:63] posNoWhite:[96:62] Found pattern:[96:29->96:70] +posCursor:[96:63] posNoWhite:[96:62] Found pattern:[96:43->96:69] +posCursor:[96:63] posNoWhite:[96:62] Found pattern:[96:44->96:65] +Ppat_construct Some:[96:44->96:48] +posCursor:[96:63] posNoWhite:[96:62] Found pattern:[96:49->96:64] +posCursor:[96:63] posNoWhite:[96:62] Found pattern:[96:62->96:63] +Ppat_construct O:[96:62->96:63] +Completable: CtypedPattern(sourceType:Value[someOtherValue], lookingToComplete:CVariant, patternType:Switch, prefix:O, pattern: [RecordField:fourthStuff, Tuple:0, Variant:Some(0), Variant:WithPayload(0)], seenIdents: []) +[] + +Complete src/TypeContextCompletion_Records.res 99:67 +posCursor:[99:67] posNoWhite:[99:66] Found expr:[99:3->99:78] +posCursor:[99:67] posNoWhite:[99:66] Found pattern:[99:29->99:70] +posCursor:[99:67] posNoWhite:[99:66] Found pattern:[99:42->99:69] +posCursor:[99:67] posNoWhite:[99:66] Found pattern:[99:46->99:68] +Ppat_construct Five:[99:46->99:50] +posCursor:[99:67] posNoWhite:[99:66] Found pattern:[99:50->99:69] +posCursor:[99:67] posNoWhite:[99:66] Found pattern:[99:54->99:67] +posCursor:[99:67] posNoWhite:[99:66] Found pattern:[99:66->99:67] +Ppat_construct T:[99:66->99:67] +Completable: CtypedPattern(sourceType:Value[someOtherValue], lookingToComplete:CVariant, patternType:Switch, prefix:T, pattern: [RecordField:thirdStuff, Tuple:1, Variant:Five(1)], seenIdents: [One, Two, T]) +[{ + "label": "Three(_)", + "kind": 4, + "tags": [], + "detail": "Three(int)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Three(${1:_})", + "insertTextFormat": 2 + }] + +Complete src/TypeContextCompletion_Records.res 102:43 +posCursor:[102:43] posNoWhite:[102:42] Found expr:[102:3->102:52] +posCursor:[102:43] posNoWhite:[102:42] Found pattern:[102:29->102:44] +posCursor:[102:43] posNoWhite:[102:42] Found pattern:[102:42->102:43] +Ppat_construct S:[102:42->102:43] +Completable: CtypedPattern(sourceType:Value[someOtherValue], lookingToComplete:CVariant, patternType:Switch, prefix:S, pattern: [RecordField:otherThing], seenIdents: []) +[{ + "label": "None", + "kind": 4, + "tags": [], + "detail": "None\n\n", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Some(One)", + "kind": 4, + "tags": [], + "detail": "One\n\n", + "documentation": null, + "sortText": null, + "insertText": "Some(One)", + "insertTextFormat": 2 + }, { + "label": "Some(Two)", + "kind": 4, + "tags": [], + "detail": "Two\n\n", + "documentation": null, + "sortText": null, + "insertText": "Some(Two)", + "insertTextFormat": 2 + }, { + "label": "Some(Three(_))", + "kind": 4, + "tags": [], + "detail": "Three(int)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Some(Three(${1:_}))", + "insertTextFormat": 2 + }, { + "label": "Some(Four(_))", + "kind": 4, + "tags": [], + "detail": "Four(someOtherVariant)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Some(Four(${1:_}))", + "insertTextFormat": 2 + }, { + "label": "Some(Five(_))", + "kind": 4, + "tags": [], + "detail": "Five(someOtherVariant, someVariant)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Some(Five(${1:_}))", + "insertTextFormat": 2 + }] + +Complete src/TypeContextCompletion_Records.res 105:39 +posCursor:[105:39] posNoWhite:[105:38] Found expr:[105:3->105:48] +posCursor:[105:39] posNoWhite:[105:38] Found pattern:[105:29->105:40] +posCursor:[105:39] posNoWhite:[105:38] Found pattern:[105:38->105:39] +Ppat_construct S:[105:38->105:39] +Completable: CtypedPattern(sourceType:Value[someOtherValue], lookingToComplete:CVariant, patternType:Switch, prefix:S, pattern: [RecordField:other2], seenIdents: []) +[{ + "label": "None", + "kind": 4, + "tags": [], + "detail": "None\n\n", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Some(_)", + "kind": 4, + "tags": [], + "detail": "Some(_)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Some(${1:_})", + "insertTextFormat": 2 + }] + +Complete src/TypeContextCompletion_Records.res 108:64 +posCursor:[108:64] posNoWhite:[108:62] Found expr:[108:3->108:75] +posCursor:[108:64] posNoWhite:[108:62] Found pattern:[108:29->108:67] +posCursor:[108:64] posNoWhite:[108:62] Found pattern:[108:42->108:66] +posCursor:[108:64] posNoWhite:[108:62] Found pattern:[108:46->108:65] +Ppat_construct Four:[108:46->108:50] +Completable: Cpath Value[Four] +[] + +Complete src/TypeContextCompletion_Records.res 111:38 +posCursor:[111:38] posNoWhite:[111:36] Found expr:[111:3->111:47] +posCursor:[111:38] posNoWhite:[111:36] Found pattern:[111:29->111:39] +Completable: CtypedPattern(sourceType:Value[someOtherValue], lookingToComplete:CNoContext, patternType:Switch, prefix:"", pattern: [RecordField:other2], seenIdents: []) +[{ + "label": "None", + "kind": 4, + "tags": [], + "detail": "None\n\n", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Some(_)", + "kind": 4, + "tags": [], + "detail": "Some(_)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Some(${1:_})", + "insertTextFormat": 2 + }] + +Complete src/TypeContextCompletion_Records.res 114:55 +posCursor:[114:55] posNoWhite:[114:53] Found expr:[114:3->114:67] +posCursor:[114:55] posNoWhite:[114:53] Found pattern:[114:22->114:59] +posCursor:[114:55] posNoWhite:[114:53] Found pattern:[114:34->114:59] +Completable: CtypedPattern(sourceType:Value[someVal], lookingToComplete:CNoContext, patternType:Switch, prefix:"", pattern: [RecordField:something, RecordField:whatIsThis], seenIdents: [false]) +[{ + "label": "true", + "kind": 12, + "tags": [], + "detail": "boolean\n\n", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypeContextCompletion_Records.res 117:46 +posCursor:[117:46] posNoWhite:[117:45] Found expr:[117:3->117:58] +posCursor:[117:46] posNoWhite:[117:45] Found pattern:[117:22->117:50] +posCursor:[117:46] posNoWhite:[117:45] Found pattern:[117:34->117:50] +Completable: CtypedPattern(sourceType:Value[someVal], lookingToComplete:CNoContext, patternType:Switch, prefix:"", pattern: [RecordField:something, RecordField:whatIsThis], seenIdents: []) +[{ + "label": "false", + "kind": 12, + "tags": [], + "detail": "boolean\n\n", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "true", + "kind": 12, + "tags": [], + "detail": "boolean\n\n", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypeContextCompletion_Records.res 120:49 +posCursor:[120:49] posNoWhite:[120:48] Found expr:[120:3->120:62] +posCursor:[120:49] posNoWhite:[120:48] Found pattern:[120:22->120:54] +posCursor:[120:49] posNoWhite:[120:48] Found pattern:[120:34->120:52] +posCursor:[120:49] posNoWhite:[120:48] Found pattern:[120:47->120:49] +Completable: CtypedPattern(sourceType:Value[someVal], lookingToComplete:CVariant, patternType:Switch, prefix:fa, pattern: [RecordField:something, RecordField:whatIsThis], seenIdents: []) +[{ + "label": "false", + "kind": 12, + "tags": [], + "detail": "boolean\n\n", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypeContextCompletion_Records.res 125:15 +posCursor:[125:15] posNoWhite:[125:14] Found expr:[125:3->131:11] +Completable: CtypedPattern(sourceType:Value[x], lookingToComplete:CNoContext, patternType:Switch, prefix:"", pattern: [], seenIdents: []) +[{ + "label": "None", + "kind": 4, + "tags": [], + "detail": "None\n\n", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Some(One)", + "kind": 4, + "tags": [], + "detail": "One\n\n", + "documentation": null, + "sortText": null, + "insertText": "Some(One)", + "insertTextFormat": 2 + }, { + "label": "Some(Two)", + "kind": 4, + "tags": [], + "detail": "Two\n\n", + "documentation": null, + "sortText": null, + "insertText": "Some(Two)", + "insertTextFormat": 2 + }, { + "label": "Some(Three(_))", + "kind": 4, + "tags": [], + "detail": "Three(int)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Some(Three(${1:_}))", + "insertTextFormat": 2 + }, { + "label": "Some(Four(_))", + "kind": 4, + "tags": [], + "detail": "Four(someOtherVariant)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Some(Four(${1:_}))", + "insertTextFormat": 2 + }, { + "label": "Some(Five(_))", + "kind": 4, + "tags": [], + "detail": "Five(someOtherVariant, someVariant)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Some(Five(${1:_}))", + "insertTextFormat": 2 + }] + +Complete src/TypeContextCompletion_Records.res 128:14 +posCursor:[128:14] posNoWhite:[128:12] Found expr:[128:3->128:13] +[] + +Complete src/TypeContextCompletion_Records.res 133:15 +posCursor:[133:15] posNoWhite:[133:14] Found expr:[133:3->133:17] +Completable: CtypedPattern(sourceType:Value[y], lookingToComplete:CNoContext, patternType:Switch, prefix:"", pattern: [], seenIdents: []) +[{ + "label": "One", + "kind": 4, + "tags": [], + "detail": "One\n\n", + "documentation": null, + "sortText": null, + "insertText": "One", + "insertTextFormat": 2 + }, { + "label": "Two", + "kind": 4, + "tags": [], + "detail": "Two\n\n", + "documentation": null, + "sortText": null, + "insertText": "Two", + "insertTextFormat": 2 + }, { + "label": "Three(_)", + "kind": 4, + "tags": [], + "detail": "Three(int)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Three(${1:_})", + "insertTextFormat": 2 + }, { + "label": "Four(_)", + "kind": 4, + "tags": [], + "detail": "Four(someOtherVariant)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Four(${1:_})", + "insertTextFormat": 2 + }, { + "label": "Five(_)", + "kind": 4, + "tags": [], + "detail": "Five(someOtherVariant, someVariant)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Five(${1:_})", + "insertTextFormat": 2 + }] + +Complete src/TypeContextCompletion_Records.res 136:36 +posCursor:[136:36] posNoWhite:[136:34] Found expr:[136:3->136:38] +Completable: CtypedPattern(sourceType:Value[y], lookingToComplete:CNoContext, patternType:Switch, prefix:"", pattern: [], seenIdents: [One, Two, Three]) +[{ + "label": "Four(_)", + "kind": 4, + "tags": [], + "detail": "Four(someOtherVariant)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Four(${1:_})", + "insertTextFormat": 2 + }, { + "label": "Five(_)", + "kind": 4, + "tags": [], + "detail": "Five(someOtherVariant, someVariant)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Five(${1:_})", + "insertTextFormat": 2 + }] + +Complete src/TypeContextCompletion_Records.res 140:33 +posCursor:[140:33] posNoWhite:[140:32] Found expr:[140:3->140:44] +posCursor:[140:33] posNoWhite:[140:32] Found pattern:[140:22->140:36] +Completable: CtypedPattern(sourceType:Value[someVal], lookingToComplete:CNoContext, patternType:Switch, prefix:"", pattern: [RecordField:something], seenIdents: []) +[{ + "label": "{}", + "kind": 4, + "tags": [], + "detail": "Empty record", + "documentation": null, + "sortText": "a", + "insertText": "{${1}}", + "insertTextFormat": 2 + }] + +Complete src/TypeContextCompletion_Records.res 144:35 +posCursor:[144:35] posNoWhite:[144:34] Found expr:[144:3->144:46] +posCursor:[144:35] posNoWhite:[144:34] Found pattern:[144:22->144:38] +posCursor:[144:35] posNoWhite:[144:34] Found pattern:[144:34->144:36] +Completable: CtypedPattern(sourceType:Value[someVal], lookingToComplete:CRecordField, patternType:Switch, prefix:"", pattern: [RecordField:something], seenIdents: []) +[{ + "label": "somethingElse", + "kind": 5, + "tags": [], + "detail": "somethingElse: int\n\ntype someRecord = {\n somethingElse: int,\n whatIsThis: bool,\n anotherLevel: anotherLevel,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "whatIsThis", + "kind": 5, + "tags": [], + "detail": "whatIsThis: bool\n\ntype someRecord = {\n somethingElse: int,\n whatIsThis: bool,\n anotherLevel: anotherLevel,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "anotherLevel", + "kind": 5, + "tags": [], + "detail": "anotherLevel: anotherLevel\n\ntype someRecord = {\n somethingElse: int,\n whatIsThis: bool,\n anotherLevel: anotherLevel,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypeContextCompletion_Records.res 147:45 +posCursor:[147:45] posNoWhite:[147:44] Found expr:[147:3->147:58] +posCursor:[147:45] posNoWhite:[147:44] Found pattern:[147:29->147:50] +posCursor:[147:45] posNoWhite:[147:44] Found pattern:[147:43->147:49] +posCursor:[147:45] posNoWhite:[147:44] Found pattern:[147:44->147:45] +Completable: CtypedPattern(sourceType:Value[someOtherValue], lookingToComplete:CNoContext, patternType:Switch, prefix:"", pattern: [RecordField:fourthStuff, Tuple:0], seenIdents: []) +[{ + "label": "None", + "kind": 4, + "tags": [], + "detail": "None\n\n", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Some(#WithPayload(_))", + "kind": 4, + "tags": [], + "detail": "#WithPayload(someVariant)", + "documentation": null, + "sortText": null, + "insertText": "Some(#WithPayload(${1:_}))", + "insertTextFormat": 2 + }] + diff --git a/analysis/tests/src/expected/TypedContextCompletionSpec.res.spec.txt b/analysis/tests/src/expected/TypedContextCompletionSpec.res.spec.txt new file mode 100644 index 000000000..e960e25e8 --- /dev/null +++ b/analysis/tests/src/expected/TypedContextCompletionSpec.res.spec.txt @@ -0,0 +1,965 @@ +Dump AST src/TypedContextCompletionSpec.res 49:40 + +Source: +// let x = someVariantToString(~someVaria +// ^ast + + +Pstr_value( + value: + Ppat_var(x) + expr: + <*>Pexp_apply( + expr: + Pexp_ident:someVariantToString + args: + <*>~someVaria= + <*>Pexp_ident:someVaria + ) +) + +Dump AST src/TypedContextCompletionSpec.res 53:43 + +// Find source: exp -> labelled arg +// Looking for: no context +Source: +// let x = someVariantToString(~someVariant= +// ^ast + + +Pstr_value( + value: + Ppat_var(x) + expr: + <*>Pexp_apply( + expr: + Pexp_ident:someVariantToString + args: + <*>~someVariant= + Pexp_extension(%rescript.exprhole) + ) +) + + +// Find source: exp -> labelled arg +// Looking for: variant +Dump AST src/TypedContextCompletionSpec.res 61:44 + +Source: +// let x = someVariantToString(~someVariant=T +// ^ast + + +Pstr_value( + value: + Ppat_var(x) + expr: + <*>Pexp_apply( + expr: + Pexp_ident:someVariantToString + args: + ~someVariant= + <*>Pexp_construct(<*>T) + ) +) + +// Find source: exp -> labelled arg +// Looking for: variant/ident? +Dump AST src/TypedContextCompletionSpec.res 65:44 + +Source: +// let x = someVariantToString(~someVariant=t +// ^ast + + +Pstr_value( + value: + Ppat_var(x) + expr: + <*>Pexp_apply( + expr: + Pexp_ident:someVariantToString + args: + ~someVariant= + <*>Pexp_ident:t + ) +) + +// Find source: exp -> labelled arg +// Looking for: TypeDefinition. -> anything +Dump AST src/TypedContextCompletionSpec.res 69:58 + +Source: +// let x = someVariantToString(~someVariant=TypeDefinition. +// ^ast + + +Pstr_value( + value: + Ppat_var(x) + expr: + <*>Pexp_apply( + expr: + Pexp_ident:someVariantToString + args: + ~someVariant= + <*>Pexp_ident:TypeDefinition."" + ) +) + +// Find source: exp -> labelled arg +// Looking for: no context +Dump AST src/TypedContextCompletionSpec.res 73:44 + +Source: +// let x = someVariantToString(~anotherThing= +// ^ast + + +Pstr_value( + value: + Ppat_var(x) + expr: + <*>Pexp_apply( + expr: + Pexp_ident:someVariantToString + args: + <*>~anotherThing= + Pexp_extension(%rescript.exprhole) + ) +) + +// Find source: exp -> labelled arg +// Looking for: no context +Dump AST src/TypedContextCompletionSpec.res 77:42 + +Source: +// let x = someVariantToString(~thirdThing= +// ^ast + + +Pstr_value( + value: + Ppat_var(x) + expr: + <*>Pexp_apply( + expr: + Pexp_ident:someVariantToString + args: + <*>~thirdThing= + Pexp_extension(%rescript.exprhole) + ) +) + +// Find source: exp -> labelled arg +// Looking for: polyvariant +Dump AST src/TypedContextCompletionSpec.res 81:44 + +Source: +// let x = someVariantToString(~thirdThing=#t +// ^ast + + +Pstr_value( + value: + Ppat_var(x) + expr: + <*>Pexp_apply( + expr: + Pexp_ident:someVariantToString + args: + ~thirdThing= + <*>Pexp_variant(t) + ) +) + +// Find source: exp -> labelled arg +// Looking for: polyvariant +Dump AST src/TypedContextCompletionSpec.res 85:44 + +Source: +// let x = someVariantToString(~thirdThing=#T +// ^ast + + +Pstr_value( + value: + Ppat_var(x) + expr: + <*>Pexp_apply( + expr: + Pexp_ident:someVariantToString + args: + ~thirdThing= + <*>Pexp_variant(T) + ) +) + +// Find source: exp -> labelled arg -> fn argument unlabelled 0 +// Looking for: record field +Dump AST src/TypedContextCompletionSpec.res 93:36 + +Source: +// let _ = doStuff(~doThing=({age, n}) => {()}) +// ^ast + + +Pstr_value( + value: + Ppat_any + expr: + <*>Pexp_apply( + expr: + Pexp_ident:doStuff + args: + ~doThing= + <*>Pexp_fun( + arg: Nolabel, + pattern: <*>Ppat_record( + fields: + age: Ppat_var(age) + <*>n: Ppat_var(<*>n) + ), + next expr: + Pexp_construct(()) + ) + ) +) + +// Find source: exp +// Looking for: record field +Dump AST src/TypedContextCompletionSpec.res 97:15 + +Source: +// let {another} = someVal +// ^ast + + +Pstr_value( + value: + <*>Ppat_record( + fields: + <*>another: Ppat_var(<*>another) + ) + expr: + Pexp_ident:someVal +) + +// Find source: exp +// Looking for: record field +Dump AST src/TypedContextCompletionSpec.res 101:23 + +Source: +// let {anotherThing, s} = someVal +// ^ast + + +Pstr_value( + value: + <*>Ppat_record( + fields: + anotherThing: Ppat_var(anotherThing) + <*>s: Ppat_var(<*>s) + ) + expr: + Pexp_ident:someVal +) + +Dump AST src/TypedContextCompletionSpec.res 105:8 + +// Find source: exp +// Looking for: record field +Source: +// let {} = someVal +// ^ast + + +Pstr_value( + value: + <*>Ppat_record( + fields: + + ) + expr: + Pexp_ident:someVal +) + +// Find source: exp +// Looking for: record field +Dump AST src/TypedContextCompletionSpec.res 109:8 + +Source: +// let {} = getSomeVal(~irrelevant=123) +// ^ast + + +Pstr_value( + value: + <*>Ppat_record( + fields: + + ) + expr: + Pexp_apply( + expr: + Pexp_ident:getSomeVal + args: + ~irrelevant= + Pexp_constant(Pconst_integer(123)) + ) +) + +Dump AST src/TypedContextCompletionSpec.res 113:20 + +// Find source: exp + pat[rfield something] +// Looking for: record field +Source: +// let {something: {}} = someVal +// ^ast + + +Pstr_value( + value: + <*>Ppat_record( + fields: + something: <*>Ppat_record( + fields: + + ) + ) + expr: + Pexp_ident:someVal +) + +// Find source: exp + pat[rfield something, rfield anotherLevel] +// Looking for: record field +Dump AST src/TypedContextCompletionSpec.res 117:47 + +Source: +// let {something: {whatIsThis, anotherLevel: {}}} = someVal +// ^ast + + +Pstr_value( + value: + <*>Ppat_record( + fields: + something: <*>Ppat_record( + fields: + whatIsThis: Ppat_var(whatIsThis) + anotherLevel: <*>Ppat_record( + fields: + + ) + ) + ) + expr: + Pexp_ident:someVal +) + +Dump AST src/TypedContextCompletionSpec.res 121:48 + +// Find source: exp + pat[rfield something, rfield anotherLevel] +// Looking for: record field +Source: +// let {something: {whatIsThis, anotherLevel: {l}}} = someVal +// ^ast + + +Pstr_value( + value: + <*>Ppat_record( + fields: + something: <*>Ppat_record( + fields: + whatIsThis: Ppat_var(whatIsThis) + anotherLevel: <*>Ppat_record( + fields: + <*>l: Ppat_var(<*>l) + ) + ) + ) + expr: + Pexp_ident:someVal +) + +Dump AST src/TypedContextCompletionSpec.res 125:47 + +// Find source: exp + pat[rfield something] +// Looking for: record field +Source: +// let {something: {whatIsThis, anotherLevel, }} = someVal +// ^ast + + +Pstr_value( + value: + <*>Ppat_record( + fields: + something: <*>Ppat_record( + fields: + whatIsThis: Ppat_var(whatIsThis) + anotherLevel: Ppat_var(anotherLevel) + ) + ) + expr: + Pexp_ident:someVal +) + +Dump AST src/TypedContextCompletionSpec.res 129:31 + +// Find source: exp + pat[rfield something] +// Looking for: record field + +Source: +// let {something: {whatIsThis, ,anotherLevel}} = someVal +// ^ast + + +Pstr_value( + value: + <*>Ppat_record( + fields: + something: <*>Ppat_record( + fields: + whatIsThis: Ppat_var(whatIsThis) + anotherLevel: Ppat_var(anotherLevel) + ) + ) + expr: + Pexp_ident:someVal +) + +Dump AST src/TypedContextCompletionSpec.res 137:44 +// Find source: exp +// Looking for: record field som +Source: +// switch someVal { | {thirdThing: "123", som} => () } +// ^ast + + +Pstr_eval( + <*>Pexp_match(Pexp_ident:someVal) + case 1: + pattern<*>: + <*>Ppat_record( + fields: + thirdThing: Ppat_constant(Pconst_string(123)) + <*>som: <*>Ppat_var(<*>som) + ) + expr: + Pexp_construct(()) +) + +Dump AST src/TypedContextCompletionSpec.res 141:52 + +// Find source: exp +// Looking for: record field som + +Source: +// switch someVal { | {thirdThing: "1234"} => () | {} => () } +// ^ast + + +Pstr_eval( + <*>Pexp_match(Pexp_ident:someVal) + case 1: + pattern: + Ppat_record( + fields: + thirdThing: Ppat_constant(Pconst_string(1234)) + ) + expr: + Pexp_construct(()) + case 2: + pattern<*>: + <*>Ppat_record( + fields: + + ) + expr: + Pexp_construct(()) +) + +Dump AST src/TypedContextCompletionSpec.res 145:89 + +// Find source: exp + pat[rfield something] +// Looking for: record field + +Source: +// switch someVal { | {thirdThing: "1234"} => () | {something: {whatIsThis, anotherLevel, }} => () } +// ^ast + + +Pstr_eval( + <*>Pexp_match(Pexp_ident:someVal) + case 1: + pattern: + Ppat_record( + fields: + thirdThing: Ppat_constant(Pconst_string(1234)) + ) + expr: + Pexp_construct(()) + case 2: + pattern<*>: + <*>Ppat_record( + fields: + something: <*>Ppat_record( + fields: + whatIsThis: Ppat_var(whatIsThis) + anotherLevel: Ppat_var(anotherLevel) + ) + ) + expr: + Pexp_construct(()) +) + +Dump AST src/TypedContextCompletionSpec.res 149:48 + +// Find source: exp + pat[rfield something] +// Looking for: variant + +Source: +// switch someOtherValue { | {something: Two | T} => () } +// ^ast + + +Pstr_eval( + <*>Pexp_match(Pexp_ident:someOtherValue) + case 1: + pattern<*>: + <*>Ppat_record( + fields: + something: Ppat_or( + Ppat_construct(Two), + Ppat_construct(<*>T) + ) + ) + expr: + Pexp_construct(()) +) + +Dump AST src/TypedContextCompletionSpec.res 152:48 + +// Find source: exp + pat[rfield otherThing, variant Some(0)] +// Looking for: variant + +Source: +// switch someOtherValue { | {otherThing: Some(T)} => () } +// ^ast + + +Pstr_eval( + <*>Pexp_match(Pexp_ident:someOtherValue) + case 1: + pattern<*>: + <*>Ppat_record( + fields: + otherThing: <*>Ppat_construct(Some,Ppat_construct(<*>T)) + ) + expr: + Pexp_construct(()) +) + +Dump AST src/TypedContextCompletionSpec.res 155:47 + +// Find source: exp + pat[rfield thirdStuff, tuple(1)] +// Looking for: variant + +Source: +// switch someOtherValue { | {thirdStuff: (_, T)} => () } +// ^ast + + +Pstr_eval( + <*>Pexp_match(Pexp_ident:someOtherValue) + case 1: + pattern<*>: + <*>Ppat_record( + fields: + thirdStuff: <*>Ppat_tuple( + Ppat_any, + Ppat_construct(<*>T) + ) + ) + expr: + Pexp_construct(()) +) + +Dump AST src/TypedContextCompletionSpec.res 158:51 + +// Find source: exp + pat[rfield thirdStuff, tuple(1), variant Four(0)] +// Looking for: no context + +Source: +// switch someOtherValue { | {thirdStuff: (_, Four())} => () } +// ^ast + + +Pstr_eval( + <*>Pexp_match(Pexp_ident:someOtherValue) + case 1: + pattern<*>: + <*>Ppat_record( + fields: + thirdStuff: <*>Ppat_tuple( + Ppat_any, + <*>Ppat_construct(Four,<*>Ppat_construct(<*>())) + ) + ) + expr: + Pexp_construct(()) +) + +Dump AST src/TypedContextCompletionSpec.res 161:55 + +// Find source: exp + pat[rfield thirdStuff, tuple(2), variant Five(1)] +// Looking for: variant + +Source: +// switch someOtherValue { | {thirdStuff: (_, Five(_, O))} => () } +// ^ast + + +Pstr_eval( + <*>Pexp_match(Pexp_ident:someOtherValue) + case 1: + pattern<*>: + <*>Ppat_record( + fields: + thirdStuff: <*>Ppat_tuple( + Ppat_any, + <*>Ppat_construct(Five,<*>Ppat_tuple( + Ppat_any, + Ppat_construct(<*>O) + )) + ) + ) + expr: + Pexp_construct(()) +) + +Dump AST src/TypedContextCompletionSpec.res 164:63 +// Find source: exp + pat[rfield thirdStuff, tuple(2), variant Five(1)] +// Looking for: variant + +Source: +// switch someOtherValue { | {fourthStuff: (Some(#WithPayload(O)), _)} => () } +// ^ast + + +Pstr_eval( + <*>Pexp_match(Pexp_ident:someOtherValue) + case 1: + pattern<*>: + <*>Ppat_record( + fields: + fourthStuff: <*>Ppat_tuple( + <*>Ppat_construct(Some,<*>Ppat_variant(WithPayload,Ppat_construct(<*>O))), + Ppat_any + ) + ) + expr: + Pexp_construct(()) +) + +Dump AST src/TypedContextCompletionSpec.res 167:67 + +Source: +// switch someOtherValue { | {thirdStuff: (_, Five(_, One | Two | T))} => () } +// ^ast + + +Pstr_eval( + <*>Pexp_match(Pexp_ident:someOtherValue) + case 1: + pattern<*>: + <*>Ppat_record( + fields: + thirdStuff: <*>Ppat_tuple( + Ppat_any, + <*>Ppat_construct(Five,<*>Ppat_tuple( + Ppat_any, + Ppat_or( + Ppat_or( + Ppat_construct(One), + Ppat_construct(Two) + ), + Ppat_construct(<*>T) + ) + )) + ) + ) + expr: + Pexp_construct(()) +) + +Dump AST src/TypedContextCompletionSpec.res 170:43 + +Source: +// switch someOtherValue { | {otherThing: S} => () } +// ^ast + + +Pstr_eval( + <*>Pexp_match(Pexp_ident:someOtherValue) + case 1: + pattern<*>: + <*>Ppat_record( + fields: + otherThing: Ppat_construct(<*>S) + ) + expr: + Pexp_construct(()) +) + +Dump AST src/TypedContextCompletionSpec.res 173:39 + +Source: +// switch someOtherValue { | {other2: S} => () } +// ^ast + + +Pstr_eval( + <*>Pexp_match(Pexp_ident:someOtherValue) + case 1: + pattern<*>: + <*>Ppat_record( + fields: + other2: Ppat_construct(<*>S) + ) + expr: + Pexp_construct(()) +) + +Dump AST src/TypedContextCompletionSpec.res 176:64 + +Source: +// switch someOtherValue { | {thirdStuff: (_, Four(TwentyFive | ))} => () } +// ^ast + + +Pstr_eval( + <*>Pexp_match(Pexp_ident:someOtherValue) + case 1: + pattern<*>: + <*>Ppat_record( + fields: + thirdStuff: <*>Ppat_tuple( + Ppat_any, + <*>Ppat_construct(Four,Ppat_or( + Ppat_construct(TwentyFive), + Ppat_extension(%rescript.patternhole) + )) + ) + ) + expr: + Pexp_construct(()) +) + +Dump AST src/TypedContextCompletionSpec.res 179:38 + +Source: +// switch someOtherValue { | {other2: } => () } +// ^ast + + +Pstr_eval( + <*>Pexp_match(Pexp_ident:someOtherValue) + case 1: + pattern<*>: + <*>Ppat_record( + fields: + other2: Ppat_extension(%rescript.patternhole) + ) + expr: + Pexp_construct(()) +) + +Dump AST src/TypedContextCompletionSpec.res 182:55 + +Source: +// switch someVal { | {something: {whatIsThis: false | } } => () } +// ^ast + + +Pstr_eval( + <*>Pexp_match(Pexp_ident:someVal) + case 1: + pattern<*>: + <*>Ppat_record( + fields: + something: <*>Ppat_record( + fields: + whatIsThis: Ppat_or( + Ppat_construct(false), + Ppat_extension(%rescript.patternhole) + ) + ) + ) + expr: + Pexp_construct(()) +) + +Dump AST src/TypedContextCompletionSpec.res 185:46 + +Source: +// switch someVal { | {something: {whatIsThis: } } => () } +// ^ast + + +Pstr_eval( + <*>Pexp_match(Pexp_ident:someVal) + case 1: + pattern<*>: + <*>Ppat_record( + fields: + something: <*>Ppat_record( + fields: + whatIsThis: Ppat_extension(%rescript.patternhole) + ) + ) + expr: + Pexp_construct(()) +) + +Dump AST src/TypedContextCompletionSpec.res 188:49 + +Source: +// switch someVal { | {something: {whatIsThis: fa } } => () } +// ^ast + + +Pstr_eval( + <*>Pexp_match(Pexp_ident:someVal) + case 1: + pattern<*>: + <*>Ppat_record( + fields: + something: <*>Ppat_record( + fields: + whatIsThis: Ppat_var(<*>fa) + ) + ) + expr: + Pexp_construct(()) +) + +Dump AST src/TypedContextCompletionSpec.res 192:15 + +Source: +// switch x { | } +// ^ast + + +Pstr_eval( + <*>Pexp_match(Pexp_ident:x) + case 1: + pattern: + Ppat_extension(%rescript.patternhole) + expr: + Pexp_extension(%rescript.exprhole) +) + +Dump AST src/TypedContextCompletionSpec.res 196:14 + + +Dump AST src/TypedContextCompletionSpec.res 199:15 + +Source: +// switch y { | } +// ^ast + + +Pstr_eval( + <*>Pexp_match(Pexp_ident:y) + case 1: + pattern: + Ppat_extension(%rescript.patternhole) + expr: + Pexp_extension(%rescript.exprhole) +) + +Dump AST src/TypedContextCompletionSpec.res 202:36 + +Source: +// switch y { | One | Two | Three | } +// ^ast + + +Pstr_eval( + <*>Pexp_match(Pexp_ident:y) + case 1: + pattern: + Ppat_or( + Ppat_or( + Ppat_or( + Ppat_construct(One), + Ppat_construct(Two) + ), + Ppat_construct(Three) + ), + Ppat_extension(%rescript.patternhole) + ) + expr: + Pexp_extension(%rescript.exprhole) +) + +Dump AST src/TypedContextCompletionSpec.res 206:33 + +Source: +// switch someVal { | {something: } => () } +// ^ast + + +Pstr_eval( + <*>Pexp_match(Pexp_ident:someVal) + case 1: + pattern<*>: + <*>Ppat_record( + fields: + something: Ppat_extension(%rescript.patternhole) + ) + expr: + Pexp_construct(()) +) + +Dump AST src/TypedContextCompletionSpec.res 210:22 + +Source: +// switch someVal { | => () } +// ^ast + + +Pstr_eval( + <*>Pexp_match(Pexp_ident:someVal) + case 1: + pattern: + Ppat_construct(()) + expr: + Pexp_extension(%rescript.exprhole) +) + +Dump AST src/TypedContextCompletionSpec.res 214:35 + +Source: +// switch someVal { | {something: {} } => () } +// ^ast + + +Pstr_eval( + <*>Pexp_match(Pexp_ident:someVal) + case 1: + pattern<*>: + <*>Ppat_record( + fields: + something: <*>Ppat_record( + fields: + + ) + ) + expr: + Pexp_construct(()) +) + diff --git a/analysis/tests/src/expected/TypedContextCompletionSpec.res.txt b/analysis/tests/src/expected/TypedContextCompletionSpec.res.txt new file mode 100644 index 000000000..66239d087 --- /dev/null +++ b/analysis/tests/src/expected/TypedContextCompletionSpec.res.txt @@ -0,0 +1,2838 @@ +Dump AST src/TypedContextCompletionSpec.res 49:40 + +Source: +// let x = someVariantToString(~someVaria +// ^ast + +<*>Pstr_value( + value: + Ppat_var(x) + expr: + <*>Pexp_apply( + expr: + Pexp_ident:someVariantToString + args: + <*>~someVaria= + [@ns.namedArgLoc]<*>Pexp_ident:someVaria + ) +) + +Dump AST src/TypedContextCompletionSpec.res 53:43 + +Source: +// let x = someVariantToString(~someVariant= +// ^ast + +<*>Pstr_value( + value: + Ppat_var(x) + expr: + <*>Pexp_apply( + expr: + Pexp_ident:someVariantToString + args: + <*>~someVariant= + [@ns.namedArgLoc]Pexp_extension(%rescript.exprhole) + ) +) + + +Dump AST src/TypedContextCompletionSpec.res 61:44 + +Source: +// let x = someVariantToString(~someVariant=T +// ^ast + +<*>Pstr_value( + value: + Ppat_var(x) + expr: + <*>Pexp_apply( + expr: + Pexp_ident:someVariantToString + args: + ~someVariant= + [@ns.namedArgLoc]<*>Pexp_construct(<*>T) + ) +) + +Dump AST src/TypedContextCompletionSpec.res 65:44 + +Source: +// let x = someVariantToString(~someVariant=t +// ^ast + +<*>Pstr_value( + value: + Ppat_var(x) + expr: + <*>Pexp_apply( + expr: + Pexp_ident:someVariantToString + args: + ~someVariant= + [@ns.namedArgLoc]<*>Pexp_ident:t + ) +) + +Dump AST src/TypedContextCompletionSpec.res 69:58 + +Source: +// let x = someVariantToString(~someVariant=TypeDefinition. +// ^ast + +<*>Pstr_value( + value: + Ppat_var(x) + expr: + <*>Pexp_apply( + expr: + Pexp_ident:someVariantToString + args: + ~someVariant= + [@ns.namedArgLoc]<*>Pexp_ident:TypeDefinition."" + ) +) + +Dump AST src/TypedContextCompletionSpec.res 73:44 + +Source: +// let x = someVariantToString(~anotherThing= +// ^ast + +<*>Pstr_value( + value: + Ppat_var(x) + expr: + <*>Pexp_apply( + expr: + Pexp_ident:someVariantToString + args: + <*>~anotherThing= + [@ns.namedArgLoc]Pexp_extension(%rescript.exprhole) + ) +) + +Dump AST src/TypedContextCompletionSpec.res 77:42 + +Source: +// let x = someVariantToString(~thirdThing= +// ^ast + +<*>Pstr_value( + value: + Ppat_var(x) + expr: + <*>Pexp_apply( + expr: + Pexp_ident:someVariantToString + args: + <*>~thirdThing= + [@ns.namedArgLoc]Pexp_extension(%rescript.exprhole) + ) +) + +Dump AST src/TypedContextCompletionSpec.res 81:44 + +Source: +// let x = someVariantToString(~thirdThing=#t +// ^ast + +<*>Pstr_value( + value: + Ppat_var(x) + expr: + <*>Pexp_apply( + expr: + Pexp_ident:someVariantToString + args: + ~thirdThing= + [@ns.namedArgLoc]<*>Pexp_variant(t) + ) +) + +Dump AST src/TypedContextCompletionSpec.res 85:44 + +Source: +// let x = someVariantToString(~thirdThing=#T +// ^ast + +<*>Pstr_value( + value: + Ppat_var(x) + expr: + <*>Pexp_apply( + expr: + Pexp_ident:someVariantToString + args: + ~thirdThing= + [@ns.namedArgLoc]<*>Pexp_variant(T) + ) +) + +Complete src/TypedContextCompletionSpec.res 93:36 +posCursor:[93:36] posNoWhite:[93:35] Found expr:[93:11->93:47] +Pexp_apply ...[93:11->93:18] (~doThing93:20->93:27=...[93:28->93:46]) +posCursor:[93:36] posNoWhite:[93:35] Found expr:[93:28->93:46] +posCursor:[93:36] posNoWhite:[93:35] Found pattern:[93:29->93:37] +posCursor:[93:36] posNoWhite:[93:35] Found pattern:[93:35->93:36] +[] + +Complete src/TypedContextCompletionSpec.res 97:15 +posCursor:[97:15] posNoWhite:[97:14] Found pattern:[97:7->97:16] +posCursor:[97:15] posNoWhite:[97:14] Found pattern:[97:8->97:15] +Completable: CtypedPattern(sourceType:Value[someVal], lookingToComplete:CRecordField, patternType:Destructure, prefix:another, pattern: [], seenIdents: [another]) +[{ + "label": "anotherThing", + "kind": 5, + "tags": [], + "detail": "anotherThing: option\n\ntype anotherRecord = {\n something: someRecord,\n anotherThing: option,\n thirdThing: string,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypedContextCompletionSpec.res 101:23 +posCursor:[101:23] posNoWhite:[101:22] Found pattern:[101:7->101:24] +posCursor:[101:23] posNoWhite:[101:22] Found pattern:[101:22->101:23] +Completable: CtypedPattern(sourceType:Value[someVal], lookingToComplete:CRecordField, patternType:Destructure, prefix:s, pattern: [], seenIdents: [anotherThing, s]) +[{ + "label": "something", + "kind": 5, + "tags": [], + "detail": "something: someRecord\n\ntype anotherRecord = {\n something: someRecord,\n anotherThing: option,\n thirdThing: string,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypedContextCompletionSpec.res 105:8 +posCursor:[105:8] posNoWhite:[105:7] Found pattern:[105:7->105:9] +Completable: CtypedPattern(sourceType:Value[someVal], lookingToComplete:CRecordField, patternType:Destructure, prefix:"", pattern: [], seenIdents: []) +[{ + "label": "something", + "kind": 5, + "tags": [], + "detail": "something: someRecord\n\ntype anotherRecord = {\n something: someRecord,\n anotherThing: option,\n thirdThing: string,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "anotherThing", + "kind": 5, + "tags": [], + "detail": "anotherThing: option\n\ntype anotherRecord = {\n something: someRecord,\n anotherThing: option,\n thirdThing: string,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "thirdThing", + "kind": 5, + "tags": [], + "detail": "thirdThing: string\n\ntype anotherRecord = {\n something: someRecord,\n anotherThing: option,\n thirdThing: string,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypedContextCompletionSpec.res 109:8 +posCursor:[109:8] posNoWhite:[109:7] Found pattern:[109:7->109:9] +Completable: CtypedPattern(sourceType:Value[getSomeVal](~irrelevant), lookingToComplete:CRecordField, patternType:Destructure, prefix:"", pattern: [], seenIdents: []) +[{ + "label": "something", + "kind": 5, + "tags": [], + "detail": "something: someRecord\n\ntype anotherRecord = {\n something: someRecord,\n anotherThing: option,\n thirdThing: string,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "anotherThing", + "kind": 5, + "tags": [], + "detail": "anotherThing: option\n\ntype anotherRecord = {\n something: someRecord,\n anotherThing: option,\n thirdThing: string,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "thirdThing", + "kind": 5, + "tags": [], + "detail": "thirdThing: string\n\ntype anotherRecord = {\n something: someRecord,\n anotherThing: option,\n thirdThing: string,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypedContextCompletionSpec.res 113:20 +posCursor:[113:20] posNoWhite:[113:19] Found pattern:[113:7->113:22] +posCursor:[113:20] posNoWhite:[113:19] Found pattern:[113:19->113:21] +Completable: CtypedPattern(sourceType:Value[someVal], lookingToComplete:CRecordField, patternType:Destructure, prefix:"", pattern: [RecordField:something], seenIdents: []) +[{ + "label": "somethingElse", + "kind": 5, + "tags": [], + "detail": "somethingElse: int\n\ntype someRecord = {\n somethingElse: int,\n whatIsThis: bool,\n anotherLevel: anotherLevel,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "whatIsThis", + "kind": 5, + "tags": [], + "detail": "whatIsThis: bool\n\ntype someRecord = {\n somethingElse: int,\n whatIsThis: bool,\n anotherLevel: anotherLevel,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "anotherLevel", + "kind": 5, + "tags": [], + "detail": "anotherLevel: anotherLevel\n\ntype someRecord = {\n somethingElse: int,\n whatIsThis: bool,\n anotherLevel: anotherLevel,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypedContextCompletionSpec.res 117:47 +posCursor:[117:47] posNoWhite:[117:46] Found pattern:[117:7->117:50] +posCursor:[117:47] posNoWhite:[117:46] Found pattern:[117:19->117:49] +posCursor:[117:47] posNoWhite:[117:46] Found pattern:[117:46->117:48] +Completable: CtypedPattern(sourceType:Value[someVal], lookingToComplete:CRecordField, patternType:Destructure, prefix:"", pattern: [RecordField:something, RecordField:anotherLevel], seenIdents: []) +[{ + "label": "level", + "kind": 5, + "tags": [], + "detail": "level: int\n\ntype anotherLevel = {level: int, someOtherArg: bool}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "someOtherArg", + "kind": 5, + "tags": [], + "detail": "someOtherArg: bool\n\ntype anotherLevel = {level: int, someOtherArg: bool}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypedContextCompletionSpec.res 121:48 +posCursor:[121:48] posNoWhite:[121:47] Found pattern:[121:7->121:51] +posCursor:[121:48] posNoWhite:[121:47] Found pattern:[121:19->121:50] +posCursor:[121:48] posNoWhite:[121:47] Found pattern:[121:46->121:49] +posCursor:[121:48] posNoWhite:[121:47] Found pattern:[121:47->121:48] +Completable: CtypedPattern(sourceType:Value[someVal], lookingToComplete:CRecordField, patternType:Destructure, prefix:l, pattern: [RecordField:something, RecordField:anotherLevel], seenIdents: [l]) +[{ + "label": "level", + "kind": 5, + "tags": [], + "detail": "level: int\n\ntype anotherLevel = {level: int, someOtherArg: bool}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypedContextCompletionSpec.res 125:47 +posCursor:[125:47] posNoWhite:[125:44] Found pattern:[125:7->125:49] +posCursor:[125:47] posNoWhite:[125:44] Found pattern:[125:19->125:48] +Completable: CtypedPattern(sourceType:Value[someVal], lookingToComplete:CRecordField, patternType:Destructure, prefix:"", pattern: [RecordField:something], seenIdents: [whatIsThis, anotherLevel]) +[{ + "label": "somethingElse", + "kind": 5, + "tags": [], + "detail": "somethingElse: int\n\ntype someRecord = {\n somethingElse: int,\n whatIsThis: bool,\n anotherLevel: anotherLevel,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypedContextCompletionSpec.res 129:31 +posCursor:[129:31] posNoWhite:[129:30] Found pattern:[129:7->129:47] +posCursor:[129:31] posNoWhite:[129:30] Found pattern:[129:19->129:46] +Completable: CtypedPattern(sourceType:Value[someVal], lookingToComplete:CRecordField, patternType:Destructure, prefix:"", pattern: [RecordField:something], seenIdents: [whatIsThis, anotherLevel]) +[{ + "label": "somethingElse", + "kind": 5, + "tags": [], + "detail": "somethingElse: int\n\ntype someRecord = {\n somethingElse: int,\n whatIsThis: bool,\n anotherLevel: anotherLevel,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypedContextCompletionSpec.res 137:44 +posCursor:[137:44] posNoWhite:[137:43] Found expr:[137:3->137:54] +posCursor:[137:44] posNoWhite:[137:43] Found pattern:[137:22->137:46] +posCursor:[137:44] posNoWhite:[137:43] Found pattern:[137:42->137:45] +Completable: CtypedPattern(sourceType:Value[someVal], lookingToComplete:CRecordField, patternType:Switch, prefix:som, pattern: [], seenIdents: [thirdThing, som]) +[{ + "label": "something", + "kind": 5, + "tags": [], + "detail": "something: someRecord\n\ntype anotherRecord = {\n something: someRecord,\n anotherThing: option,\n thirdThing: string,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypedContextCompletionSpec.res 141:52 +posCursor:[141:52] posNoWhite:[141:51] Found expr:[141:3->141:61] +posCursor:[141:52] posNoWhite:[141:51] Found pattern:[141:51->141:53] +Completable: CtypedPattern(sourceType:Value[someVal], lookingToComplete:CRecordField, patternType:Switch, prefix:"", pattern: [], seenIdents: []) +[{ + "label": "something", + "kind": 5, + "tags": [], + "detail": "something: someRecord\n\ntype anotherRecord = {\n something: someRecord,\n anotherThing: option,\n thirdThing: string,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "anotherThing", + "kind": 5, + "tags": [], + "detail": "anotherThing: option\n\ntype anotherRecord = {\n something: someRecord,\n anotherThing: option,\n thirdThing: string,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "thirdThing", + "kind": 5, + "tags": [], + "detail": "thirdThing: string\n\ntype anotherRecord = {\n something: someRecord,\n anotherThing: option,\n thirdThing: string,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypedContextCompletionSpec.res 145:89 +posCursor:[145:89] posNoWhite:[145:88] Found expr:[145:3->145:100] +posCursor:[145:89] posNoWhite:[145:88] Found pattern:[145:51->145:92] +posCursor:[145:89] posNoWhite:[145:88] Found pattern:[145:63->145:91] +Completable: CtypedPattern(sourceType:Value[someVal], lookingToComplete:CRecordField, patternType:Switch, prefix:"", pattern: [RecordField:something], seenIdents: [whatIsThis, anotherLevel]) +[{ + "label": "somethingElse", + "kind": 5, + "tags": [], + "detail": "somethingElse: int\n\ntype someRecord = {\n somethingElse: int,\n whatIsThis: bool,\n anotherLevel: anotherLevel,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypedContextCompletionSpec.res 149:48 +posCursor:[149:48] posNoWhite:[149:47] Found expr:[149:3->149:57] +posCursor:[149:48] posNoWhite:[149:47] Found pattern:[149:29->149:49] +posCursor:[149:48] posNoWhite:[149:47] Found pattern:[149:41->149:48] +posCursor:[149:48] posNoWhite:[149:47] Found pattern:[149:47->149:48] +Ppat_construct T:[149:47->149:48] +Completable: CtypedPattern(sourceType:Value[someOtherValue], lookingToComplete:CVariant, patternType:Switch, prefix:T, pattern: [RecordField:something], seenIdents: [Two, T]) +[{ + "label": "Three(_)", + "kind": 4, + "tags": [], + "detail": "Three(int)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Three(${1:_})", + "insertTextFormat": 2 + }] + +Complete src/TypedContextCompletionSpec.res 152:48 +posCursor:[152:48] posNoWhite:[152:47] Found expr:[152:3->152:58] +posCursor:[152:48] posNoWhite:[152:47] Found pattern:[152:29->152:50] +posCursor:[152:48] posNoWhite:[152:47] Found pattern:[152:42->152:49] +Ppat_construct Some:[152:42->152:46] +posCursor:[152:48] posNoWhite:[152:47] Found pattern:[152:47->152:48] +Ppat_construct T:[152:47->152:48] +Completable: CtypedPattern(sourceType:Value[someOtherValue], lookingToComplete:CVariant, patternType:Switch, prefix:T, pattern: [RecordField:otherThing, Variant:Some(0)], seenIdents: []) +[{ + "label": "Two", + "kind": 4, + "tags": [], + "detail": "Two\n\n", + "documentation": null, + "sortText": null, + "insertText": "Two", + "insertTextFormat": 2 + }, { + "label": "Three(_)", + "kind": 4, + "tags": [], + "detail": "Three(int)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Three(${1:_})", + "insertTextFormat": 2 + }] + +Complete src/TypedContextCompletionSpec.res 155:47 +posCursor:[155:47] posNoWhite:[155:46] Found expr:[155:3->155:57] +posCursor:[155:47] posNoWhite:[155:46] Found pattern:[155:29->155:49] +posCursor:[155:47] posNoWhite:[155:46] Found pattern:[155:42->155:48] +posCursor:[155:47] posNoWhite:[155:46] Found pattern:[155:46->155:47] +Ppat_construct T:[155:46->155:47] +Completable: CtypedPattern(sourceType:Value[someOtherValue], lookingToComplete:CVariant, patternType:Switch, prefix:T, pattern: [RecordField:thirdStuff, Tuple:1], seenIdents: []) +[{ + "label": "Two", + "kind": 4, + "tags": [], + "detail": "Two\n\n", + "documentation": null, + "sortText": null, + "insertText": "Two", + "insertTextFormat": 2 + }, { + "label": "Three(_)", + "kind": 4, + "tags": [], + "detail": "Three(int)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Three(${1:_})", + "insertTextFormat": 2 + }] + +Complete src/TypedContextCompletionSpec.res 158:51 +posCursor:[158:51] posNoWhite:[158:50] Found expr:[158:3->158:62] +posCursor:[158:51] posNoWhite:[158:50] Found pattern:[158:29->158:54] +posCursor:[158:51] posNoWhite:[158:50] Found pattern:[158:42->158:53] +posCursor:[158:51] posNoWhite:[158:50] Found pattern:[158:46->158:52] +Ppat_construct Four:[158:46->158:50] +posCursor:[158:51] posNoWhite:[158:50] Found pattern:[158:50->158:52] +Ppat_construct ():[158:50->158:52] +Completable: CtypedPattern(sourceType:Value[someOtherValue], lookingToComplete:CNoContext, patternType:Switch, prefix:"", pattern: [RecordField:thirdStuff, Tuple:1, Variant:Four(0)], seenIdents: []) +[{ + "label": "TwentyFive", + "kind": 4, + "tags": [], + "detail": "TwentyFive\n\n", + "documentation": null, + "sortText": null, + "insertText": "TwentyFive", + "insertTextFormat": 2 + }, { + "label": "SixtyTwo", + "kind": 4, + "tags": [], + "detail": "SixtyTwo\n\n", + "documentation": null, + "sortText": null, + "insertText": "SixtyTwo", + "insertTextFormat": 2 + }] + +Complete src/TypedContextCompletionSpec.res 161:55 +posCursor:[161:55] posNoWhite:[161:54] Found expr:[161:3->161:66] +posCursor:[161:55] posNoWhite:[161:54] Found pattern:[161:29->161:58] +posCursor:[161:55] posNoWhite:[161:54] Found pattern:[161:42->161:57] +posCursor:[161:55] posNoWhite:[161:54] Found pattern:[161:46->161:56] +Ppat_construct Five:[161:46->161:50] +posCursor:[161:55] posNoWhite:[161:54] Found pattern:[161:50->161:57] +posCursor:[161:55] posNoWhite:[161:54] Found pattern:[161:54->161:55] +Ppat_construct O:[161:54->161:55] +Completable: CtypedPattern(sourceType:Value[someOtherValue], lookingToComplete:CVariant, patternType:Switch, prefix:O, pattern: [RecordField:thirdStuff, Tuple:1, Variant:Five(1)], seenIdents: []) +[{ + "label": "One", + "kind": 4, + "tags": [], + "detail": "One\n\n", + "documentation": null, + "sortText": null, + "insertText": "One", + "insertTextFormat": 2 + }] + +Complete src/TypedContextCompletionSpec.res 164:63 +posCursor:[164:63] posNoWhite:[164:62] Found expr:[164:3->164:78] +posCursor:[164:63] posNoWhite:[164:62] Found pattern:[164:29->164:70] +posCursor:[164:63] posNoWhite:[164:62] Found pattern:[164:43->164:69] +posCursor:[164:63] posNoWhite:[164:62] Found pattern:[164:44->164:65] +Ppat_construct Some:[164:44->164:48] +posCursor:[164:63] posNoWhite:[164:62] Found pattern:[164:49->164:64] +posCursor:[164:63] posNoWhite:[164:62] Found pattern:[164:62->164:63] +Ppat_construct O:[164:62->164:63] +Completable: CtypedPattern(sourceType:Value[someOtherValue], lookingToComplete:CVariant, patternType:Switch, prefix:O, pattern: [RecordField:fourthStuff, Tuple:0, Variant:Some(0), Variant:WithPayload(0)], seenIdents: []) +[] + +Complete src/TypedContextCompletionSpec.res 167:67 +posCursor:[167:67] posNoWhite:[167:66] Found expr:[167:3->167:78] +posCursor:[167:67] posNoWhite:[167:66] Found pattern:[167:29->167:70] +posCursor:[167:67] posNoWhite:[167:66] Found pattern:[167:42->167:69] +posCursor:[167:67] posNoWhite:[167:66] Found pattern:[167:46->167:68] +Ppat_construct Five:[167:46->167:50] +posCursor:[167:67] posNoWhite:[167:66] Found pattern:[167:50->167:69] +posCursor:[167:67] posNoWhite:[167:66] Found pattern:[167:54->167:67] +posCursor:[167:67] posNoWhite:[167:66] Found pattern:[167:66->167:67] +Ppat_construct T:[167:66->167:67] +Completable: CtypedPattern(sourceType:Value[someOtherValue], lookingToComplete:CVariant, patternType:Switch, prefix:T, pattern: [RecordField:thirdStuff, Tuple:1, Variant:Five(1)], seenIdents: [One, Two, T]) +[{ + "label": "Three(_)", + "kind": 4, + "tags": [], + "detail": "Three(int)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Three(${1:_})", + "insertTextFormat": 2 + }] + +Complete src/TypedContextCompletionSpec.res 170:43 +posCursor:[170:43] posNoWhite:[170:42] Found expr:[170:3->170:52] +posCursor:[170:43] posNoWhite:[170:42] Found pattern:[170:29->170:44] +posCursor:[170:43] posNoWhite:[170:42] Found pattern:[170:42->170:43] +Ppat_construct S:[170:42->170:43] +Completable: CtypedPattern(sourceType:Value[someOtherValue], lookingToComplete:CVariant, patternType:Switch, prefix:S, pattern: [RecordField:otherThing], seenIdents: []) +[{ + "label": "None", + "kind": 4, + "tags": [], + "detail": "None\n\n", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Some(One)", + "kind": 4, + "tags": [], + "detail": "One\n\n", + "documentation": null, + "sortText": null, + "insertText": "Some(One)", + "insertTextFormat": 2 + }, { + "label": "Some(Two)", + "kind": 4, + "tags": [], + "detail": "Two\n\n", + "documentation": null, + "sortText": null, + "insertText": "Some(Two)", + "insertTextFormat": 2 + }, { + "label": "Some(Three(_))", + "kind": 4, + "tags": [], + "detail": "Three(int)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Some(Three(${1:_}))", + "insertTextFormat": 2 + }, { + "label": "Some(Four(_))", + "kind": 4, + "tags": [], + "detail": "Four(someOtherVariant)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Some(Four(${1:_}))", + "insertTextFormat": 2 + }, { + "label": "Some(Five(_))", + "kind": 4, + "tags": [], + "detail": "Five(someOtherVariant, someVariant)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Some(Five(${1:_}))", + "insertTextFormat": 2 + }] + +Complete src/TypedContextCompletionSpec.res 173:39 +posCursor:[173:39] posNoWhite:[173:38] Found expr:[173:3->173:48] +posCursor:[173:39] posNoWhite:[173:38] Found pattern:[173:29->173:40] +posCursor:[173:39] posNoWhite:[173:38] Found pattern:[173:38->173:39] +Ppat_construct S:[173:38->173:39] +Completable: CtypedPattern(sourceType:Value[someOtherValue], lookingToComplete:CVariant, patternType:Switch, prefix:S, pattern: [RecordField:other2], seenIdents: []) +[{ + "label": "None", + "kind": 4, + "tags": [], + "detail": "None\n\n", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Some(_)", + "kind": 4, + "tags": [], + "detail": "Some(_)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Some(${1:_})", + "insertTextFormat": 2 + }] + +Complete src/TypedContextCompletionSpec.res 176:64 +posCursor:[176:64] posNoWhite:[176:62] Found expr:[176:3->176:75] +posCursor:[176:64] posNoWhite:[176:62] Found pattern:[176:29->176:67] +posCursor:[176:64] posNoWhite:[176:62] Found pattern:[176:42->176:66] +posCursor:[176:64] posNoWhite:[176:62] Found pattern:[176:46->176:65] +Ppat_construct Four:[176:46->176:50] +Completable: Cpath Value[Four] +[] + +Complete src/TypedContextCompletionSpec.res 179:38 +posCursor:[179:38] posNoWhite:[179:36] Found expr:[179:3->179:47] +posCursor:[179:38] posNoWhite:[179:36] Found pattern:[179:29->179:39] +Completable: CtypedPattern(sourceType:Value[someOtherValue], lookingToComplete:CNoContext, patternType:Switch, prefix:"", pattern: [RecordField:other2], seenIdents: []) +[{ + "label": "None", + "kind": 4, + "tags": [], + "detail": "None\n\n", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Some(_)", + "kind": 4, + "tags": [], + "detail": "Some(_)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Some(${1:_})", + "insertTextFormat": 2 + }] + +Complete src/TypedContextCompletionSpec.res 182:55 +posCursor:[182:55] posNoWhite:[182:53] Found expr:[182:3->182:67] +posCursor:[182:55] posNoWhite:[182:53] Found pattern:[182:22->182:59] +posCursor:[182:55] posNoWhite:[182:53] Found pattern:[182:34->182:59] +Completable: CtypedPattern(sourceType:Value[someVal], lookingToComplete:CNoContext, patternType:Switch, prefix:"", pattern: [RecordField:something, RecordField:whatIsThis], seenIdents: [false]) +[{ + "label": "true", + "kind": 12, + "tags": [], + "detail": "boolean\n\n", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypedContextCompletionSpec.res 185:46 +posCursor:[185:46] posNoWhite:[185:45] Found expr:[185:3->185:58] +posCursor:[185:46] posNoWhite:[185:45] Found pattern:[185:22->185:50] +posCursor:[185:46] posNoWhite:[185:45] Found pattern:[185:34->185:50] +Completable: CtypedPattern(sourceType:Value[someVal], lookingToComplete:CNoContext, patternType:Switch, prefix:"", pattern: [RecordField:something, RecordField:whatIsThis], seenIdents: []) +[{ + "label": "false", + "kind": 12, + "tags": [], + "detail": "boolean\n\n", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "true", + "kind": 12, + "tags": [], + "detail": "boolean\n\n", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypedContextCompletionSpec.res 188:49 +posCursor:[188:49] posNoWhite:[188:48] Found expr:[188:3->188:62] +posCursor:[188:49] posNoWhite:[188:48] Found pattern:[188:22->188:54] +posCursor:[188:49] posNoWhite:[188:48] Found pattern:[188:34->188:52] +posCursor:[188:49] posNoWhite:[188:48] Found pattern:[188:47->188:49] +Completable: CtypedPattern(sourceType:Value[someVal], lookingToComplete:CVariant, patternType:Switch, prefix:fa, pattern: [RecordField:something, RecordField:whatIsThis], seenIdents: []) +[{ + "label": "false", + "kind": 12, + "tags": [], + "detail": "boolean\n\n", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypedContextCompletionSpec.res 192:15 +posCursor:[192:15] posNoWhite:[192:14] Found expr:[192:3->192:17] +Completable: CtypedPattern(sourceType:Value[x], lookingToComplete:CNoContext, patternType:Switch, prefix:"", pattern: [], seenIdents: []) +[{ + "label": "None", + "kind": 4, + "tags": [], + "detail": "None\n\n", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Some(One)", + "kind": 4, + "tags": [], + "detail": "One\n\n", + "documentation": null, + "sortText": null, + "insertText": "Some(One)", + "insertTextFormat": 2 + }, { + "label": "Some(Two)", + "kind": 4, + "tags": [], + "detail": "Two\n\n", + "documentation": null, + "sortText": null, + "insertText": "Some(Two)", + "insertTextFormat": 2 + }, { + "label": "Some(Three(_))", + "kind": 4, + "tags": [], + "detail": "Three(int)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Some(Three(${1:_}))", + "insertTextFormat": 2 + }, { + "label": "Some(Four(_))", + "kind": 4, + "tags": [], + "detail": "Four(someOtherVariant)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Some(Four(${1:_}))", + "insertTextFormat": 2 + }, { + "label": "Some(Five(_))", + "kind": 4, + "tags": [], + "detail": "Five(someOtherVariant, someVariant)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Some(Five(${1:_}))", + "insertTextFormat": 2 + }] + +Complete src/TypedContextCompletionSpec.res 196:14 +posCursor:[196:14] posNoWhite:[196:12] Found expr:[196:3->196:13] +[] + +Complete src/TypedContextCompletionSpec.res 199:15 +posCursor:[199:15] posNoWhite:[199:14] Found expr:[199:3->199:17] +Completable: CtypedPattern(sourceType:Value[y], lookingToComplete:CNoContext, patternType:Switch, prefix:"", pattern: [], seenIdents: []) +[{ + "label": "One", + "kind": 4, + "tags": [], + "detail": "One\n\n", + "documentation": null, + "sortText": null, + "insertText": "One", + "insertTextFormat": 2 + }, { + "label": "Two", + "kind": 4, + "tags": [], + "detail": "Two\n\n", + "documentation": null, + "sortText": null, + "insertText": "Two", + "insertTextFormat": 2 + }, { + "label": "Three(_)", + "kind": 4, + "tags": [], + "detail": "Three(int)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Three(${1:_})", + "insertTextFormat": 2 + }, { + "label": "Four(_)", + "kind": 4, + "tags": [], + "detail": "Four(someOtherVariant)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Four(${1:_})", + "insertTextFormat": 2 + }, { + "label": "Five(_)", + "kind": 4, + "tags": [], + "detail": "Five(someOtherVariant, someVariant)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Five(${1:_})", + "insertTextFormat": 2 + }] + +Complete src/TypedContextCompletionSpec.res 202:36 +posCursor:[202:36] posNoWhite:[202:34] Found expr:[202:3->202:38] +Completable: CtypedPattern(sourceType:Value[y], lookingToComplete:CNoContext, patternType:Switch, prefix:"", pattern: [], seenIdents: [One, Two, Three]) +[{ + "label": "Four(_)", + "kind": 4, + "tags": [], + "detail": "Four(someOtherVariant)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Four(${1:_})", + "insertTextFormat": 2 + }, { + "label": "Five(_)", + "kind": 4, + "tags": [], + "detail": "Five(someOtherVariant, someVariant)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Five(${1:_})", + "insertTextFormat": 2 + }] + +Complete src/TypedContextCompletionSpec.res 206:33 +posCursor:[206:33] posNoWhite:[206:32] Found expr:[206:3->206:44] +posCursor:[206:33] posNoWhite:[206:32] Found pattern:[206:22->206:36] +Completable: CtypedPattern(sourceType:Value[someVal], lookingToComplete:CNoContext, patternType:Switch, prefix:"", pattern: [RecordField:something], seenIdents: []) +[{ + "label": "{}", + "kind": 4, + "tags": [], + "detail": "Empty record", + "documentation": null, + "sortText": "a", + "insertText": "{${1}}", + "insertTextFormat": 2 + }] + +Complete src/TypedContextCompletionSpec.res 210:22 +posCursor:[210:22] posNoWhite:[210:20] Found expr:[210:3->210:30] +Completable: Cpath Value[""] +[{ + "label": "y", + "kind": 12, + "tags": [], + "detail": "someVariant", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "x", + "kind": 12, + "tags": [], + "detail": "option", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "someOtherValue", + "kind": 12, + "tags": [], + "detail": "someRecordWithVariant", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "getSomeVal", + "kind": 12, + "tags": [], + "detail": "(~irrelevant: int) => anotherRecord", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "someVal", + "kind": 12, + "tags": [], + "detail": "anotherRecord", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Arg", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Array", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "ArrayLabels", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Auto", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_Array", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_Float", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_HashMap", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_HashMapInt", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_HashMapString", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_HashSet", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_HashSetInt", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_HashSetString", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_Id", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_Int", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_List", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_Map", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_MapDict", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_MapInt", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_MapString", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_MutableMap", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_MutableMapInt", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_MutableMapString", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_MutableQueue", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_MutableSet", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_MutableSetInt", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_MutableSetString", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_MutableStack", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_Option", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_Range", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_Result", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_Set", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_SetDict", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_SetInt", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_SetString", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_SortArray", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_SortArrayInt", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_SortArrayString", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_internalAVLset", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_internalAVLtree", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_internalBuckets", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_internalBucketsType", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_internalMapInt", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_internalMapString", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_internalSetBuckets", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_internalSetInt", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_internalSetString", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Belt_internals", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "BrokenParserCases", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Buffer", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Bytes", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "BytesLabels", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Callback", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "CamlinternalLazy", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "CamlinternalMod", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Char", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "CodeLens", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "CompletePrioritize1", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "CompletePrioritize2", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Completion", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Complex", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Component", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "CreateInterface", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Cross", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Dce", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Debug", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Definition", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "DefinitionWithInterface", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Digest", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Div", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "DocumentSymbol", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Dom", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Dom_storage", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Dom_storage2", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Filename", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Fragment", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Genlex", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Hashtbl", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "HashtblLabels", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Highlight", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Hover", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "InlayHint", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Int32", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Int64", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Js", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Js_OO", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Js_array", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Js_array2", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Js_bigint", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Js_cast", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Js_console", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Js_date", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Js_dict", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Js_exn", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Js_float", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Js_global", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Js_int", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Js_json", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Js_list", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Js_mapperRt", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Js_math", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Js_null", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Js_null_undefined", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Js_obj", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Js_option", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Js_promise", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Js_re", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Js_result", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Js_string", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Js_string2", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Js_typed_array", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Js_typed_array2", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Js_types", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Js_undefined", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Js_vector", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Jsx", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Lazy", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Lexing", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "List", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "ListLabels", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "LongIdentTest", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Map", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "MapLabels", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "MoreLabels", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Node", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Node_buffer", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Node_child_process", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Node_fs", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Node_module", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Node_path", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Node_process", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Obj", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Object", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Parsing", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Patterns", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Pervasives", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Printexc", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Queue", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Random", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "React", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "ReactDOM", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "ReactDOMRe", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "ReactDOMServer", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "ReactDOMStyle", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "ReactEvent", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "ReactTestUtils", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "ReasonReact", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "RecModules", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "RecordCompletion", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "RecoveryOnProp", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "References", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "ReferencesWithInterface", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Rename", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "RenameWithInterface", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "RescriptReactErrorBoundary", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "RescriptReactRouter", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Set", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "SetLabels", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Sort", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Stack", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "StdLabels", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Stream", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "String", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "StringLabels", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Sys", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "TableclothMap", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "TypeContextCompletion_Jsx", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "TypeContextCompletion_LabelledArguments", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "TypeContextCompletion_Records", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "TypeDefinition", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "TypedContextCompletionSpec", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Uchar", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Xform", + "kind": 9, + "tags": [], + "detail": "file module", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypedContextCompletionSpec.res 214:23 +posCursor:[214:23] posNoWhite:[214:22] Found expr:[214:3->214:32] +posCursor:[214:23] posNoWhite:[214:22] Found pattern:[214:22->214:24] +Completable: CtypedPattern(sourceType:Value[someVal], lookingToComplete:CRecordField, patternType:Switch, prefix:"", pattern: [], seenIdents: []) +[{ + "label": "something", + "kind": 5, + "tags": [], + "detail": "something: someRecord\n\ntype anotherRecord = {\n something: someRecord,\n anotherThing: option,\n thirdThing: string,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "anotherThing", + "kind": 5, + "tags": [], + "detail": "anotherThing: option\n\ntype anotherRecord = {\n something: someRecord,\n anotherThing: option,\n thirdThing: string,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "thirdThing", + "kind": 5, + "tags": [], + "detail": "thirdThing: string\n\ntype anotherRecord = {\n something: someRecord,\n anotherThing: option,\n thirdThing: string,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypedContextCompletionSpec.res 218:31 +posCursor:[218:31] posNoWhite:[218:30] Found expr:[218:3->218:41] +posCursor:[218:31] posNoWhite:[218:30] Found pattern:[218:22->218:33] +posCursor:[218:31] posNoWhite:[218:30] Found pattern:[218:23->218:32] +Completable: CtypedPattern(sourceType:Value[someVal], lookingToComplete:CRecordField, patternType:Switch, prefix:something, pattern: [], seenIdents: [something]) +[] + +Complete src/TypedContextCompletionSpec.res 221:35 +posCursor:[221:35] posNoWhite:[221:34] Found expr:[221:3->221:45] +posCursor:[221:35] posNoWhite:[221:34] Found pattern:[221:22->221:37] +posCursor:[221:35] posNoWhite:[221:34] Found pattern:[221:34->221:36] +Completable: CtypedPattern(sourceType:Value[someVal], lookingToComplete:CRecordField, patternType:Switch, prefix:"", pattern: [RecordField:something], seenIdents: []) +[{ + "label": "somethingElse", + "kind": 5, + "tags": [], + "detail": "somethingElse: int\n\ntype someRecord = {\n somethingElse: int,\n whatIsThis: bool,\n anotherLevel: anotherLevel,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "whatIsThis", + "kind": 5, + "tags": [], + "detail": "whatIsThis: bool\n\ntype someRecord = {\n somethingElse: int,\n whatIsThis: bool,\n anotherLevel: anotherLevel,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "anotherLevel", + "kind": 5, + "tags": [], + "detail": "anotherLevel: anotherLevel\n\ntype someRecord = {\n somethingElse: int,\n whatIsThis: bool,\n anotherLevel: anotherLevel,\n}", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypedContextCompletionSpec.res 225:38 +posCursor:[225:38] posNoWhite:[225:37] Found expr:[225:3->225:50] +posCursor:[225:38] posNoWhite:[225:37] Found pattern:[225:22->225:42] +posCursor:[225:38] posNoWhite:[225:37] Found pattern:[225:34->225:42] +Completable: CtypedPattern(sourceType:Value[someVal], lookingToComplete:CNoContext, patternType:Switch, prefix:"", pattern: [RecordField:something, RecordField:el], seenIdents: []) +[] + +Complete src/TypedContextCompletionSpec.res 228:41 +posCursor:[228:41] posNoWhite:[228:40] Found expr:[228:3->228:51] +posCursor:[228:41] posNoWhite:[228:40] Found pattern:[228:29->228:43] +posCursor:[228:41] posNoWhite:[228:40] Found pattern:[228:38->228:42] +posCursor:[228:41] posNoWhite:[228:40] Found pattern:[228:40->228:41] +Ppat_construct ():[228:40->228:41] +Completable: CtypedPattern(sourceType:Value[someOtherValue], lookingToComplete:CNoContext, patternType:Switch, prefix:"", pattern: [RecordField:other2, Polyvariant:S(0)], seenIdents: []) +[] + +Complete src/TypedContextCompletionSpec.res 231:63 +posCursor:[231:63] posNoWhite:[231:62] Found expr:[231:3->231:74] +posCursor:[231:63] posNoWhite:[231:62] Found pattern:[231:29->231:66] +posCursor:[231:63] posNoWhite:[231:62] Found pattern:[231:42->231:65] +Ppat_construct Some:[231:42->231:46] +posCursor:[231:63] posNoWhite:[231:62] Found pattern:[231:46->231:66] +posCursor:[231:63] posNoWhite:[231:62] Found pattern:[231:50->231:64] +posCursor:[231:63] posNoWhite:[231:62] Found pattern:[231:62->231:63] +Completable: CtypedPattern(sourceType:Value[someOtherValue], lookingToComplete:CVariant, patternType:Switch, prefix:t, pattern: [RecordField:thirdStuff, Variant:Some(1), RecordField:something], seenIdents: []) +[] + +Complete src/TypedContextCompletionSpec.res 234:59 +posCursor:[234:59] posNoWhite:[234:58] Found expr:[234:3->234:70] +posCursor:[234:59] posNoWhite:[234:58] Found pattern:[234:29->234:62] +posCursor:[234:59] posNoWhite:[234:58] Found pattern:[234:42->234:61] +posCursor:[234:59] posNoWhite:[234:58] Found pattern:[234:46->234:60] +posCursor:[234:59] posNoWhite:[234:58] Found pattern:[234:58->234:59] +Completable: CtypedPattern(sourceType:Value[someOtherValue], lookingToComplete:CVariant, patternType:Switch, prefix:t, pattern: [RecordField:thirdStuff, Tuple:1, RecordField:something], seenIdents: []) +[] + +Complete src/TypedContextCompletionSpec.res 238:49 +posCursor:[238:49] posNoWhite:[238:48] Found expr:[238:3->238:52] +posCursor:[238:49] posNoWhite:[238:48] Found pattern:[238:48->238:49] +Ppat_construct T:[238:48->238:49] +Completable: CtypedPattern(sourceType:Value[y], lookingToComplete:CVariant, patternType:Switch, prefix:T, pattern: [], seenIdents: [One, Two, Three, T]) +[] + +Complete src/TypedContextCompletionSpec.res 241:55 +posCursor:[241:55] posNoWhite:[241:53] Found expr:[241:3->241:67] +posCursor:[241:55] posNoWhite:[241:53] Found pattern:[241:22->241:59] +posCursor:[241:55] posNoWhite:[241:53] Found pattern:[241:34->241:59] +Completable: CtypedPattern(sourceType:Value[someVal], lookingToComplete:CNoContext, patternType:Switch, prefix:"", pattern: [RecordField:something, RecordField:whatIsThis], seenIdents: [false]) +[{ + "label": "true", + "kind": 12, + "tags": [], + "detail": "boolean\n\n", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypedContextCompletionSpec.res 245:49 +posCursor:[245:49] posNoWhite:[245:46] Found expr:[245:3->245:51] +Completable: CtypedPattern(sourceType:Value[y], lookingToComplete:CNoContext, patternType:Switch, prefix:"", pattern: [], seenIdents: [One, Two, Three]) +[{ + "label": "Four(_)", + "kind": 4, + "tags": [], + "detail": "Four(someOtherVariant)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Four(${1:_})", + "insertTextFormat": 2 + }, { + "label": "Five(_)", + "kind": 4, + "tags": [], + "detail": "Five(someOtherVariant, someVariant)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Five(${1:_})", + "insertTextFormat": 2 + }] + +Complete src/TypedContextCompletionSpec.res 248:41 +posCursor:[248:41] posNoWhite:[248:40] Found expr:[248:3->248:55] +posCursor:[248:41] posNoWhite:[248:40] Found pattern:[248:29->248:43] +Completable: CtypedPattern(sourceType:Value[someOtherValue], lookingToComplete:CNoContext, patternType:Switch, prefix:"", pattern: [RecordField:thirdStuff], seenIdents: []) +[{ + "label": "(_, _, _, _)", + "kind": 4, + "tags": [], + "detail": "Full tuple match", + "documentation": null, + "sortText": "a", + "insertText": "(${1:_}, ${2:_}, ${3:_}, ${4:_})", + "insertTextFormat": 2 + }, { + "label": "()", + "kind": 4, + "tags": [], + "detail": "Empty tuple match for single element", + "documentation": null, + "sortText": "b", + "insertText": "($1)", + "insertTextFormat": 2 + }] + +Complete src/TypedContextCompletionSpec.res 253:30 +XXX Not found! +Completable: CtypedExpression(sourceType:Type[Completion, r], lookingToComplete:CNoContext, prefix:"", pattern: [] +[] + +Complete src/TypedContextCompletionSpec.res 256:27 +posCursor:[256:27] posNoWhite:[256:26] Found expr:[256:17->256:29] +Completable: CtypedExpression(sourceType:Value[x], lookingToComplete:CRecordField, prefix:"", pattern: [], seenIdents: [age]) +[] + +Complete src/TypedContextCompletionSpec.res 264:37 +posCursor:[264:37] posNoWhite:[264:36] Found expr:[264:3->264:42] +posCursor:[264:37] posNoWhite:[264:36] Found pattern:[264:32->264:39] +Ppat_construct One:[264:32->264:35] +posCursor:[264:37] posNoWhite:[264:36] Found pattern:[264:36->264:38] +Completable: CtypedPattern(sourceType:Value[withInlineRecords], lookingToComplete:CRecordField, patternType:Switch, prefix:"", pattern: [Variant:One(0)], seenIdents: []) +[{ + "label": "first", + "kind": 5, + "tags": [], + "detail": "first: bool\n\nbool", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "second", + "kind": 5, + "tags": [], + "detail": "second: option\n\noption", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypedContextCompletionSpec.res 267:32 +posCursor:[267:32] posNoWhite:[267:30] Found expr:[267:3->267:35] +Completable: CtypedPattern(sourceType:Value[withInlineRecords], lookingToComplete:CNoContext, patternType:Switch, prefix:"", pattern: [], seenIdents: []) +[{ + "label": "One(_)", + "kind": 4, + "tags": [], + "detail": "One\n\n", + "documentation": null, + "sortText": null, + "insertText": "One(${1:_})", + "insertTextFormat": 2 + }, { + "label": "TTwo", + "kind": 4, + "tags": [], + "detail": "TTwo\n\n", + "documentation": null, + "sortText": null, + "insertText": "TTwo", + "insertTextFormat": 2 + }, { + "label": "TThree", + "kind": 4, + "tags": [], + "detail": "TThree\n\n", + "documentation": null, + "sortText": null, + "insertText": "TThree", + "insertTextFormat": 2 + }] + +Complete src/TypedContextCompletionSpec.res 277:60 +posCursor:[277:60] posNoWhite:[277:59] Found expr:[277:19->277:85] +posCursor:[277:60] posNoWhite:[277:59] Found pattern:[277:45->277:62] +posCursor:[277:60] posNoWhite:[277:59] Found pattern:[277:55->277:61] +Ppat_construct Some:[277:55->277:59] +posCursor:[277:60] posNoWhite:[277:59] Found pattern:[277:59->277:61] +Ppat_construct ():[277:59->277:61] +Completable: CtypedPattern(sourceType:Value[location].state, lookingToComplete:CNoContext, patternType:Switch, prefix:"", pattern: [RecordField:shallow, Variant:Some(0)], seenIdents: []) +[{ + "label": "false", + "kind": 12, + "tags": [], + "detail": "boolean\n\n", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "true", + "kind": 12, + "tags": [], + "detail": "boolean\n\n", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }] + +Complete src/TypedContextCompletionSpec.res 280:54 +posCursor:[280:54] posNoWhite:[280:53] Found expr:[280:19->280:79] +posCursor:[280:54] posNoWhite:[280:53] Found pattern:[280:45->280:56] +Completable: CtypedPattern(sourceType:Value[location].state, lookingToComplete:CNoContext, patternType:Switch, prefix:"", pattern: [RecordField:shallow], seenIdents: []) +[{ + "label": "None", + "kind": 4, + "tags": [], + "detail": "None\n\n", + "documentation": null, + "sortText": null, + "insertText": null, + "insertTextFormat": null + }, { + "label": "Some(_)", + "kind": 4, + "tags": [], + "detail": "Some(_)\n\n", + "documentation": null, + "sortText": null, + "insertText": "Some(${1:_})", + "insertTextFormat": 2 + }] + diff --git a/server/src/server.ts b/server/src/server.ts index 76c78e0b7..cdea55c7d 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -34,6 +34,12 @@ interface extensionConfiguration { binaryPath: string | null; } +interface clientCapabilites { + completion: { + supportsSnippets: boolean; + }; +} + // All values here are temporary, and will be overridden as the server is // initialized, and the current config is received from the client. let extensionConfiguration: extensionConfiguration = { @@ -45,6 +51,11 @@ let extensionConfiguration: extensionConfiguration = { codeLens: false, binaryPath: null, }; +let clientCapabilites: clientCapabilites = { + completion: { + supportsSnippets: false, + }, +}; let pullConfigurationPeriodically: NodeJS.Timeout | null = null; // https://microsoft.github.io/language-server-protocol/specification#initialize @@ -607,7 +618,7 @@ function semanticTokens(msg: p.RequestMessage) { function completion(msg: p.RequestMessage) { // https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_completion - let params = msg.params as p.ReferenceParams; + let params = msg.params as p.CompletionParams; let filePath = fileURLToPath(params.textDocument.uri); let code = getOpenedFileContent(params.textDocument.uri); let tmpname = utils.createFileInTempDir(); @@ -620,6 +631,7 @@ function completion(msg: p.RequestMessage) { params.position.line, params.position.character, tmpname, + clientCapabilites.completion.supportsSnippets ? "true" : "false", ], msg ); @@ -1000,6 +1012,15 @@ function onMessage(msg: p.Message) { extensionConfiguration = initialConfiguration; } + // Build and save config representing the client capabilities we care about. + clientCapabilites = { + completion: { + supportsSnippets: + initParams.capabilities.textDocument?.completion?.completionItem + ?.snippetSupport === true, + }, + }; + // send the list of features we support let result: p.InitializeResult = { // This tells the client: "hey, we support the following operations".