1 //! rust-analyzer extensions to the LSP.
2
3 use std::{collections::HashMap, path::PathBuf};
4
5 use ide_db::line_index::WideEncoding;
6 use lsp_types::request::Request;
7 use lsp_types::{
8 notification::Notification, CodeActionKind, DocumentOnTypeFormattingParams,
9 PartialResultParams, Position, Range, TextDocumentIdentifier, WorkDoneProgressParams,
10 };
11 use lsp_types::{PositionEncodingKind, Url};
12 use serde::{Deserialize, Serialize};
13
14 use crate::line_index::PositionEncoding;
15
16 pub enum AnalyzerStatus {}
17
18 impl Request for AnalyzerStatus {
19 type Params = AnalyzerStatusParams;
20 type Result = String;
21 const METHOD: &'static str = "rust-analyzer/analyzerStatus";
22 }
23
24 #[derive(Deserialize, Serialize, Debug)]
25 #[serde(rename_all = "camelCase")]
26 pub struct AnalyzerStatusParams {
27 pub text_document: Option<TextDocumentIdentifier>,
28 }
29
30 #[derive(Deserialize, Serialize, Debug)]
31 #[serde(rename_all = "camelCase")]
32 pub struct CrateInfoResult {
33 pub name: Option<String>,
34 pub version: Option<String>,
35 pub path: Url,
36 }
37 pub enum FetchDependencyList {}
38
39 impl Request for FetchDependencyList {
40 type Params = FetchDependencyListParams;
41 type Result = FetchDependencyListResult;
42 const METHOD: &'static str = "rust-analyzer/fetchDependencyList";
43 }
44
45 #[derive(Deserialize, Serialize, Debug)]
46 #[serde(rename_all = "camelCase")]
47 pub struct FetchDependencyListParams {}
48
49 #[derive(Deserialize, Serialize, Debug)]
50 #[serde(rename_all = "camelCase")]
51 pub struct FetchDependencyListResult {
52 pub crates: Vec<CrateInfoResult>,
53 }
54
55 pub enum MemoryUsage {}
56
57 impl Request for MemoryUsage {
58 type Params = ();
59 type Result = String;
60 const METHOD: &'static str = "rust-analyzer/memoryUsage";
61 }
62
63 pub enum ShuffleCrateGraph {}
64
65 impl Request for ShuffleCrateGraph {
66 type Params = ();
67 type Result = ();
68 const METHOD: &'static str = "rust-analyzer/shuffleCrateGraph";
69 }
70
71 pub enum ReloadWorkspace {}
72
73 impl Request for ReloadWorkspace {
74 type Params = ();
75 type Result = ();
76 const METHOD: &'static str = "rust-analyzer/reloadWorkspace";
77 }
78
79 pub enum RebuildProcMacros {}
80
81 impl Request for RebuildProcMacros {
82 type Params = ();
83 type Result = ();
84 const METHOD: &'static str = "rust-analyzer/rebuildProcMacros";
85 }
86
87 pub enum SyntaxTree {}
88
89 impl Request for SyntaxTree {
90 type Params = SyntaxTreeParams;
91 type Result = String;
92 const METHOD: &'static str = "rust-analyzer/syntaxTree";
93 }
94
95 #[derive(Deserialize, Serialize, Debug)]
96 #[serde(rename_all = "camelCase")]
97 pub struct SyntaxTreeParams {
98 pub text_document: TextDocumentIdentifier,
99 pub range: Option<Range>,
100 }
101
102 pub enum ViewHir {}
103
104 impl Request for ViewHir {
105 type Params = lsp_types::TextDocumentPositionParams;
106 type Result = String;
107 const METHOD: &'static str = "rust-analyzer/viewHir";
108 }
109
110 pub enum ViewMir {}
111
112 impl Request for ViewMir {
113 type Params = lsp_types::TextDocumentPositionParams;
114 type Result = String;
115 const METHOD: &'static str = "rust-analyzer/viewMir";
116 }
117
118 pub enum InterpretFunction {}
119
120 impl Request for InterpretFunction {
121 type Params = lsp_types::TextDocumentPositionParams;
122 type Result = String;
123 const METHOD: &'static str = "rust-analyzer/interpretFunction";
124 }
125
126 pub enum ViewFileText {}
127
128 impl Request for ViewFileText {
129 type Params = lsp_types::TextDocumentIdentifier;
130 type Result = String;
131 const METHOD: &'static str = "rust-analyzer/viewFileText";
132 }
133
134 #[derive(Deserialize, Serialize, Debug)]
135 #[serde(rename_all = "camelCase")]
136 pub struct ViewCrateGraphParams {
137 /// Include *all* crates, not just crates in the workspace.
138 pub full: bool,
139 }
140
141 pub enum ViewCrateGraph {}
142
143 impl Request for ViewCrateGraph {
144 type Params = ViewCrateGraphParams;
145 type Result = String;
146 const METHOD: &'static str = "rust-analyzer/viewCrateGraph";
147 }
148
149 #[derive(Deserialize, Serialize, Debug)]
150 #[serde(rename_all = "camelCase")]
151 pub struct ViewItemTreeParams {
152 pub text_document: TextDocumentIdentifier,
153 }
154
155 pub enum ViewItemTree {}
156
157 impl Request for ViewItemTree {
158 type Params = ViewItemTreeParams;
159 type Result = String;
160 const METHOD: &'static str = "rust-analyzer/viewItemTree";
161 }
162
163 pub enum ExpandMacro {}
164
165 impl Request for ExpandMacro {
166 type Params = ExpandMacroParams;
167 type Result = Option<ExpandedMacro>;
168 const METHOD: &'static str = "rust-analyzer/expandMacro";
169 }
170
171 #[derive(Deserialize, Serialize, Debug)]
172 #[serde(rename_all = "camelCase")]
173 pub struct ExpandMacroParams {
174 pub text_document: TextDocumentIdentifier,
175 pub position: Position,
176 }
177
178 #[derive(Deserialize, Serialize, Debug)]
179 #[serde(rename_all = "camelCase")]
180 pub struct ExpandedMacro {
181 pub name: String,
182 pub expansion: String,
183 }
184
185 pub enum CancelFlycheck {}
186
187 impl Notification for CancelFlycheck {
188 type Params = ();
189 const METHOD: &'static str = "rust-analyzer/cancelFlycheck";
190 }
191
192 pub enum RunFlycheck {}
193
194 impl Notification for RunFlycheck {
195 type Params = RunFlycheckParams;
196 const METHOD: &'static str = "rust-analyzer/runFlycheck";
197 }
198
199 pub enum ClearFlycheck {}
200
201 impl Notification for ClearFlycheck {
202 type Params = ();
203 const METHOD: &'static str = "rust-analyzer/clearFlycheck";
204 }
205
206 pub enum OpenServerLogs {}
207
208 impl Notification for OpenServerLogs {
209 type Params = ();
210 const METHOD: &'static str = "rust-analyzer/openServerLogs";
211 }
212
213 #[derive(Deserialize, Serialize, Debug)]
214 #[serde(rename_all = "camelCase")]
215 pub struct RunFlycheckParams {
216 pub text_document: Option<TextDocumentIdentifier>,
217 }
218
219 pub enum MatchingBrace {}
220
221 impl Request for MatchingBrace {
222 type Params = MatchingBraceParams;
223 type Result = Vec<Position>;
224 const METHOD: &'static str = "experimental/matchingBrace";
225 }
226
227 #[derive(Deserialize, Serialize, Debug)]
228 #[serde(rename_all = "camelCase")]
229 pub struct MatchingBraceParams {
230 pub text_document: TextDocumentIdentifier,
231 pub positions: Vec<Position>,
232 }
233
234 pub enum ParentModule {}
235
236 impl Request for ParentModule {
237 type Params = lsp_types::TextDocumentPositionParams;
238 type Result = Option<lsp_types::GotoDefinitionResponse>;
239 const METHOD: &'static str = "experimental/parentModule";
240 }
241
242 pub enum JoinLines {}
243
244 impl Request for JoinLines {
245 type Params = JoinLinesParams;
246 type Result = Vec<lsp_types::TextEdit>;
247 const METHOD: &'static str = "experimental/joinLines";
248 }
249
250 #[derive(Deserialize, Serialize, Debug)]
251 #[serde(rename_all = "camelCase")]
252 pub struct JoinLinesParams {
253 pub text_document: TextDocumentIdentifier,
254 pub ranges: Vec<Range>,
255 }
256
257 pub enum OnEnter {}
258
259 impl Request for OnEnter {
260 type Params = lsp_types::TextDocumentPositionParams;
261 type Result = Option<Vec<SnippetTextEdit>>;
262 const METHOD: &'static str = "experimental/onEnter";
263 }
264
265 pub enum Runnables {}
266
267 impl Request for Runnables {
268 type Params = RunnablesParams;
269 type Result = Vec<Runnable>;
270 const METHOD: &'static str = "experimental/runnables";
271 }
272
273 #[derive(Serialize, Deserialize, Debug)]
274 #[serde(rename_all = "camelCase")]
275 pub struct RunnablesParams {
276 pub text_document: TextDocumentIdentifier,
277 pub position: Option<Position>,
278 }
279
280 #[derive(Deserialize, Serialize, Debug)]
281 #[serde(rename_all = "camelCase")]
282 pub struct Runnable {
283 pub label: String,
284 #[serde(skip_serializing_if = "Option::is_none")]
285 pub location: Option<lsp_types::LocationLink>,
286 pub kind: RunnableKind,
287 pub args: CargoRunnable,
288 }
289
290 #[derive(Serialize, Deserialize, Debug)]
291 #[serde(rename_all = "lowercase")]
292 pub enum RunnableKind {
293 Cargo,
294 }
295
296 #[derive(Deserialize, Serialize, Debug)]
297 #[serde(rename_all = "camelCase")]
298 pub struct CargoRunnable {
299 // command to be executed instead of cargo
300 pub override_cargo: Option<String>,
301 #[serde(skip_serializing_if = "Option::is_none")]
302 pub workspace_root: Option<PathBuf>,
303 // command, --package and --lib stuff
304 pub cargo_args: Vec<String>,
305 // user-specified additional cargo args, like `--release`.
306 pub cargo_extra_args: Vec<String>,
307 // stuff after --
308 pub executable_args: Vec<String>,
309 #[serde(skip_serializing_if = "Option::is_none")]
310 pub expect_test: Option<bool>,
311 }
312
313 pub enum RelatedTests {}
314
315 impl Request for RelatedTests {
316 type Params = lsp_types::TextDocumentPositionParams;
317 type Result = Vec<TestInfo>;
318 const METHOD: &'static str = "rust-analyzer/relatedTests";
319 }
320
321 #[derive(Debug, Deserialize, Serialize)]
322 pub struct TestInfo {
323 pub runnable: Runnable,
324 }
325
326 #[derive(Serialize, Deserialize, Debug)]
327 #[serde(rename_all = "camelCase")]
328 pub struct InlayHintsParams {
329 pub text_document: TextDocumentIdentifier,
330 pub range: Option<lsp_types::Range>,
331 }
332
333 pub enum Ssr {}
334
335 impl Request for Ssr {
336 type Params = SsrParams;
337 type Result = lsp_types::WorkspaceEdit;
338 const METHOD: &'static str = "experimental/ssr";
339 }
340
341 #[derive(Debug, Deserialize, Serialize)]
342 #[serde(rename_all = "camelCase")]
343 pub struct SsrParams {
344 pub query: String,
345 pub parse_only: bool,
346
347 /// File position where SSR was invoked. Paths in `query` will be resolved relative to this
348 /// position.
349 #[serde(flatten)]
350 pub position: lsp_types::TextDocumentPositionParams,
351
352 /// Current selections. Search/replace will be restricted to these if non-empty.
353 pub selections: Vec<lsp_types::Range>,
354 }
355
356 pub enum ServerStatusNotification {}
357
358 impl Notification for ServerStatusNotification {
359 type Params = ServerStatusParams;
360 const METHOD: &'static str = "experimental/serverStatus";
361 }
362
363 #[derive(Deserialize, Serialize, PartialEq, Eq, Clone)]
364 pub struct ServerStatusParams {
365 pub health: Health,
366 pub quiescent: bool,
367 pub message: Option<String>,
368 }
369
370 #[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
371 #[serde(rename_all = "camelCase")]
372 pub enum Health {
373 Ok,
374 Warning,
375 Error,
376 }
377
378 pub enum CodeActionRequest {}
379
380 impl Request for CodeActionRequest {
381 type Params = lsp_types::CodeActionParams;
382 type Result = Option<Vec<CodeAction>>;
383 const METHOD: &'static str = "textDocument/codeAction";
384 }
385
386 pub enum CodeActionResolveRequest {}
387
388 impl Request for CodeActionResolveRequest {
389 type Params = CodeAction;
390 type Result = CodeAction;
391 const METHOD: &'static str = "codeAction/resolve";
392 }
393
394 #[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
395 #[serde(rename_all = "camelCase")]
396 pub struct CodeAction {
397 pub title: String,
398 #[serde(skip_serializing_if = "Option::is_none")]
399 pub group: Option<String>,
400 #[serde(skip_serializing_if = "Option::is_none")]
401 pub kind: Option<CodeActionKind>,
402 #[serde(skip_serializing_if = "Option::is_none")]
403 pub command: Option<lsp_types::Command>,
404 #[serde(skip_serializing_if = "Option::is_none")]
405 pub edit: Option<SnippetWorkspaceEdit>,
406 #[serde(skip_serializing_if = "Option::is_none")]
407 pub is_preferred: Option<bool>,
408
409 #[serde(skip_serializing_if = "Option::is_none")]
410 pub data: Option<CodeActionData>,
411 }
412
413 #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
414 #[serde(rename_all = "camelCase")]
415 pub struct CodeActionData {
416 pub code_action_params: lsp_types::CodeActionParams,
417 pub id: String,
418 }
419
420 #[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
421 #[serde(rename_all = "camelCase")]
422 pub struct SnippetWorkspaceEdit {
423 #[serde(skip_serializing_if = "Option::is_none")]
424 pub changes: Option<HashMap<lsp_types::Url, Vec<lsp_types::TextEdit>>>,
425 #[serde(skip_serializing_if = "Option::is_none")]
426 pub document_changes: Option<Vec<SnippetDocumentChangeOperation>>,
427 #[serde(skip_serializing_if = "Option::is_none")]
428 pub change_annotations:
429 Option<HashMap<lsp_types::ChangeAnnotationIdentifier, lsp_types::ChangeAnnotation>>,
430 }
431
432 #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
433 #[serde(untagged, rename_all = "lowercase")]
434 pub enum SnippetDocumentChangeOperation {
435 Op(lsp_types::ResourceOp),
436 Edit(SnippetTextDocumentEdit),
437 }
438
439 #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
440 #[serde(rename_all = "camelCase")]
441 pub struct SnippetTextDocumentEdit {
442 pub text_document: lsp_types::OptionalVersionedTextDocumentIdentifier,
443 pub edits: Vec<SnippetTextEdit>,
444 }
445
446 #[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
447 #[serde(rename_all = "camelCase")]
448 pub struct SnippetTextEdit {
449 pub range: Range,
450 pub new_text: String,
451 #[serde(skip_serializing_if = "Option::is_none")]
452 pub insert_text_format: Option<lsp_types::InsertTextFormat>,
453 /// The annotation id if this is an annotated
454 #[serde(skip_serializing_if = "Option::is_none")]
455 pub annotation_id: Option<lsp_types::ChangeAnnotationIdentifier>,
456 }
457
458 pub enum HoverRequest {}
459
460 impl Request for HoverRequest {
461 type Params = HoverParams;
462 type Result = Option<Hover>;
463 const METHOD: &'static str = lsp_types::request::HoverRequest::METHOD;
464 }
465
466 #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
467 #[serde(rename_all = "camelCase")]
468 pub struct HoverParams {
469 pub text_document: TextDocumentIdentifier,
470 pub position: PositionOrRange,
471
472 #[serde(flatten)]
473 pub work_done_progress_params: WorkDoneProgressParams,
474 }
475
476 #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
477 #[serde(untagged)]
478 pub enum PositionOrRange {
479 Position(lsp_types::Position),
480 Range(lsp_types::Range),
481 }
482
483 #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
484 pub struct Hover {
485 #[serde(flatten)]
486 pub hover: lsp_types::Hover,
487 #[serde(skip_serializing_if = "Vec::is_empty")]
488 pub actions: Vec<CommandLinkGroup>,
489 }
490
491 #[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
492 pub struct CommandLinkGroup {
493 #[serde(skip_serializing_if = "Option::is_none")]
494 pub title: Option<String>,
495 pub commands: Vec<CommandLink>,
496 }
497
498 // LSP v3.15 Command does not have a `tooltip` field, vscode supports one.
499 #[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
500 pub struct CommandLink {
501 #[serde(flatten)]
502 pub command: lsp_types::Command,
503 #[serde(skip_serializing_if = "Option::is_none")]
504 pub tooltip: Option<String>,
505 }
506
507 pub enum ExternalDocs {}
508
509 impl Request for ExternalDocs {
510 type Params = lsp_types::TextDocumentPositionParams;
511 type Result = ExternalDocsResponse;
512 const METHOD: &'static str = "experimental/externalDocs";
513 }
514
515 #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
516 #[serde(untagged)]
517 pub enum ExternalDocsResponse {
518 Simple(Option<lsp_types::Url>),
519 WithLocal(ExternalDocsPair),
520 }
521
522 #[derive(Debug, Default, PartialEq, Serialize, Deserialize, Clone)]
523 #[serde(rename_all = "camelCase")]
524 pub struct ExternalDocsPair {
525 pub web: Option<lsp_types::Url>,
526 pub local: Option<lsp_types::Url>,
527 }
528
529 pub enum OpenCargoToml {}
530
531 impl Request for OpenCargoToml {
532 type Params = OpenCargoTomlParams;
533 type Result = Option<lsp_types::GotoDefinitionResponse>;
534 const METHOD: &'static str = "experimental/openCargoToml";
535 }
536
537 #[derive(Serialize, Deserialize, Debug)]
538 #[serde(rename_all = "camelCase")]
539 pub struct OpenCargoTomlParams {
540 pub text_document: TextDocumentIdentifier,
541 }
542
543 /// Information about CodeLens, that is to be resolved.
544 #[derive(Debug, Serialize, Deserialize)]
545 #[serde(rename_all = "camelCase")]
546 pub struct CodeLensResolveData {
547 pub version: i32,
548 pub kind: CodeLensResolveDataKind,
549 }
550
551 #[derive(Debug, Serialize, Deserialize)]
552 #[serde(rename_all = "camelCase")]
553 pub enum CodeLensResolveDataKind {
554 Impls(lsp_types::request::GotoImplementationParams),
555 References(lsp_types::TextDocumentPositionParams),
556 }
557
negotiated_encoding(caps: &lsp_types::ClientCapabilities) -> PositionEncoding558 pub fn negotiated_encoding(caps: &lsp_types::ClientCapabilities) -> PositionEncoding {
559 let client_encodings = match &caps.general {
560 Some(general) => general.position_encodings.as_deref().unwrap_or_default(),
561 None => &[],
562 };
563
564 for enc in client_encodings {
565 if enc == &PositionEncodingKind::UTF8 {
566 return PositionEncoding::Utf8;
567 } else if enc == &PositionEncodingKind::UTF32 {
568 return PositionEncoding::Wide(WideEncoding::Utf32);
569 }
570 // NB: intentionally prefer just about anything else to utf-16.
571 }
572
573 PositionEncoding::Wide(WideEncoding::Utf16)
574 }
575
576 pub enum MoveItem {}
577
578 impl Request for MoveItem {
579 type Params = MoveItemParams;
580 type Result = Vec<SnippetTextEdit>;
581 const METHOD: &'static str = "experimental/moveItem";
582 }
583
584 #[derive(Serialize, Deserialize, Debug)]
585 #[serde(rename_all = "camelCase")]
586 pub struct MoveItemParams {
587 pub direction: MoveItemDirection,
588 pub text_document: TextDocumentIdentifier,
589 pub range: Range,
590 }
591
592 #[derive(Serialize, Deserialize, Debug)]
593 pub enum MoveItemDirection {
594 Up,
595 Down,
596 }
597
598 #[derive(Debug)]
599 pub enum WorkspaceSymbol {}
600
601 impl Request for WorkspaceSymbol {
602 type Params = WorkspaceSymbolParams;
603 type Result = Option<Vec<lsp_types::SymbolInformation>>;
604 const METHOD: &'static str = "workspace/symbol";
605 }
606
607 #[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
608 #[serde(rename_all = "camelCase")]
609 pub struct WorkspaceSymbolParams {
610 #[serde(flatten)]
611 pub partial_result_params: PartialResultParams,
612
613 #[serde(flatten)]
614 pub work_done_progress_params: WorkDoneProgressParams,
615
616 /// A non-empty query string
617 pub query: String,
618
619 pub search_scope: Option<WorkspaceSymbolSearchScope>,
620
621 pub search_kind: Option<WorkspaceSymbolSearchKind>,
622 }
623
624 #[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
625 #[serde(rename_all = "camelCase")]
626 pub enum WorkspaceSymbolSearchScope {
627 Workspace,
628 WorkspaceAndDependencies,
629 }
630
631 #[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
632 #[serde(rename_all = "camelCase")]
633 pub enum WorkspaceSymbolSearchKind {
634 OnlyTypes,
635 AllSymbols,
636 }
637
638 /// The document on type formatting request is sent from the client to
639 /// the server to format parts of the document during typing. This is
640 /// almost same as lsp_types::request::OnTypeFormatting, but the
641 /// result has SnippetTextEdit in it instead of TextEdit.
642 #[derive(Debug)]
643 pub enum OnTypeFormatting {}
644
645 impl Request for OnTypeFormatting {
646 type Params = DocumentOnTypeFormattingParams;
647 type Result = Option<Vec<SnippetTextEdit>>;
648 const METHOD: &'static str = "textDocument/onTypeFormatting";
649 }
650
651 #[derive(Debug, Serialize, Deserialize)]
652 pub struct CompletionResolveData {
653 pub position: lsp_types::TextDocumentPositionParams,
654 pub imports: Vec<CompletionImport>,
655 }
656
657 #[derive(Debug, Serialize, Deserialize)]
658 pub struct InlayHintResolveData {}
659
660 #[derive(Debug, Serialize, Deserialize)]
661 pub struct CompletionImport {
662 pub full_import_path: String,
663 pub imported_name: String,
664 }
665
666 #[derive(Debug, Deserialize, Default)]
667 pub struct ClientCommandOptions {
668 pub commands: Vec<String>,
669 }
670