diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ide/src/hover.rs | 29 | ||||
-rw-r--r-- | crates/ide/src/inlay_hints.rs | 21 | ||||
-rw-r--r-- | crates/ide/src/runnables.rs | 35 | ||||
-rw-r--r-- | crates/project_model/src/project_json.rs | 10 | ||||
-rw-r--r-- | crates/rust-analyzer/src/bin/main.rs | 13 | ||||
-rw-r--r-- | crates/rust-analyzer/src/cargo_target_spec.rs | 5 | ||||
-rw-r--r-- | crates/rust-analyzer/src/config.rs | 535 | ||||
-rw-r--r-- | crates/rust-analyzer/src/global_state.rs | 2 | ||||
-rw-r--r-- | crates/rust-analyzer/src/handlers.rs | 95 | ||||
-rw-r--r-- | crates/rust-analyzer/src/main_loop.rs | 11 | ||||
-rw-r--r-- | crates/rust-analyzer/src/reload.rs | 26 | ||||
-rw-r--r-- | crates/rust-analyzer/src/to_proto.rs | 6 | ||||
-rw-r--r-- | crates/rust-analyzer/tests/rust-analyzer/main.rs | 22 | ||||
-rw-r--r-- | crates/rust-analyzer/tests/rust-analyzer/support.rs | 44 |
14 files changed, 412 insertions, 442 deletions
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index f2ad95cb6..72c9c66fe 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs | |||
@@ -17,7 +17,7 @@ use crate::{ | |||
17 | doc_links::{remove_links, rewrite_links}, | 17 | doc_links::{remove_links, rewrite_links}, |
18 | markdown_remove::remove_markdown, | 18 | markdown_remove::remove_markdown, |
19 | markup::Markup, | 19 | markup::Markup, |
20 | runnables::runnable, | 20 | runnables::{runnable, runnable_fn}, |
21 | FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, | 21 | FileId, FilePosition, NavigationTarget, RangeInfo, Runnable, |
22 | }; | 22 | }; |
23 | 23 | ||
@@ -31,19 +31,6 @@ pub struct HoverConfig { | |||
31 | pub markdown: bool, | 31 | pub markdown: bool, |
32 | } | 32 | } |
33 | 33 | ||
34 | impl Default for HoverConfig { | ||
35 | fn default() -> Self { | ||
36 | Self { | ||
37 | implementations: true, | ||
38 | run: true, | ||
39 | debug: true, | ||
40 | goto_type_def: true, | ||
41 | links_in_hover: true, | ||
42 | markdown: true, | ||
43 | } | ||
44 | } | ||
45 | } | ||
46 | |||
47 | impl HoverConfig { | 34 | impl HoverConfig { |
48 | pub const NO_ACTIONS: Self = Self { | 35 | pub const NO_ACTIONS: Self = Self { |
49 | implementations: false, | 36 | implementations: false, |
@@ -204,22 +191,20 @@ fn runnable_action( | |||
204 | match def { | 191 | match def { |
205 | Definition::ModuleDef(it) => match it { | 192 | Definition::ModuleDef(it) => match it { |
206 | ModuleDef::Module(it) => match it.definition_source(sema.db).value { | 193 | ModuleDef::Module(it) => match it.definition_source(sema.db).value { |
207 | ModuleSource::Module(it) => runnable(&sema, it.syntax().clone(), file_id) | 194 | ModuleSource::Module(it) => { |
208 | .map(|it| HoverAction::Runnable(it)), | 195 | runnable(&sema, it.syntax().clone()).map(|it| HoverAction::Runnable(it)) |
196 | } | ||
209 | _ => None, | 197 | _ => None, |
210 | }, | 198 | }, |
211 | ModuleDef::Function(it) => { | 199 | ModuleDef::Function(func) => { |
212 | #[allow(deprecated)] | 200 | let src = func.source(sema.db)?; |
213 | let src = it.source(sema.db)?; | ||
214 | if src.file_id != file_id.into() { | 201 | if src.file_id != file_id.into() { |
215 | mark::hit!(hover_macro_generated_struct_fn_doc_comment); | 202 | mark::hit!(hover_macro_generated_struct_fn_doc_comment); |
216 | mark::hit!(hover_macro_generated_struct_fn_doc_attr); | 203 | mark::hit!(hover_macro_generated_struct_fn_doc_attr); |
217 | |||
218 | return None; | 204 | return None; |
219 | } | 205 | } |
220 | 206 | ||
221 | runnable(&sema, src.value.syntax().clone(), file_id) | 207 | runnable_fn(&sema, func).map(HoverAction::Runnable) |
222 | .map(|it| HoverAction::Runnable(it)) | ||
223 | } | 208 | } |
224 | _ => None, | 209 | _ => None, |
225 | }, | 210 | }, |
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 65df7979c..fe60abfc8 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs | |||
@@ -18,12 +18,6 @@ pub struct InlayHintsConfig { | |||
18 | pub max_length: Option<usize>, | 18 | pub max_length: Option<usize>, |
19 | } | 19 | } |
20 | 20 | ||
21 | impl Default for InlayHintsConfig { | ||
22 | fn default() -> Self { | ||
23 | Self { type_hints: true, parameter_hints: true, chaining_hints: true, max_length: None } | ||
24 | } | ||
25 | } | ||
26 | |||
27 | #[derive(Clone, Debug, PartialEq, Eq)] | 21 | #[derive(Clone, Debug, PartialEq, Eq)] |
28 | pub enum InlayKind { | 22 | pub enum InlayKind { |
29 | TypeHint, | 23 | TypeHint, |
@@ -433,8 +427,15 @@ mod tests { | |||
433 | 427 | ||
434 | use crate::{fixture, inlay_hints::InlayHintsConfig}; | 428 | use crate::{fixture, inlay_hints::InlayHintsConfig}; |
435 | 429 | ||
430 | const TEST_CONFIG: InlayHintsConfig = InlayHintsConfig { | ||
431 | type_hints: true, | ||
432 | parameter_hints: true, | ||
433 | chaining_hints: true, | ||
434 | max_length: None, | ||
435 | }; | ||
436 | |||
436 | fn check(ra_fixture: &str) { | 437 | fn check(ra_fixture: &str) { |
437 | check_with_config(InlayHintsConfig::default(), ra_fixture); | 438 | check_with_config(TEST_CONFIG, ra_fixture); |
438 | } | 439 | } |
439 | 440 | ||
440 | fn check_with_config(config: InlayHintsConfig, ra_fixture: &str) { | 441 | fn check_with_config(config: InlayHintsConfig, ra_fixture: &str) { |
@@ -748,7 +749,7 @@ fn main() { | |||
748 | #[test] | 749 | #[test] |
749 | fn hint_truncation() { | 750 | fn hint_truncation() { |
750 | check_with_config( | 751 | check_with_config( |
751 | InlayHintsConfig { max_length: Some(8), ..Default::default() }, | 752 | InlayHintsConfig { max_length: Some(8), ..TEST_CONFIG }, |
752 | r#" | 753 | r#" |
753 | struct Smol<T>(T); | 754 | struct Smol<T>(T); |
754 | 755 | ||
@@ -831,7 +832,7 @@ fn main() { | |||
831 | #[test] | 832 | #[test] |
832 | fn omitted_parameters_hints_heuristics() { | 833 | fn omitted_parameters_hints_heuristics() { |
833 | check_with_config( | 834 | check_with_config( |
834 | InlayHintsConfig { max_length: Some(8), ..Default::default() }, | 835 | InlayHintsConfig { max_length: Some(8), ..TEST_CONFIG }, |
835 | r#" | 836 | r#" |
836 | fn map(f: i32) {} | 837 | fn map(f: i32) {} |
837 | fn filter(predicate: i32) {} | 838 | fn filter(predicate: i32) {} |
@@ -924,7 +925,7 @@ fn main() { | |||
924 | #[test] | 925 | #[test] |
925 | fn unit_structs_have_no_type_hints() { | 926 | fn unit_structs_have_no_type_hints() { |
926 | check_with_config( | 927 | check_with_config( |
927 | InlayHintsConfig { max_length: Some(8), ..Default::default() }, | 928 | InlayHintsConfig { max_length: Some(8), ..TEST_CONFIG }, |
928 | r#" | 929 | r#" |
929 | enum Result<T, E> { Ok(T), Err(E) } | 930 | enum Result<T, E> { Ok(T), Err(E) } |
930 | use Result::*; | 931 | use Result::*; |
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs index c893afc7c..f4030f3ef 100644 --- a/crates/ide/src/runnables.rs +++ b/crates/ide/src/runnables.rs | |||
@@ -2,11 +2,11 @@ use std::fmt; | |||
2 | 2 | ||
3 | use assists::utils::test_related_attribute; | 3 | use assists::utils::test_related_attribute; |
4 | use cfg::CfgExpr; | 4 | use cfg::CfgExpr; |
5 | use hir::{AsAssocItem, HasAttrs, InFile, Semantics}; | 5 | use hir::{AsAssocItem, HasAttrs, HasSource, Semantics}; |
6 | use ide_db::RootDatabase; | 6 | use ide_db::RootDatabase; |
7 | use itertools::Itertools; | 7 | use itertools::Itertools; |
8 | use syntax::{ | 8 | use syntax::{ |
9 | ast::{self, AstNode, AttrsOwner, ModuleItemOwner, NameOwner}, | 9 | ast::{self, AstNode, AttrsOwner, ModuleItemOwner}, |
10 | match_ast, SyntaxNode, | 10 | match_ast, SyntaxNode, |
11 | }; | 11 | }; |
12 | 12 | ||
@@ -96,17 +96,16 @@ impl Runnable { | |||
96 | pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> { | 96 | pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> { |
97 | let sema = Semantics::new(db); | 97 | let sema = Semantics::new(db); |
98 | let source_file = sema.parse(file_id); | 98 | let source_file = sema.parse(file_id); |
99 | source_file.syntax().descendants().filter_map(|i| runnable(&sema, i, file_id)).collect() | 99 | source_file.syntax().descendants().filter_map(|i| runnable(&sema, i)).collect() |
100 | } | 100 | } |
101 | 101 | ||
102 | pub(crate) fn runnable( | 102 | pub(crate) fn runnable(sema: &Semantics<RootDatabase>, item: SyntaxNode) -> Option<Runnable> { |
103 | sema: &Semantics<RootDatabase>, | ||
104 | item: SyntaxNode, | ||
105 | file_id: FileId, | ||
106 | ) -> Option<Runnable> { | ||
107 | let runnable_item = match_ast! { | 103 | let runnable_item = match_ast! { |
108 | match (item.clone()) { | 104 | match (item.clone()) { |
109 | ast::Fn(it) => runnable_fn(sema, it, file_id), | 105 | ast::Fn(func) => { |
106 | let def = sema.to_def(&func)?; | ||
107 | runnable_fn(sema, def) | ||
108 | }, | ||
110 | ast::Module(it) => runnable_mod(sema, it), | 109 | ast::Module(it) => runnable_mod(sema, it), |
111 | _ => None, | 110 | _ => None, |
112 | } | 111 | } |
@@ -114,23 +113,23 @@ pub(crate) fn runnable( | |||
114 | runnable_item.or_else(|| runnable_doctest(sema, item)) | 113 | runnable_item.or_else(|| runnable_doctest(sema, item)) |
115 | } | 114 | } |
116 | 115 | ||
117 | fn runnable_fn(sema: &Semantics<RootDatabase>, func: ast::Fn, file_id: FileId) -> Option<Runnable> { | 116 | pub(crate) fn runnable_fn(sema: &Semantics<RootDatabase>, def: hir::Function) -> Option<Runnable> { |
118 | let def = sema.to_def(&func)?; | 117 | let func = def.source(sema.db)?; |
119 | let name_string = func.name()?.text().to_string(); | 118 | let name_string = def.name(sema.db).to_string(); |
120 | 119 | ||
121 | let kind = if name_string == "main" { | 120 | let kind = if name_string == "main" { |
122 | RunnableKind::Bin | 121 | RunnableKind::Bin |
123 | } else { | 122 | } else { |
124 | let canonical_path = sema.to_def(&func).and_then(|def| { | 123 | let canonical_path = { |
125 | let def: hir::ModuleDef = def.into(); | 124 | let def: hir::ModuleDef = def.into(); |
126 | def.canonical_path(sema.db) | 125 | def.canonical_path(sema.db) |
127 | }); | 126 | }; |
128 | let test_id = canonical_path.map(TestId::Path).unwrap_or(TestId::Name(name_string)); | 127 | let test_id = canonical_path.map(TestId::Path).unwrap_or(TestId::Name(name_string)); |
129 | 128 | ||
130 | if test_related_attribute(&func).is_some() { | 129 | if test_related_attribute(&func.value).is_some() { |
131 | let attr = TestAttr::from_fn(&func); | 130 | let attr = TestAttr::from_fn(&func.value); |
132 | RunnableKind::Test { test_id, attr } | 131 | RunnableKind::Test { test_id, attr } |
133 | } else if func.has_atom_attr("bench") { | 132 | } else if func.value.has_atom_attr("bench") { |
134 | RunnableKind::Bench { test_id } | 133 | RunnableKind::Bench { test_id } |
135 | } else { | 134 | } else { |
136 | return None; | 135 | return None; |
@@ -139,7 +138,7 @@ fn runnable_fn(sema: &Semantics<RootDatabase>, func: ast::Fn, file_id: FileId) - | |||
139 | 138 | ||
140 | let nav = NavigationTarget::from_named( | 139 | let nav = NavigationTarget::from_named( |
141 | sema.db, | 140 | sema.db, |
142 | InFile::new(file_id.into(), &func), | 141 | func.as_ref().map(|it| it as &dyn ast::NameOwner), |
143 | SymbolKind::Function, | 142 | SymbolKind::Function, |
144 | ); | 143 | ); |
145 | let cfg = def.attrs(sema.db).cfg(); | 144 | let cfg = def.attrs(sema.db).cfg(); |
diff --git a/crates/project_model/src/project_json.rs b/crates/project_model/src/project_json.rs index af884eb84..41a2ac03e 100644 --- a/crates/project_model/src/project_json.rs +++ b/crates/project_model/src/project_json.rs | |||
@@ -110,13 +110,13 @@ impl ProjectJson { | |||
110 | } | 110 | } |
111 | } | 111 | } |
112 | 112 | ||
113 | #[derive(Deserialize)] | 113 | #[derive(Deserialize, Debug, Clone)] |
114 | pub struct ProjectJsonData { | 114 | pub struct ProjectJsonData { |
115 | sysroot_src: Option<PathBuf>, | 115 | sysroot_src: Option<PathBuf>, |
116 | crates: Vec<CrateData>, | 116 | crates: Vec<CrateData>, |
117 | } | 117 | } |
118 | 118 | ||
119 | #[derive(Deserialize)] | 119 | #[derive(Deserialize, Debug, Clone)] |
120 | struct CrateData { | 120 | struct CrateData { |
121 | display_name: Option<String>, | 121 | display_name: Option<String>, |
122 | root_module: PathBuf, | 122 | root_module: PathBuf, |
@@ -132,7 +132,7 @@ struct CrateData { | |||
132 | source: Option<CrateSource>, | 132 | source: Option<CrateSource>, |
133 | } | 133 | } |
134 | 134 | ||
135 | #[derive(Deserialize)] | 135 | #[derive(Deserialize, Debug, Clone)] |
136 | #[serde(rename = "edition")] | 136 | #[serde(rename = "edition")] |
137 | enum EditionData { | 137 | enum EditionData { |
138 | #[serde(rename = "2015")] | 138 | #[serde(rename = "2015")] |
@@ -153,7 +153,7 @@ impl From<EditionData> for Edition { | |||
153 | } | 153 | } |
154 | } | 154 | } |
155 | 155 | ||
156 | #[derive(Deserialize)] | 156 | #[derive(Deserialize, Debug, Clone)] |
157 | struct DepData { | 157 | struct DepData { |
158 | /// Identifies a crate by position in the crates array. | 158 | /// Identifies a crate by position in the crates array. |
159 | #[serde(rename = "crate")] | 159 | #[serde(rename = "crate")] |
@@ -162,7 +162,7 @@ struct DepData { | |||
162 | name: CrateName, | 162 | name: CrateName, |
163 | } | 163 | } |
164 | 164 | ||
165 | #[derive(Deserialize)] | 165 | #[derive(Deserialize, Debug, Clone)] |
166 | struct CrateSource { | 166 | struct CrateSource { |
167 | include_dirs: Vec<PathBuf>, | 167 | include_dirs: Vec<PathBuf>, |
168 | exclude_dirs: Vec<PathBuf>, | 168 | exclude_dirs: Vec<PathBuf>, |
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs index defdcbd74..3af3c59d8 100644 --- a/crates/rust-analyzer/src/bin/main.rs +++ b/crates/rust-analyzer/src/bin/main.rs | |||
@@ -8,11 +8,7 @@ use std::{convert::TryFrom, env, fs, path::PathBuf, process}; | |||
8 | 8 | ||
9 | use lsp_server::Connection; | 9 | use lsp_server::Connection; |
10 | use project_model::ProjectManifest; | 10 | use project_model::ProjectManifest; |
11 | use rust_analyzer::{ | 11 | use rust_analyzer::{cli, config::Config, from_json, Result}; |
12 | cli, | ||
13 | config::{Config, LinkedProject}, | ||
14 | from_json, Result, | ||
15 | }; | ||
16 | use vfs::AbsPathBuf; | 12 | use vfs::AbsPathBuf; |
17 | 13 | ||
18 | #[cfg(all(feature = "mimalloc"))] | 14 | #[cfg(all(feature = "mimalloc"))] |
@@ -138,13 +134,12 @@ fn run_server() -> Result<()> { | |||
138 | } | 134 | } |
139 | }; | 135 | }; |
140 | 136 | ||
141 | let mut config = Config::new(root_path); | 137 | let mut config = Config::new(root_path, initialize_params.capabilities); |
142 | if let Some(json) = initialize_params.initialization_options { | 138 | if let Some(json) = initialize_params.initialization_options { |
143 | config.update(json); | 139 | config.update(json); |
144 | } | 140 | } |
145 | config.update_caps(&initialize_params.capabilities); | ||
146 | 141 | ||
147 | if config.linked_projects.is_empty() { | 142 | if config.linked_projects().is_empty() { |
148 | let workspace_roots = initialize_params | 143 | let workspace_roots = initialize_params |
149 | .workspace_folders | 144 | .workspace_folders |
150 | .map(|workspaces| { | 145 | .map(|workspaces| { |
@@ -163,7 +158,7 @@ fn run_server() -> Result<()> { | |||
163 | log::error!("failed to find any projects in {:?}", workspace_roots); | 158 | log::error!("failed to find any projects in {:?}", workspace_roots); |
164 | } | 159 | } |
165 | 160 | ||
166 | config.linked_projects = discovered.into_iter().map(LinkedProject::from).collect(); | 161 | config.discovered_projects = Some(discovered); |
167 | } | 162 | } |
168 | 163 | ||
169 | config | 164 | config |
diff --git a/crates/rust-analyzer/src/cargo_target_spec.rs b/crates/rust-analyzer/src/cargo_target_spec.rs index 8a8b4a32c..5af0802a2 100644 --- a/crates/rust-analyzer/src/cargo_target_spec.rs +++ b/crates/rust-analyzer/src/cargo_target_spec.rs | |||
@@ -84,14 +84,15 @@ impl CargoTargetSpec { | |||
84 | } | 84 | } |
85 | } | 85 | } |
86 | 86 | ||
87 | if snap.config.cargo.all_features { | 87 | let cargo_config = snap.config.cargo(); |
88 | if cargo_config.all_features { | ||
88 | args.push("--all-features".to_string()); | 89 | args.push("--all-features".to_string()); |
89 | } else { | 90 | } else { |
90 | let mut features = Vec::new(); | 91 | let mut features = Vec::new(); |
91 | if let Some(cfg) = cfg.as_ref() { | 92 | if let Some(cfg) = cfg.as_ref() { |
92 | required_features(cfg, &mut features); | 93 | required_features(cfg, &mut features); |
93 | } | 94 | } |
94 | for feature in &snap.config.cargo.features { | 95 | for feature in cargo_config.features { |
95 | features.push(feature.clone()); | 96 | features.push(feature.clone()); |
96 | } | 97 | } |
97 | features.dedup(); | 98 | features.dedup(); |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index a80652e83..24e7936fc 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -148,13 +148,19 @@ config_data! { | |||
148 | /// of projects.\n\nElements must be paths pointing to `Cargo.toml`, | 148 | /// of projects.\n\nElements must be paths pointing to `Cargo.toml`, |
149 | /// `rust-project.json`, or JSON objects in `rust-project.json` format. | 149 | /// `rust-project.json`, or JSON objects in `rust-project.json` format. |
150 | linkedProjects: Vec<ManifestOrProjectJson> = "[]", | 150 | linkedProjects: Vec<ManifestOrProjectJson> = "[]", |
151 | |||
151 | /// Number of syntax trees rust-analyzer keeps in memory. Defaults to 128. | 152 | /// Number of syntax trees rust-analyzer keeps in memory. Defaults to 128. |
152 | lruCapacity: Option<usize> = "null", | 153 | lruCapacity: Option<usize> = "null", |
154 | |||
153 | /// Whether to show `can't find Cargo.toml` error message. | 155 | /// Whether to show `can't find Cargo.toml` error message. |
154 | notifications_cargoTomlNotFound: bool = "true", | 156 | notifications_cargoTomlNotFound: bool = "true", |
157 | |||
155 | /// Enable Proc macro support, `#rust-analyzer.cargo.loadOutDirsFromCheck#` must be | 158 | /// Enable Proc macro support, `#rust-analyzer.cargo.loadOutDirsFromCheck#` must be |
156 | /// enabled. | 159 | /// enabled. |
157 | procMacro_enable: bool = "false", | 160 | procMacro_enable: bool = "false", |
161 | /// Internal config, path to proc-macro server executable (typically, | ||
162 | /// this is rust-analyzer itself, but we override this in tests). | ||
163 | procMacro_server: Option<PathBuf> = "null", | ||
158 | 164 | ||
159 | /// Command to be executed instead of 'cargo' for runnables. | 165 | /// Command to be executed instead of 'cargo' for runnables. |
160 | runnables_overrideCargo: Option<String> = "null", | 166 | runnables_overrideCargo: Option<String> = "null", |
@@ -163,7 +169,7 @@ config_data! { | |||
163 | runnables_cargoExtraArgs: Vec<String> = "[]", | 169 | runnables_cargoExtraArgs: Vec<String> = "[]", |
164 | 170 | ||
165 | /// Path to the rust compiler sources, for usage in rustc_private projects. | 171 | /// Path to the rust compiler sources, for usage in rustc_private projects. |
166 | rustcSource : Option<String> = "null", | 172 | rustcSource : Option<PathBuf> = "null", |
167 | 173 | ||
168 | /// Additional arguments to `rustfmt`. | 174 | /// Additional arguments to `rustfmt`. |
169 | rustfmt_extraArgs: Vec<String> = "[]", | 175 | rustfmt_extraArgs: Vec<String> = "[]", |
@@ -173,34 +179,17 @@ config_data! { | |||
173 | } | 179 | } |
174 | } | 180 | } |
175 | 181 | ||
182 | impl Default for ConfigData { | ||
183 | fn default() -> Self { | ||
184 | ConfigData::from_json(serde_json::Value::Null) | ||
185 | } | ||
186 | } | ||
187 | |||
176 | #[derive(Debug, Clone)] | 188 | #[derive(Debug, Clone)] |
177 | pub struct Config { | 189 | pub struct Config { |
178 | pub caps: lsp_types::ClientCapabilities, | 190 | caps: lsp_types::ClientCapabilities, |
179 | 191 | data: ConfigData, | |
180 | pub publish_diagnostics: bool, | 192 | pub discovered_projects: Option<Vec<ProjectManifest>>, |
181 | pub diagnostics: DiagnosticsConfig, | ||
182 | pub diagnostics_map: DiagnosticsMapConfig, | ||
183 | pub lru_capacity: Option<usize>, | ||
184 | pub proc_macro_srv: Option<(PathBuf, Vec<OsString>)>, | ||
185 | pub files: FilesConfig, | ||
186 | pub notifications: NotificationsConfig, | ||
187 | |||
188 | pub cargo_autoreload: bool, | ||
189 | pub cargo: CargoConfig, | ||
190 | pub rustfmt: RustfmtConfig, | ||
191 | pub flycheck: Option<FlycheckConfig>, | ||
192 | pub runnables: RunnablesConfig, | ||
193 | |||
194 | pub inlay_hints: InlayHintsConfig, | ||
195 | pub completion: CompletionConfig, | ||
196 | pub assist: AssistConfig, | ||
197 | pub call_info_full: bool, | ||
198 | pub lens: LensConfig, | ||
199 | pub hover: HoverConfig, | ||
200 | pub semantic_tokens_refresh: bool, | ||
201 | pub code_lens_refresh: bool, | ||
202 | |||
203 | pub linked_projects: Vec<LinkedProject>, | ||
204 | pub root_path: AbsPathBuf, | 193 | pub root_path: AbsPathBuf, |
205 | } | 194 | } |
206 | 195 | ||
@@ -230,12 +219,6 @@ pub struct LensConfig { | |||
230 | pub method_refs: bool, | 219 | pub method_refs: bool, |
231 | } | 220 | } |
232 | 221 | ||
233 | impl Default for LensConfig { | ||
234 | fn default() -> Self { | ||
235 | Self { run: true, debug: true, implementations: true, method_refs: false } | ||
236 | } | ||
237 | } | ||
238 | |||
239 | impl LensConfig { | 222 | impl LensConfig { |
240 | pub fn any(&self) -> bool { | 223 | pub fn any(&self) -> bool { |
241 | self.implementations || self.runnable() || self.references() | 224 | self.implementations || self.runnable() || self.references() |
@@ -278,7 +261,7 @@ pub enum RustfmtConfig { | |||
278 | } | 261 | } |
279 | 262 | ||
280 | /// Configuration for runnable items, such as `main` function or tests. | 263 | /// Configuration for runnable items, such as `main` function or tests. |
281 | #[derive(Debug, Clone, Default)] | 264 | #[derive(Debug, Clone)] |
282 | pub struct RunnablesConfig { | 265 | pub struct RunnablesConfig { |
283 | /// Custom command to be executed instead of `cargo` for runnables. | 266 | /// Custom command to be executed instead of `cargo` for runnables. |
284 | pub override_cargo: Option<String>, | 267 | pub override_cargo: Option<String>, |
@@ -287,250 +270,15 @@ pub struct RunnablesConfig { | |||
287 | } | 270 | } |
288 | 271 | ||
289 | impl Config { | 272 | impl Config { |
290 | pub fn new(root_path: AbsPathBuf) -> Self { | 273 | pub fn new(root_path: AbsPathBuf, caps: ClientCapabilities) -> Self { |
291 | // Defaults here don't matter, we'll immediately re-write them with | 274 | Config { caps, data: ConfigData::default(), discovered_projects: None, root_path } |
292 | // ConfigData. | ||
293 | let mut res = Config { | ||
294 | caps: lsp_types::ClientCapabilities::default(), | ||
295 | |||
296 | publish_diagnostics: false, | ||
297 | diagnostics: DiagnosticsConfig::default(), | ||
298 | diagnostics_map: DiagnosticsMapConfig::default(), | ||
299 | lru_capacity: None, | ||
300 | proc_macro_srv: None, | ||
301 | files: FilesConfig { watcher: FilesWatcher::Notify, exclude: Vec::new() }, | ||
302 | notifications: NotificationsConfig { cargo_toml_not_found: false }, | ||
303 | |||
304 | cargo_autoreload: false, | ||
305 | cargo: CargoConfig::default(), | ||
306 | rustfmt: RustfmtConfig::Rustfmt { extra_args: Vec::new() }, | ||
307 | flycheck: Some(FlycheckConfig::CargoCommand { | ||
308 | command: String::new(), | ||
309 | target_triple: None, | ||
310 | no_default_features: false, | ||
311 | all_targets: false, | ||
312 | all_features: false, | ||
313 | extra_args: Vec::new(), | ||
314 | features: Vec::new(), | ||
315 | }), | ||
316 | runnables: RunnablesConfig::default(), | ||
317 | |||
318 | inlay_hints: InlayHintsConfig { | ||
319 | type_hints: false, | ||
320 | parameter_hints: false, | ||
321 | chaining_hints: false, | ||
322 | max_length: None, | ||
323 | }, | ||
324 | completion: CompletionConfig::default(), | ||
325 | assist: AssistConfig::default(), | ||
326 | call_info_full: false, | ||
327 | lens: LensConfig::default(), | ||
328 | hover: HoverConfig::default(), | ||
329 | semantic_tokens_refresh: false, | ||
330 | code_lens_refresh: false, | ||
331 | linked_projects: Vec::new(), | ||
332 | root_path, | ||
333 | }; | ||
334 | res.do_update(serde_json::json!({})); | ||
335 | res | ||
336 | } | 275 | } |
337 | pub fn update(&mut self, json: serde_json::Value) { | 276 | pub fn update(&mut self, json: serde_json::Value) { |
338 | log::info!("updating config from JSON: {:#}", json); | 277 | log::info!("updating config from JSON: {:#}", json); |
339 | if json.is_null() || json.as_object().map_or(false, |it| it.is_empty()) { | 278 | if json.is_null() || json.as_object().map_or(false, |it| it.is_empty()) { |
340 | return; | 279 | return; |
341 | } | 280 | } |
342 | self.do_update(json); | 281 | self.data = ConfigData::from_json(json); |
343 | log::info!("updated config: {:#?}", self); | ||
344 | } | ||
345 | fn do_update(&mut self, json: serde_json::Value) { | ||
346 | let data = ConfigData::from_json(json); | ||
347 | |||
348 | self.publish_diagnostics = data.diagnostics_enable; | ||
349 | self.diagnostics = DiagnosticsConfig { | ||
350 | disable_experimental: !data.diagnostics_enableExperimental, | ||
351 | disabled: data.diagnostics_disabled, | ||
352 | }; | ||
353 | self.diagnostics_map = DiagnosticsMapConfig { | ||
354 | warnings_as_info: data.diagnostics_warningsAsInfo, | ||
355 | warnings_as_hint: data.diagnostics_warningsAsHint, | ||
356 | }; | ||
357 | self.lru_capacity = data.lruCapacity; | ||
358 | self.files.watcher = match data.files_watcher.as_str() { | ||
359 | "notify" => FilesWatcher::Notify, | ||
360 | "client" | _ => FilesWatcher::Client, | ||
361 | }; | ||
362 | self.notifications = | ||
363 | NotificationsConfig { cargo_toml_not_found: data.notifications_cargoTomlNotFound }; | ||
364 | self.cargo_autoreload = data.cargo_autoreload; | ||
365 | |||
366 | let rustc_source = if let Some(rustc_source) = data.rustcSource { | ||
367 | let rustpath: PathBuf = rustc_source.into(); | ||
368 | AbsPathBuf::try_from(rustpath) | ||
369 | .map_err(|_| { | ||
370 | log::error!("rustc source directory must be an absolute path"); | ||
371 | }) | ||
372 | .ok() | ||
373 | } else { | ||
374 | None | ||
375 | }; | ||
376 | |||
377 | self.cargo = CargoConfig { | ||
378 | no_default_features: data.cargo_noDefaultFeatures, | ||
379 | all_features: data.cargo_allFeatures, | ||
380 | features: data.cargo_features.clone(), | ||
381 | load_out_dirs_from_check: data.cargo_loadOutDirsFromCheck, | ||
382 | target: data.cargo_target.clone(), | ||
383 | rustc_source: rustc_source, | ||
384 | no_sysroot: data.cargo_noSysroot, | ||
385 | }; | ||
386 | self.runnables = RunnablesConfig { | ||
387 | override_cargo: data.runnables_overrideCargo, | ||
388 | cargo_extra_args: data.runnables_cargoExtraArgs, | ||
389 | }; | ||
390 | |||
391 | self.proc_macro_srv = if data.procMacro_enable { | ||
392 | std::env::current_exe().ok().map(|path| (path, vec!["proc-macro".into()])) | ||
393 | } else { | ||
394 | None | ||
395 | }; | ||
396 | |||
397 | self.rustfmt = match data.rustfmt_overrideCommand { | ||
398 | Some(mut args) if !args.is_empty() => { | ||
399 | let command = args.remove(0); | ||
400 | RustfmtConfig::CustomCommand { command, args } | ||
401 | } | ||
402 | Some(_) | None => RustfmtConfig::Rustfmt { extra_args: data.rustfmt_extraArgs }, | ||
403 | }; | ||
404 | |||
405 | self.flycheck = if data.checkOnSave_enable { | ||
406 | let flycheck_config = match data.checkOnSave_overrideCommand { | ||
407 | Some(mut args) if !args.is_empty() => { | ||
408 | let command = args.remove(0); | ||
409 | FlycheckConfig::CustomCommand { command, args } | ||
410 | } | ||
411 | Some(_) | None => FlycheckConfig::CargoCommand { | ||
412 | command: data.checkOnSave_command, | ||
413 | target_triple: data.checkOnSave_target.or(data.cargo_target), | ||
414 | all_targets: data.checkOnSave_allTargets, | ||
415 | no_default_features: data | ||
416 | .checkOnSave_noDefaultFeatures | ||
417 | .unwrap_or(data.cargo_noDefaultFeatures), | ||
418 | all_features: data.checkOnSave_allFeatures.unwrap_or(data.cargo_allFeatures), | ||
419 | features: data.checkOnSave_features.unwrap_or(data.cargo_features), | ||
420 | extra_args: data.checkOnSave_extraArgs, | ||
421 | }, | ||
422 | }; | ||
423 | Some(flycheck_config) | ||
424 | } else { | ||
425 | None | ||
426 | }; | ||
427 | |||
428 | self.inlay_hints = InlayHintsConfig { | ||
429 | type_hints: data.inlayHints_typeHints, | ||
430 | parameter_hints: data.inlayHints_parameterHints, | ||
431 | chaining_hints: data.inlayHints_chainingHints, | ||
432 | max_length: data.inlayHints_maxLength, | ||
433 | }; | ||
434 | |||
435 | self.assist.insert_use.merge = match data.assist_importMergeBehaviour { | ||
436 | MergeBehaviorDef::None => None, | ||
437 | MergeBehaviorDef::Full => Some(MergeBehavior::Full), | ||
438 | MergeBehaviorDef::Last => Some(MergeBehavior::Last), | ||
439 | }; | ||
440 | self.assist.insert_use.prefix_kind = match data.assist_importPrefix { | ||
441 | ImportPrefixDef::Plain => PrefixKind::Plain, | ||
442 | ImportPrefixDef::ByCrate => PrefixKind::ByCrate, | ||
443 | ImportPrefixDef::BySelf => PrefixKind::BySelf, | ||
444 | }; | ||
445 | |||
446 | self.completion.enable_postfix_completions = data.completion_postfix_enable; | ||
447 | self.completion.enable_autoimport_completions = data.completion_autoimport_enable; | ||
448 | self.completion.add_call_parenthesis = data.completion_addCallParenthesis; | ||
449 | self.completion.add_call_argument_snippets = data.completion_addCallArgumentSnippets; | ||
450 | self.completion.merge = self.assist.insert_use.merge; | ||
451 | |||
452 | self.call_info_full = data.callInfo_full; | ||
453 | |||
454 | self.lens = LensConfig { | ||
455 | run: data.lens_enable && data.lens_run, | ||
456 | debug: data.lens_enable && data.lens_debug, | ||
457 | implementations: data.lens_enable && data.lens_implementations, | ||
458 | method_refs: data.lens_enable && data.lens_methodReferences, | ||
459 | }; | ||
460 | |||
461 | if !data.linkedProjects.is_empty() { | ||
462 | self.linked_projects.clear(); | ||
463 | for linked_project in data.linkedProjects { | ||
464 | let linked_project = match linked_project { | ||
465 | ManifestOrProjectJson::Manifest(it) => { | ||
466 | let path = self.root_path.join(it); | ||
467 | match ProjectManifest::from_manifest_file(path) { | ||
468 | Ok(it) => it.into(), | ||
469 | Err(e) => { | ||
470 | log::error!("failed to load linked project: {}", e); | ||
471 | continue; | ||
472 | } | ||
473 | } | ||
474 | } | ||
475 | ManifestOrProjectJson::ProjectJson(it) => { | ||
476 | ProjectJson::new(&self.root_path, it).into() | ||
477 | } | ||
478 | }; | ||
479 | self.linked_projects.push(linked_project); | ||
480 | } | ||
481 | } | ||
482 | |||
483 | self.hover = HoverConfig { | ||
484 | implementations: data.hoverActions_enable && data.hoverActions_implementations, | ||
485 | run: data.hoverActions_enable && data.hoverActions_run, | ||
486 | debug: data.hoverActions_enable && data.hoverActions_debug, | ||
487 | goto_type_def: data.hoverActions_enable && data.hoverActions_gotoTypeDef, | ||
488 | links_in_hover: data.hoverActions_linksInHover, | ||
489 | markdown: true, | ||
490 | }; | ||
491 | } | ||
492 | |||
493 | pub fn update_caps(&mut self, caps: &ClientCapabilities) { | ||
494 | self.caps = caps.clone(); | ||
495 | if let Some(doc_caps) = caps.text_document.as_ref() { | ||
496 | if let Some(value) = doc_caps.hover.as_ref().and_then(|it| it.content_format.as_ref()) { | ||
497 | self.hover.markdown = value.contains(&MarkupKind::Markdown) | ||
498 | } | ||
499 | |||
500 | self.completion.allow_snippets(false); | ||
501 | self.completion.active_resolve_capabilities = | ||
502 | enabled_completions_resolve_capabilities(caps).unwrap_or_default(); | ||
503 | if let Some(completion) = &doc_caps.completion { | ||
504 | if let Some(completion_item) = &completion.completion_item { | ||
505 | if let Some(value) = completion_item.snippet_support { | ||
506 | self.completion.allow_snippets(value); | ||
507 | } | ||
508 | } | ||
509 | } | ||
510 | } | ||
511 | |||
512 | self.assist.allow_snippets(false); | ||
513 | if let Some(experimental) = &caps.experimental { | ||
514 | let get_bool = | ||
515 | |index: &str| experimental.get(index).and_then(|it| it.as_bool()) == Some(true); | ||
516 | |||
517 | let snippet_text_edit = get_bool("snippetTextEdit"); | ||
518 | self.assist.allow_snippets(snippet_text_edit); | ||
519 | } | ||
520 | |||
521 | if let Some(workspace_caps) = caps.workspace.as_ref() { | ||
522 | if let Some(refresh_support) = | ||
523 | workspace_caps.semantic_tokens.as_ref().and_then(|it| it.refresh_support) | ||
524 | { | ||
525 | self.semantic_tokens_refresh = refresh_support; | ||
526 | } | ||
527 | |||
528 | if let Some(refresh_support) = | ||
529 | workspace_caps.code_lens.as_ref().and_then(|it| it.refresh_support) | ||
530 | { | ||
531 | self.code_lens_refresh = refresh_support; | ||
532 | } | ||
533 | } | ||
534 | } | 282 | } |
535 | 283 | ||
536 | pub fn json_schema() -> serde_json::Value { | 284 | pub fn json_schema() -> serde_json::Value { |
@@ -550,6 +298,38 @@ macro_rules! try_or { | |||
550 | } | 298 | } |
551 | 299 | ||
552 | impl Config { | 300 | impl Config { |
301 | pub fn linked_projects(&self) -> Vec<LinkedProject> { | ||
302 | if self.data.linkedProjects.is_empty() { | ||
303 | self.discovered_projects | ||
304 | .as_ref() | ||
305 | .into_iter() | ||
306 | .flatten() | ||
307 | .cloned() | ||
308 | .map(LinkedProject::from) | ||
309 | .collect() | ||
310 | } else { | ||
311 | self.data | ||
312 | .linkedProjects | ||
313 | .iter() | ||
314 | .filter_map(|linked_project| { | ||
315 | let res = match linked_project { | ||
316 | ManifestOrProjectJson::Manifest(it) => { | ||
317 | let path = self.root_path.join(it); | ||
318 | ProjectManifest::from_manifest_file(path) | ||
319 | .map_err(|e| log::error!("failed to load linked project: {}", e)) | ||
320 | .ok()? | ||
321 | .into() | ||
322 | } | ||
323 | ManifestOrProjectJson::ProjectJson(it) => { | ||
324 | ProjectJson::new(&self.root_path, it.clone()).into() | ||
325 | } | ||
326 | }; | ||
327 | Some(res) | ||
328 | }) | ||
329 | .collect() | ||
330 | } | ||
331 | } | ||
332 | |||
553 | pub fn location_link(&self) -> bool { | 333 | pub fn location_link(&self) -> bool { |
554 | try_or!(self.caps.text_document.as_ref()?.definition?.link_support?, false) | 334 | try_or!(self.caps.text_document.as_ref()?.definition?.link_support?, false) |
555 | } | 335 | } |
@@ -625,16 +405,217 @@ impl Config { | |||
625 | pub fn status_notification(&self) -> bool { | 405 | pub fn status_notification(&self) -> bool { |
626 | self.experimental("statusNotification") | 406 | self.experimental("statusNotification") |
627 | } | 407 | } |
408 | |||
409 | pub fn publish_diagnostics(&self) -> bool { | ||
410 | self.data.diagnostics_enable | ||
411 | } | ||
412 | pub fn diagnostics(&self) -> DiagnosticsConfig { | ||
413 | DiagnosticsConfig { | ||
414 | disable_experimental: !self.data.diagnostics_enableExperimental, | ||
415 | disabled: self.data.diagnostics_disabled.clone(), | ||
416 | } | ||
417 | } | ||
418 | pub fn diagnostics_map(&self) -> DiagnosticsMapConfig { | ||
419 | DiagnosticsMapConfig { | ||
420 | warnings_as_info: self.data.diagnostics_warningsAsInfo.clone(), | ||
421 | warnings_as_hint: self.data.diagnostics_warningsAsHint.clone(), | ||
422 | } | ||
423 | } | ||
424 | pub fn lru_capacity(&self) -> Option<usize> { | ||
425 | self.data.lruCapacity | ||
426 | } | ||
427 | pub fn proc_macro_srv(&self) -> Option<(PathBuf, Vec<OsString>)> { | ||
428 | if !self.data.procMacro_enable { | ||
429 | return None; | ||
430 | } | ||
431 | |||
432 | let path = self.data.procMacro_server.clone().or_else(|| std::env::current_exe().ok())?; | ||
433 | Some((path, vec!["proc-macro".into()])) | ||
434 | } | ||
435 | pub fn files(&self) -> FilesConfig { | ||
436 | FilesConfig { | ||
437 | watcher: match self.data.files_watcher.as_str() { | ||
438 | "notify" => FilesWatcher::Notify, | ||
439 | "client" | _ => FilesWatcher::Client, | ||
440 | }, | ||
441 | exclude: Vec::new(), | ||
442 | } | ||
443 | } | ||
444 | pub fn notifications(&self) -> NotificationsConfig { | ||
445 | NotificationsConfig { cargo_toml_not_found: self.data.notifications_cargoTomlNotFound } | ||
446 | } | ||
447 | pub fn cargo_autoreload(&self) -> bool { | ||
448 | self.data.cargo_autoreload | ||
449 | } | ||
450 | pub fn cargo(&self) -> CargoConfig { | ||
451 | let rustc_source = self.data.rustcSource.clone().and_then(|it| { | ||
452 | AbsPathBuf::try_from(it) | ||
453 | .map_err(|_| log::error!("rustc source directory must be an absolute path")) | ||
454 | .ok() | ||
455 | }); | ||
456 | |||
457 | CargoConfig { | ||
458 | no_default_features: self.data.cargo_noDefaultFeatures, | ||
459 | all_features: self.data.cargo_allFeatures, | ||
460 | features: self.data.cargo_features.clone(), | ||
461 | load_out_dirs_from_check: self.data.cargo_loadOutDirsFromCheck, | ||
462 | target: self.data.cargo_target.clone(), | ||
463 | rustc_source, | ||
464 | no_sysroot: self.data.cargo_noSysroot, | ||
465 | } | ||
466 | } | ||
467 | pub fn rustfmt(&self) -> RustfmtConfig { | ||
468 | match &self.data.rustfmt_overrideCommand { | ||
469 | Some(args) if !args.is_empty() => { | ||
470 | let mut args = args.clone(); | ||
471 | let command = args.remove(0); | ||
472 | RustfmtConfig::CustomCommand { command, args } | ||
473 | } | ||
474 | Some(_) | None => { | ||
475 | RustfmtConfig::Rustfmt { extra_args: self.data.rustfmt_extraArgs.clone() } | ||
476 | } | ||
477 | } | ||
478 | } | ||
479 | pub fn flycheck(&self) -> Option<FlycheckConfig> { | ||
480 | if !self.data.checkOnSave_enable { | ||
481 | return None; | ||
482 | } | ||
483 | let flycheck_config = match &self.data.checkOnSave_overrideCommand { | ||
484 | Some(args) if !args.is_empty() => { | ||
485 | let mut args = args.clone(); | ||
486 | let command = args.remove(0); | ||
487 | FlycheckConfig::CustomCommand { command, args } | ||
488 | } | ||
489 | Some(_) | None => FlycheckConfig::CargoCommand { | ||
490 | command: self.data.checkOnSave_command.clone(), | ||
491 | target_triple: self | ||
492 | .data | ||
493 | .checkOnSave_target | ||
494 | .clone() | ||
495 | .or(self.data.cargo_target.clone()), | ||
496 | all_targets: self.data.checkOnSave_allTargets, | ||
497 | no_default_features: self | ||
498 | .data | ||
499 | .checkOnSave_noDefaultFeatures | ||
500 | .unwrap_or(self.data.cargo_noDefaultFeatures), | ||
501 | all_features: self | ||
502 | .data | ||
503 | .checkOnSave_allFeatures | ||
504 | .unwrap_or(self.data.cargo_allFeatures), | ||
505 | features: self | ||
506 | .data | ||
507 | .checkOnSave_features | ||
508 | .clone() | ||
509 | .unwrap_or(self.data.cargo_features.clone()), | ||
510 | extra_args: self.data.checkOnSave_extraArgs.clone(), | ||
511 | }, | ||
512 | }; | ||
513 | Some(flycheck_config) | ||
514 | } | ||
515 | pub fn runnables(&self) -> RunnablesConfig { | ||
516 | RunnablesConfig { | ||
517 | override_cargo: self.data.runnables_overrideCargo.clone(), | ||
518 | cargo_extra_args: self.data.runnables_cargoExtraArgs.clone(), | ||
519 | } | ||
520 | } | ||
521 | pub fn inlay_hints(&self) -> InlayHintsConfig { | ||
522 | InlayHintsConfig { | ||
523 | type_hints: self.data.inlayHints_typeHints, | ||
524 | parameter_hints: self.data.inlayHints_parameterHints, | ||
525 | chaining_hints: self.data.inlayHints_chainingHints, | ||
526 | max_length: self.data.inlayHints_maxLength, | ||
527 | } | ||
528 | } | ||
529 | fn merge_behavior(&self) -> Option<MergeBehavior> { | ||
530 | match self.data.assist_importMergeBehaviour { | ||
531 | MergeBehaviorDef::None => None, | ||
532 | MergeBehaviorDef::Full => Some(MergeBehavior::Full), | ||
533 | MergeBehaviorDef::Last => Some(MergeBehavior::Last), | ||
534 | } | ||
535 | } | ||
536 | pub fn completion(&self) -> CompletionConfig { | ||
537 | let mut res = CompletionConfig::default(); | ||
538 | res.enable_postfix_completions = self.data.completion_postfix_enable; | ||
539 | res.enable_autoimport_completions = self.data.completion_autoimport_enable; | ||
540 | res.add_call_parenthesis = self.data.completion_addCallParenthesis; | ||
541 | res.add_call_argument_snippets = self.data.completion_addCallArgumentSnippets; | ||
542 | res.merge = self.merge_behavior(); | ||
543 | res.active_resolve_capabilities = | ||
544 | enabled_completions_resolve_capabilities(&self.caps).unwrap_or_default(); | ||
545 | |||
546 | res.allow_snippets(try_or!( | ||
547 | self.caps | ||
548 | .text_document | ||
549 | .as_ref()? | ||
550 | .completion | ||
551 | .as_ref()? | ||
552 | .completion_item | ||
553 | .as_ref()? | ||
554 | .snippet_support?, | ||
555 | false | ||
556 | )); | ||
557 | res | ||
558 | } | ||
559 | pub fn assist(&self) -> AssistConfig { | ||
560 | let mut res = AssistConfig::default(); | ||
561 | res.insert_use.merge = self.merge_behavior(); | ||
562 | res.insert_use.prefix_kind = match self.data.assist_importPrefix { | ||
563 | ImportPrefixDef::Plain => PrefixKind::Plain, | ||
564 | ImportPrefixDef::ByCrate => PrefixKind::ByCrate, | ||
565 | ImportPrefixDef::BySelf => PrefixKind::BySelf, | ||
566 | }; | ||
567 | res.allow_snippets(self.experimental("snippetTextEdit")); | ||
568 | res | ||
569 | } | ||
570 | pub fn call_info_full(&self) -> bool { | ||
571 | self.data.callInfo_full | ||
572 | } | ||
573 | pub fn lens(&self) -> LensConfig { | ||
574 | LensConfig { | ||
575 | run: self.data.lens_enable && self.data.lens_run, | ||
576 | debug: self.data.lens_enable && self.data.lens_debug, | ||
577 | implementations: self.data.lens_enable && self.data.lens_implementations, | ||
578 | method_refs: self.data.lens_enable && self.data.lens_methodReferences, | ||
579 | } | ||
580 | } | ||
581 | pub fn hover(&self) -> HoverConfig { | ||
582 | HoverConfig { | ||
583 | implementations: self.data.hoverActions_enable | ||
584 | && self.data.hoverActions_implementations, | ||
585 | run: self.data.hoverActions_enable && self.data.hoverActions_run, | ||
586 | debug: self.data.hoverActions_enable && self.data.hoverActions_debug, | ||
587 | goto_type_def: self.data.hoverActions_enable && self.data.hoverActions_gotoTypeDef, | ||
588 | links_in_hover: self.data.hoverActions_linksInHover, | ||
589 | markdown: try_or!( | ||
590 | self.caps | ||
591 | .text_document | ||
592 | .as_ref()? | ||
593 | .hover | ||
594 | .as_ref()? | ||
595 | .content_format | ||
596 | .as_ref()? | ||
597 | .as_slice(), | ||
598 | &[] | ||
599 | ) | ||
600 | .contains(&MarkupKind::Markdown), | ||
601 | } | ||
602 | } | ||
603 | pub fn semantic_tokens_refresh(&self) -> bool { | ||
604 | try_or!(self.caps.workspace.as_ref()?.semantic_tokens.as_ref()?.refresh_support?, false) | ||
605 | } | ||
606 | pub fn code_lens_refresh(&self) -> bool { | ||
607 | try_or!(self.caps.workspace.as_ref()?.code_lens.as_ref()?.refresh_support?, false) | ||
608 | } | ||
628 | } | 609 | } |
629 | 610 | ||
630 | #[derive(Deserialize)] | 611 | #[derive(Deserialize, Debug, Clone)] |
631 | #[serde(untagged)] | 612 | #[serde(untagged)] |
632 | enum ManifestOrProjectJson { | 613 | enum ManifestOrProjectJson { |
633 | Manifest(PathBuf), | 614 | Manifest(PathBuf), |
634 | ProjectJson(ProjectJsonData), | 615 | ProjectJson(ProjectJsonData), |
635 | } | 616 | } |
636 | 617 | ||
637 | #[derive(Deserialize)] | 618 | #[derive(Deserialize, Debug, Clone)] |
638 | #[serde(rename_all = "snake_case")] | 619 | #[serde(rename_all = "snake_case")] |
639 | enum MergeBehaviorDef { | 620 | enum MergeBehaviorDef { |
640 | None, | 621 | None, |
@@ -642,7 +623,7 @@ enum MergeBehaviorDef { | |||
642 | Last, | 623 | Last, |
643 | } | 624 | } |
644 | 625 | ||
645 | #[derive(Deserialize)] | 626 | #[derive(Deserialize, Debug, Clone)] |
646 | #[serde(rename_all = "snake_case")] | 627 | #[serde(rename_all = "snake_case")] |
647 | enum ImportPrefixDef { | 628 | enum ImportPrefixDef { |
648 | Plain, | 629 | Plain, |
@@ -658,6 +639,7 @@ macro_rules! _config_data { | |||
658 | )* | 639 | )* |
659 | }) => { | 640 | }) => { |
660 | #[allow(non_snake_case)] | 641 | #[allow(non_snake_case)] |
642 | #[derive(Debug, Clone)] | ||
661 | struct $name { $($field: $ty,)* } | 643 | struct $name { $($field: $ty,)* } |
662 | impl $name { | 644 | impl $name { |
663 | fn from_json(mut json: serde_json::Value) -> $name { | 645 | fn from_json(mut json: serde_json::Value) -> $name { |
@@ -763,6 +745,9 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json | |||
763 | "Option<String>" => set! { | 745 | "Option<String>" => set! { |
764 | "type": ["null", "string"], | 746 | "type": ["null", "string"], |
765 | }, | 747 | }, |
748 | "Option<PathBuf>" => set! { | ||
749 | "type": ["null", "string"], | ||
750 | }, | ||
766 | "Option<bool>" => set! { | 751 | "Option<bool>" => set! { |
767 | "type": ["null", "boolean"], | 752 | "type": ["null", "boolean"], |
768 | }, | 753 | }, |
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 71dc56915..19ab4d596 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs | |||
@@ -109,7 +109,7 @@ impl GlobalState { | |||
109 | Handle { handle, receiver } | 109 | Handle { handle, receiver } |
110 | }; | 110 | }; |
111 | 111 | ||
112 | let analysis_host = AnalysisHost::new(config.lru_capacity); | 112 | let analysis_host = AnalysisHost::new(config.lru_capacity()); |
113 | let (flycheck_sender, flycheck_receiver) = unbounded(); | 113 | let (flycheck_sender, flycheck_receiver) = unbounded(); |
114 | GlobalState { | 114 | GlobalState { |
115 | sender, | 115 | sender, |
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs index 071b34cda..33661325a 100644 --- a/crates/rust-analyzer/src/handlers.rs +++ b/crates/rust-analyzer/src/handlers.rs | |||
@@ -9,9 +9,9 @@ use std::{ | |||
9 | }; | 9 | }; |
10 | 10 | ||
11 | use ide::{ | 11 | use ide::{ |
12 | AssistConfig, CompletionResolveCapability, FileId, FilePosition, FileRange, HoverAction, | 12 | CompletionResolveCapability, FileId, FilePosition, FileRange, HoverAction, HoverGotoTypeData, |
13 | HoverGotoTypeData, LineIndex, NavigationTarget, Query, RangeInfo, Runnable, RunnableKind, | 13 | LineIndex, NavigationTarget, Query, RangeInfo, Runnable, RunnableKind, SearchScope, |
14 | SearchScope, SourceChange, SymbolKind, TextEdit, | 14 | SourceChange, SymbolKind, TextEdit, |
15 | }; | 15 | }; |
16 | use itertools::Itertools; | 16 | use itertools::Itertools; |
17 | use lsp_server::ErrorCode; | 17 | use lsp_server::ErrorCode; |
@@ -548,7 +548,7 @@ pub(crate) fn handle_runnables( | |||
548 | } | 548 | } |
549 | 549 | ||
550 | // Add `cargo check` and `cargo test` for all targets of the whole package | 550 | // Add `cargo check` and `cargo test` for all targets of the whole package |
551 | let config = &snap.config.runnables; | 551 | let config = snap.config.runnables(); |
552 | match cargo_spec { | 552 | match cargo_spec { |
553 | Some(spec) => { | 553 | Some(spec) => { |
554 | for &cmd in ["check", "test"].iter() { | 554 | for &cmd in ["check", "test"].iter() { |
@@ -579,9 +579,9 @@ pub(crate) fn handle_runnables( | |||
579 | kind: lsp_ext::RunnableKind::Cargo, | 579 | kind: lsp_ext::RunnableKind::Cargo, |
580 | args: lsp_ext::CargoRunnable { | 580 | args: lsp_ext::CargoRunnable { |
581 | workspace_root: None, | 581 | workspace_root: None, |
582 | override_cargo: config.override_cargo.clone(), | 582 | override_cargo: config.override_cargo, |
583 | cargo_args: vec!["check".to_string(), "--workspace".to_string()], | 583 | cargo_args: vec!["check".to_string(), "--workspace".to_string()], |
584 | cargo_extra_args: config.cargo_extra_args.clone(), | 584 | cargo_extra_args: config.cargo_extra_args, |
585 | executable_args: Vec::new(), | 585 | executable_args: Vec::new(), |
586 | expect_test: None, | 586 | expect_test: None, |
587 | }, | 587 | }, |
@@ -620,7 +620,8 @@ pub(crate) fn handle_completion( | |||
620 | return Ok(None); | 620 | return Ok(None); |
621 | } | 621 | } |
622 | 622 | ||
623 | let items = match snap.analysis.completions(&snap.config.completion, position)? { | 623 | let completion_config = &snap.config.completion(); |
624 | let items = match snap.analysis.completions(completion_config, position)? { | ||
624 | None => return Ok(None), | 625 | None => return Ok(None), |
625 | Some(items) => items, | 626 | Some(items) => items, |
626 | }; | 627 | }; |
@@ -633,7 +634,7 @@ pub(crate) fn handle_completion( | |||
633 | let mut new_completion_items = | 634 | let mut new_completion_items = |
634 | to_proto::completion_item(&line_index, line_endings, item.clone()); | 635 | to_proto::completion_item(&line_index, line_endings, item.clone()); |
635 | 636 | ||
636 | if snap.config.completion.resolve_additional_edits_lazily() { | 637 | if completion_config.resolve_additional_edits_lazily() { |
637 | for new_item in &mut new_completion_items { | 638 | for new_item in &mut new_completion_items { |
638 | let _ = fill_resolve_data(&mut new_item.data, &item, &text_document_position) | 639 | let _ = fill_resolve_data(&mut new_item.data, &item, &text_document_position) |
639 | .take(); | 640 | .take(); |
@@ -663,9 +664,8 @@ pub(crate) fn handle_completion_resolve( | |||
663 | } | 664 | } |
664 | 665 | ||
665 | // FIXME resolve the other capabilities also? | 666 | // FIXME resolve the other capabilities also? |
666 | if !snap | 667 | let completion_config = &snap.config.completion(); |
667 | .config | 668 | if !completion_config |
668 | .completion | ||
669 | .active_resolve_capabilities | 669 | .active_resolve_capabilities |
670 | .contains(&CompletionResolveCapability::AdditionalTextEdits) | 670 | .contains(&CompletionResolveCapability::AdditionalTextEdits) |
671 | { | 671 | { |
@@ -690,7 +690,7 @@ pub(crate) fn handle_completion_resolve( | |||
690 | let additional_edits = snap | 690 | let additional_edits = snap |
691 | .analysis | 691 | .analysis |
692 | .resolve_completion_edits( | 692 | .resolve_completion_edits( |
693 | &snap.config.completion, | 693 | &completion_config, |
694 | FilePosition { file_id, offset }, | 694 | FilePosition { file_id, offset }, |
695 | &resolve_data.full_import_path, | 695 | &resolve_data.full_import_path, |
696 | resolve_data.imported_name, | 696 | resolve_data.imported_name, |
@@ -746,7 +746,7 @@ pub(crate) fn handle_signature_help( | |||
746 | Some(it) => it, | 746 | Some(it) => it, |
747 | None => return Ok(None), | 747 | None => return Ok(None), |
748 | }; | 748 | }; |
749 | let concise = !snap.config.call_info_full; | 749 | let concise = !snap.config.call_info_full(); |
750 | let res = | 750 | let res = |
751 | to_proto::signature_help(call_info, concise, snap.config.signature_help_label_offsets()); | 751 | to_proto::signature_help(call_info, concise, snap.config.signature_help_label_offsets()); |
752 | Ok(Some(res)) | 752 | Ok(Some(res)) |
@@ -758,14 +758,12 @@ pub(crate) fn handle_hover( | |||
758 | ) -> Result<Option<lsp_ext::Hover>> { | 758 | ) -> Result<Option<lsp_ext::Hover>> { |
759 | let _p = profile::span("handle_hover"); | 759 | let _p = profile::span("handle_hover"); |
760 | let position = from_proto::file_position(&snap, params.text_document_position_params)?; | 760 | let position = from_proto::file_position(&snap, params.text_document_position_params)?; |
761 | let info = match snap.analysis.hover( | 761 | let hover_config = snap.config.hover(); |
762 | position, | 762 | let info = |
763 | snap.config.hover.links_in_hover, | 763 | match snap.analysis.hover(position, hover_config.links_in_hover, hover_config.markdown)? { |
764 | snap.config.hover.markdown, | 764 | None => return Ok(None), |
765 | )? { | 765 | Some(info) => info, |
766 | None => return Ok(None), | 766 | }; |
767 | Some(info) => info, | ||
768 | }; | ||
769 | let line_index = snap.analysis.file_line_index(position.file_id)?; | 767 | let line_index = snap.analysis.file_line_index(position.file_id)?; |
770 | let range = to_proto::range(&line_index, info.range); | 768 | let range = to_proto::range(&line_index, info.range); |
771 | let hover = lsp_ext::Hover { | 769 | let hover = lsp_ext::Hover { |
@@ -851,7 +849,7 @@ pub(crate) fn handle_formatting( | |||
851 | let file_line_index = snap.analysis.file_line_index(file_id)?; | 849 | let file_line_index = snap.analysis.file_line_index(file_id)?; |
852 | let file_line_endings = snap.file_line_endings(file_id); | 850 | let file_line_endings = snap.file_line_endings(file_id); |
853 | 851 | ||
854 | let mut rustfmt = match &snap.config.rustfmt { | 852 | let mut rustfmt = match snap.config.rustfmt() { |
855 | RustfmtConfig::Rustfmt { extra_args } => { | 853 | RustfmtConfig::Rustfmt { extra_args } => { |
856 | let mut cmd = process::Command::new(toolchain::rustfmt()); | 854 | let mut cmd = process::Command::new(toolchain::rustfmt()); |
857 | cmd.args(extra_args); | 855 | cmd.args(extra_args); |
@@ -947,14 +945,12 @@ pub(crate) fn handle_code_action( | |||
947 | let range = from_proto::text_range(&line_index, params.range); | 945 | let range = from_proto::text_range(&line_index, params.range); |
948 | let frange = FileRange { file_id, range }; | 946 | let frange = FileRange { file_id, range }; |
949 | 947 | ||
950 | let assists_config = AssistConfig { | 948 | let mut assists_config = snap.config.assist(); |
951 | allowed: params | 949 | assists_config.allowed = params |
952 | .clone() | 950 | .clone() |
953 | .context | 951 | .context |
954 | .only | 952 | .only |
955 | .map(|it| it.into_iter().filter_map(from_proto::assist_kind).collect()), | 953 | .map(|it| it.into_iter().filter_map(from_proto::assist_kind).collect()); |
956 | ..snap.config.assist | ||
957 | }; | ||
958 | 954 | ||
959 | let mut res: Vec<lsp_ext::CodeAction> = Vec::new(); | 955 | let mut res: Vec<lsp_ext::CodeAction> = Vec::new(); |
960 | 956 | ||
@@ -989,7 +985,7 @@ fn add_quick_fixes( | |||
989 | line_index: &Arc<LineIndex>, | 985 | line_index: &Arc<LineIndex>, |
990 | acc: &mut Vec<lsp_ext::CodeAction>, | 986 | acc: &mut Vec<lsp_ext::CodeAction>, |
991 | ) -> Result<()> { | 987 | ) -> Result<()> { |
992 | let diagnostics = snap.analysis.diagnostics(&snap.config.diagnostics, frange.file_id)?; | 988 | let diagnostics = snap.analysis.diagnostics(&snap.config.diagnostics(), frange.file_id)?; |
993 | 989 | ||
994 | for fix in diagnostics | 990 | for fix in diagnostics |
995 | .into_iter() | 991 | .into_iter() |
@@ -1018,7 +1014,7 @@ fn add_quick_fixes( | |||
1018 | } | 1014 | } |
1019 | 1015 | ||
1020 | pub(crate) fn handle_code_action_resolve( | 1016 | pub(crate) fn handle_code_action_resolve( |
1021 | mut snap: GlobalStateSnapshot, | 1017 | snap: GlobalStateSnapshot, |
1022 | mut code_action: lsp_ext::CodeAction, | 1018 | mut code_action: lsp_ext::CodeAction, |
1023 | ) -> Result<lsp_ext::CodeAction> { | 1019 | ) -> Result<lsp_ext::CodeAction> { |
1024 | let _p = profile::span("handle_code_action_resolve"); | 1020 | let _p = profile::span("handle_code_action_resolve"); |
@@ -1032,13 +1028,14 @@ pub(crate) fn handle_code_action_resolve( | |||
1032 | let range = from_proto::text_range(&line_index, params.code_action_params.range); | 1028 | let range = from_proto::text_range(&line_index, params.code_action_params.range); |
1033 | let frange = FileRange { file_id, range }; | 1029 | let frange = FileRange { file_id, range }; |
1034 | 1030 | ||
1035 | snap.config.assist.allowed = params | 1031 | let mut assists_config = snap.config.assist(); |
1032 | assists_config.allowed = params | ||
1036 | .code_action_params | 1033 | .code_action_params |
1037 | .context | 1034 | .context |
1038 | .only | 1035 | .only |
1039 | .map(|it| it.into_iter().filter_map(from_proto::assist_kind).collect()); | 1036 | .map(|it| it.into_iter().filter_map(from_proto::assist_kind).collect()); |
1040 | 1037 | ||
1041 | let assists = snap.analysis.assists(&snap.config.assist, true, frange)?; | 1038 | let assists = snap.analysis.assists(&assists_config, true, frange)?; |
1042 | let (id, index) = split_once(¶ms.id, ':').unwrap(); | 1039 | let (id, index) = split_once(¶ms.id, ':').unwrap(); |
1043 | let index = index.parse::<usize>().unwrap(); | 1040 | let index = index.parse::<usize>().unwrap(); |
1044 | let assist = &assists[index]; | 1041 | let assist = &assists[index]; |
@@ -1055,7 +1052,8 @@ pub(crate) fn handle_code_lens( | |||
1055 | let _p = profile::span("handle_code_lens"); | 1052 | let _p = profile::span("handle_code_lens"); |
1056 | let mut lenses: Vec<CodeLens> = Default::default(); | 1053 | let mut lenses: Vec<CodeLens> = Default::default(); |
1057 | 1054 | ||
1058 | if snap.config.lens.none() { | 1055 | let lens_config = snap.config.lens(); |
1056 | if lens_config.none() { | ||
1059 | // early return before any db query! | 1057 | // early return before any db query! |
1060 | return Ok(Some(lenses)); | 1058 | return Ok(Some(lenses)); |
1061 | } | 1059 | } |
@@ -1064,7 +1062,7 @@ pub(crate) fn handle_code_lens( | |||
1064 | let line_index = snap.analysis.file_line_index(file_id)?; | 1062 | let line_index = snap.analysis.file_line_index(file_id)?; |
1065 | let cargo_spec = CargoTargetSpec::for_file(&snap, file_id)?; | 1063 | let cargo_spec = CargoTargetSpec::for_file(&snap, file_id)?; |
1066 | 1064 | ||
1067 | if snap.config.lens.runnable() { | 1065 | if lens_config.runnable() { |
1068 | // Gather runnables | 1066 | // Gather runnables |
1069 | for runnable in snap.analysis.runnables(file_id)? { | 1067 | for runnable in snap.analysis.runnables(file_id)? { |
1070 | if should_skip_target(&runnable, cargo_spec.as_ref()) { | 1068 | if should_skip_target(&runnable, cargo_spec.as_ref()) { |
@@ -1074,7 +1072,7 @@ pub(crate) fn handle_code_lens( | |||
1074 | let action = runnable.action(); | 1072 | let action = runnable.action(); |
1075 | let range = to_proto::range(&line_index, runnable.nav.full_range); | 1073 | let range = to_proto::range(&line_index, runnable.nav.full_range); |
1076 | let r = to_proto::runnable(&snap, file_id, runnable)?; | 1074 | let r = to_proto::runnable(&snap, file_id, runnable)?; |
1077 | if snap.config.lens.run { | 1075 | if lens_config.run { |
1078 | let lens = CodeLens { | 1076 | let lens = CodeLens { |
1079 | range, | 1077 | range, |
1080 | command: Some(run_single_command(&r, action.run_title)), | 1078 | command: Some(run_single_command(&r, action.run_title)), |
@@ -1083,7 +1081,7 @@ pub(crate) fn handle_code_lens( | |||
1083 | lenses.push(lens); | 1081 | lenses.push(lens); |
1084 | } | 1082 | } |
1085 | 1083 | ||
1086 | if action.debugee && snap.config.lens.debug { | 1084 | if action.debugee && lens_config.debug { |
1087 | let debug_lens = | 1085 | let debug_lens = |
1088 | CodeLens { range, command: Some(debug_single_command(&r)), data: None }; | 1086 | CodeLens { range, command: Some(debug_single_command(&r)), data: None }; |
1089 | lenses.push(debug_lens); | 1087 | lenses.push(debug_lens); |
@@ -1091,7 +1089,7 @@ pub(crate) fn handle_code_lens( | |||
1091 | } | 1089 | } |
1092 | } | 1090 | } |
1093 | 1091 | ||
1094 | if snap.config.lens.implementations { | 1092 | if lens_config.implementations { |
1095 | // Handle impls | 1093 | // Handle impls |
1096 | lenses.extend( | 1094 | lenses.extend( |
1097 | snap.analysis | 1095 | snap.analysis |
@@ -1126,7 +1124,7 @@ pub(crate) fn handle_code_lens( | |||
1126 | ); | 1124 | ); |
1127 | } | 1125 | } |
1128 | 1126 | ||
1129 | if snap.config.lens.references() { | 1127 | if lens_config.references() { |
1130 | lenses.extend(snap.analysis.find_all_methods(file_id)?.into_iter().map(|it| { | 1128 | lenses.extend(snap.analysis.find_all_methods(file_id)?.into_iter().map(|it| { |
1131 | let range = to_proto::range(&line_index, it.range); | 1129 | let range = to_proto::range(&line_index, it.range); |
1132 | let position = to_proto::position(&line_index, it.range.start()); | 1130 | let position = to_proto::position(&line_index, it.range.start()); |
@@ -1272,7 +1270,7 @@ pub(crate) fn publish_diagnostics( | |||
1272 | 1270 | ||
1273 | let diagnostics: Vec<Diagnostic> = snap | 1271 | let diagnostics: Vec<Diagnostic> = snap |
1274 | .analysis | 1272 | .analysis |
1275 | .diagnostics(&snap.config.diagnostics, file_id)? | 1273 | .diagnostics(&snap.config.diagnostics(), file_id)? |
1276 | .into_iter() | 1274 | .into_iter() |
1277 | .map(|d| Diagnostic { | 1275 | .map(|d| Diagnostic { |
1278 | range: to_proto::range(&line_index, d.range), | 1276 | range: to_proto::range(&line_index, d.range), |
@@ -1305,7 +1303,7 @@ pub(crate) fn handle_inlay_hints( | |||
1305 | let line_index = snap.analysis.file_line_index(file_id)?; | 1303 | let line_index = snap.analysis.file_line_index(file_id)?; |
1306 | Ok(snap | 1304 | Ok(snap |
1307 | .analysis | 1305 | .analysis |
1308 | .inlay_hints(file_id, &snap.config.inlay_hints)? | 1306 | .inlay_hints(file_id, &snap.config.inlay_hints())? |
1309 | .into_iter() | 1307 | .into_iter() |
1310 | .map(|it| to_proto::inlay_hint(&line_index, it)) | 1308 | .map(|it| to_proto::inlay_hint(&line_index, it)) |
1311 | .collect()) | 1309 | .collect()) |
@@ -1575,7 +1573,7 @@ fn show_impl_command_link( | |||
1575 | snap: &GlobalStateSnapshot, | 1573 | snap: &GlobalStateSnapshot, |
1576 | position: &FilePosition, | 1574 | position: &FilePosition, |
1577 | ) -> Option<lsp_ext::CommandLinkGroup> { | 1575 | ) -> Option<lsp_ext::CommandLinkGroup> { |
1578 | if snap.config.hover.implementations { | 1576 | if snap.config.hover().implementations { |
1579 | if let Some(nav_data) = snap.analysis.goto_implementation(*position).unwrap_or(None) { | 1577 | if let Some(nav_data) = snap.analysis.goto_implementation(*position).unwrap_or(None) { |
1580 | let uri = to_proto::url(snap, position.file_id); | 1578 | let uri = to_proto::url(snap, position.file_id); |
1581 | let line_index = snap.analysis.file_line_index(position.file_id).ok()?; | 1579 | let line_index = snap.analysis.file_line_index(position.file_id).ok()?; |
@@ -1603,7 +1601,8 @@ fn runnable_action_links( | |||
1603 | runnable: Runnable, | 1601 | runnable: Runnable, |
1604 | ) -> Option<lsp_ext::CommandLinkGroup> { | 1602 | ) -> Option<lsp_ext::CommandLinkGroup> { |
1605 | let cargo_spec = CargoTargetSpec::for_file(&snap, file_id).ok()?; | 1603 | let cargo_spec = CargoTargetSpec::for_file(&snap, file_id).ok()?; |
1606 | if !snap.config.hover.runnable() || should_skip_target(&runnable, cargo_spec.as_ref()) { | 1604 | let hover_config = snap.config.hover(); |
1605 | if !hover_config.runnable() || should_skip_target(&runnable, cargo_spec.as_ref()) { | ||
1607 | return None; | 1606 | return None; |
1608 | } | 1607 | } |
1609 | 1608 | ||
@@ -1611,12 +1610,12 @@ fn runnable_action_links( | |||
1611 | to_proto::runnable(snap, file_id, runnable).ok().map(|r| { | 1610 | to_proto::runnable(snap, file_id, runnable).ok().map(|r| { |
1612 | let mut group = lsp_ext::CommandLinkGroup::default(); | 1611 | let mut group = lsp_ext::CommandLinkGroup::default(); |
1613 | 1612 | ||
1614 | if snap.config.hover.run { | 1613 | if hover_config.run { |
1615 | let run_command = run_single_command(&r, action.run_title); | 1614 | let run_command = run_single_command(&r, action.run_title); |
1616 | group.commands.push(to_command_link(run_command, r.label.clone())); | 1615 | group.commands.push(to_command_link(run_command, r.label.clone())); |
1617 | } | 1616 | } |
1618 | 1617 | ||
1619 | if snap.config.hover.debug { | 1618 | if hover_config.debug { |
1620 | let dbg_command = debug_single_command(&r); | 1619 | let dbg_command = debug_single_command(&r); |
1621 | group.commands.push(to_command_link(dbg_command, r.label)); | 1620 | group.commands.push(to_command_link(dbg_command, r.label)); |
1622 | } | 1621 | } |
@@ -1629,7 +1628,7 @@ fn goto_type_action_links( | |||
1629 | snap: &GlobalStateSnapshot, | 1628 | snap: &GlobalStateSnapshot, |
1630 | nav_targets: &[HoverGotoTypeData], | 1629 | nav_targets: &[HoverGotoTypeData], |
1631 | ) -> Option<lsp_ext::CommandLinkGroup> { | 1630 | ) -> Option<lsp_ext::CommandLinkGroup> { |
1632 | if !snap.config.hover.goto_type_def || nav_targets.is_empty() { | 1631 | if !snap.config.hover().goto_type_def || nav_targets.is_empty() { |
1633 | return None; | 1632 | return None; |
1634 | } | 1633 | } |
1635 | 1634 | ||
@@ -1650,7 +1649,7 @@ fn prepare_hover_actions( | |||
1650 | file_id: FileId, | 1649 | file_id: FileId, |
1651 | actions: &[HoverAction], | 1650 | actions: &[HoverAction], |
1652 | ) -> Vec<lsp_ext::CommandLinkGroup> { | 1651 | ) -> Vec<lsp_ext::CommandLinkGroup> { |
1653 | if snap.config.hover.none() || !snap.config.hover_actions() { | 1652 | if snap.config.hover().none() || !snap.config.hover_actions() { |
1654 | return Vec::new(); | 1653 | return Vec::new(); |
1655 | } | 1654 | } |
1656 | 1655 | ||
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 8eca79f7e..53f9546b8 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs | |||
@@ -99,7 +99,8 @@ impl fmt::Debug for Event { | |||
99 | 99 | ||
100 | impl GlobalState { | 100 | impl GlobalState { |
101 | fn run(mut self, inbox: Receiver<lsp_server::Message>) -> Result<()> { | 101 | fn run(mut self, inbox: Receiver<lsp_server::Message>) -> Result<()> { |
102 | if self.config.linked_projects.is_empty() && self.config.notifications.cargo_toml_not_found | 102 | if self.config.linked_projects().is_empty() |
103 | && self.config.notifications().cargo_toml_not_found | ||
103 | { | 104 | { |
104 | self.show_message( | 105 | self.show_message( |
105 | lsp_types::MessageType::Error, | 106 | lsp_types::MessageType::Error, |
@@ -296,7 +297,7 @@ impl GlobalState { | |||
296 | flycheck::Message::AddDiagnostic { workspace_root, diagnostic } => { | 297 | flycheck::Message::AddDiagnostic { workspace_root, diagnostic } => { |
297 | let diagnostics = | 298 | let diagnostics = |
298 | crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp( | 299 | crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp( |
299 | &self.config.diagnostics_map, | 300 | &self.config.diagnostics_map(), |
300 | &diagnostic, | 301 | &diagnostic, |
301 | &workspace_root, | 302 | &workspace_root, |
302 | ); | 303 | ); |
@@ -365,13 +366,13 @@ impl GlobalState { | |||
365 | self.update_file_notifications_on_threadpool(); | 366 | self.update_file_notifications_on_threadpool(); |
366 | 367 | ||
367 | // Refresh semantic tokens if the client supports it. | 368 | // Refresh semantic tokens if the client supports it. |
368 | if self.config.semantic_tokens_refresh { | 369 | if self.config.semantic_tokens_refresh() { |
369 | self.semantic_tokens_cache.lock().clear(); | 370 | self.semantic_tokens_cache.lock().clear(); |
370 | self.send_request::<lsp_types::request::SemanticTokensRefesh>((), |_, _| ()); | 371 | self.send_request::<lsp_types::request::SemanticTokensRefesh>((), |_, _| ()); |
371 | } | 372 | } |
372 | 373 | ||
373 | // Refresh code lens if the client supports it. | 374 | // Refresh code lens if the client supports it. |
374 | if self.config.code_lens_refresh { | 375 | if self.config.code_lens_refresh() { |
375 | self.send_request::<lsp_types::request::CodeLensRefresh>((), |_, _| ()); | 376 | self.send_request::<lsp_types::request::CodeLensRefresh>((), |_, _| ()); |
376 | } | 377 | } |
377 | } | 378 | } |
@@ -658,7 +659,7 @@ impl GlobalState { | |||
658 | .collect::<Vec<_>>(); | 659 | .collect::<Vec<_>>(); |
659 | 660 | ||
660 | log::trace!("updating notifications for {:?}", subscriptions); | 661 | log::trace!("updating notifications for {:?}", subscriptions); |
661 | if self.config.publish_diagnostics { | 662 | if self.config.publish_diagnostics() { |
662 | let snapshot = self.snapshot(); | 663 | let snapshot = self.snapshot(); |
663 | self.task_pool.handle.spawn(move || { | 664 | self.task_pool.handle.spawn(move || { |
664 | let diagnostics = subscriptions | 665 | let diagnostics = subscriptions |
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index ce5cedeb3..51c24e966 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs | |||
@@ -19,12 +19,12 @@ impl GlobalState { | |||
19 | pub(crate) fn update_configuration(&mut self, config: Config) { | 19 | pub(crate) fn update_configuration(&mut self, config: Config) { |
20 | let _p = profile::span("GlobalState::update_configuration"); | 20 | let _p = profile::span("GlobalState::update_configuration"); |
21 | let old_config = mem::replace(&mut self.config, config); | 21 | let old_config = mem::replace(&mut self.config, config); |
22 | if self.config.lru_capacity != old_config.lru_capacity { | 22 | if self.config.lru_capacity() != old_config.lru_capacity() { |
23 | self.analysis_host.update_lru_capacity(old_config.lru_capacity); | 23 | self.analysis_host.update_lru_capacity(self.config.lru_capacity()); |
24 | } | 24 | } |
25 | if self.config.linked_projects != old_config.linked_projects { | 25 | if self.config.linked_projects() != old_config.linked_projects() { |
26 | self.fetch_workspaces() | 26 | self.fetch_workspaces() |
27 | } else if self.config.flycheck != old_config.flycheck { | 27 | } else if self.config.flycheck() != old_config.flycheck() { |
28 | self.reload_flycheck(); | 28 | self.reload_flycheck(); |
29 | } | 29 | } |
30 | } | 30 | } |
@@ -36,7 +36,7 @@ impl GlobalState { | |||
36 | Status::Loading | Status::NeedsReload => return, | 36 | Status::Loading | Status::NeedsReload => return, |
37 | Status::Ready | Status::Invalid => (), | 37 | Status::Ready | Status::Invalid => (), |
38 | } | 38 | } |
39 | if self.config.cargo_autoreload { | 39 | if self.config.cargo_autoreload() { |
40 | self.fetch_workspaces(); | 40 | self.fetch_workspaces(); |
41 | } else { | 41 | } else { |
42 | self.transition(Status::NeedsReload); | 42 | self.transition(Status::NeedsReload); |
@@ -94,8 +94,8 @@ impl GlobalState { | |||
94 | pub(crate) fn fetch_workspaces(&mut self) { | 94 | pub(crate) fn fetch_workspaces(&mut self) { |
95 | log::info!("will fetch workspaces"); | 95 | log::info!("will fetch workspaces"); |
96 | self.task_pool.handle.spawn({ | 96 | self.task_pool.handle.spawn({ |
97 | let linked_projects = self.config.linked_projects.clone(); | 97 | let linked_projects = self.config.linked_projects(); |
98 | let cargo_config = self.config.cargo.clone(); | 98 | let cargo_config = self.config.cargo(); |
99 | move || { | 99 | move || { |
100 | let workspaces = linked_projects | 100 | let workspaces = linked_projects |
101 | .iter() | 101 | .iter() |
@@ -143,7 +143,7 @@ impl GlobalState { | |||
143 | return; | 143 | return; |
144 | } | 144 | } |
145 | 145 | ||
146 | if let FilesWatcher::Client = self.config.files.watcher { | 146 | if let FilesWatcher::Client = self.config.files().watcher { |
147 | let registration_options = lsp_types::DidChangeWatchedFilesRegistrationOptions { | 147 | let registration_options = lsp_types::DidChangeWatchedFilesRegistrationOptions { |
148 | watchers: workspaces | 148 | watchers: workspaces |
149 | .iter() | 149 | .iter() |
@@ -170,9 +170,9 @@ impl GlobalState { | |||
170 | 170 | ||
171 | let project_folders = ProjectFolders::new(&workspaces); | 171 | let project_folders = ProjectFolders::new(&workspaces); |
172 | 172 | ||
173 | self.proc_macro_client = match &self.config.proc_macro_srv { | 173 | self.proc_macro_client = match self.config.proc_macro_srv() { |
174 | None => None, | 174 | None => None, |
175 | Some((path, args)) => match ProcMacroClient::extern_process(path.into(), args) { | 175 | Some((path, args)) => match ProcMacroClient::extern_process(path.clone(), args) { |
176 | Ok(it) => Some(it), | 176 | Ok(it) => Some(it), |
177 | Err(err) => { | 177 | Err(err) => { |
178 | log::error!( | 178 | log::error!( |
@@ -185,7 +185,7 @@ impl GlobalState { | |||
185 | }, | 185 | }, |
186 | }; | 186 | }; |
187 | 187 | ||
188 | let watch = match self.config.files.watcher { | 188 | let watch = match self.config.files().watcher { |
189 | FilesWatcher::Client => vec![], | 189 | FilesWatcher::Client => vec![], |
190 | FilesWatcher::Notify => project_folders.watch, | 190 | FilesWatcher::Notify => project_folders.watch, |
191 | }; | 191 | }; |
@@ -211,7 +211,7 @@ impl GlobalState { | |||
211 | }; | 211 | }; |
212 | for ws in workspaces.iter() { | 212 | for ws in workspaces.iter() { |
213 | crate_graph.extend(ws.to_crate_graph( | 213 | crate_graph.extend(ws.to_crate_graph( |
214 | self.config.cargo.target.as_deref(), | 214 | self.config.cargo().target.as_deref(), |
215 | self.proc_macro_client.as_ref(), | 215 | self.proc_macro_client.as_ref(), |
216 | &mut load, | 216 | &mut load, |
217 | )); | 217 | )); |
@@ -231,7 +231,7 @@ impl GlobalState { | |||
231 | } | 231 | } |
232 | 232 | ||
233 | fn reload_flycheck(&mut self) { | 233 | fn reload_flycheck(&mut self) { |
234 | let config = match self.config.flycheck.clone() { | 234 | let config = match self.config.flycheck() { |
235 | Some(it) => it, | 235 | Some(it) => it, |
236 | None => { | 236 | None => { |
237 | self.flycheck = Vec::new(); | 237 | self.flycheck = Vec::new(); |
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index e0413ec06..a5f7e3af7 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -818,7 +818,7 @@ pub(crate) fn runnable( | |||
818 | file_id: FileId, | 818 | file_id: FileId, |
819 | runnable: Runnable, | 819 | runnable: Runnable, |
820 | ) -> Result<lsp_ext::Runnable> { | 820 | ) -> Result<lsp_ext::Runnable> { |
821 | let config = &snap.config.runnables; | 821 | let config = snap.config.runnables(); |
822 | let spec = CargoTargetSpec::for_file(snap, file_id)?; | 822 | let spec = CargoTargetSpec::for_file(snap, file_id)?; |
823 | let workspace_root = spec.as_ref().map(|it| it.workspace_root.clone()); | 823 | let workspace_root = spec.as_ref().map(|it| it.workspace_root.clone()); |
824 | let target = spec.as_ref().map(|s| s.target.clone()); | 824 | let target = spec.as_ref().map(|s| s.target.clone()); |
@@ -833,9 +833,9 @@ pub(crate) fn runnable( | |||
833 | kind: lsp_ext::RunnableKind::Cargo, | 833 | kind: lsp_ext::RunnableKind::Cargo, |
834 | args: lsp_ext::CargoRunnable { | 834 | args: lsp_ext::CargoRunnable { |
835 | workspace_root: workspace_root.map(|it| it.into()), | 835 | workspace_root: workspace_root.map(|it| it.into()), |
836 | override_cargo: config.override_cargo.clone(), | 836 | override_cargo: config.override_cargo, |
837 | cargo_args, | 837 | cargo_args, |
838 | cargo_extra_args: config.cargo_extra_args.clone(), | 838 | cargo_extra_args: config.cargo_extra_args, |
839 | executable_args, | 839 | executable_args, |
840 | expect_test: None, | 840 | expect_test: None, |
841 | }, | 841 | }, |
diff --git a/crates/rust-analyzer/tests/rust-analyzer/main.rs b/crates/rust-analyzer/tests/rust-analyzer/main.rs index 84db0856d..38d09f3ee 100644 --- a/crates/rust-analyzer/tests/rust-analyzer/main.rs +++ b/crates/rust-analyzer/tests/rust-analyzer/main.rs | |||
@@ -13,6 +13,7 @@ mod support; | |||
13 | 13 | ||
14 | use std::{collections::HashMap, path::PathBuf, time::Instant}; | 14 | use std::{collections::HashMap, path::PathBuf, time::Instant}; |
15 | 15 | ||
16 | use expect_test::expect; | ||
16 | use lsp_types::{ | 17 | use lsp_types::{ |
17 | notification::DidOpenTextDocument, | 18 | notification::DidOpenTextDocument, |
18 | request::{CodeActionRequest, Completion, Formatting, GotoTypeDefinition, HoverRequest}, | 19 | request::{CodeActionRequest, Completion, Formatting, GotoTypeDefinition, HoverRequest}, |
@@ -569,9 +570,9 @@ fn main() { | |||
569 | } | 570 | } |
570 | "###, | 571 | "###, |
571 | ) | 572 | ) |
572 | .with_config(|config| { | 573 | .with_config(serde_json::json!({ |
573 | config.cargo.load_out_dirs_from_check = true; | 574 | "cargo": { "loadOutDirsFromCheck": true } |
574 | }) | 575 | })) |
575 | .server() | 576 | .server() |
576 | .wait_until_workspace_is_loaded(); | 577 | .wait_until_workspace_is_loaded(); |
577 | 578 | ||
@@ -712,12 +713,13 @@ pub fn foo(_input: TokenStream) -> TokenStream { | |||
712 | 713 | ||
713 | "###, | 714 | "###, |
714 | ) | 715 | ) |
715 | .with_config(|config| { | 716 | .with_config(serde_json::json!({ |
716 | let macro_srv_path = PathBuf::from(env!("CARGO_BIN_EXE_rust-analyzer")); | 717 | "cargo": { "loadOutDirsFromCheck": true }, |
717 | 718 | "procMacro": { | |
718 | config.cargo.load_out_dirs_from_check = true; | 719 | "enable": true, |
719 | config.proc_macro_srv = Some((macro_srv_path, vec!["proc-macro".into()])); | 720 | "server": PathBuf::from(env!("CARGO_BIN_EXE_rust-analyzer")), |
720 | }) | 721 | } |
722 | })) | ||
721 | .root("foo") | 723 | .root("foo") |
722 | .root("bar") | 724 | .root("bar") |
723 | .server() | 725 | .server() |
@@ -731,5 +733,5 @@ pub fn foo(_input: TokenStream) -> TokenStream { | |||
731 | work_done_progress_params: Default::default(), | 733 | work_done_progress_params: Default::default(), |
732 | }); | 734 | }); |
733 | let value = res.get("contents").unwrap().get("value").unwrap().to_string(); | 735 | let value = res.get("contents").unwrap().get("value").unwrap().to_string(); |
734 | assert_eq!(value, r#""\n```rust\nfoo::Bar\n```\n\n```rust\nfn bar()\n```""#) | 736 | expect![[r#""\n```rust\nfoo::Bar\n```\n\n```rust\nfn bar()\n```""#]].assert_eq(&value); |
735 | } | 737 | } |
diff --git a/crates/rust-analyzer/tests/rust-analyzer/support.rs b/crates/rust-analyzer/tests/rust-analyzer/support.rs index aac7dbcce..2658ee185 100644 --- a/crates/rust-analyzer/tests/rust-analyzer/support.rs +++ b/crates/rust-analyzer/tests/rust-analyzer/support.rs | |||
@@ -12,11 +12,8 @@ use lsp_types::{ | |||
12 | notification::Exit, request::Shutdown, TextDocumentIdentifier, Url, WorkDoneProgress, | 12 | notification::Exit, request::Shutdown, TextDocumentIdentifier, Url, WorkDoneProgress, |
13 | }; | 13 | }; |
14 | use lsp_types::{ProgressParams, ProgressParamsValue}; | 14 | use lsp_types::{ProgressParams, ProgressParamsValue}; |
15 | use project_model::{CargoConfig, ProjectManifest}; | 15 | use project_model::ProjectManifest; |
16 | use rust_analyzer::{ | 16 | use rust_analyzer::{config::Config, main_loop}; |
17 | config::{Config, FilesConfig, FilesWatcher, LinkedProject}, | ||
18 | main_loop, | ||
19 | }; | ||
20 | use serde::Serialize; | 17 | use serde::Serialize; |
21 | use serde_json::{to_string_pretty, Value}; | 18 | use serde_json::{to_string_pretty, Value}; |
22 | use test_utils::{find_mismatch, Fixture}; | 19 | use test_utils::{find_mismatch, Fixture}; |
@@ -29,12 +26,18 @@ pub(crate) struct Project<'a> { | |||
29 | with_sysroot: bool, | 26 | with_sysroot: bool, |
30 | tmp_dir: Option<TestDir>, | 27 | tmp_dir: Option<TestDir>, |
31 | roots: Vec<PathBuf>, | 28 | roots: Vec<PathBuf>, |
32 | config: Option<Box<dyn Fn(&mut Config)>>, | 29 | config: serde_json::Value, |
33 | } | 30 | } |
34 | 31 | ||
35 | impl<'a> Project<'a> { | 32 | impl<'a> Project<'a> { |
36 | pub(crate) fn with_fixture(fixture: &str) -> Project { | 33 | pub(crate) fn with_fixture(fixture: &str) -> Project { |
37 | Project { fixture, tmp_dir: None, roots: vec![], with_sysroot: false, config: None } | 34 | Project { |
35 | fixture, | ||
36 | tmp_dir: None, | ||
37 | roots: vec![], | ||
38 | with_sysroot: false, | ||
39 | config: serde_json::Value::Null, | ||
40 | } | ||
38 | } | 41 | } |
39 | 42 | ||
40 | pub(crate) fn tmp_dir(mut self, tmp_dir: TestDir) -> Project<'a> { | 43 | pub(crate) fn tmp_dir(mut self, tmp_dir: TestDir) -> Project<'a> { |
@@ -52,8 +55,8 @@ impl<'a> Project<'a> { | |||
52 | self | 55 | self |
53 | } | 56 | } |
54 | 57 | ||
55 | pub(crate) fn with_config(mut self, config: impl Fn(&mut Config) + 'static) -> Project<'a> { | 58 | pub(crate) fn with_config(mut self, config: serde_json::Value) -> Project<'a> { |
56 | self.config = Some(Box::new(config)); | 59 | self.config = config; |
57 | self | 60 | self |
58 | } | 61 | } |
59 | 62 | ||
@@ -77,14 +80,14 @@ impl<'a> Project<'a> { | |||
77 | if roots.is_empty() { | 80 | if roots.is_empty() { |
78 | roots.push(tmp_dir_path.clone()); | 81 | roots.push(tmp_dir_path.clone()); |
79 | } | 82 | } |
80 | let linked_projects = roots | 83 | let discovered_projects = roots |
81 | .into_iter() | 84 | .into_iter() |
82 | .map(|it| ProjectManifest::discover_single(&it).unwrap()) | 85 | .map(|it| ProjectManifest::discover_single(&it).unwrap()) |
83 | .map(LinkedProject::from) | ||
84 | .collect::<Vec<_>>(); | 86 | .collect::<Vec<_>>(); |
85 | 87 | ||
86 | let mut config = Config { | 88 | let mut config = Config::new( |
87 | caps: lsp_types::ClientCapabilities { | 89 | tmp_dir_path, |
90 | lsp_types::ClientCapabilities { | ||
88 | text_document: Some(lsp_types::TextDocumentClientCapabilities { | 91 | text_document: Some(lsp_types::TextDocumentClientCapabilities { |
89 | definition: Some(lsp_types::GotoCapability { | 92 | definition: Some(lsp_types::GotoCapability { |
90 | link_support: Some(true), | 93 | link_support: Some(true), |
@@ -96,6 +99,10 @@ impl<'a> Project<'a> { | |||
96 | ), | 99 | ), |
97 | ..Default::default() | 100 | ..Default::default() |
98 | }), | 101 | }), |
102 | hover: Some(lsp_types::HoverClientCapabilities { | ||
103 | content_format: Some(vec![lsp_types::MarkupKind::Markdown]), | ||
104 | ..Default::default() | ||
105 | }), | ||
99 | ..Default::default() | 106 | ..Default::default() |
100 | }), | 107 | }), |
101 | window: Some(lsp_types::WindowClientCapabilities { | 108 | window: Some(lsp_types::WindowClientCapabilities { |
@@ -104,14 +111,9 @@ impl<'a> Project<'a> { | |||
104 | }), | 111 | }), |
105 | ..Default::default() | 112 | ..Default::default() |
106 | }, | 113 | }, |
107 | cargo: CargoConfig { no_sysroot: !self.with_sysroot, ..Default::default() }, | 114 | ); |
108 | linked_projects, | 115 | config.discovered_projects = Some(discovered_projects); |
109 | files: FilesConfig { watcher: FilesWatcher::Client, exclude: Vec::new() }, | 116 | config.update(self.config); |
110 | ..Config::new(tmp_dir_path) | ||
111 | }; | ||
112 | if let Some(f) = &self.config { | ||
113 | f(&mut config) | ||
114 | } | ||
115 | 117 | ||
116 | Server::new(tmp_dir, config) | 118 | Server::new(tmp_dir, config) |
117 | } | 119 | } |