• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<!---
2lsp_ext.rs hash: 2d60bbffe70ae198
3
4If you need to change the above hash to make the test pass, please check if you
5need to adjust this doc as well and ping this issue:
6
7  https://github.com/rust-lang/rust-analyzer/issues/4604
8
9--->
10
11# LSP Extensions
12
13This document describes LSP extensions used by rust-analyzer.
14It's a best effort document, when in doubt, consult the source (and send a PR with clarification ;-) ).
15We aim to upstream all non Rust-specific extensions to the protocol, but this is not a top priority.
16All capabilities are enabled via the `experimental` field of `ClientCapabilities` or `ServerCapabilities`.
17Requests which we hope to upstream live under `experimental/` namespace.
18Requests, which are likely to always remain specific to `rust-analyzer` are under `rust-analyzer/` namespace.
19
20If you want to be notified about the changes to this document, subscribe to [#4604](https://github.com/rust-lang/rust-analyzer/issues/4604).
21
22## Configuration in `initializationOptions`
23
24**Upstream Issue:** https://github.com/microsoft/language-server-protocol/issues/567
25
26The `initializationOptions` field of the `InitializeParams` of the initialization request should contain the `"rust-analyzer"` section of the configuration.
27
28`rust-analyzer` normally sends a `"workspace/configuration"` request with `{ "items": ["rust-analyzer"] }` payload.
29However, the server can't do this during initialization.
30At the same time some essential configuration parameters are needed early on, before servicing requests.
31For this reason, we ask that `initializationOptions` contains the configuration, as if the server did make a `"workspace/configuration"` request.
32
33If a language client does not know about `rust-analyzer`'s configuration options it can get sensible defaults by doing any of the following:
34 * Not sending `initializationOptions`
35 * Sending `"initializationOptions": null`
36 * Sending `"initializationOptions": {}`
37
38## Snippet `TextEdit`
39
40**Upstream Issue:** https://github.com/microsoft/language-server-protocol/issues/724
41
42**Experimental Client Capability:** `{ "snippetTextEdit": boolean }`
43
44If this capability is set, `WorkspaceEdit`s returned from `codeAction` requests and `TextEdit`s returned from `textDocument/onTypeFormatting` requests might contain `SnippetTextEdit`s instead of usual `TextEdit`s:
45
46```typescript
47interface SnippetTextEdit extends TextEdit {
48    insertTextFormat?: InsertTextFormat;
49    annotationId?: ChangeAnnotationIdentifier;
50}
51```
52
53```typescript
54export interface TextDocumentEdit {
55    textDocument: OptionalVersionedTextDocumentIdentifier;
56    edits: (TextEdit | SnippetTextEdit)[];
57}
58```
59
60When applying such code action or text edit, the editor should insert snippet, with tab stops and placeholder.
61At the moment, rust-analyzer guarantees that only a single edit will have `InsertTextFormat.Snippet`.
62
63### Example
64
65"Add `derive`" code action transforms `struct S;` into `#[derive($0)] struct S;`
66
67### Unresolved Questions
68
69* Where exactly are `SnippetTextEdit`s allowed (only in code actions at the moment)?
70* Can snippets span multiple files (so far, no)?
71
72## `CodeAction` Groups
73
74**Upstream Issue:** https://github.com/microsoft/language-server-protocol/issues/994
75
76**Experimental Client Capability:** `{ "codeActionGroup": boolean }`
77
78If this capability is set, `CodeAction`s returned from the server contain an additional field, `group`:
79
80```typescript
81interface CodeAction {
82    title: string;
83    group?: string;
84    ...
85}
86```
87
88All code-actions with the same `group` should be grouped under single (extendable) entry in lightbulb menu.
89The set of actions `[ { title: "foo" }, { group: "frobnicate", title: "bar" }, { group: "frobnicate", title: "baz" }]` should be rendered as
90
91```
92��
93  +-------------+
94  | foo         |
95  +-------------+-----+
96  | frobnicate >| bar |
97  +-------------+-----+
98                | baz |
99                +-----+
100```
101
102Alternatively, selecting `frobnicate` could present a user with an additional menu to choose between `bar` and `baz`.
103
104### Example
105
106```rust
107fn main() {
108    let x: Entry/*cursor here*/ = todo!();
109}
110```
111
112Invoking code action at this position will yield two code actions for importing `Entry` from either `collections::HashMap` or `collection::BTreeMap`, grouped under a single "import" group.
113
114### Unresolved Questions
115
116* Is a fixed two-level structure enough?
117* Should we devise a general way to encode custom interaction protocols for GUI refactorings?
118
119## Parent Module
120
121**Upstream Issue:** https://github.com/microsoft/language-server-protocol/issues/1002
122
123**Experimental Server Capability:** `{ "parentModule": boolean }`
124
125This request is sent from client to server to handle "Goto Parent Module" editor action.
126
127**Method:** `experimental/parentModule`
128
129**Request:** `TextDocumentPositionParams`
130
131**Response:** `Location | Location[] | LocationLink[] | null`
132
133
134### Example
135
136```rust
137// src/main.rs
138mod foo;
139// src/foo.rs
140
141/* cursor here*/
142```
143
144`experimental/parentModule` returns a single `Link` to the `mod foo;` declaration.
145
146### Unresolved Question
147
148* An alternative would be to use a more general "gotoSuper" request, which would work for super methods, super classes and super modules.
149  This is the approach IntelliJ Rust is taking.
150  However, experience shows that super module (which generally has a feeling of navigation between files) should be separate.
151  If you want super module, but the cursor happens to be inside an overridden function, the behavior with single "gotoSuper" request is surprising.
152
153## Join Lines
154
155**Upstream Issue:** https://github.com/microsoft/language-server-protocol/issues/992
156
157**Experimental Server Capability:** `{ "joinLines": boolean }`
158
159This request is sent from client to server to handle "Join Lines" editor action.
160
161**Method:** `experimental/joinLines`
162
163**Request:**
164
165```typescript
166interface JoinLinesParams {
167    textDocument: TextDocumentIdentifier,
168    /// Currently active selections/cursor offsets.
169    /// This is an array to support multiple cursors.
170    ranges: Range[],
171}
172```
173
174**Response:** `TextEdit[]`
175
176### Example
177
178```rust
179fn main() {
180    /*cursor here*/let x = {
181        92
182    };
183}
184```
185
186`experimental/joinLines` yields (curly braces are automagically removed)
187
188```rust
189fn main() {
190    let x = 92;
191}
192```
193
194### Unresolved Question
195
196* What is the position of the cursor after `joinLines`?
197  Currently, this is left to editor's discretion, but it might be useful to specify on the server via snippets.
198  However, it then becomes unclear how it works with multi cursor.
199
200## On Enter
201
202**Upstream Issue:** https://github.com/microsoft/language-server-protocol/issues/1001
203
204**Experimental Server Capability:** `{ "onEnter": boolean }`
205
206This request is sent from client to server to handle the <kbd>Enter</kbd> key press.
207
208**Method:** `experimental/onEnter`
209
210**Request:**: `TextDocumentPositionParams`
211
212**Response:**
213
214```typescript
215SnippetTextEdit[]
216```
217
218### Example
219
220```rust
221fn main() {
222    // Some /*cursor here*/ docs
223    let x = 92;
224}
225```
226
227`experimental/onEnter` returns the following snippet
228
229```rust
230fn main() {
231    // Some
232    // $0 docs
233    let x = 92;
234}
235```
236
237The primary goal of `onEnter` is to handle automatic indentation when opening a new line.
238This is not yet implemented.
239The secondary goal is to handle fixing up syntax, like continuing doc strings and comments, and escaping `\n` in string literals.
240
241As proper cursor positioning is raison-d'etat for `onEnter`, it uses `SnippetTextEdit`.
242
243### Unresolved Question
244
245* How to deal with synchronicity of the request?
246  One option is to require the client to block until the server returns the response.
247  Another option is to do a OT-style merging of edits from client and server.
248  A third option is to do a record-replay: client applies heuristic on enter immediately, then applies all user's keypresses.
249  When the server is ready with the response, the client rollbacks all the changes and applies the recorded actions on top of the correct response.
250* How to deal with multiple carets?
251* Should we extend this to arbitrary typed events and not just `onEnter`?
252
253## Structural Search Replace (SSR)
254
255**Experimental Server Capability:** `{ "ssr": boolean }`
256
257This request is sent from client to server to handle structural search replace -- automated syntax tree based transformation of the source.
258
259**Method:** `experimental/ssr`
260
261**Request:**
262
263```typescript
264interface SsrParams {
265    /// Search query.
266    /// The specific syntax is specified outside of the protocol.
267    query: string,
268    /// If true, only check the syntax of the query and don't compute the actual edit.
269    parseOnly: boolean,
270    /// The current text document. This and `position` will be used to determine in what scope
271    /// paths in `query` should be resolved.
272    textDocument: TextDocumentIdentifier;
273    /// Position where SSR was invoked.
274    position: Position;
275    /// Current selections. Search/replace will be restricted to these if non-empty.
276    selections: Range[];
277}
278```
279
280**Response:**
281
282```typescript
283WorkspaceEdit
284```
285
286### Example
287
288SSR with query `foo($a, $b) ==>> ($a).foo($b)` will transform, eg `foo(y + 5, z)` into `(y + 5).foo(z)`.
289
290### Unresolved Question
291
292* Probably needs search without replace mode
293* Needs a way to limit the scope to certain files.
294
295## Matching Brace
296
297**Upstream Issue:** https://github.com/microsoft/language-server-protocol/issues/999
298
299**Experimental Server Capability:** `{ "matchingBrace": boolean }`
300
301This request is sent from client to server to handle "Matching Brace" editor action.
302
303**Method:** `experimental/matchingBrace`
304
305**Request:**
306
307```typescript
308interface MatchingBraceParams {
309    textDocument: TextDocumentIdentifier,
310    /// Position for each cursor
311    positions: Position[],
312}
313```
314
315**Response:**
316
317```typescript
318Position[]
319```
320
321### Example
322
323```rust
324fn main() {
325    let x: Vec<()>/*cursor here*/ = vec![]
326}
327```
328
329`experimental/matchingBrace` yields the position of `<`.
330In many cases, matching braces can be handled by the editor.
331However, some cases (like disambiguating between generics and comparison operations) need a real parser.
332Moreover, it would be cool if editors didn't need to implement even basic language parsing
333
334### Unresolved Question
335
336* Should we return a nested brace structure, to allow [paredit](https://paredit.org/)-like actions of jump *out* of the current brace pair?
337  This is how `SelectionRange` request works.
338* Alternatively, should we perhaps flag certain `SelectionRange`s as being brace pairs?
339
340## Runnables
341
342**Upstream Issue:** https://github.com/microsoft/language-server-protocol/issues/944
343
344**Experimental Server Capability:** `{ "runnables": { "kinds": string[] } }`
345
346This request is sent from client to server to get the list of things that can be run (tests, binaries, `cargo check -p`).
347
348**Method:** `experimental/runnables`
349
350**Request:**
351
352```typescript
353interface RunnablesParams {
354    textDocument: TextDocumentIdentifier;
355    /// If null, compute runnables for the whole file.
356    position?: Position;
357}
358```
359
360**Response:** `Runnable[]`
361
362```typescript
363interface Runnable {
364    label: string;
365    /// If this Runnable is associated with a specific function/module, etc, the location of this item
366    location?: LocationLink;
367    /// Running things is necessary technology specific, `kind` needs to be advertised via server capabilities,
368    // the type of `args` is specific to `kind`. The actual running is handled by the client.
369    kind: string;
370    args: any;
371}
372```
373
374rust-analyzer supports only one `kind`, `"cargo"`. The `args` for `"cargo"` look like this:
375
376```typescript
377{
378    workspaceRoot?: string;
379    cargoArgs: string[];
380    cargoExtraArgs: string[];
381    executableArgs: string[];
382    expectTest?: boolean;
383    overrideCargo?: string;
384}
385```
386
387## Open External Documentation
388
389This request is sent from the client to the server to obtain web and local URL(s) for documentation related to the symbol under the cursor, if available.
390
391**Method:** `experimental/externalDocs`
392
393**Request:** `TextDocumentPositionParams`
394
395**Response:** `string | null`
396
397## Local Documentation
398
399**Experimental Client Capability:** `{ "localDocs": boolean }`
400
401If this capability is set, the `Open External Documentation` request returned from the server will have the following structure:
402
403```typescript
404interface ExternalDocsResponse {
405    web?: string;
406    local?: string;
407}
408```
409
410## Analyzer Status
411
412**Method:** `rust-analyzer/analyzerStatus`
413
414**Request:**
415
416```typescript
417interface AnalyzerStatusParams {
418    /// If specified, show dependencies of the current file.
419    textDocument?: TextDocumentIdentifier;
420}
421```
422
423**Response:** `string`
424
425Returns internal status message, mostly for debugging purposes.
426
427## Reload Workspace
428
429**Method:** `rust-analyzer/reloadWorkspace`
430
431**Request:** `null`
432
433**Response:** `null`
434
435Reloads project information (that is, re-executes `cargo metadata`).
436
437## Rebuild proc-macros
438
439**Method:** `rust-analyzer/rebuildProcMacros`
440
441**Request:** `null`
442
443**Response:** `null`
444
445Rebuilds build scripts and proc-macros, and runs the build scripts to reseed the build data.
446
447## Server Status
448
449**Experimental Client Capability:** `{ "serverStatusNotification": boolean }`
450
451**Method:** `experimental/serverStatus`
452
453**Notification:**
454
455```typescript
456interface ServerStatusParams {
457    /// `ok` means that the server is completely functional.
458    ///
459    /// `warning` means that the server is partially functional.
460    /// It can answer correctly to most requests, but some results
461    /// might be wrong due to, for example, some missing dependencies.
462    ///
463    /// `error` means that the server is not functional. For example,
464    /// there's a fatal build configuration problem. The server might
465    /// still give correct answers to simple requests, but most results
466    /// will be incomplete or wrong.
467    health: "ok" | "warning" | "error",
468    /// Is there any pending background work which might change the status?
469    /// For example, are dependencies being downloaded?
470    quiescent: boolean,
471    /// Explanatory message to show on hover.
472    message?: string,
473}
474```
475
476This notification is sent from server to client.
477The client can use it to display *persistent* status to the user (in modline).
478It is similar to the `showMessage`, but is intended for stares rather than point-in-time events.
479
480Note that this functionality is intended primarily to inform the end user about the state of the server.
481In particular, it's valid for the client to completely ignore this extension.
482Clients are discouraged from but are allowed to use the `health` status to decide if it's worth sending a request to the server.
483
484### Controlling Flycheck
485
486The flycheck/checkOnSave feature can be controlled via notifications sent by the client to the server.
487
488**Method:** `rust-analyzer/runFlycheck`
489
490**Notification:**
491
492```typescript
493interface RunFlycheckParams {
494    /// The text document whose cargo workspace flycheck process should be started.
495    /// If the document is null or does not belong to a cargo workspace all flycheck processes will be started.
496    textDocument: lc.TextDocumentIdentifier | null;
497}
498```
499
500Triggers the flycheck processes.
501
502
503**Method:** `rust-analyzer/clearFlycheck`
504
505**Notification:**
506
507```typescript
508interface ClearFlycheckParams {}
509```
510
511Clears the flycheck diagnostics.
512
513**Method:** `rust-analyzer/cancelFlycheck`
514
515**Notification:**
516
517```typescript
518interface CancelFlycheckParams {}
519```
520
521Cancels all running flycheck processes.
522
523## Syntax Tree
524
525**Method:** `rust-analyzer/syntaxTree`
526
527**Request:**
528
529```typescript
530interface SyntaxTreeParams {
531    textDocument: TextDocumentIdentifier,
532    range?: Range,
533}
534```
535
536**Response:** `string`
537
538Returns textual representation of a parse tree for the file/selected region.
539Primarily for debugging, but very useful for all people working on rust-analyzer itself.
540
541## View Hir
542
543**Method:** `rust-analyzer/viewHir`
544
545**Request:** `TextDocumentPositionParams`
546
547**Response:** `string`
548
549Returns a textual representation of the HIR of the function containing the cursor.
550For debugging or when working on rust-analyzer itself.
551
552## View Mir
553
554**Method:** `rust-analyzer/viewMir`
555
556**Request:** `TextDocumentPositionParams`
557
558**Response:** `string`
559
560Returns a textual representation of the MIR of the function containing the cursor.
561For debugging or when working on rust-analyzer itself.
562
563## Interpret Function
564
565**Method:** `rust-analyzer/interpretFunction`
566
567**Request:** `TextDocumentPositionParams`
568
569**Response:** `string`
570
571Tries to evaluate the function using internal rust analyzer knowledge, without compiling
572the code. Currently evaluates the function under cursor, but will give a runnable in
573future. Highly experimental.
574
575## View File Text
576
577**Method:** `rust-analyzer/viewFileText`
578
579**Request:** `TextDocumentIdentifier`
580
581**Response:** `string`
582
583Returns the text of a file as seen by the server.
584This is for debugging file sync problems.
585
586## View ItemTree
587
588**Method:** `rust-analyzer/viewItemTree`
589
590**Request:**
591
592```typescript
593interface ViewItemTreeParams {
594    textDocument: TextDocumentIdentifier,
595}
596```
597
598**Response:** `string`
599
600Returns a textual representation of the `ItemTree` of the currently open file, for debugging.
601
602## View Crate Graph
603
604**Method:** `rust-analyzer/viewCrateGraph`
605
606**Request:**
607
608```typescript
609interface ViewCrateGraphParams {
610    full: boolean,
611}
612```
613
614**Response:** `string`
615
616Renders rust-analyzer's crate graph as an SVG image.
617
618If `full` is `true`, the graph includes non-workspace crates (crates.io dependencies as well as sysroot crates).
619
620## Shuffle Crate Graph
621
622**Method:** `rust-analyzer/shuffleCrateGraph`
623
624**Request:** `null`
625
626Shuffles the crate IDs in the crate graph, for debugging purposes.
627
628## Expand Macro
629
630**Method:** `rust-analyzer/expandMacro`
631
632**Request:**
633
634```typescript
635interface ExpandMacroParams {
636    textDocument: TextDocumentIdentifier,
637    position: Position,
638}
639```
640
641**Response:**
642
643```typescript
644interface ExpandedMacro {
645    name: string,
646    expansion: string,
647}
648```
649
650Expands macro call at a given position.
651
652## Hover Actions
653
654**Experimental Client Capability:** `{ "hoverActions": boolean }`
655
656If this capability is set, `Hover` request returned from the server might contain an additional field, `actions`:
657
658```typescript
659interface Hover {
660    ...
661    actions?: CommandLinkGroup[];
662}
663
664interface CommandLink extends Command {
665    /**
666     * A tooltip for the command, when represented in the UI.
667     */
668    tooltip?: string;
669}
670
671interface CommandLinkGroup {
672    title?: string;
673    commands: CommandLink[];
674}
675```
676
677Such actions on the client side are appended to a hover bottom as command links:
678```
679  +-----------------------------+
680  | Hover content               |
681  |                             |
682  +-----------------------------+
683  | _Action1_ | _Action2_       |  <- first group, no TITLE
684  +-----------------------------+
685  | TITLE _Action1_ | _Action2_ |  <- second group
686  +-----------------------------+
687  ...
688```
689
690## Open Cargo.toml
691
692**Upstream Issue:** https://github.com/rust-lang/rust-analyzer/issues/6462
693
694**Experimental Server Capability:** `{ "openCargoToml": boolean }`
695
696This request is sent from client to server to open the current project's Cargo.toml
697
698**Method:** `experimental/openCargoToml`
699
700**Request:** `OpenCargoTomlParams`
701
702**Response:** `Location | null`
703
704
705### Example
706
707```rust
708// Cargo.toml
709[package]
710// src/main.rs
711
712/* cursor here*/
713```
714
715`experimental/openCargoToml` returns a single `Link` to the start of the `[package]` keyword.
716
717## Related tests
718
719This request is sent from client to server to get the list of tests for the specified position.
720
721**Method:** `rust-analyzer/relatedTests`
722
723**Request:** `TextDocumentPositionParams`
724
725**Response:** `TestInfo[]`
726
727```typescript
728interface TestInfo {
729    runnable: Runnable;
730}
731```
732
733## Hover Range
734
735**Upstream Issue:** https://github.com/microsoft/language-server-protocol/issues/377
736
737**Experimental Server Capability:** { "hoverRange": boolean }
738
739This extension allows passing a `Range` as a `position` field of `HoverParams`.
740The primary use-case is to use the hover request to show the type of the expression currently selected.
741
742```typescript
743interface HoverParams extends WorkDoneProgressParams {
744    textDocument: TextDocumentIdentifier;
745    position: Range | Position;
746}
747```
748Whenever the client sends a `Range`, it is understood as the current selection and any hover included in the range will show the type of the expression if possible.
749
750### Example
751
752```rust
753fn main() {
754    let expression = $01 + 2 * 3$0;
755}
756```
757
758Triggering a hover inside the selection above will show a result of `i32`.
759
760## Move Item
761
762**Upstream Issue:** https://github.com/rust-lang/rust-analyzer/issues/6823
763
764This request is sent from client to server to move item under cursor or selection in some direction.
765
766**Method:** `experimental/moveItem`
767
768**Request:** `MoveItemParams`
769
770**Response:** `SnippetTextEdit[]`
771
772```typescript
773export interface MoveItemParams {
774    textDocument: TextDocumentIdentifier,
775    range: Range,
776    direction: Direction
777}
778
779export const enum Direction {
780    Up = "Up",
781    Down = "Down"
782}
783```
784
785## Workspace Symbols Filtering
786
787**Upstream Issue:** https://github.com/microsoft/language-server-protocol/issues/941
788
789**Experimental Server Capability:** `{ "workspaceSymbolScopeKindFiltering": boolean }`
790
791Extends the existing `workspace/symbol` request with ability to filter symbols by broad scope and kind of symbol.
792If this capability is set, `workspace/symbol` parameter gains two new optional fields:
793
794
795```typescript
796interface WorkspaceSymbolParams {
797    /**
798     * Return only the symbols defined in the specified scope.
799     */
800    searchScope?: WorkspaceSymbolSearchScope;
801    /**
802     * Return only the symbols of specified kinds.
803     */
804    searchKind?: WorkspaceSymbolSearchKind;
805    ...
806}
807
808const enum WorkspaceSymbolSearchScope {
809    Workspace = "workspace",
810    WorkspaceAndDependencies = "workspaceAndDependencies"
811}
812
813const enum WorkspaceSymbolSearchKind {
814    OnlyTypes = "onlyTypes",
815    AllSymbols = "allSymbols"
816}
817```
818
819## Client Commands
820
821**Upstream Issue:** https://github.com/microsoft/language-server-protocol/issues/642
822
823**Experimental Client Capability:** `{ "commands?": ClientCommandOptions }`
824
825Certain LSP types originating on the server, notably code lenses, embed commands.
826Commands can be serviced either by the server or by the client.
827However, the server doesn't know which commands are available on the client.
828
829This extensions allows the client to communicate this info.
830
831
832```typescript
833export interface ClientCommandOptions {
834    /**
835     * The commands to be executed on the client
836     */
837    commands: string[];
838}
839```
840
841## Colored Diagnostic Output
842
843**Experimental Client Capability:** `{ "colorDiagnosticOutput": boolean }`
844
845If this capability is set, the "full compiler diagnostics" provided by `checkOnSave`
846will include ANSI color and style codes to render the diagnostic in a similar manner
847as `cargo`. This is translated into `--message-format=json-diagnostic-rendered-ansi`
848when flycheck is run, instead of the default `--message-format=json`.
849
850The full compiler rendered diagnostics are included in the server response
851regardless of this capability:
852
853```typescript
854// https://microsoft.github.io/language-server-protocol/specifications/specification-current#diagnostic
855export interface Diagnostic {
856    ...
857    data?: {
858        /**
859         * The human-readable compiler output as it would be printed to a terminal.
860         * Includes ANSI color and style codes if the client has set the experimental
861         * `colorDiagnosticOutput` capability.
862         */
863        rendered?: string;
864    };
865}
866```
867
868## Dependency Tree
869
870**Method:** `rust-analyzer/fetchDependencyList`
871
872**Request:**
873
874```typescript
875export interface FetchDependencyListParams {}
876```
877
878**Response:**
879```typescript
880export interface FetchDependencyListResult {
881    crates: {
882        name: string;
883        version: string;
884        path: string;
885    }[];
886}
887```
888Returns all crates from this workspace, so it can be used create a viewTree to help navigate the dependency tree.
889