diff options
Diffstat (limited to 'docs/dev/lsp-extensions.md')
-rw-r--r-- | docs/dev/lsp-extensions.md | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md new file mode 100644 index 000000000..158d3c599 --- /dev/null +++ b/docs/dev/lsp-extensions.md | |||
@@ -0,0 +1,172 @@ | |||
1 | # LSP Extensions | ||
2 | |||
3 | This document describes LSP extensions used by rust-analyzer. | ||
4 | It's a best effort document, when in doubt, consult the source (and send a PR with clarification ;-) ). | ||
5 | We aim to upstream all non Rust-specific extensions to the protocol, but this is not a top priority. | ||
6 | All capabilities are enabled via `experimental` field of `ClientCapabilities`. | ||
7 | |||
8 | ## Snippet `TextEdit` | ||
9 | |||
10 | **Issue:** https://github.com/microsoft/language-server-protocol/issues/724 | ||
11 | |||
12 | **Client Capability:** `{ "snippetTextEdit": boolean }` | ||
13 | |||
14 | If this capability is set, `WorkspaceEdit`s returned from `codeAction` requests might contain `SnippetTextEdit`s instead of usual `TextEdit`s: | ||
15 | |||
16 | ```typescript | ||
17 | interface SnippetTextEdit extends TextEdit { | ||
18 | insertTextFormat?: InsertTextFormat; | ||
19 | } | ||
20 | ``` | ||
21 | |||
22 | ```typescript | ||
23 | export interface TextDocumentEdit { | ||
24 | textDocument: VersionedTextDocumentIdentifier; | ||
25 | edits: (TextEdit | SnippetTextEdit)[]; | ||
26 | } | ||
27 | ``` | ||
28 | |||
29 | When applying such code action, the editor should insert snippet, with tab stops and placeholder. | ||
30 | At the moment, rust-analyzer guarantees that only a single edit will have `InsertTextFormat.Snippet`. | ||
31 | |||
32 | ### Example | ||
33 | |||
34 | "Add `derive`" code action transforms `struct S;` into `#[derive($0)] struct S;` | ||
35 | |||
36 | ### Unresolved Questions | ||
37 | |||
38 | * Where exactly are `SnippetTextEdit`s allowed (only in code actions at the moment)? | ||
39 | * Can snippets span multiple files (so far, no)? | ||
40 | |||
41 | ## Join Lines | ||
42 | |||
43 | **Issue:** https://github.com/microsoft/language-server-protocol/issues/992 | ||
44 | |||
45 | **Server Capability:** `{ "joinLines": boolean }` | ||
46 | |||
47 | This request is send from client to server to handle "Join Lines" editor action. | ||
48 | |||
49 | **Method:** `experimental/JoinLines` | ||
50 | |||
51 | **Request:** | ||
52 | |||
53 | ```typescript | ||
54 | interface JoinLinesParams { | ||
55 | textDocument: TextDocumentIdentifier, | ||
56 | /// Currently active selections/cursor offsets. | ||
57 | /// This is an array to support multiple cursors. | ||
58 | ranges: Range[], | ||
59 | } | ||
60 | ``` | ||
61 | |||
62 | **Response:** | ||
63 | |||
64 | ```typescript | ||
65 | TextEdit[] | ||
66 | ``` | ||
67 | |||
68 | ### Example | ||
69 | |||
70 | ```rust | ||
71 | fn main() { | ||
72 | /*cursor here*/let x = { | ||
73 | 92 | ||
74 | }; | ||
75 | } | ||
76 | ``` | ||
77 | |||
78 | `experimental/joinLines` yields (curly braces are automagiacally removed) | ||
79 | |||
80 | ```rust | ||
81 | fn main() { | ||
82 | let x = 92; | ||
83 | } | ||
84 | ``` | ||
85 | |||
86 | ### Unresolved Question | ||
87 | |||
88 | * What is the position of the cursor after `joinLines`? | ||
89 | Currently this is left to editor's discretion, but it might be useful to specify on the server via snippets. | ||
90 | However, it then becomes unclear how it works with multi cursor. | ||
91 | |||
92 | ## Structural Search Replace (SSR) | ||
93 | |||
94 | **Server Capability:** `{ "ssr": boolean }` | ||
95 | |||
96 | This request is send from client to server to handle structural search replace -- automated syntax tree based transformation of the source. | ||
97 | |||
98 | **Method:** `experimental/ssr` | ||
99 | |||
100 | **Request:** | ||
101 | |||
102 | ```typescript | ||
103 | interface SsrParams { | ||
104 | /// Search query. | ||
105 | /// The specific syntax is specified outside of the protocol. | ||
106 | query: string, | ||
107 | /// If true, only check the syntax of the query and don't compute the actual edit. | ||
108 | parseOnly: bool, | ||
109 | } | ||
110 | ``` | ||
111 | |||
112 | **Response:** | ||
113 | |||
114 | ```typescript | ||
115 | WorkspaceEdit | ||
116 | ``` | ||
117 | |||
118 | ### Example | ||
119 | |||
120 | SSR with query `foo($a:expr, $b:expr) ==>> ($a).foo($b)` will transform, eg `foo(y + 5, z)` into `(y + 5).foo(z)`. | ||
121 | |||
122 | ### Unresolved Question | ||
123 | |||
124 | * Probably needs search without replace mode | ||
125 | * Needs a way to limit the scope to certain files. | ||
126 | |||
127 | ## `CodeAction` Groups | ||
128 | |||
129 | **Issue:** https://github.com/microsoft/language-server-protocol/issues/994 | ||
130 | |||
131 | **Client Capability:** `{ "codeActionGroup": boolean }` | ||
132 | |||
133 | If this capability is set, `CodeAction` returned from the server contain an additional field, `group`: | ||
134 | |||
135 | ```typescript | ||
136 | interface CodeAction { | ||
137 | title: string; | ||
138 | group?: string; | ||
139 | ... | ||
140 | } | ||
141 | ``` | ||
142 | |||
143 | All code-actions with the same `group` should be grouped under single (extendable) entry in lightbulb menu. | ||
144 | The set of actions `[ { title: "foo" }, { group: "frobnicate", title: "bar" }, { group: "frobnicate", title: "baz" }]` should be rendered as | ||
145 | |||
146 | ``` | ||
147 | 💡 | ||
148 | +-------------+ | ||
149 | | foo | | ||
150 | +-------------+-----+ | ||
151 | | frobnicate >| bar | | ||
152 | +-------------+-----+ | ||
153 | | baz | | ||
154 | +-----+ | ||
155 | ``` | ||
156 | |||
157 | Alternatively, selecting `frobnicate` could present a user with an additional menu to choose between `bar` and `baz`. | ||
158 | |||
159 | ### Example | ||
160 | |||
161 | ```rust | ||
162 | fn main() { | ||
163 | let x: Entry/*cursor here*/ = todo!(); | ||
164 | } | ||
165 | ``` | ||
166 | |||
167 | Invoking 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. | ||
168 | |||
169 | ### Unresolved Questions | ||
170 | |||
171 | * Is a fixed two-level structure enough? | ||
172 | * Should we devise a general way to encode custom interaction protocols for GUI refactorings? | ||