]> git.proxmox.com Git - rustc.git/blob - src/tools/rust-analyzer/crates/rust-analyzer/src/caps.rs
New upstream version 1.68.2+dfsg1
[rustc.git] / src / tools / rust-analyzer / crates / rust-analyzer / src / caps.rs
1 //! Advertises the capabilities of the LSP Server.
2 use lsp_types::{
3 CallHierarchyServerCapability, ClientCapabilities, CodeActionKind, CodeActionOptions,
4 CodeActionProviderCapability, CodeLensOptions, CompletionOptions,
5 CompletionOptionsCompletionItem, DeclarationCapability, DocumentOnTypeFormattingOptions,
6 FileOperationFilter, FileOperationPattern, FileOperationPatternKind,
7 FileOperationRegistrationOptions, FoldingRangeProviderCapability, HoverProviderCapability,
8 ImplementationProviderCapability, InlayHintOptions, InlayHintServerCapabilities, OneOf,
9 PositionEncodingKind, RenameOptions, SaveOptions, SelectionRangeProviderCapability,
10 SemanticTokensFullOptions, SemanticTokensLegend, SemanticTokensOptions, ServerCapabilities,
11 SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind,
12 TextDocumentSyncOptions, TypeDefinitionProviderCapability, WorkDoneProgressOptions,
13 WorkspaceFileOperationsServerCapabilities, WorkspaceServerCapabilities,
14 };
15 use serde_json::json;
16
17 use crate::config::{Config, RustfmtConfig};
18 use crate::lsp_ext::supports_utf8;
19 use crate::semantic_tokens;
20
21 pub fn server_capabilities(config: &Config) -> ServerCapabilities {
22 ServerCapabilities {
23 position_encoding: if supports_utf8(config.caps()) {
24 Some(PositionEncodingKind::UTF8)
25 } else {
26 None
27 },
28 text_document_sync: Some(TextDocumentSyncCapability::Options(TextDocumentSyncOptions {
29 open_close: Some(true),
30 change: Some(TextDocumentSyncKind::INCREMENTAL),
31 will_save: None,
32 will_save_wait_until: None,
33 save: Some(SaveOptions::default().into()),
34 })),
35 hover_provider: Some(HoverProviderCapability::Simple(true)),
36 completion_provider: Some(CompletionOptions {
37 resolve_provider: completions_resolve_provider(config.caps()),
38 trigger_characters: Some(vec![
39 ":".to_string(),
40 ".".to_string(),
41 "'".to_string(),
42 "(".to_string(),
43 ]),
44 all_commit_characters: None,
45 completion_item: completion_item(config),
46 work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None },
47 }),
48 signature_help_provider: Some(SignatureHelpOptions {
49 trigger_characters: Some(vec!["(".to_string(), ",".to_string(), "<".to_string()]),
50 retrigger_characters: None,
51 work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None },
52 }),
53 declaration_provider: Some(DeclarationCapability::Simple(true)),
54 definition_provider: Some(OneOf::Left(true)),
55 type_definition_provider: Some(TypeDefinitionProviderCapability::Simple(true)),
56 implementation_provider: Some(ImplementationProviderCapability::Simple(true)),
57 references_provider: Some(OneOf::Left(true)),
58 document_highlight_provider: Some(OneOf::Left(true)),
59 document_symbol_provider: Some(OneOf::Left(true)),
60 workspace_symbol_provider: Some(OneOf::Left(true)),
61 code_action_provider: Some(code_action_capabilities(config.caps())),
62 code_lens_provider: Some(CodeLensOptions { resolve_provider: Some(true) }),
63 document_formatting_provider: Some(OneOf::Left(true)),
64 document_range_formatting_provider: match config.rustfmt() {
65 RustfmtConfig::Rustfmt { enable_range_formatting: true, .. } => Some(OneOf::Left(true)),
66 _ => Some(OneOf::Left(false)),
67 },
68 document_on_type_formatting_provider: Some(DocumentOnTypeFormattingOptions {
69 first_trigger_character: "=".to_string(),
70 more_trigger_character: Some(more_trigger_character(config)),
71 }),
72 selection_range_provider: Some(SelectionRangeProviderCapability::Simple(true)),
73 folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)),
74 rename_provider: Some(OneOf::Right(RenameOptions {
75 prepare_provider: Some(true),
76 work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None },
77 })),
78 linked_editing_range_provider: None,
79 document_link_provider: None,
80 color_provider: None,
81 execute_command_provider: None,
82 workspace: Some(WorkspaceServerCapabilities {
83 workspace_folders: None,
84 file_operations: Some(WorkspaceFileOperationsServerCapabilities {
85 did_create: None,
86 will_create: None,
87 did_rename: None,
88 will_rename: Some(FileOperationRegistrationOptions {
89 filters: vec![
90 FileOperationFilter {
91 scheme: Some(String::from("file")),
92 pattern: FileOperationPattern {
93 glob: String::from("**/*.rs"),
94 matches: Some(FileOperationPatternKind::File),
95 options: None,
96 },
97 },
98 FileOperationFilter {
99 scheme: Some(String::from("file")),
100 pattern: FileOperationPattern {
101 glob: String::from("**"),
102 matches: Some(FileOperationPatternKind::Folder),
103 options: None,
104 },
105 },
106 ],
107 }),
108 did_delete: None,
109 will_delete: None,
110 }),
111 }),
112 call_hierarchy_provider: Some(CallHierarchyServerCapability::Simple(true)),
113 semantic_tokens_provider: Some(
114 SemanticTokensOptions {
115 legend: SemanticTokensLegend {
116 token_types: semantic_tokens::SUPPORTED_TYPES.to_vec(),
117 token_modifiers: semantic_tokens::SUPPORTED_MODIFIERS.to_vec(),
118 },
119
120 full: Some(SemanticTokensFullOptions::Delta { delta: Some(true) }),
121 range: Some(true),
122 work_done_progress_options: Default::default(),
123 }
124 .into(),
125 ),
126 moniker_provider: None,
127 inlay_hint_provider: Some(OneOf::Right(InlayHintServerCapabilities::Options(
128 InlayHintOptions {
129 work_done_progress_options: Default::default(),
130 resolve_provider: Some(true),
131 },
132 ))),
133 experimental: Some(json!({
134 "externalDocs": true,
135 "hoverRange": true,
136 "joinLines": true,
137 "matchingBrace": true,
138 "moveItem": true,
139 "onEnter": true,
140 "openCargoToml": true,
141 "parentModule": true,
142 "runnables": {
143 "kinds": [ "cargo" ],
144 },
145 "ssr": true,
146 "workspaceSymbolScopeKindFiltering": true,
147 })),
148 }
149 }
150
151 fn completions_resolve_provider(client_caps: &ClientCapabilities) -> Option<bool> {
152 if completion_item_edit_resolve(client_caps) {
153 Some(true)
154 } else {
155 tracing::info!("No `additionalTextEdits` completion resolve capability was found in the client capabilities, autoimport completion is disabled");
156 None
157 }
158 }
159
160 /// Parses client capabilities and returns all completion resolve capabilities rust-analyzer supports.
161 pub(crate) fn completion_item_edit_resolve(caps: &ClientCapabilities) -> bool {
162 (|| {
163 Some(
164 caps.text_document
165 .as_ref()?
166 .completion
167 .as_ref()?
168 .completion_item
169 .as_ref()?
170 .resolve_support
171 .as_ref()?
172 .properties
173 .iter()
174 .any(|cap_string| cap_string.as_str() == "additionalTextEdits"),
175 )
176 })() == Some(true)
177 }
178
179 fn completion_item(config: &Config) -> Option<CompletionOptionsCompletionItem> {
180 Some(CompletionOptionsCompletionItem {
181 label_details_support: Some(config.completion_label_details_support()),
182 })
183 }
184
185 fn code_action_capabilities(client_caps: &ClientCapabilities) -> CodeActionProviderCapability {
186 client_caps
187 .text_document
188 .as_ref()
189 .and_then(|it| it.code_action.as_ref())
190 .and_then(|it| it.code_action_literal_support.as_ref())
191 .map_or(CodeActionProviderCapability::Simple(true), |_| {
192 CodeActionProviderCapability::Options(CodeActionOptions {
193 // Advertise support for all built-in CodeActionKinds.
194 // Ideally we would base this off of the client capabilities
195 // but the client is supposed to fall back gracefully for unknown values.
196 code_action_kinds: Some(vec![
197 CodeActionKind::EMPTY,
198 CodeActionKind::QUICKFIX,
199 CodeActionKind::REFACTOR,
200 CodeActionKind::REFACTOR_EXTRACT,
201 CodeActionKind::REFACTOR_INLINE,
202 CodeActionKind::REFACTOR_REWRITE,
203 ]),
204 resolve_provider: Some(true),
205 work_done_progress_options: Default::default(),
206 })
207 })
208 }
209
210 fn more_trigger_character(config: &Config) -> Vec<String> {
211 let mut res = vec![".".to_string(), ">".to_string(), "{".to_string()];
212 if config.snippet_cap() {
213 res.push("<".to_string());
214 }
215 res
216 }