]> git.lizzy.rs Git - rust.git/blob - crates/rust-analyzer/src/lsp_ext.rs
Merge #7777
[rust.git] / crates / rust-analyzer / src / lsp_ext.rs
1 //! rust-analyzer extensions to the LSP.
2
3 use std::{collections::HashMap, path::PathBuf};
4
5 use lsp_types::request::Request;
6 use lsp_types::{
7     notification::Notification, CodeActionKind, Position, Range, TextDocumentIdentifier,
8 };
9 use serde::{Deserialize, Serialize};
10
11 pub enum AnalyzerStatus {}
12
13 impl Request for AnalyzerStatus {
14     type Params = AnalyzerStatusParams;
15     type Result = String;
16     const METHOD: &'static str = "rust-analyzer/analyzerStatus";
17 }
18
19 #[derive(Deserialize, Serialize, Debug)]
20 #[serde(rename_all = "camelCase")]
21 pub struct AnalyzerStatusParams {
22     pub text_document: Option<TextDocumentIdentifier>,
23 }
24
25 pub enum MemoryUsage {}
26
27 impl Request for MemoryUsage {
28     type Params = ();
29     type Result = String;
30     const METHOD: &'static str = "rust-analyzer/memoryUsage";
31 }
32
33 pub enum ReloadWorkspace {}
34
35 impl Request for ReloadWorkspace {
36     type Params = ();
37     type Result = ();
38     const METHOD: &'static str = "rust-analyzer/reloadWorkspace";
39 }
40
41 pub enum SyntaxTree {}
42
43 impl Request for SyntaxTree {
44     type Params = SyntaxTreeParams;
45     type Result = String;
46     const METHOD: &'static str = "rust-analyzer/syntaxTree";
47 }
48
49 #[derive(Deserialize, Serialize, Debug)]
50 #[serde(rename_all = "camelCase")]
51 pub struct SyntaxTreeParams {
52     pub text_document: TextDocumentIdentifier,
53     pub range: Option<Range>,
54 }
55
56 pub enum ViewHir {}
57
58 impl Request for ViewHir {
59     type Params = lsp_types::TextDocumentPositionParams;
60     type Result = String;
61     const METHOD: &'static str = "rust-analyzer/viewHir";
62 }
63
64 pub enum ExpandMacro {}
65
66 impl Request for ExpandMacro {
67     type Params = ExpandMacroParams;
68     type Result = Option<ExpandedMacro>;
69     const METHOD: &'static str = "rust-analyzer/expandMacro";
70 }
71
72 #[derive(Deserialize, Serialize, Debug)]
73 #[serde(rename_all = "camelCase")]
74 pub struct ExpandMacroParams {
75     pub text_document: TextDocumentIdentifier,
76     pub position: Position,
77 }
78
79 #[derive(Deserialize, Serialize, Debug)]
80 #[serde(rename_all = "camelCase")]
81 pub struct ExpandedMacro {
82     pub name: String,
83     pub expansion: String,
84 }
85
86 pub enum MatchingBrace {}
87
88 impl Request for MatchingBrace {
89     type Params = MatchingBraceParams;
90     type Result = Vec<Position>;
91     const METHOD: &'static str = "experimental/matchingBrace";
92 }
93
94 #[derive(Deserialize, Serialize, Debug)]
95 #[serde(rename_all = "camelCase")]
96 pub struct MatchingBraceParams {
97     pub text_document: TextDocumentIdentifier,
98     pub positions: Vec<Position>,
99 }
100
101 pub enum ParentModule {}
102
103 impl Request for ParentModule {
104     type Params = lsp_types::TextDocumentPositionParams;
105     type Result = Option<lsp_types::GotoDefinitionResponse>;
106     const METHOD: &'static str = "experimental/parentModule";
107 }
108
109 pub enum JoinLines {}
110
111 impl Request for JoinLines {
112     type Params = JoinLinesParams;
113     type Result = Vec<lsp_types::TextEdit>;
114     const METHOD: &'static str = "experimental/joinLines";
115 }
116
117 #[derive(Deserialize, Serialize, Debug)]
118 #[serde(rename_all = "camelCase")]
119 pub struct JoinLinesParams {
120     pub text_document: TextDocumentIdentifier,
121     pub ranges: Vec<Range>,
122 }
123
124 pub enum OnEnter {}
125
126 impl Request for OnEnter {
127     type Params = lsp_types::TextDocumentPositionParams;
128     type Result = Option<Vec<SnippetTextEdit>>;
129     const METHOD: &'static str = "experimental/onEnter";
130 }
131
132 pub enum Runnables {}
133
134 impl Request for Runnables {
135     type Params = RunnablesParams;
136     type Result = Vec<Runnable>;
137     const METHOD: &'static str = "experimental/runnables";
138 }
139
140 #[derive(Serialize, Deserialize, Debug)]
141 #[serde(rename_all = "camelCase")]
142 pub struct RunnablesParams {
143     pub text_document: TextDocumentIdentifier,
144     pub position: Option<Position>,
145 }
146
147 #[derive(Deserialize, Serialize, Debug)]
148 #[serde(rename_all = "camelCase")]
149 pub struct Runnable {
150     pub label: String,
151     #[serde(skip_serializing_if = "Option::is_none")]
152     pub location: Option<lsp_types::LocationLink>,
153     pub kind: RunnableKind,
154     pub args: CargoRunnable,
155 }
156
157 #[derive(Serialize, Deserialize, Debug)]
158 #[serde(rename_all = "lowercase")]
159 pub enum RunnableKind {
160     Cargo,
161 }
162
163 #[derive(Deserialize, Serialize, Debug)]
164 #[serde(rename_all = "camelCase")]
165 pub struct CargoRunnable {
166     // command to be executed instead of cargo
167     pub override_cargo: Option<String>,
168     #[serde(skip_serializing_if = "Option::is_none")]
169     pub workspace_root: Option<PathBuf>,
170     // command, --package and --lib stuff
171     pub cargo_args: Vec<String>,
172     // user-specified additional cargo args, like `--release`.
173     pub cargo_extra_args: Vec<String>,
174     // stuff after --
175     pub executable_args: Vec<String>,
176     #[serde(skip_serializing_if = "Option::is_none")]
177     pub expect_test: Option<bool>,
178 }
179
180 pub enum InlayHints {}
181
182 impl Request for InlayHints {
183     type Params = InlayHintsParams;
184     type Result = Vec<InlayHint>;
185     const METHOD: &'static str = "rust-analyzer/inlayHints";
186 }
187
188 #[derive(Serialize, Deserialize, Debug)]
189 #[serde(rename_all = "camelCase")]
190 pub struct InlayHintsParams {
191     pub text_document: TextDocumentIdentifier,
192 }
193
194 #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
195 pub enum InlayKind {
196     TypeHint,
197     ParameterHint,
198     ChainingHint,
199 }
200
201 #[derive(Debug, Deserialize, Serialize)]
202 pub struct InlayHint {
203     pub range: Range,
204     pub kind: InlayKind,
205     pub label: String,
206 }
207
208 pub enum Ssr {}
209
210 impl Request for Ssr {
211     type Params = SsrParams;
212     type Result = lsp_types::WorkspaceEdit;
213     const METHOD: &'static str = "experimental/ssr";
214 }
215
216 #[derive(Debug, Deserialize, Serialize)]
217 #[serde(rename_all = "camelCase")]
218 pub struct SsrParams {
219     pub query: String,
220     pub parse_only: bool,
221
222     /// File position where SSR was invoked. Paths in `query` will be resolved relative to this
223     /// position.
224     #[serde(flatten)]
225     pub position: lsp_types::TextDocumentPositionParams,
226
227     /// Current selections. Search/replace will be restricted to these if non-empty.
228     pub selections: Vec<lsp_types::Range>,
229 }
230
231 pub enum StatusNotification {}
232
233 #[derive(Serialize, Deserialize)]
234 #[serde(rename_all = "camelCase")]
235 pub enum Status {
236     Loading,
237     ReadyPartial,
238     Ready,
239     NeedsReload,
240     Invalid,
241 }
242
243 #[derive(Deserialize, Serialize)]
244 pub struct StatusParams {
245     pub status: Status,
246 }
247
248 impl Notification for StatusNotification {
249     type Params = StatusParams;
250     const METHOD: &'static str = "rust-analyzer/status";
251 }
252
253 pub enum CodeActionRequest {}
254
255 impl Request for CodeActionRequest {
256     type Params = lsp_types::CodeActionParams;
257     type Result = Option<Vec<CodeAction>>;
258     const METHOD: &'static str = "textDocument/codeAction";
259 }
260
261 pub enum CodeActionResolveRequest {}
262 impl Request for CodeActionResolveRequest {
263     type Params = CodeAction;
264     type Result = CodeAction;
265     const METHOD: &'static str = "codeAction/resolve";
266 }
267
268 #[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
269 #[serde(rename_all = "camelCase")]
270 pub struct CodeAction {
271     pub title: String,
272     #[serde(skip_serializing_if = "Option::is_none")]
273     pub group: Option<String>,
274     #[serde(skip_serializing_if = "Option::is_none")]
275     pub kind: Option<CodeActionKind>,
276     // We don't handle commands on the client-side
277     // #[serde(skip_serializing_if = "Option::is_none")]
278     // pub command: Option<lsp_types::Command>,
279     #[serde(skip_serializing_if = "Option::is_none")]
280     pub edit: Option<SnippetWorkspaceEdit>,
281     #[serde(skip_serializing_if = "Option::is_none")]
282     pub is_preferred: Option<bool>,
283
284     #[serde(skip_serializing_if = "Option::is_none")]
285     pub data: Option<CodeActionData>,
286 }
287
288 #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
289 #[serde(rename_all = "camelCase")]
290 pub struct CodeActionData {
291     pub code_action_params: lsp_types::CodeActionParams,
292     pub id: String,
293 }
294
295 #[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
296 #[serde(rename_all = "camelCase")]
297 pub struct SnippetWorkspaceEdit {
298     #[serde(skip_serializing_if = "Option::is_none")]
299     pub changes: Option<HashMap<lsp_types::Url, Vec<lsp_types::TextEdit>>>,
300     #[serde(skip_serializing_if = "Option::is_none")]
301     pub document_changes: Option<Vec<SnippetDocumentChangeOperation>>,
302 }
303
304 #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
305 #[serde(untagged, rename_all = "lowercase")]
306 pub enum SnippetDocumentChangeOperation {
307     Op(lsp_types::ResourceOp),
308     Edit(SnippetTextDocumentEdit),
309 }
310
311 #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
312 #[serde(rename_all = "camelCase")]
313 pub struct SnippetTextDocumentEdit {
314     pub text_document: lsp_types::OptionalVersionedTextDocumentIdentifier,
315     pub edits: Vec<SnippetTextEdit>,
316 }
317
318 #[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
319 #[serde(rename_all = "camelCase")]
320 pub struct SnippetTextEdit {
321     pub range: Range,
322     pub new_text: String,
323     #[serde(skip_serializing_if = "Option::is_none")]
324     pub insert_text_format: Option<lsp_types::InsertTextFormat>,
325 }
326
327 pub enum HoverRequest {}
328
329 impl Request for HoverRequest {
330     type Params = lsp_types::HoverParams;
331     type Result = Option<Hover>;
332     const METHOD: &'static str = "textDocument/hover";
333 }
334
335 #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
336 pub struct Hover {
337     #[serde(flatten)]
338     pub hover: lsp_types::Hover,
339     #[serde(skip_serializing_if = "Vec::is_empty")]
340     pub actions: Vec<CommandLinkGroup>,
341 }
342
343 #[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
344 pub struct CommandLinkGroup {
345     #[serde(skip_serializing_if = "Option::is_none")]
346     pub title: Option<String>,
347     pub commands: Vec<CommandLink>,
348 }
349
350 // LSP v3.15 Command does not have a `tooltip` field, vscode supports one.
351 #[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
352 pub struct CommandLink {
353     #[serde(flatten)]
354     pub command: lsp_types::Command,
355     #[serde(skip_serializing_if = "Option::is_none")]
356     pub tooltip: Option<String>,
357 }
358
359 pub enum ExternalDocs {}
360
361 impl Request for ExternalDocs {
362     type Params = lsp_types::TextDocumentPositionParams;
363     type Result = Option<lsp_types::Url>;
364     const METHOD: &'static str = "experimental/externalDocs";
365 }
366
367 pub enum OpenCargoToml {}
368
369 impl Request for OpenCargoToml {
370     type Params = OpenCargoTomlParams;
371     type Result = Option<lsp_types::GotoDefinitionResponse>;
372     const METHOD: &'static str = "experimental/openCargoToml";
373 }
374
375 #[derive(Serialize, Deserialize, Debug)]
376 #[serde(rename_all = "camelCase")]
377 pub struct OpenCargoTomlParams {
378     pub text_document: TextDocumentIdentifier,
379 }
380
381 /// Information about CodeLens, that is to be resolved.
382 #[derive(Debug, Serialize, Deserialize)]
383 #[serde(rename_all = "camelCase")]
384 pub(crate) enum CodeLensResolveData {
385     Impls(lsp_types::request::GotoImplementationParams),
386     References(lsp_types::TextDocumentPositionParams),
387 }
388
389 pub fn supports_utf8(caps: &lsp_types::ClientCapabilities) -> bool {
390     caps.offset_encoding.as_deref().unwrap_or_default().iter().any(|it| it == "utf-8")
391 }