From 2347c03dcd717fbc0648c1e4e3d64a886217de5d Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 10 Mar 2020 18:39:17 +0100 Subject: Introduce CompletionOptions --- crates/ra_ide/src/completion.rs | 25 ++++++++++++++++++++-- crates/ra_ide/src/completion/complete_postfix.rs | 2 +- crates/ra_ide/src/completion/completion_context.rs | 5 ++++- crates/ra_ide/src/completion/completion_item.rs | 10 ++++++--- crates/ra_ide/src/completion/presentation.rs | 11 ++-------- crates/ra_ide/src/lib.rs | 13 +++++++++-- 6 files changed, 48 insertions(+), 18 deletions(-) diff --git a/crates/ra_ide/src/completion.rs b/crates/ra_ide/src/completion.rs index c378c2c62..a27e0fc15 100644 --- a/crates/ra_ide/src/completion.rs +++ b/crates/ra_ide/src/completion.rs @@ -33,6 +33,23 @@ pub use crate::completion::completion_item::{ CompletionItem, CompletionItemKind, InsertTextFormat, }; +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct CompletionOptions { + pub enable_postfix_completions: bool, + pub add_call_parenthesis: bool, + pub add_call_argument_snippets: bool, +} + +impl Default for CompletionOptions { + fn default() -> Self { + CompletionOptions { + enable_postfix_completions: true, + add_call_parenthesis: true, + add_call_argument_snippets: true, + } + } +} + /// Main entry point for completion. We run completion as a two-phase process. /// /// First, we look at the position and collect a so-called `CompletionContext. @@ -55,8 +72,12 @@ pub use crate::completion::completion_item::{ /// `foo` *should* be present among the completion variants. Filtering by /// identifier prefix/fuzzy match should be done higher in the stack, together /// with ordering of completions (currently this is done by the client). -pub(crate) fn completions(db: &RootDatabase, position: FilePosition) -> Option { - let ctx = CompletionContext::new(db, position)?; +pub(crate) fn completions( + db: &RootDatabase, + position: FilePosition, + opts: &CompletionOptions, +) -> Option { + let ctx = CompletionContext::new(db, position, opts)?; let mut acc = Completions::default(); diff --git a/crates/ra_ide/src/completion/complete_postfix.rs b/crates/ra_ide/src/completion/complete_postfix.rs index 65ecea125..6d000548d 100644 --- a/crates/ra_ide/src/completion/complete_postfix.rs +++ b/crates/ra_ide/src/completion/complete_postfix.rs @@ -12,7 +12,7 @@ use crate::{ }; pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { - if !ctx.db.feature_flags.get("completion.enable-postfix") { + if !ctx.options.enable_postfix_completions { return; } diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs index 40535c09e..3646fb8dc 100644 --- a/crates/ra_ide/src/completion/completion_context.rs +++ b/crates/ra_ide/src/completion/completion_context.rs @@ -11,7 +11,7 @@ use ra_syntax::{ }; use ra_text_edit::AtomTextEdit; -use crate::FilePosition; +use crate::{completion::CompletionOptions, FilePosition}; /// `CompletionContext` is created early during completion to figure out, where /// exactly is the cursor, syntax-wise. @@ -19,6 +19,7 @@ use crate::FilePosition; pub(crate) struct CompletionContext<'a> { pub(super) sema: Semantics<'a, RootDatabase>, pub(super) db: &'a RootDatabase, + pub(super) options: &'a CompletionOptions, pub(super) offset: TextUnit, /// The token before the cursor, in the original file. pub(super) original_token: SyntaxToken, @@ -57,6 +58,7 @@ impl<'a> CompletionContext<'a> { pub(super) fn new( db: &'a RootDatabase, position: FilePosition, + options: &'a CompletionOptions, ) -> Option> { let sema = Semantics::new(db); @@ -80,6 +82,7 @@ impl<'a> CompletionContext<'a> { let mut ctx = CompletionContext { sema, db, + options, original_token, token, offset: position.offset, diff --git a/crates/ra_ide/src/completion/completion_item.rs b/crates/ra_ide/src/completion/completion_item.rs index 19bbb2517..1d14e9636 100644 --- a/crates/ra_ide/src/completion/completion_item.rs +++ b/crates/ra_ide/src/completion/completion_item.rs @@ -321,14 +321,18 @@ impl Into> for Completions { #[cfg(test)] pub(crate) fn do_completion(code: &str, kind: CompletionKind) -> Vec { - use crate::completion::completions; - use crate::mock_analysis::{analysis_and_position, single_file_with_position}; + use crate::{ + completion::{completions, CompletionOptions}, + mock_analysis::{analysis_and_position, single_file_with_position}, + }; + let (analysis, position) = if code.contains("//-") { analysis_and_position(code) } else { single_file_with_position(code) }; - let completions = completions(&analysis.db, position).unwrap(); + let options = CompletionOptions::default(); + let completions = completions(&analysis.db, position, &options).unwrap(); let completion_items: Vec = completions.into(); let mut kind_completions: Vec = completion_items.into_iter().filter(|c| c.completion_kind == kind).collect(); diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index aada4d025..25aff329e 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs @@ -212,21 +212,14 @@ impl Completions { .detail(function_signature.to_string()); // If not an import, add parenthesis automatically. - if ctx.use_item_syntax.is_none() - && !ctx.is_call - && ctx.db.feature_flags.get("completion.insertion.add-call-parenthesis") - { + if ctx.use_item_syntax.is_none() && !ctx.is_call && ctx.options.add_call_parenthesis { tested_by!(inserts_parens_for_function_calls); let (snippet, label) = if params.is_empty() || has_self_param && params.len() == 1 { (format!("{}()$0", name), format!("{}()", name)) } else { builder = builder.trigger_call_info(); - let snippet = if ctx - .db - .feature_flags - .get("completion.insertion.add-argument-snippets") - { + let snippet = if ctx.options.add_call_argument_snippets { let to_skip = if has_self_param { 1 } else { 0 }; let function_params_snippet = join( function_signature.parameter_names.iter().skip(to_skip).enumerate().map( diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs index c60e86aea..0d91ea749 100644 --- a/crates/ra_ide/src/lib.rs +++ b/crates/ra_ide/src/lib.rs @@ -62,7 +62,7 @@ use crate::display::ToNav; pub use crate::{ assists::{Assist, AssistId}, call_hierarchy::CallItem, - completion::{CompletionItem, CompletionItemKind, InsertTextFormat}, + completion::{CompletionItem, CompletionItemKind, CompletionOptions, InsertTextFormat}, diagnostics::Severity, display::{file_structure, FunctionSignature, NavigationTarget, StructureNode}, expand_macro::ExpandedMacro, @@ -451,7 +451,16 @@ impl Analysis { /// Computes completions at the given position. pub fn completions(&self, position: FilePosition) -> Cancelable>> { - self.with_db(|db| completion::completions(db, position).map(Into::into)) + let opts = CompletionOptions { + enable_postfix_completions: self.feature_flags().get("completion.enable-postfix"), + add_call_parenthesis: self + .feature_flags() + .get("completion.insertion.add-call-parenthesis"), + add_call_argument_snippets: self + .feature_flags() + .get("completion.insertion.add-argument-snippets"), + }; + self.with_db(|db| completion::completions(db, position, &opts).map(Into::into)) } /// Computes assists (aka code actions aka intentions) for the given -- cgit v1.2.3 From bf582e77d6e5603149b355a5650cd4d15318f776 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 10 Mar 2020 18:47:09 +0100 Subject: Pull completion options up to the rust-analyzer --- crates/ra_ide/src/completion/presentation.rs | 5 +---- crates/ra_ide/src/lib.rs | 17 ++++++----------- crates/ra_ide_db/src/feature_flags.rs | 4 ++++ crates/rust-analyzer/src/cli/analysis_bench.rs | 12 +++++++----- crates/rust-analyzer/src/main_loop/handlers.rs | 16 +++++++++++++--- 5 files changed, 31 insertions(+), 23 deletions(-) diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs index 25aff329e..3dc56e4a3 100644 --- a/crates/ra_ide/src/completion/presentation.rs +++ b/crates/ra_ide/src/completion/presentation.rs @@ -104,10 +104,7 @@ impl Completions { }; // Add `<>` for generic types - if ctx.is_path_type - && !ctx.has_type_args - && ctx.db.feature_flags.get("completion.insertion.add-call-parenthesis") - { + if ctx.is_path_type && !ctx.has_type_args && ctx.options.add_call_parenthesis { let has_non_default_type_params = match resolution { ScopeDef::ModuleDef(Adt(it)) => it.has_non_default_type_params(ctx.db), ScopeDef::ModuleDef(TypeAlias(it)) => it.has_non_default_type_params(ctx.db), diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs index 0d91ea749..d888bb745 100644 --- a/crates/ra_ide/src/lib.rs +++ b/crates/ra_ide/src/lib.rs @@ -450,17 +450,12 @@ impl Analysis { } /// Computes completions at the given position. - pub fn completions(&self, position: FilePosition) -> Cancelable>> { - let opts = CompletionOptions { - enable_postfix_completions: self.feature_flags().get("completion.enable-postfix"), - add_call_parenthesis: self - .feature_flags() - .get("completion.insertion.add-call-parenthesis"), - add_call_argument_snippets: self - .feature_flags() - .get("completion.insertion.add-argument-snippets"), - }; - self.with_db(|db| completion::completions(db, position, &opts).map(Into::into)) + pub fn completions( + &self, + position: FilePosition, + options: &CompletionOptions, + ) -> Cancelable>> { + self.with_db(|db| completion::completions(db, position, options).map(Into::into)) } /// Computes assists (aka code actions aka intentions) for the given diff --git a/crates/ra_ide_db/src/feature_flags.rs b/crates/ra_ide_db/src/feature_flags.rs index 968415072..dbb3f50a0 100644 --- a/crates/ra_ide_db/src/feature_flags.rs +++ b/crates/ra_ide_db/src/feature_flags.rs @@ -2,6 +2,10 @@ use rustc_hash::FxHashMap; +// FIXME: looks like a much better design is to pass options to each call, +// rather than to have a global ambient feature flags -- that way, the clients +// can issue two successive calls with different options. + /// Feature flags hold fine-grained toggles for all *user-visible* features of /// rust-analyzer. /// diff --git a/crates/rust-analyzer/src/cli/analysis_bench.rs b/crates/rust-analyzer/src/cli/analysis_bench.rs index 91855e592..28a23934f 100644 --- a/crates/rust-analyzer/src/cli/analysis_bench.rs +++ b/crates/rust-analyzer/src/cli/analysis_bench.rs @@ -12,7 +12,7 @@ use ra_db::{ salsa::{Database, Durability}, FileId, SourceDatabaseExt, }; -use ra_ide::{Analysis, AnalysisChange, AnalysisHost, FilePosition, LineCol}; +use ra_ide::{Analysis, AnalysisChange, AnalysisHost, CompletionOptions, FilePosition, LineCol}; use crate::cli::{load_cargo::load_cargo, Verbosity}; @@ -94,17 +94,19 @@ pub fn analysis_bench(verbosity: Verbosity, path: &Path, what: BenchWhat) -> Res .analysis() .file_line_index(file_id)? .offset(LineCol { line: pos.line - 1, col_utf16: pos.column }); - let file_postion = FilePosition { file_id, offset }; + let file_position = FilePosition { file_id, offset }; if is_completion { - let res = - do_work(&mut host, file_id, |analysis| analysis.completions(file_postion)); + let options = CompletionOptions::default(); + let res = do_work(&mut host, file_id, |analysis| { + analysis.completions(file_position, &options) + }); if verbosity.is_verbose() { println!("\n{:#?}", res); } } else { let res = - do_work(&mut host, file_id, |analysis| analysis.goto_definition(file_postion)); + do_work(&mut host, file_id, |analysis| analysis.goto_definition(file_position)); if verbosity.is_verbose() { println!("\n{:#?}", res); } diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index 8dc6e8dc0..155f677a6 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs @@ -20,8 +20,8 @@ use lsp_types::{ TextEdit, WorkspaceEdit, }; use ra_ide::{ - Assist, AssistId, FileId, FilePosition, FileRange, Query, RangeInfo, Runnable, RunnableKind, - SearchScope, + Assist, AssistId, CompletionOptions, FileId, FilePosition, FileRange, Query, RangeInfo, + Runnable, RunnableKind, SearchScope, }; use ra_prof::profile; use ra_syntax::{AstNode, SyntaxKind, TextRange, TextUnit}; @@ -424,7 +424,17 @@ pub fn handle_completion( return Ok(None); } - let items = match world.analysis().completions(position)? { + let options = CompletionOptions { + enable_postfix_completions: world.feature_flags().get("completion.enable-postfix"), + add_call_parenthesis: world + .feature_flags() + .get("completion.insertion.add-call-parenthesis"), + add_call_argument_snippets: world + .feature_flags() + .get("completion.insertion.add-argument-snippets"), + }; + + let items = match world.analysis().completions(position, &options)? { None => return Ok(None), Some(items) => items, }; -- cgit v1.2.3 From 14094e44770559c13a1e8bdfcfb989d3bedd00d8 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 10 Mar 2020 18:56:15 +0100 Subject: Move FeatureFlags --- crates/ra_ide/src/lib.rs | 16 +----- crates/ra_ide_db/src/feature_flags.rs | 77 -------------------------- crates/ra_ide_db/src/lib.rs | 10 +--- crates/rust-analyzer/src/cli/load_cargo.rs | 4 +- crates/rust-analyzer/src/feature_flags.rs | 77 ++++++++++++++++++++++++++ crates/rust-analyzer/src/lib.rs | 1 + crates/rust-analyzer/src/main_loop.rs | 7 ++- crates/rust-analyzer/src/main_loop/handlers.rs | 10 ++-- crates/rust-analyzer/src/world.rs | 18 +++--- 9 files changed, 101 insertions(+), 119 deletions(-) delete mode 100644 crates/ra_ide_db/src/feature_flags.rs create mode 100644 crates/rust-analyzer/src/feature_flags.rs diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs index d888bb745..9f45003d3 100644 --- a/crates/ra_ide/src/lib.rs +++ b/crates/ra_ide/src/lib.rs @@ -84,7 +84,6 @@ pub use ra_db::{ }; pub use ra_ide_db::{ change::{AnalysisChange, LibraryData}, - feature_flags::FeatureFlags, line_index::{LineCol, LineIndex}, line_index_utils::translate_offset_with_edit, search::SearchScope, @@ -131,13 +130,13 @@ pub struct AnalysisHost { impl Default for AnalysisHost { fn default() -> AnalysisHost { - AnalysisHost::new(None, FeatureFlags::default()) + AnalysisHost::new(None) } } impl AnalysisHost { - pub fn new(lru_capcity: Option, feature_flags: FeatureFlags) -> AnalysisHost { - AnalysisHost { db: RootDatabase::new(lru_capcity, feature_flags) } + pub fn new(lru_capacity: Option) -> AnalysisHost { + AnalysisHost { db: RootDatabase::new(lru_capacity) } } /// Returns a snapshot of the current state, which you can query for /// semantic information. @@ -145,10 +144,6 @@ impl AnalysisHost { Analysis { db: self.db.snapshot() } } - pub fn feature_flags(&self) -> &FeatureFlags { - &self.db.feature_flags - } - /// Applies changes to the current state of the world. If there are /// outstanding snapshots, they will be canceled. pub fn apply_change(&mut self, change: AnalysisChange) { @@ -224,11 +219,6 @@ impl Analysis { (host.analysis(), file_id) } - /// Features for Analysis. - pub fn feature_flags(&self) -> &FeatureFlags { - &self.db.feature_flags - } - /// Debug info about the current state of the analysis. pub fn status(&self) -> Cancelable { self.with_db(|db| status::status(&*db)) diff --git a/crates/ra_ide_db/src/feature_flags.rs b/crates/ra_ide_db/src/feature_flags.rs deleted file mode 100644 index dbb3f50a0..000000000 --- a/crates/ra_ide_db/src/feature_flags.rs +++ /dev/null @@ -1,77 +0,0 @@ -//! See docs for `FeatureFlags`. - -use rustc_hash::FxHashMap; - -// FIXME: looks like a much better design is to pass options to each call, -// rather than to have a global ambient feature flags -- that way, the clients -// can issue two successive calls with different options. - -/// Feature flags hold fine-grained toggles for all *user-visible* features of -/// rust-analyzer. -/// -/// The exists such that users are able to disable any annoying feature (and, -/// with many users and many features, some features are bound to be annoying -/// for some users) -/// -/// Note that we purposefully use run-time checked strings, and not something -/// checked at compile time, to keep things simple and flexible. -/// -/// Also note that, at the moment, `FeatureFlags` also store features for -/// `rust-analyzer`. This should be benign layering violation. -#[derive(Debug)] -pub struct FeatureFlags { - flags: FxHashMap, -} - -impl FeatureFlags { - fn new(flags: &[(&str, bool)]) -> FeatureFlags { - let flags = flags - .iter() - .map(|&(name, value)| { - check_flag_name(name); - (name.to_string(), value) - }) - .collect(); - FeatureFlags { flags } - } - - pub fn set(&mut self, flag: &str, value: bool) -> Result<(), ()> { - match self.flags.get_mut(flag) { - None => Err(()), - Some(slot) => { - *slot = value; - Ok(()) - } - } - } - - pub fn get(&self, flag: &str) -> bool { - match self.flags.get(flag) { - None => panic!("unknown flag: {:?}", flag), - Some(value) => *value, - } - } -} - -impl Default for FeatureFlags { - fn default() -> FeatureFlags { - FeatureFlags::new(&[ - ("lsp.diagnostics", true), - ("completion.insertion.add-call-parenthesis", true), - ("completion.insertion.add-argument-snippets", true), - ("completion.enable-postfix", true), - ("call-info.full", true), - ("notifications.workspace-loaded", true), - ("notifications.cargo-toml-not-found", true), - ]) - } -} - -fn check_flag_name(flag: &str) { - for c in flag.bytes() { - match c { - b'a'..=b'z' | b'-' | b'.' => (), - _ => panic!("flag name does not match conventions: {:?}", flag), - } - } -} diff --git a/crates/ra_ide_db/src/lib.rs b/crates/ra_ide_db/src/lib.rs index a105c7556..6bcccc848 100644 --- a/crates/ra_ide_db/src/lib.rs +++ b/crates/ra_ide_db/src/lib.rs @@ -5,7 +5,6 @@ pub mod marks; pub mod line_index; pub mod line_index_utils; -pub mod feature_flags; pub mod symbol_index; pub mod change; pub mod defs; @@ -22,7 +21,7 @@ use ra_db::{ }; use rustc_hash::FxHashMap; -use crate::{feature_flags::FeatureFlags, line_index::LineIndex, symbol_index::SymbolsDatabase}; +use crate::{line_index::LineIndex, symbol_index::SymbolsDatabase}; #[salsa::database( ra_db::SourceDatabaseStorage, @@ -37,7 +36,6 @@ use crate::{feature_flags::FeatureFlags, line_index::LineIndex, symbol_index::Sy #[derive(Debug)] pub struct RootDatabase { runtime: salsa::Runtime, - pub feature_flags: Arc, pub(crate) debug_data: Arc, pub last_gc: crate::wasm_shims::Instant, pub last_gc_check: crate::wasm_shims::Instant, @@ -82,17 +80,16 @@ impl salsa::Database for RootDatabase { impl Default for RootDatabase { fn default() -> RootDatabase { - RootDatabase::new(None, FeatureFlags::default()) + RootDatabase::new(None) } } impl RootDatabase { - pub fn new(lru_capacity: Option, feature_flags: FeatureFlags) -> RootDatabase { + pub fn new(lru_capacity: Option) -> RootDatabase { let mut db = RootDatabase { runtime: salsa::Runtime::default(), last_gc: crate::wasm_shims::Instant::now(), last_gc_check: crate::wasm_shims::Instant::now(), - feature_flags: Arc::new(feature_flags), debug_data: Default::default(), }; db.set_crate_graph_with_durability(Default::default(), Durability::HIGH); @@ -112,7 +109,6 @@ impl salsa::ParallelDatabase for RootDatabase { runtime: self.runtime.snapshot(self), last_gc: self.last_gc, last_gc_check: self.last_gc_check, - feature_flags: Arc::clone(&self.feature_flags), debug_data: Arc::clone(&self.debug_data), }) } diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs index 4be987860..5df29a383 100644 --- a/crates/rust-analyzer/src/cli/load_cargo.rs +++ b/crates/rust-analyzer/src/cli/load_cargo.rs @@ -6,7 +6,7 @@ use std::path::Path; use anyhow::Result; use crossbeam_channel::{unbounded, Receiver}; use ra_db::{CrateGraph, FileId, SourceRootId}; -use ra_ide::{AnalysisChange, AnalysisHost, FeatureFlags}; +use ra_ide::{AnalysisChange, AnalysisHost}; use ra_project_model::{get_rustc_cfg_options, PackageRoot, ProjectWorkspace}; use ra_vfs::{RootEntry, Vfs, VfsChange, VfsTask, Watch}; use rustc_hash::{FxHashMap, FxHashSet}; @@ -82,7 +82,7 @@ pub(crate) fn load( receiver: Receiver, ) -> AnalysisHost { let lru_cap = std::env::var("RA_LRU_CAP").ok().and_then(|it| it.parse::().ok()); - let mut host = AnalysisHost::new(lru_cap, FeatureFlags::default()); + let mut host = AnalysisHost::new(lru_cap); let mut analysis_change = AnalysisChange::new(); analysis_change.set_crate_graph(crate_graph); diff --git a/crates/rust-analyzer/src/feature_flags.rs b/crates/rust-analyzer/src/feature_flags.rs new file mode 100644 index 000000000..dbb3f50a0 --- /dev/null +++ b/crates/rust-analyzer/src/feature_flags.rs @@ -0,0 +1,77 @@ +//! See docs for `FeatureFlags`. + +use rustc_hash::FxHashMap; + +// FIXME: looks like a much better design is to pass options to each call, +// rather than to have a global ambient feature flags -- that way, the clients +// can issue two successive calls with different options. + +/// Feature flags hold fine-grained toggles for all *user-visible* features of +/// rust-analyzer. +/// +/// The exists such that users are able to disable any annoying feature (and, +/// with many users and many features, some features are bound to be annoying +/// for some users) +/// +/// Note that we purposefully use run-time checked strings, and not something +/// checked at compile time, to keep things simple and flexible. +/// +/// Also note that, at the moment, `FeatureFlags` also store features for +/// `rust-analyzer`. This should be benign layering violation. +#[derive(Debug)] +pub struct FeatureFlags { + flags: FxHashMap, +} + +impl FeatureFlags { + fn new(flags: &[(&str, bool)]) -> FeatureFlags { + let flags = flags + .iter() + .map(|&(name, value)| { + check_flag_name(name); + (name.to_string(), value) + }) + .collect(); + FeatureFlags { flags } + } + + pub fn set(&mut self, flag: &str, value: bool) -> Result<(), ()> { + match self.flags.get_mut(flag) { + None => Err(()), + Some(slot) => { + *slot = value; + Ok(()) + } + } + } + + pub fn get(&self, flag: &str) -> bool { + match self.flags.get(flag) { + None => panic!("unknown flag: {:?}", flag), + Some(value) => *value, + } + } +} + +impl Default for FeatureFlags { + fn default() -> FeatureFlags { + FeatureFlags::new(&[ + ("lsp.diagnostics", true), + ("completion.insertion.add-call-parenthesis", true), + ("completion.insertion.add-argument-snippets", true), + ("completion.enable-postfix", true), + ("call-info.full", true), + ("notifications.workspace-loaded", true), + ("notifications.cargo-toml-not-found", true), + ]) + } +} + +fn check_flag_name(flag: &str) { + for c in flag.bytes() { + match c { + b'a'..=b'z' | b'-' | b'.' => (), + _ => panic!("flag name does not match conventions: {:?}", flag), + } + } +} diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs index a0f968823..e50e47b19 100644 --- a/crates/rust-analyzer/src/lib.rs +++ b/crates/rust-analyzer/src/lib.rs @@ -37,6 +37,7 @@ mod config; mod world; mod diagnostics; mod semantic_tokens; +mod feature_flags; use serde::de::DeserializeOwned; diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 221f464b6..f9de712a0 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -18,7 +18,7 @@ use crossbeam_channel::{select, unbounded, RecvError, Sender}; use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response}; use lsp_types::{ClientCapabilities, NumberOrString}; use ra_cargo_watch::{url_from_path_with_drive_lowercasing, CheckOptions, CheckTask}; -use ra_ide::{Canceled, FeatureFlags, FileId, LibraryData, SourceRootId}; +use ra_ide::{Canceled, FileId, LibraryData, SourceRootId}; use ra_prof::profile; use ra_vfs::{VfsFile, VfsTask, Watch}; use relative_path::RelativePathBuf; @@ -28,6 +28,7 @@ use threadpool::ThreadPool; use crate::{ diagnostics::DiagnosticTask, + feature_flags::FeatureFlags, main_loop::{ pending_requests::{PendingRequest, PendingRequests}, subscriptions::Subscriptions, @@ -423,7 +424,7 @@ fn loop_turn( { loop_state.workspace_loaded = true; let n_packages: usize = world_state.workspaces.iter().map(|it| it.n_packages()).sum(); - if world_state.feature_flags().get("notifications.workspace-loaded") { + if world_state.feature_flags.get("notifications.workspace-loaded") { let msg = format!("workspace loaded, {} rust packages", n_packages); show_message(req::MessageType::Info, msg, &connection.sender); } @@ -839,7 +840,7 @@ fn update_file_notifications_on_threadpool( subscriptions: Vec, ) { log::trace!("updating notifications for {:?}", subscriptions); - let publish_diagnostics = world.feature_flags().get("lsp.diagnostics"); + let publish_diagnostics = world.feature_flags.get("lsp.diagnostics"); pool.execute(move || { for file_id in subscriptions { if publish_diagnostics { diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index 155f677a6..fcb40432d 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs @@ -425,12 +425,10 @@ pub fn handle_completion( } let options = CompletionOptions { - enable_postfix_completions: world.feature_flags().get("completion.enable-postfix"), - add_call_parenthesis: world - .feature_flags() - .get("completion.insertion.add-call-parenthesis"), + enable_postfix_completions: world.feature_flags.get("completion.enable-postfix"), + add_call_parenthesis: world.feature_flags.get("completion.insertion.add-call-parenthesis"), add_call_argument_snippets: world - .feature_flags() + .feature_flags .get("completion.insertion.add-argument-snippets"), }; @@ -471,7 +469,7 @@ pub fn handle_signature_help( let _p = profile("handle_signature_help"); let position = params.try_conv_with(&world)?; if let Some(call_info) = world.analysis().call_info(position)? { - let concise = !world.analysis().feature_flags().get("call-info.full"); + let concise = !world.feature_flags.get("call-info.full"); let mut active_parameter = call_info.active_parameter.map(|it| it as i64); if concise && call_info.signature.has_self_param { 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 6f394055a..1ddc3c1a5 100644 --- a/crates/rust-analyzer/src/world.rs +++ b/crates/rust-analyzer/src/world.rs @@ -13,8 +13,7 @@ use lsp_types::Url; use parking_lot::RwLock; use ra_cargo_watch::{url_from_path_with_drive_lowercasing, CheckOptions, CheckWatcher}; use ra_ide::{ - Analysis, AnalysisChange, AnalysisHost, CrateGraph, FeatureFlags, FileId, LibraryData, - SourceRootId, + Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, LibraryData, SourceRootId, }; use ra_project_model::{get_rustc_cfg_options, ProjectWorkspace}; use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot, VfsTask, Watch}; @@ -22,6 +21,7 @@ use relative_path::RelativePathBuf; use crate::{ diagnostics::{CheckFixes, DiagnosticCollection}, + feature_flags::FeatureFlags, main_loop::pending_requests::{CompletedRequest, LatestRequests}, vfs_glob::{Glob, RustPackageFilterBuilder}, LspError, Result, @@ -45,6 +45,7 @@ pub struct Options { #[derive(Debug)] pub struct WorldState { pub options: Options, + pub feature_flags: Arc, //FIXME: this belongs to `LoopState` rather than to `WorldState` pub roots_to_scan: usize, pub roots: Vec, @@ -60,6 +61,7 @@ pub struct WorldState { /// An immutable snapshot of the world's state at a point in time. pub struct WorldSnapshot { pub options: Options, + pub feature_flags: Arc, pub workspaces: Arc>, pub analysis: Analysis, pub latest_requests: Arc>, @@ -146,10 +148,11 @@ impl WorldState { CheckWatcher::dummy() }); - let mut analysis_host = AnalysisHost::new(lru_capacity, feature_flags); + let mut analysis_host = AnalysisHost::new(lru_capacity); analysis_host.apply_change(change); WorldState { options, + feature_flags: Arc::new(feature_flags), roots_to_scan, roots: folder_roots, workspaces: Arc::new(workspaces), @@ -216,6 +219,7 @@ impl WorldState { pub fn snapshot(&self) -> WorldSnapshot { WorldSnapshot { options: self.options.clone(), + feature_flags: Arc::clone(&self.feature_flags), workspaces: Arc::clone(&self.workspaces), analysis: self.analysis_host.analysis(), vfs: Arc::clone(&self.vfs), @@ -235,10 +239,6 @@ impl WorldState { pub fn complete_request(&mut self, request: CompletedRequest) { self.latest_requests.write().record(request) } - - pub fn feature_flags(&self) -> &FeatureFlags { - self.analysis_host.feature_flags() - } } impl WorldSnapshot { @@ -306,8 +306,4 @@ impl WorldSnapshot { let path = self.vfs.read().file2path(VfsFile(file_id.0)); self.workspaces.iter().find_map(|ws| ws.workspace_root_for(&path)) } - - pub fn feature_flags(&self) -> &FeatureFlags { - self.analysis.feature_flags() - } } -- cgit v1.2.3