Skip to content

Commit a97e5eb

Browse files
committed
Centralize all config
1 parent 1e012eb commit a97e5eb

File tree

9 files changed

+151
-328
lines changed

9 files changed

+151
-328
lines changed

crates/ra_flycheck/src/lib.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,22 @@ use crate::conv::{map_rust_diagnostic_to_lsp, MappedRustDiagnostic};
2222

2323
pub use crate::conv::url_from_path_with_drive_lowercasing;
2424

25-
#[derive(Clone, Debug)]
25+
#[derive(Clone, Debug, PartialEq, Eq)]
2626
pub enum FlycheckConfig {
2727
CargoCommand { command: String, all_targets: bool, extra_args: Vec<String> },
2828
CustomCommand { command: String, args: Vec<String> },
2929
}
3030

31+
impl Default for FlycheckConfig {
32+
fn default() -> Self {
33+
FlycheckConfig::CargoCommand {
34+
command: "check".to_string(),
35+
all_targets: true,
36+
extra_args: Vec::new(),
37+
}
38+
}
39+
}
40+
3141
/// Flycheck wraps the shared state and communication machinery used for
3242
/// running `cargo check` (or other compatible command) and providing
3343
/// diagnostics based on the output.

crates/rust-analyzer/src/bin/main.rs

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ mod args;
55

66
use lsp_server::Connection;
77

8-
use rust_analyzer::{cli, from_json, show_message, Result, ServerConfig};
8+
use rust_analyzer::{cli, from_json, Config, Result};
99

1010
use crate::args::HelpPrinted;
1111

@@ -78,24 +78,18 @@ fn run_server() -> Result<()> {
7878
.filter(|workspaces| !workspaces.is_empty())
7979
.unwrap_or_else(|| vec![root]);
8080

81-
let server_config = initialize_params
82-
.initialization_options
83-
.and_then(|v| {
84-
from_json::<ServerConfig>("config", v)
85-
.map_err(|e| {
86-
log::error!("{}", e);
87-
show_message(lsp_types::MessageType::Error, e.to_string(), &connection.sender);
88-
})
89-
.ok()
90-
})
91-
.unwrap_or_default();
92-
93-
rust_analyzer::main_loop(
94-
workspace_roots,
95-
initialize_params.capabilities,
96-
server_config,
97-
connection,
98-
)?;
81+
let config = {
82+
let mut config = Config::default();
83+
if let Some(value) = &initialize_params.initialization_options {
84+
config.update(value);
85+
}
86+
if let Some(caps) = &initialize_params.capabilities.text_document {
87+
config.update_caps(caps);
88+
}
89+
config
90+
};
91+
92+
rust_analyzer::main_loop(workspace_roots, config, connection)?;
9993

10094
log::info!("shutting down IO...");
10195
io_threads.join()?;

crates/rust-analyzer/src/config.rs

Lines changed: 93 additions & 158 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,11 @@
77
//! configure the server itself, feature flags are passed into analysis, and
88
//! tweak things like automatic insertion of `()` in completions.
99
10-
use rustc_hash::FxHashMap;
11-
12-
use crate::feature_flags::FeatureFlags;
1310
use lsp_types::TextDocumentClientCapabilities;
1411
use ra_flycheck::FlycheckConfig;
1512
use ra_ide::{CompletionConfig, InlayHintsConfig};
1613
use ra_project_model::CargoFeatures;
17-
use serde::{Deserialize, Deserializer};
14+
use serde::Deserialize;
1815

1916
#[derive(Debug, Clone)]
2017
pub struct Config {
@@ -61,171 +58,109 @@ impl Default for RustfmtConfig {
6158
}
6259
}
6360

64-
pub(crate) fn get_config(
65-
config: &ServerConfig,
66-
text_document_caps: Option<&TextDocumentClientCapabilities>,
67-
) -> Config {
68-
let feature_flags = get_feature_flags(config);
69-
Config {
70-
publish_decorations: config.publish_decorations,
71-
publish_diagnostics: feature_flags.get("lsp.diagnostics"),
72-
notifications: NotificationsConfig {
73-
workspace_loaded: feature_flags.get("notifications.workspace-loaded"),
74-
cargo_toml_not_found: feature_flags.get("notifications.cargo-toml-not-found"),
75-
},
76-
supports_location_link: text_document_caps
77-
.and_then(|it| it.definition)
78-
.and_then(|it| it.link_support)
79-
.unwrap_or(false),
80-
line_folding_only: text_document_caps
81-
.and_then(|it| it.folding_range.as_ref())
82-
.and_then(|it| it.line_folding_only)
83-
.unwrap_or(false),
84-
inlay_hints: InlayHintsConfig {
85-
type_hints: config.inlay_hints_type,
86-
parameter_hints: config.inlay_hints_parameter,
87-
chaining_hints: config.inlay_hints_chaining,
88-
max_length: config.inlay_hints_max_length,
89-
},
90-
completion: CompletionConfig {
91-
enable_postfix_completions: feature_flags.get("completion.enable-postfix"),
92-
add_call_parenthesis: feature_flags.get("completion.insertion.add-call-parenthesis"),
93-
add_call_argument_snippets: feature_flags
94-
.get("completion.insertion.add-argument-snippets"),
95-
},
96-
call_info_full: feature_flags.get("call-info.full"),
97-
check: if config.cargo_watch_enable {
98-
Some(FlycheckConfig::CargoCommand {
99-
command: config.cargo_watch_command.clone(),
100-
all_targets: config.cargo_watch_all_targets,
101-
extra_args: config.cargo_watch_args.clone(),
102-
})
103-
} else {
104-
None
105-
},
106-
rustfmt: RustfmtConfig::Rustfmt { extra_args: config.rustfmt_args.clone() },
107-
vscode_lldb: config.vscode_lldb,
108-
proc_macro_srv: None, // FIXME: get this from config
109-
lru_capacity: config.lru_capacity,
110-
use_client_watching: config.use_client_watching,
111-
exclude_globs: config.exclude_globs.clone(),
112-
cargo: config.cargo_features.clone(),
113-
with_sysroot: config.with_sysroot,
114-
}
115-
}
116-
117-
fn get_feature_flags(config: &ServerConfig) -> FeatureFlags {
118-
let mut ff = FeatureFlags::default();
119-
for (flag, &value) in &config.feature_flags {
120-
if ff.set(flag.as_str(), value).is_err() {
121-
log::error!("unknown feature flag: {:?}", flag);
61+
impl Default for Config {
62+
fn default() -> Self {
63+
Config {
64+
publish_decorations: false,
65+
publish_diagnostics: true,
66+
notifications: NotificationsConfig {
67+
workspace_loaded: true,
68+
cargo_toml_not_found: true,
69+
},
70+
supports_location_link: false,
71+
line_folding_only: false,
72+
inlay_hints: InlayHintsConfig {
73+
type_hints: true,
74+
parameter_hints: true,
75+
chaining_hints: true,
76+
max_length: None,
77+
},
78+
completion: CompletionConfig {
79+
enable_postfix_completions: true,
80+
add_call_parenthesis: true,
81+
add_call_argument_snippets: true,
82+
},
83+
call_info_full: true,
84+
rustfmt: RustfmtConfig::default(),
85+
check: Some(FlycheckConfig::default()),
86+
vscode_lldb: false,
87+
proc_macro_srv: None,
88+
lru_capacity: None,
89+
use_client_watching: false,
90+
exclude_globs: Vec::new(),
91+
cargo: CargoFeatures::default(),
92+
with_sysroot: true,
12293
}
12394
}
124-
log::info!("feature_flags: {:#?}", ff);
125-
ff
12695
}
12796

128-
/// Client provided initialization options
129-
#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
130-
#[serde(rename_all = "camelCase", default)]
131-
pub struct ServerConfig {
132-
/// Whether the client supports our custom highlighting publishing decorations.
133-
/// This is different to the highlightingOn setting, which is whether the user
134-
/// wants our custom highlighting to be used.
135-
///
136-
/// Defaults to `false`
137-
#[serde(deserialize_with = "nullable_bool_false")]
138-
pub publish_decorations: bool,
139-
140-
pub exclude_globs: Vec<String>,
141-
#[serde(deserialize_with = "nullable_bool_false")]
142-
pub use_client_watching: bool,
143-
144-
pub lru_capacity: Option<usize>,
145-
146-
#[serde(deserialize_with = "nullable_bool_true")]
147-
pub inlay_hints_type: bool,
148-
#[serde(deserialize_with = "nullable_bool_true")]
149-
pub inlay_hints_parameter: bool,
150-
#[serde(deserialize_with = "nullable_bool_true")]
151-
pub inlay_hints_chaining: bool,
152-
pub inlay_hints_max_length: Option<usize>,
153-
154-
pub cargo_watch_enable: bool,
155-
pub cargo_watch_args: Vec<String>,
156-
pub cargo_watch_command: String,
157-
pub cargo_watch_all_targets: bool,
158-
159-
/// For internal usage to make integrated tests faster.
160-
#[serde(deserialize_with = "nullable_bool_true")]
161-
pub with_sysroot: bool,
97+
impl Config {
98+
#[rustfmt::skip]
99+
pub fn update(&mut self, value: &serde_json::Value) {
100+
let line_folding_only = self.line_folding_only;
101+
let supports_location_link = self.supports_location_link;
102+
*self = Default::default();
103+
self.line_folding_only = line_folding_only;
104+
self.supports_location_link = supports_location_link;
105+
106+
set(value, "publishDecorations", &mut self.publish_decorations);
107+
set(value, "excludeGlobs", &mut self.exclude_globs);
108+
set(value, "useClientWatching", &mut self.use_client_watching);
109+
set(value, "lruCapacity", &mut self.lru_capacity);
110+
111+
set(value, "inlayHintsType", &mut self.inlay_hints.type_hints);
112+
set(value, "inlayHintsParameter", &mut self.inlay_hints.parameter_hints);
113+
set(value, "inlayHintsChaining", &mut self.inlay_hints.chaining_hints);
114+
set(value, "inlayHintsMaxLength", &mut self.inlay_hints.max_length);
115+
116+
if let Some(false) = get(value, "cargo_watch_enable") {
117+
self.check = None
118+
} else {
119+
if let Some(FlycheckConfig::CargoCommand { command, extra_args, all_targets }) = &mut self.check
120+
{
121+
set(value, "cargoWatchArgs", extra_args);
122+
set(value, "cargoWatchCommand", command);
123+
set(value, "cargoWatchAllTargets", all_targets);
124+
}
125+
};
126+
127+
set(value, "withSysroot", &mut self.with_sysroot);
128+
if let RustfmtConfig::Rustfmt { extra_args } = &mut self.rustfmt {
129+
set(value, "rustfmtArgs", extra_args);
130+
}
162131

163-
/// Fine grained feature flags to disable specific features.
164-
pub feature_flags: FxHashMap<String, bool>,
132+
set(value, "cargoFeatures/noDefaultFeatures", &mut self.cargo.no_default_features);
133+
set(value, "cargoFeatures/allFeatures", &mut self.cargo.all_features);
134+
set(value, "cargoFeatures/features", &mut self.cargo.features);
135+
set(value, "cargoFeatures/loadOutDirsFromCheck", &mut self.cargo.load_out_dirs_from_check);
165136

166-
pub rustfmt_args: Vec<String>,
137+
set(value, "vscodeLldb", &mut self.vscode_lldb);
167138

168-
/// Cargo feature configurations.
169-
pub cargo_features: CargoFeatures,
139+
set(value, "featureFlags/lsp.diagnostics", &mut self.publish_diagnostics);
140+
set(value, "featureFlags/notifications.workspace-loaded", &mut self.notifications.workspace_loaded);
141+
set(value, "featureFlags/notifications.cargo-toml-not-found", &mut self.notifications.cargo_toml_not_found);
142+
set(value, "featureFlags/completion.enable-postfix", &mut self.completion.enable_postfix_completions);
143+
set(value, "featureFlags/completion.insertion.add-call-parenthesis", &mut self.completion.add_call_parenthesis);
144+
set(value, "featureFlags/completion.insertion.add-argument-snippets", &mut self.completion.add_call_argument_snippets);
145+
set(value, "featureFlags/call-info.full", &mut self.call_info_full);
170146

171-
/// Enabled if the vscode_lldb extension is available.
172-
pub vscode_lldb: bool,
173-
}
147+
fn get<'a, T: Deserialize<'a>>(value: &'a serde_json::Value, pointer: &str) -> Option<T> {
148+
value.pointer(pointer).and_then(|it| T::deserialize(it).ok())
149+
}
174150

175-
impl Default for ServerConfig {
176-
fn default() -> ServerConfig {
177-
ServerConfig {
178-
publish_decorations: false,
179-
exclude_globs: Vec::new(),
180-
use_client_watching: false,
181-
lru_capacity: None,
182-
inlay_hints_type: true,
183-
inlay_hints_parameter: true,
184-
inlay_hints_chaining: true,
185-
inlay_hints_max_length: None,
186-
cargo_watch_enable: true,
187-
cargo_watch_args: Vec::new(),
188-
cargo_watch_command: "check".to_string(),
189-
cargo_watch_all_targets: true,
190-
with_sysroot: true,
191-
feature_flags: FxHashMap::default(),
192-
cargo_features: Default::default(),
193-
rustfmt_args: Vec::new(),
194-
vscode_lldb: false,
151+
fn set<'a, T: Deserialize<'a>>(value: &'a serde_json::Value, pointer: &str, slot: &mut T) {
152+
if let Some(new_value) = get(value, pointer) {
153+
*slot = new_value
154+
}
195155
}
196156
}
197-
}
198-
199-
/// Deserializes a null value to a bool false by default
200-
fn nullable_bool_false<'de, D>(deserializer: D) -> Result<bool, D::Error>
201-
where
202-
D: Deserializer<'de>,
203-
{
204-
let opt = Option::deserialize(deserializer)?;
205-
Ok(opt.unwrap_or(false))
206-
}
207157

208-
/// Deserializes a null value to a bool true by default
209-
fn nullable_bool_true<'de, D>(deserializer: D) -> Result<bool, D::Error>
210-
where
211-
D: Deserializer<'de>,
212-
{
213-
let opt = Option::deserialize(deserializer)?;
214-
Ok(opt.unwrap_or(true))
215-
}
216-
217-
#[cfg(test)]
218-
mod test {
219-
use super::*;
220-
221-
#[test]
222-
fn deserialize_init_options_defaults() {
223-
// check that null == default for both fields
224-
let default = ServerConfig::default();
225-
assert_eq!(default, serde_json::from_str(r#"{}"#).unwrap());
226-
assert_eq!(
227-
default,
228-
serde_json::from_str(r#"{"publishDecorations":null, "lruCapacity":null}"#).unwrap()
229-
);
158+
pub fn update_caps(&mut self, caps: &TextDocumentClientCapabilities) {
159+
if let Some(value) = caps.definition.as_ref().and_then(|it| it.link_support) {
160+
self.supports_location_link = value;
161+
}
162+
if let Some(value) = caps.folding_range.as_ref().and_then(|it| it.line_folding_only) {
163+
self.line_folding_only = value
164+
}
230165
}
231166
}

0 commit comments

Comments
 (0)