Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/rust-analyzer/src/cli/scip.rs2
-rw-r--r--crates/rust-analyzer/src/config.rs1161
-rw-r--r--crates/rust-analyzer/src/global_state.rs10
-rw-r--r--crates/rust-analyzer/src/handlers/notification.rs30
-rw-r--r--crates/rust-analyzer/src/handlers/request.rs11
-rw-r--r--crates/rust-analyzer/src/lsp/to_proto.rs3
-rw-r--r--crates/rust-analyzer/src/main_loop.rs12
-rw-r--r--crates/rust-analyzer/src/reload.rs18
-rw-r--r--crates/rust-analyzer/src/target_spec.rs4
9 files changed, 607 insertions, 644 deletions
diff --git a/crates/rust-analyzer/src/cli/scip.rs b/crates/rust-analyzer/src/cli/scip.rs
index ceb8534fdf..b92713129d 100644
--- a/crates/rust-analyzer/src/cli/scip.rs
+++ b/crates/rust-analyzer/src/cli/scip.rs
@@ -51,7 +51,7 @@ impl flags::Scip {
// FIXME @alibektas : What happens to errors without logging?
error!(?error_sink, "Config Error(s)");
}
- let cargo_config = config.cargo();
+ let cargo_config = config.cargo(None);
let (db, vfs, _) = load_workspace_at(
root.as_path().as_ref(),
&cargo_config,
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 2889af844b..c884216b3e 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -62,12 +62,10 @@ 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! {
- /// Configs that apply on a workspace-wide scope. There are 3 levels on which a global configuration can be configured
- // FIXME: 1. and 3. should be split, some configs do not make sense per project
+ /// Configs that apply on a workspace-wide scope. There are 2 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)
+ /// 1. `rust-analyzer.toml` file under user's config directory (e.g ~/.config/rust-analyzer/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 -> {
@@ -76,178 +74,7 @@ config_data! {
/// How many worker threads to handle priming caches. The default `0` means to pick automatically.
cachePriming_numThreads: NumThreads = NumThreads::Physical,
- /// Pass `--all-targets` to cargo invocation.
- cargo_allTargets: bool = true,
- /// Automatically refresh project info via `cargo metadata` on
- /// `Cargo.toml` or `.cargo/config.toml` changes.
- pub(crate) cargo_autoreload: bool = true,
- /// Run build scripts (`build.rs`) for more precise code analysis.
- cargo_buildScripts_enable: bool = true,
- /// Specifies the invocation strategy to use when running the build scripts command.
- /// If `per_workspace` is set, the command will be executed for each Rust workspace with the
- /// workspace as the working directory.
- /// If `once` is set, the command will be executed once with the opened project as the
- /// working directory.
- /// This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`
- /// is set.
- 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
- /// option.
- ///
- /// If there are multiple linked projects/workspaces, this command is invoked for
- /// each of them, with the working directory being the workspace root
- /// (i.e., the folder containing the `Cargo.toml`). This can be overwritten
- /// by changing `#rust-analyzer.cargo.buildScripts.invocationStrategy#`.
- ///
- /// By default, a cargo invocation will be constructed for the configured
- /// targets and features, with the following base command line:
- ///
- /// ```bash
- /// cargo check --quiet --workspace --message-format=json --all-targets --keep-going
- /// ```
- /// .
- 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,
- /// Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to
- /// avoid checking unnecessary things.
- cargo_buildScripts_useRustcWrapper: bool = true,
- /// List of cfg options to enable with the given values.
- cargo_cfgs: FxHashMap<String, Option<String>> = {
- let mut m = FxHashMap::default();
- m.insert("debug_assertions".to_owned(), None);
- m.insert("miri".to_owned(), None);
- m
- },
- /// Extra arguments that are passed to every cargo invocation.
- 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> = FxHashMap::default(),
- /// List of features to activate.
- ///
- /// Set this to `"all"` to pass `--all-features` to cargo.
- cargo_features: CargoFeaturesDef = CargoFeaturesDef::Selected(vec![]),
- /// Whether to pass `--no-default-features` to cargo.
- 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> = Some("discover".to_owned()),
- /// 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> = 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> = 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> = None,
- /// Run the check command for diagnostics on save.
- checkOnSave | checkOnSave_enable: bool = true,
-
- /// Check all targets and tests (`--all-targets`). Defaults to
- /// `#rust-analyzer.cargo.allTargets#`.
- check_allTargets | checkOnSave_allTargets: Option<bool> = None,
- /// Cargo command to use for `cargo check`.
- check_command | checkOnSave_command: String = "check".to_owned(),
- /// Extra arguments for `cargo check`.
- 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> = 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> = 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> = FxHashSet::default(),
- /// 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 = InvocationStrategy::PerWorkspace,
- /// Whether to pass `--no-default-features` to Cargo. Defaults to
- /// `#rust-analyzer.cargo.noDefaultFeatures#`.
- 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
- /// (if your client supports the `colorDiagnosticOutput` experimental
- /// capability, you can use `--message-format=json-diagnostic-rendered-ansi`).
- ///
- /// If you're changing this because you're using some tool wrapping
- /// Cargo, you might also want to change
- /// `#rust-analyzer.cargo.buildScripts.overrideCommand#`.
- ///
- /// If there are multiple linked projects/workspaces, this command is invoked for
- /// each of them, with the working directory being the workspace root
- /// (i.e., the folder containing the `Cargo.toml`). This can be overwritten
- /// by changing `#rust-analyzer.check.invocationStrategy#`.
- ///
- /// If `$saved_file` is part of the command, rust-analyzer will pass
- /// the absolute path of the saved file to the provided command. This is
- /// intended to be used with non-Cargo build systems.
- /// Note that `$saved_file` is experimental and may be removed in the future.
- ///
- /// An example command would be:
- ///
- /// ```bash
- /// cargo check --workspace --message-format=json --all-targets
- /// ```
- /// .
- 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> = None,
- /// Whether `--workspace` should be passed to `cargo check`.
- /// If false, `-p <package>` will be passed instead.
- check_workspace: bool = true,
-
- /// List of rust-analyzer diagnostics to disable.
- diagnostics_disabled: FxHashSet<String> = FxHashSet::default(),
- /// Whether to show native rust-analyzer diagnostics.
- diagnostics_enable: bool = true,
- /// Whether to show experimental rust-analyzer diagnostics that might
- /// have more false positives than usual.
- 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> = FxHashMap::default(),
- /// Whether to run additional style lints.
- 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> = 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> = vec![],
/// These directories will be ignored by rust-analyzer. They are
/// relative to the workspace root, and globs are not supported. You may
@@ -255,266 +82,6 @@ config_data! {
files_excludeDirs: Vec<Utf8PathBuf> = vec![],
- /// Disable project auto-discovery in favor of explicitly specified set
- /// of projects.
- ///
- /// Elements must be paths pointing to `Cargo.toml`,
- /// `rust-project.json`, `.rs` files (which will be treated as standalone files) or JSON
- /// objects in `rust-project.json` format.
- linkedProjects: Vec<ManifestOrProjectJson> = vec![],
-
- /// Number of syntax trees rust-analyzer keeps in memory. Defaults to 128.
- lru_capacity: Option<u16> = None,
- /// Sets the LRU capacity of the specified queries.
- lru_query_capacities: FxHashMap<Box<str>, u16> = FxHashMap::default(),
-
- /// 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>]>> = FxHashMap::default(),
-
- /// Command to be executed instead of 'cargo' for runnables.
- 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> = vec![],
- /// Additional arguments to be passed through Cargo to launched tests, benchmarks, or
- /// doc-tests.
- ///
- /// Unless the launched target uses a
- /// [custom test harness](https://doc.rust-lang.org/cargo/reference/cargo-targets.html#the-harness-field),
- /// they will end up being interpreted as options to
- /// [`rustc`’s built-in test harness (“libtest”)](https://doc.rust-lang.org/rustc/tests/index.html#cli-arguments).
- runnables_extraTestBinaryArgs: Vec<String> = vec!["--show-output".to_owned()],
-
- /// 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
- /// is installed.
- ///
- /// Any project which uses rust-analyzer with the rustcPrivate
- /// 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> = None,
-
-
- /// Enables automatic discovery of projects using [`DiscoverWorkspaceConfig::command`].
- ///
- /// [`DiscoverWorkspaceConfig`] also requires setting `progress_label` and `files_to_watch`.
- /// `progress_label` is used for the title in progress indicators, whereas `files_to_watch`
- /// is used to determine which build system-specific files should be watched in order to
- /// reload rust-analyzer.
- ///
- /// Below is an example of a valid configuration:
- /// ```json
- /// "rust-analyzer.workspace.discoverConfig": {
- /// "command": [
- /// "rust-project",
- /// "develop-json"
- /// ],
- /// "progressLabel": "rust-analyzer",
- /// "filesToWatch": [
- /// "BUCK"
- /// ]
- /// }
- /// ```
- ///
- /// ## On `DiscoverWorkspaceConfig::command`
- ///
- /// **Warning**: This format is provisional and subject to change.
- ///
- /// [`DiscoverWorkspaceConfig::command`] *must* return a JSON object
- /// corresponding to `DiscoverProjectData::Finished`:
- ///
- /// ```norun
- /// #[derive(Debug, Clone, Deserialize, Serialize)]
- /// #[serde(tag = "kind")]
- /// #[serde(rename_all = "snake_case")]
- /// enum DiscoverProjectData {
- /// Finished { buildfile: Utf8PathBuf, project: ProjectJsonData },
- /// Error { error: String, source: Option<String> },
- /// Progress { message: String },
- /// }
- /// ```
- ///
- /// As JSON, `DiscoverProjectData::Finished` is:
- ///
- /// ```json
- /// {
- /// // the internally-tagged representation of the enum.
- /// "kind": "finished",
- /// // the file used by a non-Cargo build system to define
- /// // a package or target.
- /// "buildfile": "rust-analyzer/BUILD",
- /// // the contents of a rust-project.json, elided for brevity
- /// "project": {
- /// "sysroot": "foo",
- /// "crates": []
- /// }
- /// }
- /// ```
- ///
- /// It is encouraged, but not required, to use the other variants on
- /// `DiscoverProjectData` to provide a more polished end-user experience.
- ///
- /// `DiscoverWorkspaceConfig::command` may *optionally* include an `{arg}`,
- /// which will be substituted with the JSON-serialized form of the following
- /// enum:
- ///
- /// ```norun
- /// #[derive(PartialEq, Clone, Debug, Serialize)]
- /// #[serde(rename_all = "camelCase")]
- /// pub enum DiscoverArgument {
- /// Path(AbsPathBuf),
- /// Buildfile(AbsPathBuf),
- /// }
- /// ```
- ///
- /// The JSON representation of `DiscoverArgument::Path` is:
- ///
- /// ```json
- /// {
- /// "path": "src/main.rs"
- /// }
- /// ```
- ///
- /// Similarly, the JSON representation of `DiscoverArgument::Buildfile` is:
- ///
- /// ```
- /// {
- /// "buildfile": "BUILD"
- /// }
- /// ```
- ///
- /// `DiscoverArgument::Path` is used to find and generate a `rust-project.json`,
- /// and therefore, a workspace, whereas `DiscoverArgument::buildfile` is used to
- /// to update an existing workspace. As a reference for implementors,
- /// buck2's `rust-project` will likely be useful:
- /// https://github.com/facebook/buck2/tree/main/integrations/rust-project.
- workspace_discoverConfig: Option<DiscoverWorkspaceConfig> = None,
- }
-}
-
-config_data! {
- /// Local configurations can be defined per `SourceRoot`. This almost always corresponds to a `Crate`.
- local: struct LocalDefaultConfigData <- LocalConfigInput -> {
- /// Whether to insert #[must_use] when generating `as_` methods
- /// for enum variants.
- assist_emitMustUse: bool = false,
- /// Placeholder expression to use for missing expressions in assists.
- assist_expressionFillDefault: ExprFillDefaultDef = ExprFillDefaultDef::Todo,
- /// Enable borrow checking for term search code assists. If set to false, also there will be more suggestions, but some of them may not borrow-check.
- assist_termSearch_borrowcheck: bool = true,
- /// Term search fuel in "units of work" for assists (Defaults to 1800).
- assist_termSearch_fuel: usize = 1800,
-
- /// 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 prefix external (including std, core) crate imports with `::`. e.g. "use ::std::io::Read;".
- imports_prefixExternPrelude: bool = false,
- }
-}
-
-config_data! {
- workspace: struct WorkspaceDefaultConfigData <- WorkspaceConfigInput -> {
-
- /// Additional arguments to `rustfmt`.
- 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>> = 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,
-
- }
-}
-
-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 -> {
- /// 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.
- completion_snippets_custom: FxHashMap<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,
- /// Term search fuel in "units of work" for autocompletion (Defaults to 1000).
- completion_termSearch_fuel: usize = 1000,
-
- /// Controls file watching implementation.
- files_watcher: FilesWatcherDef = FilesWatcherDef::Client,
/// Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords.
highlightRelated_breakPoints_enable: bool = true,
@@ -663,6 +230,19 @@ config_data! {
/// `#rust-analyzer.lens.enable#` is set.
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`, `.rs` files (which will be treated as standalone files) or JSON
+ /// objects in `rust-project.json` format.
+ linkedProjects: Vec<ManifestOrProjectJson> = vec![],
+
+ /// Number of syntax trees rust-analyzer keeps in memory. Defaults to 128.
+ lru_capacity: Option<u16> = None,
+ /// Sets the LRU capacity of the specified queries.
+ lru_query_capacities: FxHashMap<Box<str>, u16> = FxHashMap::default(),
+
/// Whether to show `can't find Cargo.toml` error message.
notifications_cargoTomlNotFound: bool = true,
@@ -727,6 +307,419 @@ config_data! {
/// Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list.
typing_autoClosingAngleBrackets_enable: bool = false,
+
+ /// Enables automatic discovery of projects using [`DiscoverWorkspaceConfig::command`].
+ ///
+ /// [`DiscoverWorkspaceConfig`] also requires setting `progress_label` and `files_to_watch`.
+ /// `progress_label` is used for the title in progress indicators, whereas `files_to_watch`
+ /// is used to determine which build system-specific files should be watched in order to
+ /// reload rust-analyzer.
+ ///
+ /// Below is an example of a valid configuration:
+ /// ```json
+ /// "rust-analyzer.workspace.discoverConfig": {
+ /// "command": [
+ /// "rust-project",
+ /// "develop-json"
+ /// ],
+ /// "progressLabel": "rust-analyzer",
+ /// "filesToWatch": [
+ /// "BUCK"
+ /// ]
+ /// }
+ /// ```
+ ///
+ /// ## On `DiscoverWorkspaceConfig::command`
+ ///
+ /// **Warning**: This format is provisional and subject to change.
+ ///
+ /// [`DiscoverWorkspaceConfig::command`] *must* return a JSON object
+ /// corresponding to `DiscoverProjectData::Finished`:
+ ///
+ /// ```norun
+ /// #[derive(Debug, Clone, Deserialize, Serialize)]
+ /// #[serde(tag = "kind")]
+ /// #[serde(rename_all = "snake_case")]
+ /// enum DiscoverProjectData {
+ /// Finished { buildfile: Utf8PathBuf, project: ProjectJsonData },
+ /// Error { error: String, source: Option<String> },
+ /// Progress { message: String },
+ /// }
+ /// ```
+ ///
+ /// As JSON, `DiscoverProjectData::Finished` is:
+ ///
+ /// ```json
+ /// {
+ /// // the internally-tagged representation of the enum.
+ /// "kind": "finished",
+ /// // the file used by a non-Cargo build system to define
+ /// // a package or target.
+ /// "buildfile": "rust-analyzer/BUILD",
+ /// // the contents of a rust-project.json, elided for brevity
+ /// "project": {
+ /// "sysroot": "foo",
+ /// "crates": []
+ /// }
+ /// }
+ /// ```
+ ///
+ /// It is encouraged, but not required, to use the other variants on
+ /// `DiscoverProjectData` to provide a more polished end-user experience.
+ ///
+ /// `DiscoverWorkspaceConfig::command` may *optionally* include an `{arg}`,
+ /// which will be substituted with the JSON-serialized form of the following
+ /// enum:
+ ///
+ /// ```norun
+ /// #[derive(PartialEq, Clone, Debug, Serialize)]
+ /// #[serde(rename_all = "camelCase")]
+ /// pub enum DiscoverArgument {
+ /// Path(AbsPathBuf),
+ /// Buildfile(AbsPathBuf),
+ /// }
+ /// ```
+ ///
+ /// The JSON representation of `DiscoverArgument::Path` is:
+ ///
+ /// ```json
+ /// {
+ /// "path": "src/main.rs"
+ /// }
+ /// ```
+ ///
+ /// Similarly, the JSON representation of `DiscoverArgument::Buildfile` is:
+ ///
+ /// ```
+ /// {
+ /// "buildfile": "BUILD"
+ /// }
+ /// ```
+ ///
+ /// `DiscoverArgument::Path` is used to find and generate a `rust-project.json`,
+ /// and therefore, a workspace, whereas `DiscoverArgument::buildfile` is used to
+ /// to update an existing workspace. As a reference for implementors,
+ /// buck2's `rust-project` will likely be useful:
+ /// https://github.com/facebook/buck2/tree/main/integrations/rust-project.
+ workspace_discoverConfig: Option<DiscoverWorkspaceConfig> = None,
+ }
+}
+
+config_data! {
+ /// Local configurations can be defined per `SourceRoot`. This almost always corresponds to a `Crate`.
+ local: struct LocalDefaultConfigData <- LocalConfigInput -> {
+ /// Whether to insert #[must_use] when generating `as_` methods
+ /// for enum variants.
+ assist_emitMustUse: bool = false,
+ /// Placeholder expression to use for missing expressions in assists.
+ assist_expressionFillDefault: ExprFillDefaultDef = ExprFillDefaultDef::Todo,
+ /// Enable borrow checking for term search code assists. If set to false, also there will be more suggestions, but some of them may not borrow-check.
+ assist_termSearch_borrowcheck: bool = true,
+ /// Term search fuel in "units of work" for assists (Defaults to 1800).
+ assist_termSearch_fuel: usize = 1800,
+
+
+ /// 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.
+ completion_snippets_custom: FxHashMap<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,
+ /// Term search fuel in "units of work" for autocompletion (Defaults to 1000).
+ completion_termSearch_fuel: usize = 1000,
+
+ /// List of rust-analyzer diagnostics to disable.
+ diagnostics_disabled: FxHashSet<String> = FxHashSet::default(),
+ /// Whether to show native rust-analyzer diagnostics.
+ diagnostics_enable: bool = true,
+ /// Whether to show experimental rust-analyzer diagnostics that might
+ /// have more false positives than usual.
+ 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> = FxHashMap::default(),
+ /// Whether to run additional style lints.
+ 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> = 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> = vec![],
+
+ /// 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 prefix external (including std, core) crate imports with `::`. e.g. "use ::std::io::Read;".
+ imports_prefixExternPrelude: bool = false,
+ }
+}
+
+config_data! {
+ workspace: struct WorkspaceDefaultConfigData <- WorkspaceConfigInput -> {
+ /// Pass `--all-targets` to cargo invocation.
+ cargo_allTargets: bool = true,
+ /// Automatically refresh project info via `cargo metadata` on
+ /// `Cargo.toml` or `.cargo/config.toml` changes.
+ cargo_autoreload: bool = true,
+ /// Run build scripts (`build.rs`) for more precise code analysis.
+ cargo_buildScripts_enable: bool = true,
+ /// Specifies the invocation strategy to use when running the build scripts command.
+ /// If `per_workspace` is set, the command will be executed for each Rust workspace with the
+ /// workspace as the working directory.
+ /// If `once` is set, the command will be executed once with the opened project as the
+ /// working directory.
+ /// This config only has an effect when `#rust-analyzer.cargo.buildScripts.overrideCommand#`
+ /// is set.
+ 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
+ /// option.
+ ///
+ /// If there are multiple linked projects/workspaces, this command is invoked for
+ /// each of them, with the working directory being the workspace root
+ /// (i.e., the folder containing the `Cargo.toml`). This can be overwritten
+ /// by changing `#rust-analyzer.cargo.buildScripts.invocationStrategy#`.
+ ///
+ /// By default, a cargo invocation will be constructed for the configured
+ /// targets and features, with the following base command line:
+ ///
+ /// ```bash
+ /// cargo check --quiet --workspace --message-format=json --all-targets --keep-going
+ /// ```
+ /// .
+ 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,
+ /// Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to
+ /// avoid checking unnecessary things.
+ cargo_buildScripts_useRustcWrapper: bool = true,
+ /// List of cfg options to enable with the given values.
+ cargo_cfgs: FxHashMap<String, Option<String>> = {
+ let mut m = FxHashMap::default();
+ m.insert("debug_assertions".to_owned(), None);
+ m.insert("miri".to_owned(), None);
+ m
+ },
+ /// Extra arguments that are passed to every cargo invocation.
+ 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> = FxHashMap::default(),
+ /// List of features to activate.
+ ///
+ /// Set this to `"all"` to pass `--all-features` to cargo.
+ cargo_features: CargoFeaturesDef = CargoFeaturesDef::Selected(vec![]),
+ /// Whether to pass `--no-default-features` to cargo.
+ 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> = Some("discover".to_owned()),
+ /// 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> = 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> = 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> = None,
+
+ /// Run the check command for diagnostics on save.
+ checkOnSave | checkOnSave_enable: bool = true,
+
+
+ /// Check all targets and tests (`--all-targets`). Defaults to
+ /// `#rust-analyzer.cargo.allTargets#`.
+ check_allTargets | checkOnSave_allTargets: Option<bool> = None,
+ /// Cargo command to use for `cargo check`.
+ check_command | checkOnSave_command: String = "check".to_owned(),
+ /// Extra arguments for `cargo check`.
+ 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> = 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> = 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> = FxHashSet::default(),
+ /// 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 = InvocationStrategy::PerWorkspace,
+ /// Whether to pass `--no-default-features` to Cargo. Defaults to
+ /// `#rust-analyzer.cargo.noDefaultFeatures#`.
+ 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
+ /// (if your client supports the `colorDiagnosticOutput` experimental
+ /// capability, you can use `--message-format=json-diagnostic-rendered-ansi`).
+ ///
+ /// If you're changing this because you're using some tool wrapping
+ /// Cargo, you might also want to change
+ /// `#rust-analyzer.cargo.buildScripts.overrideCommand#`.
+ ///
+ /// If there are multiple linked projects/workspaces, this command is invoked for
+ /// each of them, with the working directory being the workspace root
+ /// (i.e., the folder containing the `Cargo.toml`). This can be overwritten
+ /// by changing `#rust-analyzer.check.invocationStrategy#`.
+ ///
+ /// If `$saved_file` is part of the command, rust-analyzer will pass
+ /// the absolute path of the saved file to the provided command. This is
+ /// intended to be used with non-Cargo build systems.
+ /// Note that `$saved_file` is experimental and may be removed in the future.
+ ///
+ /// An example command would be:
+ ///
+ /// ```bash
+ /// cargo check --workspace --message-format=json --all-targets
+ /// ```
+ /// .
+ 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> = None,
+ /// Whether `--workspace` should be passed to `cargo check`.
+ /// If false, `-p <package>` will be passed instead.
+ check_workspace: 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>]>> = FxHashMap::default(),
+
+ /// Command to be executed instead of 'cargo' for runnables.
+ 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> = vec![],
+ /// Additional arguments to be passed through Cargo to launched tests, benchmarks, or
+ /// doc-tests.
+ ///
+ /// Unless the launched target uses a
+ /// [custom test harness](https://doc.rust-lang.org/cargo/reference/cargo-targets.html#the-harness-field),
+ /// they will end up being interpreted as options to
+ /// [`rustc`’s built-in test harness (“libtest”)](https://doc.rust-lang.org/rustc/tests/index.html#cli-arguments).
+ runnables_extraTestBinaryArgs: Vec<String> = vec!["--show-output".to_owned()],
+
+ /// 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
+ /// is installed.
+ ///
+ /// Any project which uses rust-analyzer with the rustcPrivate
+ /// 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> = None,
+
+ /// Additional arguments to `rustfmt`.
+ 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>> = 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,
+
+
/// 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).
@@ -735,6 +728,19 @@ config_data! {
workspace_symbol_search_limit: usize = 128,
/// Workspace symbol search scope.
workspace_symbol_search_scope: WorkspaceSymbolSearchScopeDef = WorkspaceSymbolSearchScopeDef::Workspace,
+
+ }
+}
+
+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 -> {
+
+ /// Controls file watching implementation.
+ files_watcher: FilesWatcherDef = FilesWatcherDef::Client,
+
+
}
}
@@ -874,7 +880,7 @@ impl Config {
// IMPORTANT : This holds as long as ` completion_snippets_custom` is declared `client`.
config.snippets.clear();
- let snips = self.completion_snippets_custom().to_owned();
+ let snips = self.completion_snippets_custom(None).to_owned();
for (name, def) in snips.iter() {
if def.prefix.is_empty() && def.postfix.is_empty() {
@@ -1016,7 +1022,7 @@ impl Config {
config.source_root_parent_map = source_root_map;
}
- if config.check_command().is_empty() {
+ if config.check_command(None).is_empty() {
config.validation_errors.0.push(Arc::new(ConfigErrorInner::Json {
config_key: "/check/command".to_owned(),
error: serde_json::Error::custom("expected a non-empty string"),
@@ -1412,13 +1418,15 @@ impl Config {
pub fn completion(&self, source_root: Option<SourceRootId>) -> CompletionConfig {
CompletionConfig {
- enable_postfix_completions: self.completion_postfix_enable().to_owned(),
- enable_imports_on_the_fly: self.completion_autoimport_enable().to_owned()
+ enable_postfix_completions: self.completion_postfix_enable(source_root).to_owned(),
+ enable_imports_on_the_fly: self.completion_autoimport_enable(source_root).to_owned()
&& self.caps.completion_item_edit_resolve(),
- enable_self_on_the_fly: self.completion_autoself_enable().to_owned(),
- enable_private_editable: self.completion_privateEditable_enable().to_owned(),
- full_function_signatures: self.completion_fullFunctionSignatures_enable().to_owned(),
- callable: match self.completion_callable_snippets() {
+ 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,
@@ -1429,9 +1437,9 @@ impl Config {
prefer_prelude: self.imports_preferPrelude(source_root).to_owned(),
prefer_absolute: self.imports_prefixExternPrelude(source_root).to_owned(),
snippets: self.snippets.clone().to_vec(),
- limit: self.completion_limit().to_owned(),
- enable_term_search: self.completion_termSearch_enable().to_owned(),
- term_search_fuel: self.completion_termSearch_fuel().to_owned() as u64,
+ limit: self.completion_limit(source_root).to_owned(),
+ enable_term_search: self.completion_termSearch_enable(source_root).to_owned(),
+ term_search_fuel: self.completion_termSearch_fuel(source_root).to_owned() as u64,
}
}
@@ -1443,11 +1451,11 @@ impl Config {
pub fn diagnostics(&self, source_root: Option<SourceRootId>) -> DiagnosticsConfig {
DiagnosticsConfig {
- enabled: *self.diagnostics_enable(),
+ enabled: *self.diagnostics_enable(source_root),
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(),
+ disable_experimental: !self.diagnostics_experimental_enable(source_root),
+ disabled: self.diagnostics_disabled(source_root).clone(),
expr_fill_default: match self.assist_expressionFillDefault(source_root) {
ExprFillDefaultDef::Todo => ExprFillDefaultMode::Todo,
ExprFillDefaultDef::Default => ExprFillDefaultMode::Default,
@@ -1457,7 +1465,7 @@ impl Config {
prefer_no_std: self.imports_preferNoStd(source_root).to_owned(),
prefer_prelude: self.imports_preferPrelude(source_root).to_owned(),
prefer_absolute: self.imports_prefixExternPrelude(source_root).to_owned(),
- style_lints: self.diagnostics_styleLints_enable().to_owned(),
+ style_lints: self.diagnostics_styleLints_enable(source_root).to_owned(),
term_search_fuel: self.assist_termSearch_fuel(source_root).to_owned() as u64,
term_search_borrowck: self.assist_termSearch_borrowcheck(source_root).to_owned(),
}
@@ -1715,36 +1723,36 @@ impl Config {
self.cachePriming_enable().to_owned()
}
- pub fn publish_diagnostics(&self) -> bool {
- self.diagnostics_enable().to_owned()
+ pub fn publish_diagnostics(&self, source_root: Option<SourceRootId>) -> bool {
+ self.diagnostics_enable(source_root).to_owned()
}
- pub fn diagnostics_map(&self) -> DiagnosticsMapConfig {
+ pub fn diagnostics_map(&self, source_root: Option<SourceRootId>) -> DiagnosticsMapConfig {
DiagnosticsMapConfig {
- 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(),
+ remap_prefix: self.diagnostics_remapPrefix(source_root).clone(),
+ warnings_as_info: self.diagnostics_warningsAsInfo(source_root).clone(),
+ warnings_as_hint: self.diagnostics_warningsAsHint(source_root).clone(),
+ check_ignore: self.check_ignore(source_root).clone(),
}
}
- pub fn extra_args(&self) -> &Vec<String> {
- self.cargo_extraArgs()
+ pub fn extra_args(&self, source_root: Option<SourceRootId>) -> &Vec<String> {
+ self.cargo_extraArgs(source_root)
}
- pub fn extra_env(&self) -> &FxHashMap<String, String> {
- self.cargo_extraEnv()
+ pub fn extra_env(&self, source_root: Option<SourceRootId>) -> &FxHashMap<String, String> {
+ self.cargo_extraEnv(source_root)
}
- pub fn check_extra_args(&self) -> Vec<String> {
- let mut extra_args = self.extra_args().clone();
- extra_args.extend_from_slice(self.check_extraArgs());
+ pub fn check_extra_args(&self, source_root: Option<SourceRootId>) -> Vec<String> {
+ let mut extra_args = self.extra_args(source_root).clone();
+ extra_args.extend_from_slice(self.check_extraArgs(source_root));
extra_args
}
- pub fn check_extra_env(&self) -> FxHashMap<String, String> {
- let mut extra_env = self.cargo_extraEnv().clone();
- extra_env.extend(self.check_extraEnv().clone());
+ pub fn check_extra_env(&self, source_root: Option<SourceRootId>) -> FxHashMap<String, String> {
+ let mut extra_env = self.cargo_extraEnv(source_root).clone();
+ extra_env.extend(self.check_extraEnv(source_root).clone());
extra_env
}
@@ -1761,8 +1769,11 @@ impl Config {
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.procMacro_ignored()
+ pub fn ignored_proc_macros(
+ &self,
+ source_root: Option<SourceRootId>,
+ ) -> &FxHashMap<Box<str>, Box<[Box<str>]>> {
+ self.procMacro_ignored(source_root)
}
pub fn expand_proc_macros(&self) -> bool {
@@ -1787,23 +1798,23 @@ impl Config {
}
}
- pub fn cargo_autoreload_config(&self) -> bool {
- self.cargo_autoreload().to_owned()
+ pub fn cargo_autoreload_config(&self, source_root: Option<SourceRootId>) -> bool {
+ self.cargo_autoreload(source_root).to_owned()
}
- pub fn run_build_scripts(&self) -> bool {
- self.cargo_buildScripts_enable().to_owned() || self.procMacro_enable().to_owned()
+ pub fn run_build_scripts(&self, source_root: Option<SourceRootId>) -> bool {
+ self.cargo_buildScripts_enable(source_root).to_owned() || self.procMacro_enable().to_owned()
}
- pub fn cargo(&self) -> CargoConfig {
- let rustc_source = self.rustc_source().as_ref().map(|rustc_src| {
+ pub fn cargo(&self, source_root: Option<SourceRootId>) -> CargoConfig {
+ let rustc_source = self.rustc_source(source_root).as_ref().map(|rustc_src| {
if rustc_src == "discover" {
RustLibSource::Discover
} else {
RustLibSource::Path(self.root_path.join(rustc_src))
}
});
- let sysroot = self.cargo_sysroot().as_ref().map(|sysroot| {
+ let sysroot = self.cargo_sysroot(source_root).as_ref().map(|sysroot| {
if sysroot == "discover" {
RustLibSource::Discover
} else {
@@ -1811,24 +1822,24 @@ impl Config {
}
});
let sysroot_src =
- self.cargo_sysrootSrc().as_ref().map(|sysroot| self.root_path.join(sysroot));
+ self.cargo_sysrootSrc(source_root).as_ref().map(|sysroot| self.root_path.join(sysroot));
CargoConfig {
- all_targets: *self.cargo_allTargets(),
- features: match &self.cargo_features() {
+ all_targets: *self.cargo_allTargets(source_root),
+ features: match &self.cargo_features(source_root) {
CargoFeaturesDef::All => CargoFeatures::All,
CargoFeaturesDef::Selected(features) => CargoFeatures::Selected {
features: features.clone(),
- no_default_features: self.cargo_noDefaultFeatures().to_owned(),
+ no_default_features: self.cargo_noDefaultFeatures(source_root).to_owned(),
},
},
- target: self.cargo_target().clone(),
+ target: self.cargo_target(source_root).clone(),
sysroot,
sysroot_src,
rustc_source,
cfg_overrides: project_model::CfgOverrides {
global: CfgDiff::new(
- self.cargo_cfgs()
+ self.cargo_cfgs(source_root)
.iter()
.map(|(key, val)| match val {
Some(val) => CfgAtom::KeyValue {
@@ -1843,15 +1854,15 @@ impl Config {
.unwrap(),
selective: Default::default(),
},
- wrap_rustc_in_build_scripts: *self.cargo_buildScripts_useRustcWrapper(),
- invocation_strategy: match self.cargo_buildScripts_invocationStrategy() {
+ wrap_rustc_in_build_scripts: *self.cargo_buildScripts_useRustcWrapper(source_root),
+ invocation_strategy: match self.cargo_buildScripts_invocationStrategy(source_root) {
InvocationStrategy::Once => project_model::InvocationStrategy::Once,
InvocationStrategy::PerWorkspace => project_model::InvocationStrategy::PerWorkspace,
},
- 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(),
+ run_build_script_command: self.cargo_buildScripts_overrideCommand(source_root).clone(),
+ extra_args: self.cargo_extraArgs(source_root).clone(),
+ extra_env: self.cargo_extraEnv(source_root).clone(),
+ target_dir: self.target_dir_from_config(source_root),
}
}
@@ -1869,37 +1880,37 @@ impl Config {
}
}
- pub fn flycheck_workspace(&self) -> bool {
- *self.check_workspace()
+ pub fn flycheck_workspace(&self, source_root: Option<SourceRootId>) -> bool {
+ *self.check_workspace(source_root)
}
- pub(crate) fn cargo_test_options(&self) -> CargoOptions {
+ pub(crate) fn cargo_test_options(&self, source_root: Option<SourceRootId>) -> CargoOptions {
CargoOptions {
- target_triples: self.cargo_target().clone().into_iter().collect(),
+ target_triples: self.cargo_target(source_root).clone().into_iter().collect(),
all_targets: false,
- no_default_features: *self.cargo_noDefaultFeatures(),
- all_features: matches!(self.cargo_features(), CargoFeaturesDef::All),
- features: match self.cargo_features().clone() {
+ no_default_features: *self.cargo_noDefaultFeatures(source_root),
+ all_features: matches!(self.cargo_features(source_root), CargoFeaturesDef::All),
+ features: match self.cargo_features(source_root).clone() {
CargoFeaturesDef::All => vec![],
CargoFeaturesDef::Selected(it) => it,
},
- extra_args: self.extra_args().clone(),
- extra_test_bin_args: self.runnables_extraTestBinaryArgs().clone(),
- extra_env: self.extra_env().clone(),
- target_dir: self.target_dir_from_config(),
+ extra_args: self.extra_args(source_root).clone(),
+ extra_test_bin_args: self.runnables_extraTestBinaryArgs(source_root).clone(),
+ extra_env: self.extra_env(source_root).clone(),
+ target_dir: self.target_dir_from_config(source_root),
}
}
- pub(crate) fn flycheck(&self) -> FlycheckConfig {
- match &self.check_overrideCommand() {
+ pub(crate) fn flycheck(&self, source_root: Option<SourceRootId>) -> FlycheckConfig {
+ match &self.check_overrideCommand(source_root) {
Some(args) if !args.is_empty() => {
let mut args = args.clone();
let command = args.remove(0);
FlycheckConfig::CustomCommand {
command,
args,
- extra_env: self.check_extra_env(),
- invocation_strategy: match self.check_invocationStrategy() {
+ extra_env: self.check_extra_env(source_root),
+ invocation_strategy: match self.check_invocationStrategy(source_root) {
InvocationStrategy::Once => crate::flycheck::InvocationStrategy::Once,
InvocationStrategy::PerWorkspace => {
crate::flycheck::InvocationStrategy::PerWorkspace
@@ -1908,44 +1919,50 @@ impl Config {
}
}
Some(_) | None => FlycheckConfig::CargoCommand {
- command: self.check_command().clone(),
+ command: self.check_command(source_root).clone(),
options: CargoOptions {
target_triples: self
- .check_targets()
+ .check_targets(source_root)
.clone()
.and_then(|targets| match &targets.0[..] {
[] => None,
targets => Some(targets.into()),
})
- .unwrap_or_else(|| self.cargo_target().clone().into_iter().collect()),
- all_targets: self.check_allTargets().unwrap_or(*self.cargo_allTargets()),
+ .unwrap_or_else(|| {
+ self.cargo_target(source_root).clone().into_iter().collect()
+ }),
+ all_targets: self
+ .check_allTargets(source_root)
+ .unwrap_or(*self.cargo_allTargets(source_root)),
no_default_features: self
- .check_noDefaultFeatures()
- .unwrap_or(*self.cargo_noDefaultFeatures()),
+ .check_noDefaultFeatures(source_root)
+ .unwrap_or(*self.cargo_noDefaultFeatures(source_root)),
all_features: matches!(
- self.check_features().as_ref().unwrap_or(self.cargo_features()),
+ self.check_features(source_root)
+ .as_ref()
+ .unwrap_or(self.cargo_features(source_root)),
CargoFeaturesDef::All
),
features: match self
- .check_features()
+ .check_features(source_root)
.clone()
- .unwrap_or_else(|| self.cargo_features().clone())
+ .unwrap_or_else(|| self.cargo_features(source_root).clone())
{
CargoFeaturesDef::All => vec![],
CargoFeaturesDef::Selected(it) => it,
},
- extra_args: self.check_extra_args(),
- extra_test_bin_args: self.runnables_extraTestBinaryArgs().clone(),
- extra_env: self.check_extra_env(),
- target_dir: self.target_dir_from_config(),
+ extra_args: self.check_extra_args(source_root),
+ extra_test_bin_args: self.runnables_extraTestBinaryArgs(source_root).clone(),
+ extra_env: self.check_extra_env(source_root),
+ target_dir: self.target_dir_from_config(source_root),
},
ansi_color_output: self.color_diagnostic_output(),
},
}
}
- fn target_dir_from_config(&self) -> Option<Utf8PathBuf> {
- self.cargo_targetDir().as_ref().and_then(|target_dir| match target_dir {
+ fn target_dir_from_config(&self, source_root: Option<SourceRootId>) -> Option<Utf8PathBuf> {
+ self.cargo_targetDir(source_root).as_ref().and_then(|target_dir| match target_dir {
TargetDirectory::UseSubdirectory(true) => {
Some(Utf8PathBuf::from("target/rust-analyzer"))
}
@@ -1955,19 +1972,19 @@ impl Config {
})
}
- pub fn check_on_save(&self) -> bool {
- *self.checkOnSave()
+ pub fn check_on_save(&self, source_root: Option<SourceRootId>) -> bool {
+ *self.checkOnSave(source_root)
}
- pub fn script_rebuild_on_save(&self) -> bool {
- *self.cargo_buildScripts_rebuildOnSave()
+ pub fn script_rebuild_on_save(&self, source_root: Option<SourceRootId>) -> bool {
+ *self.cargo_buildScripts_rebuildOnSave(source_root)
}
- pub fn runnables(&self) -> RunnablesConfig {
+ pub fn runnables(&self, source_root: Option<SourceRootId>) -> RunnablesConfig {
RunnablesConfig {
- override_cargo: self.runnables_command().clone(),
- cargo_extra_args: self.runnables_extraArgs().clone(),
- extra_test_binary_args: self.runnables_extraTestBinaryArgs().clone(),
+ override_cargo: self.runnables_command(source_root).clone(),
+ cargo_extra_args: self.runnables_extraArgs(source_root).clone(),
+ extra_test_binary_args: self.runnables_extraTestBinaryArgs(source_root).clone(),
}
}
@@ -2006,19 +2023,19 @@ impl Config {
}
}
- pub fn workspace_symbol(&self) -> WorkspaceSymbolConfig {
+ pub fn workspace_symbol(&self, source_root: Option<SourceRootId>) -> WorkspaceSymbolConfig {
WorkspaceSymbolConfig {
- search_scope: match self.workspace_symbol_search_scope() {
+ search_scope: match self.workspace_symbol_search_scope(source_root) {
WorkspaceSymbolSearchScopeDef::Workspace => WorkspaceSymbolSearchScope::Workspace,
WorkspaceSymbolSearchScopeDef::WorkspaceAndDependencies => {
WorkspaceSymbolSearchScope::WorkspaceAndDependencies
}
},
- search_kind: match self.workspace_symbol_search_kind() {
+ search_kind: match self.workspace_symbol_search_kind(source_root) {
WorkspaceSymbolSearchKindDef::OnlyTypes => WorkspaceSymbolSearchKind::OnlyTypes,
WorkspaceSymbolSearchKindDef::AllSymbols => WorkspaceSymbolSearchKind::AllSymbols,
},
- search_limit: *self.workspace_symbol_search_limit(),
+ search_limit: *self.workspace_symbol_search_limit(source_root),
}
}
@@ -3522,9 +3539,9 @@ mod tests {
}));
(config, _, _) = config.apply_change(change);
- assert_eq!(config.cargo_targetDir(), &None);
+ assert_eq!(config.cargo_targetDir(None), &None);
assert!(
- matches!(config.flycheck(), FlycheckConfig::CargoCommand { options, .. } if options.target_dir.is_none())
+ matches!(config.flycheck(None), FlycheckConfig::CargoCommand { options, .. } if options.target_dir.is_none())
);
}
@@ -3540,9 +3557,9 @@ mod tests {
(config, _, _) = config.apply_change(change);
- assert_eq!(config.cargo_targetDir(), &Some(TargetDirectory::UseSubdirectory(true)));
+ assert_eq!(config.cargo_targetDir(None), &Some(TargetDirectory::UseSubdirectory(true)));
assert!(
- matches!(config.flycheck(), FlycheckConfig::CargoCommand { options, .. } if options.target_dir == Some(Utf8PathBuf::from("target/rust-analyzer")))
+ matches!(config.flycheck(None), FlycheckConfig::CargoCommand { options, .. } if options.target_dir == Some(Utf8PathBuf::from("target/rust-analyzer")))
);
}
@@ -3559,83 +3576,11 @@ mod tests {
(config, _, _) = config.apply_change(change);
assert_eq!(
- config.cargo_targetDir(),
+ config.cargo_targetDir(None),
&Some(TargetDirectory::Directory(Utf8PathBuf::from("other_folder")))
);
assert!(
- matches!(config.flycheck(), FlycheckConfig::CargoCommand { options, .. } if options.target_dir == Some(Utf8PathBuf::from("other_folder")))
+ matches!(config.flycheck(None), FlycheckConfig::CargoCommand { options, .. } if options.target_dir == Some(Utf8PathBuf::from("other_folder")))
);
}
-
- #[test]
- fn toml_unknown_key() {
- let config =
- Config::new(AbsPathBuf::assert(project_root()), Default::default(), vec![], None);
-
- let mut change = ConfigChange::default();
-
- change.change_user_config(Some(
- toml::toml! {
- [cargo.cfgs]
- these = "these"
- should = "should"
- be = "be"
- valid = "valid"
-
- [invalid.config]
- err = "error"
-
- [cargo]
- target = "ok"
-
- // FIXME: This should be an error
- [cargo.sysroot]
- non-table = "expected"
- }
- .to_string()
- .into(),
- ));
-
- let (config, e, _) = config.apply_change(change);
- expect_test::expect![[r#"
- ConfigErrors(
- [
- Toml {
- config_key: "invalid/config/err",
- error: Error {
- inner: Error {
- inner: TomlError {
- message: "unexpected field",
- raw: None,
- keys: [],
- span: None,
- },
- },
- },
- },
- ],
- )
- "#]]
- .assert_debug_eq(&e);
- let mut change = ConfigChange::default();
-
- change.change_user_config(Some(
- toml::toml! {
- [cargo.cfgs]
- these = "these"
- should = "should"
- be = "be"
- valid = "valid"
- }
- .to_string()
- .into(),
- ));
- let (_, e, _) = config.apply_change(change);
- expect_test::expect![[r#"
- ConfigErrors(
- [],
- )
- "#]]
- .assert_debug_eq(&e);
- }
}
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index 9d0082c370..35e1da80bf 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -631,6 +631,10 @@ impl GlobalStateSnapshot {
file_id_to_url(&self.vfs_read(), id)
}
+ pub(crate) fn vfs_path_to_file_id(&self, vfs_path: &VfsPath) -> anyhow::Result<FileId> {
+ vfs_path_to_file_id(&self.vfs_read(), vfs_path)
+ }
+
pub(crate) fn file_line_index(&self, file_id: FileId) -> Cancellable<LineIndex> {
let endings = self.vfs.read().1[&file_id];
let index = self.analysis.file_line_index(file_id)?;
@@ -725,3 +729,9 @@ pub(crate) fn url_to_file_id(vfs: &vfs::Vfs, url: &Url) -> anyhow::Result<FileId
let res = vfs.file_id(&path).ok_or_else(|| anyhow::format_err!("file not found: {path}"))?;
Ok(res)
}
+
+pub(crate) fn vfs_path_to_file_id(vfs: &vfs::Vfs, vfs_path: &VfsPath) -> anyhow::Result<FileId> {
+ let res =
+ vfs.file_id(vfs_path).ok_or_else(|| anyhow::format_err!("file not found: {vfs_path}"))?;
+ Ok(res)
+}
diff --git a/crates/rust-analyzer/src/handlers/notification.rs b/crates/rust-analyzer/src/handlers/notification.rs
index 38b88ff2d0..e8d1a7e4df 100644
--- a/crates/rust-analyzer/src/handlers/notification.rs
+++ b/crates/rust-analyzer/src/handlers/notification.rs
@@ -145,14 +145,18 @@ pub(crate) fn handle_did_save_text_document(
state: &mut GlobalState,
params: DidSaveTextDocumentParams,
) -> anyhow::Result<()> {
- if state.config.script_rebuild_on_save() && state.build_deps_changed {
- state.build_deps_changed = false;
- state
- .fetch_build_data_queue
- .request_op("build_deps_changed - save notification".to_owned(), ());
- }
-
if let Ok(vfs_path) = from_proto::vfs_path(&params.text_document.uri) {
+ let snap = state.snapshot();
+ let file_id = snap.vfs_path_to_file_id(&vfs_path)?;
+ let sr = snap.analysis.source_root_id(file_id)?;
+
+ if state.config.script_rebuild_on_save(Some(sr)) && state.build_deps_changed {
+ state.build_deps_changed = false;
+ state
+ .fetch_build_data_queue
+ .request_op("build_deps_changed - save notification".to_owned(), ());
+ }
+
// Re-fetch workspaces if a workspace related file has changed
if let Some(path) = vfs_path.as_path() {
let additional_files = &state
@@ -182,15 +186,16 @@ pub(crate) fn handle_did_save_text_document(
}
}
- if !state.config.check_on_save() || run_flycheck(state, vfs_path) {
+ if !state.config.check_on_save(Some(sr)) || run_flycheck(state, vfs_path) {
return Ok(());
}
- } else if state.config.check_on_save() {
+ } else if state.config.check_on_save(None) {
// No specific flycheck was triggered, so let's trigger all of them.
for flycheck in state.flycheck.iter() {
flycheck.restart_workspace(None);
}
}
+
Ok(())
}
@@ -288,6 +293,7 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool {
let file_id = state.vfs.read().0.file_id(&vfs_path);
if let Some(file_id) = file_id {
let world = state.snapshot();
+ let source_root_id = world.analysis.source_root_id(file_id).ok();
let mut updated = false;
let task = move || -> std::result::Result<(), ide::Cancelled> {
// Is the target binary? If so we let flycheck run only for the workspace that contains the crate.
@@ -373,9 +379,9 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool {
for (id, package) in workspace_ids.clone() {
if id == flycheck.id() {
updated = true;
- match package
- .filter(|_| !world.config.flycheck_workspace() || target.is_some())
- {
+ match package.filter(|_| {
+ !world.config.flycheck_workspace(source_root_id) || target.is_some()
+ }) {
Some(package) => flycheck
.restart_for_package(package, target.clone().map(TupleExt::head)),
None => flycheck.restart_workspace(saved_file.clone()),
diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs
index 50df9dc876..09d5086201 100644
--- a/crates/rust-analyzer/src/handlers/request.rs
+++ b/crates/rust-analyzer/src/handlers/request.rs
@@ -256,7 +256,7 @@ pub(crate) fn handle_run_test(
let handle = CargoTestHandle::new(
test_path,
- state.config.cargo_test_options(),
+ state.config.cargo_test_options(None),
cargo.workspace_root(),
test_target,
state.test_run_sender.clone(),
@@ -565,7 +565,7 @@ pub(crate) fn handle_workspace_symbol(
) -> anyhow::Result<Option<lsp_types::WorkspaceSymbolResponse>> {
let _p = tracing::info_span!("handle_workspace_symbol").entered();
- let config = snap.config.workspace_symbol();
+ let config = snap.config.workspace_symbol(None);
let (all_symbols, libs) = decide_search_scope_and_kind(&params, &config);
let query = {
@@ -852,6 +852,7 @@ pub(crate) fn handle_runnables(
) -> anyhow::Result<Vec<lsp_ext::Runnable>> {
let _p = tracing::info_span!("handle_runnables").entered();
let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
+ let source_root = snap.analysis.source_root_id(file_id).ok();
let line_index = snap.file_line_index(file_id)?;
let offset = params.position.and_then(|it| from_proto::offset(&line_index, it).ok());
let target_spec = TargetSpec::for_file(&snap, file_id)?;
@@ -894,7 +895,7 @@ pub(crate) fn handle_runnables(
}
// Add `cargo check` and `cargo test` for all targets of the whole package
- let config = snap.config.runnables();
+ let config = snap.config.runnables(source_root);
match target_spec {
Some(TargetSpec::Cargo(spec)) => {
let is_crate_no_std = snap.analysis.is_crate_no_std(spec.crate_id)?;
@@ -2119,7 +2120,7 @@ fn run_rustfmt(
RustfmtConfig::Rustfmt { extra_args, enable_range_formatting } => {
// FIXME: Set RUSTUP_TOOLCHAIN
let mut cmd = process::Command::new(toolchain::Tool::Rustfmt.path());
- cmd.envs(snap.config.extra_env());
+ cmd.envs(snap.config.extra_env(source_root_id));
cmd.args(extra_args);
if let Some(edition) = edition {
@@ -2177,7 +2178,7 @@ fn run_rustfmt(
_ => process::Command::new(cmd),
};
- cmd.envs(snap.config.extra_env());
+ cmd.envs(snap.config.extra_env(source_root_id));
cmd.args(args);
cmd
}
diff --git a/crates/rust-analyzer/src/lsp/to_proto.rs b/crates/rust-analyzer/src/lsp/to_proto.rs
index 7eed9ce2f3..6dff8abb0f 100644
--- a/crates/rust-analyzer/src/lsp/to_proto.rs
+++ b/crates/rust-analyzer/src/lsp/to_proto.rs
@@ -1369,8 +1369,9 @@ pub(crate) fn runnable(
snap: &GlobalStateSnapshot,
runnable: Runnable,
) -> Cancellable<Option<lsp_ext::Runnable>> {
- let config = snap.config.runnables();
let target_spec = TargetSpec::for_file(snap, runnable.nav.file_id)?;
+ let source_root = snap.analysis.source_root_id(runnable.nav.file_id).ok();
+ let config = snap.config.runnables(source_root);
match target_spec {
Some(TargetSpec::Cargo(spec)) => {
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 616d6b4935..ec71b4a7a1 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -404,7 +404,7 @@ impl GlobalState {
if self.is_quiescent() {
let became_quiescent = !was_quiescent;
if became_quiescent {
- if self.config.check_on_save() {
+ if self.config.check_on_save(None) {
// Project has loaded properly, kick off initial flycheck
self.flycheck.iter().for_each(|flycheck| flycheck.restart_workspace(None));
}
@@ -434,7 +434,7 @@ impl GlobalState {
let project_or_mem_docs_changed =
became_quiescent || state_changed || memdocs_added_or_removed;
- if project_or_mem_docs_changed && self.config.publish_diagnostics() {
+ if project_or_mem_docs_changed && self.config.publish_diagnostics(None) {
self.update_diagnostics();
}
if project_or_mem_docs_changed && self.config.test_explorer() {
@@ -455,7 +455,7 @@ impl GlobalState {
}
}
- if self.config.cargo_autoreload_config()
+ if self.config.cargo_autoreload_config(None)
|| self.config.discover_workspace_config().is_some()
{
if let Some((cause, FetchWorkspaceRequest { path, force_crate_graph_reload })) =
@@ -925,7 +925,7 @@ impl GlobalState {
FlycheckMessage::AddDiagnostic { id, workspace_root, diagnostic } => {
let snap = self.snapshot();
let diagnostics = crate::diagnostics::to_proto::map_rust_diagnostic_to_lsp(
- &self.config.diagnostics_map(),
+ &self.config.diagnostics_map(None),
&diagnostic,
&workspace_root,
&snap,
@@ -973,9 +973,9 @@ impl GlobalState {
// When we're running multiple flychecks, we have to include a disambiguator in
// the title, or the editor complains. Note that this is a user-facing string.
let title = if self.flycheck.len() == 1 {
- format!("{}", self.config.flycheck())
+ format!("{}", self.config.flycheck(None))
} else {
- format!("{} (#{})", self.config.flycheck(), id + 1)
+ format!("{} (#{})", self.config.flycheck(None), id + 1)
};
self.report_progress(
&title,
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index 68366136ed..12667e3c90 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -100,7 +100,7 @@ impl GlobalState {
{
let req = FetchWorkspaceRequest { path: None, force_crate_graph_reload: false };
self.fetch_workspaces_queue.request_op("discovered projects changed".to_owned(), req)
- } else if self.config.flycheck() != old_config.flycheck() {
+ } else if self.config.flycheck(None) != old_config.flycheck(None) {
self.reload_flycheck();
}
@@ -122,7 +122,7 @@ impl GlobalState {
};
let mut message = String::new();
- if !self.config.cargo_autoreload()
+ if !self.config.cargo_autoreload_config(None)
&& self.is_quiescent()
&& self.fetch_workspaces_queue.op_requested()
&& self.config.discover_workspace_config().is_none()
@@ -264,7 +264,7 @@ impl GlobalState {
.map(ManifestPath::try_from)
.filter_map(Result::ok)
.collect();
- let cargo_config = self.config.cargo();
+ let cargo_config = self.config.cargo(None);
let discover_command = self.config.discover_workspace_config().cloned();
let is_quiescent = !(self.discover_workspace_queue.op_in_progress()
|| self.vfs_progress_config_version < self.vfs_config_version
@@ -357,7 +357,7 @@ impl GlobalState {
pub(crate) fn fetch_build_data(&mut self, cause: Cause) {
info!(%cause, "will fetch build data");
let workspaces = Arc::clone(&self.workspaces);
- let config = self.config.cargo();
+ let config = self.config.cargo(None);
let root_path = self.config.root_path().clone();
self.task_pool.handle.spawn_with_sender(ThreadIntent::Worker, move |sender| {
@@ -382,7 +382,7 @@ impl GlobalState {
pub(crate) fn fetch_proc_macros(&mut self, cause: Cause, paths: Vec<ProcMacroPaths>) {
info!(%cause, "will load proc macros");
- let ignored_proc_macros = self.config.ignored_proc_macros().clone();
+ let ignored_proc_macros = self.config.ignored_proc_macros(None).clone();
let proc_macro_clients = self.proc_macro_clients.clone();
self.task_pool.handle.spawn_with_sender(ThreadIntent::Worker, move |sender| {
@@ -507,7 +507,7 @@ impl GlobalState {
// FIXME: can we abort the build scripts here if they are already running?
self.workspaces = Arc::new(workspaces);
- if self.config.run_build_scripts() {
+ if self.config.run_build_scripts(None) {
self.build_deps_changed = false;
self.fetch_build_data_queue.request_op("workspace updated".to_owned(), ());
}
@@ -627,7 +627,7 @@ impl GlobalState {
..
} => cargo_config_extra_env
.iter()
- .chain(self.config.extra_env())
+ .chain(self.config.extra_env(None))
.map(|(a, b)| (a.clone(), b.clone()))
.chain(
ws.sysroot
@@ -702,7 +702,7 @@ impl GlobalState {
vfs.file_id(&vfs_path)
};
- ws_to_crate_graph(&self.workspaces, self.config.extra_env(), load)
+ ws_to_crate_graph(&self.workspaces, self.config.extra_env(None), load)
};
let mut change = ChangeWithProcMacros::new();
if self.config.expand_proc_macros() {
@@ -791,7 +791,7 @@ impl GlobalState {
fn reload_flycheck(&mut self) {
let _p = tracing::info_span!("GlobalState::reload_flycheck").entered();
- let config = self.config.flycheck();
+ let config = self.config.flycheck(None);
let sender = self.flycheck_sender.clone();
let invocation_strategy = match config {
FlycheckConfig::CargoCommand { .. } => {
diff --git a/crates/rust-analyzer/src/target_spec.rs b/crates/rust-analyzer/src/target_spec.rs
index 954e13cbf2..b4aa73d278 100644
--- a/crates/rust-analyzer/src/target_spec.rs
+++ b/crates/rust-analyzer/src/target_spec.rs
@@ -113,7 +113,7 @@ impl CargoTargetSpec {
kind: &RunnableKind,
cfg: &Option<CfgExpr>,
) -> (Vec<String>, Vec<String>) {
- let config = snap.config.runnables();
+ let config = snap.config.runnables(None);
let extra_test_binary_args = config.extra_test_binary_args;
let mut cargo_args = Vec::new();
@@ -168,7 +168,7 @@ impl CargoTargetSpec {
(Default::default(), Default::default())
};
- let cargo_config = snap.config.cargo();
+ let cargo_config = snap.config.cargo(None);
match &cargo_config.features {
CargoFeatures::All => {