diff options
Diffstat (limited to 'crates/ra_ide_api/src')
-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 |
4 files changed, 90 insertions, 7 deletions
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)) |