From 797cd34c7c996251816226dac369fece1587a416 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 1 Apr 2020 17:00:37 +0200 Subject: Reduce feature flags --- crates/rust-analyzer/src/config.rs | 37 +++++++++++++++++++++++++- crates/rust-analyzer/src/main_loop.rs | 33 +++++------------------ crates/rust-analyzer/src/main_loop/handlers.rs | 16 +++-------- crates/rust-analyzer/src/world.rs | 14 +--------- 4 files changed, 48 insertions(+), 52 deletions(-) diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index fb7895ce0..94627d35d 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -9,24 +9,35 @@ use rustc_hash::FxHashMap; +use crate::feature_flags::FeatureFlags; use lsp_types::TextDocumentClientCapabilities; use ra_flycheck::FlycheckConfig; -use ra_ide::InlayHintsConfig; +use ra_ide::{CompletionConfig, InlayHintsConfig}; use ra_project_model::CargoFeatures; use serde::{Deserialize, Deserializer}; #[derive(Debug, Clone)] pub struct Config { pub publish_decorations: bool, + pub publish_diagnostics: bool, + pub notifications: NotificationsConfig, pub supports_location_link: bool, pub line_folding_only: bool, pub inlay_hints: InlayHintsConfig, + pub completion: CompletionConfig, + pub call_info_full: bool, pub rustfmt: RustfmtConfig, pub check: Option, pub vscode_lldb: bool, pub proc_macro_srv: Option, } +#[derive(Debug, Clone)] +pub struct NotificationsConfig { + pub workspace_loaded: bool, + pub cargo_toml_not_found: bool, +} + #[derive(Debug, Clone)] pub enum RustfmtConfig { Rustfmt { @@ -49,8 +60,14 @@ pub(crate) fn get_config( config: &ServerConfig, text_document_caps: Option<&TextDocumentClientCapabilities>, ) -> Config { + let feature_flags = get_feature_flags(config); Config { publish_decorations: config.publish_decorations, + publish_diagnostics: feature_flags.get("lsp.diagnostics"), + notifications: NotificationsConfig { + workspace_loaded: feature_flags.get("notifications.workspace-loaded"), + cargo_toml_not_found: feature_flags.get("notifications.cargo-toml-not-found"), + }, supports_location_link: text_document_caps .and_then(|it| it.definition) .and_then(|it| it.link_support) @@ -65,6 +82,13 @@ pub(crate) fn get_config( chaining_hints: config.inlay_hints_chaining, max_length: config.inlay_hints_max_length, }, + completion: CompletionConfig { + enable_postfix_completions: feature_flags.get("completion.enable-postfix"), + add_call_parenthesis: feature_flags.get("completion.insertion.add-call-parenthesis"), + add_call_argument_snippets: feature_flags + .get("completion.insertion.add-argument-snippets"), + }, + call_info_full: feature_flags.get("call-info.full"), check: if config.cargo_watch_enable { Some(FlycheckConfig::CargoCommand { command: config.cargo_watch_command.clone(), @@ -80,6 +104,17 @@ pub(crate) fn get_config( } } +fn get_feature_flags(config: &ServerConfig) -> FeatureFlags { + let mut ff = FeatureFlags::default(); + for (flag, &value) in &config.feature_flags { + if ff.set(flag.as_str(), value).is_err() { + log::error!("unknown feature flag: {:?}", flag); + } + } + log::info!("feature_flags: {:#?}", ff); + ff +} + /// Client provided initialization options #[derive(Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase", default)] diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index de40e2ac2..8f89fb7ea 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -33,7 +33,6 @@ use threadpool::ThreadPool; use crate::{ config::get_config, diagnostics::DiagnosticTask, - feature_flags::FeatureFlags, main_loop::{ pending_requests::{PendingRequest, PendingRequests}, subscriptions::Subscriptions, @@ -66,22 +65,6 @@ impl fmt::Display for LspError { impl Error for LspError {} -fn get_feature_flags(config: &ServerConfig, connection: &Connection) -> FeatureFlags { - let mut ff = FeatureFlags::default(); - for (flag, &value) in &config.feature_flags { - if ff.set(flag.as_str(), value).is_err() { - log::error!("unknown feature flag: {:?}", flag); - show_message( - req::MessageType::Error, - format!("unknown feature flag: {:?}", flag), - &connection.sender, - ); - } - } - log::info!("feature_flags: {:#?}", ff); - ff -} - pub fn main_loop( ws_roots: Vec, client_caps: ClientCapabilities, @@ -112,8 +95,8 @@ pub fn main_loop( let text_document_caps = client_caps.text_document.as_ref(); let mut loop_state = LoopState::default(); let mut world_state = { - let feature_flags = get_feature_flags(&config, &connection); - + // TODO: refactor + let new_config = get_config(&config, text_document_caps); // FIXME: support dynamic workspace loading. let workspaces = { let mut loaded_workspaces = Vec::new(); @@ -131,7 +114,7 @@ pub fn main_loop( if let Some(ra_project_model::CargoTomlNotFoundError { .. }) = e.downcast_ref() { - if !feature_flags.get("notifications.cargo-toml-not-found") { + if !new_config.notifications.cargo_toml_not_found { continue; } } @@ -180,8 +163,7 @@ pub fn main_loop( config.lru_capacity, &globs, Watch(!config.use_client_watching), - get_config(&config, text_document_caps), - feature_flags, + new_config, ) }; @@ -406,7 +388,6 @@ fn loop_turn( world_state.update_configuration( new_config.lru_capacity, get_config(&new_config, text_document_caps), - get_feature_flags(&new_config, connection), ); } (None, Some(Err(e))) => { @@ -441,8 +422,8 @@ fn loop_turn( }); } - let show_progress = !loop_state.workspace_loaded - && world_state.feature_flags.get("notifications.workspace-loaded"); + let show_progress = + !loop_state.workspace_loaded && world_state.config.notifications.workspace_loaded; if !loop_state.workspace_loaded && loop_state.roots_scanned == loop_state.roots_total @@ -930,7 +911,7 @@ fn update_file_notifications_on_threadpool( subscriptions: Vec, ) { log::trace!("updating notifications for {:?}", subscriptions); - let publish_diagnostics = world.feature_flags.get("lsp.diagnostics"); + let publish_diagnostics = world.config.publish_diagnostics; pool.execute(move || { for file_id in subscriptions { if publish_diagnostics { diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index bb99b38a8..d0f64f007 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs @@ -19,8 +19,8 @@ use lsp_types::{ TextEdit, WorkspaceEdit, }; use ra_ide::{ - Assist, AssistId, CompletionConfig, FileId, FilePosition, FileRange, Query, RangeInfo, - Runnable, RunnableKind, SearchScope, + Assist, AssistId, FileId, FilePosition, FileRange, Query, RangeInfo, Runnable, RunnableKind, + SearchScope, }; use ra_prof::profile; use ra_syntax::{AstNode, SyntaxKind, TextRange, TextUnit}; @@ -426,15 +426,7 @@ pub fn handle_completion( return Ok(None); } - let config = CompletionConfig { - enable_postfix_completions: world.feature_flags.get("completion.enable-postfix"), - add_call_parenthesis: world.feature_flags.get("completion.insertion.add-call-parenthesis"), - add_call_argument_snippets: world - .feature_flags - .get("completion.insertion.add-argument-snippets"), - }; - - let items = match world.analysis().completions(position, &config)? { + let items = match world.analysis().completions(position, &world.config.completion)? { None => return Ok(None), Some(items) => items, }; @@ -471,7 +463,7 @@ pub fn handle_signature_help( let _p = profile("handle_signature_help"); let position = params.try_conv_with(&world)?; if let Some(call_info) = world.analysis().call_info(position)? { - let concise = !world.feature_flags.get("call-info.full"); + let concise = !world.config.call_info_full; let mut active_parameter = call_info.active_parameter.map(|it| it as i64); if concise && call_info.signature.has_self_param { active_parameter = active_parameter.map(|it| it.saturating_sub(1)); diff --git a/crates/rust-analyzer/src/world.rs b/crates/rust-analyzer/src/world.rs index 124de4d8e..df1b7ceeb 100644 --- a/crates/rust-analyzer/src/world.rs +++ b/crates/rust-analyzer/src/world.rs @@ -23,7 +23,6 @@ use stdx::format_to; use crate::{ config::Config, diagnostics::{CheckFixes, DiagnosticCollection}, - feature_flags::FeatureFlags, main_loop::pending_requests::{CompletedRequest, LatestRequests}, vfs_glob::{Glob, RustPackageFilterBuilder}, LspError, Result, @@ -59,7 +58,6 @@ fn create_flycheck(workspaces: &[ProjectWorkspace], config: &Config) -> Option, pub roots: Vec, pub workspaces: Arc>, pub analysis_host: AnalysisHost, @@ -73,7 +71,6 @@ pub struct WorldState { /// An immutable snapshot of the world's state at a point in time. pub struct WorldSnapshot { pub config: Config, - pub feature_flags: Arc, pub workspaces: Arc>, pub analysis: Analysis, pub latest_requests: Arc>, @@ -89,7 +86,6 @@ impl WorldState { exclude_globs: &[Glob], watch: Watch, config: Config, - feature_flags: FeatureFlags, ) -> WorldState { let mut change = AnalysisChange::new(); @@ -197,7 +193,6 @@ impl WorldState { analysis_host.apply_change(change); WorldState { config: config, - feature_flags: Arc::new(feature_flags), roots: folder_roots, workspaces: Arc::new(workspaces), analysis_host, @@ -209,13 +204,7 @@ impl WorldState { } } - pub fn update_configuration( - &mut self, - lru_capacity: Option, - config: Config, - feature_flags: FeatureFlags, - ) { - self.feature_flags = Arc::new(feature_flags); + pub fn update_configuration(&mut self, lru_capacity: Option, config: Config) { self.analysis_host.update_lru_capacity(lru_capacity); self.flycheck = create_flycheck(&self.workspaces, &config); self.config = config; @@ -275,7 +264,6 @@ impl WorldState { pub fn snapshot(&self) -> WorldSnapshot { WorldSnapshot { config: self.config.clone(), - feature_flags: Arc::clone(&self.feature_flags), workspaces: Arc::clone(&self.workspaces), analysis: self.analysis_host.analysis(), vfs: Arc::clone(&self.vfs), -- cgit v1.2.3 From 1e012eb991da7344f2423ce1447917c3eb388e87 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 1 Apr 2020 17:22:56 +0200 Subject: Move all config to config --- crates/ra_project_model/src/cargo_workspace.rs | 1 + crates/rust-analyzer/src/config.rs | 10 ++++++++++ crates/rust-analyzer/src/main_loop.rs | 13 ++++++------- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs index f4fd6ad28..91735a726 100644 --- a/crates/ra_project_model/src/cargo_workspace.rs +++ b/crates/ra_project_model/src/cargo_workspace.rs @@ -43,6 +43,7 @@ impl ops::Index for CargoWorkspace { } } +// TODO: rename to CargoConfig, kill `rename_all`, kill serde dep? #[derive(Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(rename_all = "camelCase", default)] pub struct CargoFeatures { diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 94627d35d..8a8e42ed8 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -30,6 +30,11 @@ pub struct Config { pub check: Option, pub vscode_lldb: bool, pub proc_macro_srv: Option, + pub lru_capacity: Option, + pub use_client_watching: bool, + pub exclude_globs: Vec, + pub cargo: CargoFeatures, + pub with_sysroot: bool, } #[derive(Debug, Clone)] @@ -101,6 +106,11 @@ pub(crate) fn get_config( rustfmt: RustfmtConfig::Rustfmt { extra_args: config.rustfmt_args.clone() }, vscode_lldb: config.vscode_lldb, proc_macro_srv: None, // FIXME: get this from config + lru_capacity: config.lru_capacity, + use_client_watching: config.use_client_watching, + exclude_globs: config.exclude_globs.clone(), + cargo: config.cargo_features.clone(), + with_sysroot: config.with_sysroot, } } diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 8f89fb7ea..c973d43fa 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -71,7 +71,9 @@ pub fn main_loop( config: ServerConfig, connection: Connection, ) -> Result<()> { - log::info!("server_config: {:#?}", config); + let text_document_caps = client_caps.text_document.as_ref(); + let config = get_config(&config, text_document_caps); + log::info!("initial config: {:#?}", config); // Windows scheduler implements priority boosts: if thread waits for an // event (like a condvar), and event fires, priority of the thread is @@ -92,11 +94,8 @@ pub fn main_loop( SetThreadPriority(thread, thread_priority_above_normal); } - let text_document_caps = client_caps.text_document.as_ref(); let mut loop_state = LoopState::default(); let mut world_state = { - // TODO: refactor - let new_config = get_config(&config, text_document_caps); // FIXME: support dynamic workspace loading. let workspaces = { let mut loaded_workspaces = Vec::new(); @@ -104,7 +103,7 @@ pub fn main_loop( let workspace = ra_project_model::ProjectWorkspace::discover_with_sysroot( ws_root.as_path(), config.with_sysroot, - &config.cargo_features, + &config.cargo, ); match workspace { Ok(workspace) => loaded_workspaces.push(workspace), @@ -114,7 +113,7 @@ pub fn main_loop( if let Some(ra_project_model::CargoTomlNotFoundError { .. }) = e.downcast_ref() { - if !new_config.notifications.cargo_toml_not_found { + if !config.notifications.cargo_toml_not_found { continue; } } @@ -163,7 +162,7 @@ pub fn main_loop( config.lru_capacity, &globs, Watch(!config.use_client_watching), - new_config, + config, ) }; -- cgit v1.2.3 From a97e5eb85d1a8a2a07663abbd9beaae317fdb24d Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 1 Apr 2020 18:41:43 +0200 Subject: Centralize all config --- crates/ra_flycheck/src/lib.rs | 12 +- crates/rust-analyzer/src/bin/main.rs | 32 ++- crates/rust-analyzer/src/config.rs | 251 ++++++++-------------- crates/rust-analyzer/src/feature_flags.rs | 77 ------- crates/rust-analyzer/src/lib.rs | 3 +- crates/rust-analyzer/src/main_loop.rs | 43 +--- crates/rust-analyzer/src/world.rs | 20 +- crates/rust-analyzer/tests/heavy_tests/main.rs | 2 +- crates/rust-analyzer/tests/heavy_tests/support.rs | 39 +--- 9 files changed, 151 insertions(+), 328 deletions(-) delete mode 100644 crates/rust-analyzer/src/feature_flags.rs diff --git a/crates/ra_flycheck/src/lib.rs b/crates/ra_flycheck/src/lib.rs index 13494a731..f3d6f8f5f 100644 --- a/crates/ra_flycheck/src/lib.rs +++ b/crates/ra_flycheck/src/lib.rs @@ -22,12 +22,22 @@ use crate::conv::{map_rust_diagnostic_to_lsp, MappedRustDiagnostic}; pub use crate::conv::url_from_path_with_drive_lowercasing; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq, Eq)] pub enum FlycheckConfig { CargoCommand { command: String, all_targets: bool, extra_args: Vec }, CustomCommand { command: String, args: Vec }, } +impl Default for FlycheckConfig { + fn default() -> Self { + FlycheckConfig::CargoCommand { + command: "check".to_string(), + all_targets: true, + extra_args: Vec::new(), + } + } +} + /// Flycheck wraps the shared state and communication machinery used for /// running `cargo check` (or other compatible command) and providing /// diagnostics based on the output. diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs index a744a6695..483f50ce6 100644 --- a/crates/rust-analyzer/src/bin/main.rs +++ b/crates/rust-analyzer/src/bin/main.rs @@ -5,7 +5,7 @@ mod args; use lsp_server::Connection; -use rust_analyzer::{cli, from_json, show_message, Result, ServerConfig}; +use rust_analyzer::{cli, from_json, Config, Result}; use crate::args::HelpPrinted; @@ -78,24 +78,18 @@ fn run_server() -> Result<()> { .filter(|workspaces| !workspaces.is_empty()) .unwrap_or_else(|| vec![root]); - let server_config = initialize_params - .initialization_options - .and_then(|v| { - from_json::("config", v) - .map_err(|e| { - log::error!("{}", e); - show_message(lsp_types::MessageType::Error, e.to_string(), &connection.sender); - }) - .ok() - }) - .unwrap_or_default(); - - rust_analyzer::main_loop( - workspace_roots, - initialize_params.capabilities, - server_config, - connection, - )?; + let config = { + let mut config = Config::default(); + if let Some(value) = &initialize_params.initialization_options { + config.update(value); + } + if let Some(caps) = &initialize_params.capabilities.text_document { + config.update_caps(caps); + } + config + }; + + rust_analyzer::main_loop(workspace_roots, config, connection)?; log::info!("shutting down IO..."); io_threads.join()?; diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 8a8e42ed8..c07626e5c 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -7,14 +7,11 @@ //! configure the server itself, feature flags are passed into analysis, and //! tweak things like automatic insertion of `()` in completions. -use rustc_hash::FxHashMap; - -use crate::feature_flags::FeatureFlags; use lsp_types::TextDocumentClientCapabilities; use ra_flycheck::FlycheckConfig; use ra_ide::{CompletionConfig, InlayHintsConfig}; use ra_project_model::CargoFeatures; -use serde::{Deserialize, Deserializer}; +use serde::Deserialize; #[derive(Debug, Clone)] pub struct Config { @@ -61,171 +58,109 @@ impl Default for RustfmtConfig { } } -pub(crate) fn get_config( - config: &ServerConfig, - text_document_caps: Option<&TextDocumentClientCapabilities>, -) -> Config { - let feature_flags = get_feature_flags(config); - Config { - publish_decorations: config.publish_decorations, - publish_diagnostics: feature_flags.get("lsp.diagnostics"), - notifications: NotificationsConfig { - workspace_loaded: feature_flags.get("notifications.workspace-loaded"), - cargo_toml_not_found: feature_flags.get("notifications.cargo-toml-not-found"), - }, - supports_location_link: text_document_caps - .and_then(|it| it.definition) - .and_then(|it| it.link_support) - .unwrap_or(false), - line_folding_only: text_document_caps - .and_then(|it| it.folding_range.as_ref()) - .and_then(|it| it.line_folding_only) - .unwrap_or(false), - inlay_hints: InlayHintsConfig { - type_hints: config.inlay_hints_type, - parameter_hints: config.inlay_hints_parameter, - chaining_hints: config.inlay_hints_chaining, - max_length: config.inlay_hints_max_length, - }, - completion: CompletionConfig { - enable_postfix_completions: feature_flags.get("completion.enable-postfix"), - add_call_parenthesis: feature_flags.get("completion.insertion.add-call-parenthesis"), - add_call_argument_snippets: feature_flags - .get("completion.insertion.add-argument-snippets"), - }, - call_info_full: feature_flags.get("call-info.full"), - check: if config.cargo_watch_enable { - Some(FlycheckConfig::CargoCommand { - command: config.cargo_watch_command.clone(), - all_targets: config.cargo_watch_all_targets, - extra_args: config.cargo_watch_args.clone(), - }) - } else { - None - }, - rustfmt: RustfmtConfig::Rustfmt { extra_args: config.rustfmt_args.clone() }, - vscode_lldb: config.vscode_lldb, - proc_macro_srv: None, // FIXME: get this from config - lru_capacity: config.lru_capacity, - use_client_watching: config.use_client_watching, - exclude_globs: config.exclude_globs.clone(), - cargo: config.cargo_features.clone(), - with_sysroot: config.with_sysroot, - } -} - -fn get_feature_flags(config: &ServerConfig) -> FeatureFlags { - let mut ff = FeatureFlags::default(); - for (flag, &value) in &config.feature_flags { - if ff.set(flag.as_str(), value).is_err() { - log::error!("unknown feature flag: {:?}", flag); +impl Default for Config { + fn default() -> Self { + Config { + publish_decorations: false, + publish_diagnostics: true, + notifications: NotificationsConfig { + workspace_loaded: true, + cargo_toml_not_found: true, + }, + supports_location_link: false, + line_folding_only: false, + inlay_hints: InlayHintsConfig { + type_hints: true, + parameter_hints: true, + chaining_hints: true, + max_length: None, + }, + completion: CompletionConfig { + enable_postfix_completions: true, + add_call_parenthesis: true, + add_call_argument_snippets: true, + }, + call_info_full: true, + rustfmt: RustfmtConfig::default(), + check: Some(FlycheckConfig::default()), + vscode_lldb: false, + proc_macro_srv: None, + lru_capacity: None, + use_client_watching: false, + exclude_globs: Vec::new(), + cargo: CargoFeatures::default(), + with_sysroot: true, } } - log::info!("feature_flags: {:#?}", ff); - ff } -/// Client provided initialization options -#[derive(Deserialize, Clone, Debug, PartialEq, Eq)] -#[serde(rename_all = "camelCase", default)] -pub struct ServerConfig { - /// Whether the client supports our custom highlighting publishing decorations. - /// This is different to the highlightingOn setting, which is whether the user - /// wants our custom highlighting to be used. - /// - /// Defaults to `false` - #[serde(deserialize_with = "nullable_bool_false")] - pub publish_decorations: bool, - - pub exclude_globs: Vec, - #[serde(deserialize_with = "nullable_bool_false")] - pub use_client_watching: bool, - - pub lru_capacity: Option, - - #[serde(deserialize_with = "nullable_bool_true")] - pub inlay_hints_type: bool, - #[serde(deserialize_with = "nullable_bool_true")] - pub inlay_hints_parameter: bool, - #[serde(deserialize_with = "nullable_bool_true")] - pub inlay_hints_chaining: bool, - pub inlay_hints_max_length: Option, - - pub cargo_watch_enable: bool, - pub cargo_watch_args: Vec, - pub cargo_watch_command: String, - pub cargo_watch_all_targets: bool, - - /// For internal usage to make integrated tests faster. - #[serde(deserialize_with = "nullable_bool_true")] - pub with_sysroot: bool, +impl Config { + #[rustfmt::skip] + pub fn update(&mut self, value: &serde_json::Value) { + let line_folding_only = self.line_folding_only; + let supports_location_link = self.supports_location_link; + *self = Default::default(); + self.line_folding_only = line_folding_only; + self.supports_location_link = supports_location_link; + + set(value, "publishDecorations", &mut self.publish_decorations); + set(value, "excludeGlobs", &mut self.exclude_globs); + set(value, "useClientWatching", &mut self.use_client_watching); + set(value, "lruCapacity", &mut self.lru_capacity); + + set(value, "inlayHintsType", &mut self.inlay_hints.type_hints); + set(value, "inlayHintsParameter", &mut self.inlay_hints.parameter_hints); + set(value, "inlayHintsChaining", &mut self.inlay_hints.chaining_hints); + set(value, "inlayHintsMaxLength", &mut self.inlay_hints.max_length); + + if let Some(false) = get(value, "cargo_watch_enable") { + self.check = None + } else { + if let Some(FlycheckConfig::CargoCommand { command, extra_args, all_targets }) = &mut self.check + { + set(value, "cargoWatchArgs", extra_args); + set(value, "cargoWatchCommand", command); + set(value, "cargoWatchAllTargets", all_targets); + } + }; + + set(value, "withSysroot", &mut self.with_sysroot); + if let RustfmtConfig::Rustfmt { extra_args } = &mut self.rustfmt { + set(value, "rustfmtArgs", extra_args); + } - /// Fine grained feature flags to disable specific features. - pub feature_flags: FxHashMap, + set(value, "cargoFeatures/noDefaultFeatures", &mut self.cargo.no_default_features); + set(value, "cargoFeatures/allFeatures", &mut self.cargo.all_features); + set(value, "cargoFeatures/features", &mut self.cargo.features); + set(value, "cargoFeatures/loadOutDirsFromCheck", &mut self.cargo.load_out_dirs_from_check); - pub rustfmt_args: Vec, + set(value, "vscodeLldb", &mut self.vscode_lldb); - /// Cargo feature configurations. - pub cargo_features: CargoFeatures, + set(value, "featureFlags/lsp.diagnostics", &mut self.publish_diagnostics); + set(value, "featureFlags/notifications.workspace-loaded", &mut self.notifications.workspace_loaded); + set(value, "featureFlags/notifications.cargo-toml-not-found", &mut self.notifications.cargo_toml_not_found); + set(value, "featureFlags/completion.enable-postfix", &mut self.completion.enable_postfix_completions); + set(value, "featureFlags/completion.insertion.add-call-parenthesis", &mut self.completion.add_call_parenthesis); + set(value, "featureFlags/completion.insertion.add-argument-snippets", &mut self.completion.add_call_argument_snippets); + set(value, "featureFlags/call-info.full", &mut self.call_info_full); - /// Enabled if the vscode_lldb extension is available. - pub vscode_lldb: bool, -} + fn get<'a, T: Deserialize<'a>>(value: &'a serde_json::Value, pointer: &str) -> Option { + value.pointer(pointer).and_then(|it| T::deserialize(it).ok()) + } -impl Default for ServerConfig { - fn default() -> ServerConfig { - ServerConfig { - publish_decorations: false, - exclude_globs: Vec::new(), - use_client_watching: false, - lru_capacity: None, - inlay_hints_type: true, - inlay_hints_parameter: true, - inlay_hints_chaining: true, - inlay_hints_max_length: None, - cargo_watch_enable: true, - cargo_watch_args: Vec::new(), - cargo_watch_command: "check".to_string(), - cargo_watch_all_targets: true, - with_sysroot: true, - feature_flags: FxHashMap::default(), - cargo_features: Default::default(), - rustfmt_args: Vec::new(), - vscode_lldb: false, + fn set<'a, T: Deserialize<'a>>(value: &'a serde_json::Value, pointer: &str, slot: &mut T) { + if let Some(new_value) = get(value, pointer) { + *slot = new_value + } } } -} - -/// Deserializes a null value to a bool false by default -fn nullable_bool_false<'de, D>(deserializer: D) -> Result -where - D: Deserializer<'de>, -{ - let opt = Option::deserialize(deserializer)?; - Ok(opt.unwrap_or(false)) -} -/// Deserializes a null value to a bool true by default -fn nullable_bool_true<'de, D>(deserializer: D) -> Result -where - D: Deserializer<'de>, -{ - let opt = Option::deserialize(deserializer)?; - Ok(opt.unwrap_or(true)) -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn deserialize_init_options_defaults() { - // check that null == default for both fields - let default = ServerConfig::default(); - assert_eq!(default, serde_json::from_str(r#"{}"#).unwrap()); - assert_eq!( - default, - serde_json::from_str(r#"{"publishDecorations":null, "lruCapacity":null}"#).unwrap() - ); + pub fn update_caps(&mut self, caps: &TextDocumentClientCapabilities) { + if let Some(value) = caps.definition.as_ref().and_then(|it| it.link_support) { + self.supports_location_link = value; + } + if let Some(value) = caps.folding_range.as_ref().and_then(|it| it.line_folding_only) { + self.line_folding_only = value + } } } diff --git a/crates/rust-analyzer/src/feature_flags.rs b/crates/rust-analyzer/src/feature_flags.rs deleted file mode 100644 index dbb3f50a0..000000000 --- a/crates/rust-analyzer/src/feature_flags.rs +++ /dev/null @@ -1,77 +0,0 @@ -//! See docs for `FeatureFlags`. - -use rustc_hash::FxHashMap; - -// FIXME: looks like a much better design is to pass options to each call, -// rather than to have a global ambient feature flags -- that way, the clients -// can issue two successive calls with different options. - -/// Feature flags hold fine-grained toggles for all *user-visible* features of -/// rust-analyzer. -/// -/// The exists such that users are able to disable any annoying feature (and, -/// with many users and many features, some features are bound to be annoying -/// for some users) -/// -/// Note that we purposefully use run-time checked strings, and not something -/// checked at compile time, to keep things simple and flexible. -/// -/// Also note that, at the moment, `FeatureFlags` also store features for -/// `rust-analyzer`. This should be benign layering violation. -#[derive(Debug)] -pub struct FeatureFlags { - flags: FxHashMap, -} - -impl FeatureFlags { - fn new(flags: &[(&str, bool)]) -> FeatureFlags { - let flags = flags - .iter() - .map(|&(name, value)| { - check_flag_name(name); - (name.to_string(), value) - }) - .collect(); - FeatureFlags { flags } - } - - pub fn set(&mut self, flag: &str, value: bool) -> Result<(), ()> { - match self.flags.get_mut(flag) { - None => Err(()), - Some(slot) => { - *slot = value; - Ok(()) - } - } - } - - pub fn get(&self, flag: &str) -> bool { - match self.flags.get(flag) { - None => panic!("unknown flag: {:?}", flag), - Some(value) => *value, - } - } -} - -impl Default for FeatureFlags { - fn default() -> FeatureFlags { - FeatureFlags::new(&[ - ("lsp.diagnostics", true), - ("completion.insertion.add-call-parenthesis", true), - ("completion.insertion.add-argument-snippets", true), - ("completion.enable-postfix", true), - ("call-info.full", true), - ("notifications.workspace-loaded", true), - ("notifications.cargo-toml-not-found", true), - ]) - } -} - -fn check_flag_name(flag: &str) { - for c in flag.bytes() { - match c { - b'a'..=b'z' | b'-' | b'.' => (), - _ => panic!("flag name does not match conventions: {:?}", flag), - } - } -} diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs index e50e47b19..6062d0984 100644 --- a/crates/rust-analyzer/src/lib.rs +++ b/crates/rust-analyzer/src/lib.rs @@ -37,14 +37,13 @@ mod config; mod world; mod diagnostics; mod semantic_tokens; -mod feature_flags; use serde::de::DeserializeOwned; pub type Result = std::result::Result>; pub use crate::{ + config::Config, caps::server_capabilities, - config::ServerConfig, main_loop::LspError, main_loop::{main_loop, show_message}, }; diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index c973d43fa..00f92dbd5 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -17,9 +17,8 @@ use std::{ use crossbeam_channel::{never, select, unbounded, RecvError, Sender}; use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response}; use lsp_types::{ - ClientCapabilities, NumberOrString, TextDocumentClientCapabilities, WorkDoneProgress, - WorkDoneProgressBegin, WorkDoneProgressCreateParams, WorkDoneProgressEnd, - WorkDoneProgressReport, + NumberOrString, WorkDoneProgress, WorkDoneProgressBegin, WorkDoneProgressCreateParams, + WorkDoneProgressEnd, WorkDoneProgressReport, }; use ra_flycheck::{url_from_path_with_drive_lowercasing, CheckTask}; use ra_ide::{Canceled, FileId, LibraryData, SourceRootId}; @@ -31,7 +30,7 @@ use serde::{de::DeserializeOwned, Serialize}; use threadpool::ThreadPool; use crate::{ - config::get_config, + config::Config, diagnostics::DiagnosticTask, main_loop::{ pending_requests::{PendingRequest, PendingRequests}, @@ -39,7 +38,7 @@ use crate::{ }, req, world::{WorldSnapshot, WorldState}, - Result, ServerConfig, + Result, }; use req::ConfigurationParams; @@ -65,14 +64,7 @@ impl fmt::Display for LspError { impl Error for LspError {} -pub fn main_loop( - ws_roots: Vec, - client_caps: ClientCapabilities, - config: ServerConfig, - connection: Connection, -) -> Result<()> { - let text_document_caps = client_caps.text_document.as_ref(); - let config = get_config(&config, text_document_caps); +pub fn main_loop(ws_roots: Vec, config: Config, connection: Connection) -> Result<()> { log::info!("initial config: {:#?}", config); // Windows scheduler implements priority boosts: if thread waits for an @@ -205,7 +197,6 @@ pub fn main_loop( &task_sender, &libdata_sender, &connection, - text_document_caps, &mut world_state, &mut loop_state, event, @@ -316,7 +307,6 @@ fn loop_turn( task_sender: &Sender, libdata_sender: &Sender, connection: &Connection, - text_document_caps: Option<&TextDocumentClientCapabilities>, world_state: &mut WorldState, loop_state: &mut LoopState, event: Event, @@ -370,27 +360,14 @@ fn loop_turn( log::debug!("config update response: '{:?}", resp); let Response { error, result, .. } = resp; - match ( - error, - result.map(|result| serde_json::from_value::>(result)), - ) { + match (error, result) { (Some(err), _) => { log::error!("failed to fetch the server settings: {:?}", err) } - (None, Some(Ok(new_config))) => { - let new_config = new_config - .first() - .expect( - "the client is expected to always send a non-empty config data", - ) - .to_owned(); - world_state.update_configuration( - new_config.lru_capacity, - get_config(&new_config, text_document_caps), - ); - } - (None, Some(Err(e))) => { - log::error!("failed to parse client config response: {}", e) + (None, Some(new_config)) => { + let mut config = world_state.config.clone(); + config.update(&new_config); + world_state.update_configuration(config); } (None, None) => { log::error!("received empty server settings response from the client") diff --git a/crates/rust-analyzer/src/world.rs b/crates/rust-analyzer/src/world.rs index df1b7ceeb..5674f42ef 100644 --- a/crates/rust-analyzer/src/world.rs +++ b/crates/rust-analyzer/src/world.rs @@ -11,7 +11,7 @@ use std::{ use crossbeam_channel::{unbounded, Receiver}; use lsp_types::Url; use parking_lot::RwLock; -use ra_flycheck::{url_from_path_with_drive_lowercasing, Flycheck}; +use ra_flycheck::{url_from_path_with_drive_lowercasing, Flycheck, FlycheckConfig}; use ra_ide::{ Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, LibraryData, SourceRootId, }; @@ -30,9 +30,7 @@ use crate::{ use ra_db::ExternSourceId; use rustc_hash::{FxHashMap, FxHashSet}; -fn create_flycheck(workspaces: &[ProjectWorkspace], config: &Config) -> Option { - let check_config = config.check.as_ref()?; - +fn create_flycheck(workspaces: &[ProjectWorkspace], config: &FlycheckConfig) -> Option { // FIXME: Figure out the multi-workspace situation workspaces .iter() @@ -42,7 +40,7 @@ fn create_flycheck(workspaces: &[ProjectWorkspace], config: &Config) -> Option, config: Config) { - self.analysis_host.update_lru_capacity(lru_capacity); - self.flycheck = create_flycheck(&self.workspaces, &config); + pub fn update_configuration(&mut self, config: Config) { + self.analysis_host.update_lru_capacity(config.lru_capacity); + if config.check != self.config.check { + self.flycheck = + config.check.as_ref().and_then(|it| create_flycheck(&self.workspaces, it)); + } + self.config = config; } diff --git a/crates/rust-analyzer/tests/heavy_tests/main.rs b/crates/rust-analyzer/tests/heavy_tests/main.rs index 5af5eaad2..638813311 100644 --- a/crates/rust-analyzer/tests/heavy_tests/main.rs +++ b/crates/rust-analyzer/tests/heavy_tests/main.rs @@ -615,7 +615,7 @@ fn main() { message(); } "###, ) .with_config(|config| { - config.cargo_features.load_out_dirs_from_check = true; + config.cargo.load_out_dirs_from_check = true; }) .server(); server.wait_until_workspace_is_loaded(); diff --git a/crates/rust-analyzer/tests/heavy_tests/support.rs b/crates/rust-analyzer/tests/heavy_tests/support.rs index d8bed6d7f..c83cb8adb 100644 --- a/crates/rust-analyzer/tests/heavy_tests/support.rs +++ b/crates/rust-analyzer/tests/heavy_tests/support.rs @@ -11,8 +11,7 @@ use lsp_server::{Connection, Message, Notification, Request}; use lsp_types::{ notification::{DidOpenTextDocument, Exit}, request::Shutdown, - ClientCapabilities, DidOpenTextDocumentParams, GotoCapability, TextDocumentClientCapabilities, - TextDocumentIdentifier, TextDocumentItem, Url, WorkDoneProgress, + DidOpenTextDocumentParams, TextDocumentIdentifier, TextDocumentItem, Url, WorkDoneProgress, }; use serde::Serialize; use serde_json::{to_string_pretty, Value}; @@ -20,14 +19,14 @@ use tempfile::TempDir; use test_utils::{find_mismatch, parse_fixture}; use req::{ProgressParams, ProgressParamsValue}; -use rust_analyzer::{main_loop, req, ServerConfig}; +use rust_analyzer::{main_loop, req, Config}; pub struct Project<'a> { fixture: &'a str, with_sysroot: bool, tmp_dir: Option, roots: Vec, - config: Option>, + config: Option>, } impl<'a> Project<'a> { @@ -50,7 +49,7 @@ impl<'a> Project<'a> { self } - pub fn with_config(mut self, config: impl Fn(&mut ServerConfig) + 'static) -> Project<'a> { + pub fn with_config(mut self, config: impl Fn(&mut Config) + 'static) -> Project<'a> { self.config = Some(Box::new(config)); self } @@ -78,8 +77,11 @@ impl<'a> Project<'a> { let roots = self.roots.into_iter().map(|root| tmp_dir.path().join(root)).collect(); - let mut config = - ServerConfig { with_sysroot: self.with_sysroot, ..ServerConfig::default() }; + let mut config = Config { + supports_location_link: true, + with_sysroot: self.with_sysroot, + ..Config::default() + }; if let Some(f) = &self.config { f(&mut config) @@ -105,7 +107,7 @@ pub struct Server { impl Server { fn new( dir: TempDir, - config: ServerConfig, + config: Config, roots: Vec, files: Vec<(PathBuf, String)>, ) -> Server { @@ -116,26 +118,7 @@ impl Server { let _thread = jod_thread::Builder::new() .name("test server".to_string()) - .spawn(move || { - main_loop( - roots, - ClientCapabilities { - workspace: None, - text_document: Some(TextDocumentClientCapabilities { - definition: Some(GotoCapability { - dynamic_registration: None, - link_support: Some(true), - }), - ..Default::default() - }), - window: None, - experimental: None, - }, - config, - connection, - ) - .unwrap() - }) + .spawn(move || main_loop(roots, config, connection).unwrap()) .expect("failed to spawn a thread"); let res = -- cgit v1.2.3 From e870cbc23d78f5bc424983b1d9ef945888f9dc49 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 1 Apr 2020 18:46:26 +0200 Subject: Centralize client capabilities --- crates/rust-analyzer/src/bin/main.rs | 2 +- crates/rust-analyzer/src/config.rs | 22 ++++++++++++---------- crates/rust-analyzer/src/conv.rs | 2 +- crates/rust-analyzer/src/lib.rs | 3 +-- crates/rust-analyzer/src/main_loop/handlers.rs | 2 +- crates/rust-analyzer/tests/heavy_tests/support.rs | 7 +++++-- 6 files changed, 21 insertions(+), 17 deletions(-) diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs index 483f50ce6..a3897b728 100644 --- a/crates/rust-analyzer/src/bin/main.rs +++ b/crates/rust-analyzer/src/bin/main.rs @@ -5,7 +5,7 @@ mod args; use lsp_server::Connection; -use rust_analyzer::{cli, from_json, Config, Result}; +use rust_analyzer::{cli, config::Config, from_json, Result}; use crate::args::HelpPrinted; diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index c07626e5c..e72017dcc 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -15,11 +15,10 @@ use serde::Deserialize; #[derive(Debug, Clone)] pub struct Config { + pub client_caps: ClientCapsConfig, pub publish_decorations: bool, pub publish_diagnostics: bool, pub notifications: NotificationsConfig, - pub supports_location_link: bool, - pub line_folding_only: bool, pub inlay_hints: InlayHintsConfig, pub completion: CompletionConfig, pub call_info_full: bool, @@ -58,6 +57,12 @@ impl Default for RustfmtConfig { } } +#[derive(Debug, Clone, Default)] +pub struct ClientCapsConfig { + pub location_link: bool, + pub line_folding_only: bool, +} + impl Default for Config { fn default() -> Self { Config { @@ -67,8 +72,7 @@ impl Default for Config { workspace_loaded: true, cargo_toml_not_found: true, }, - supports_location_link: false, - line_folding_only: false, + client_caps: ClientCapsConfig::default(), inlay_hints: InlayHintsConfig { type_hints: true, parameter_hints: true, @@ -97,11 +101,9 @@ impl Default for Config { impl Config { #[rustfmt::skip] pub fn update(&mut self, value: &serde_json::Value) { - let line_folding_only = self.line_folding_only; - let supports_location_link = self.supports_location_link; + let client_caps = self.client_caps.clone(); *self = Default::default(); - self.line_folding_only = line_folding_only; - self.supports_location_link = supports_location_link; + self.client_caps = client_caps; set(value, "publishDecorations", &mut self.publish_decorations); set(value, "excludeGlobs", &mut self.exclude_globs); @@ -157,10 +159,10 @@ impl Config { pub fn update_caps(&mut self, caps: &TextDocumentClientCapabilities) { if let Some(value) = caps.definition.as_ref().and_then(|it| it.link_support) { - self.supports_location_link = value; + self.client_caps.location_link = value; } if let Some(value) = caps.folding_range.as_ref().and_then(|it| it.line_folding_only) { - self.line_folding_only = value + self.client_caps.line_folding_only = value } } } diff --git a/crates/rust-analyzer/src/conv.rs b/crates/rust-analyzer/src/conv.rs index e8dc953c3..57c4c8ce5 100644 --- a/crates/rust-analyzer/src/conv.rs +++ b/crates/rust-analyzer/src/conv.rs @@ -579,7 +579,7 @@ impl TryConvWith<&WorldSnapshot> for (FileId, RangeInfo>) .into_iter() .map(|nav| (file_id, RangeInfo::new(range, nav))) .try_conv_with_to_vec(world)?; - if world.config.supports_location_link { + if world.config.client_caps.location_link { Ok(links.into()) } else { let locations: Vec = links diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs index 6062d0984..02953be30 100644 --- a/crates/rust-analyzer/src/lib.rs +++ b/crates/rust-analyzer/src/lib.rs @@ -33,7 +33,7 @@ mod conv; mod main_loop; mod markdown; pub mod req; -mod config; +pub mod config; mod world; mod diagnostics; mod semantic_tokens; @@ -42,7 +42,6 @@ use serde::de::DeserializeOwned; pub type Result = std::result::Result>; pub use crate::{ - config::Config, caps::server_capabilities, main_loop::LspError, main_loop::{main_loop, show_message}, diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index d0f64f007..23e48c089 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs @@ -450,7 +450,7 @@ pub fn handle_folding_range( let ctx = FoldConvCtx { text: &text, line_index: &line_index, - line_folding_only: world.config.line_folding_only, + line_folding_only: world.config.client_caps.line_folding_only, }; let res = Some(folds.into_iter().map_conv_with(&ctx).collect()); Ok(res) diff --git a/crates/rust-analyzer/tests/heavy_tests/support.rs b/crates/rust-analyzer/tests/heavy_tests/support.rs index c83cb8adb..7eebedff7 100644 --- a/crates/rust-analyzer/tests/heavy_tests/support.rs +++ b/crates/rust-analyzer/tests/heavy_tests/support.rs @@ -19,7 +19,10 @@ use tempfile::TempDir; use test_utils::{find_mismatch, parse_fixture}; use req::{ProgressParams, ProgressParamsValue}; -use rust_analyzer::{main_loop, req, Config}; +use rust_analyzer::{ + config::{ClientCapsConfig, Config}, + main_loop, req, +}; pub struct Project<'a> { fixture: &'a str, @@ -78,7 +81,7 @@ impl<'a> Project<'a> { let roots = self.roots.into_iter().map(|root| tmp_dir.path().join(root)).collect(); let mut config = Config { - supports_location_link: true, + client_caps: ClientCapsConfig { location_link: true, ..Default::default() }, with_sysroot: self.with_sysroot, ..Config::default() }; -- cgit v1.2.3 From 4936abdd49b1d0ba6b2a858bee3a5a665de9d6f3 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 1 Apr 2020 18:51:16 +0200 Subject: Reduce scope of deserialization --- crates/ra_project_model/src/cargo_workspace.rs | 20 ++++++++------------ crates/ra_project_model/src/lib.rs | 6 +++--- crates/rust-analyzer/src/bin/main.rs | 1 - crates/rust-analyzer/src/cli/load_cargo.rs | 4 ++-- crates/rust-analyzer/src/config.rs | 6 +++--- 5 files changed, 16 insertions(+), 21 deletions(-) diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs index 91735a726..c1b6e1ddc 100644 --- a/crates/ra_project_model/src/cargo_workspace.rs +++ b/crates/ra_project_model/src/cargo_workspace.rs @@ -13,7 +13,6 @@ use cargo_metadata::{BuildScript, CargoOpt, Message, MetadataCommand, PackageId} use ra_arena::{Arena, Idx}; use ra_db::Edition; use rustc_hash::FxHashMap; -use serde::Deserialize; /// `CargoWorkspace` represents the logical structure of, well, a Cargo /// workspace. It pretty closely mirrors `cargo metadata` output. @@ -43,10 +42,8 @@ impl ops::Index for CargoWorkspace { } } -// TODO: rename to CargoConfig, kill `rename_all`, kill serde dep? -#[derive(Deserialize, Clone, Debug, PartialEq, Eq)] -#[serde(rename_all = "camelCase", default)] -pub struct CargoFeatures { +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct CargoConfig { /// Do not activate the `default` feature. pub no_default_features: bool, @@ -61,9 +58,9 @@ pub struct CargoFeatures { pub load_out_dirs_from_check: bool, } -impl Default for CargoFeatures { +impl Default for CargoConfig { fn default() -> Self { - CargoFeatures { + CargoConfig { no_default_features: false, all_features: true, features: Vec::new(), @@ -142,7 +139,7 @@ impl PackageData { impl CargoWorkspace { pub fn from_cargo_metadata( cargo_toml: &Path, - cargo_features: &CargoFeatures, + cargo_features: &CargoConfig, ) -> Result { let mut meta = MetadataCommand::new(); meta.manifest_path(cargo_toml); @@ -276,7 +273,7 @@ pub struct ExternResources { pub fn load_extern_resources( cargo_toml: &Path, - cargo_features: &CargoFeatures, + cargo_features: &CargoConfig, ) -> Result { let mut cmd = Command::new(cargo_binary()); cmd.args(&["check", "--message-format=json", "--manifest-path"]).arg(cargo_toml); @@ -294,9 +291,8 @@ pub fn load_extern_resources( let mut res = ExternResources::default(); - let stdout = String::from_utf8(output.stdout)?; - for line in stdout.lines() { - if let Ok(message) = serde_json::from_str::(&line) { + for message in cargo_metadata::parse_messages(output.stdout.as_slice()) { + if let Ok(message) = message { match message { Message::BuildScriptExecuted(BuildScript { package_id, out_dir, .. }) => { res.out_dirs.insert(package_id, out_dir); diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index 444d3bb3f..dd9c80691 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs @@ -19,7 +19,7 @@ use rustc_hash::FxHashMap; use serde_json::from_reader; pub use crate::{ - cargo_workspace::{CargoFeatures, CargoWorkspace, Package, Target, TargetKind}, + cargo_workspace::{CargoConfig, CargoWorkspace, Package, Target, TargetKind}, json_project::JsonProject, sysroot::Sysroot, }; @@ -78,14 +78,14 @@ impl PackageRoot { } impl ProjectWorkspace { - pub fn discover(path: &Path, cargo_features: &CargoFeatures) -> Result { + pub fn discover(path: &Path, cargo_features: &CargoConfig) -> Result { ProjectWorkspace::discover_with_sysroot(path, true, cargo_features) } pub fn discover_with_sysroot( path: &Path, with_sysroot: bool, - cargo_features: &CargoFeatures, + cargo_features: &CargoConfig, ) -> Result { match find_rust_project_json(path) { Some(json_path) => { diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs index a3897b728..608f4f67b 100644 --- a/crates/rust-analyzer/src/bin/main.rs +++ b/crates/rust-analyzer/src/bin/main.rs @@ -4,7 +4,6 @@ mod args; use lsp_server::Connection; - use rust_analyzer::{cli, config::Config, from_json, Result}; use crate::args::HelpPrinted; diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs index 832f04226..2c0bde920 100644 --- a/crates/rust-analyzer/src/cli/load_cargo.rs +++ b/crates/rust-analyzer/src/cli/load_cargo.rs @@ -8,7 +8,7 @@ use crossbeam_channel::{unbounded, Receiver}; use ra_db::{ExternSourceId, FileId, SourceRootId}; use ra_ide::{AnalysisChange, AnalysisHost}; use ra_project_model::{ - get_rustc_cfg_options, CargoFeatures, PackageRoot, ProcMacroClient, ProjectWorkspace, + get_rustc_cfg_options, CargoConfig, PackageRoot, ProcMacroClient, ProjectWorkspace, }; use ra_vfs::{RootEntry, Vfs, VfsChange, VfsTask, Watch}; use rustc_hash::{FxHashMap, FxHashSet}; @@ -29,7 +29,7 @@ pub(crate) fn load_cargo( let root = std::env::current_dir()?.join(root); let ws = ProjectWorkspace::discover( root.as_ref(), - &CargoFeatures { load_out_dirs_from_check, ..Default::default() }, + &CargoConfig { load_out_dirs_from_check, ..Default::default() }, )?; let mut extern_dirs = FxHashSet::default(); diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index e72017dcc..57372768c 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -10,7 +10,7 @@ use lsp_types::TextDocumentClientCapabilities; use ra_flycheck::FlycheckConfig; use ra_ide::{CompletionConfig, InlayHintsConfig}; -use ra_project_model::CargoFeatures; +use ra_project_model::CargoConfig; use serde::Deserialize; #[derive(Debug, Clone)] @@ -29,7 +29,7 @@ pub struct Config { pub lru_capacity: Option, pub use_client_watching: bool, pub exclude_globs: Vec, - pub cargo: CargoFeatures, + pub cargo: CargoConfig, pub with_sysroot: bool, } @@ -92,7 +92,7 @@ impl Default for Config { lru_capacity: None, use_client_watching: false, exclude_globs: Vec::new(), - cargo: CargoFeatures::default(), + cargo: CargoConfig::default(), with_sysroot: true, } } -- cgit v1.2.3 From 1ac345a9f693e54aecd2ad70731acc75f982d2ae Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 1 Apr 2020 18:56:47 +0200 Subject: Centralize defaults --- crates/ra_flycheck/src/lib.rs | 10 ---------- crates/rust-analyzer/src/config.rs | 14 ++++++-------- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/crates/ra_flycheck/src/lib.rs b/crates/ra_flycheck/src/lib.rs index f3d6f8f5f..b54a30ab8 100644 --- a/crates/ra_flycheck/src/lib.rs +++ b/crates/ra_flycheck/src/lib.rs @@ -28,16 +28,6 @@ pub enum FlycheckConfig { CustomCommand { command: String, args: Vec }, } -impl Default for FlycheckConfig { - fn default() -> Self { - FlycheckConfig::CargoCommand { - command: "check".to_string(), - all_targets: true, - extra_args: Vec::new(), - } - } -} - /// Flycheck wraps the shared state and communication machinery used for /// running `cargo check` (or other compatible command) and providing /// diagnostics based on the output. diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 57372768c..d95ed9ec7 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -51,12 +51,6 @@ pub enum RustfmtConfig { }, } -impl Default for RustfmtConfig { - fn default() -> Self { - RustfmtConfig::Rustfmt { extra_args: Vec::new() } - } -} - #[derive(Debug, Clone, Default)] pub struct ClientCapsConfig { pub location_link: bool, @@ -85,8 +79,12 @@ impl Default for Config { add_call_argument_snippets: true, }, call_info_full: true, - rustfmt: RustfmtConfig::default(), - check: Some(FlycheckConfig::default()), + rustfmt: RustfmtConfig::Rustfmt { extra_args: Vec::new() }, + check: Some(FlycheckConfig::CargoCommand { + command: "check".to_string(), + all_targets: true, + extra_args: Vec::new(), + }), vscode_lldb: false, proc_macro_srv: None, lru_capacity: None, -- cgit v1.2.3 From 1225f719fe920587ebbe4170fc5aee1d87eadc22 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 1 Apr 2020 19:27:45 +0200 Subject: Fix pointer syntax --- crates/rust-analyzer/src/config.rs | 56 +++++++++++++++++++---------------- crates/rust-analyzer/src/main_loop.rs | 10 ++++--- 2 files changed, 36 insertions(+), 30 deletions(-) diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index d95ed9ec7..3c8f55f1e 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -99,56 +99,60 @@ impl Default for Config { impl Config { #[rustfmt::skip] pub fn update(&mut self, value: &serde_json::Value) { + log::info!("Config::update({:#})", value); + let client_caps = self.client_caps.clone(); *self = Default::default(); self.client_caps = client_caps; - set(value, "publishDecorations", &mut self.publish_decorations); - set(value, "excludeGlobs", &mut self.exclude_globs); - set(value, "useClientWatching", &mut self.use_client_watching); - set(value, "lruCapacity", &mut self.lru_capacity); + set(value, "/publishDecorations", &mut self.publish_decorations); + set(value, "/excludeGlobs", &mut self.exclude_globs); + set(value, "/useClientWatching", &mut self.use_client_watching); + set(value, "/lruCapacity", &mut self.lru_capacity); - set(value, "inlayHintsType", &mut self.inlay_hints.type_hints); - set(value, "inlayHintsParameter", &mut self.inlay_hints.parameter_hints); - set(value, "inlayHintsChaining", &mut self.inlay_hints.chaining_hints); - set(value, "inlayHintsMaxLength", &mut self.inlay_hints.max_length); + set(value, "/inlayHintsType", &mut self.inlay_hints.type_hints); + set(value, "/inlayHintsParameter", &mut self.inlay_hints.parameter_hints); + set(value, "/inlayHintsChaining", &mut self.inlay_hints.chaining_hints); + set(value, "/inlayHintsMaxLength", &mut self.inlay_hints.max_length); if let Some(false) = get(value, "cargo_watch_enable") { self.check = None } else { if let Some(FlycheckConfig::CargoCommand { command, extra_args, all_targets }) = &mut self.check { - set(value, "cargoWatchArgs", extra_args); - set(value, "cargoWatchCommand", command); - set(value, "cargoWatchAllTargets", all_targets); + set(value, "/cargoWatchArgs", extra_args); + set(value, "/cargoWatchCommand", command); + set(value, "/cargoWatchAllTargets", all_targets); } }; - set(value, "withSysroot", &mut self.with_sysroot); + set(value, "/withSysroot", &mut self.with_sysroot); if let RustfmtConfig::Rustfmt { extra_args } = &mut self.rustfmt { - set(value, "rustfmtArgs", extra_args); + set(value, "/rustfmtArgs", extra_args); } - set(value, "cargoFeatures/noDefaultFeatures", &mut self.cargo.no_default_features); - set(value, "cargoFeatures/allFeatures", &mut self.cargo.all_features); - set(value, "cargoFeatures/features", &mut self.cargo.features); - set(value, "cargoFeatures/loadOutDirsFromCheck", &mut self.cargo.load_out_dirs_from_check); + set(value, "/cargoFeatures/noDefaultFeatures", &mut self.cargo.no_default_features); + set(value, "/cargoFeatures/allFeatures", &mut self.cargo.all_features); + set(value, "/cargoFeatures/features", &mut self.cargo.features); + set(value, "/cargoFeatures/loadOutDirsFromCheck", &mut self.cargo.load_out_dirs_from_check); + + set(value, "/vscodeLldb", &mut self.vscode_lldb); - set(value, "vscodeLldb", &mut self.vscode_lldb); + set(value, "/featureFlags/lsp.diagnostics", &mut self.publish_diagnostics); + set(value, "/featureFlags/notifications.workspace-loaded", &mut self.notifications.workspace_loaded); + set(value, "/featureFlags/notifications.cargo-toml-not-found", &mut self.notifications.cargo_toml_not_found); + set(value, "/featureFlags/completion.enable-postfix", &mut self.completion.enable_postfix_completions); + set(value, "/featureFlags/completion.insertion.add-call-parenthesis", &mut self.completion.add_call_parenthesis); + set(value, "/featureFlags/completion.insertion.add-argument-snippets", &mut self.completion.add_call_argument_snippets); + set(value, "/featureFlags/call-info.full", &mut self.call_info_full); - set(value, "featureFlags/lsp.diagnostics", &mut self.publish_diagnostics); - set(value, "featureFlags/notifications.workspace-loaded", &mut self.notifications.workspace_loaded); - set(value, "featureFlags/notifications.cargo-toml-not-found", &mut self.notifications.cargo_toml_not_found); - set(value, "featureFlags/completion.enable-postfix", &mut self.completion.enable_postfix_completions); - set(value, "featureFlags/completion.insertion.add-call-parenthesis", &mut self.completion.add_call_parenthesis); - set(value, "featureFlags/completion.insertion.add-argument-snippets", &mut self.completion.add_call_argument_snippets); - set(value, "featureFlags/call-info.full", &mut self.call_info_full); + log::info!("Config::update() = {:#?}", self); fn get<'a, T: Deserialize<'a>>(value: &'a serde_json::Value, pointer: &str) -> Option { value.pointer(pointer).and_then(|it| T::deserialize(it).ok()) } - fn set<'a, T: Deserialize<'a>>(value: &'a serde_json::Value, pointer: &str, slot: &mut T) { + fn set<'a, T: Deserialize<'a> + std::fmt::Debug>(value: &'a serde_json::Value, pointer: &str, slot: &mut T) { if let Some(new_value) = get(value, pointer) { *slot = new_value } diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 00f92dbd5..45ae0ad9d 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -364,10 +364,12 @@ fn loop_turn( (Some(err), _) => { log::error!("failed to fetch the server settings: {:?}", err) } - (None, Some(new_config)) => { - let mut config = world_state.config.clone(); - config.update(&new_config); - world_state.update_configuration(config); + (None, Some(configs)) => { + if let Some(new_config) = configs.get(0) { + let mut config = world_state.config.clone(); + config.update(&new_config); + world_state.update_configuration(config); + } } (None, None) => { log::error!("received empty server settings response from the client") -- cgit v1.2.3