Move FeatureFlags

This commit is contained in:
Aleksey Kladov
2020-03-10 18:56:15 +01:00
parent bf582e77d6
commit 14094e4477
8 changed files with 24 additions and 42 deletions

View File

@@ -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<VfsTask>,
) -> AnalysisHost {
let lru_cap = std::env::var("RA_LRU_CAP").ok().and_then(|it| it.parse::<usize>().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);

View File

@@ -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<String, bool>,
}
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),
}
}
}

View File

@@ -37,6 +37,7 @@ mod config;
mod world;
mod diagnostics;
mod semantic_tokens;
mod feature_flags;
use serde::de::DeserializeOwned;

View File

@@ -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<FileId>,
) {
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 {

View File

@@ -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));

View File

@@ -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<FeatureFlags>,
//FIXME: this belongs to `LoopState` rather than to `WorldState`
pub roots_to_scan: usize,
pub roots: Vec<PathBuf>,
@@ -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<FeatureFlags>,
pub workspaces: Arc<Vec<ProjectWorkspace>>,
pub analysis: Analysis,
pub latest_requests: Arc<RwLock<LatestRequests>>,
@@ -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()
}
}