Unnamed repository; edit this file 'description' to name the repository.
Auto merge of #16639 - alibektas:13529/config_restruct, r=Veykril
internal : redesign rust-analyzer::config This PR aims to cover the infrastructural requirements for the `rust-analyzer.toml` ( #13529 ) issue. This means, that 1. We no longer have a single config base. The once single `ConfigData` has been divided into 4 : A tree of `.ratoml` files, a set of configs coming from the client ( this is what was called before the `CrateData` except that now values do not default to anything when they are not defined) , a set of configs that will reflect what the contents of a `ratoml` file defined in user's config directory ( e.g `~/.config/rust-analyzer/.rust-analyzer.toml` and finally a tree root that is populated by default values only. 2. Configs have also been divided into 3 different blocks : `global` , `local` , `client`. The current status of a config may change until #13529 got merged. Once again many thanks to `@cormacrelf` for doing all the serde work.
bors 2024-04-16
parent e64610d · parent 60d3a73 · commit 1179c3e
-rw-r--r--Cargo.lock55
-rw-r--r--crates/base-db/src/input.rs7
-rw-r--r--crates/ide/src/expand_macro.rs8
-rw-r--r--crates/ide/src/lib.rs9
-rw-r--r--crates/project-model/src/cfg_flag.rs3
-rw-r--r--crates/project-model/src/project_json.rs22
-rw-r--r--crates/rust-analyzer/Cargo.toml2
-rw-r--r--crates/rust-analyzer/src/config.rs2027
-rw-r--r--crates/rust-analyzer/src/diagnostics.rs4
-rw-r--r--crates/rust-analyzer/src/global_state.rs2
-rw-r--r--crates/rust-analyzer/src/handlers/request.rs63
-rw-r--r--crates/rust-analyzer/src/lsp/to_proto.rs4
-rw-r--r--crates/rust-analyzer/src/main_loop.rs2
-rw-r--r--crates/rust-analyzer/src/reload.rs4
-rw-r--r--docs/user/generated_config.adoc89
15 files changed, 1380 insertions, 921 deletions
diff --git a/Cargo.lock b/Cargo.lock
index e786563c39..20bd36b894 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -781,6 +781,7 @@ checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4"
dependencies = [
"equivalent",
"hashbrown",
+ "serde",
]
[[package]]
@@ -1594,6 +1595,7 @@ dependencies = [
"ide",
"ide-db",
"ide-ssr",
+ "indexmap",
"itertools",
"load-cargo",
"lsp-server 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1622,6 +1624,7 @@ dependencies = [
"test-fixture",
"test-utils",
"tikv-jemallocator",
+ "toml",
"toolchain",
"tracing",
"tracing-subscriber",
@@ -1776,6 +1779,15 @@ dependencies = [
]
[[package]]
+name = "serde_spanned"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1"
+dependencies = [
+ "serde",
+]
+
+[[package]]
name = "sharded-slab"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2027,6 +2039,40 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
+name = "toml"
+version = "0.8.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35"
+dependencies = [
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "toml_edit",
+]
+
+[[package]]
+name = "toml_datetime"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.21.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03"
+dependencies = [
+ "indexmap",
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "winnow",
+]
+
+[[package]]
name = "toolchain"
version = "0.0.0"
dependencies = [
@@ -2403,6 +2449,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
[[package]]
+name = "winnow"
+version = "0.5.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8434aeec7b290e8da5c3f0d628cb0eac6cabcb31d14bb74f779a08109a5914d6"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
name = "write-json"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs
index 1924ce578a..6a8ab71624 100644
--- a/crates/base-db/src/input.rs
+++ b/crates/base-db/src/input.rs
@@ -19,6 +19,10 @@ use vfs::{file_set::FileSet, AbsPathBuf, AnchoredPath, FileId, VfsPath};
// Map from crate id to the name of the crate and path of the proc-macro. If the value is `None`,
// then the crate for the proc-macro hasn't been build yet as the build data is missing.
pub type ProcMacroPaths = FxHashMap<CrateId, Result<(Option<String>, AbsPathBuf), String>>;
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
+pub struct SourceRootId(pub u32);
+
/// Files are grouped into source roots. A source root is a directory on the
/// file systems which is watched for changes. Typically it corresponds to a
/// Rust crate. Source roots *might* be nested: in this case, a file belongs to
@@ -26,9 +30,6 @@ pub type ProcMacroPaths = FxHashMap<CrateId, Result<(Option<String>, AbsPathBuf)
/// source root, and the analyzer does not know the root path of the source root at
/// all. So, a file from one source root can't refer to a file in another source
/// root by path.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
-pub struct SourceRootId(pub u32);
-
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SourceRoot {
/// Sysroot or crates.io library.
diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs
index 4b0961cbbe..e2d629a02f 100644
--- a/crates/ide/src/expand_macro.rs
+++ b/crates/ide/src/expand_macro.rs
@@ -177,7 +177,9 @@ fn _format(
use ide_db::base_db::{FileLoader, SourceDatabase};
// hack until we get hygiene working (same character amount to preserve formatting as much as possible)
const DOLLAR_CRATE_REPLACE: &str = "__r_a_";
- let expansion = expansion.replace("$crate", DOLLAR_CRATE_REPLACE);
+ const BUILTIN_REPLACE: &str = "builtin__POUND";
+ let expansion =
+ expansion.replace("$crate", DOLLAR_CRATE_REPLACE).replace("builtin #", BUILTIN_REPLACE);
let (prefix, suffix) = match kind {
SyntaxKind::MACRO_PAT => ("fn __(", ": u32);"),
SyntaxKind::MACRO_EXPR | SyntaxKind::MACRO_STMTS => ("fn __() {", "}"),
@@ -206,7 +208,9 @@ fn _format(
let captured_stdout = String::from_utf8(output.stdout).ok()?;
if output.status.success() && !captured_stdout.trim().is_empty() {
- let output = captured_stdout.replace(DOLLAR_CRATE_REPLACE, "$crate");
+ let output = captured_stdout
+ .replace(DOLLAR_CRATE_REPLACE, "$crate")
+ .replace(BUILTIN_REPLACE, "builtin #");
let output = output.trim().strip_prefix(prefix)?;
let output = match kind {
SyntaxKind::MACRO_PAT => {
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 5f5af20ac5..431aa30e56 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -66,7 +66,7 @@ use hir::ChangeWithProcMacros;
use ide_db::{
base_db::{
salsa::{self, ParallelDatabase},
- CrateOrigin, Env, FileLoader, FileSet, SourceDatabase, VfsPath,
+ CrateOrigin, Env, FileLoader, FileSet, SourceDatabase, SourceDatabaseExt, VfsPath,
},
prime_caches, symbol_index, FxHashMap, FxIndexSet, LineIndexDatabase,
};
@@ -273,6 +273,10 @@ impl Analysis {
self.with_db(|db| status::status(db, file_id))
}
+ pub fn source_root(&self, file_id: FileId) -> Cancellable<SourceRootId> {
+ self.with_db(|db| db.file_source_root(file_id))
+ }
+
pub fn parallel_prime_caches<F>(&self, num_worker_threads: u8, cb: F) -> Cancellable<()>
where
F: Fn(ParallelPrimeCachesProgress) + Sync + std::panic::UnwindSafe,
@@ -282,7 +286,7 @@ impl Analysis {
/// Gets the text of the source file.
pub fn file_text(&self, file_id: FileId) -> Cancellable<Arc<str>> {
- self.with_db(|db| db.file_text(file_id))
+ self.with_db(|db| SourceDatabaseExt::file_text(db, file_id))
}
/// Gets the syntax tree of the file.
@@ -292,7 +296,6 @@ impl Analysis {
/// Returns true if this file belongs to an immutable library.
pub fn is_library_file(&self, file_id: FileId) -> Cancellable<bool> {
- use ide_db::base_db::SourceDatabaseExt;
self.with_db(|db| db.source_root(db.file_source_root(file_id)).is_library)
}
diff --git a/crates/project-model/src/cfg_flag.rs b/crates/project-model/src/cfg_flag.rs
index af682904b1..6192e18da0 100644
--- a/crates/project-model/src/cfg_flag.rs
+++ b/crates/project-model/src/cfg_flag.rs
@@ -4,8 +4,9 @@
use std::{fmt, str::FromStr};
use cfg::CfgOptions;
+use serde::Serialize;
-#[derive(Clone, Eq, PartialEq, Debug)]
+#[derive(Clone, Eq, PartialEq, Debug, Serialize)]
pub enum CfgFlag {
Atom(String),
KeyValue { key: String, value: String },
diff --git a/crates/project-model/src/project_json.rs b/crates/project-model/src/project_json.rs
index 1872d27c56..a8e30d2267 100644
--- a/crates/project-model/src/project_json.rs
+++ b/crates/project-model/src/project_json.rs
@@ -52,7 +52,7 @@
use base_db::{CrateDisplayName, CrateName};
use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
use rustc_hash::FxHashMap;
-use serde::{de, Deserialize};
+use serde::{de, Deserialize, Serialize};
use span::Edition;
use crate::cfg_flag::CfgFlag;
@@ -161,14 +161,14 @@ impl ProjectJson {
}
}
-#[derive(Deserialize, Debug, Clone)]
+#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ProjectJsonData {
sysroot: Option<Utf8PathBuf>,
sysroot_src: Option<Utf8PathBuf>,
crates: Vec<CrateData>,
}
-#[derive(Deserialize, Debug, Clone)]
+#[derive(Serialize, Deserialize, Debug, Clone)]
struct CrateData {
display_name: Option<String>,
root_module: Utf8PathBuf,
@@ -190,7 +190,7 @@ struct CrateData {
repository: Option<String>,
}
-#[derive(Deserialize, Debug, Clone)]
+#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename = "edition")]
enum EditionData {
#[serde(rename = "2015")]
@@ -218,20 +218,21 @@ impl From<EditionData> for Edition {
///
/// This will differ from `CrateId` when multiple `ProjectJson`
/// workspaces are loaded.
-#[derive(Deserialize, Debug, Clone, Copy, Eq, PartialEq, Hash)]
+#[derive(Serialize, Deserialize, Debug, Clone, Copy, Eq, PartialEq, Hash)]
#[serde(transparent)]
pub struct CrateArrayIdx(pub usize);
-#[derive(Deserialize, Debug, Clone, Eq, PartialEq)]
+#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
pub(crate) struct Dep {
/// Identifies a crate by position in the crates array.
#[serde(rename = "crate")]
pub(crate) krate: CrateArrayIdx,
+ #[serde(serialize_with = "serialize_crate_name")]
#[serde(deserialize_with = "deserialize_crate_name")]
pub(crate) name: CrateName,
}
-#[derive(Deserialize, Debug, Clone)]
+#[derive(Serialize, Deserialize, Debug, Clone)]
struct CrateSource {
include_dirs: Vec<Utf8PathBuf>,
exclude_dirs: Vec<Utf8PathBuf>,
@@ -244,3 +245,10 @@ where
let name = String::deserialize(de)?;
CrateName::new(&name).map_err(|err| de::Error::custom(format!("invalid crate name: {err:?}")))
}
+
+fn serialize_crate_name<S>(name: &CrateName, se: S) -> Result<S::Ok, S::Error>
+where
+ S: serde::Serializer,
+{
+ se.serialize_str(name)
+}
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index 6d70124188..1cc3343e5f 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -39,11 +39,13 @@ tracing.workspace = true
tracing-subscriber.workspace = true
tracing-tree.workspace = true
triomphe.workspace = true
+toml = "0.8.8"
nohash-hasher.workspace = true
always-assert = "0.2.0"
walkdir = "2.3.2"
semver.workspace = true
memchr = "2.7.1"
+indexmap = { workspace = true, features = ["serde"] }
cfg.workspace = true
flycheck.workspace = true
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 5890af17eb..14a4185654 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -6,7 +6,6 @@
//! Of particular interest is the `feature_flags` hash map: while other fields
//! configure the server itself, feature flags are passed into analysis, and
//! tweak things like automatic insertion of `()` in completions.
-
use std::{fmt, iter, ops::Not};
use cfg::{CfgAtom, CfgDiff};
@@ -15,12 +14,13 @@ use ide::{
AssistConfig, CallableSnippets, CompletionConfig, DiagnosticsConfig, ExprFillDefaultMode,
HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayFieldsToResolve,
InlayHintsConfig, JoinLinesConfig, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind,
- Snippet, SnippetScope,
+ Snippet, SnippetScope, SourceRootId,
};
use ide_db::{
imports::insert_use::{ImportGranularity, InsertUseConfig, PrefixKind},
SnippetCap,
};
+use indexmap::IndexMap;
use itertools::Itertools;
use lsp_types::{ClientCapabilities, MarkupKind};
use paths::{Utf8Path, Utf8PathBuf};
@@ -29,7 +29,7 @@ use project_model::{
};
use rustc_hash::{FxHashMap, FxHashSet};
use semver::Version;
-use serde::{de::DeserializeOwned, Deserialize};
+use serde::{de::DeserializeOwned, Deserialize, Serialize};
use stdx::format_to_acc;
use vfs::{AbsPath, AbsPathBuf};
@@ -59,38 +59,45 @@ mod patch_old_style;
// To deprecate an option by replacing it with another name use `new_name | `old_name` so that we keep
// parsing the old name.
config_data! {
- struct ConfigData {
+ /// Configs that apply on a workspace-wide scope. There are 3 levels on which a global configuration can be configured
+ ///
+ /// 1. `rust-analyzer.toml` file under user's config directory (e.g ~/.config/rust-analyzer.toml)
+ /// 2. Client's own configurations (e.g `settings.json` on VS Code)
+ /// 3. `rust-analyzer.toml` file located at the workspace root
+ ///
+ /// A config is searched for by traversing a "config tree" in a bottom up fashion. It is chosen by the nearest first principle.
+ global: struct GlobalDefaultConfigData <- GlobalConfigInput -> {
/// Whether to insert #[must_use] when generating `as_` methods
/// for enum variants.
- assist_emitMustUse: bool = "false",
+ assist_emitMustUse: bool = false,
/// Placeholder expression to use for missing expressions in assists.
- assist_expressionFillDefault: ExprFillDefaultDef = "\"todo\"",
+ assist_expressionFillDefault: ExprFillDefaultDef = ExprFillDefaultDef::Todo,
/// Warm up caches on project load.
- cachePriming_enable: bool = "true",
+ cachePriming_enable: bool = true,
/// How many worker threads to handle priming caches. The default `0` means to pick automatically.
- cachePriming_numThreads: ParallelCachePrimingNumThreads = "0",
+ cachePriming_numThreads: ParallelCachePrimingNumThreads = 0u8,
/// Pass `--all-targets` to cargo invocation.
- cargo_allTargets: bool = "true",
+ cargo_allTargets: bool = true,
/// Automatically refresh project info via `cargo metadata` on
/// `Cargo.toml` or `.cargo/config.toml` changes.
- cargo_autoreload: bool = "true",
+ pub(crate) cargo_autoreload: bool = true,
/// Run build scripts (`build.rs`) for more precise code analysis.
- cargo_buildScripts_enable: bool = "true",
+ cargo_buildScripts_enable: bool = true,
/// Specifies the working directory for running build scripts.
/// - "workspace": run build scripts for a workspace in the workspace's root directory.
/// This is incompatible with `#rust-analyzer.cargo.buildScripts.invocationStrategy#` set to `once`.
/// - "root": run build scripts in the project's root directory.
/// This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`
/// is set.
- cargo_buildScripts_invocationLocation: InvocationLocation = "\"workspace\"",
+ cargo_buildScripts_invocationLocation: InvocationLocation = InvocationLocation::Workspace,
/// Specifies the invocation strategy to use when running the build scripts command.
/// If `per_workspace` is set, the command will be executed for each workspace.
/// If `once` is set, the command will be executed once.
/// This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`
/// is set.
- cargo_buildScripts_invocationStrategy: InvocationStrategy = "\"per_workspace\"",
+ cargo_buildScripts_invocationStrategy: InvocationStrategy = InvocationStrategy::PerWorkspace,
/// Override the command rust-analyzer uses to run build scripts and
/// build procedural macros. The command is required to output json
/// and should therefore include `--message-format=json` or a similar
@@ -109,81 +116,81 @@ config_data! {
/// cargo check --quiet --workspace --message-format=json --all-targets
/// ```
/// .
- cargo_buildScripts_overrideCommand: Option<Vec<String>> = "null",
+ cargo_buildScripts_overrideCommand: Option<Vec<String>> = None,
/// Rerun proc-macros building/build-scripts running when proc-macro
/// or build-script sources change and are saved.
- cargo_buildScripts_rebuildOnSave: bool = "true",
+ cargo_buildScripts_rebuildOnSave: bool = true,
/// Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to
/// avoid checking unnecessary things.
- cargo_buildScripts_useRustcWrapper: bool = "true",
+ cargo_buildScripts_useRustcWrapper: bool = true,
/// List of cfg options to enable with the given values.
- cargo_cfgs: FxHashMap<String, String> = "{}",
+ cargo_cfgs: FxHashMap<String, String> = FxHashMap::default(),
/// Extra arguments that are passed to every cargo invocation.
- cargo_extraArgs: Vec<String> = "[]",
+ cargo_extraArgs: Vec<String> = vec![],
/// Extra environment variables that will be set when running cargo, rustc
/// or other commands within the workspace. Useful for setting RUSTFLAGS.
- cargo_extraEnv: FxHashMap<String, String> = "{}",
+ cargo_extraEnv: FxHashMap<String, String> = FxHashMap::default(),
/// List of features to activate.
///
/// Set this to `"all"` to pass `--all-features` to cargo.
- cargo_features: CargoFeaturesDef = "[]",
+ cargo_features: CargoFeaturesDef = CargoFeaturesDef::Selected(vec![]),
/// Whether to pass `--no-default-features` to cargo.
- cargo_noDefaultFeatures: bool = "false",
+ cargo_noDefaultFeatures: bool = false,
/// Relative path to the sysroot, or "discover" to try to automatically find it via
/// "rustc --print sysroot".
///
/// Unsetting this disables sysroot loading.
///
/// This option does not take effect until rust-analyzer is restarted.
- cargo_sysroot: Option<String> = "\"discover\"",
+ cargo_sysroot: Option<String> = Some("discover".to_owned()),
/// Whether to run cargo metadata on the sysroot library allowing rust-analyzer to analyze
/// third-party dependencies of the standard libraries.
///
/// This will cause `cargo` to create a lockfile in your sysroot directory. rust-analyzer
/// will attempt to clean up afterwards, but nevertheless requires the location to be
/// writable to.
- cargo_sysrootQueryMetadata: bool = "false",
+ cargo_sysrootQueryMetadata: bool = false,
/// Relative path to the sysroot library sources. If left unset, this will default to
/// `{cargo.sysroot}/lib/rustlib/src/rust/library`.
///
/// This option does not take effect until rust-analyzer is restarted.
- cargo_sysrootSrc: Option<String> = "null",
+ cargo_sysrootSrc: Option<String> = None,
/// Compilation target override (target triple).
// FIXME(@poliorcetics): move to multiple targets here too, but this will need more work
// than `checkOnSave_target`
- cargo_target: Option<String> = "null",
+ cargo_target: Option<String> = None,
/// Optional path to a rust-analyzer specific target directory.
/// This prevents rust-analyzer's `cargo check` and initial build-script and proc-macro
/// building from locking the `Cargo.lock` at the expense of duplicating build artifacts.
///
/// Set to `true` to use a subdirectory of the existing target directory or
/// set to a path relative to the workspace to use that path.
- cargo_targetDir | rust_analyzerTargetDir: Option<TargetDirectory> = "null",
+ cargo_targetDir | rust_analyzerTargetDir: Option<TargetDirectory> = None,
/// Unsets the implicit `#[cfg(test)]` for the specified crates.
- cargo_unsetTest: Vec<String> = "[\"core\"]",
+ cargo_unsetTest: Vec<String> = vec!["core".to_owned()],
/// Run the check command for diagnostics on save.
- checkOnSave | checkOnSave_enable: bool = "true",
+ checkOnSave | checkOnSave_enable: bool = true,
/// Check all targets and tests (`--all-targets`). Defaults to
/// `#rust-analyzer.cargo.allTargets#`.
- check_allTargets | checkOnSave_allTargets: Option<bool> = "null",
+ check_allTargets | checkOnSave_allTargets: Option<bool> = None,
/// Cargo command to use for `cargo check`.
- check_command | checkOnSave_command: String = "\"check\"",
+ check_command | checkOnSave_command: String = "check".to_owned(),
/// Extra arguments for `cargo check`.
- check_extraArgs | checkOnSave_extraArgs: Vec<String> = "[]",
+ check_extraArgs | checkOnSave_extraArgs: Vec<String> = vec![],
/// Extra environment variables that will be set when running `cargo check`.
/// Extends `#rust-analyzer.cargo.extraEnv#`.
- check_extraEnv | checkOnSave_extraEnv: FxHashMap<String, String> = "{}",
+ check_extraEnv | checkOnSave_extraEnv: FxHashMap<String, String> = FxHashMap::default(),
/// List of features to activate. Defaults to
/// `#rust-analyzer.cargo.features#`.
///
/// Set to `"all"` to pass `--all-features` to Cargo.
- check_features | checkOnSave_features: Option<CargoFeaturesDef> = "null",
+ check_features | checkOnSave_features: Option<CargoFeaturesDef> = None,
/// List of `cargo check` (or other command specified in `check.command`) diagnostics to ignore.
///
/// For example for `cargo check`: `dead_code`, `unused_imports`, `unused_variables`,...
- check_ignore: FxHashSet<String> = "[]",
+ check_ignore: FxHashSet<String> = FxHashSet::default(),
/// Specifies the working directory for running checks.
/// - "workspace": run checks for workspaces in the corresponding workspaces' root directories.
// FIXME: Ideally we would support this in some way
@@ -191,16 +198,16 @@ config_data! {
/// - "root": run checks in the project's root directory.
/// This config only has an effect when `#rust-analyzer.check.overrideCommand#`
/// is set.
- check_invocationLocation | checkOnSave_invocationLocation: InvocationLocation = "\"workspace\"",
+ check_invocationLocation | checkOnSave_invocationLocation: InvocationLocation = InvocationLocation::Workspace,
/// Specifies the invocation strategy to use when running the check command.
/// If `per_workspace` is set, the command will be executed for each workspace.
/// If `once` is set, the command will be executed once.
/// This config only has an effect when `#rust-analyzer.check.overrideCommand#`
/// is set.
- check_invocationStrategy | checkOnSave_invocationStrategy: InvocationStrategy = "\"per_workspace\"",
+ check_invocationStrategy | checkOnSave_invocationStrategy: InvocationStrategy = InvocationStrategy::PerWorkspace,
/// Whether to pass `--no-default-features` to Cargo. Defaults to
/// `#rust-analyzer.cargo.noDefaultFeatures#`.
- check_noDefaultFeatures | checkOnSave_noDefaultFeatures: Option<bool> = "null",
+ check_noDefaultFeatures | checkOnSave_noDefaultFeatures: Option<bool> = None,
/// Override the command rust-analyzer uses instead of `cargo check` for
/// diagnostics on save. The command is required to output json and
/// should therefore include `--message-format=json` or a similar option
@@ -228,309 +235,163 @@ config_data! {
/// cargo check --workspace --message-format=json --all-targets
/// ```
/// .
- check_overrideCommand | checkOnSave_overrideCommand: Option<Vec<String>> = "null",
+ check_overrideCommand | checkOnSave_overrideCommand: Option<Vec<String>> = None,
/// Check for specific targets. Defaults to `#rust-analyzer.cargo.target#` if empty.
///
/// Can be a single target, e.g. `"x86_64-unknown-linux-gnu"` or a list of targets, e.g.
/// `["aarch64-apple-darwin", "x86_64-apple-darwin"]`.
///
/// Aliased as `"checkOnSave.targets"`.
- check_targets | checkOnSave_targets | checkOnSave_target: Option<CheckOnSaveTargets> = "null",
+ check_targets | checkOnSave_targets | checkOnSave_target: Option<CheckOnSaveTargets> = None,
/// Whether `--workspace` should be passed to `cargo check`.
/// If false, `-p <package>` will be passed instead.
- check_workspace: bool = "true",
-
- /// Toggles the additional completions that automatically add imports when completed.
- /// Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.
- completion_autoimport_enable: bool = "true",
- /// Toggles the additional completions that automatically show method calls and field accesses
- /// with `self` prefixed to them when inside a method.
- completion_autoself_enable: bool = "true",
- /// Whether to add parenthesis and argument snippets when completing function.
- completion_callable_snippets: CallableCompletionDef = "\"fill_arguments\"",
- /// Whether to show full function/method signatures in completion docs.
- completion_fullFunctionSignatures_enable: bool = "false",
- /// Maximum number of completions to return. If `None`, the limit is infinite.
- completion_limit: Option<usize> = "null",
- /// Whether to show postfix snippets like `dbg`, `if`, `not`, etc.
- completion_postfix_enable: bool = "true",
- /// Enables completions of private items and fields that are defined in the current workspace even if they are not visible at the current position.
- completion_privateEditable_enable: bool = "false",
- /// Custom completion snippets.
- // NOTE: Keep this list in sync with the feature docs of user snippets.
- completion_snippets_custom: FxHashMap<String, SnippetDef> = r#"{
- "Arc::new": {
- "postfix": "arc",
- "body": "Arc::new(${receiver})",
- "requires": "std::sync::Arc",
- "description": "Put the expression into an `Arc`",
- "scope": "expr"
- },
- "Rc::new": {
- "postfix": "rc",
- "body": "Rc::new(${receiver})",
- "requires": "std::rc::Rc",
- "description": "Put the expression into an `Rc`",
- "scope": "expr"
- },
- "Box::pin": {
- "postfix": "pinbox",
- "body": "Box::pin(${receiver})",
- "requires": "std::boxed::Box",
- "description": "Put the expression into a pinned `Box`",
- "scope": "expr"
- },
- "Ok": {
- "postfix": "ok",
- "body": "Ok(${receiver})",
- "description": "Wrap the expression in a `Result::Ok`",
- "scope": "expr"
- },
- "Err": {
- "postfix": "err",
- "body": "Err(${receiver})",
- "description": "Wrap the expression in a `Result::Err`",
- "scope": "expr"
- },
- "Some": {
- "postfix": "some",
- "body": "Some(${receiver})",
- "description": "Wrap the expression in an `Option::Some`",
- "scope": "expr"
- }
- }"#,
- /// Whether to enable term search based snippets like `Some(foo.bar().baz())`.
- completion_termSearch_enable: bool = "false",
+ check_workspace: bool = true,
/// List of rust-analyzer diagnostics to disable.
- diagnostics_disabled: FxHashSet<String> = "[]",
+ diagnostics_disabled: FxHashSet<String> = FxHashSet::default(),
/// Whether to show native rust-analyzer diagnostics.
- diagnostics_enable: bool = "true",
+ diagnostics_enable: bool = true,
/// Whether to show experimental rust-analyzer diagnostics that might
/// have more false positives than usual.
- diagnostics_experimental_enable: bool = "false",
+ diagnostics_experimental_enable: bool = false,
/// Map of prefixes to be substituted when parsing diagnostic file paths.
/// This should be the reverse mapping of what is passed to `rustc` as `--remap-path-prefix`.
- diagnostics_remapPrefix: FxHashMap<String, String> = "{}",
+ diagnostics_remapPrefix: FxHashMap<String, String> = FxHashMap::default(),
/// Whether to run additional style lints.
- diagnostics_styleLints_enable: bool = "false",
+ diagnostics_styleLints_enable: bool = false,
/// List of warnings that should be displayed with hint severity.
///
/// The warnings will be indicated by faded text or three dots in code
/// and will not show up in the `Problems Panel`.
- diagnostics_warningsAsHint: Vec<String> = "[]",
+ diagnostics_warningsAsHint: Vec<String> = vec![],
/// List of warnings that should be displayed with info severity.
///
/// The warnings will be indicated by a blue squiggly underline in code
/// and a blue icon in the `Problems Panel`.
- diagnostics_warningsAsInfo: Vec<String> = "[]",
+ diagnostics_warningsAsInfo: Vec<String> = vec![],
/// These directories will be ignored by rust-analyzer. They are
/// relative to the workspace root, and globs are not supported. You may
/// also need to add the folders to Code's `files.watcherExclude`.
- files_excludeDirs: Vec<Utf8PathBuf> = "[]",
+ files_excludeDirs: Vec<Utf8PathBuf> = vec![],
/// Controls file watching implementation.
- files_watcher: FilesWatcherDef = "\"client\"",
-
- /// Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords.
- highlightRelated_breakPoints_enable: bool = "true",
- /// Enables highlighting of all captures of a closure while the cursor is on the `|` or move keyword of a closure.
- highlightRelated_closureCaptures_enable: bool = "true",
- /// Enables highlighting of all exit points while the cursor is on any `return`, `?`, `fn`, or return type arrow (`->`).
- highlightRelated_exitPoints_enable: bool = "true",
- /// Enables highlighting of related references while the cursor is on any identifier.
- highlightRelated_references_enable: bool = "true",
- /// Enables highlighting of all break points for a loop or block context while the cursor is on any `async` or `await` keywords.
- highlightRelated_yieldPoints_enable: bool = "true",
+ files_watcher: FilesWatcherDef = FilesWatcherDef::Client,
/// Whether to show `Debug` action. Only applies when
/// `#rust-analyzer.hover.actions.enable#` is set.
- hover_actions_debug_enable: bool = "true",
+ hover_actions_debug_enable: bool = true,
/// Whether to show HoverActions in Rust files.
- hover_actions_enable: bool = "true",
+ hover_actions_enable: bool = true,
/// Whether to show `Go to Type Definition` action. Only applies when
/// `#rust-analyzer.hover.actions.enable#` is set.
- hover_actions_gotoTypeDef_enable: bool = "true",
+ hover_actions_gotoTypeDef_enable: bool = true,
/// Whether to show `Implementations` action. Only applies when
/// `#rust-analyzer.hover.actions.enable#` is set.
- hover_actions_implementations_enable: bool = "true",
+ hover_actions_implementations_enable: bool = true,
/// Whether to show `References` action. Only applies when
/// `#rust-analyzer.hover.actions.enable#` is set.
- hover_actions_references_enable: bool = "false",
+ hover_actions_references_enable: bool = false,
/// Whether to show `Run` action. Only applies when
/// `#rust-analyzer.hover.actions.enable#` is set.
- hover_actions_run_enable: bool = "true",
+ hover_actions_run_enable: bool = true,
/// Whether to show documentation on hover.
- hover_documentation_enable: bool = "true",
+ hover_documentation_enable: bool = true,
/// Whether to show keyword hover popups. Only applies when
/// `#rust-analyzer.hover.documentation.enable#` is set.
- hover_documentation_keywords_enable: bool = "true",
+ hover_documentation_keywords_enable: bool = true,
/// Use markdown syntax for links on hover.
- hover_links_enable: bool = "true",
+ hover_links_enable: bool = true,
/// How to render the align information in a memory layout hover.
- hover_memoryLayout_alignment: Option<MemoryLayoutHoverRenderKindDef> = "\"hexadecimal\"",
+ hover_memoryLayout_alignment: Option<MemoryLayoutHoverRenderKindDef> = Some(MemoryLayoutHoverRenderKindDef::Hexadecimal),
/// Whether to show memory layout data on hover.
- hover_memoryLayout_enable: bool = "true",
+ hover_memoryLayout_enable: bool = true,
/// How to render the niche information in a memory layout hover.
- hover_memoryLayout_niches: Option<bool> = "false",
+ hover_memoryLayout_niches: Option<bool> = Some(false),
/// How to render the offset information in a memory layout hover.
- hover_memoryLayout_offset: Option<MemoryLayoutHoverRenderKindDef> = "\"hexadecimal\"",
+ hover_memoryLayout_offset: Option<MemoryLayoutHoverRenderKindDef> = Some(MemoryLayoutHoverRenderKindDef::Hexadecimal),
/// How to render the size information in a memory layout hover.
- hover_memoryLayout_size: Option<MemoryLayoutHoverRenderKindDef> = "\"both\"",
+ hover_memoryLayout_size: Option<MemoryLayoutHoverRenderKindDef> = Some(MemoryLayoutHoverRenderKindDef::Both),
/// How many fields of a struct to display when hovering a struct.
- hover_show_structFields: Option<usize> = "null",
+ hover_show_structFields: Option<usize> = None,
/// How many associated items of a trait to display when hovering a trait.
- hover_show_traitAssocItems: Option<usize> = "null",
+ hover_show_traitAssocItems: Option<usize> = None,
- /// Whether to enforce the import granularity setting for all files. If set to false rust-analyzer will try to keep import styles consistent per file.
- imports_granularity_enforce: bool = "false",
- /// How imports should be grouped into use statements.
- imports_granularity_group: ImportGranularityDef = "\"crate\"",
- /// Group inserted imports by the https://rust-analyzer.github.io/manual.html#auto-import[following order]. Groups are separated by newlines.
- imports_group_enable: bool = "true",
- /// Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`.
- imports_merge_glob: bool = "true",
- /// Prefer to unconditionally use imports of the core and alloc crate, over the std crate.
- imports_preferNoStd | imports_prefer_no_std: bool = "false",
- /// Whether to prefer import paths containing a `prelude` module.
- imports_preferPrelude: bool = "false",
- /// The path structure for newly inserted paths to use.
- imports_prefix: ImportPrefixDef = "\"plain\"",
-
- /// Whether to show inlay type hints for binding modes.
- inlayHints_bindingModeHints_enable: bool = "false",
- /// Whether to show inlay type hints for method chains.
- inlayHints_chainingHints_enable: bool = "true",
- /// Whether to show inlay hints after a closing `}` to indicate what item it belongs to.
- inlayHints_closingBraceHints_enable: bool = "true",
- /// Minimum number of lines required before the `}` until the hint is shown (set to 0 or 1
- /// to always show them).
- inlayHints_closingBraceHints_minLines: usize = "25",
- /// Whether to show inlay hints for closure captures.
- inlayHints_closureCaptureHints_enable: bool = "false",
- /// Whether to show inlay type hints for return types of closures.
- inlayHints_closureReturnTypeHints_enable: ClosureReturnTypeHintsDef = "\"never\"",
- /// Closure notation in type and chaining inlay hints.
- inlayHints_closureStyle: ClosureStyle = "\"impl_fn\"",
- /// Whether to show enum variant discriminant hints.
- inlayHints_discriminantHints_enable: DiscriminantHintsDef = "\"never\"",
- /// Whether to show inlay hints for type adjustments.
- inlayHints_expressionAdjustmentHints_enable: AdjustmentHintsDef = "\"never\"",
- /// Whether to hide inlay hints for type adjustments outside of `unsafe` blocks.
- inlayHints_expressionAdjustmentHints_hideOutsideUnsafe: bool = "false",
- /// Whether to show inlay hints as postfix ops (`.*` instead of `*`, etc).
- inlayHints_expressionAdjustmentHints_mode: AdjustmentHintsModeDef = "\"prefix\"",
- /// Whether to show implicit drop hints.
- inlayHints_implicitDrops_enable: bool = "false",
- /// Whether to show inlay type hints for elided lifetimes in function signatures.
- inlayHints_lifetimeElisionHints_enable: LifetimeElisionDef = "\"never\"",
- /// Whether to prefer using parameter names as the name for elided lifetime hints if possible.
- inlayHints_lifetimeElisionHints_useParameterNames: bool = "false",
- /// Maximum length for inlay hints. Set to null to have an unlimited length.
- inlayHints_maxLength: Option<usize> = "25",
- /// Whether to show function parameter name inlay hints at the call
- /// site.
- inlayHints_parameterHints_enable: bool = "true",
- /// Whether to show exclusive range inlay hints.
- inlayHints_rangeExclusiveHints_enable: bool = "false",
- /// Whether to show inlay hints for compiler inserted reborrows.
- /// This setting is deprecated in favor of #rust-analyzer.inlayHints.expressionAdjustmentHints.enable#.
- inlayHints_reborrowHints_enable: ReborrowHintsDef = "\"never\"",
- /// Whether to render leading colons for type hints, and trailing colons for parameter hints.
- inlayHints_renderColons: bool = "true",
- /// Whether to show inlay type hints for variables.
- inlayHints_typeHints_enable: bool = "true",
- /// Whether to hide inlay type hints for `let` statements that initialize to a closure.
- /// Only applies to closures with blocks, same as `#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`.
- inlayHints_typeHints_hideClosureInitialization: bool = "false",
- /// Whether to hide inlay type hints for constructors.
- inlayHints_typeHints_hideNamedConstructor: bool = "false",
/// Enables the experimental support for interpreting tests.
- interpret_tests: bool = "false",
-
- /// Join lines merges consecutive declaration and initialization of an assignment.
- joinLines_joinAssignments: bool = "true",
- /// Join lines inserts else between consecutive ifs.
- joinLines_joinElseIf: bool = "true",
- /// Join lines removes trailing commas.
- joinLines_removeTrailingComma: bool = "true",
- /// Join lines unwraps trivial blocks.
- joinLines_unwrapTrivialBlock: bool = "true",
-
+ interpret_tests: bool = false,
/// Whether to show `Debug` lens. Only applies when
/// `#rust-analyzer.lens.enable#` is set.
- lens_debug_enable: bool = "true",
+ lens_debug_enable: bool = true,
/// Whether to show CodeLens in Rust files.
- lens_enable: bool = "true",
+ lens_enable: bool = true,
/// Internal config: use custom client-side commands even when the
/// client doesn't set the corresponding capability.
- lens_forceCustomCommands: bool = "true",
+ lens_forceCustomCommands: bool = true,
/// Whether to show `Implementations` lens. Only applies when
/// `#rust-analyzer.lens.enable#` is set.
- lens_implementations_enable: bool = "true",
+ lens_implementations_enable: bool = true,
/// Where to render annotations.
- lens_location: AnnotationLocation = "\"above_name\"",
+ lens_location: AnnotationLocation = AnnotationLocation::AboveName,
/// Whether to show `References` lens for Struct, Enum, and Union.
/// Only applies when `#rust-analyzer.lens.enable#` is set.
- lens_references_adt_enable: bool = "false",
+ lens_references_adt_enable: bool = false,
/// Whether to show `References` lens for Enum Variants.
/// Only applies when `#rust-analyzer.lens.enable#` is set.
- lens_references_enumVariant_enable: bool = "false",
+ lens_references_enumVariant_enable: bool = false,
/// Whether to show `Method References` lens. Only applies when
/// `#rust-analyzer.lens.enable#` is set.
- lens_references_method_enable: bool = "false",
+ lens_references_method_enable: bool = false,
/// Whether to show `References` lens for Trait.
/// Only applies when `#rust-analyzer.lens.enable#` is set.
- lens_references_trait_enable: bool = "false",
+ lens_references_trait_enable: bool = false,
/// Whether to show `Run` lens. Only applies when
/// `#rust-analyzer.lens.enable#` is set.
- lens_run_enable: bool = "true",
+ lens_run_enable: bool = true,
/// Disable project auto-discovery in favor of explicitly specified set
/// of projects.
///
/// Elements must be paths pointing to `Cargo.toml`,
/// `rust-project.json`, or JSON objects in `rust-project.json` format.
- linkedProjects: Vec<ManifestOrProjectJson> = "[]",
+ linkedProjects: Vec<ManifestOrProjectJson> = vec![],
/// Number of syntax trees rust-analyzer keeps in memory. Defaults to 128.
- lru_capacity: Option<usize> = "null",
+ lru_capacity: Option<usize> = None,
/// Sets the LRU capacity of the specified queries.
- lru_query_capacities: FxHashMap<Box<str>, usize> = "{}",
+ lru_query_capacities: FxHashMap<Box<str>, usize> = FxHashMap::default(),
/// Whether to show `can't find Cargo.toml` error message.
- notifications_cargoTomlNotFound: bool = "true",
+ notifications_cargoTomlNotFound: bool = true,
/// Whether to send an UnindexedProject notification to the client.
- notifications_unindexedProject: bool = "false",
+ notifications_unindexedProject: bool = false,
/// How many worker threads in the main loop. The default `null` means to pick automatically.
- numThreads: Option<usize> = "null",
+ numThreads: Option<usize> = None,
/// Expand attribute macros. Requires `#rust-analyzer.procMacro.enable#` to be set.
- procMacro_attributes_enable: bool = "true",
+ procMacro_attributes_enable: bool = true,
/// Enable support for procedural macros, implies `#rust-analyzer.cargo.buildScripts.enable#`.
- procMacro_enable: bool = "true",
+ procMacro_enable: bool = true,
/// These proc-macros will be ignored when trying to expand them.
///
/// This config takes a map of crate names with the exported proc-macro names to ignore as values.
- procMacro_ignored: FxHashMap<Box<str>, Box<[Box<str>]>> = "{}",
+ procMacro_ignored: FxHashMap<Box<str>, Box<[Box<str>]>> = FxHashMap::default(),
/// Internal config, path to proc-macro server executable.
- procMacro_server: Option<Utf8PathBuf> = "null",
+ procMacro_server: Option<Utf8PathBuf> = None,
/// Exclude imports from find-all-references.
- references_excludeImports: bool = "false",
+ references_excludeImports: bool = false,
/// Exclude tests from find-all-references.
- references_excludeTests: bool = "false",
+ references_excludeTests: bool = false,
/// Command to be executed instead of 'cargo' for runnables.
- runnables_command: Option<String> = "null",
+ runnables_command: Option<String> = None,
/// Additional arguments to be passed to cargo for runnables such as
/// tests or binaries. For example, it may be `--release`.
- runnables_extraArgs: Vec<String> = "[]",
+ runnables_extraArgs: Vec<String> = vec![],
/// Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private
/// projects, or "discover" to try to automatically find it if the `rustc-dev` component
@@ -540,81 +401,236 @@ config_data! {
/// crates must set `[package.metadata.rust-analyzer] rustc_private=true` to use it.
///
/// This option does not take effect until rust-analyzer is restarted.
- rustc_source: Option<String> = "null",
+ rustc_source: Option<String> = None,
/// Additional arguments to `rustfmt`.
- rustfmt_extraArgs: Vec<String> = "[]",
+ rustfmt_extraArgs: Vec<String> = vec![],
/// Advanced option, fully override the command rust-analyzer uses for
/// formatting. This should be the equivalent of `rustfmt` here, and
/// not that of `cargo fmt`. The file contents will be passed on the
/// standard input and the formatted result will be read from the
/// standard output.
- rustfmt_overrideCommand: Option<Vec<String>> = "null",
+ rustfmt_overrideCommand: Option<Vec<String>> = None,
/// Enables the use of rustfmt's unstable range formatting command for the
/// `textDocument/rangeFormatting` request. The rustfmt option is unstable and only
/// available on a nightly build.
- rustfmt_rangeFormatting_enable: bool = "false",
+ rustfmt_rangeFormatting_enable: bool = false,
+
+
+ /// Show full signature of the callable. Only shows parameters if disabled.
+ signatureInfo_detail: SignatureDetail = SignatureDetail::Full,
+ /// Show documentation.
+ signatureInfo_documentation_enable: bool = true,
+
+ /// Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list.
+ typing_autoClosingAngleBrackets_enable: bool = false,
+
+ /// Workspace symbol search kind.
+ workspace_symbol_search_kind: WorkspaceSymbolSearchKindDef = WorkspaceSymbolSearchKindDef::OnlyTypes,
+ /// Limits the number of items returned from a workspace symbol search (Defaults to 128).
+ /// Some clients like vs-code issue new searches on result filtering and don't require all results to be returned in the initial search.
+ /// Other clients requires all results upfront and might require a higher limit.
+ workspace_symbol_search_limit: usize = 128,
+ /// Workspace symbol search scope.
+ workspace_symbol_search_scope: WorkspaceSymbolSearchScopeDef = WorkspaceSymbolSearchScopeDef::Workspace,
+ }
+}
+
+config_data! {
+ /// Local configurations can be overridden for every crate by placing a `rust-analyzer.toml` on crate root.
+ /// A config is searched for by traversing a "config tree" in a bottom up fashion. It is chosen by the nearest first principle.
+ local: struct LocalDefaultConfigData <- LocalConfigInput -> {
+ /// Toggles the additional completions that automatically add imports when completed.
+ /// Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.
+ completion_autoimport_enable: bool = true,
+ /// Toggles the additional completions that automatically show method calls and field accesses
+ /// with `self` prefixed to them when inside a method.
+ completion_autoself_enable: bool = true,
+ /// Whether to add parenthesis and argument snippets when completing function.
+ completion_callable_snippets: CallableCompletionDef = CallableCompletionDef::FillArguments,
+ /// Whether to show full function/method signatures in completion docs.
+ completion_fullFunctionSignatures_enable: bool = false,
+ /// Maximum number of completions to return. If `None`, the limit is infinite.
+ completion_limit: Option<usize> = None,
+ /// Whether to show postfix snippets like `dbg`, `if`, `not`, etc.
+ completion_postfix_enable: bool = true,
+ /// Enables completions of private items and fields that are defined in the current workspace even if they are not visible at the current position.
+ completion_privateEditable_enable: bool = false,
+ /// Custom completion snippets.
+ // NOTE: we use IndexMap for deterministic serialization ordering
+ completion_snippets_custom: IndexMap<String, SnippetDef> = serde_json::from_str(r#"{
+ "Arc::new": {
+ "postfix": "arc",
+ "body": "Arc::new(${receiver})",
+ "requires": "std::sync::Arc",
+ "description": "Put the expression into an `Arc`",
+ "scope": "expr"
+ },
+ "Rc::new": {
+ "postfix": "rc",
+ "body": "Rc::new(${receiver})",
+ "requires": "std::rc::Rc",
+ "description": "Put the expression into an `Rc`",
+ "scope": "expr"
+ },
+ "Box::pin": {
+ "postfix": "pinbox",
+ "body": "Box::pin(${receiver})",
+ "requires": "std::boxed::Box",
+ "description": "Put the expression into a pinned `Box`",
+ "scope": "expr"
+ },
+ "Ok": {
+ "postfix": "ok",
+ "body": "Ok(${receiver})",
+ "description": "Wrap the expression in a `Result::Ok`",
+ "scope": "expr"
+ },
+ "Err": {
+ "postfix": "err",
+ "body": "Err(${receiver})",
+ "description": "Wrap the expression in a `Result::Err`",
+ "scope": "expr"
+ },
+ "Some": {
+ "postfix": "some",
+ "body": "Some(${receiver})",
+ "description": "Wrap the expression in an `Option::Some`",
+ "scope": "expr"
+ }
+ }"#).unwrap(),
+ /// Whether to enable term search based snippets like `Some(foo.bar().baz())`.
+ completion_termSearch_enable: bool = false,
+
+ /// Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords.
+ highlightRelated_breakPoints_enable: bool = true,
+ /// Enables highlighting of all captures of a closure while the cursor is on the `|` or move keyword of a closure.
+ highlightRelated_closureCaptures_enable: bool = true,
+ /// Enables highlighting of all exit points while the cursor is on any `return`, `?`, `fn`, or return type arrow (`->`).
+ highlightRelated_exitPoints_enable: bool = true,
+ /// Enables highlighting of related references while the cursor is on any identifier.
+ highlightRelated_references_enable: bool = true,
+ /// Enables highlighting of all break points for a loop or block context while the cursor is on any `async` or `await` keywords.
+ highlightRelated_yieldPoints_enable: bool = true,
+
+ /// Whether to enforce the import granularity setting for all files. If set to false rust-analyzer will try to keep import styles consistent per file.
+ imports_granularity_enforce: bool = false,
+ /// How imports should be grouped into use statements.
+ imports_granularity_group: ImportGranularityDef = ImportGranularityDef::Crate,
+ /// Group inserted imports by the https://rust-analyzer.github.io/manual.html#auto-import[following order]. Groups are separated by newlines.
+ imports_group_enable: bool = true,
+ /// Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`.
+ imports_merge_glob: bool = true,
+ /// Prefer to unconditionally use imports of the core and alloc crate, over the std crate.
+ imports_preferNoStd | imports_prefer_no_std: bool = false,
+ /// Whether to prefer import paths containing a `prelude` module.
+ imports_preferPrelude: bool = false,
+ /// The path structure for newly inserted paths to use.
+ imports_prefix: ImportPrefixDef = ImportPrefixDef::Plain,
+
+
+ /// Whether to show inlay type hints for binding modes.
+ inlayHints_bindingModeHints_enable: bool = false,
+ /// Whether to show inlay type hints for method chains.
+ inlayHints_chainingHints_enable: bool = true,
+ /// Whether to show inlay hints after a closing `}` to indicate what item it belongs to.
+ inlayHints_closingBraceHints_enable: bool = true,
+ /// Minimum number of lines required before the `}` until the hint is shown (set to 0 or 1
+ /// to always show them).
+ inlayHints_closingBraceHints_minLines: usize = 25,
+ /// Whether to show inlay hints for closure captures.
+ inlayHints_closureCaptureHints_enable: bool = false,
+ /// Whether to show inlay type hints for return types of closures.
+ inlayHints_closureReturnTypeHints_enable: ClosureReturnTypeHintsDef = ClosureReturnTypeHintsDef::Never,
+ /// Closure notation in type and chaining inlay hints.
+ inlayHints_closureStyle: ClosureStyle = ClosureStyle::ImplFn,
+ /// Whether to show enum variant discriminant hints.
+ inlayHints_discriminantHints_enable: DiscriminantHintsDef = DiscriminantHintsDef::Never,
+ /// Whether to show inlay hints for type adjustments.
+ inlayHints_expressionAdjustmentHints_enable: AdjustmentHintsDef = AdjustmentHintsDef::Never,
+ /// Whether to hide inlay hints for type adjustments outside of `unsafe` blocks.
+ inlayHints_expressionAdjustmentHints_hideOutsideUnsafe: bool = false,
+ /// Whether to show inlay hints as postfix ops (`.*` instead of `*`, etc).
+ inlayHints_expressionAdjustmentHints_mode: AdjustmentHintsModeDef = AdjustmentHintsModeDef::Prefix,
+ /// Whether to show implicit drop hints.
+ inlayHints_implicitDrops_enable: bool = false,
+ /// Whether to show inlay type hints for elided lifetimes in function signatures.
+ inlayHints_lifetimeElisionHints_enable: LifetimeElisionDef = LifetimeElisionDef::Never,
+ /// Whether to prefer using parameter names as the name for elided lifetime hints if possible.
+ inlayHints_lifetimeElisionHints_useParameterNames: bool = false,
+ /// Maximum length for inlay hints. Set to null to have an unlimited length.
+ inlayHints_maxLength: Option<usize> = Some(25),
+ /// Whether to show function parameter name inlay hints at the call
+ /// site.
+ inlayHints_parameterHints_enable: bool = true,
+ /// Whether to show exclusive range inlay hints.
+ inlayHints_rangeExclusiveHints_enable: bool = false,
+ /// Whether to show inlay hints for compiler inserted reborrows.
+ /// This setting is deprecated in favor of #rust-analyzer.inlayHints.expressionAdjustmentHints.enable#.
+ inlayHints_reborrowHints_enable: ReborrowHintsDef = ReborrowHintsDef::Never,
+ /// Whether to render leading colons for type hints, and trailing colons for parameter hints.
+ inlayHints_renderColons: bool = true,
+ /// Whether to show inlay type hints for variables.
+ inlayHints_typeHints_enable: bool = true,
+ /// Whether to hide inlay type hints for `let` statements that initialize to a closure.
+ /// Only applies to closures with blocks, same as `#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`.
+ inlayHints_typeHints_hideClosureInitialization: bool = false,
+ /// Whether to hide inlay type hints for constructors.
+ inlayHints_typeHints_hideNamedConstructor: bool = false,
+
+
+ /// Join lines merges consecutive declaration and initialization of an assignment.
+ joinLines_joinAssignments: bool = true,
+ /// Join lines inserts else between consecutive ifs.
+ joinLines_joinElseIf: bool = true,
+ /// Join lines removes trailing commas.
+ joinLines_removeTrailingComma: bool = true,
+ /// Join lines unwraps trivial blocks.
+ joinLines_unwrapTrivialBlock: bool = true,
/// Inject additional highlighting into doc comments.
///
/// When enabled, rust-analyzer will highlight rust source in doc comments as well as intra
/// doc links.
- semanticHighlighting_doc_comment_inject_enable: bool = "true",
+ semanticHighlighting_doc_comment_inject_enable: bool = true,
/// Whether the server is allowed to emit non-standard tokens and modifiers.
- semanticHighlighting_nonStandardTokens: bool = "true",
+ semanticHighlighting_nonStandardTokens: bool = true,
/// Use semantic tokens for operators.
///
/// When disabled, rust-analyzer will emit semantic tokens only for operator tokens when
/// they are tagged with modifiers.
- semanticHighlighting_operator_enable: bool = "true",
+ semanticHighlighting_operator_enable: bool = true,
/// Use specialized semantic tokens for operators.
///
/// When enabled, rust-analyzer will emit special token types for operator tokens instead
/// of the generic `operator` token type.
- semanticHighlighting_operator_specialization_enable: bool = "false",
+ semanticHighlighting_operator_specialization_enable: bool = false,
/// Use semantic tokens for punctuation.
///
/// When disabled, rust-analyzer will emit semantic tokens only for punctuation tokens when
/// they are tagged with modifiers or have a special role.
- semanticHighlighting_punctuation_enable: bool = "false",
+ semanticHighlighting_punctuation_enable: bool = false,
/// When enabled, rust-analyzer will emit a punctuation semantic token for the `!` of macro
/// calls.
- semanticHighlighting_punctuation_separate_macro_bang: bool = "false",
+ semanticHighlighting_punctuation_separate_macro_bang: bool = false,
/// Use specialized semantic tokens for punctuation.
///
/// When enabled, rust-analyzer will emit special token types for punctuation tokens instead
/// of the generic `punctuation` token type.
- semanticHighlighting_punctuation_specialization_enable: bool = "false",
+ semanticHighlighting_punctuation_specialization_enable: bool = false,
/// Use semantic tokens for strings.
///
/// In some editors (e.g. vscode) semantic tokens override other highlighting grammars.
/// By disabling semantic tokens for strings, other grammars can be used to highlight
/// their contents.
- semanticHighlighting_strings_enable: bool = "true",
-
- /// Show full signature of the callable. Only shows parameters if disabled.
- signatureInfo_detail: SignatureDetail = "\"full\"",
- /// Show documentation.
- signatureInfo_documentation_enable: bool = "true",
-
- /// Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list.
- typing_autoClosingAngleBrackets_enable: bool = "false",
-
- /// Workspace symbol search kind.
- workspace_symbol_search_kind: WorkspaceSymbolSearchKindDef = "\"only_types\"",
- /// Limits the number of items returned from a workspace symbol search (Defaults to 128).
- /// Some clients like vs-code issue new searches on result filtering and don't require all results to be returned in the initial search.
- /// Other clients requires all results upfront and might require a higher limit.
- workspace_symbol_search_limit: usize = "128",
- /// Workspace symbol search scope.
- workspace_symbol_search_scope: WorkspaceSymbolSearchScopeDef = "\"workspace\"",
+ semanticHighlighting_strings_enable: bool = true,
}
}
-impl Default for ConfigData {
- fn default() -> Self {
- ConfigData::from_json(serde_json::Value::Null, &mut Vec::new())
- }
+config_data! {
+ /// Configs that only make sense when they are set by a client. As such they can only be defined
+ /// by setting them using client's settings (e.g `settings.json` on VS Code).
+ client: struct ClientDefaultConfigData <- ClientConfigInput -> {}
}
#[derive(Debug, Clone)]
@@ -624,10 +640,40 @@ pub struct Config {
workspace_roots: Vec<AbsPathBuf>,
caps: lsp_types::ClientCapabilities,
root_path: AbsPathBuf,
- data: ConfigData,
detached_files: Vec<AbsPathBuf>,
snippets: Vec<Snippet>,
visual_studio_code_version: Option<Version>,
+
+ default_config: DefaultConfigData,
+ client_config: FullConfigInput,
+ user_config: GlobalLocalConfigInput,
+ #[allow(dead_code)]
+ ratoml_files: FxHashMap<SourceRootId, RatomlNode>,
+}
+
+#[derive(Clone, Debug)]
+struct RatomlNode {
+ #[allow(dead_code)]
+ node: GlobalLocalConfigInput,
+ #[allow(dead_code)]
+ parent: Option<SourceRootId>,
+}
+
+macro_rules! try_ {
+ ($expr:expr) => {
+ || -> _ { Some($expr) }()
+ };
+}
+macro_rules! try_or {
+ ($expr:expr, $or:expr) => {
+ try_!($expr).unwrap_or($or)
+ };
+}
+
+macro_rules! try_or_def {
+ ($expr:expr) => {
+ try_!($expr).unwrap_or_default()
+ };
}
type ParallelCachePrimingNumThreads = u8;
@@ -675,7 +721,7 @@ pub struct LensConfig {
pub location: AnnotationLocation,
}
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Deserialize)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum AnnotationLocation {
AboveName,
@@ -830,13 +876,16 @@ impl Config {
) -> Self {
Config {
caps,
- data: ConfigData::default(),
detached_files: Vec::new(),
discovered_projects: Vec::new(),
root_path,
snippets: Default::default(),
workspace_roots,
visual_studio_code_version,
+ client_config: FullConfigInput::default(),
+ user_config: GlobalLocalConfigInput::default(),
+ ratoml_files: FxHashMap::default(),
+ default_config: DefaultConfigData::default(),
}
}
@@ -866,15 +915,19 @@ impl Config {
}
let mut errors = Vec::new();
self.detached_files =
- get_field::<Vec<Utf8PathBuf>>(&mut json, &mut errors, "detachedFiles", None, "[]")
+ get_field::<Vec<Utf8PathBuf>>(&mut json, &mut errors, "detachedFiles", None)
+ .unwrap_or_default()
.into_iter()
.map(AbsPathBuf::assert)
.collect();
patch_old_style::patch_json_for_outdated_configs(&mut json);
- self.data = ConfigData::from_json(json, &mut errors);
- tracing::debug!("deserialized config data: {:#?}", self.data);
+ self.client_config = FullConfigInput::from_json(json, &mut errors);
+ tracing::debug!(?self.client_config, "deserialized config data");
self.snippets.clear();
- for (name, def) in self.data.completion_snippets_custom.iter() {
+
+ let snips = self.completion_snippets_custom(None).to_owned();
+
+ for (name, def) in snips.iter() {
if def.prefix.is_empty() && def.postfix.is_empty() {
continue;
}
@@ -912,7 +965,7 @@ impl Config {
fn validate(&self, error_sink: &mut Vec<(String, serde_json::Error)>) {
use serde::de::Error;
- if self.data.check_command.is_empty() {
+ if self.check_command().is_empty() {
error_sink.push((
"/check/command".to_owned(),
serde_json::Error::custom("expected a non-empty string"),
@@ -921,7 +974,7 @@ impl Config {
}
pub fn json_schema() -> serde_json::Value {
- ConfigData::json_schema()
+ FullConfigInput::json_schema()
}
pub fn root_path(&self) -> &AbsPathBuf {
@@ -937,44 +990,302 @@ impl Config {
}
}
-macro_rules! try_ {
- ($expr:expr) => {
- || -> _ { Some($expr) }()
- };
-}
-macro_rules! try_or {
- ($expr:expr, $or:expr) => {
- try_!($expr).unwrap_or($or)
- };
-}
+impl Config {
+ pub fn assist(&self, source_root: Option<SourceRootId>) -> AssistConfig {
+ AssistConfig {
+ snippet_cap: SnippetCap::new(self.experimental("snippetTextEdit")),
+ allowed: None,
+ insert_use: self.insert_use_config(source_root),
+ prefer_no_std: self.imports_preferNoStd(source_root).to_owned(),
+ assist_emit_must_use: self.assist_emitMustUse().to_owned(),
+ prefer_prelude: self.imports_preferPrelude(source_root).to_owned(),
+ }
+ }
-macro_rules! try_or_def {
- ($expr:expr) => {
- try_!($expr).unwrap_or_default()
- };
-}
+ pub fn completion(&self, source_root: Option<SourceRootId>) -> CompletionConfig {
+ CompletionConfig {
+ enable_postfix_completions: self.completion_postfix_enable(source_root).to_owned(),
+ enable_imports_on_the_fly: self.completion_autoimport_enable(source_root).to_owned()
+ && completion_item_edit_resolve(&self.caps),
+ enable_self_on_the_fly: self.completion_autoself_enable(source_root).to_owned(),
+ enable_private_editable: self.completion_privateEditable_enable(source_root).to_owned(),
+ full_function_signatures: self
+ .completion_fullFunctionSignatures_enable(source_root)
+ .to_owned(),
+ callable: match self.completion_callable_snippets(source_root) {
+ CallableCompletionDef::FillArguments => Some(CallableSnippets::FillArguments),
+ CallableCompletionDef::AddParentheses => Some(CallableSnippets::AddParentheses),
+ CallableCompletionDef::None => None,
+ },
+ insert_use: self.insert_use_config(source_root),
+ prefer_no_std: self.imports_preferNoStd(source_root).to_owned(),
+ snippet_cap: SnippetCap::new(try_or_def!(
+ self.caps
+ .text_document
+ .as_ref()?
+ .completion
+ .as_ref()?
+ .completion_item
+ .as_ref()?
+ .snippet_support?
+ )),
+ snippets: self.snippets.clone().to_vec(),
+ limit: self.completion_limit(source_root).to_owned(),
+ enable_term_search: self.completion_termSearch_enable(source_root).to_owned(),
+ prefer_prelude: self.imports_preferPrelude(source_root).to_owned(),
+ }
+ }
+
+ pub fn diagnostics(&self, source_root: Option<SourceRootId>) -> DiagnosticsConfig {
+ DiagnosticsConfig {
+ enabled: *self.diagnostics_enable(),
+ proc_attr_macros_enabled: self.expand_proc_attr_macros(),
+ proc_macros_enabled: *self.procMacro_enable(),
+ disable_experimental: !self.diagnostics_experimental_enable(),
+ disabled: self.diagnostics_disabled().clone(),
+ expr_fill_default: match self.assist_expressionFillDefault() {
+ ExprFillDefaultDef::Todo => ExprFillDefaultMode::Todo,
+ ExprFillDefaultDef::Default => ExprFillDefaultMode::Default,
+ },
+ insert_use: self.insert_use_config(source_root),
+ prefer_no_std: self.imports_preferNoStd(source_root).to_owned(),
+ prefer_prelude: self.imports_preferPrelude(source_root).to_owned(),
+ style_lints: self.diagnostics_styleLints_enable().to_owned(),
+ }
+ }
+ pub fn expand_proc_attr_macros(&self) -> bool {
+ self.procMacro_enable().to_owned() && self.procMacro_attributes_enable().to_owned()
+ }
+
+ pub fn highlight_related(&self, source_root: Option<SourceRootId>) -> HighlightRelatedConfig {
+ HighlightRelatedConfig {
+ references: self.highlightRelated_references_enable(source_root).to_owned(),
+ break_points: self.highlightRelated_breakPoints_enable(source_root).to_owned(),
+ exit_points: self.highlightRelated_exitPoints_enable(source_root).to_owned(),
+ yield_points: self.highlightRelated_yieldPoints_enable(source_root).to_owned(),
+ closure_captures: self.highlightRelated_closureCaptures_enable(source_root).to_owned(),
+ }
+ }
+
+ pub fn hover_actions(&self) -> HoverActionsConfig {
+ let enable = self.experimental("hoverActions") && self.hover_actions_enable().to_owned();
+ HoverActionsConfig {
+ implementations: enable && self.hover_actions_implementations_enable().to_owned(),
+ references: enable && self.hover_actions_references_enable().to_owned(),
+ run: enable && self.hover_actions_run_enable().to_owned(),
+ debug: enable && self.hover_actions_debug_enable().to_owned(),
+ goto_type_def: enable && self.hover_actions_gotoTypeDef_enable().to_owned(),
+ }
+ }
+
+ pub fn hover(&self) -> HoverConfig {
+ let mem_kind = |kind| match kind {
+ MemoryLayoutHoverRenderKindDef::Both => MemoryLayoutHoverRenderKind::Both,
+ MemoryLayoutHoverRenderKindDef::Decimal => MemoryLayoutHoverRenderKind::Decimal,
+ MemoryLayoutHoverRenderKindDef::Hexadecimal => MemoryLayoutHoverRenderKind::Hexadecimal,
+ };
+ HoverConfig {
+ links_in_hover: self.hover_links_enable().to_owned(),
+ memory_layout: self.hover_memoryLayout_enable().then_some(MemoryLayoutHoverConfig {
+ size: self.hover_memoryLayout_size().map(mem_kind),
+ offset: self.hover_memoryLayout_offset().map(mem_kind),
+ alignment: self.hover_memoryLayout_alignment().map(mem_kind),
+ niches: self.hover_memoryLayout_niches().unwrap_or_default(),
+ }),
+ documentation: self.hover_documentation_enable().to_owned(),
+ format: {
+ let is_markdown = try_or_def!(self
+ .caps
+ .text_document
+ .as_ref()?
+ .hover
+ .as_ref()?
+ .content_format
+ .as_ref()?
+ .as_slice())
+ .contains(&MarkupKind::Markdown);
+ if is_markdown {
+ HoverDocFormat::Markdown
+ } else {
+ HoverDocFormat::PlainText
+ }
+ },
+ keywords: self.hover_documentation_keywords_enable().to_owned(),
+ max_trait_assoc_items_count: self.hover_show_traitAssocItems().to_owned(),
+ max_struct_field_count: self.hover_show_structFields().to_owned(),
+ }
+ }
+
+ pub fn inlay_hints(&self, source_root: Option<SourceRootId>) -> InlayHintsConfig {
+ let client_capability_fields = self
+ .caps
+ .text_document
+ .as_ref()
+ .and_then(|text| text.inlay_hint.as_ref())
+ .and_then(|inlay_hint_caps| inlay_hint_caps.resolve_support.as_ref())
+ .map(|inlay_resolve| inlay_resolve.properties.iter())
+ .into_iter()
+ .flatten()
+ .cloned()
+ .collect::<FxHashSet<_>>();
+
+ InlayHintsConfig {
+ render_colons: self.inlayHints_renderColons(source_root).to_owned(),
+ type_hints: self.inlayHints_typeHints_enable(source_root).to_owned(),
+ parameter_hints: self.inlayHints_parameterHints_enable(source_root).to_owned(),
+ chaining_hints: self.inlayHints_chainingHints_enable(source_root).to_owned(),
+ discriminant_hints: match self.inlayHints_discriminantHints_enable(source_root) {
+ DiscriminantHintsDef::Always => ide::DiscriminantHints::Always,
+ DiscriminantHintsDef::Never => ide::DiscriminantHints::Never,
+ DiscriminantHintsDef::Fieldless => ide::DiscriminantHints::Fieldless,
+ },
+ closure_return_type_hints: match self
+ .inlayHints_closureReturnTypeHints_enable(source_root)
+ {
+ ClosureReturnTypeHintsDef::Always => ide::ClosureReturnTypeHints::Always,
+ ClosureReturnTypeHintsDef::Never => ide::ClosureReturnTypeHints::Never,
+ ClosureReturnTypeHintsDef::WithBlock => ide::ClosureReturnTypeHints::WithBlock,
+ },
+ lifetime_elision_hints: match self.inlayHints_lifetimeElisionHints_enable(source_root) {
+ LifetimeElisionDef::Always => ide::LifetimeElisionHints::Always,
+ LifetimeElisionDef::Never => ide::LifetimeElisionHints::Never,
+ LifetimeElisionDef::SkipTrivial => ide::LifetimeElisionHints::SkipTrivial,
+ },
+ hide_named_constructor_hints: self
+ .inlayHints_typeHints_hideNamedConstructor(source_root)
+ .to_owned(),
+ hide_closure_initialization_hints: self
+ .inlayHints_typeHints_hideClosureInitialization(source_root)
+ .to_owned(),
+ closure_style: match self.inlayHints_closureStyle(source_root) {
+ ClosureStyle::ImplFn => hir::ClosureStyle::ImplFn,
+ ClosureStyle::RustAnalyzer => hir::ClosureStyle::RANotation,
+ ClosureStyle::WithId => hir::ClosureStyle::ClosureWithId,
+ ClosureStyle::Hide => hir::ClosureStyle::Hide,
+ },
+ closure_capture_hints: self
+ .inlayHints_closureCaptureHints_enable(source_root)
+ .to_owned(),
+ adjustment_hints: match self.inlayHints_expressionAdjustmentHints_enable(source_root) {
+ AdjustmentHintsDef::Always => ide::AdjustmentHints::Always,
+ AdjustmentHintsDef::Never => {
+ match self.inlayHints_reborrowHints_enable(source_root) {
+ ReborrowHintsDef::Always | ReborrowHintsDef::Mutable => {
+ ide::AdjustmentHints::ReborrowOnly
+ }
+ ReborrowHintsDef::Never => ide::AdjustmentHints::Never,
+ }
+ }
+ AdjustmentHintsDef::Reborrow => ide::AdjustmentHints::ReborrowOnly,
+ },
+ adjustment_hints_mode: match self.inlayHints_expressionAdjustmentHints_mode(source_root)
+ {
+ AdjustmentHintsModeDef::Prefix => ide::AdjustmentHintsMode::Prefix,
+ AdjustmentHintsModeDef::Postfix => ide::AdjustmentHintsMode::Postfix,
+ AdjustmentHintsModeDef::PreferPrefix => ide::AdjustmentHintsMode::PreferPrefix,
+ AdjustmentHintsModeDef::PreferPostfix => ide::AdjustmentHintsMode::PreferPostfix,
+ },
+ adjustment_hints_hide_outside_unsafe: self
+ .inlayHints_expressionAdjustmentHints_hideOutsideUnsafe(source_root)
+ .to_owned(),
+ binding_mode_hints: self.inlayHints_bindingModeHints_enable(source_root).to_owned(),
+ param_names_for_lifetime_elision_hints: self
+ .inlayHints_lifetimeElisionHints_useParameterNames(source_root)
+ .to_owned(),
+ max_length: self.inlayHints_maxLength(source_root).to_owned(),
+ closing_brace_hints_min_lines: if self
+ .inlayHints_closingBraceHints_enable(source_root)
+ .to_owned()
+ {
+ Some(self.inlayHints_closingBraceHints_minLines(source_root).to_owned())
+ } else {
+ None
+ },
+ fields_to_resolve: InlayFieldsToResolve {
+ resolve_text_edits: client_capability_fields.contains("textEdits"),
+ resolve_hint_tooltip: client_capability_fields.contains("tooltip"),
+ resolve_label_tooltip: client_capability_fields.contains("label.tooltip"),
+ resolve_label_location: client_capability_fields.contains("label.location"),
+ resolve_label_command: client_capability_fields.contains("label.command"),
+ },
+ implicit_drop_hints: self.inlayHints_implicitDrops_enable(source_root).to_owned(),
+ range_exclusive_hints: self
+ .inlayHints_rangeExclusiveHints_enable(source_root)
+ .to_owned(),
+ }
+ }
+
+ fn insert_use_config(&self, source_root: Option<SourceRootId>) -> InsertUseConfig {
+ InsertUseConfig {
+ granularity: match self.imports_granularity_group(source_root) {
+ ImportGranularityDef::Preserve => ImportGranularity::Preserve,
+ ImportGranularityDef::Item => ImportGranularity::Item,
+ ImportGranularityDef::Crate => ImportGranularity::Crate,
+ ImportGranularityDef::Module => ImportGranularity::Module,
+ ImportGranularityDef::One => ImportGranularity::One,
+ },
+ enforce_granularity: self.imports_granularity_enforce(source_root).to_owned(),
+ prefix_kind: match self.imports_prefix(source_root) {
+ ImportPrefixDef::Plain => PrefixKind::Plain,
+ ImportPrefixDef::ByCrate => PrefixKind::ByCrate,
+ ImportPrefixDef::BySelf => PrefixKind::BySelf,
+ },
+ group: self.imports_group_enable(source_root).to_owned(),
+ skip_glob_imports: !self.imports_merge_glob(source_root),
+ }
+ }
+
+ pub fn join_lines(&self, source_root: Option<SourceRootId>) -> JoinLinesConfig {
+ JoinLinesConfig {
+ join_else_if: self.joinLines_joinElseIf(source_root).to_owned(),
+ remove_trailing_comma: self.joinLines_removeTrailingComma(source_root).to_owned(),
+ unwrap_trivial_blocks: self.joinLines_unwrapTrivialBlock(source_root).to_owned(),
+ join_assignments: self.joinLines_joinAssignments(source_root).to_owned(),
+ }
+ }
+
+ pub fn highlighting_non_standard_tokens(&self, source_root: Option<SourceRootId>) -> bool {
+ self.semanticHighlighting_nonStandardTokens(source_root).to_owned()
+ }
+
+ pub fn highlighting_config(&self, source_root: Option<SourceRootId>) -> HighlightConfig {
+ HighlightConfig {
+ strings: self.semanticHighlighting_strings_enable(source_root).to_owned(),
+ punctuation: self.semanticHighlighting_punctuation_enable(source_root).to_owned(),
+ specialize_punctuation: self
+ .semanticHighlighting_punctuation_specialization_enable(source_root)
+ .to_owned(),
+ macro_bang: self
+ .semanticHighlighting_punctuation_separate_macro_bang(source_root)
+ .to_owned(),
+ operator: self.semanticHighlighting_operator_enable(source_root).to_owned(),
+ specialize_operator: self
+ .semanticHighlighting_operator_specialization_enable(source_root)
+ .to_owned(),
+ inject_doc_comment: self
+ .semanticHighlighting_doc_comment_inject_enable(source_root)
+ .to_owned(),
+ syntactic_name_ref_highlighting: false,
+ }
+ }
-impl Config {
pub fn has_linked_projects(&self) -> bool {
- !self.data.linkedProjects.is_empty()
+ !self.linkedProjects().is_empty()
}
pub fn linked_manifests(&self) -> impl Iterator<Item = &Utf8Path> + '_ {
- self.data.linkedProjects.iter().filter_map(|it| match it {
+ self.linkedProjects().iter().filter_map(|it| match it {
ManifestOrProjectJson::Manifest(p) => Some(&**p),
ManifestOrProjectJson::ProjectJson(_) => None,
})
}
pub fn has_linked_project_jsons(&self) -> bool {
- self.data
- .linkedProjects
- .iter()
- .any(|it| matches!(it, ManifestOrProjectJson::ProjectJson(_)))
+ self.linkedProjects().iter().any(|it| matches!(it, ManifestOrProjectJson::ProjectJson(_)))
}
pub fn linked_or_discovered_projects(&self) -> Vec<LinkedProject> {
- match self.data.linkedProjects.as_slice() {
+ match self.linkedProjects().as_slice() {
[] => {
let exclude_dirs: Vec<_> =
- self.data.files_excludeDirs.iter().map(|p| self.root_path.join(p)).collect();
+ self.files_excludeDirs().iter().map(|p| self.root_path.join(p)).collect();
self.discovered_projects
.iter()
.filter(
@@ -1028,7 +1339,7 @@ impl Config {
}
pub fn prefill_caches(&self) -> bool {
- self.data.cachePriming_enable
+ self.cachePriming_enable().to_owned()
}
pub fn location_link(&self) -> bool {
@@ -1165,117 +1476,95 @@ impl Config {
}
pub fn publish_diagnostics(&self) -> bool {
- self.data.diagnostics_enable
- }
-
- pub fn diagnostics(&self) -> DiagnosticsConfig {
- DiagnosticsConfig {
- enabled: self.data.diagnostics_enable,
- proc_attr_macros_enabled: self.expand_proc_attr_macros(),
- proc_macros_enabled: self.data.procMacro_enable,
- disable_experimental: !self.data.diagnostics_experimental_enable,
- disabled: self.data.diagnostics_disabled.clone(),
- expr_fill_default: match self.data.assist_expressionFillDefault {
- ExprFillDefaultDef::Todo => ExprFillDefaultMode::Todo,
- ExprFillDefaultDef::Default => ExprFillDefaultMode::Default,
- },
- insert_use: self.insert_use_config(),
- prefer_no_std: self.data.imports_preferNoStd,
- prefer_prelude: self.data.imports_preferPrelude,
- style_lints: self.data.diagnostics_styleLints_enable,
- }
+ self.diagnostics_enable().to_owned()
}
pub fn diagnostics_map(&self) -> DiagnosticsMapConfig {
DiagnosticsMapConfig {
- remap_prefix: self.data.diagnostics_remapPrefix.clone(),
- warnings_as_info: self.data.diagnostics_warningsAsInfo.clone(),
- warnings_as_hint: self.data.diagnostics_warningsAsHint.clone(),
- check_ignore: self.data.check_ignore.clone(),
+ remap_prefix: self.diagnostics_remapPrefix().clone(),
+ warnings_as_info: self.diagnostics_warningsAsInfo().clone(),
+ warnings_as_hint: self.diagnostics_warningsAsHint().clone(),
+ check_ignore: self.check_ignore().clone(),
}
}
pub fn extra_args(&self) -> &Vec<String> {
- &self.data.cargo_extraArgs
+ self.cargo_extraArgs()
}
pub fn extra_env(&self) -> &FxHashMap<String, String> {
- &self.data.cargo_extraEnv
+ self.cargo_extraEnv()
}
pub fn check_extra_args(&self) -> Vec<String> {
let mut extra_args = self.extra_args().clone();
- extra_args.extend_from_slice(&self.data.check_extraArgs);
+ extra_args.extend_from_slice(self.check_extraArgs());
extra_args
}
pub fn check_extra_env(&self) -> FxHashMap<String, String> {
- let mut extra_env = self.data.cargo_extraEnv.clone();
- extra_env.extend(self.data.check_extraEnv.clone());
+ let mut extra_env = self.cargo_extraEnv().clone();
+ extra_env.extend(self.check_extraEnv().clone());
extra_env
}
pub fn lru_parse_query_capacity(&self) -> Option<usize> {
- self.data.lru_capacity
+ self.lru_capacity().to_owned()
}
- pub fn lru_query_capacities(&self) -> Option<&FxHashMap<Box<str>, usize>> {
- self.data.lru_query_capacities.is_empty().not().then_some(&self.data.lru_query_capacities)
+ pub fn lru_query_capacities_config(&self) -> Option<&FxHashMap<Box<str>, usize>> {
+ self.lru_query_capacities().is_empty().not().then(|| self.lru_query_capacities())
}
pub fn proc_macro_srv(&self) -> Option<AbsPathBuf> {
- let path = self.data.procMacro_server.clone()?;
+ let path = self.procMacro_server().clone()?;
Some(AbsPathBuf::try_from(path).unwrap_or_else(|path| self.root_path.join(path)))
}
pub fn ignored_proc_macros(&self) -> &FxHashMap<Box<str>, Box<[Box<str>]>> {
- &self.data.procMacro_ignored
+ self.procMacro_ignored()
}
pub fn expand_proc_macros(&self) -> bool {
- self.data.procMacro_enable
- }
-
- pub fn expand_proc_attr_macros(&self) -> bool {
- self.data.procMacro_enable && self.data.procMacro_attributes_enable
+ self.procMacro_enable().to_owned()
}
pub fn files(&self) -> FilesConfig {
FilesConfig {
- watcher: match self.data.files_watcher {
+ watcher: match self.files_watcher() {
FilesWatcherDef::Client if self.did_change_watched_files_dynamic_registration() => {
FilesWatcher::Client
}
_ => FilesWatcher::Server,
},
- exclude: self.data.files_excludeDirs.iter().map(|it| self.root_path.join(it)).collect(),
+ exclude: self.files_excludeDirs().iter().map(|it| self.root_path.join(it)).collect(),
}
}
pub fn notifications(&self) -> NotificationsConfig {
NotificationsConfig {
- cargo_toml_not_found: self.data.notifications_cargoTomlNotFound,
- unindexed_project: self.data.notifications_unindexedProject,
+ cargo_toml_not_found: self.notifications_cargoTomlNotFound().to_owned(),
+ unindexed_project: self.notifications_unindexedProject().to_owned(),
}
}
- pub fn cargo_autoreload(&self) -> bool {
- self.data.cargo_autoreload
+ pub fn cargo_autoreload_config(&self) -> bool {
+ self.cargo_autoreload().to_owned()
}
pub fn run_build_scripts(&self) -> bool {
- self.data.cargo_buildScripts_enable || self.data.procMacro_enable
+ self.cargo_buildScripts_enable().to_owned() || self.procMacro_enable().to_owned()
}
pub fn cargo(&self) -> CargoConfig {
- let rustc_source = self.data.rustc_source.as_ref().map(|rustc_src| {
+ let rustc_source = self.rustc_source().as_ref().map(|rustc_src| {
if rustc_src == "discover" {
RustLibSource::Discover
} else {
RustLibSource::Path(self.root_path.join(rustc_src))
}
});
- let sysroot = self.data.cargo_sysroot.as_ref().map(|sysroot| {
+ let sysroot = self.cargo_sysroot().as_ref().map(|sysroot| {
if sysroot == "discover" {
RustLibSource::Discover
} else {
@@ -1283,27 +1572,26 @@ impl Config {
}
});
let sysroot_src =
- self.data.cargo_sysrootSrc.as_ref().map(|sysroot| self.root_path.join(sysroot));
- let sysroot_query_metadata = self.data.cargo_sysrootQueryMetadata;
+ self.cargo_sysrootSrc().as_ref().map(|sysroot| self.root_path.join(sysroot));
+ let sysroot_query_metadata = self.cargo_sysrootQueryMetadata();
CargoConfig {
- all_targets: self.data.cargo_allTargets,
- features: match &self.data.cargo_features {
+ all_targets: *self.cargo_allTargets(),
+ features: match &self.cargo_features() {
CargoFeaturesDef::All => CargoFeatures::All,
CargoFeaturesDef::Selected(features) => CargoFeatures::Selected {
features: features.clone(),
- no_default_features: self.data.cargo_noDefaultFeatures,
+ no_default_features: self.cargo_noDefaultFeatures().to_owned(),
},
},
- target: self.data.cargo_target.clone(),
+ target: self.cargo_target().clone(),
sysroot,
- sysroot_query_metadata,
+ sysroot_query_metadata: *sysroot_query_metadata,
sysroot_src,
rustc_source,
cfg_overrides: project_model::CfgOverrides {
global: CfgDiff::new(
- self.data
- .cargo_cfgs
+ self.cargo_cfgs()
.iter()
.map(|(key, val)| {
if val.is_empty() {
@@ -1317,8 +1605,7 @@ impl Config {
)
.unwrap(),
selective: self
- .data
- .cargo_unsetTest
+ .cargo_unsetTest()
.iter()
.map(|it| {
(
@@ -1328,49 +1615,49 @@ impl Config {
})
.collect(),
},
- wrap_rustc_in_build_scripts: self.data.cargo_buildScripts_useRustcWrapper,
- invocation_strategy: match self.data.cargo_buildScripts_invocationStrategy {
+ wrap_rustc_in_build_scripts: *self.cargo_buildScripts_useRustcWrapper(),
+ invocation_strategy: match self.cargo_buildScripts_invocationStrategy() {
InvocationStrategy::Once => project_model::InvocationStrategy::Once,
InvocationStrategy::PerWorkspace => project_model::InvocationStrategy::PerWorkspace,
},
- invocation_location: match self.data.cargo_buildScripts_invocationLocation {
+ invocation_location: match self.cargo_buildScripts_invocationLocation() {
InvocationLocation::Root => {
project_model::InvocationLocation::Root(self.root_path.clone())
}
InvocationLocation::Workspace => project_model::InvocationLocation::Workspace,
},
- run_build_script_command: self.data.cargo_buildScripts_overrideCommand.clone(),
- extra_args: self.data.cargo_extraArgs.clone(),
- extra_env: self.data.cargo_extraEnv.clone(),
+ run_build_script_command: self.cargo_buildScripts_overrideCommand().clone(),
+ extra_args: self.cargo_extraArgs().clone(),
+ extra_env: self.cargo_extraEnv().clone(),
target_dir: self.target_dir_from_config(),
}
}
pub fn rustfmt(&self) -> RustfmtConfig {
- match &self.data.rustfmt_overrideCommand {
+ match &self.rustfmt_overrideCommand() {
Some(args) if !args.is_empty() => {
let mut args = args.clone();
let command = args.remove(0);
RustfmtConfig::CustomCommand { command, args }
}
Some(_) | None => RustfmtConfig::Rustfmt {
- extra_args: self.data.rustfmt_extraArgs.clone(),
- enable_range_formatting: self.data.rustfmt_rangeFormatting_enable,
+ extra_args: self.rustfmt_extraArgs().clone(),
+ enable_range_formatting: *self.rustfmt_rangeFormatting_enable(),
},
}
}
pub fn flycheck_workspace(&self) -> bool {
- self.data.check_workspace
+ *self.check_workspace()
}
pub fn cargo_test_options(&self) -> CargoOptions {
CargoOptions {
- target_triples: self.data.cargo_target.clone().into_iter().collect(),
+ target_triples: self.cargo_target().clone().into_iter().collect(),
all_targets: false,
- no_default_features: self.data.cargo_noDefaultFeatures,
- all_features: matches!(self.data.cargo_features, CargoFeaturesDef::All),
- features: match self.data.cargo_features.clone() {
+ no_default_features: *self.cargo_noDefaultFeatures(),
+ all_features: matches!(self.cargo_features(), CargoFeaturesDef::All),
+ features: match self.cargo_features().clone() {
CargoFeaturesDef::All => vec![],
CargoFeaturesDef::Selected(it) => it,
},
@@ -1381,7 +1668,7 @@ impl Config {
}
pub fn flycheck(&self) -> FlycheckConfig {
- match &self.data.check_overrideCommand {
+ match &self.check_overrideCommand() {
Some(args) if !args.is_empty() => {
let mut args = args.clone();
let command = args.remove(0);
@@ -1389,13 +1676,13 @@ impl Config {
command,
args,
extra_env: self.check_extra_env(),
- invocation_strategy: match self.data.check_invocationStrategy {
+ invocation_strategy: match self.check_invocationStrategy() {
InvocationStrategy::Once => flycheck::InvocationStrategy::Once,
InvocationStrategy::PerWorkspace => {
flycheck::InvocationStrategy::PerWorkspace
}
},
- invocation_location: match self.data.check_invocationLocation {
+ invocation_location: match self.check_invocationLocation() {
InvocationLocation::Root => {
flycheck::InvocationLocation::Root(self.root_path.clone())
}
@@ -1404,31 +1691,28 @@ impl Config {
}
}
Some(_) | None => FlycheckConfig::CargoCommand {
- command: self.data.check_command.clone(),
+ command: self.check_command().clone(),
options: CargoOptions {
target_triples: self
- .data
- .check_targets
+ .check_targets()
.clone()
.and_then(|targets| match &targets.0[..] {
[] => None,
targets => Some(targets.into()),
})
- .unwrap_or_else(|| self.data.cargo_target.clone().into_iter().collect()),
- all_targets: self.data.check_allTargets.unwrap_or(self.data.cargo_allTargets),
+ .unwrap_or_else(|| self.cargo_target().clone().into_iter().collect()),
+ all_targets: self.check_allTargets().unwrap_or(*self.cargo_allTargets()),
no_default_features: self
- .data
- .check_noDefaultFeatures
- .unwrap_or(self.data.cargo_noDefaultFeatures),
+ .check_noDefaultFeatures()
+ .unwrap_or(*self.cargo_noDefaultFeatures()),
all_features: matches!(
- self.data.check_features.as_ref().unwrap_or(&self.data.cargo_features),
+ self.check_features().as_ref().unwrap_or(self.cargo_features()),
CargoFeaturesDef::All
),
features: match self
- .data
- .check_features
+ .check_features()
.clone()
- .unwrap_or_else(|| self.data.cargo_features.clone())
+ .unwrap_or_else(|| self.cargo_features().clone())
{
CargoFeaturesDef::All => vec![],
CargoFeaturesDef::Selected(it) => it,
@@ -1443,7 +1727,7 @@ impl Config {
}
fn target_dir_from_config(&self) -> Option<Utf8PathBuf> {
- self.data.cargo_targetDir.as_ref().and_then(|target_dir| match target_dir {
+ self.cargo_targetDir().as_ref().and_then(|target_dir| match target_dir {
TargetDirectory::UseSubdirectory(true) => {
Some(Utf8PathBuf::from("target/rust-analyzer"))
}
@@ -1454,294 +1738,66 @@ impl Config {
}
pub fn check_on_save(&self) -> bool {
- self.data.checkOnSave
+ *self.checkOnSave()
}
pub fn script_rebuild_on_save(&self) -> bool {
- self.data.cargo_buildScripts_rebuildOnSave
+ *self.cargo_buildScripts_rebuildOnSave()
}
pub fn runnables(&self) -> RunnablesConfig {
RunnablesConfig {
- override_cargo: self.data.runnables_command.clone(),
- cargo_extra_args: self.data.runnables_extraArgs.clone(),
- }
- }
-
- pub fn inlay_hints(&self) -> InlayHintsConfig {
- let client_capability_fields = self
- .caps
- .text_document
- .as_ref()
- .and_then(|text| text.inlay_hint.as_ref())
- .and_then(|inlay_hint_caps| inlay_hint_caps.resolve_support.as_ref())
- .map(|inlay_resolve| inlay_resolve.properties.iter())
- .into_iter()
- .flatten()
- .cloned()
- .collect::<FxHashSet<_>>();
-
- InlayHintsConfig {
- render_colons: self.data.inlayHints_renderColons,
- type_hints: self.data.inlayHints_typeHints_enable,
- parameter_hints: self.data.inlayHints_parameterHints_enable,
- chaining_hints: self.data.inlayHints_chainingHints_enable,
- implicit_drop_hints: self.data.inlayHints_implicitDrops_enable,
- discriminant_hints: match self.data.inlayHints_discriminantHints_enable {
- DiscriminantHintsDef::Always => ide::DiscriminantHints::Always,
- DiscriminantHintsDef::Never => ide::DiscriminantHints::Never,
- DiscriminantHintsDef::Fieldless => ide::DiscriminantHints::Fieldless,
- },
- closure_return_type_hints: match self.data.inlayHints_closureReturnTypeHints_enable {
- ClosureReturnTypeHintsDef::Always => ide::ClosureReturnTypeHints::Always,
- ClosureReturnTypeHintsDef::Never => ide::ClosureReturnTypeHints::Never,
- ClosureReturnTypeHintsDef::WithBlock => ide::ClosureReturnTypeHints::WithBlock,
- },
- lifetime_elision_hints: match self.data.inlayHints_lifetimeElisionHints_enable {
- LifetimeElisionDef::Always => ide::LifetimeElisionHints::Always,
- LifetimeElisionDef::Never => ide::LifetimeElisionHints::Never,
- LifetimeElisionDef::SkipTrivial => ide::LifetimeElisionHints::SkipTrivial,
- },
- hide_named_constructor_hints: self.data.inlayHints_typeHints_hideNamedConstructor,
- hide_closure_initialization_hints: self
- .data
- .inlayHints_typeHints_hideClosureInitialization,
- closure_style: match self.data.inlayHints_closureStyle {
- ClosureStyle::ImplFn => hir::ClosureStyle::ImplFn,
- ClosureStyle::RustAnalyzer => hir::ClosureStyle::RANotation,
- ClosureStyle::WithId => hir::ClosureStyle::ClosureWithId,
- ClosureStyle::Hide => hir::ClosureStyle::Hide,
- },
- closure_capture_hints: self.data.inlayHints_closureCaptureHints_enable,
- adjustment_hints: match self.data.inlayHints_expressionAdjustmentHints_enable {
- AdjustmentHintsDef::Always => ide::AdjustmentHints::Always,
- AdjustmentHintsDef::Never => match self.data.inlayHints_reborrowHints_enable {
- ReborrowHintsDef::Always | ReborrowHintsDef::Mutable => {
- ide::AdjustmentHints::ReborrowOnly
- }
- ReborrowHintsDef::Never => ide::AdjustmentHints::Never,
- },
- AdjustmentHintsDef::Reborrow => ide::AdjustmentHints::ReborrowOnly,
- },
- adjustment_hints_mode: match self.data.inlayHints_expressionAdjustmentHints_mode {
- AdjustmentHintsModeDef::Prefix => ide::AdjustmentHintsMode::Prefix,
- AdjustmentHintsModeDef::Postfix => ide::AdjustmentHintsMode::Postfix,
- AdjustmentHintsModeDef::PreferPrefix => ide::AdjustmentHintsMode::PreferPrefix,
- AdjustmentHintsModeDef::PreferPostfix => ide::AdjustmentHintsMode::PreferPostfix,
- },
- adjustment_hints_hide_outside_unsafe: self
- .data
- .inlayHints_expressionAdjustmentHints_hideOutsideUnsafe,
- binding_mode_hints: self.data.inlayHints_bindingModeHints_enable,
- param_names_for_lifetime_elision_hints: self
- .data
- .inlayHints_lifetimeElisionHints_useParameterNames,
- max_length: self.data.inlayHints_maxLength,
- closing_brace_hints_min_lines: if self.data.inlayHints_closingBraceHints_enable {
- Some(self.data.inlayHints_closingBraceHints_minLines)
- } else {
- None
- },
- range_exclusive_hints: self.data.inlayHints_rangeExclusiveHints_enable,
- fields_to_resolve: InlayFieldsToResolve {
- resolve_text_edits: client_capability_fields.contains("textEdits"),
- resolve_hint_tooltip: client_capability_fields.contains("tooltip"),
- resolve_label_tooltip: client_capability_fields.contains("label.tooltip"),
- resolve_label_location: client_capability_fields.contains("label.location"),
- resolve_label_command: client_capability_fields.contains("label.command"),
- },
- }
- }
-
- fn insert_use_config(&self) -> InsertUseConfig {
- InsertUseConfig {
- granularity: match self.data.imports_granularity_group {
- ImportGranularityDef::Preserve => ImportGranularity::Preserve,
- ImportGranularityDef::Item => ImportGranularity::Item,
- ImportGranularityDef::Crate => ImportGranularity::Crate,
- ImportGranularityDef::Module => ImportGranularity::Module,
- ImportGranularityDef::One => ImportGranularity::One,
- },
- enforce_granularity: self.data.imports_granularity_enforce,
- prefix_kind: match self.data.imports_prefix {
- ImportPrefixDef::Plain => PrefixKind::Plain,
- ImportPrefixDef::ByCrate => PrefixKind::ByCrate,
- ImportPrefixDef::BySelf => PrefixKind::BySelf,
- },
- group: self.data.imports_group_enable,
- skip_glob_imports: !self.data.imports_merge_glob,
- }
- }
-
- pub fn completion(&self) -> CompletionConfig {
- CompletionConfig {
- enable_postfix_completions: self.data.completion_postfix_enable,
- enable_imports_on_the_fly: self.data.completion_autoimport_enable
- && completion_item_edit_resolve(&self.caps),
- enable_self_on_the_fly: self.data.completion_autoself_enable,
- enable_private_editable: self.data.completion_privateEditable_enable,
- enable_term_search: self.data.completion_termSearch_enable,
- full_function_signatures: self.data.completion_fullFunctionSignatures_enable,
- callable: match self.data.completion_callable_snippets {
- CallableCompletionDef::FillArguments => Some(CallableSnippets::FillArguments),
- CallableCompletionDef::AddParentheses => Some(CallableSnippets::AddParentheses),
- CallableCompletionDef::None => None,
- },
- insert_use: self.insert_use_config(),
- prefer_no_std: self.data.imports_preferNoStd,
- prefer_prelude: self.data.imports_preferPrelude,
- snippet_cap: SnippetCap::new(try_or_def!(
- self.caps
- .text_document
- .as_ref()?
- .completion
- .as_ref()?
- .completion_item
- .as_ref()?
- .snippet_support?
- )),
- snippets: self.snippets.clone(),
- limit: self.data.completion_limit,
+ override_cargo: self.runnables_command().clone(),
+ cargo_extra_args: self.runnables_extraArgs().clone(),
}
}
pub fn find_all_refs_exclude_imports(&self) -> bool {
- self.data.references_excludeImports
+ *self.references_excludeImports()
}
pub fn find_all_refs_exclude_tests(&self) -> bool {
- self.data.references_excludeTests
+ *self.references_excludeTests()
}
pub fn snippet_cap(&self) -> bool {
self.experimental("snippetTextEdit")
}
- pub fn assist(&self) -> AssistConfig {
- AssistConfig {
- snippet_cap: SnippetCap::new(self.experimental("snippetTextEdit")),
- allowed: None,
- insert_use: self.insert_use_config(),
- prefer_no_std: self.data.imports_preferNoStd,
- prefer_prelude: self.data.imports_preferPrelude,
- assist_emit_must_use: self.data.assist_emitMustUse,
- }
- }
-
- pub fn join_lines(&self) -> JoinLinesConfig {
- JoinLinesConfig {
- join_else_if: self.data.joinLines_joinElseIf,
- remove_trailing_comma: self.data.joinLines_removeTrailingComma,
- unwrap_trivial_blocks: self.data.joinLines_unwrapTrivialBlock,
- join_assignments: self.data.joinLines_joinAssignments,
- }
- }
-
pub fn call_info(&self) -> CallInfoConfig {
CallInfoConfig {
- params_only: matches!(self.data.signatureInfo_detail, SignatureDetail::Parameters),
- docs: self.data.signatureInfo_documentation_enable,
+ params_only: matches!(self.signatureInfo_detail(), SignatureDetail::Parameters),
+ docs: *self.signatureInfo_documentation_enable(),
}
}
pub fn lens(&self) -> LensConfig {
LensConfig {
- run: self.data.lens_enable && self.data.lens_run_enable,
- debug: self.data.lens_enable && self.data.lens_debug_enable,
- interpret: self.data.lens_enable
- && self.data.lens_run_enable
- && self.data.interpret_tests,
- implementations: self.data.lens_enable && self.data.lens_implementations_enable,
- method_refs: self.data.lens_enable && self.data.lens_references_method_enable,
- refs_adt: self.data.lens_enable && self.data.lens_references_adt_enable,
- refs_trait: self.data.lens_enable && self.data.lens_references_trait_enable,
- enum_variant_refs: self.data.lens_enable
- && self.data.lens_references_enumVariant_enable,
- location: self.data.lens_location,
- }
- }
-
- pub fn hover_actions(&self) -> HoverActionsConfig {
- let enable = self.experimental("hoverActions") && self.data.hover_actions_enable;
- HoverActionsConfig {
- implementations: enable && self.data.hover_actions_implementations_enable,
- references: enable && self.data.hover_actions_references_enable,
- run: enable && self.data.hover_actions_run_enable,
- debug: enable && self.data.hover_actions_debug_enable,
- goto_type_def: enable && self.data.hover_actions_gotoTypeDef_enable,
- }
- }
-
- pub fn highlighting_non_standard_tokens(&self) -> bool {
- self.data.semanticHighlighting_nonStandardTokens
- }
-
- pub fn highlighting_config(&self) -> HighlightConfig {
- HighlightConfig {
- strings: self.data.semanticHighlighting_strings_enable,
- punctuation: self.data.semanticHighlighting_punctuation_enable,
- specialize_punctuation: self
- .data
- .semanticHighlighting_punctuation_specialization_enable,
- macro_bang: self.data.semanticHighlighting_punctuation_separate_macro_bang,
- operator: self.data.semanticHighlighting_operator_enable,
- specialize_operator: self.data.semanticHighlighting_operator_specialization_enable,
- inject_doc_comment: self.data.semanticHighlighting_doc_comment_inject_enable,
- syntactic_name_ref_highlighting: false,
- }
- }
-
- pub fn hover(&self) -> HoverConfig {
- let mem_kind = |kind| match kind {
- MemoryLayoutHoverRenderKindDef::Both => MemoryLayoutHoverRenderKind::Both,
- MemoryLayoutHoverRenderKindDef::Decimal => MemoryLayoutHoverRenderKind::Decimal,
- MemoryLayoutHoverRenderKindDef::Hexadecimal => MemoryLayoutHoverRenderKind::Hexadecimal,
- };
- HoverConfig {
- links_in_hover: self.data.hover_links_enable,
- memory_layout: self.data.hover_memoryLayout_enable.then_some(MemoryLayoutHoverConfig {
- size: self.data.hover_memoryLayout_size.map(mem_kind),
- offset: self.data.hover_memoryLayout_offset.map(mem_kind),
- alignment: self.data.hover_memoryLayout_alignment.map(mem_kind),
- niches: self.data.hover_memoryLayout_niches.unwrap_or_default(),
- }),
- documentation: self.data.hover_documentation_enable,
- format: {
- let is_markdown = try_or_def!(self
- .caps
- .text_document
- .as_ref()?
- .hover
- .as_ref()?
- .content_format
- .as_ref()?
- .as_slice())
- .contains(&MarkupKind::Markdown);
- if is_markdown {
- HoverDocFormat::Markdown
- } else {
- HoverDocFormat::PlainText
- }
- },
- keywords: self.data.hover_documentation_keywords_enable,
- max_trait_assoc_items_count: self.data.hover_show_traitAssocItems,
- max_struct_field_count: self.data.hover_show_structFields,
+ run: *self.lens_run_enable(),
+ debug: *self.lens_enable() && *self.lens_debug_enable(),
+ interpret: *self.lens_enable() && *self.lens_run_enable() && *self.interpret_tests(),
+ implementations: *self.lens_enable() && *self.lens_implementations_enable(),
+ method_refs: *self.lens_enable() && *self.lens_references_method_enable(),
+ refs_adt: *self.lens_enable() && *self.lens_references_adt_enable(),
+ refs_trait: *self.lens_enable() && *self.lens_references_trait_enable(),
+ enum_variant_refs: *self.lens_enable() && *self.lens_references_enumVariant_enable(),
+ location: *self.lens_location(),
}
}
pub fn workspace_symbol(&self) -> WorkspaceSymbolConfig {
WorkspaceSymbolConfig {
- search_scope: match self.data.workspace_symbol_search_scope {
+ search_scope: match self.workspace_symbol_search_scope() {
WorkspaceSymbolSearchScopeDef::Workspace => WorkspaceSymbolSearchScope::Workspace,
WorkspaceSymbolSearchScopeDef::WorkspaceAndDependencies => {
WorkspaceSymbolSearchScope::WorkspaceAndDependencies
}
},
- search_kind: match self.data.workspace_symbol_search_kind {
+ search_kind: match self.workspace_symbol_search_kind() {
WorkspaceSymbolSearchKindDef::OnlyTypes => WorkspaceSymbolSearchKind::OnlyTypes,
WorkspaceSymbolSearchKindDef::AllSymbols => WorkspaceSymbolSearchKind::AllSymbols,
},
- search_limit: self.data.workspace_symbol_search_limit,
+ search_limit: *self.workspace_symbol_search_limit(),
}
}
@@ -1775,7 +1831,7 @@ impl Config {
try_or!(self.caps.experimental.as_ref()?.get("commands")?, &serde_json::Value::Null);
let commands: Option<lsp_ext::ClientCommandOptions> =
serde_json::from_value(commands.clone()).ok();
- let force = commands.is_none() && self.data.lens_forceCustomCommands;
+ let force = commands.is_none() && *self.lens_forceCustomCommands();
let commands = commands.map(|it| it.commands).unwrap_or_default();
let get = |name: &str| commands.iter().any(|it| it == name) || force;
@@ -1789,29 +1845,19 @@ impl Config {
}
}
- pub fn highlight_related(&self) -> HighlightRelatedConfig {
- HighlightRelatedConfig {
- references: self.data.highlightRelated_references_enable,
- break_points: self.data.highlightRelated_breakPoints_enable,
- exit_points: self.data.highlightRelated_exitPoints_enable,
- yield_points: self.data.highlightRelated_yieldPoints_enable,
- closure_captures: self.data.highlightRelated_closureCaptures_enable,
- }
- }
-
pub fn prime_caches_num_threads(&self) -> u8 {
- match self.data.cachePriming_numThreads {
+ match *self.cachePriming_numThreads() {
0 => num_cpus::get_physical().try_into().unwrap_or(u8::MAX),
n => n,
}
}
pub fn main_loop_num_threads(&self) -> usize {
- self.data.numThreads.unwrap_or(num_cpus::get_physical())
+ self.numThreads().unwrap_or(num_cpus::get_physical())
}
pub fn typing_autoclose_angle(&self) -> bool {
- self.data.typing_autoClosingAngleBrackets_enable
+ *self.typing_autoClosingAngleBrackets_enable()
}
// VSCode is our reference implementation, so we allow ourselves to work around issues by
@@ -1822,100 +1868,120 @@ impl Config {
}
// Deserialization definitions
-macro_rules! create_bool_or_string_de {
+macro_rules! create_bool_or_string_serde {
($ident:ident<$bool:literal, $string:literal>) => {
- fn $ident<'de, D>(d: D) -> Result<(), D::Error>
- where
- D: serde::Deserializer<'de>,
- {
- struct V;
- impl<'de> serde::de::Visitor<'de> for V {
- type Value = ();
-
- fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
- formatter.write_str(concat!(
- stringify!($bool),
- " or \"",
- stringify!($string),
- "\""
- ))
- }
+ mod $ident {
+ pub(super) fn deserialize<'de, D>(d: D) -> Result<(), D::Error>
+ where
+ D: serde::Deserializer<'de>,
+ {
+ struct V;
+ impl<'de> serde::de::Visitor<'de> for V {
+ type Value = ();
+
+ fn expecting(
+ &self,
+ formatter: &mut std::fmt::Formatter<'_>,
+ ) -> std::fmt::Result {
+ formatter.write_str(concat!(
+ stringify!($bool),
+ " or \"",
+ stringify!($string),
+ "\""
+ ))
+ }
- fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
- where
- E: serde::de::Error,
- {
- match v {
- $bool => Ok(()),
- _ => Err(serde::de::Error::invalid_value(
- serde::de::Unexpected::Bool(v),
- &self,
- )),
+ fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
+ where
+ E: serde::de::Error,
+ {
+ match v {
+ $bool => Ok(()),
+ _ => Err(serde::de::Error::invalid_value(
+ serde::de::Unexpected::Bool(v),
+ &self,
+ )),
+ }
}
- }
- fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
- where
- E: serde::de::Error,
- {
- match v {
- $string => Ok(()),
- _ => Err(serde::de::Error::invalid_value(
- serde::de::Unexpected::Str(v),
- &self,
- )),
+ fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
+ where
+ E: serde::de::Error,
+ {
+ match v {
+ $string => Ok(()),
+ _ => Err(serde::de::Error::invalid_value(
+ serde::de::Unexpected::Str(v),
+ &self,
+ )),
+ }
}
- }
- fn visit_enum<A>(self, a: A) -> Result<Self::Value, A::Error>
- where
- A: serde::de::EnumAccess<'de>,
- {
- use serde::de::VariantAccess;
- let (variant, va) = a.variant::<&'de str>()?;
- va.unit_variant()?;
- match variant {
- $string => Ok(()),
- _ => Err(serde::de::Error::invalid_value(
- serde::de::Unexpected::Str(variant),
- &self,
- )),
+ fn visit_enum<A>(self, a: A) -> Result<Self::Value, A::Error>
+ where
+ A: serde::de::EnumAccess<'de>,
+ {
+ use serde::de::VariantAccess;
+ let (variant, va) = a.variant::<&'de str>()?;
+ va.unit_variant()?;
+ match variant {
+ $string => Ok(()),
+ _ => Err(serde::de::Error::invalid_value(
+ serde::de::Unexpected::Str(variant),
+ &self,
+ )),
+ }
}
}
+ d.deserialize_any(V)
+ }
+
+ pub(super) fn serialize<S>(serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: serde::Serializer,
+ {
+ serializer.serialize_str($string)
}
- d.deserialize_any(V)
}
};
}
-create_bool_or_string_de!(true_or_always<true, "always">);
-create_bool_or_string_de!(false_or_never<false, "never">);
+create_bool_or_string_serde!(true_or_always<true, "always">);
+create_bool_or_string_serde!(false_or_never<false, "never">);
macro_rules! named_unit_variant {
($variant:ident) => {
- pub(super) fn $variant<'de, D>(deserializer: D) -> Result<(), D::Error>
- where
- D: serde::Deserializer<'de>,
- {
- struct V;
- impl<'de> serde::de::Visitor<'de> for V {
- type Value = ();
- fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.write_str(concat!("\"", stringify!($variant), "\""))
- }
- fn visit_str<E: serde::de::Error>(self, value: &str) -> Result<Self::Value, E> {
- if value == stringify!($variant) {
- Ok(())
- } else {
- Err(E::invalid_value(serde::de::Unexpected::Str(value), &self))
+ pub(super) mod $variant {
+ pub(in super::super) fn deserialize<'de, D>(deserializer: D) -> Result<(), D::Error>
+ where
+ D: serde::Deserializer<'de>,
+ {
+ struct V;
+ impl<'de> serde::de::Visitor<'de> for V {
+ type Value = ();
+ fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.write_str(concat!("\"", stringify!($variant), "\""))
+ }
+ fn visit_str<E: serde::de::Error>(self, value: &str) -> Result<Self::Value, E> {
+ if value == stringify!($variant) {
+ Ok(())
+ } else {
+ Err(E::invalid_value(serde::de::Unexpected::Str(value), &self))
+ }
}
}
+ deserializer.deserialize_str(V)
+ }
+ pub(in super::super) fn serialize<S>(serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: serde::Serializer,
+ {
+ serializer.serialize_str(stringify!($variant))
}
- deserializer.deserialize_str(V)
}
};
}
-mod de_unit_v {
+mod unit_v {
named_unit_variant!(all);
named_unit_variant!(skip_trivial);
named_unit_variant!(mutable);
@@ -1927,7 +1993,7 @@ mod de_unit_v {
named_unit_variant!(both);
}
-#[derive(Deserialize, Debug, Clone, Copy)]
+#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq)]
#[serde(rename_all = "snake_case")]
#[derive(Default)]
enum SnippetScopeDef {
@@ -1937,67 +2003,92 @@ enum SnippetScopeDef {
Type,
}
-#[derive(Deserialize, Debug, Clone, Default)]
+#[derive(Serialize, Deserialize, Debug, Clone, Default)]
#[serde(default)]
struct SnippetDef {
- #[serde(deserialize_with = "single_or_array")]
+ #[serde(with = "single_or_array")]
+ #[serde(skip_serializing_if = "Vec::is_empty")]
prefix: Vec<String>,
- #[serde(deserialize_with = "single_or_array")]
+
+ #[serde(with = "single_or_array")]
+ #[serde(skip_serializing_if = "Vec::is_empty")]
postfix: Vec<String>,
- description: Option<String>,
- #[serde(deserialize_with = "single_or_array")]
+
+ #[serde(with = "single_or_array")]
+ #[serde(skip_serializing_if = "Vec::is_empty")]
body: Vec<String>,
- #[serde(deserialize_with = "single_or_array")]
+
+ #[serde(with = "single_or_array")]
+ #[serde(skip_serializing_if = "Vec::is_empty")]
requires: Vec<String>,
+
+ #[serde(skip_serializing_if = "Option::is_none")]
+ description: Option<String>,
+
scope: SnippetScopeDef,
}
-fn single_or_array<'de, D>(deserializer: D) -> Result<Vec<String>, D::Error>
-where
- D: serde::Deserializer<'de>,
-{
- struct SingleOrVec;
+mod single_or_array {
+ use serde::{Deserialize, Serialize};
- impl<'de> serde::de::Visitor<'de> for SingleOrVec {
- type Value = Vec<String>;
+ pub(super) fn deserialize<'de, D>(deserializer: D) -> Result<Vec<String>, D::Error>
+ where
+ D: serde::Deserializer<'de>,
+ {
+ struct SingleOrVec;
- fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- formatter.write_str("string or array of strings")
- }
+ impl<'de> serde::de::Visitor<'de> for SingleOrVec {
+ type Value = Vec<String>;
- fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
- where
- E: serde::de::Error,
- {
- Ok(vec![value.to_owned()])
- }
+ fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ formatter.write_str("string or array of strings")
+ }
- fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
- where
- A: serde::de::SeqAccess<'de>,
- {
- Deserialize::deserialize(serde::de::value::SeqAccessDeserializer::new(seq))
+ fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
+ where
+ E: serde::de::Error,
+ {
+ Ok(vec![value.to_owned()])
+ }
+
+ fn visit_seq<A>(self, seq: A) -> Result<Self::Value, A::Error>
+ where
+ A: serde::de::SeqAccess<'de>,
+ {
+ Deserialize::deserialize(serde::de::value::SeqAccessDeserializer::new(seq))
+ }
}
+
+ deserializer.deserialize_any(SingleOrVec)
}
- deserializer.deserialize_any(SingleOrVec)
+ pub(super) fn serialize<S>(vec: &[String], serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: serde::Serializer,
+ {
+ match vec {
+ // [] case is handled by skip_serializing_if
+ [single] => serializer.serialize_str(single),
+ slice => slice.serialize(serializer),
+ }
+ }
}
-#[derive(Deserialize, Debug, Clone)]
+#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(untagged)]
enum ManifestOrProjectJson {
Manifest(Utf8PathBuf),
ProjectJson(ProjectJsonData),
}
-#[derive(Deserialize, Debug, Clone)]
+#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "snake_case")]
enum ExprFillDefaultDef {
Todo,
Default,
}
-#[derive(Deserialize, Debug, Clone)]
+#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "snake_case")]
enum ImportGranularityDef {
Preserve,
@@ -2007,7 +2098,7 @@ enum ImportGranularityDef {
One,
}
-#[derive(Deserialize, Debug, Copy, Clone)]
+#[derive(Serialize, Deserialize, Debug, Copy, Clone)]
#[serde(rename_all = "snake_case")]
enum CallableCompletionDef {
FillArguments,
@@ -2015,54 +2106,54 @@ enum CallableCompletionDef {
None,
}
-#[derive(Deserialize, Debug, Clone)]
+#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(untagged)]
enum CargoFeaturesDef {
- #[serde(deserialize_with = "de_unit_v::all")]
+ #[serde(with = "unit_v::all")]
All,
Selected(Vec<String>),
}
-#[derive(Deserialize, Debug, Clone)]
+#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "snake_case")]
-enum InvocationStrategy {
+pub(crate) enum InvocationStrategy {
Once,
PerWorkspace,
}
-#[derive(Deserialize, Debug, Clone)]
-struct CheckOnSaveTargets(#[serde(deserialize_with = "single_or_array")] Vec<String>);
+#[derive(Serialize, Deserialize, Debug, Clone)]
+struct CheckOnSaveTargets(#[serde(with = "single_or_array")] Vec<String>);
-#[derive(Deserialize, Debug, Clone)]
+#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "snake_case")]
enum InvocationLocation {
Root,
Workspace,
}
-#[derive(Deserialize, Debug, Clone)]
+#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(untagged)]
enum LifetimeElisionDef {
- #[serde(deserialize_with = "true_or_always")]
+ #[serde(with = "true_or_always")]
Always,
- #[serde(deserialize_with = "false_or_never")]
+ #[serde(with = "false_or_never")]
Never,
- #[serde(deserialize_with = "de_unit_v::skip_trivial")]
+ #[serde(with = "unit_v::skip_trivial")]
SkipTrivial,
}
-#[derive(Deserialize, Debug, Clone)]
+#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(untagged)]
enum ClosureReturnTypeHintsDef {
- #[serde(deserialize_with = "true_or_always")]
+ #[serde(with = "true_or_always")]
Always,
- #[serde(deserialize_with = "false_or_never")]
+ #[serde(with = "false_or_never")]
Never,
- #[serde(deserialize_with = "de_unit_v::with_block")]
+ #[serde(with = "unit_v::with_block")]
WithBlock,
}
-#[derive(Deserialize, Debug, Clone)]
+#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "snake_case")]
enum ClosureStyle {
ImplFn,
@@ -2071,40 +2162,40 @@ enum ClosureStyle {
Hide,
}
-#[derive(Deserialize, Debug, Clone)]
+#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(untagged)]
enum ReborrowHintsDef {
- #[serde(deserialize_with = "true_or_always")]
+ #[serde(with = "true_or_always")]
Always,
- #[serde(deserialize_with = "false_or_never")]
+ #[serde(with = "false_or_never")]
Never,
- #[serde(deserialize_with = "de_unit_v::mutable")]
+ #[serde(with = "unit_v::mutable")]
Mutable,
}
-#[derive(Deserialize, Debug, Clone)]
+#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(untagged)]
enum AdjustmentHintsDef {
- #[serde(deserialize_with = "true_or_always")]
+ #[serde(with = "true_or_always")]
Always,
- #[serde(deserialize_with = "false_or_never")]
+ #[serde(with = "false_or_never")]
Never,
- #[serde(deserialize_with = "de_unit_v::reborrow")]
+ #[serde(with = "unit_v::reborrow")]
Reborrow,
}
-#[derive(Deserialize, Debug, Clone)]
+#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(untagged)]
enum DiscriminantHintsDef {
- #[serde(deserialize_with = "true_or_always")]
+ #[serde(with = "true_or_always")]
Always,
- #[serde(deserialize_with = "false_or_never")]
+ #[serde(with = "false_or_never")]
Never,
- #[serde(deserialize_with = "de_unit_v::fieldless")]
+ #[serde(with = "unit_v::fieldless")]
Fieldless,
}
-#[derive(Deserialize, Debug, Clone)]
+#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "snake_case")]
enum AdjustmentHintsModeDef {
Prefix,
@@ -2113,7 +2204,7 @@ enum AdjustmentHintsModeDef {
PreferPostfix,
}
-#[derive(Deserialize, Debug, Clone)]
+#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "snake_case")]
enum FilesWatcherDef {
Client,
@@ -2121,7 +2212,7 @@ enum FilesWatcherDef {
Server,
}
-#[derive(Deserialize, Debug, Clone)]
+#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "snake_case")]
enum ImportPrefixDef {
Plain,
@@ -2131,40 +2222,51 @@ enum ImportPrefixDef {
ByCrate,
}
-#[derive(Deserialize, Debug, Clone)]
+#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "snake_case")]
enum WorkspaceSymbolSearchScopeDef {
Workspace,
WorkspaceAndDependencies,
}
-#[derive(Deserialize, Debug, Clone)]
+#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "snake_case")]
enum SignatureDetail {
Full,
Parameters,
}
-#[derive(Deserialize, Debug, Clone)]
+#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "snake_case")]
enum WorkspaceSymbolSearchKindDef {
OnlyTypes,
AllSymbols,
}
-#[derive(Deserialize, Debug, Copy, Clone)]
+#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq)]
#[serde(rename_all = "snake_case")]
#[serde(untagged)]
-pub enum MemoryLayoutHoverRenderKindDef {
- #[serde(deserialize_with = "de_unit_v::decimal")]
+enum MemoryLayoutHoverRenderKindDef {
+ #[serde(with = "unit_v::decimal")]
Decimal,
- #[serde(deserialize_with = "de_unit_v::hexadecimal")]
+ #[serde(with = "unit_v::hexadecimal")]
Hexadecimal,
- #[serde(deserialize_with = "de_unit_v::both")]
+ #[serde(with = "unit_v::both")]
Both,
}
-#[derive(Deserialize, Debug, Clone, PartialEq)]
+#[test]
+fn untagged_option_hover_render_kind() {
+ let hex = MemoryLayoutHoverRenderKindDef::Hexadecimal;
+
+ let ser = serde_json::to_string(&Some(hex)).unwrap();
+ assert_eq!(&ser, "\"hexadecimal\"");
+
+ let opt: Option<_> = serde_json::from_str("\"hexadecimal\"").unwrap();
+ assert_eq!(opt, Some(hex));
+}
+
+#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(rename_all = "snake_case")]
#[serde(untagged)]
pub enum TargetDirectory {
@@ -2172,68 +2274,326 @@ pub enum TargetDirectory {
Directory(Utf8PathBuf),
}
+macro_rules! _default_val {
+ (@verbatim: $s:literal, $ty:ty) => {{
+ let default_: $ty = serde_json::from_str(&$s).unwrap();
+ default_
+ }};
+ ($default:expr, $ty:ty) => {{
+ let default_: $ty = $default;
+ default_
+ }};
+}
+use _default_val as default_val;
+
+macro_rules! _default_str {
+ (@verbatim: $s:literal, $_ty:ty) => {
+ $s.to_owned()
+ };
+ ($default:expr, $ty:ty) => {{
+ let val = default_val!($default, $ty);
+ serde_json::to_string_pretty(&val).unwrap()
+ }};
+}
+use _default_str as default_str;
+
+macro_rules! _impl_for_config_data {
+ (local, $(
+ $(#[doc=$doc:literal])*
+ $vis:vis $field:ident : $ty:ty = $default:expr,
+ )*
+ ) => {
+ impl Config {
+ $(
+ $($doc)*
+ #[allow(non_snake_case)]
+ $vis fn $field(&self, _source_root: Option<SourceRootId>) -> &$ty {
+ if let Some(v) = self.client_config.local.$field.as_ref() {
+ return &v;
+ }
+
+ if let Some(v) = self.user_config.local.$field.as_ref() {
+ return &v;
+ }
+
+ &self.default_config.local.$field
+ }
+ )*
+ }
+ };
+ (global, $(
+ $(#[doc=$doc:literal])*
+ $vis:vis $field:ident : $ty:ty = $default:expr,
+ )*
+ ) => {
+ impl Config {
+ $(
+ $($doc)*
+ #[allow(non_snake_case)]
+ $vis fn $field(&self) -> &$ty {
+ if let Some(v) = self.client_config.global.$field.as_ref() {
+ return &v;
+ }
+
+ if let Some(v) = self.user_config.global.$field.as_ref() {
+ return &v;
+ }
+
+ &self.default_config.global.$field
+ }
+ )*
+ }
+ };
+ (client, $(
+ $(#[doc=$doc:literal])*
+ $vis:vis $field:ident : $ty:ty = $default:expr,
+ )*
+ ) => {
+ impl Config {
+ $(
+ $($doc)*
+ #[allow(non_snake_case)]
+ $vis fn $field(&self) -> &$ty {
+ if let Some(v) = self.client_config.global.$field.as_ref() {
+ return &v;
+ }
+
+ &self.default_config.client.$field
+ }
+ )*
+ }
+ };
+}
+use _impl_for_config_data as impl_for_config_data;
+
macro_rules! _config_data {
- (struct $name:ident {
+ // modname is for the tests
+ ($(#[doc=$dox:literal])* $modname:ident: struct $name:ident <- $input:ident -> {
$(
$(#[doc=$doc:literal])*
- $field:ident $(| $alias:ident)*: $ty:ty = $default:expr,
+ $vis:vis $field:ident $(| $alias:ident)*: $ty:ty = $(@$marker:ident: )? $default:expr,
)*
}) => {
+ /// Default config values for this grouping.
#[allow(non_snake_case)]
- #[derive(Debug, Clone)]
+ #[derive(Debug, Clone, Serialize)]
struct $name { $($field: $ty,)* }
- impl $name {
- fn from_json(mut json: serde_json::Value, error_sink: &mut Vec<(String, serde_json::Error)>) -> $name {
+
+ impl_for_config_data!{
+ $modname,
+ $(
+ $vis $field : $ty = $default,
+ )*
+ }
+
+ /// All fields `Option<T>`, `None` representing fields not set in a particular JSON/TOML blob.
+ #[allow(non_snake_case)]
+ #[derive(Clone, Serialize, Default)]
+ struct $input { $(
+ #[serde(skip_serializing_if = "Option::is_none")]
+ $field: Option<$ty>,
+ )* }
+
+ impl std::fmt::Debug for $input {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ let mut s = f.debug_struct(stringify!($input));
+ $(
+ if let Some(val) = self.$field.as_ref() {
+ s.field(stringify!($field), val);
+ }
+ )*
+ s.finish()
+ }
+ }
+
+ impl Default for $name {
+ fn default() -> Self {
$name {$(
+ $field: default_val!($(@$marker:)? $default, $ty),
+ )*}
+ }
+ }
+
+ #[allow(unused)]
+ impl $name {
+ /// Applies overrides from some more local config blob, to self.
+ fn apply_input(&mut self, input: $input) {
+ $(
+ if let Some(value) = input.$field {
+ self.$field = value;
+ }
+ )*
+ }
+
+ fn clone_with_overrides(&self, input: $input) -> Self {
+ Self {$(
+ $field: input.$field.unwrap_or_else(|| self.$field.clone()),
+ )*}
+ }
+ }
+
+ #[allow(unused, clippy::ptr_arg)]
+ impl $input {
+ fn from_json(json: &mut serde_json::Value, error_sink: &mut Vec<(String, serde_json::Error)>) -> Self {
+ Self {$(
$field: get_field(
- &mut json,
+ json,
error_sink,
stringify!($field),
None$(.or(Some(stringify!($alias))))*,
- $default,
),
)*}
}
- fn json_schema() -> serde_json::Value {
- schema(&[
- $({
- let field = stringify!($field);
- let ty = stringify!($ty);
-
- (field, ty, &[$($doc),*], $default)
- },)*
- ])
+ fn from_toml(toml: &mut toml::Table, error_sink: &mut Vec<(String, toml::de::Error)>) -> Self {
+ Self {$(
+ $field: get_field_toml::<$ty>(
+ toml,
+ error_sink,
+ stringify!($field),
+ None$(.or(Some(stringify!($alias))))*,
+ ),
+ )*}
}
- #[cfg(test)]
- fn manual() -> String {
- manual(&[
+ fn schema_fields(sink: &mut Vec<SchemaField>) {
+ sink.extend_from_slice(&[
$({
let field = stringify!($field);
let ty = stringify!($ty);
+ let default = default_str!($(@$marker:)? $default, $ty);
- (field, ty, &[$($doc),*], $default)
+ (field, ty, &[$($doc),*], default)
},)*
])
}
}
- #[test]
- fn fields_are_sorted() {
- [$(stringify!($field)),*].windows(2).for_each(|w| assert!(w[0] <= w[1], "{} <= {} does not hold", w[0], w[1]));
+ mod $modname {
+ #[test]
+ fn fields_are_sorted() {
+ let field_names: &'static [&'static str] = &[$(stringify!($field)),*];
+ field_names.windows(2).for_each(|w| assert!(w[0] <= w[1], "{} <= {} does not hold", w[0], w[1]));
+ }
}
};
}
use _config_data as config_data;
+#[derive(Default, Debug, Clone)]
+struct DefaultConfigData {
+ global: GlobalDefaultConfigData,
+ local: LocalDefaultConfigData,
+ #[allow(dead_code)]
+ client: ClientDefaultConfigData,
+}
+
+/// All of the config levels, all fields `Option<T>`, to describe fields that are actually set by
+/// some rust-analyzer.toml file or JSON blob. An empty rust-analyzer.toml corresponds to
+/// all fields being None.
+#[derive(Debug, Clone, Default)]
+struct FullConfigInput {
+ global: GlobalConfigInput,
+ local: LocalConfigInput,
+ #[allow(dead_code)]
+ client: ClientConfigInput,
+}
+
+impl FullConfigInput {
+ fn from_json(
+ mut json: serde_json::Value,
+ error_sink: &mut Vec<(String, serde_json::Error)>,
+ ) -> FullConfigInput {
+ FullConfigInput {
+ global: GlobalConfigInput::from_json(&mut json, error_sink),
+ local: LocalConfigInput::from_json(&mut json, error_sink),
+ client: ClientConfigInput::from_json(&mut json, error_sink),
+ }
+ }
+
+ fn schema_fields() -> Vec<SchemaField> {
+ let mut fields = Vec::new();
+ GlobalConfigInput::schema_fields(&mut fields);
+ LocalConfigInput::schema_fields(&mut fields);
+ ClientConfigInput::schema_fields(&mut fields);
+ // HACK: sort the fields, so the diffs on the generated docs/schema are smaller
+ fields.sort_by_key(|&(x, ..)| x);
+ fields
+ }
+
+ fn json_schema() -> serde_json::Value {
+ schema(&Self::schema_fields())
+ }
+
+ #[cfg(test)]
+ fn manual() -> String {
+ manual(&Self::schema_fields())
+ }
+}
+
+/// All of the config levels, all fields `Option<T>`, to describe fields that are actually set by
+/// some rust-analyzer.toml file or JSON blob. An empty rust-analyzer.toml corresponds to
+/// all fields being None.
+#[derive(Debug, Clone, Default)]
+struct GlobalLocalConfigInput {
+ global: GlobalConfigInput,
+ local: LocalConfigInput,
+}
+
+impl GlobalLocalConfigInput {
+ #[allow(dead_code)]
+ fn from_toml(
+ mut toml: toml::Table,
+ error_sink: &mut Vec<(String, toml::de::Error)>,
+ ) -> GlobalLocalConfigInput {
+ GlobalLocalConfigInput {
+ global: GlobalConfigInput::from_toml(&mut toml, error_sink),
+ local: LocalConfigInput::from_toml(&mut toml, error_sink),
+ }
+ }
+}
+
+fn get_field_toml<T: DeserializeOwned>(
+ val: &toml::Table,
+ error_sink: &mut Vec<(String, toml::de::Error)>,
+ field: &'static str,
+ alias: Option<&'static str>,
+) -> Option<T> {
+ alias
+ .into_iter()
+ .chain(iter::once(field))
+ .filter_map(move |field| {
+ let subkeys = field.split('_');
+ let mut v = val;
+ for subkey in subkeys {
+ if let Some(val) = v.get(subkey) {
+ if let Some(map) = val.as_table() {
+ v = map;
+ } else {
+ return Some(toml::Value::try_into(val.clone()).map_err(|e| (e, v)));
+ }
+ } else {
+ return None;
+ }
+ }
+ None
+ })
+ .find(Result::is_ok)
+ .and_then(|res| match res {
+ Ok(it) => Some(it),
+ Err((e, pointer)) => {
+ error_sink.push((pointer.to_string(), e));
+ None
+ }
+ })
+}
+
fn get_field<T: DeserializeOwned>(
json: &mut serde_json::Value,
error_sink: &mut Vec<(String, serde_json::Error)>,
field: &'static str,
alias: Option<&'static str>,
- default: &str,
-) -> T {
+) -> Option<T> {
// XXX: check alias first, to work around the VS Code where it pre-fills the
// defaults instead of sending an empty object.
alias
@@ -2254,12 +2614,11 @@ fn get_field<T: DeserializeOwned>(
None
}
})
- .unwrap_or_else(|| {
- serde_json::from_str(default).unwrap_or_else(|e| panic!("{e} on: `{default}`"))
- })
}
-fn schema(fields: &[(&'static str, &'static str, &[&str], &str)]) -> serde_json::Value {
+type SchemaField = (&'static str, &'static str, &'static [&'static str], String);
+
+fn schema(fields: &[SchemaField]) -> serde_json::Value {
let map = fields
.iter()
.map(|(field, ty, doc, default)| {
@@ -2310,7 +2669,7 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
"FxHashMap<Box<str>, Box<[Box<str>]>>" => set! {
"type": "object",
},
- "FxHashMap<String, SnippetDef>" => set! {
+ "IndexMap<String, SnippetDef>" => set! {
"type": "object",
},
"FxHashMap<String, String>" => set! {
@@ -2621,7 +2980,7 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
}
#[cfg(test)]
-fn manual(fields: &[(&'static str, &'static str, &[&str], &str)]) -> String {
+fn manual(fields: &[SchemaField]) -> String {
fields.iter().fold(String::new(), |mut acc, (field, _ty, doc, default)| {
let name = format!("rust-analyzer.{}", field.replace('_', "."));
let doc = doc_comment_to_string(doc);
@@ -2716,7 +3075,7 @@ mod tests {
#[test]
fn generate_config_documentation() {
let docs_path = project_root().join("docs/user/generated_config.adoc");
- let expected = ConfigData::manual();
+ let expected = FullConfigInput::manual();
ensure_file_contents(&docs_path, &expected);
}
@@ -2788,7 +3147,7 @@ mod tests {
"rust": { "analyzerTargetDir": null }
}))
.unwrap();
- assert_eq!(config.data.cargo_targetDir, None);
+ assert_eq!(config.cargo_targetDir(), &None);
assert!(
matches!(config.flycheck(), FlycheckConfig::CargoCommand { options, .. } if options.target_dir.is_none())
);
@@ -2807,7 +3166,7 @@ mod tests {
"rust": { "analyzerTargetDir": true }
}))
.unwrap();
- assert_eq!(config.data.cargo_targetDir, Some(TargetDirectory::UseSubdirectory(true)));
+ assert_eq!(config.cargo_targetDir(), &Some(TargetDirectory::UseSubdirectory(true)));
assert!(
matches!(config.flycheck(), FlycheckConfig::CargoCommand { options, .. } if options.target_dir == Some(Utf8PathBuf::from("target/rust-analyzer")))
);
@@ -2827,8 +3186,8 @@ mod tests {
}))
.unwrap();
assert_eq!(
- config.data.cargo_targetDir,
- Some(TargetDirectory::Directory(Utf8PathBuf::from("other_folder")))
+ config.cargo_targetDir(),
+ &Some(TargetDirectory::Directory(Utf8PathBuf::from("other_folder")))
);
assert!(
matches!(config.flycheck(), FlycheckConfig::CargoCommand { options, .. } if options.target_dir == Some(Utf8PathBuf::from("other_folder")))
diff --git a/crates/rust-analyzer/src/diagnostics.rs b/crates/rust-analyzer/src/diagnostics.rs
index a0a53f545c..65a9a49149 100644
--- a/crates/rust-analyzer/src/diagnostics.rs
+++ b/crates/rust-analyzer/src/diagnostics.rs
@@ -154,10 +154,12 @@ pub(crate) fn fetch_native_diagnostics(
.copied()
.filter_map(|file_id| {
let line_index = snapshot.file_line_index(file_id).ok()?;
+ let source_root = snapshot.analysis.source_root(file_id).ok()?;
+
let diagnostics = snapshot
.analysis
.diagnostics(
- &snapshot.config.diagnostics(),
+ &snapshot.config.diagnostics(Some(source_root)),
ide::AssistResolveStrategy::None,
file_id,
)
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index 79ddab3275..ec10bc7ccd 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -189,7 +189,7 @@ impl GlobalState {
};
let mut analysis_host = AnalysisHost::new(config.lru_parse_query_capacity());
- if let Some(capacities) = config.lru_query_capacities() {
+ if let Some(capacities) = config.lru_query_capacities_config() {
analysis_host.update_lru_capacities(capacities);
}
let (flycheck_sender, flycheck_receiver) = unbounded();
diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs
index c99b22bb7d..06c9816632 100644
--- a/crates/rust-analyzer/src/handlers/request.rs
+++ b/crates/rust-analyzer/src/handlers/request.rs
@@ -369,8 +369,9 @@ pub(crate) fn handle_join_lines(
) -> anyhow::Result<Vec<lsp_types::TextEdit>> {
let _p = tracing::span!(tracing::Level::INFO, "handle_join_lines").entered();
- let config = snap.config.join_lines();
let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
+ let source_root = snap.analysis.source_root(file_id)?;
+ let config = snap.config.join_lines(Some(source_root));
let line_index = snap.file_line_index(file_id)?;
let mut res = TextEdit::default();
@@ -937,7 +938,8 @@ pub(crate) fn handle_completion(
let completion_trigger_character =
params.context.and_then(|ctx| ctx.trigger_character).and_then(|s| s.chars().next());
- let completion_config = &snap.config.completion();
+ let source_root = snap.analysis.source_root(position.file_id)?;
+ let completion_config = &snap.config.completion(Some(source_root));
let items = match snap.analysis.completions(
completion_config,
position,
@@ -978,11 +980,12 @@ pub(crate) fn handle_completion_resolve(
let file_id = from_proto::file_id(&snap, &resolve_data.position.text_document.uri)?;
let line_index = snap.file_line_index(file_id)?;
let offset = from_proto::offset(&line_index, resolve_data.position.position)?;
+ let source_root = snap.analysis.source_root(file_id)?;
let additional_edits = snap
.analysis
.resolve_completion_edits(
- &snap.config.completion(),
+ &snap.config.completion(Some(source_root)),
FilePosition { file_id, offset },
resolve_data
.imports
@@ -1052,16 +1055,17 @@ pub(crate) fn handle_hover(
PositionOrRange::Position(position) => Range::new(position, position),
PositionOrRange::Range(range) => range,
};
-
let file_range = from_proto::file_range(&snap, &params.text_document, range)?;
- let info = match snap.analysis.hover(&snap.config.hover(), file_range)? {
+
+ let hover = snap.config.hover();
+ let info = match snap.analysis.hover(&hover, file_range)? {
None => return Ok(None),
Some(info) => info,
};
let line_index = snap.file_line_index(file_range.file_id)?;
let range = to_proto::range(&line_index, info.range);
- let markup_kind = snap.config.hover().format;
+ let markup_kind = hover.format;
let hover = lsp_ext::Hover {
hover: lsp_types::Hover {
contents: HoverContents::Markup(to_proto::markup_content(
@@ -1205,11 +1209,12 @@ pub(crate) fn handle_code_action(
return Ok(None);
}
- let line_index =
- snap.file_line_index(from_proto::file_id(&snap, &params.text_document.uri)?)?;
+ let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
+ let line_index = snap.file_line_index(file_id)?;
let frange = from_proto::file_range(&snap, &params.text_document, params.range)?;
+ let source_root = snap.analysis.source_root(file_id)?;
- let mut assists_config = snap.config.assist();
+ let mut assists_config = snap.config.assist(Some(source_root));
assists_config.allowed = params
.context
.only
@@ -1226,7 +1231,7 @@ pub(crate) fn handle_code_action(
};
let assists = snap.analysis.assists_with_fixes(
&assists_config,
- &snap.config.diagnostics(),
+ &snap.config.diagnostics(Some(source_root)),
resolve,
frange,
)?;
@@ -1280,8 +1285,9 @@ pub(crate) fn handle_code_action_resolve(
let line_index = snap.file_line_index(file_id)?;
let range = from_proto::text_range(&line_index, params.code_action_params.range)?;
let frange = FileRange { file_id, range };
+ let source_root = snap.analysis.source_root(file_id)?;
- let mut assists_config = snap.config.assist();
+ let mut assists_config = snap.config.assist(Some(source_root));
assists_config.allowed = params
.code_action_params
.context
@@ -1304,7 +1310,7 @@ pub(crate) fn handle_code_action_resolve(
let assists = snap.analysis.assists_with_fixes(
&assists_config,
- &snap.config.diagnostics(),
+ &snap.config.diagnostics(Some(source_root)),
AssistResolveStrategy::Single(assist_resolve),
frange,
)?;
@@ -1433,8 +1439,12 @@ pub(crate) fn handle_document_highlight(
let _p = tracing::span!(tracing::Level::INFO, "handle_document_highlight").entered();
let position = from_proto::file_position(&snap, params.text_document_position_params)?;
let line_index = snap.file_line_index(position.file_id)?;
+ let source_root = snap.analysis.source_root(position.file_id)?;
- let refs = match snap.analysis.highlight_related(snap.config.highlight_related(), position)? {
+ let refs = match snap
+ .analysis
+ .highlight_related(snap.config.highlight_related(Some(source_root)), position)?
+ {
None => return Ok(None),
Some(refs) => refs,
};
@@ -1480,7 +1490,9 @@ pub(crate) fn handle_inlay_hints(
params.range,
)?;
let line_index = snap.file_line_index(file_id)?;
- let inlay_hints_config = snap.config.inlay_hints();
+ let source_root = snap.analysis.source_root(file_id)?;
+
+ let inlay_hints_config = snap.config.inlay_hints(Some(source_root));
Ok(Some(
snap.analysis
.inlay_hints(&inlay_hints_config, file_id, Some(range))?
@@ -1512,7 +1524,9 @@ pub(crate) fn handle_inlay_hints_resolve(
let line_index = snap.file_line_index(file_id)?;
let hint_position = from_proto::offset(&line_index, original_hint.position)?;
- let mut forced_resolve_inlay_hints_config = snap.config.inlay_hints();
+ let source_root = snap.analysis.source_root(file_id)?;
+
+ let mut forced_resolve_inlay_hints_config = snap.config.inlay_hints(Some(source_root));
forced_resolve_inlay_hints_config.fields_to_resolve = InlayFieldsToResolve::empty();
let resolve_hints = snap.analysis.inlay_hints_resolve(
&forced_resolve_inlay_hints_config,
@@ -1644,8 +1658,9 @@ pub(crate) fn handle_semantic_tokens_full(
let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
let text = snap.analysis.file_text(file_id)?;
let line_index = snap.file_line_index(file_id)?;
+ let source_root = snap.analysis.source_root(file_id)?;
- let mut highlight_config = snap.config.highlighting_config();
+ let mut highlight_config = snap.config.highlighting_config(Some(source_root));
// Avoid flashing a bunch of unresolved references when the proc-macro servers haven't been spawned yet.
highlight_config.syntactic_name_ref_highlighting =
snap.workspaces.is_empty() || !snap.proc_macros_loaded;
@@ -1656,7 +1671,7 @@ pub(crate) fn handle_semantic_tokens_full(
&line_index,
highlights,
snap.config.semantics_tokens_augments_syntax_tokens(),
- snap.config.highlighting_non_standard_tokens(),
+ snap.config.highlighting_non_standard_tokens(Some(source_root)),
);
// Unconditionally cache the tokens
@@ -1674,8 +1689,9 @@ pub(crate) fn handle_semantic_tokens_full_delta(
let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
let text = snap.analysis.file_text(file_id)?;
let line_index = snap.file_line_index(file_id)?;
+ let source_root = snap.analysis.source_root(file_id)?;
- let mut highlight_config = snap.config.highlighting_config();
+ let mut highlight_config = snap.config.highlighting_config(Some(source_root));
// Avoid flashing a bunch of unresolved references when the proc-macro servers haven't been spawned yet.
highlight_config.syntactic_name_ref_highlighting =
snap.workspaces.is_empty() || !snap.proc_macros_loaded;
@@ -1686,7 +1702,7 @@ pub(crate) fn handle_semantic_tokens_full_delta(
&line_index,
highlights,
snap.config.semantics_tokens_augments_syntax_tokens(),
- snap.config.highlighting_non_standard_tokens(),
+ snap.config.highlighting_non_standard_tokens(Some(source_root)),
);
let cached_tokens = snap.semantic_tokens_cache.lock().remove(&params.text_document.uri);
@@ -1717,8 +1733,9 @@ pub(crate) fn handle_semantic_tokens_range(
let frange = from_proto::file_range(&snap, &params.text_document, params.range)?;
let text = snap.analysis.file_text(frange.file_id)?;
let line_index = snap.file_line_index(frange.file_id)?;
+ let source_root = snap.analysis.source_root(frange.file_id)?;
- let mut highlight_config = snap.config.highlighting_config();
+ let mut highlight_config = snap.config.highlighting_config(Some(source_root));
// Avoid flashing a bunch of unresolved references when the proc-macro servers haven't been spawned yet.
highlight_config.syntactic_name_ref_highlighting =
snap.workspaces.is_empty() || !snap.proc_macros_loaded;
@@ -1729,7 +1746,7 @@ pub(crate) fn handle_semantic_tokens_range(
&line_index,
highlights,
snap.config.semantics_tokens_augments_syntax_tokens(),
- snap.config.highlighting_non_standard_tokens(),
+ snap.config.highlighting_non_standard_tokens(Some(source_root)),
);
Ok(Some(semantic_tokens.into()))
}
@@ -1942,8 +1959,8 @@ fn goto_type_action_links(
snap: &GlobalStateSnapshot,
nav_targets: &[HoverGotoTypeData],
) -> Option<lsp_ext::CommandLinkGroup> {
- if !snap.config.hover_actions().goto_type_def
- || nav_targets.is_empty()
+ if nav_targets.is_empty()
+ || !snap.config.hover_actions().goto_type_def
|| !snap.config.client_commands().goto_location
{
return None;
diff --git a/crates/rust-analyzer/src/lsp/to_proto.rs b/crates/rust-analyzer/src/lsp/to_proto.rs
index ad4e3bded7..7e03458c52 100644
--- a/crates/rust-analyzer/src/lsp/to_proto.rs
+++ b/crates/rust-analyzer/src/lsp/to_proto.rs
@@ -233,7 +233,7 @@ pub(crate) fn completion_items(
completion_item(&mut res, config, line_index, &tdpp, max_relevance, item);
}
- if let Some(limit) = config.completion().limit {
+ if let Some(limit) = config.completion(None).limit {
res.sort_by(|item1, item2| item1.sort_text.cmp(&item2.sort_text));
res.truncate(limit);
}
@@ -317,7 +317,7 @@ fn completion_item(
set_score(&mut lsp_item, max_relevance, item.relevance);
- if config.completion().enable_imports_on_the_fly && !item.import_to_add.is_empty() {
+ if config.completion(None).enable_imports_on_the_fly && !item.import_to_add.is_empty() {
let imports = item
.import_to_add
.into_iter()
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 4279baeda3..f37b25fb95 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -428,7 +428,7 @@ impl GlobalState {
}
}
- if self.config.cargo_autoreload() {
+ if self.config.cargo_autoreload_config() {
if let Some((cause, force_crate_graph_reload)) =
self.fetch_workspaces_queue.should_start_op()
{
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index c4a42ce427..d2e495dbfc 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -76,9 +76,9 @@ impl GlobalState {
if self.config.lru_parse_query_capacity() != old_config.lru_parse_query_capacity() {
self.analysis_host.update_lru_capacity(self.config.lru_parse_query_capacity());
}
- if self.config.lru_query_capacities() != old_config.lru_query_capacities() {
+ if self.config.lru_query_capacities_config() != old_config.lru_query_capacities_config() {
self.analysis_host.update_lru_capacities(
- &self.config.lru_query_capacities().cloned().unwrap_or_default(),
+ &self.config.lru_query_capacities_config().cloned().unwrap_or_default(),
);
}
if self.config.linked_or_discovered_projects() != old_config.linked_or_discovered_projects()
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index 8f69895b2e..af4483a2cc 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -159,10 +159,17 @@ building from locking the `Cargo.lock` at the expense of duplicating build artif
Set to `true` to use a subdirectory of the existing target directory or
set to a path relative to the workspace to use that path.
--
-[[rust-analyzer.cargo.unsetTest]]rust-analyzer.cargo.unsetTest (default: `["core"]`)::
+[[rust-analyzer.cargo.unsetTest]]rust-analyzer.cargo.unsetTest::
+
--
+Default:
+----
+[
+ "core"
+]
+----
Unsets the implicit `#[cfg(test)]` for the specified crates.
+
--
[[rust-analyzer.checkOnSave]]rust-analyzer.checkOnSave (default: `true`)::
+
@@ -321,46 +328,46 @@ Enables completions of private items and fields that are defined in the current
Default:
----
{
- "Arc::new": {
- "postfix": "arc",
- "body": "Arc::new(${receiver})",
- "requires": "std::sync::Arc",
- "description": "Put the expression into an `Arc`",
- "scope": "expr"
- },
- "Rc::new": {
- "postfix": "rc",
- "body": "Rc::new(${receiver})",
- "requires": "std::rc::Rc",
- "description": "Put the expression into an `Rc`",
- "scope": "expr"
- },
- "Box::pin": {
- "postfix": "pinbox",
- "body": "Box::pin(${receiver})",
- "requires": "std::boxed::Box",
- "description": "Put the expression into a pinned `Box`",
- "scope": "expr"
- },
- "Ok": {
- "postfix": "ok",
- "body": "Ok(${receiver})",
- "description": "Wrap the expression in a `Result::Ok`",
- "scope": "expr"
- },
- "Err": {
- "postfix": "err",
- "body": "Err(${receiver})",
- "description": "Wrap the expression in a `Result::Err`",
- "scope": "expr"
- },
- "Some": {
- "postfix": "some",
- "body": "Some(${receiver})",
- "description": "Wrap the expression in an `Option::Some`",
- "scope": "expr"
- }
- }
+ "Arc::new": {
+ "postfix": "arc",
+ "body": "Arc::new(${receiver})",
+ "requires": "std::sync::Arc",
+ "description": "Put the expression into an `Arc`",
+ "scope": "expr"
+ },
+ "Rc::new": {
+ "postfix": "rc",
+ "body": "Rc::new(${receiver})",
+ "requires": "std::rc::Rc",
+ "description": "Put the expression into an `Rc`",
+ "scope": "expr"
+ },
+ "Box::pin": {
+ "postfix": "pinbox",
+ "body": "Box::pin(${receiver})",
+ "requires": "std::boxed::Box",
+ "description": "Put the expression into a pinned `Box`",
+ "scope": "expr"
+ },
+ "Ok": {
+ "postfix": "ok",
+ "body": "Ok(${receiver})",
+ "description": "Wrap the expression in a `Result::Ok`",
+ "scope": "expr"
+ },
+ "Err": {
+ "postfix": "err",
+ "body": "Err(${receiver})",
+ "description": "Wrap the expression in a `Result::Err`",
+ "scope": "expr"
+ },
+ "Some": {
+ "postfix": "some",
+ "body": "Some(${receiver})",
+ "description": "Wrap the expression in an `Option::Some`",
+ "scope": "expr"
+ }
+}
----
Custom completion snippets.