diff options
-rw-r--r-- | crates/ra_flycheck/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_project_model/src/cargo_workspace.rs | 19 | ||||
-rw-r--r-- | crates/ra_project_model/src/lib.rs | 6 | ||||
-rw-r--r-- | crates/rust-analyzer/src/bin/main.rs | 31 | ||||
-rw-r--r-- | crates/rust-analyzer/src/cli/load_cargo.rs | 4 | ||||
-rw-r--r-- | crates/rust-analyzer/src/config.rs | 252 | ||||
-rw-r--r-- | crates/rust-analyzer/src/conv.rs | 2 | ||||
-rw-r--r-- | crates/rust-analyzer/src/feature_flags.rs | 77 | ||||
-rw-r--r-- | crates/rust-analyzer/src/lib.rs | 4 | ||||
-rw-r--r-- | crates/rust-analyzer/src/main_loop.rs | 79 | ||||
-rw-r--r-- | crates/rust-analyzer/src/main_loop/handlers.rs | 18 | ||||
-rw-r--r-- | crates/rust-analyzer/src/world.rs | 32 | ||||
-rw-r--r-- | crates/rust-analyzer/tests/heavy_tests/main.rs | 2 | ||||
-rw-r--r-- | crates/rust-analyzer/tests/heavy_tests/support.rs | 42 |
14 files changed, 196 insertions, 374 deletions
diff --git a/crates/ra_flycheck/src/lib.rs b/crates/ra_flycheck/src/lib.rs index 13494a731..b54a30ab8 100644 --- a/crates/ra_flycheck/src/lib.rs +++ b/crates/ra_flycheck/src/lib.rs | |||
@@ -22,7 +22,7 @@ use crate::conv::{map_rust_diagnostic_to_lsp, MappedRustDiagnostic}; | |||
22 | 22 | ||
23 | pub use crate::conv::url_from_path_with_drive_lowercasing; | 23 | pub use crate::conv::url_from_path_with_drive_lowercasing; |
24 | 24 | ||
25 | #[derive(Clone, Debug)] | 25 | #[derive(Clone, Debug, PartialEq, Eq)] |
26 | pub enum FlycheckConfig { | 26 | pub enum FlycheckConfig { |
27 | CargoCommand { command: String, all_targets: bool, extra_args: Vec<String> }, | 27 | CargoCommand { command: String, all_targets: bool, extra_args: Vec<String> }, |
28 | CustomCommand { command: String, args: Vec<String> }, | 28 | CustomCommand { command: String, args: Vec<String> }, |
diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs index f4fd6ad28..c1b6e1ddc 100644 --- a/crates/ra_project_model/src/cargo_workspace.rs +++ b/crates/ra_project_model/src/cargo_workspace.rs | |||
@@ -13,7 +13,6 @@ use cargo_metadata::{BuildScript, CargoOpt, Message, MetadataCommand, PackageId} | |||
13 | use ra_arena::{Arena, Idx}; | 13 | use ra_arena::{Arena, Idx}; |
14 | use ra_db::Edition; | 14 | use ra_db::Edition; |
15 | use rustc_hash::FxHashMap; | 15 | use rustc_hash::FxHashMap; |
16 | use serde::Deserialize; | ||
17 | 16 | ||
18 | /// `CargoWorkspace` represents the logical structure of, well, a Cargo | 17 | /// `CargoWorkspace` represents the logical structure of, well, a Cargo |
19 | /// workspace. It pretty closely mirrors `cargo metadata` output. | 18 | /// workspace. It pretty closely mirrors `cargo metadata` output. |
@@ -43,9 +42,8 @@ impl ops::Index<Target> for CargoWorkspace { | |||
43 | } | 42 | } |
44 | } | 43 | } |
45 | 44 | ||
46 | #[derive(Deserialize, Clone, Debug, PartialEq, Eq)] | 45 | #[derive(Clone, Debug, PartialEq, Eq)] |
47 | #[serde(rename_all = "camelCase", default)] | 46 | pub struct CargoConfig { |
48 | pub struct CargoFeatures { | ||
49 | /// Do not activate the `default` feature. | 47 | /// Do not activate the `default` feature. |
50 | pub no_default_features: bool, | 48 | pub no_default_features: bool, |
51 | 49 | ||
@@ -60,9 +58,9 @@ pub struct CargoFeatures { | |||
60 | pub load_out_dirs_from_check: bool, | 58 | pub load_out_dirs_from_check: bool, |
61 | } | 59 | } |
62 | 60 | ||
63 | impl Default for CargoFeatures { | 61 | impl Default for CargoConfig { |
64 | fn default() -> Self { | 62 | fn default() -> Self { |
65 | CargoFeatures { | 63 | CargoConfig { |
66 | no_default_features: false, | 64 | no_default_features: false, |
67 | all_features: true, | 65 | all_features: true, |
68 | features: Vec::new(), | 66 | features: Vec::new(), |
@@ -141,7 +139,7 @@ impl PackageData { | |||
141 | impl CargoWorkspace { | 139 | impl CargoWorkspace { |
142 | pub fn from_cargo_metadata( | 140 | pub fn from_cargo_metadata( |
143 | cargo_toml: &Path, | 141 | cargo_toml: &Path, |
144 | cargo_features: &CargoFeatures, | 142 | cargo_features: &CargoConfig, |
145 | ) -> Result<CargoWorkspace> { | 143 | ) -> Result<CargoWorkspace> { |
146 | let mut meta = MetadataCommand::new(); | 144 | let mut meta = MetadataCommand::new(); |
147 | meta.manifest_path(cargo_toml); | 145 | meta.manifest_path(cargo_toml); |
@@ -275,7 +273,7 @@ pub struct ExternResources { | |||
275 | 273 | ||
276 | pub fn load_extern_resources( | 274 | pub fn load_extern_resources( |
277 | cargo_toml: &Path, | 275 | cargo_toml: &Path, |
278 | cargo_features: &CargoFeatures, | 276 | cargo_features: &CargoConfig, |
279 | ) -> Result<ExternResources> { | 277 | ) -> Result<ExternResources> { |
280 | let mut cmd = Command::new(cargo_binary()); | 278 | let mut cmd = Command::new(cargo_binary()); |
281 | cmd.args(&["check", "--message-format=json", "--manifest-path"]).arg(cargo_toml); | 279 | cmd.args(&["check", "--message-format=json", "--manifest-path"]).arg(cargo_toml); |
@@ -293,9 +291,8 @@ pub fn load_extern_resources( | |||
293 | 291 | ||
294 | let mut res = ExternResources::default(); | 292 | let mut res = ExternResources::default(); |
295 | 293 | ||
296 | let stdout = String::from_utf8(output.stdout)?; | 294 | for message in cargo_metadata::parse_messages(output.stdout.as_slice()) { |
297 | for line in stdout.lines() { | 295 | if let Ok(message) = message { |
298 | if let Ok(message) = serde_json::from_str::<cargo_metadata::Message>(&line) { | ||
299 | match message { | 296 | match message { |
300 | Message::BuildScriptExecuted(BuildScript { package_id, out_dir, .. }) => { | 297 | Message::BuildScriptExecuted(BuildScript { package_id, out_dir, .. }) => { |
301 | res.out_dirs.insert(package_id, out_dir); | 298 | res.out_dirs.insert(package_id, out_dir); |
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index 444d3bb3f..dd9c80691 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs | |||
@@ -19,7 +19,7 @@ use rustc_hash::FxHashMap; | |||
19 | use serde_json::from_reader; | 19 | use serde_json::from_reader; |
20 | 20 | ||
21 | pub use crate::{ | 21 | pub use crate::{ |
22 | cargo_workspace::{CargoFeatures, CargoWorkspace, Package, Target, TargetKind}, | 22 | cargo_workspace::{CargoConfig, CargoWorkspace, Package, Target, TargetKind}, |
23 | json_project::JsonProject, | 23 | json_project::JsonProject, |
24 | sysroot::Sysroot, | 24 | sysroot::Sysroot, |
25 | }; | 25 | }; |
@@ -78,14 +78,14 @@ impl PackageRoot { | |||
78 | } | 78 | } |
79 | 79 | ||
80 | impl ProjectWorkspace { | 80 | impl ProjectWorkspace { |
81 | pub fn discover(path: &Path, cargo_features: &CargoFeatures) -> Result<ProjectWorkspace> { | 81 | pub fn discover(path: &Path, cargo_features: &CargoConfig) -> Result<ProjectWorkspace> { |
82 | ProjectWorkspace::discover_with_sysroot(path, true, cargo_features) | 82 | ProjectWorkspace::discover_with_sysroot(path, true, cargo_features) |
83 | } | 83 | } |
84 | 84 | ||
85 | pub fn discover_with_sysroot( | 85 | pub fn discover_with_sysroot( |
86 | path: &Path, | 86 | path: &Path, |
87 | with_sysroot: bool, | 87 | with_sysroot: bool, |
88 | cargo_features: &CargoFeatures, | 88 | cargo_features: &CargoConfig, |
89 | ) -> Result<ProjectWorkspace> { | 89 | ) -> Result<ProjectWorkspace> { |
90 | match find_rust_project_json(path) { | 90 | match find_rust_project_json(path) { |
91 | Some(json_path) => { | 91 | Some(json_path) => { |
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs index a744a6695..608f4f67b 100644 --- a/crates/rust-analyzer/src/bin/main.rs +++ b/crates/rust-analyzer/src/bin/main.rs | |||
@@ -4,8 +4,7 @@ | |||
4 | mod args; | 4 | mod args; |
5 | 5 | ||
6 | use lsp_server::Connection; | 6 | use lsp_server::Connection; |
7 | 7 | use rust_analyzer::{cli, config::Config, from_json, Result}; | |
8 | use rust_analyzer::{cli, from_json, show_message, Result, ServerConfig}; | ||
9 | 8 | ||
10 | use crate::args::HelpPrinted; | 9 | use crate::args::HelpPrinted; |
11 | 10 | ||
@@ -78,24 +77,18 @@ fn run_server() -> Result<()> { | |||
78 | .filter(|workspaces| !workspaces.is_empty()) | 77 | .filter(|workspaces| !workspaces.is_empty()) |
79 | .unwrap_or_else(|| vec![root]); | 78 | .unwrap_or_else(|| vec![root]); |
80 | 79 | ||
81 | let server_config = initialize_params | 80 | let config = { |
82 | .initialization_options | 81 | let mut config = Config::default(); |
83 | .and_then(|v| { | 82 | if let Some(value) = &initialize_params.initialization_options { |
84 | from_json::<ServerConfig>("config", v) | 83 | config.update(value); |
85 | .map_err(|e| { | 84 | } |
86 | log::error!("{}", e); | 85 | if let Some(caps) = &initialize_params.capabilities.text_document { |
87 | show_message(lsp_types::MessageType::Error, e.to_string(), &connection.sender); | 86 | config.update_caps(caps); |
88 | }) | 87 | } |
89 | .ok() | 88 | config |
90 | }) | 89 | }; |
91 | .unwrap_or_default(); | ||
92 | 90 | ||
93 | rust_analyzer::main_loop( | 91 | rust_analyzer::main_loop(workspace_roots, config, connection)?; |
94 | workspace_roots, | ||
95 | initialize_params.capabilities, | ||
96 | server_config, | ||
97 | connection, | ||
98 | )?; | ||
99 | 92 | ||
100 | log::info!("shutting down IO..."); | 93 | log::info!("shutting down IO..."); |
101 | io_threads.join()?; | 94 | io_threads.join()?; |
diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs index 832f04226..2c0bde920 100644 --- a/crates/rust-analyzer/src/cli/load_cargo.rs +++ b/crates/rust-analyzer/src/cli/load_cargo.rs | |||
@@ -8,7 +8,7 @@ use crossbeam_channel::{unbounded, Receiver}; | |||
8 | use ra_db::{ExternSourceId, FileId, SourceRootId}; | 8 | use ra_db::{ExternSourceId, FileId, SourceRootId}; |
9 | use ra_ide::{AnalysisChange, AnalysisHost}; | 9 | use ra_ide::{AnalysisChange, AnalysisHost}; |
10 | use ra_project_model::{ | 10 | use ra_project_model::{ |
11 | get_rustc_cfg_options, CargoFeatures, PackageRoot, ProcMacroClient, ProjectWorkspace, | 11 | get_rustc_cfg_options, CargoConfig, PackageRoot, ProcMacroClient, ProjectWorkspace, |
12 | }; | 12 | }; |
13 | use ra_vfs::{RootEntry, Vfs, VfsChange, VfsTask, Watch}; | 13 | use ra_vfs::{RootEntry, Vfs, VfsChange, VfsTask, Watch}; |
14 | use rustc_hash::{FxHashMap, FxHashSet}; | 14 | use rustc_hash::{FxHashMap, FxHashSet}; |
@@ -29,7 +29,7 @@ pub(crate) fn load_cargo( | |||
29 | let root = std::env::current_dir()?.join(root); | 29 | let root = std::env::current_dir()?.join(root); |
30 | let ws = ProjectWorkspace::discover( | 30 | let ws = ProjectWorkspace::discover( |
31 | root.as_ref(), | 31 | root.as_ref(), |
32 | &CargoFeatures { load_out_dirs_from_check, ..Default::default() }, | 32 | &CargoConfig { load_out_dirs_from_check, ..Default::default() }, |
33 | )?; | 33 | )?; |
34 | 34 | ||
35 | let mut extern_dirs = FxHashSet::default(); | 35 | let mut extern_dirs = FxHashSet::default(); |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index fb7895ce0..3c8f55f1e 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -7,24 +7,36 @@ | |||
7 | //! configure the server itself, feature flags are passed into analysis, and | 7 | //! configure the server itself, feature flags are passed into analysis, and |
8 | //! tweak things like automatic insertion of `()` in completions. | 8 | //! tweak things like automatic insertion of `()` in completions. |
9 | 9 | ||
10 | use rustc_hash::FxHashMap; | ||
11 | |||
12 | use lsp_types::TextDocumentClientCapabilities; | 10 | use lsp_types::TextDocumentClientCapabilities; |
13 | use ra_flycheck::FlycheckConfig; | 11 | use ra_flycheck::FlycheckConfig; |
14 | use ra_ide::InlayHintsConfig; | 12 | use ra_ide::{CompletionConfig, InlayHintsConfig}; |
15 | use ra_project_model::CargoFeatures; | 13 | use ra_project_model::CargoConfig; |
16 | use serde::{Deserialize, Deserializer}; | 14 | use serde::Deserialize; |
17 | 15 | ||
18 | #[derive(Debug, Clone)] | 16 | #[derive(Debug, Clone)] |
19 | pub struct Config { | 17 | pub struct Config { |
18 | pub client_caps: ClientCapsConfig, | ||
20 | pub publish_decorations: bool, | 19 | pub publish_decorations: bool, |
21 | pub supports_location_link: bool, | 20 | pub publish_diagnostics: bool, |
22 | pub line_folding_only: bool, | 21 | pub notifications: NotificationsConfig, |
23 | pub inlay_hints: InlayHintsConfig, | 22 | pub inlay_hints: InlayHintsConfig, |
23 | pub completion: CompletionConfig, | ||
24 | pub call_info_full: bool, | ||
24 | pub rustfmt: RustfmtConfig, | 25 | pub rustfmt: RustfmtConfig, |
25 | pub check: Option<FlycheckConfig>, | 26 | pub check: Option<FlycheckConfig>, |
26 | pub vscode_lldb: bool, | 27 | pub vscode_lldb: bool, |
27 | pub proc_macro_srv: Option<String>, | 28 | pub proc_macro_srv: Option<String>, |
29 | pub lru_capacity: Option<usize>, | ||
30 | pub use_client_watching: bool, | ||
31 | pub exclude_globs: Vec<String>, | ||
32 | pub cargo: CargoConfig, | ||
33 | pub with_sysroot: bool, | ||
34 | } | ||
35 | |||
36 | #[derive(Debug, Clone)] | ||
37 | pub struct NotificationsConfig { | ||
38 | pub workspace_loaded: bool, | ||
39 | pub cargo_toml_not_found: bool, | ||
28 | } | 40 | } |
29 | 41 | ||
30 | #[derive(Debug, Clone)] | 42 | #[derive(Debug, Clone)] |
@@ -39,148 +51,120 @@ pub enum RustfmtConfig { | |||
39 | }, | 51 | }, |
40 | } | 52 | } |
41 | 53 | ||
42 | impl Default for RustfmtConfig { | 54 | #[derive(Debug, Clone, Default)] |
43 | fn default() -> Self { | 55 | pub struct ClientCapsConfig { |
44 | RustfmtConfig::Rustfmt { extra_args: Vec::new() } | 56 | pub location_link: bool, |
45 | } | 57 | pub line_folding_only: bool, |
46 | } | 58 | } |
47 | 59 | ||
48 | pub(crate) fn get_config( | 60 | impl Default for Config { |
49 | config: &ServerConfig, | 61 | fn default() -> Self { |
50 | text_document_caps: Option<&TextDocumentClientCapabilities>, | 62 | Config { |
51 | ) -> Config { | 63 | publish_decorations: false, |
52 | Config { | 64 | publish_diagnostics: true, |
53 | publish_decorations: config.publish_decorations, | 65 | notifications: NotificationsConfig { |
54 | supports_location_link: text_document_caps | 66 | workspace_loaded: true, |
55 | .and_then(|it| it.definition) | 67 | cargo_toml_not_found: true, |
56 | .and_then(|it| it.link_support) | 68 | }, |
57 | .unwrap_or(false), | 69 | client_caps: ClientCapsConfig::default(), |
58 | line_folding_only: text_document_caps | 70 | inlay_hints: InlayHintsConfig { |
59 | .and_then(|it| it.folding_range.as_ref()) | 71 | type_hints: true, |
60 | .and_then(|it| it.line_folding_only) | 72 | parameter_hints: true, |
61 | .unwrap_or(false), | 73 | chaining_hints: true, |
62 | inlay_hints: InlayHintsConfig { | 74 | max_length: None, |
63 | type_hints: config.inlay_hints_type, | 75 | }, |
64 | parameter_hints: config.inlay_hints_parameter, | 76 | completion: CompletionConfig { |
65 | chaining_hints: config.inlay_hints_chaining, | 77 | enable_postfix_completions: true, |
66 | max_length: config.inlay_hints_max_length, | 78 | add_call_parenthesis: true, |
67 | }, | 79 | add_call_argument_snippets: true, |
68 | check: if config.cargo_watch_enable { | 80 | }, |
69 | Some(FlycheckConfig::CargoCommand { | 81 | call_info_full: true, |
70 | command: config.cargo_watch_command.clone(), | 82 | rustfmt: RustfmtConfig::Rustfmt { extra_args: Vec::new() }, |
71 | all_targets: config.cargo_watch_all_targets, | 83 | check: Some(FlycheckConfig::CargoCommand { |
72 | extra_args: config.cargo_watch_args.clone(), | 84 | command: "check".to_string(), |
73 | }) | 85 | all_targets: true, |
74 | } else { | 86 | extra_args: Vec::new(), |
75 | None | 87 | }), |
76 | }, | 88 | vscode_lldb: false, |
77 | rustfmt: RustfmtConfig::Rustfmt { extra_args: config.rustfmt_args.clone() }, | 89 | proc_macro_srv: None, |
78 | vscode_lldb: config.vscode_lldb, | 90 | lru_capacity: None, |
79 | proc_macro_srv: None, // FIXME: get this from config | 91 | use_client_watching: false, |
92 | exclude_globs: Vec::new(), | ||
93 | cargo: CargoConfig::default(), | ||
94 | with_sysroot: true, | ||
95 | } | ||
80 | } | 96 | } |
81 | } | 97 | } |
82 | 98 | ||
83 | /// Client provided initialization options | 99 | impl Config { |
84 | #[derive(Deserialize, Clone, Debug, PartialEq, Eq)] | 100 | #[rustfmt::skip] |
85 | #[serde(rename_all = "camelCase", default)] | 101 | pub fn update(&mut self, value: &serde_json::Value) { |
86 | pub struct ServerConfig { | 102 | log::info!("Config::update({:#})", value); |
87 | /// Whether the client supports our custom highlighting publishing decorations. | ||
88 | /// This is different to the highlightingOn setting, which is whether the user | ||
89 | /// wants our custom highlighting to be used. | ||
90 | /// | ||
91 | /// Defaults to `false` | ||
92 | #[serde(deserialize_with = "nullable_bool_false")] | ||
93 | pub publish_decorations: bool, | ||
94 | 103 | ||
95 | pub exclude_globs: Vec<String>, | 104 | let client_caps = self.client_caps.clone(); |
96 | #[serde(deserialize_with = "nullable_bool_false")] | 105 | *self = Default::default(); |
97 | pub use_client_watching: bool, | 106 | self.client_caps = client_caps; |
98 | 107 | ||
99 | pub lru_capacity: Option<usize>, | 108 | set(value, "/publishDecorations", &mut self.publish_decorations); |
109 | set(value, "/excludeGlobs", &mut self.exclude_globs); | ||
110 | set(value, "/useClientWatching", &mut self.use_client_watching); | ||
111 | set(value, "/lruCapacity", &mut self.lru_capacity); | ||
100 | 112 | ||
101 | #[serde(deserialize_with = "nullable_bool_true")] | 113 | set(value, "/inlayHintsType", &mut self.inlay_hints.type_hints); |
102 | pub inlay_hints_type: bool, | 114 | set(value, "/inlayHintsParameter", &mut self.inlay_hints.parameter_hints); |
103 | #[serde(deserialize_with = "nullable_bool_true")] | 115 | set(value, "/inlayHintsChaining", &mut self.inlay_hints.chaining_hints); |
104 | pub inlay_hints_parameter: bool, | 116 | set(value, "/inlayHintsMaxLength", &mut self.inlay_hints.max_length); |
105 | #[serde(deserialize_with = "nullable_bool_true")] | ||
106 | pub inlay_hints_chaining: bool, | ||
107 | pub inlay_hints_max_length: Option<usize>, | ||
108 | |||
109 | pub cargo_watch_enable: bool, | ||
110 | pub cargo_watch_args: Vec<String>, | ||
111 | pub cargo_watch_command: String, | ||
112 | pub cargo_watch_all_targets: bool, | ||
113 | |||
114 | /// For internal usage to make integrated tests faster. | ||
115 | #[serde(deserialize_with = "nullable_bool_true")] | ||
116 | pub with_sysroot: bool, | ||
117 | 117 | ||
118 | /// Fine grained feature flags to disable specific features. | 118 | if let Some(false) = get(value, "cargo_watch_enable") { |
119 | pub feature_flags: FxHashMap<String, bool>, | 119 | self.check = None |
120 | } else { | ||
121 | if let Some(FlycheckConfig::CargoCommand { command, extra_args, all_targets }) = &mut self.check | ||
122 | { | ||
123 | set(value, "/cargoWatchArgs", extra_args); | ||
124 | set(value, "/cargoWatchCommand", command); | ||
125 | set(value, "/cargoWatchAllTargets", all_targets); | ||
126 | } | ||
127 | }; | ||
128 | |||
129 | set(value, "/withSysroot", &mut self.with_sysroot); | ||
130 | if let RustfmtConfig::Rustfmt { extra_args } = &mut self.rustfmt { | ||
131 | set(value, "/rustfmtArgs", extra_args); | ||
132 | } | ||
120 | 133 | ||
121 | pub rustfmt_args: Vec<String>, | 134 | set(value, "/cargoFeatures/noDefaultFeatures", &mut self.cargo.no_default_features); |
135 | set(value, "/cargoFeatures/allFeatures", &mut self.cargo.all_features); | ||
136 | set(value, "/cargoFeatures/features", &mut self.cargo.features); | ||
137 | set(value, "/cargoFeatures/loadOutDirsFromCheck", &mut self.cargo.load_out_dirs_from_check); | ||
122 | 138 | ||
123 | /// Cargo feature configurations. | 139 | set(value, "/vscodeLldb", &mut self.vscode_lldb); |
124 | pub cargo_features: CargoFeatures, | ||
125 | 140 | ||
126 | /// Enabled if the vscode_lldb extension is available. | 141 | set(value, "/featureFlags/lsp.diagnostics", &mut self.publish_diagnostics); |
127 | pub vscode_lldb: bool, | 142 | set(value, "/featureFlags/notifications.workspace-loaded", &mut self.notifications.workspace_loaded); |
128 | } | 143 | set(value, "/featureFlags/notifications.cargo-toml-not-found", &mut self.notifications.cargo_toml_not_found); |
144 | set(value, "/featureFlags/completion.enable-postfix", &mut self.completion.enable_postfix_completions); | ||
145 | set(value, "/featureFlags/completion.insertion.add-call-parenthesis", &mut self.completion.add_call_parenthesis); | ||
146 | set(value, "/featureFlags/completion.insertion.add-argument-snippets", &mut self.completion.add_call_argument_snippets); | ||
147 | set(value, "/featureFlags/call-info.full", &mut self.call_info_full); | ||
129 | 148 | ||
130 | impl Default for ServerConfig { | 149 | log::info!("Config::update() = {:#?}", self); |
131 | fn default() -> ServerConfig { | ||
132 | ServerConfig { | ||
133 | publish_decorations: false, | ||
134 | exclude_globs: Vec::new(), | ||
135 | use_client_watching: false, | ||
136 | lru_capacity: None, | ||
137 | inlay_hints_type: true, | ||
138 | inlay_hints_parameter: true, | ||
139 | inlay_hints_chaining: true, | ||
140 | inlay_hints_max_length: None, | ||
141 | cargo_watch_enable: true, | ||
142 | cargo_watch_args: Vec::new(), | ||
143 | cargo_watch_command: "check".to_string(), | ||
144 | cargo_watch_all_targets: true, | ||
145 | with_sysroot: true, | ||
146 | feature_flags: FxHashMap::default(), | ||
147 | cargo_features: Default::default(), | ||
148 | rustfmt_args: Vec::new(), | ||
149 | vscode_lldb: false, | ||
150 | } | ||
151 | } | ||
152 | } | ||
153 | 150 | ||
154 | /// Deserializes a null value to a bool false by default | 151 | fn get<'a, T: Deserialize<'a>>(value: &'a serde_json::Value, pointer: &str) -> Option<T> { |
155 | fn nullable_bool_false<'de, D>(deserializer: D) -> Result<bool, D::Error> | 152 | value.pointer(pointer).and_then(|it| T::deserialize(it).ok()) |
156 | where | 153 | } |
157 | D: Deserializer<'de>, | ||
158 | { | ||
159 | let opt = Option::deserialize(deserializer)?; | ||
160 | Ok(opt.unwrap_or(false)) | ||
161 | } | ||
162 | 154 | ||
163 | /// Deserializes a null value to a bool true by default | 155 | fn set<'a, T: Deserialize<'a> + std::fmt::Debug>(value: &'a serde_json::Value, pointer: &str, slot: &mut T) { |
164 | fn nullable_bool_true<'de, D>(deserializer: D) -> Result<bool, D::Error> | 156 | if let Some(new_value) = get(value, pointer) { |
165 | where | 157 | *slot = new_value |
166 | D: Deserializer<'de>, | 158 | } |
167 | { | 159 | } |
168 | let opt = Option::deserialize(deserializer)?; | 160 | } |
169 | Ok(opt.unwrap_or(true)) | ||
170 | } | ||
171 | 161 | ||
172 | #[cfg(test)] | 162 | pub fn update_caps(&mut self, caps: &TextDocumentClientCapabilities) { |
173 | mod test { | 163 | if let Some(value) = caps.definition.as_ref().and_then(|it| it.link_support) { |
174 | use super::*; | 164 | self.client_caps.location_link = value; |
175 | 165 | } | |
176 | #[test] | 166 | if let Some(value) = caps.folding_range.as_ref().and_then(|it| it.line_folding_only) { |
177 | fn deserialize_init_options_defaults() { | 167 | self.client_caps.line_folding_only = value |
178 | // check that null == default for both fields | 168 | } |
179 | let default = ServerConfig::default(); | ||
180 | assert_eq!(default, serde_json::from_str(r#"{}"#).unwrap()); | ||
181 | assert_eq!( | ||
182 | default, | ||
183 | serde_json::from_str(r#"{"publishDecorations":null, "lruCapacity":null}"#).unwrap() | ||
184 | ); | ||
185 | } | 169 | } |
186 | } | 170 | } |
diff --git a/crates/rust-analyzer/src/conv.rs b/crates/rust-analyzer/src/conv.rs index e8dc953c3..57c4c8ce5 100644 --- a/crates/rust-analyzer/src/conv.rs +++ b/crates/rust-analyzer/src/conv.rs | |||
@@ -579,7 +579,7 @@ impl TryConvWith<&WorldSnapshot> for (FileId, RangeInfo<Vec<NavigationTarget>>) | |||
579 | .into_iter() | 579 | .into_iter() |
580 | .map(|nav| (file_id, RangeInfo::new(range, nav))) | 580 | .map(|nav| (file_id, RangeInfo::new(range, nav))) |
581 | .try_conv_with_to_vec(world)?; | 581 | .try_conv_with_to_vec(world)?; |
582 | if world.config.supports_location_link { | 582 | if world.config.client_caps.location_link { |
583 | Ok(links.into()) | 583 | Ok(links.into()) |
584 | } else { | 584 | } else { |
585 | let locations: Vec<Location> = links | 585 | let locations: Vec<Location> = links |
diff --git a/crates/rust-analyzer/src/feature_flags.rs b/crates/rust-analyzer/src/feature_flags.rs deleted file mode 100644 index dbb3f50a0..000000000 --- a/crates/rust-analyzer/src/feature_flags.rs +++ /dev/null | |||
@@ -1,77 +0,0 @@ | |||
1 | //! See docs for `FeatureFlags`. | ||
2 | |||
3 | use rustc_hash::FxHashMap; | ||
4 | |||
5 | // FIXME: looks like a much better design is to pass options to each call, | ||
6 | // rather than to have a global ambient feature flags -- that way, the clients | ||
7 | // can issue two successive calls with different options. | ||
8 | |||
9 | /// Feature flags hold fine-grained toggles for all *user-visible* features of | ||
10 | /// rust-analyzer. | ||
11 | /// | ||
12 | /// The exists such that users are able to disable any annoying feature (and, | ||
13 | /// with many users and many features, some features are bound to be annoying | ||
14 | /// for some users) | ||
15 | /// | ||
16 | /// Note that we purposefully use run-time checked strings, and not something | ||
17 | /// checked at compile time, to keep things simple and flexible. | ||
18 | /// | ||
19 | /// Also note that, at the moment, `FeatureFlags` also store features for | ||
20 | /// `rust-analyzer`. This should be benign layering violation. | ||
21 | #[derive(Debug)] | ||
22 | pub struct FeatureFlags { | ||
23 | flags: FxHashMap<String, bool>, | ||
24 | } | ||
25 | |||
26 | impl FeatureFlags { | ||
27 | fn new(flags: &[(&str, bool)]) -> FeatureFlags { | ||
28 | let flags = flags | ||
29 | .iter() | ||
30 | .map(|&(name, value)| { | ||
31 | check_flag_name(name); | ||
32 | (name.to_string(), value) | ||
33 | }) | ||
34 | .collect(); | ||
35 | FeatureFlags { flags } | ||
36 | } | ||
37 | |||
38 | pub fn set(&mut self, flag: &str, value: bool) -> Result<(), ()> { | ||
39 | match self.flags.get_mut(flag) { | ||
40 | None => Err(()), | ||
41 | Some(slot) => { | ||
42 | *slot = value; | ||
43 | Ok(()) | ||
44 | } | ||
45 | } | ||
46 | } | ||
47 | |||
48 | pub fn get(&self, flag: &str) -> bool { | ||
49 | match self.flags.get(flag) { | ||
50 | None => panic!("unknown flag: {:?}", flag), | ||
51 | Some(value) => *value, | ||
52 | } | ||
53 | } | ||
54 | } | ||
55 | |||
56 | impl Default for FeatureFlags { | ||
57 | fn default() -> FeatureFlags { | ||
58 | FeatureFlags::new(&[ | ||
59 | ("lsp.diagnostics", true), | ||
60 | ("completion.insertion.add-call-parenthesis", true), | ||
61 | ("completion.insertion.add-argument-snippets", true), | ||
62 | ("completion.enable-postfix", true), | ||
63 | ("call-info.full", true), | ||
64 | ("notifications.workspace-loaded", true), | ||
65 | ("notifications.cargo-toml-not-found", true), | ||
66 | ]) | ||
67 | } | ||
68 | } | ||
69 | |||
70 | fn check_flag_name(flag: &str) { | ||
71 | for c in flag.bytes() { | ||
72 | match c { | ||
73 | b'a'..=b'z' | b'-' | b'.' => (), | ||
74 | _ => panic!("flag name does not match conventions: {:?}", flag), | ||
75 | } | ||
76 | } | ||
77 | } | ||
diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs index e50e47b19..02953be30 100644 --- a/crates/rust-analyzer/src/lib.rs +++ b/crates/rust-analyzer/src/lib.rs | |||
@@ -33,18 +33,16 @@ mod conv; | |||
33 | mod main_loop; | 33 | mod main_loop; |
34 | mod markdown; | 34 | mod markdown; |
35 | pub mod req; | 35 | pub mod req; |
36 | mod config; | 36 | pub mod config; |
37 | mod world; | 37 | mod world; |
38 | mod diagnostics; | 38 | mod diagnostics; |
39 | mod semantic_tokens; | 39 | mod semantic_tokens; |
40 | mod feature_flags; | ||
41 | 40 | ||
42 | use serde::de::DeserializeOwned; | 41 | use serde::de::DeserializeOwned; |
43 | 42 | ||
44 | pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>; | 43 | pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>; |
45 | pub use crate::{ | 44 | pub use crate::{ |
46 | caps::server_capabilities, | 45 | caps::server_capabilities, |
47 | config::ServerConfig, | ||
48 | main_loop::LspError, | 46 | main_loop::LspError, |
49 | main_loop::{main_loop, show_message}, | 47 | main_loop::{main_loop, show_message}, |
50 | }; | 48 | }; |
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index de40e2ac2..45ae0ad9d 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs | |||
@@ -17,9 +17,8 @@ use std::{ | |||
17 | use crossbeam_channel::{never, select, unbounded, RecvError, Sender}; | 17 | use crossbeam_channel::{never, select, unbounded, RecvError, Sender}; |
18 | use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response}; | 18 | use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response}; |
19 | use lsp_types::{ | 19 | use lsp_types::{ |
20 | ClientCapabilities, NumberOrString, TextDocumentClientCapabilities, WorkDoneProgress, | 20 | NumberOrString, WorkDoneProgress, WorkDoneProgressBegin, WorkDoneProgressCreateParams, |
21 | WorkDoneProgressBegin, WorkDoneProgressCreateParams, WorkDoneProgressEnd, | 21 | WorkDoneProgressEnd, WorkDoneProgressReport, |
22 | WorkDoneProgressReport, | ||
23 | }; | 22 | }; |
24 | use ra_flycheck::{url_from_path_with_drive_lowercasing, CheckTask}; | 23 | use ra_flycheck::{url_from_path_with_drive_lowercasing, CheckTask}; |
25 | use ra_ide::{Canceled, FileId, LibraryData, SourceRootId}; | 24 | use ra_ide::{Canceled, FileId, LibraryData, SourceRootId}; |
@@ -31,16 +30,15 @@ use serde::{de::DeserializeOwned, Serialize}; | |||
31 | use threadpool::ThreadPool; | 30 | use threadpool::ThreadPool; |
32 | 31 | ||
33 | use crate::{ | 32 | use crate::{ |
34 | config::get_config, | 33 | config::Config, |
35 | diagnostics::DiagnosticTask, | 34 | diagnostics::DiagnosticTask, |
36 | feature_flags::FeatureFlags, | ||
37 | main_loop::{ | 35 | main_loop::{ |
38 | pending_requests::{PendingRequest, PendingRequests}, | 36 | pending_requests::{PendingRequest, PendingRequests}, |
39 | subscriptions::Subscriptions, | 37 | subscriptions::Subscriptions, |
40 | }, | 38 | }, |
41 | req, | 39 | req, |
42 | world::{WorldSnapshot, WorldState}, | 40 | world::{WorldSnapshot, WorldState}, |
43 | Result, ServerConfig, | 41 | Result, |
44 | }; | 42 | }; |
45 | use req::ConfigurationParams; | 43 | use req::ConfigurationParams; |
46 | 44 | ||
@@ -66,29 +64,8 @@ impl fmt::Display for LspError { | |||
66 | 64 | ||
67 | impl Error for LspError {} | 65 | impl Error for LspError {} |
68 | 66 | ||
69 | fn get_feature_flags(config: &ServerConfig, connection: &Connection) -> FeatureFlags { | 67 | pub fn main_loop(ws_roots: Vec<PathBuf>, config: Config, connection: Connection) -> Result<()> { |
70 | let mut ff = FeatureFlags::default(); | 68 | log::info!("initial config: {:#?}", config); |
71 | for (flag, &value) in &config.feature_flags { | ||
72 | if ff.set(flag.as_str(), value).is_err() { | ||
73 | log::error!("unknown feature flag: {:?}", flag); | ||
74 | show_message( | ||
75 | req::MessageType::Error, | ||
76 | format!("unknown feature flag: {:?}", flag), | ||
77 | &connection.sender, | ||
78 | ); | ||
79 | } | ||
80 | } | ||
81 | log::info!("feature_flags: {:#?}", ff); | ||
82 | ff | ||
83 | } | ||
84 | |||
85 | pub fn main_loop( | ||
86 | ws_roots: Vec<PathBuf>, | ||
87 | client_caps: ClientCapabilities, | ||
88 | config: ServerConfig, | ||
89 | connection: Connection, | ||
90 | ) -> Result<()> { | ||
91 | log::info!("server_config: {:#?}", config); | ||
92 | 69 | ||
93 | // Windows scheduler implements priority boosts: if thread waits for an | 70 | // Windows scheduler implements priority boosts: if thread waits for an |
94 | // event (like a condvar), and event fires, priority of the thread is | 71 | // event (like a condvar), and event fires, priority of the thread is |
@@ -109,11 +86,8 @@ pub fn main_loop( | |||
109 | SetThreadPriority(thread, thread_priority_above_normal); | 86 | SetThreadPriority(thread, thread_priority_above_normal); |
110 | } | 87 | } |
111 | 88 | ||
112 | let text_document_caps = client_caps.text_document.as_ref(); | ||
113 | let mut loop_state = LoopState::default(); | 89 | let mut loop_state = LoopState::default(); |
114 | let mut world_state = { | 90 | let mut world_state = { |
115 | let feature_flags = get_feature_flags(&config, &connection); | ||
116 | |||
117 | // FIXME: support dynamic workspace loading. | 91 | // FIXME: support dynamic workspace loading. |
118 | let workspaces = { | 92 | let workspaces = { |
119 | let mut loaded_workspaces = Vec::new(); | 93 | let mut loaded_workspaces = Vec::new(); |
@@ -121,7 +95,7 @@ pub fn main_loop( | |||
121 | let workspace = ra_project_model::ProjectWorkspace::discover_with_sysroot( | 95 | let workspace = ra_project_model::ProjectWorkspace::discover_with_sysroot( |
122 | ws_root.as_path(), | 96 | ws_root.as_path(), |
123 | config.with_sysroot, | 97 | config.with_sysroot, |
124 | &config.cargo_features, | 98 | &config.cargo, |
125 | ); | 99 | ); |
126 | match workspace { | 100 | match workspace { |
127 | Ok(workspace) => loaded_workspaces.push(workspace), | 101 | Ok(workspace) => loaded_workspaces.push(workspace), |
@@ -131,7 +105,7 @@ pub fn main_loop( | |||
131 | if let Some(ra_project_model::CargoTomlNotFoundError { .. }) = | 105 | if let Some(ra_project_model::CargoTomlNotFoundError { .. }) = |
132 | e.downcast_ref() | 106 | e.downcast_ref() |
133 | { | 107 | { |
134 | if !feature_flags.get("notifications.cargo-toml-not-found") { | 108 | if !config.notifications.cargo_toml_not_found { |
135 | continue; | 109 | continue; |
136 | } | 110 | } |
137 | } | 111 | } |
@@ -180,8 +154,7 @@ pub fn main_loop( | |||
180 | config.lru_capacity, | 154 | config.lru_capacity, |
181 | &globs, | 155 | &globs, |
182 | Watch(!config.use_client_watching), | 156 | Watch(!config.use_client_watching), |
183 | get_config(&config, text_document_caps), | 157 | config, |
184 | feature_flags, | ||
185 | ) | 158 | ) |
186 | }; | 159 | }; |
187 | 160 | ||
@@ -224,7 +197,6 @@ pub fn main_loop( | |||
224 | &task_sender, | 197 | &task_sender, |
225 | &libdata_sender, | 198 | &libdata_sender, |
226 | &connection, | 199 | &connection, |
227 | text_document_caps, | ||
228 | &mut world_state, | 200 | &mut world_state, |
229 | &mut loop_state, | 201 | &mut loop_state, |
230 | event, | 202 | event, |
@@ -335,7 +307,6 @@ fn loop_turn( | |||
335 | task_sender: &Sender<Task>, | 307 | task_sender: &Sender<Task>, |
336 | libdata_sender: &Sender<LibraryData>, | 308 | libdata_sender: &Sender<LibraryData>, |
337 | connection: &Connection, | 309 | connection: &Connection, |
338 | text_document_caps: Option<&TextDocumentClientCapabilities>, | ||
339 | world_state: &mut WorldState, | 310 | world_state: &mut WorldState, |
340 | loop_state: &mut LoopState, | 311 | loop_state: &mut LoopState, |
341 | event: Event, | 312 | event: Event, |
@@ -389,28 +360,16 @@ fn loop_turn( | |||
389 | log::debug!("config update response: '{:?}", resp); | 360 | log::debug!("config update response: '{:?}", resp); |
390 | let Response { error, result, .. } = resp; | 361 | let Response { error, result, .. } = resp; |
391 | 362 | ||
392 | match ( | 363 | match (error, result) { |
393 | error, | ||
394 | result.map(|result| serde_json::from_value::<Vec<ServerConfig>>(result)), | ||
395 | ) { | ||
396 | (Some(err), _) => { | 364 | (Some(err), _) => { |
397 | log::error!("failed to fetch the server settings: {:?}", err) | 365 | log::error!("failed to fetch the server settings: {:?}", err) |
398 | } | 366 | } |
399 | (None, Some(Ok(new_config))) => { | 367 | (None, Some(configs)) => { |
400 | let new_config = new_config | 368 | if let Some(new_config) = configs.get(0) { |
401 | .first() | 369 | let mut config = world_state.config.clone(); |
402 | .expect( | 370 | config.update(&new_config); |
403 | "the client is expected to always send a non-empty config data", | 371 | world_state.update_configuration(config); |
404 | ) | 372 | } |
405 | .to_owned(); | ||
406 | world_state.update_configuration( | ||
407 | new_config.lru_capacity, | ||
408 | get_config(&new_config, text_document_caps), | ||
409 | get_feature_flags(&new_config, connection), | ||
410 | ); | ||
411 | } | ||
412 | (None, Some(Err(e))) => { | ||
413 | log::error!("failed to parse client config response: {}", e) | ||
414 | } | 373 | } |
415 | (None, None) => { | 374 | (None, None) => { |
416 | log::error!("received empty server settings response from the client") | 375 | log::error!("received empty server settings response from the client") |
@@ -441,8 +400,8 @@ fn loop_turn( | |||
441 | }); | 400 | }); |
442 | } | 401 | } |
443 | 402 | ||
444 | let show_progress = !loop_state.workspace_loaded | 403 | let show_progress = |
445 | && world_state.feature_flags.get("notifications.workspace-loaded"); | 404 | !loop_state.workspace_loaded && world_state.config.notifications.workspace_loaded; |
446 | 405 | ||
447 | if !loop_state.workspace_loaded | 406 | if !loop_state.workspace_loaded |
448 | && loop_state.roots_scanned == loop_state.roots_total | 407 | && loop_state.roots_scanned == loop_state.roots_total |
@@ -930,7 +889,7 @@ fn update_file_notifications_on_threadpool( | |||
930 | subscriptions: Vec<FileId>, | 889 | subscriptions: Vec<FileId>, |
931 | ) { | 890 | ) { |
932 | log::trace!("updating notifications for {:?}", subscriptions); | 891 | log::trace!("updating notifications for {:?}", subscriptions); |
933 | let publish_diagnostics = world.feature_flags.get("lsp.diagnostics"); | 892 | let publish_diagnostics = world.config.publish_diagnostics; |
934 | pool.execute(move || { | 893 | pool.execute(move || { |
935 | for file_id in subscriptions { | 894 | for file_id in subscriptions { |
936 | if publish_diagnostics { | 895 | if publish_diagnostics { |
diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index bb99b38a8..23e48c089 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs | |||
@@ -19,8 +19,8 @@ use lsp_types::{ | |||
19 | TextEdit, WorkspaceEdit, | 19 | TextEdit, WorkspaceEdit, |
20 | }; | 20 | }; |
21 | use ra_ide::{ | 21 | use ra_ide::{ |
22 | Assist, AssistId, CompletionConfig, FileId, FilePosition, FileRange, Query, RangeInfo, | 22 | Assist, AssistId, FileId, FilePosition, FileRange, Query, RangeInfo, Runnable, RunnableKind, |
23 | Runnable, RunnableKind, SearchScope, | 23 | SearchScope, |
24 | }; | 24 | }; |
25 | use ra_prof::profile; | 25 | use ra_prof::profile; |
26 | use ra_syntax::{AstNode, SyntaxKind, TextRange, TextUnit}; | 26 | use ra_syntax::{AstNode, SyntaxKind, TextRange, TextUnit}; |
@@ -426,15 +426,7 @@ pub fn handle_completion( | |||
426 | return Ok(None); | 426 | return Ok(None); |
427 | } | 427 | } |
428 | 428 | ||
429 | let config = CompletionConfig { | 429 | let items = match world.analysis().completions(position, &world.config.completion)? { |
430 | enable_postfix_completions: world.feature_flags.get("completion.enable-postfix"), | ||
431 | add_call_parenthesis: world.feature_flags.get("completion.insertion.add-call-parenthesis"), | ||
432 | add_call_argument_snippets: world | ||
433 | .feature_flags | ||
434 | .get("completion.insertion.add-argument-snippets"), | ||
435 | }; | ||
436 | |||
437 | let items = match world.analysis().completions(position, &config)? { | ||
438 | None => return Ok(None), | 430 | None => return Ok(None), |
439 | Some(items) => items, | 431 | Some(items) => items, |
440 | }; | 432 | }; |
@@ -458,7 +450,7 @@ pub fn handle_folding_range( | |||
458 | let ctx = FoldConvCtx { | 450 | let ctx = FoldConvCtx { |
459 | text: &text, | 451 | text: &text, |
460 | line_index: &line_index, | 452 | line_index: &line_index, |
461 | line_folding_only: world.config.line_folding_only, | 453 | line_folding_only: world.config.client_caps.line_folding_only, |
462 | }; | 454 | }; |
463 | let res = Some(folds.into_iter().map_conv_with(&ctx).collect()); | 455 | let res = Some(folds.into_iter().map_conv_with(&ctx).collect()); |
464 | Ok(res) | 456 | Ok(res) |
@@ -471,7 +463,7 @@ pub fn handle_signature_help( | |||
471 | let _p = profile("handle_signature_help"); | 463 | let _p = profile("handle_signature_help"); |
472 | let position = params.try_conv_with(&world)?; | 464 | let position = params.try_conv_with(&world)?; |
473 | if let Some(call_info) = world.analysis().call_info(position)? { | 465 | if let Some(call_info) = world.analysis().call_info(position)? { |
474 | let concise = !world.feature_flags.get("call-info.full"); | 466 | let concise = !world.config.call_info_full; |
475 | let mut active_parameter = call_info.active_parameter.map(|it| it as i64); | 467 | let mut active_parameter = call_info.active_parameter.map(|it| it as i64); |
476 | if concise && call_info.signature.has_self_param { | 468 | if concise && call_info.signature.has_self_param { |
477 | active_parameter = active_parameter.map(|it| it.saturating_sub(1)); | 469 | active_parameter = active_parameter.map(|it| it.saturating_sub(1)); |
diff --git a/crates/rust-analyzer/src/world.rs b/crates/rust-analyzer/src/world.rs index 124de4d8e..5674f42ef 100644 --- a/crates/rust-analyzer/src/world.rs +++ b/crates/rust-analyzer/src/world.rs | |||
@@ -11,7 +11,7 @@ use std::{ | |||
11 | use crossbeam_channel::{unbounded, Receiver}; | 11 | use crossbeam_channel::{unbounded, Receiver}; |
12 | use lsp_types::Url; | 12 | use lsp_types::Url; |
13 | use parking_lot::RwLock; | 13 | use parking_lot::RwLock; |
14 | use ra_flycheck::{url_from_path_with_drive_lowercasing, Flycheck}; | 14 | use ra_flycheck::{url_from_path_with_drive_lowercasing, Flycheck, FlycheckConfig}; |
15 | use ra_ide::{ | 15 | use ra_ide::{ |
16 | Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, LibraryData, SourceRootId, | 16 | Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, LibraryData, SourceRootId, |
17 | }; | 17 | }; |
@@ -23,7 +23,6 @@ use stdx::format_to; | |||
23 | use crate::{ | 23 | use crate::{ |
24 | config::Config, | 24 | config::Config, |
25 | diagnostics::{CheckFixes, DiagnosticCollection}, | 25 | diagnostics::{CheckFixes, DiagnosticCollection}, |
26 | feature_flags::FeatureFlags, | ||
27 | main_loop::pending_requests::{CompletedRequest, LatestRequests}, | 26 | main_loop::pending_requests::{CompletedRequest, LatestRequests}, |
28 | vfs_glob::{Glob, RustPackageFilterBuilder}, | 27 | vfs_glob::{Glob, RustPackageFilterBuilder}, |
29 | LspError, Result, | 28 | LspError, Result, |
@@ -31,9 +30,7 @@ use crate::{ | |||
31 | use ra_db::ExternSourceId; | 30 | use ra_db::ExternSourceId; |
32 | use rustc_hash::{FxHashMap, FxHashSet}; | 31 | use rustc_hash::{FxHashMap, FxHashSet}; |
33 | 32 | ||
34 | fn create_flycheck(workspaces: &[ProjectWorkspace], config: &Config) -> Option<Flycheck> { | 33 | fn create_flycheck(workspaces: &[ProjectWorkspace], config: &FlycheckConfig) -> Option<Flycheck> { |
35 | let check_config = config.check.as_ref()?; | ||
36 | |||
37 | // FIXME: Figure out the multi-workspace situation | 34 | // FIXME: Figure out the multi-workspace situation |
38 | workspaces | 35 | workspaces |
39 | .iter() | 36 | .iter() |
@@ -43,7 +40,7 @@ fn create_flycheck(workspaces: &[ProjectWorkspace], config: &Config) -> Option<F | |||
43 | }) | 40 | }) |
44 | .map(|cargo| { | 41 | .map(|cargo| { |
45 | let cargo_project_root = cargo.workspace_root().to_path_buf(); | 42 | let cargo_project_root = cargo.workspace_root().to_path_buf(); |
46 | Some(Flycheck::new(check_config.clone(), cargo_project_root)) | 43 | Some(Flycheck::new(config.clone(), cargo_project_root)) |
47 | }) | 44 | }) |
48 | .unwrap_or_else(|| { | 45 | .unwrap_or_else(|| { |
49 | log::warn!("Cargo check watching only supported for cargo workspaces, disabling"); | 46 | log::warn!("Cargo check watching only supported for cargo workspaces, disabling"); |
@@ -59,7 +56,6 @@ fn create_flycheck(workspaces: &[ProjectWorkspace], config: &Config) -> Option<F | |||
59 | #[derive(Debug)] | 56 | #[derive(Debug)] |
60 | pub struct WorldState { | 57 | pub struct WorldState { |
61 | pub config: Config, | 58 | pub config: Config, |
62 | pub feature_flags: Arc<FeatureFlags>, | ||
63 | pub roots: Vec<PathBuf>, | 59 | pub roots: Vec<PathBuf>, |
64 | pub workspaces: Arc<Vec<ProjectWorkspace>>, | 60 | pub workspaces: Arc<Vec<ProjectWorkspace>>, |
65 | pub analysis_host: AnalysisHost, | 61 | pub analysis_host: AnalysisHost, |
@@ -73,7 +69,6 @@ pub struct WorldState { | |||
73 | /// An immutable snapshot of the world's state at a point in time. | 69 | /// An immutable snapshot of the world's state at a point in time. |
74 | pub struct WorldSnapshot { | 70 | pub struct WorldSnapshot { |
75 | pub config: Config, | 71 | pub config: Config, |
76 | pub feature_flags: Arc<FeatureFlags>, | ||
77 | pub workspaces: Arc<Vec<ProjectWorkspace>>, | 72 | pub workspaces: Arc<Vec<ProjectWorkspace>>, |
78 | pub analysis: Analysis, | 73 | pub analysis: Analysis, |
79 | pub latest_requests: Arc<RwLock<LatestRequests>>, | 74 | pub latest_requests: Arc<RwLock<LatestRequests>>, |
@@ -89,7 +84,6 @@ impl WorldState { | |||
89 | exclude_globs: &[Glob], | 84 | exclude_globs: &[Glob], |
90 | watch: Watch, | 85 | watch: Watch, |
91 | config: Config, | 86 | config: Config, |
92 | feature_flags: FeatureFlags, | ||
93 | ) -> WorldState { | 87 | ) -> WorldState { |
94 | let mut change = AnalysisChange::new(); | 88 | let mut change = AnalysisChange::new(); |
95 | 89 | ||
@@ -191,13 +185,12 @@ impl WorldState { | |||
191 | }); | 185 | }); |
192 | change.set_crate_graph(crate_graph); | 186 | change.set_crate_graph(crate_graph); |
193 | 187 | ||
194 | let flycheck = create_flycheck(&workspaces, &config); | 188 | let flycheck = config.check.as_ref().and_then(|c| create_flycheck(&workspaces, c)); |
195 | 189 | ||
196 | let mut analysis_host = AnalysisHost::new(lru_capacity); | 190 | let mut analysis_host = AnalysisHost::new(lru_capacity); |
197 | analysis_host.apply_change(change); | 191 | analysis_host.apply_change(change); |
198 | WorldState { | 192 | WorldState { |
199 | config: config, | 193 | config: config, |
200 | feature_flags: Arc::new(feature_flags), | ||
201 | roots: folder_roots, | 194 | roots: folder_roots, |
202 | workspaces: Arc::new(workspaces), | 195 | workspaces: Arc::new(workspaces), |
203 | analysis_host, | 196 | analysis_host, |
@@ -209,15 +202,13 @@ impl WorldState { | |||
209 | } | 202 | } |
210 | } | 203 | } |
211 | 204 | ||
212 | pub fn update_configuration( | 205 | pub fn update_configuration(&mut self, config: Config) { |
213 | &mut self, | 206 | self.analysis_host.update_lru_capacity(config.lru_capacity); |
214 | lru_capacity: Option<usize>, | 207 | if config.check != self.config.check { |
215 | config: Config, | 208 | self.flycheck = |
216 | feature_flags: FeatureFlags, | 209 | config.check.as_ref().and_then(|it| create_flycheck(&self.workspaces, it)); |
217 | ) { | 210 | } |
218 | self.feature_flags = Arc::new(feature_flags); | 211 | |
219 | self.analysis_host.update_lru_capacity(lru_capacity); | ||
220 | self.flycheck = create_flycheck(&self.workspaces, &config); | ||
221 | self.config = config; | 212 | self.config = config; |
222 | } | 213 | } |
223 | 214 | ||
@@ -275,7 +266,6 @@ impl WorldState { | |||
275 | pub fn snapshot(&self) -> WorldSnapshot { | 266 | pub fn snapshot(&self) -> WorldSnapshot { |
276 | WorldSnapshot { | 267 | WorldSnapshot { |
277 | config: self.config.clone(), | 268 | config: self.config.clone(), |
278 | feature_flags: Arc::clone(&self.feature_flags), | ||
279 | workspaces: Arc::clone(&self.workspaces), | 269 | workspaces: Arc::clone(&self.workspaces), |
280 | analysis: self.analysis_host.analysis(), | 270 | analysis: self.analysis_host.analysis(), |
281 | vfs: Arc::clone(&self.vfs), | 271 | vfs: Arc::clone(&self.vfs), |
diff --git a/crates/rust-analyzer/tests/heavy_tests/main.rs b/crates/rust-analyzer/tests/heavy_tests/main.rs index 5af5eaad2..638813311 100644 --- a/crates/rust-analyzer/tests/heavy_tests/main.rs +++ b/crates/rust-analyzer/tests/heavy_tests/main.rs | |||
@@ -615,7 +615,7 @@ fn main() { message(); } | |||
615 | "###, | 615 | "###, |
616 | ) | 616 | ) |
617 | .with_config(|config| { | 617 | .with_config(|config| { |
618 | config.cargo_features.load_out_dirs_from_check = true; | 618 | config.cargo.load_out_dirs_from_check = true; |
619 | }) | 619 | }) |
620 | .server(); | 620 | .server(); |
621 | server.wait_until_workspace_is_loaded(); | 621 | server.wait_until_workspace_is_loaded(); |
diff --git a/crates/rust-analyzer/tests/heavy_tests/support.rs b/crates/rust-analyzer/tests/heavy_tests/support.rs index d8bed6d7f..7eebedff7 100644 --- a/crates/rust-analyzer/tests/heavy_tests/support.rs +++ b/crates/rust-analyzer/tests/heavy_tests/support.rs | |||
@@ -11,8 +11,7 @@ use lsp_server::{Connection, Message, Notification, Request}; | |||
11 | use lsp_types::{ | 11 | use lsp_types::{ |
12 | notification::{DidOpenTextDocument, Exit}, | 12 | notification::{DidOpenTextDocument, Exit}, |
13 | request::Shutdown, | 13 | request::Shutdown, |
14 | ClientCapabilities, DidOpenTextDocumentParams, GotoCapability, TextDocumentClientCapabilities, | 14 | DidOpenTextDocumentParams, TextDocumentIdentifier, TextDocumentItem, Url, WorkDoneProgress, |
15 | TextDocumentIdentifier, TextDocumentItem, Url, WorkDoneProgress, | ||
16 | }; | 15 | }; |
17 | use serde::Serialize; | 16 | use serde::Serialize; |
18 | use serde_json::{to_string_pretty, Value}; | 17 | use serde_json::{to_string_pretty, Value}; |
@@ -20,14 +19,17 @@ use tempfile::TempDir; | |||
20 | use test_utils::{find_mismatch, parse_fixture}; | 19 | use test_utils::{find_mismatch, parse_fixture}; |
21 | 20 | ||
22 | use req::{ProgressParams, ProgressParamsValue}; | 21 | use req::{ProgressParams, ProgressParamsValue}; |
23 | use rust_analyzer::{main_loop, req, ServerConfig}; | 22 | use rust_analyzer::{ |
23 | config::{ClientCapsConfig, Config}, | ||
24 | main_loop, req, | ||
25 | }; | ||
24 | 26 | ||
25 | pub struct Project<'a> { | 27 | pub struct Project<'a> { |
26 | fixture: &'a str, | 28 | fixture: &'a str, |
27 | with_sysroot: bool, | 29 | with_sysroot: bool, |
28 | tmp_dir: Option<TempDir>, | 30 | tmp_dir: Option<TempDir>, |
29 | roots: Vec<PathBuf>, | 31 | roots: Vec<PathBuf>, |
30 | config: Option<Box<dyn Fn(&mut ServerConfig)>>, | 32 | config: Option<Box<dyn Fn(&mut Config)>>, |
31 | } | 33 | } |
32 | 34 | ||
33 | impl<'a> Project<'a> { | 35 | impl<'a> Project<'a> { |
@@ -50,7 +52,7 @@ impl<'a> Project<'a> { | |||
50 | self | 52 | self |
51 | } | 53 | } |
52 | 54 | ||
53 | pub fn with_config(mut self, config: impl Fn(&mut ServerConfig) + 'static) -> Project<'a> { | 55 | pub fn with_config(mut self, config: impl Fn(&mut Config) + 'static) -> Project<'a> { |
54 | self.config = Some(Box::new(config)); | 56 | self.config = Some(Box::new(config)); |
55 | self | 57 | self |
56 | } | 58 | } |
@@ -78,8 +80,11 @@ impl<'a> Project<'a> { | |||
78 | 80 | ||
79 | let roots = self.roots.into_iter().map(|root| tmp_dir.path().join(root)).collect(); | 81 | let roots = self.roots.into_iter().map(|root| tmp_dir.path().join(root)).collect(); |
80 | 82 | ||
81 | let mut config = | 83 | let mut config = Config { |
82 | ServerConfig { with_sysroot: self.with_sysroot, ..ServerConfig::default() }; | 84 | client_caps: ClientCapsConfig { location_link: true, ..Default::default() }, |
85 | with_sysroot: self.with_sysroot, | ||
86 | ..Config::default() | ||
87 | }; | ||
83 | 88 | ||
84 | if let Some(f) = &self.config { | 89 | if let Some(f) = &self.config { |
85 | f(&mut config) | 90 | f(&mut config) |
@@ -105,7 +110,7 @@ pub struct Server { | |||
105 | impl Server { | 110 | impl Server { |
106 | fn new( | 111 | fn new( |
107 | dir: TempDir, | 112 | dir: TempDir, |
108 | config: ServerConfig, | 113 | config: Config, |
109 | roots: Vec<PathBuf>, | 114 | roots: Vec<PathBuf>, |
110 | files: Vec<(PathBuf, String)>, | 115 | files: Vec<(PathBuf, String)>, |
111 | ) -> Server { | 116 | ) -> Server { |
@@ -116,26 +121,7 @@ impl Server { | |||
116 | 121 | ||
117 | let _thread = jod_thread::Builder::new() | 122 | let _thread = jod_thread::Builder::new() |
118 | .name("test server".to_string()) | 123 | .name("test server".to_string()) |
119 | .spawn(move || { | 124 | .spawn(move || main_loop(roots, config, connection).unwrap()) |
120 | main_loop( | ||
121 | roots, | ||
122 | ClientCapabilities { | ||
123 | workspace: None, | ||
124 | text_document: Some(TextDocumentClientCapabilities { | ||
125 | definition: Some(GotoCapability { | ||
126 | dynamic_registration: None, | ||
127 | link_support: Some(true), | ||
128 | }), | ||
129 | ..Default::default() | ||
130 | }), | ||
131 | window: None, | ||
132 | experimental: None, | ||
133 | }, | ||
134 | config, | ||
135 | connection, | ||
136 | ) | ||
137 | .unwrap() | ||
138 | }) | ||
139 | .expect("failed to spawn a thread"); | 125 | .expect("failed to spawn a thread"); |
140 | 126 | ||
141 | let res = | 127 | let res = |