From fd33bbfa62171f10de20b1ba9a6ae89267d62125 Mon Sep 17 00:00:00 2001
From: Gabriel Nordeborn <gabbe.nord@gmail.com>
Date: Sun, 4 May 2025 17:10:41 +0200
Subject: [PATCH] docs for editor.completeFrom and friends

---
 pages/docs/manual/v12.0.0/editor-plugins.mdx | 155 ++++++++++++++++++-
 1 file changed, 154 insertions(+), 1 deletion(-)

diff --git a/pages/docs/manual/v12.0.0/editor-plugins.mdx b/pages/docs/manual/v12.0.0/editor-plugins.mdx
index 59acdeeca..331b6e2b0 100644
--- a/pages/docs/manual/v12.0.0/editor-plugins.mdx
+++ b/pages/docs/manual/v12.0.0/editor-plugins.mdx
@@ -27,7 +27,7 @@ We don't officially support these; use them at your own risk!
 
 ## Code analysis
 
-The code analysis provides extra checks for your ReScript project, such as detecting dead code and unhandled exceptions. It's powered by [reanalyze](https://github.com/rescript-association/reanalyze), which is built into the extension—no separate install required.
+The code analysis provides extra checks for your ReScript project, such as detecting dead code and unhandled exceptions. It's powered by [reanalyze](https://github.com/rescript-association/reanalyze), which is built into the extension — no separate install required.
 
 ### How to Use
 
@@ -50,3 +50,156 @@ Look [here](editor-code-analysis) for a more detailed guide about how to use the
 
 - Doesn't support cross-package dead code analysis in monorepos. Run it per package instead.
 
+## Editor features
+Below are features and configurations of the editor tooling that might be good to know about.
+
+### Pipe completions
+Pipes (`->`) are a huge and important part of the ReScript language, for many reasons. Because of that, extra care has gone into the editor experience for using pipes.
+
+#### Default pipe completion rules for non-builtin types
+By default, using `->` will give completions from the module where the type of the expression you're piping on is defined. So, if you're piping on something of the type `SomeModule.t` (like `someValue->`) then you'll get completions for all functions defined in `SomeModule` that take the type `t` as the first unlabelled argument.
+
+#### Pipe completions for builtin types
+For builtin types, completion will automatically happen based on the _standard library module_ for that type. So, `array` types will get completions from the `Array` module, `string` gets completions from `String`, and so on.
+
+There is a way to enhance this behavior via configuration, described further down in this document.
+
+### Dot completion enhancements
+In ReScript, using a dot (`.`) normally means "access record field". But, because using `.` to trigger completions is so pervasive in for example JavaScript, we extend `.` to trigger completions in more scenarios than just for record field access.
+
+This behavior has the following important implications:
+- Improves discoverability (E.g. using a `.` will reveal important pipe completions)
+- Enables a more natural completion flow for people used to JavaScript, where dots power more completions naturally
+
+Below is a list of all the scenarios where using dots trigger completion in addition to the normal record field completion.
+
+#### Objects
+When writing a `.` on something that's a [structural object](object.md), you'll get completions for those object properties. Example:
+```res
+let obj = {
+  "first": true,
+  "second": false
+}
+
+let x = obj.
+
+// Will give the following completions for object property access:
+// - ["first"]
+// - ["second"]
+```
+
+#### Pipe completions for anything
+When writing `.` on _anything_, the editor will try to do pipe completion for the value on the left of the `.`. Example:
+
+```res
+let arr = [1, 2, 3]
+
+let x = arr.
+
+// Will give the following pipe completions:
+// - ->Array.length
+// - ->Array.filter
+// - ->Array.map
+```
+
+### `@editor.completeFrom` for drawing completions from additional modules
+You can configure any type you have control over to draw pipe completions from additional modules, in addition to the main module where the type is defined, via the `@editor.completeFrom` decorator. This is useful in many different scenarios:
+
+* When you, for various reasons, need to have your type definition separate from its "main module". Could be because of cyclic dependencies, a need for the type to be in a recursive type definition chain, and so on.
+* You have separate modules with useful functions for your type but that you don't want to (or can't) include in the main module of that type.
+
+Let's look at an example:
+```res
+// Types.res
+// In this example types need to live separately in their own file, for various reasons
+type htmlInput
+
+// Utils.res
+module HtmlInput = {
+  /** Gets the HTML input value. */
+  @get
+  external value: Types.htmlInput => option<string> = "value"
+}
+```
+
+In the example above, if we try and pipe on something of the type `Types.htmlInput`, we'll get no completions because there are no functions in `Types` that take `htmlInput` as its first unlabelled argument. But, better DX would be for the editor to draw completions from our util functions for `htmlInput` in the `Utils.HtmlInput` module.
+
+With `@editor.completeFrom`, we can fix this. Let's look at an updated example:
+```res
+// Types.res
+@editor.completeFrom(Utils.HtmlInput)
+type htmlInput
+
+// Utils.res
+module HtmlInput = {
+  /** Gets the HTML input value. */
+  @get
+  external value: Types.htmlInput => option<string> = "value"
+}
+```
+
+Now when piping on a value of the type `Types.htmlInput`, the editor tooling will know to include relevant functions from the module `Utils.HtmlInput`, and you'll get the completions you expect, even if the functions aren't located in the same module.
+
+> You can point out multiple modules to draw completions from for a type either by repeating `@editor.completeFrom` with a single module path each time, or by passing an array with all the module paths you want to include, like `@editor.completeFrom([Utils.HtmlInput, HtmlInputUtils])`.
+
+### Configuring the editor via `editor` in `rescript.json`
+There's certain configuration you can do for the editor on a per project basis in `rescript.json`. Below lists all of the configuration available.
+
+#### `autocomplete` for pipe completion
+The `autocomplete` property of `editor` in `rescript.json` let's you map types to modules _on the project level_ that you want the editor to leverage when doing autocomplete for pipes. 
+
+This is useful in scenarios like:
+* You have your own util module(s) for builtin types. Maybe you have an `ArrayExtra` with helpers for arrays that you want to get completions from whenever dealing with arrays.
+* You have your own util module(s) for types you don't control yourself (and therefore can't use `@editor.completeFrom`), like from external packages you install.
+
+To configure, you pass `autocomplete` an object where the keys are the _path to the type_ you want to target, and then an array of the path to each module you want to include for consideration for pipe completions.
+
+Let's take two examples.
+
+##### Enhancing completion for builtin types
+First, let's look at including our own `ArrayExtra` in all completions for `array`:
+```json
+{
+  "editor": {
+    "autocomplete": {
+      "array": ["ArrayExtra"]
+    }
+  }
+}
+```
+
+Now, when using pipes on arrays, you'll get completions both from the standard library array functions, and also from your own `ArrayExtra` module.
+```res
+let x = [1, 2, 3]->
+
+// Example of what completing at the pipe might look like
+- Array.length
+- Array.map
+- Array.filter
+- ArrayExtra.someArrayFn
+- ArrayExtra.myOtherArrayFn
+```
+
+##### Enhancing completion for non-builtin types
+Now, let's look at an example of when you have a non-builtin type that you don't have control over.
+
+In this example, imagine this:
+* We're writing an app using `fastify`
+* We're using an external package that provides the necessary bindings in a `Fastify` module
+* We've got our own extra file `FastifyExtra` that has various custom util functions that operate on the main type `Fastify.t`
+
+We now want the editor to always suggest completions from the `FastifyExtra` module, in addition to the regular completions from the main `Fastify` module.
+
+Let's configure this using the `editor.autocomplete` config in `rescript.json`:
+
+```json
+{
+  "editor": {
+    "autocomplete": {
+      "Fastify.t": ["FastifyExt"]
+    }
+  }
+}
+```
+
+Now, when using pipes on anything of type `Fastify.t`, we'll also get completions from our custom `FastifyExtra`.