Skip to content

Commit cdf968b

Browse files
authored
docs for editor.completeFrom and friends (#1017)
1 parent d8f7760 commit cdf968b

File tree

1 file changed

+154
-1
lines changed

1 file changed

+154
-1
lines changed

pages/docs/manual/v12.0.0/editor-plugins.mdx

+154-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ We don't officially support these; use them at your own risk!
2727

2828
## Code analysis
2929

30-
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 extensionno separate install required.
30+
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 extensionno separate install required.
3131

3232
### How to Use
3333

@@ -50,3 +50,156 @@ Look [here](editor-code-analysis) for a more detailed guide about how to use the
5050

5151
- Doesn't support cross-package dead code analysis in monorepos. Run it per package instead.
5252

53+
## Editor features
54+
Below are features and configurations of the editor tooling that might be good to know about.
55+
56+
### Pipe completions
57+
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.
58+
59+
#### Default pipe completion rules for non-builtin types
60+
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.
61+
62+
#### Pipe completions for builtin types
63+
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.
64+
65+
There is a way to enhance this behavior via configuration, described further down in this document.
66+
67+
### Dot completion enhancements
68+
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.
69+
70+
This behavior has the following important implications:
71+
- Improves discoverability (E.g. using a `.` will reveal important pipe completions)
72+
- Enables a more natural completion flow for people used to JavaScript, where dots power more completions naturally
73+
74+
Below is a list of all the scenarios where using dots trigger completion in addition to the normal record field completion.
75+
76+
#### Objects
77+
When writing a `.` on something that's a [structural object](object.md), you'll get completions for those object properties. Example:
78+
```res
79+
let obj = {
80+
"first": true,
81+
"second": false
82+
}
83+
84+
let x = obj.
85+
86+
// Will give the following completions for object property access:
87+
// - ["first"]
88+
// - ["second"]
89+
```
90+
91+
#### Pipe completions for anything
92+
When writing `.` on _anything_, the editor will try to do pipe completion for the value on the left of the `.`. Example:
93+
94+
```res
95+
let arr = [1, 2, 3]
96+
97+
let x = arr.
98+
99+
// Will give the following pipe completions:
100+
// - ->Array.length
101+
// - ->Array.filter
102+
// - ->Array.map
103+
```
104+
105+
### `@editor.completeFrom` for drawing completions from additional modules
106+
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:
107+
108+
* 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.
109+
* 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.
110+
111+
Let's look at an example:
112+
```res
113+
// Types.res
114+
// In this example types need to live separately in their own file, for various reasons
115+
type htmlInput
116+
117+
// Utils.res
118+
module HtmlInput = {
119+
/** Gets the HTML input value. */
120+
@get
121+
external value: Types.htmlInput => option<string> = "value"
122+
}
123+
```
124+
125+
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.
126+
127+
With `@editor.completeFrom`, we can fix this. Let's look at an updated example:
128+
```res
129+
// Types.res
130+
@editor.completeFrom(Utils.HtmlInput)
131+
type htmlInput
132+
133+
// Utils.res
134+
module HtmlInput = {
135+
/** Gets the HTML input value. */
136+
@get
137+
external value: Types.htmlInput => option<string> = "value"
138+
}
139+
```
140+
141+
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.
142+
143+
> 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])`.
144+
145+
### Configuring the editor via `editor` in `rescript.json`
146+
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.
147+
148+
#### `autocomplete` for pipe completion
149+
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.
150+
151+
This is useful in scenarios like:
152+
* 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.
153+
* 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.
154+
155+
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.
156+
157+
Let's take two examples.
158+
159+
##### Enhancing completion for builtin types
160+
First, let's look at including our own `ArrayExtra` in all completions for `array`:
161+
```json
162+
{
163+
"editor": {
164+
"autocomplete": {
165+
"array": ["ArrayExtra"]
166+
}
167+
}
168+
}
169+
```
170+
171+
Now, when using pipes on arrays, you'll get completions both from the standard library array functions, and also from your own `ArrayExtra` module.
172+
```res
173+
let x = [1, 2, 3]->
174+
175+
// Example of what completing at the pipe might look like
176+
- Array.length
177+
- Array.map
178+
- Array.filter
179+
- ArrayExtra.someArrayFn
180+
- ArrayExtra.myOtherArrayFn
181+
```
182+
183+
##### Enhancing completion for non-builtin types
184+
Now, let's look at an example of when you have a non-builtin type that you don't have control over.
185+
186+
In this example, imagine this:
187+
* We're writing an app using `fastify`
188+
* We're using an external package that provides the necessary bindings in a `Fastify` module
189+
* We've got our own extra file `FastifyExtra` that has various custom util functions that operate on the main type `Fastify.t`
190+
191+
We now want the editor to always suggest completions from the `FastifyExtra` module, in addition to the regular completions from the main `Fastify` module.
192+
193+
Let's configure this using the `editor.autocomplete` config in `rescript.json`:
194+
195+
```json
196+
{
197+
"editor": {
198+
"autocomplete": {
199+
"Fastify.t": ["FastifyExt"]
200+
}
201+
}
202+
}
203+
```
204+
205+
Now, when using pipes on anything of type `Fastify.t`, we'll also get completions from our custom `FastifyExtra`.

0 commit comments

Comments
 (0)