diff --git a/analysis/src/CompletionBackEnd.ml b/analysis/src/CompletionBackEnd.ml index c7e5713123..0b5bb00acb 100644 --- a/analysis/src/CompletionBackEnd.ml +++ b/analysis/src/CompletionBackEnd.ml @@ -1135,6 +1135,25 @@ and getCompletionsForContextPath ~debug ~full ~opens ~rawOpens ~pos ~env ~exact | _ -> false else true) in + + let globallyConfiguredCompletionsForType = + match package.autocomplete |> Misc.StringMap.find_opt mainTypeId with + | None -> [] + | Some completionPaths -> + completionPaths |> List.map (fun p -> String.split_on_char '.' p) + in + + let globallyConfiguredCompletions = + globallyConfiguredCompletionsForType + |> List.map (fun completionPath -> + completionsForPipeFromCompletionPath ~envCompletionIsMadeFrom + ~opens ~pos ~scope ~debug ~prefix ~env ~rawOpens ~full + completionPath) + |> List.flatten + |> TypeUtils.filterPipeableFunctions ~synthetic:true ~env ~full + ~targetTypeId:mainTypeId + in + (* Extra completions can be drawn from the @editor.completeFrom attribute. Here we find and add those completions as well. *) let extraCompletions = @@ -1154,7 +1173,8 @@ and getCompletionsForContextPath ~debug ~full ~opens ~rawOpens ~pos ~env ~exact ~full ~rawOpens typ else [] in - jsxCompletions @ pipeCompletions @ extraCompletions)) + jsxCompletions @ pipeCompletions @ extraCompletions + @ globallyConfiguredCompletions)) | CTuple ctxPaths -> if Debug.verbose () then print_endline "[ctx_path]--> CTuple"; (* Turn a list of context paths into a list of type expressions. *) diff --git a/analysis/src/Packages.ml b/analysis/src/Packages.ml index dd04ee170f..34b9945a7b 100644 --- a/analysis/src/Packages.ml +++ b/analysis/src/Packages.ml @@ -66,6 +66,28 @@ let newBsPackage ~rootPath = | _ -> None) | None -> None in + let autocomplete = + match config |> Json.get "editor" with + | Some editorConfig -> ( + match editorConfig |> Json.get "autocomplete" with + | Some (Object map) -> + map + |> List.fold_left + (fun acc (key, value) -> + match value with + | Json.Array items -> + let values = + items + |> List.filter_map (function + | Json.String s -> Some s + | _ -> None) + in + Misc.StringMap.add key values acc + | _ -> acc) + Misc.StringMap.empty + | _ -> Misc.StringMap.empty) + | None -> Misc.StringMap.empty + in let uncurried = uncurried = Some true in match libBs with | None -> None @@ -158,6 +180,7 @@ let newBsPackage ~rootPath = opens; namespace; uncurried; + autocomplete; })) | None -> None in diff --git a/analysis/src/SharedTypes.ml b/analysis/src/SharedTypes.ml index 17b74e3cf2..13692e26a6 100644 --- a/analysis/src/SharedTypes.ml +++ b/analysis/src/SharedTypes.ml @@ -494,6 +494,7 @@ type package = { opens: path list; uncurried: bool; rescriptVersion: int * int; + autocomplete: file list Misc.StringMap.t; } let allFilesInPackage package = diff --git a/docs/docson/build-schema.json b/docs/docson/build-schema.json index d06504e5f3..7d7432f834 100644 --- a/docs/docson/build-schema.json +++ b/docs/docson/build-schema.json @@ -349,6 +349,24 @@ "description": "(Not implemented yet)" } ] + }, + "editor": { + "type": "object", + "properties": { + "autocomplete": { + "type": "object", + "description": "A mapping to extend the autocompletion for a given type with an array of modules. E.g. `{ \"int\": [\"IntUtils\", \"IntExt\"] }` will extend the autocompletion of the `int` type with the values from `IntUtils` and `IntExt` modules.", + "patternProperties": { + "^[a-zA-Z0-9_.]+$": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "additionalProperties": false } }, "title": "ReScript build configuration", @@ -472,6 +490,10 @@ "reanalyze": { "$ref": "#/definitions/reanalyze", "description": "Configure reanalyze, a static code analysis tool for ReScript." + }, + "editor": { + "$ref": "#/definitions/editor", + "description": "Configure editor functionality, like modules that should be included in autocompletions for given (built-in) types." } }, "additionalProperties": false, diff --git a/tests/analysis_tests/tests/rescript.json b/tests/analysis_tests/tests/rescript.json index 7f0fe3e2fd..731b10efe2 100644 --- a/tests/analysis_tests/tests/rescript.json +++ b/tests/analysis_tests/tests/rescript.json @@ -12,5 +12,11 @@ "bsc-flags": ["-w -33-44-8"], "bs-dependencies": ["@rescript/react"], "jsx": { "version": 4 }, - "suffix": ".res.js" + "suffix": ".res.js", + "editor": { + "autocomplete": { + "array": ["ArrayUtils"], + "Fastify.t": ["FastifyExt"] + } + } } diff --git a/tests/analysis_tests/tests/src/ArrayUtils.res b/tests/analysis_tests/tests/src/ArrayUtils.res new file mode 100644 index 0000000000..5b0063e912 --- /dev/null +++ b/tests/analysis_tests/tests/src/ArrayUtils.res @@ -0,0 +1 @@ +let empty = arr => Array.length(arr) === 0 diff --git a/tests/analysis_tests/tests/src/CompletionConfiguredBuiltins.res b/tests/analysis_tests/tests/src/CompletionConfiguredBuiltins.res new file mode 100644 index 0000000000..79f1b7cb4b --- /dev/null +++ b/tests/analysis_tests/tests/src/CompletionConfiguredBuiltins.res @@ -0,0 +1,9 @@ +let x = [1, 2, 3] + +// x->em +// ^com + +external fastify: Fastify.t = "fastify" + +// fastify->doSt +// ^com diff --git a/tests/analysis_tests/tests/src/Fastify.res b/tests/analysis_tests/tests/src/Fastify.res new file mode 100644 index 0000000000..63c57c4e0c --- /dev/null +++ b/tests/analysis_tests/tests/src/Fastify.res @@ -0,0 +1 @@ +type t diff --git a/tests/analysis_tests/tests/src/FastifyExt.res b/tests/analysis_tests/tests/src/FastifyExt.res new file mode 100644 index 0000000000..592e70b20d --- /dev/null +++ b/tests/analysis_tests/tests/src/FastifyExt.res @@ -0,0 +1 @@ +let doStuff = (t: Fastify.t) => Console.log(t) diff --git a/tests/analysis_tests/tests/src/expected/ArrayUtils.res.txt b/tests/analysis_tests/tests/src/expected/ArrayUtils.res.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/analysis_tests/tests/src/expected/Completion.res.txt b/tests/analysis_tests/tests/src/expected/Completion.res.txt index 5ae0ac9ca6..f896780020 100644 --- a/tests/analysis_tests/tests/src/expected/Completion.res.txt +++ b/tests/analysis_tests/tests/src/expected/Completion.res.txt @@ -633,6 +633,7 @@ Resolved opens 1 Stdlib ContextPath array->m ContextPath array Path Stdlib.Array.m +Path ArrayUtils.m [{ "label": "Array.map", "kind": 12, @@ -2215,6 +2216,7 @@ Resolved opens 3 Stdlib Completion Completion ContextPath array->ma ContextPath array Path Stdlib.Array.ma +Path ArrayUtils.ma [{ "label": "Array.map", "kind": 12, diff --git a/tests/analysis_tests/tests/src/expected/CompletionConfiguredBuiltins.res.txt b/tests/analysis_tests/tests/src/expected/CompletionConfiguredBuiltins.res.txt new file mode 100644 index 0000000000..5d3b5e8f6a --- /dev/null +++ b/tests/analysis_tests/tests/src/expected/CompletionConfiguredBuiltins.res.txt @@ -0,0 +1,37 @@ +Complete src/CompletionConfiguredBuiltins.res 2:8 +posCursor:[2:8] posNoWhite:[2:7] Found expr:[2:3->2:8] +Completable: Cpath Value[x]->em +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Value[x]->em +ContextPath Value[x] +Path x +Path Stdlib.Array.em +Path ArrayUtils.em +[{ + "label": "ArrayUtils.empty", + "kind": 12, + "tags": [], + "detail": "array<'a> => bool", + "documentation": null + }] + +Complete src/CompletionConfiguredBuiltins.res 7:16 +posCursor:[7:16] posNoWhite:[7:15] Found expr:[7:3->7:16] +Completable: Cpath Value[fastify]->doSt +Package opens Stdlib.place holder Pervasives.JsxModules.place holder +Resolved opens 1 Stdlib +ContextPath Value[fastify]->doSt +ContextPath Value[fastify] +Path fastify +CPPipe pathFromEnv:Fastify found:false +Path Fastify.doSt +Path FastifyExt.doSt +[{ + "label": "FastifyExt.doStuff", + "kind": 12, + "tags": [], + "detail": "Fastify.t => unit", + "documentation": null + }] + diff --git a/tests/analysis_tests/tests/src/expected/CompletionInferValues.res.txt b/tests/analysis_tests/tests/src/expected/CompletionInferValues.res.txt index afffa238ec..196e89f3c7 100644 --- a/tests/analysis_tests/tests/src/expected/CompletionInferValues.res.txt +++ b/tests/analysis_tests/tests/src/expected/CompletionInferValues.res.txt @@ -415,6 +415,7 @@ ContextPath Value[String, split](Nolabel, Nolabel) ContextPath Value[String, split] Path String.split Path Stdlib.Array.ma +Path ArrayUtils.ma [{ "label": "Array.map", "kind": 12, diff --git a/tests/analysis_tests/tests/src/expected/CompletionJsx.res.txt b/tests/analysis_tests/tests/src/expected/CompletionJsx.res.txt index 2375a24b36..16a384c25d 100644 --- a/tests/analysis_tests/tests/src/expected/CompletionJsx.res.txt +++ b/tests/analysis_tests/tests/src/expected/CompletionJsx.res.txt @@ -527,6 +527,7 @@ ContextPath Value[someArr]->a <> ContextPath Value[someArr] Path someArr Path Stdlib.Array.a +Path ArrayUtils.a [{ "label": "React.array", "kind": 12, diff --git a/tests/analysis_tests/tests/src/expected/DotPipeCompletionSpec.res.txt b/tests/analysis_tests/tests/src/expected/DotPipeCompletionSpec.res.txt index 6341bc3ee4..ea3337aa8d 100644 --- a/tests/analysis_tests/tests/src/expected/DotPipeCompletionSpec.res.txt +++ b/tests/analysis_tests/tests/src/expected/DotPipeCompletionSpec.res.txt @@ -216,6 +216,7 @@ ContextPath Value[ffff]->u ContextPath Value[ffff] Path ffff Path Stdlib.Array.u +Path ArrayUtils.u [{ "label": "->Array.unshiftMany", "kind": 12, @@ -329,6 +330,7 @@ ContextPath Value[Array, filter](Nolabel, Nolabel) ContextPath Value[Array, filter] Path Array.filter Path Stdlib.Array.filt +Path ArrayUtils.filt [{ "label": "->Array.filterMap", "kind": 12, diff --git a/tests/analysis_tests/tests/src/expected/Fastify.res.txt b/tests/analysis_tests/tests/src/expected/Fastify.res.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/analysis_tests/tests/src/expected/FastifyExt.res.txt b/tests/analysis_tests/tests/src/expected/FastifyExt.res.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/analysis_tests/tests/src/expected/RecordCompletion.res.txt b/tests/analysis_tests/tests/src/expected/RecordCompletion.res.txt index 7673dc6c9a..bb2b7c10a7 100644 --- a/tests/analysis_tests/tests/src/expected/RecordCompletion.res.txt +++ b/tests/analysis_tests/tests/src/expected/RecordCompletion.res.txt @@ -13,6 +13,7 @@ Path t CPPipe pathFromEnv: found:true Path RecordCompletion.n Path Stdlib.Array.m +Path ArrayUtils.m [{ "label": "Array.map", "kind": 12, @@ -54,6 +55,7 @@ Path RecordCompletion.n2 CPPipe pathFromEnv: found:true Path RecordCompletion.n Path Stdlib.Array.m +Path ArrayUtils.m [{ "label": "Array.map", "kind": 12,