aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2020-07-09 23:28:12 +0100
committerAleksey Kladov <[email protected]>2020-07-10 09:07:08 +0100
commit17edf50e2c8ce92a6f056e311d68000d64838873 (patch)
tree9df1537579505c82646c5d156a7f541bf18bd018
parent5fc84f071d8fe1792db1f20bf735ec6b85a51a2f (diff)
Avoid accidently stumping over config values
-rw-r--r--crates/rust-analyzer/src/bin/main.rs4
-rw-r--r--crates/rust-analyzer/src/config.rs293
-rw-r--r--crates/rust-analyzer/src/main_loop.rs6
3 files changed, 169 insertions, 134 deletions
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs
index 047772d0c..65f1a6d15 100644
--- a/crates/rust-analyzer/src/bin/main.rs
+++ b/crates/rust-analyzer/src/bin/main.rs
@@ -120,8 +120,8 @@ fn run_server() -> Result<()> {
120 }; 120 };
121 121
122 let mut config = Config::new(root_path); 122 let mut config = Config::new(root_path);
123 if let Some(value) = &initialize_params.initialization_options { 123 if let Some(json) = initialize_params.initialization_options {
124 config.update(value); 124 config.update(json);
125 } 125 }
126 config.update_caps(&initialize_params.capabilities); 126 config.update_caps(&initialize_params.capabilities);
127 127
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 9e7de0243..9dd81b4fc 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -111,14 +111,8 @@ pub struct NotificationsConfig {
111 111
112#[derive(Debug, Clone)] 112#[derive(Debug, Clone)]
113pub enum RustfmtConfig { 113pub enum RustfmtConfig {
114 Rustfmt { 114 Rustfmt { extra_args: Vec<String> },
115 extra_args: Vec<String>, 115 CustomCommand { command: String, args: Vec<String> },
116 },
117 #[allow(unused)]
118 CustomCommand {
119 command: String,
120 args: Vec<String>,
121 },
122} 116}
123 117
124#[derive(Debug, Clone, Default)] 118#[derive(Debug, Clone, Default)]
@@ -178,146 +172,110 @@ impl Config {
178 } 172 }
179 } 173 }
180 174
181 #[rustfmt::skip] 175 pub fn update(&mut self, json: serde_json::Value) {
182 pub fn update(&mut self, value: &serde_json::Value) { 176 log::info!("Config::update({:#})", json);
183 log::info!("Config::update({:#})", value); 177 let data = ConfigData::from_json(json);
184 178
185 let client_caps = self.client_caps.clone(); 179 self.with_sysroot = data.withSysroot;
186 let linked_projects = self.linked_projects.clone(); 180 self.publish_diagnostics = data.diagnostics_enable;
187 *self = Config::new(self.root_path.clone()); 181 self.diagnostics = DiagnosticsConfig {
188 self.client_caps = client_caps; 182 warnings_as_info: data.diagnostics_warningsAsInfo,
189 self.linked_projects = linked_projects; 183 warnings_as_hint: data.diagnostics_warningsAsHint,
190 184 };
191 set(value, "/withSysroot", &mut self.with_sysroot); 185 self.lru_capacity = data.lruCapacity;
192 set(value, "/diagnostics/enable", &mut self.publish_diagnostics); 186 self.files.watcher = match data.files_watcher.as_str() {
193 set(value, "/diagnostics/warningsAsInfo", &mut self.diagnostics.warnings_as_info); 187 "notify" => FilesWatcher::Notify,
194 set(value, "/diagnostics/warningsAsHint", &mut self.diagnostics.warnings_as_hint); 188 "client" | _ => FilesWatcher::Client,
195 set(value, "/lruCapacity", &mut self.lru_capacity); 189 };
196 self.files.watcher = match get(value, "/files/watcher") { 190 self.notifications =
197 Some("client") => FilesWatcher::Client, 191 NotificationsConfig { cargo_toml_not_found: data.notifications_cargoTomlNotFound };
198 Some("notify") | _ => FilesWatcher::Notify 192 self.cargo = CargoConfig {
193 no_default_features: data.cargo_noDefaultFeatures,
194 all_features: data.cargo_allFeatures,
195 features: data.cargo_features.clone(),
196 load_out_dirs_from_check: data.cargo_loadOutDirsFromCheck,
197 target: data.cargo_target,
199 }; 198 };
200 set(value, "/notifications/cargoTomlNotFound", &mut self.notifications.cargo_toml_not_found);
201
202 set(value, "/cargo/noDefaultFeatures", &mut self.cargo.no_default_features);
203 set(value, "/cargo/allFeatures", &mut self.cargo.all_features);
204 set(value, "/cargo/features", &mut self.cargo.features);
205 set(value, "/cargo/loadOutDirsFromCheck", &mut self.cargo.load_out_dirs_from_check);
206 set(value, "/cargo/target", &mut self.cargo.target);
207
208 match get(value, "/procMacro/enable") {
209 Some(true) => {
210 if let Ok(path) = std::env::current_exe() {
211 self.proc_macro_srv = Some((path, vec!["proc-macro".into()]));
212 }
213 }
214 _ => self.proc_macro_srv = None,
215 }
216 199
217 match get::<Vec<String>>(value, "/rustfmt/overrideCommand") { 200 self.proc_macro_srv = if data.procMacro_enable {
201 std::env::current_exe().ok().map(|path| (path, vec!["proc-macro".into()]))
202 } else {
203 None
204 };
205
206 self.rustfmt = match data.rustfmt_overrideCommand {
218 Some(mut args) if !args.is_empty() => { 207 Some(mut args) if !args.is_empty() => {
219 let command = args.remove(0); 208 let command = args.remove(0);
220 self.rustfmt = RustfmtConfig::CustomCommand { 209 RustfmtConfig::CustomCommand { command, args }
221 command,
222 args,
223 }
224 }
225 _ => {
226 if let RustfmtConfig::Rustfmt { extra_args } = &mut self.rustfmt {
227 set(value, "/rustfmt/extraArgs", extra_args);
228 }
229 } 210 }
211 Some(_) | None => RustfmtConfig::Rustfmt { extra_args: data.rustfmt_extraArgs },
230 }; 212 };
231 213
232 if let Some(false) = get(value, "/checkOnSave/enable") { 214 self.flycheck = if data.checkOnSave_enable {
233 // check is disabled 215 let flycheck_config = match data.checkOnSave_overrideCommand {
234 self.flycheck = None;
235 } else {
236 // check is enabled
237 match get::<Vec<String>>(value, "/checkOnSave/overrideCommand") {
238 // first see if the user has completely overridden the command
239 Some(mut args) if !args.is_empty() => { 216 Some(mut args) if !args.is_empty() => {
240 let command = args.remove(0); 217 let command = args.remove(0);
241 self.flycheck = Some(FlycheckConfig::CustomCommand { 218 FlycheckConfig::CustomCommand { command, args }
242 command,
243 args,
244 });
245 }
246 // otherwise configure command customizations
247 _ => {
248 if let Some(FlycheckConfig::CargoCommand { command, extra_args, all_targets, all_features, features })
249 = &mut self.flycheck
250 {
251 set(value, "/checkOnSave/extraArgs", extra_args);
252 set(value, "/checkOnSave/command", command);
253 set(value, "/checkOnSave/allTargets", all_targets);
254 *all_features = get(value, "/checkOnSave/allFeatures").unwrap_or(self.cargo.all_features);
255 *features = get(value, "/checkOnSave/features").unwrap_or(self.cargo.features.clone());
256 }
257 } 219 }
220 Some(_) | None => FlycheckConfig::CargoCommand {
221 command: data.checkOnSave_command,
222 all_targets: data.checkOnSave_allTargets,
223 all_features: data.checkOnSave_allFeatures.unwrap_or(data.cargo_allFeatures),
224 features: data.checkOnSave_features.unwrap_or(data.cargo_features),
225 extra_args: data.checkOnSave_extraArgs,
226 },
258 }; 227 };
259 } 228 Some(flycheck_config)
260
261 set(value, "/inlayHints/typeHints", &mut self.inlay_hints.type_hints);
262 set(value, "/inlayHints/parameterHints", &mut self.inlay_hints.parameter_hints);
263 set(value, "/inlayHints/chainingHints", &mut self.inlay_hints.chaining_hints);
264 set(value, "/inlayHints/maxLength", &mut self.inlay_hints.max_length);
265 set(value, "/completion/postfix/enable", &mut self.completion.enable_postfix_completions);
266 set(value, "/completion/addCallParenthesis", &mut self.completion.add_call_parenthesis);
267 set(value, "/completion/addCallArgumentSnippets", &mut self.completion.add_call_argument_snippets);
268 set(value, "/callInfo/full", &mut self.call_info_full);
269
270 let mut lens_enabled = true;
271 set(value, "/lens/enable", &mut lens_enabled);
272 if lens_enabled {
273 set(value, "/lens/run", &mut self.lens.run);
274 set(value, "/lens/debug", &mut self.lens.debug);
275 set(value, "/lens/implementations", &mut self.lens.implementations);
276 } else { 229 } else {
277 self.lens = LensConfig::NO_LENS; 230 None
278 } 231 };
279 232
280 if let Some(linked_projects) = get::<Vec<ManifestOrProjectJson>>(value, "/linkedProjects") { 233 self.inlay_hints = InlayHintsConfig {
281 if !linked_projects.is_empty() { 234 type_hints: data.inlayHints_typeHints,
282 self.linked_projects.clear(); 235 parameter_hints: data.inlayHints_parameterHints,
283 for linked_project in linked_projects { 236 chaining_hints: data.inlayHints_chainingHints,
284 let linked_project = match linked_project { 237 max_length: data.inlayHints_maxLength,
285 ManifestOrProjectJson::Manifest(it) => { 238 };
286 let path = self.root_path.join(it);
287 match ProjectManifest::from_manifest_file(path) {
288 Ok(it) => it.into(),
289 Err(_) => continue,
290 }
291 }
292 ManifestOrProjectJson::ProjectJson(it) => ProjectJson::new(&self.root_path, it).into(),
293 };
294 self.linked_projects.push(linked_project);
295 }
296 }
297 }
298 239
299 let mut use_hover_actions = false; 240 self.completion.enable_postfix_completions = data.completion_postfix_enable;
300 set(value, "/hoverActions/enable", &mut use_hover_actions); 241 self.completion.add_call_parenthesis = data.completion_addCallParenthesis;
301 if use_hover_actions { 242 self.completion.add_call_argument_snippets = data.completion_addCallArgumentSnippets;
302 set(value, "/hoverActions/implementations", &mut self.hover.implementations);
303 set(value, "/hoverActions/run", &mut self.hover.run);
304 set(value, "/hoverActions/debug", &mut self.hover.debug);
305 set(value, "/hoverActions/gotoTypeDef", &mut self.hover.goto_type_def);
306 } else {
307 self.hover = HoverConfig::NO_ACTIONS;
308 }
309 243
310 log::info!("Config::update() = {:#?}", self); 244 self.call_info_full = data.callInfo_full;
311 245
312 fn get<'a, T: Deserialize<'a>>(value: &'a serde_json::Value, pointer: &str) -> Option<T> { 246 self.lens = LensConfig {
313 value.pointer(pointer).and_then(|it| T::deserialize(it).ok()) 247 run: data.lens_enable && data.lens_run,
314 } 248 debug: data.lens_enable && data.lens_debug,
249 implementations: data.lens_enable && data.lens_implementations,
250 };
315 251
316 fn set<'a, T: Deserialize<'a>>(value: &'a serde_json::Value, pointer: &str, slot: &mut T) { 252 if !data.linkedProjects.is_empty() {
317 if let Some(new_value) = get(value, pointer) { 253 self.linked_projects.clear();
318 *slot = new_value 254 for linked_project in data.linkedProjects {
255 let linked_project = match linked_project {
256 ManifestOrProjectJson::Manifest(it) => {
257 let path = self.root_path.join(it);
258 match ProjectManifest::from_manifest_file(path) {
259 Ok(it) => it.into(),
260 Err(_) => continue,
261 }
262 }
263 ManifestOrProjectJson::ProjectJson(it) => {
264 ProjectJson::new(&self.root_path, it).into()
265 }
266 };
267 self.linked_projects.push(linked_project);
319 } 268 }
320 } 269 }
270
271 self.hover = HoverConfig {
272 implementations: data.hoverActions_enable && data.hoverActions_implementations,
273 run: data.hoverActions_enable && data.hoverActions_run,
274 debug: data.hoverActions_enable && data.hoverActions_debug,
275 goto_type_def: data.hoverActions_enable && data.hoverActions_gotoTypeDef,
276 };
277
278 log::info!("Config::update() = {:#?}", self);
321 } 279 }
322 280
323 pub fn update_caps(&mut self, caps: &ClientCapabilities) { 281 pub fn update_caps(&mut self, caps: &ClientCapabilities) {
@@ -380,3 +338,80 @@ enum ManifestOrProjectJson {
380 Manifest(PathBuf), 338 Manifest(PathBuf),
381 ProjectJson(ProjectJsonData), 339 ProjectJson(ProjectJsonData),
382} 340}
341
342macro_rules! config_data {
343 (struct $name:ident { $($field:ident: $ty:ty = $default:expr,)*}) => {
344 #[allow(non_snake_case)]
345 struct $name { $($field: $ty,)* }
346 impl $name {
347 fn from_json(mut json: serde_json::Value) -> $name {
348 $name {$(
349 $field: {
350 let pointer = stringify!($field).replace('_', "/");
351 let pointer = format!("/{}", pointer);
352 json.pointer_mut(&pointer)
353 .and_then(|it| serde_json::from_value(it.take()).ok())
354 .unwrap_or($default)
355 },
356 )*}
357 }
358 }
359
360 };
361}
362
363config_data! {
364 struct ConfigData {
365 callInfo_full: bool = true,
366
367 cargo_allFeatures: bool = false,
368 cargo_features: Vec<String> = Vec::new(),
369 cargo_loadOutDirsFromCheck: bool = false,
370 cargo_noDefaultFeatures: bool = false,
371 cargo_target: Option<String> = None,
372
373 checkOnSave_allFeatures: Option<bool> = None,
374 checkOnSave_allTargets: bool = true,
375 checkOnSave_command: String = "check".into(),
376 checkOnSave_enable: bool = false,
377 checkOnSave_extraArgs: Vec<String> = Vec::new(),
378 checkOnSave_features: Option<Vec<String>> = None,
379 checkOnSave_overrideCommand: Option<Vec<String>> = None,
380
381 completion_addCallArgumentSnippets: bool = true,
382 completion_addCallParenthesis: bool = true,
383 completion_postfix_enable: bool = true,
384
385 diagnostics_enable: bool = true,
386 diagnostics_warningsAsHint: Vec<String> = Vec::new(),
387 diagnostics_warningsAsInfo: Vec<String> = Vec::new(),
388
389 files_watcher: String = "client".into(),
390
391 hoverActions_debug: bool = true,
392 hoverActions_enable: bool = true,
393 hoverActions_gotoTypeDef: bool = true,
394 hoverActions_implementations: bool = true,
395 hoverActions_run: bool = true,
396
397 inlayHints_chainingHints: bool = true,
398 inlayHints_maxLength: Option<usize> = None,
399 inlayHints_parameterHints: bool = true,
400 inlayHints_typeHints: bool = true,
401
402 lens_debug: bool = true,
403 lens_enable: bool = true,
404 lens_implementations: bool = true,
405 lens_run: bool = true,
406
407 linkedProjects: Vec<ManifestOrProjectJson> = Vec::new(),
408 lruCapacity: Option<usize> = None,
409 notifications_cargoTomlNotFound: bool = true,
410 procMacro_enable: bool = false,
411
412 rustfmt_extraArgs: Vec<String> = Vec::new(),
413 rustfmt_overrideCommand: Option<Vec<String>> = None,
414
415 withSysroot: bool = true,
416 }
417}
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 4e556bd50..b48239058 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -467,10 +467,10 @@ impl GlobalState {
467 (Some(err), _) => { 467 (Some(err), _) => {
468 log::error!("failed to fetch the server settings: {:?}", err) 468 log::error!("failed to fetch the server settings: {:?}", err)
469 } 469 }
470 (None, Some(configs)) => { 470 (None, Some(mut configs)) => {
471 if let Some(new_config) = configs.get(0) { 471 if let Some(json) = configs.get_mut(0) {
472 let mut config = this.config.clone(); 472 let mut config = this.config.clone();
473 config.update(&new_config); 473 config.update(json.take());
474 this.update_configuration(config); 474 this.update_configuration(config);
475 } 475 }
476 } 476 }