diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2019-08-22 13:17:21 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2019-08-22 13:17:21 +0100 |
commit | 0a612fad026df7c270226822e239f8d3137cf31c (patch) | |
tree | e14c62250a13f39860965b15d4e3d7e48d022d67 | |
parent | 2d0931b9ba7aabdc634c799b32957cc6f057e875 (diff) | |
parent | 69bbe79c5037eb3cd00744593d1836e45a6f56e1 (diff) |
Merge #1715
1715: Feature flags r=matklad a=matklad
Co-authored-by: Aleksey Kladov <[email protected]>
-rw-r--r-- | crates/ra_batch/src/lib.rs | 4 | ||||
-rw-r--r-- | crates/ra_ide_api/src/completion/presentation.rs | 5 | ||||
-rw-r--r-- | crates/ra_ide_api/src/db.rs | 9 | ||||
-rw-r--r-- | crates/ra_ide_api/src/feature_flags.rs | 67 | ||||
-rw-r--r-- | crates/ra_ide_api/src/lib.rs | 16 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/config.rs | 13 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/lib.rs | 5 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main.rs | 19 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop.rs | 48 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/world.rs | 15 | ||||
-rw-r--r-- | editors/code/package.json | 8 | ||||
-rw-r--r-- | editors/code/src/config.ts | 4 | ||||
-rw-r--r-- | editors/code/src/server.ts | 3 |
13 files changed, 172 insertions, 44 deletions
diff --git a/crates/ra_batch/src/lib.rs b/crates/ra_batch/src/lib.rs index 0db751465..f458ea300 100644 --- a/crates/ra_batch/src/lib.rs +++ b/crates/ra_batch/src/lib.rs | |||
@@ -3,7 +3,7 @@ use std::{collections::HashSet, error::Error, path::Path}; | |||
3 | use rustc_hash::FxHashMap; | 3 | use rustc_hash::FxHashMap; |
4 | 4 | ||
5 | use ra_db::{CrateGraph, FileId, SourceRootId}; | 5 | use ra_db::{CrateGraph, FileId, SourceRootId}; |
6 | use ra_ide_api::{AnalysisChange, AnalysisHost}; | 6 | use ra_ide_api::{AnalysisChange, AnalysisHost, FeatureFlags}; |
7 | use ra_project_model::{PackageRoot, ProjectWorkspace}; | 7 | use ra_project_model::{PackageRoot, ProjectWorkspace}; |
8 | use ra_vfs::{RootEntry, Vfs, VfsChange}; | 8 | use ra_vfs::{RootEntry, Vfs, VfsChange}; |
9 | use ra_vfs_glob::RustPackageFilterBuilder; | 9 | use ra_vfs_glob::RustPackageFilterBuilder; |
@@ -63,7 +63,7 @@ pub fn load( | |||
63 | vfs: &mut Vfs, | 63 | vfs: &mut Vfs, |
64 | ) -> AnalysisHost { | 64 | ) -> AnalysisHost { |
65 | let lru_cap = std::env::var("RA_LRU_CAP").ok().and_then(|it| it.parse::<usize>().ok()); | 65 | let lru_cap = std::env::var("RA_LRU_CAP").ok().and_then(|it| it.parse::<usize>().ok()); |
66 | let mut host = AnalysisHost::new(lru_cap); | 66 | let mut host = AnalysisHost::new(lru_cap, FeatureFlags::default()); |
67 | let mut analysis_change = AnalysisChange::new(); | 67 | let mut analysis_change = AnalysisChange::new(); |
68 | analysis_change.set_crate_graph(crate_graph); | 68 | analysis_change.set_crate_graph(crate_graph); |
69 | 69 | ||
diff --git a/crates/ra_ide_api/src/completion/presentation.rs b/crates/ra_ide_api/src/completion/presentation.rs index 6878008d3..2b3f98482 100644 --- a/crates/ra_ide_api/src/completion/presentation.rs +++ b/crates/ra_ide_api/src/completion/presentation.rs | |||
@@ -118,7 +118,10 @@ impl Completions { | |||
118 | .set_documentation(func.docs(ctx.db)) | 118 | .set_documentation(func.docs(ctx.db)) |
119 | .detail(detail); | 119 | .detail(detail); |
120 | // If not an import, add parenthesis automatically. | 120 | // If not an import, add parenthesis automatically. |
121 | if ctx.use_item_syntax.is_none() && !ctx.is_call { | 121 | if ctx.use_item_syntax.is_none() |
122 | && !ctx.is_call | ||
123 | && ctx.db.feature_flags.get("completion.insertion.add-call-parenthesis") | ||
124 | { | ||
122 | tested_by!(inserts_parens_for_function_calls); | 125 | tested_by!(inserts_parens_for_function_calls); |
123 | let snippet = | 126 | let snippet = |
124 | if data.params().is_empty() || data.has_self_param() && data.params().len() == 1 { | 127 | if data.params().is_empty() || data.has_self_param() && data.params().len() == 1 { |
diff --git a/crates/ra_ide_api/src/db.rs b/crates/ra_ide_api/src/db.rs index fc8252e4b..f2e6b8f12 100644 --- a/crates/ra_ide_api/src/db.rs +++ b/crates/ra_ide_api/src/db.rs | |||
@@ -7,7 +7,7 @@ use ra_db::{ | |||
7 | 7 | ||
8 | use crate::{ | 8 | use crate::{ |
9 | symbol_index::{self, SymbolsDatabase}, | 9 | symbol_index::{self, SymbolsDatabase}, |
10 | LineIndex, | 10 | FeatureFlags, LineIndex, |
11 | }; | 11 | }; |
12 | 12 | ||
13 | #[salsa::database( | 13 | #[salsa::database( |
@@ -22,6 +22,7 @@ use crate::{ | |||
22 | #[derive(Debug)] | 22 | #[derive(Debug)] |
23 | pub(crate) struct RootDatabase { | 23 | pub(crate) struct RootDatabase { |
24 | runtime: salsa::Runtime<RootDatabase>, | 24 | runtime: salsa::Runtime<RootDatabase>, |
25 | pub(crate) feature_flags: Arc<FeatureFlags>, | ||
25 | pub(crate) last_gc: time::Instant, | 26 | pub(crate) last_gc: time::Instant, |
26 | pub(crate) last_gc_check: time::Instant, | 27 | pub(crate) last_gc_check: time::Instant, |
27 | } | 28 | } |
@@ -46,16 +47,17 @@ impl salsa::Database for RootDatabase { | |||
46 | 47 | ||
47 | impl Default for RootDatabase { | 48 | impl Default for RootDatabase { |
48 | fn default() -> RootDatabase { | 49 | fn default() -> RootDatabase { |
49 | RootDatabase::new(None) | 50 | RootDatabase::new(None, FeatureFlags::default()) |
50 | } | 51 | } |
51 | } | 52 | } |
52 | 53 | ||
53 | impl RootDatabase { | 54 | impl RootDatabase { |
54 | pub fn new(lru_capacity: Option<usize>) -> RootDatabase { | 55 | pub fn new(lru_capacity: Option<usize>, feature_flags: FeatureFlags) -> RootDatabase { |
55 | let mut db = RootDatabase { | 56 | let mut db = RootDatabase { |
56 | runtime: salsa::Runtime::default(), | 57 | runtime: salsa::Runtime::default(), |
57 | last_gc: time::Instant::now(), | 58 | last_gc: time::Instant::now(), |
58 | last_gc_check: time::Instant::now(), | 59 | last_gc_check: time::Instant::now(), |
60 | feature_flags: Arc::new(feature_flags), | ||
59 | }; | 61 | }; |
60 | db.set_crate_graph_with_durability(Default::default(), Durability::HIGH); | 62 | db.set_crate_graph_with_durability(Default::default(), Durability::HIGH); |
61 | db.set_local_roots_with_durability(Default::default(), Durability::HIGH); | 63 | db.set_local_roots_with_durability(Default::default(), Durability::HIGH); |
@@ -74,6 +76,7 @@ impl salsa::ParallelDatabase for RootDatabase { | |||
74 | runtime: self.runtime.snapshot(self), | 76 | runtime: self.runtime.snapshot(self), |
75 | last_gc: self.last_gc, | 77 | last_gc: self.last_gc, |
76 | last_gc_check: self.last_gc_check, | 78 | last_gc_check: self.last_gc_check, |
79 | feature_flags: Arc::clone(&self.feature_flags), | ||
77 | }) | 80 | }) |
78 | } | 81 | } |
79 | } | 82 | } |
diff --git a/crates/ra_ide_api/src/feature_flags.rs b/crates/ra_ide_api/src/feature_flags.rs new file mode 100644 index 000000000..9f82ac71c --- /dev/null +++ b/crates/ra_ide_api/src/feature_flags.rs | |||
@@ -0,0 +1,67 @@ | |||
1 | use rustc_hash::FxHashMap; | ||
2 | |||
3 | /// Feature flags hold fine-grained toggles for all *user-visible* features of | ||
4 | /// rust-analyzer. | ||
5 | /// | ||
6 | /// The exists such that users are able to disable any annoying feature (and, | ||
7 | /// with many users and many features, some features are bound to be annoying | ||
8 | /// for some users) | ||
9 | /// | ||
10 | /// Note that we purposefully use run-time checked strings, and not something | ||
11 | /// checked at compile time, to keep things simple and flexible. | ||
12 | /// | ||
13 | /// Also note that, at the moment, `FeatureFlags` also store features for | ||
14 | /// `ra_lsp_server`. This should be benign layering violation. | ||
15 | #[derive(Debug)] | ||
16 | pub struct FeatureFlags { | ||
17 | flags: FxHashMap<String, bool>, | ||
18 | } | ||
19 | |||
20 | impl FeatureFlags { | ||
21 | fn new(flags: &[(&str, bool)]) -> FeatureFlags { | ||
22 | let flags = flags | ||
23 | .iter() | ||
24 | .map(|&(name, value)| { | ||
25 | check_flag_name(name); | ||
26 | (name.to_string(), value) | ||
27 | }) | ||
28 | .collect(); | ||
29 | FeatureFlags { flags } | ||
30 | } | ||
31 | |||
32 | pub fn set(&mut self, flag: &str, value: bool) -> Result<(), ()> { | ||
33 | match self.flags.get_mut(flag) { | ||
34 | None => Err(()), | ||
35 | Some(slot) => { | ||
36 | *slot = value; | ||
37 | Ok(()) | ||
38 | } | ||
39 | } | ||
40 | } | ||
41 | |||
42 | pub fn get(&self, flag: &str) -> bool { | ||
43 | match self.flags.get(flag) { | ||
44 | None => panic!("unknown flag: {:?}", flag), | ||
45 | Some(value) => *value, | ||
46 | } | ||
47 | } | ||
48 | } | ||
49 | |||
50 | impl Default for FeatureFlags { | ||
51 | fn default() -> FeatureFlags { | ||
52 | FeatureFlags::new(&[ | ||
53 | ("lsp.diagnostics", true), | ||
54 | ("completion.insertion.add-call-parenthesis", true), | ||
55 | ("notifications.workspace-loaded", true), | ||
56 | ]) | ||
57 | } | ||
58 | } | ||
59 | |||
60 | fn check_flag_name(flag: &str) { | ||
61 | for c in flag.bytes() { | ||
62 | match c { | ||
63 | b'a'..=b'z' | b'-' | b'.' => (), | ||
64 | _ => panic!("flag name does not match conventions: {:?}", flag), | ||
65 | } | ||
66 | } | ||
67 | } | ||
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs index fa4ae4379..514dcaf96 100644 --- a/crates/ra_ide_api/src/lib.rs +++ b/crates/ra_ide_api/src/lib.rs | |||
@@ -14,6 +14,7 @@ mod db; | |||
14 | pub mod mock_analysis; | 14 | pub mod mock_analysis; |
15 | mod symbol_index; | 15 | mod symbol_index; |
16 | mod change; | 16 | mod change; |
17 | mod feature_flags; | ||
17 | 18 | ||
18 | mod status; | 19 | mod status; |
19 | mod completion; | 20 | mod completion; |
@@ -63,6 +64,7 @@ pub use crate::{ | |||
63 | completion::{CompletionItem, CompletionItemKind, InsertTextFormat}, | 64 | completion::{CompletionItem, CompletionItemKind, InsertTextFormat}, |
64 | diagnostics::Severity, | 65 | diagnostics::Severity, |
65 | display::{file_structure, FunctionSignature, NavigationTarget, StructureNode}, | 66 | display::{file_structure, FunctionSignature, NavigationTarget, StructureNode}, |
67 | feature_flags::FeatureFlags, | ||
66 | folding_ranges::{Fold, FoldKind}, | 68 | folding_ranges::{Fold, FoldKind}, |
67 | hover::HoverResult, | 69 | hover::HoverResult, |
68 | inlay_hints::{InlayHint, InlayKind}, | 70 | inlay_hints::{InlayHint, InlayKind}, |
@@ -247,13 +249,13 @@ pub struct AnalysisHost { | |||
247 | 249 | ||
248 | impl Default for AnalysisHost { | 250 | impl Default for AnalysisHost { |
249 | fn default() -> AnalysisHost { | 251 | fn default() -> AnalysisHost { |
250 | AnalysisHost::new(None) | 252 | AnalysisHost::new(None, FeatureFlags::default()) |
251 | } | 253 | } |
252 | } | 254 | } |
253 | 255 | ||
254 | impl AnalysisHost { | 256 | impl AnalysisHost { |
255 | pub fn new(lru_capcity: Option<usize>) -> AnalysisHost { | 257 | pub fn new(lru_capcity: Option<usize>, feature_flags: FeatureFlags) -> AnalysisHost { |
256 | AnalysisHost { db: db::RootDatabase::new(lru_capcity) } | 258 | AnalysisHost { db: db::RootDatabase::new(lru_capcity, feature_flags) } |
257 | } | 259 | } |
258 | /// Returns a snapshot of the current state, which you can query for | 260 | /// Returns a snapshot of the current state, which you can query for |
259 | /// semantic information. | 261 | /// semantic information. |
@@ -261,6 +263,10 @@ impl AnalysisHost { | |||
261 | Analysis { db: self.db.snapshot() } | 263 | Analysis { db: self.db.snapshot() } |
262 | } | 264 | } |
263 | 265 | ||
266 | pub fn feature_flags(&self) -> &FeatureFlags { | ||
267 | &self.db.feature_flags | ||
268 | } | ||
269 | |||
264 | /// Applies changes to the current state of the world. If there are | 270 | /// Applies changes to the current state of the world. If there are |
265 | /// outstanding snapshots, they will be canceled. | 271 | /// outstanding snapshots, they will be canceled. |
266 | pub fn apply_change(&mut self, change: AnalysisChange) { | 272 | pub fn apply_change(&mut self, change: AnalysisChange) { |
@@ -319,6 +325,10 @@ impl Analysis { | |||
319 | (host.analysis(), file_id) | 325 | (host.analysis(), file_id) |
320 | } | 326 | } |
321 | 327 | ||
328 | pub fn feature_flags(&self) -> &FeatureFlags { | ||
329 | &self.db.feature_flags | ||
330 | } | ||
331 | |||
322 | /// Debug info about the current state of the analysis | 332 | /// Debug info about the current state of the analysis |
323 | pub fn status(&self) -> Cancelable<String> { | 333 | pub fn status(&self) -> Cancelable<String> { |
324 | self.with_db(|db| status::status(&*db)) | 334 | self.with_db(|db| status::status(&*db)) |
diff --git a/crates/ra_lsp_server/src/config.rs b/crates/ra_lsp_server/src/config.rs index 71838b89c..5c5ae3e18 100644 --- a/crates/ra_lsp_server/src/config.rs +++ b/crates/ra_lsp_server/src/config.rs | |||
@@ -1,3 +1,5 @@ | |||
1 | use rustc_hash::FxHashMap; | ||
2 | |||
1 | use serde::{Deserialize, Deserializer}; | 3 | use serde::{Deserialize, Deserializer}; |
2 | 4 | ||
3 | /// Client provided initialization options | 5 | /// Client provided initialization options |
@@ -12,12 +14,6 @@ pub struct ServerConfig { | |||
12 | #[serde(deserialize_with = "nullable_bool_false")] | 14 | #[serde(deserialize_with = "nullable_bool_false")] |
13 | pub publish_decorations: bool, | 15 | pub publish_decorations: bool, |
14 | 16 | ||
15 | /// Whether or not the workspace loaded notification should be sent | ||
16 | /// | ||
17 | /// Defaults to `true` | ||
18 | #[serde(deserialize_with = "nullable_bool_true")] | ||
19 | pub show_workspace_loaded: bool, | ||
20 | |||
21 | pub exclude_globs: Vec<String>, | 17 | pub exclude_globs: Vec<String>, |
22 | 18 | ||
23 | pub lru_capacity: Option<usize>, | 19 | pub lru_capacity: Option<usize>, |
@@ -25,16 +21,19 @@ pub struct ServerConfig { | |||
25 | /// For internal usage to make integrated tests faster. | 21 | /// For internal usage to make integrated tests faster. |
26 | #[serde(deserialize_with = "nullable_bool_true")] | 22 | #[serde(deserialize_with = "nullable_bool_true")] |
27 | pub with_sysroot: bool, | 23 | pub with_sysroot: bool, |
24 | |||
25 | /// Fine grained feature flags to disable specific features. | ||
26 | pub feature_flags: FxHashMap<String, bool>, | ||
28 | } | 27 | } |
29 | 28 | ||
30 | impl Default for ServerConfig { | 29 | impl Default for ServerConfig { |
31 | fn default() -> ServerConfig { | 30 | fn default() -> ServerConfig { |
32 | ServerConfig { | 31 | ServerConfig { |
33 | publish_decorations: false, | 32 | publish_decorations: false, |
34 | show_workspace_loaded: true, | ||
35 | exclude_globs: Vec::new(), | 33 | exclude_globs: Vec::new(), |
36 | lru_capacity: None, | 34 | lru_capacity: None, |
37 | with_sysroot: true, | 35 | with_sysroot: true, |
36 | feature_flags: FxHashMap::default(), | ||
38 | } | 37 | } |
39 | } | 38 | } |
40 | } | 39 | } |
diff --git a/crates/ra_lsp_server/src/lib.rs b/crates/ra_lsp_server/src/lib.rs index ca388e472..2c5d7c72d 100644 --- a/crates/ra_lsp_server/src/lib.rs +++ b/crates/ra_lsp_server/src/lib.rs | |||
@@ -11,5 +11,8 @@ mod world; | |||
11 | 11 | ||
12 | pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>; | 12 | pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>; |
13 | pub use crate::{ | 13 | pub use crate::{ |
14 | caps::server_capabilities, config::ServerConfig, main_loop::main_loop, main_loop::LspError, | 14 | caps::server_capabilities, |
15 | config::ServerConfig, | ||
16 | main_loop::LspError, | ||
17 | main_loop::{main_loop, show_message}, | ||
15 | }; | 18 | }; |
diff --git a/crates/ra_lsp_server/src/main.rs b/crates/ra_lsp_server/src/main.rs index 36d4898bd..ae1392cb5 100644 --- a/crates/ra_lsp_server/src/main.rs +++ b/crates/ra_lsp_server/src/main.rs | |||
@@ -1,8 +1,7 @@ | |||
1 | use flexi_logger::{Duplicate, Logger}; | 1 | use flexi_logger::{Duplicate, Logger}; |
2 | use gen_lsp_server::{run_server, stdio_transport}; | 2 | use gen_lsp_server::{run_server, stdio_transport}; |
3 | use serde::Deserialize; | ||
4 | 3 | ||
5 | use ra_lsp_server::{Result, ServerConfig}; | 4 | use ra_lsp_server::{show_message, Result, ServerConfig}; |
6 | use ra_prof; | 5 | use ra_prof; |
7 | 6 | ||
8 | fn main() -> Result<()> { | 7 | fn main() -> Result<()> { |
@@ -46,15 +45,23 @@ fn main_inner() -> Result<()> { | |||
46 | .filter(|workspaces| !workspaces.is_empty()) | 45 | .filter(|workspaces| !workspaces.is_empty()) |
47 | .unwrap_or_else(|| vec![root]); | 46 | .unwrap_or_else(|| vec![root]); |
48 | 47 | ||
49 | let opts = params | 48 | let server_config: ServerConfig = params |
50 | .initialization_options | 49 | .initialization_options |
51 | .and_then(|v| { | 50 | .and_then(|v| { |
52 | ServerConfig::deserialize(v) | 51 | serde_json::from_value(v) |
53 | .map_err(|e| log::error!("failed to deserialize config: {}", e)) | 52 | .map_err(|e| { |
53 | log::error!("failed to deserialize config: {}", e); | ||
54 | show_message( | ||
55 | lsp_types::MessageType::Error, | ||
56 | format!("failed to deserialize config: {}", e), | ||
57 | s, | ||
58 | ); | ||
59 | }) | ||
54 | .ok() | 60 | .ok() |
55 | }) | 61 | }) |
56 | .unwrap_or_default(); | 62 | .unwrap_or_default(); |
57 | ra_lsp_server::main_loop(workspace_roots, params.capabilities, opts, r, s) | 63 | |
64 | ra_lsp_server::main_loop(workspace_roots, params.capabilities, server_config, r, s) | ||
58 | })?; | 65 | })?; |
59 | log::info!("shutting down IO..."); | 66 | log::info!("shutting down IO..."); |
60 | threads.join()?; | 67 | threads.join()?; |
diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs index fcb782386..ce25ff162 100644 --- a/crates/ra_lsp_server/src/main_loop.rs +++ b/crates/ra_lsp_server/src/main_loop.rs | |||
@@ -9,7 +9,7 @@ use gen_lsp_server::{ | |||
9 | handle_shutdown, ErrorCode, RawMessage, RawNotification, RawRequest, RawResponse, | 9 | handle_shutdown, ErrorCode, RawMessage, RawNotification, RawRequest, RawResponse, |
10 | }; | 10 | }; |
11 | use lsp_types::{ClientCapabilities, NumberOrString}; | 11 | use lsp_types::{ClientCapabilities, NumberOrString}; |
12 | use ra_ide_api::{Canceled, FileId, LibraryData}; | 12 | use ra_ide_api::{Canceled, FeatureFlags, FileId, LibraryData}; |
13 | use ra_prof::profile; | 13 | use ra_prof::profile; |
14 | use ra_vfs::VfsTask; | 14 | use ra_vfs::VfsTask; |
15 | use serde::{de::DeserializeOwned, Serialize}; | 15 | use serde::{de::DeserializeOwned, Serialize}; |
@@ -56,7 +56,7 @@ pub fn main_loop( | |||
56 | msg_receiver: &Receiver<RawMessage>, | 56 | msg_receiver: &Receiver<RawMessage>, |
57 | msg_sender: &Sender<RawMessage>, | 57 | msg_sender: &Sender<RawMessage>, |
58 | ) -> Result<()> { | 58 | ) -> Result<()> { |
59 | log::debug!("server_config: {:?}", config); | 59 | log::info!("server_config: {:#?}", config); |
60 | // FIXME: support dynamic workspace loading. | 60 | // FIXME: support dynamic workspace loading. |
61 | let workspaces = { | 61 | let workspaces = { |
62 | let ws_worker = workspace_loader(config.with_sysroot); | 62 | let ws_worker = workspace_loader(config.with_sysroot); |
@@ -83,6 +83,21 @@ pub fn main_loop( | |||
83 | .iter() | 83 | .iter() |
84 | .map(|glob| ra_vfs_glob::Glob::new(glob)) | 84 | .map(|glob| ra_vfs_glob::Glob::new(glob)) |
85 | .collect::<std::result::Result<Vec<_>, _>>()?; | 85 | .collect::<std::result::Result<Vec<_>, _>>()?; |
86 | let feature_flags = { | ||
87 | let mut ff = FeatureFlags::default(); | ||
88 | for (flag, value) in config.feature_flags { | ||
89 | if let Err(_) = ff.set(flag.as_str(), value) { | ||
90 | log::error!("unknown feature flag: {:?}", flag); | ||
91 | show_message( | ||
92 | req::MessageType::Error, | ||
93 | format!("unknown feature flag: {:?}", flag), | ||
94 | msg_sender, | ||
95 | ); | ||
96 | } | ||
97 | } | ||
98 | ff | ||
99 | }; | ||
100 | log::info!("feature_flags: {:#?}", feature_flags); | ||
86 | let mut state = WorldState::new( | 101 | let mut state = WorldState::new( |
87 | ws_roots, | 102 | ws_roots, |
88 | workspaces, | 103 | workspaces, |
@@ -90,13 +105,13 @@ pub fn main_loop( | |||
90 | &globs, | 105 | &globs, |
91 | Options { | 106 | Options { |
92 | publish_decorations: config.publish_decorations, | 107 | publish_decorations: config.publish_decorations, |
93 | show_workspace_loaded: config.show_workspace_loaded, | ||
94 | supports_location_link: client_caps | 108 | supports_location_link: client_caps |
95 | .text_document | 109 | .text_document |
96 | .and_then(|it| it.definition) | 110 | .and_then(|it| it.definition) |
97 | .and_then(|it| it.link_support) | 111 | .and_then(|it| it.link_support) |
98 | .unwrap_or(false), | 112 | .unwrap_or(false), |
99 | }, | 113 | }, |
114 | feature_flags, | ||
100 | ); | 115 | ); |
101 | 116 | ||
102 | let pool = ThreadPool::new(THREADPOOL_SIZE); | 117 | let pool = ThreadPool::new(THREADPOOL_SIZE); |
@@ -276,7 +291,7 @@ fn main_loop_inner( | |||
276 | && in_flight_libraries == 0 | 291 | && in_flight_libraries == 0 |
277 | { | 292 | { |
278 | let n_packages: usize = state.workspaces.iter().map(|it| it.n_packages()).sum(); | 293 | let n_packages: usize = state.workspaces.iter().map(|it| it.n_packages()).sum(); |
279 | if state.options.show_workspace_loaded { | 294 | if state.feature_flags().get("notifications.workspace-loaded") { |
280 | let msg = format!("workspace loaded, {} rust packages", n_packages); | 295 | let msg = format!("workspace loaded, {} rust packages", n_packages); |
281 | show_message(req::MessageType::Info, msg, msg_sender); | 296 | show_message(req::MessageType::Info, msg, msg_sender); |
282 | } | 297 | } |
@@ -587,17 +602,20 @@ fn update_file_notifications_on_threadpool( | |||
587 | subscriptions: Vec<FileId>, | 602 | subscriptions: Vec<FileId>, |
588 | ) { | 603 | ) { |
589 | log::trace!("updating notifications for {:?}", subscriptions); | 604 | log::trace!("updating notifications for {:?}", subscriptions); |
605 | let publish_diagnostics = world.feature_flags().get("lsp.diagnostics"); | ||
590 | pool.execute(move || { | 606 | pool.execute(move || { |
591 | for file_id in subscriptions { | 607 | for file_id in subscriptions { |
592 | match handlers::publish_diagnostics(&world, file_id) { | 608 | if publish_diagnostics { |
593 | Err(e) => { | 609 | match handlers::publish_diagnostics(&world, file_id) { |
594 | if !is_canceled(&e) { | 610 | Err(e) => { |
595 | log::error!("failed to compute diagnostics: {:?}", e); | 611 | if !is_canceled(&e) { |
612 | log::error!("failed to compute diagnostics: {:?}", e); | ||
613 | } | ||
614 | } | ||
615 | Ok(params) => { | ||
616 | let not = RawNotification::new::<req::PublishDiagnostics>(¶ms); | ||
617 | sender.send(Task::Notify(not)).unwrap(); | ||
596 | } | 618 | } |
597 | } | ||
598 | Ok(params) => { | ||
599 | let not = RawNotification::new::<req::PublishDiagnostics>(¶ms); | ||
600 | sender.send(Task::Notify(not)).unwrap(); | ||
601 | } | 619 | } |
602 | } | 620 | } |
603 | if publish_decorations { | 621 | if publish_decorations { |
@@ -617,7 +635,11 @@ fn update_file_notifications_on_threadpool( | |||
617 | }); | 635 | }); |
618 | } | 636 | } |
619 | 637 | ||
620 | fn show_message(typ: req::MessageType, message: impl Into<String>, sender: &Sender<RawMessage>) { | 638 | pub fn show_message( |
639 | typ: req::MessageType, | ||
640 | message: impl Into<String>, | ||
641 | sender: &Sender<RawMessage>, | ||
642 | ) { | ||
621 | let message = message.into(); | 643 | let message = message.into(); |
622 | let params = req::ShowMessageParams { typ, message }; | 644 | let params = req::ShowMessageParams { typ, message }; |
623 | let not = RawNotification::new::<req::ShowMessage>(¶ms); | 645 | let not = RawNotification::new::<req::ShowMessage>(¶ms); |
diff --git a/crates/ra_lsp_server/src/world.rs b/crates/ra_lsp_server/src/world.rs index 10f96812f..6696dff71 100644 --- a/crates/ra_lsp_server/src/world.rs +++ b/crates/ra_lsp_server/src/world.rs | |||
@@ -7,7 +7,8 @@ use gen_lsp_server::ErrorCode; | |||
7 | use lsp_types::Url; | 7 | use lsp_types::Url; |
8 | use parking_lot::RwLock; | 8 | use parking_lot::RwLock; |
9 | use ra_ide_api::{ | 9 | use ra_ide_api::{ |
10 | Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, LibraryData, SourceRootId, | 10 | Analysis, AnalysisChange, AnalysisHost, CrateGraph, FeatureFlags, FileId, LibraryData, |
11 | SourceRootId, | ||
11 | }; | 12 | }; |
12 | use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot}; | 13 | use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot}; |
13 | use ra_vfs_glob::{Glob, RustPackageFilterBuilder}; | 14 | use ra_vfs_glob::{Glob, RustPackageFilterBuilder}; |
@@ -22,7 +23,6 @@ use crate::{ | |||
22 | #[derive(Debug, Clone)] | 23 | #[derive(Debug, Clone)] |
23 | pub struct Options { | 24 | pub struct Options { |
24 | pub publish_decorations: bool, | 25 | pub publish_decorations: bool, |
25 | pub show_workspace_loaded: bool, | ||
26 | pub supports_location_link: bool, | 26 | pub supports_location_link: bool, |
27 | } | 27 | } |
28 | 28 | ||
@@ -58,6 +58,7 @@ impl WorldState { | |||
58 | lru_capacity: Option<usize>, | 58 | lru_capacity: Option<usize>, |
59 | exclude_globs: &[Glob], | 59 | exclude_globs: &[Glob], |
60 | options: Options, | 60 | options: Options, |
61 | feature_flags: FeatureFlags, | ||
61 | ) -> WorldState { | 62 | ) -> WorldState { |
62 | let mut change = AnalysisChange::new(); | 63 | let mut change = AnalysisChange::new(); |
63 | 64 | ||
@@ -99,7 +100,7 @@ impl WorldState { | |||
99 | } | 100 | } |
100 | change.set_crate_graph(crate_graph); | 101 | change.set_crate_graph(crate_graph); |
101 | 102 | ||
102 | let mut analysis_host = AnalysisHost::new(lru_capacity); | 103 | let mut analysis_host = AnalysisHost::new(lru_capacity, feature_flags); |
103 | analysis_host.apply_change(change); | 104 | analysis_host.apply_change(change); |
104 | WorldState { | 105 | WorldState { |
105 | options, | 106 | options, |
@@ -184,6 +185,10 @@ impl WorldState { | |||
184 | pub fn complete_request(&mut self, request: CompletedRequest) { | 185 | pub fn complete_request(&mut self, request: CompletedRequest) { |
185 | self.latest_requests.write().record(request) | 186 | self.latest_requests.write().record(request) |
186 | } | 187 | } |
188 | |||
189 | pub fn feature_flags(&self) -> &FeatureFlags { | ||
190 | self.analysis_host.feature_flags() | ||
191 | } | ||
187 | } | 192 | } |
188 | 193 | ||
189 | impl WorldSnapshot { | 194 | impl WorldSnapshot { |
@@ -246,4 +251,8 @@ impl WorldSnapshot { | |||
246 | let path = self.vfs.read().file2path(VfsFile(file_id.0)); | 251 | let path = self.vfs.read().file2path(VfsFile(file_id.0)); |
247 | self.workspaces.iter().find_map(|ws| ws.workspace_root_for(&path)) | 252 | self.workspaces.iter().find_map(|ws| ws.workspace_root_for(&path)) |
248 | } | 253 | } |
254 | |||
255 | pub fn feature_flags(&self) -> &FeatureFlags { | ||
256 | self.analysis.feature_flags() | ||
257 | } | ||
249 | } | 258 | } |
diff --git a/editors/code/package.json b/editors/code/package.json index 98faf538f..95ec6cff6 100644 --- a/editors/code/package.json +++ b/editors/code/package.json | |||
@@ -165,10 +165,10 @@ | |||
165 | "default": false, | 165 | "default": false, |
166 | "description": "When highlighting Rust code, use a unique color per identifier" | 166 | "description": "When highlighting Rust code, use a unique color per identifier" |
167 | }, | 167 | }, |
168 | "rust-analyzer.showWorkspaceLoadedNotification": { | 168 | "rust-analyzer.featureFlags": { |
169 | "type": "boolean", | 169 | "type": "object", |
170 | "default": true, | 170 | "default": {}, |
171 | "description": "Show notification when workspace was loaded" | 171 | "description": "Fine grained feature flags to disable annoying features" |
172 | }, | 172 | }, |
173 | "rust-analyzer.enableEnhancedTyping": { | 173 | "rust-analyzer.enableEnhancedTyping": { |
174 | "type": "boolean", | 174 | "type": "boolean", |
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index 4df6b50ef..570ddca46 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts | |||
@@ -23,6 +23,7 @@ export class Config { | |||
23 | public lruCapacity: null | number = null; | 23 | public lruCapacity: null | number = null; |
24 | public displayInlayHints = true; | 24 | public displayInlayHints = true; |
25 | public excludeGlobs = []; | 25 | public excludeGlobs = []; |
26 | public featureFlags = {}; | ||
26 | public cargoWatchOptions: CargoWatchOptions = { | 27 | public cargoWatchOptions: CargoWatchOptions = { |
27 | enableOnStartup: 'ask', | 28 | enableOnStartup: 'ask', |
28 | trace: 'off', | 29 | trace: 'off', |
@@ -132,5 +133,8 @@ export class Config { | |||
132 | if (config.has('excludeGlobs')) { | 133 | if (config.has('excludeGlobs')) { |
133 | this.excludeGlobs = config.get('excludeGlobs') || []; | 134 | this.excludeGlobs = config.get('excludeGlobs') || []; |
134 | } | 135 | } |
136 | if (config.has('featureFlags')) { | ||
137 | this.featureFlags = config.get('featureFlags') || {}; | ||
138 | } | ||
135 | } | 139 | } |
136 | } | 140 | } |
diff --git a/editors/code/src/server.ts b/editors/code/src/server.ts index 3273d8749..0d2a99c70 100644 --- a/editors/code/src/server.ts +++ b/editors/code/src/server.ts | |||
@@ -45,7 +45,8 @@ export class Server { | |||
45 | showWorkspaceLoaded: | 45 | showWorkspaceLoaded: |
46 | Server.config.showWorkspaceLoadedNotification, | 46 | Server.config.showWorkspaceLoadedNotification, |
47 | lruCapacity: Server.config.lruCapacity, | 47 | lruCapacity: Server.config.lruCapacity, |
48 | excludeGlobs: Server.config.excludeGlobs | 48 | excludeGlobs: Server.config.excludeGlobs, |
49 | featureFlags: Server.config.featureFlags | ||
49 | }, | 50 | }, |
50 | traceOutputChannel | 51 | traceOutputChannel |
51 | }; | 52 | }; |