Next up : generating configs for workspace level configs

This commit is contained in:
Ali Bektas 2024-08-17 01:48:23 +02:00
parent d51fd9f196
commit 94ed6217dd
6 changed files with 48 additions and 110 deletions

View file

@ -294,18 +294,6 @@ config_data! {
/// This option does not take effect until rust-analyzer is restarted. /// This option does not take effect until rust-analyzer is restarted.
rustc_source: Option<String> = None, 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,
/// Enables automatic discovery of projects using [`DiscoverWorkspaceConfig::command`]. /// Enables automatic discovery of projects using [`DiscoverWorkspaceConfig::command`].
/// ///
@ -439,6 +427,18 @@ config_data! {
config_data! { config_data! {
workspace: struct WorkspaceDefaultConfigData <- WorkspaceConfigInput -> { 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,
} }
} }
@ -775,7 +775,7 @@ pub struct Config {
user_config_path: VfsPath, user_config_path: VfsPath,
/// Config node whose values apply to **every** Rust project. /// Config node whose values apply to **every** Rust project.
user_config: Option<(GlobalLocalConfigInput, ConfigErrors)>, user_config: Option<(GlobalWorkspaceLocalConfigInput, ConfigErrors)>,
ratoml_file: FxHashMap<SourceRootId, (RatomlFile, ConfigErrors)>, ratoml_file: FxHashMap<SourceRootId, (RatomlFile, ConfigErrors)>,
@ -825,13 +825,13 @@ impl Config {
if let Ok(table) = toml::from_str(&change) { if let Ok(table) = toml::from_str(&change) {
let mut toml_errors = vec![]; let mut toml_errors = vec![];
validate_toml_table( validate_toml_table(
GlobalLocalConfigInput::FIELDS, GlobalWorkspaceLocalConfigInput::FIELDS,
&table, &table,
&mut String::new(), &mut String::new(),
&mut toml_errors, &mut toml_errors,
); );
config.user_config = Some(( config.user_config = Some((
GlobalLocalConfigInput::from_toml(table, &mut toml_errors), GlobalWorkspaceLocalConfigInput::from_toml(table, &mut toml_errors),
ConfigErrors( ConfigErrors(
toml_errors toml_errors
.into_iter() .into_iter()
@ -960,7 +960,7 @@ impl Config {
match toml::from_str(&text) { match toml::from_str(&text) {
Ok(table) => { Ok(table) => {
validate_toml_table( validate_toml_table(
GlobalLocalConfigInput::FIELDS, WorkspaceLocalConfigInput::FIELDS,
&table, &table,
&mut String::new(), &mut String::new(),
&mut toml_errors, &mut toml_errors,
@ -1863,16 +1863,16 @@ impl Config {
} }
} }
pub fn rustfmt(&self) -> RustfmtConfig { pub fn rustfmt(&self, source_root_id: Option<SourceRootId>) -> RustfmtConfig {
match &self.rustfmt_overrideCommand() { match &self.rustfmt_overrideCommand(source_root_id) {
Some(args) if !args.is_empty() => { Some(args) if !args.is_empty() => {
let mut args = args.clone(); let mut args = args.clone();
let command = args.remove(0); let command = args.remove(0);
RustfmtConfig::CustomCommand { command, args } RustfmtConfig::CustomCommand { command, args }
} }
Some(_) | None => RustfmtConfig::Rustfmt { Some(_) | None => RustfmtConfig::Rustfmt {
extra_args: self.rustfmt_extraArgs().clone(), extra_args: self.rustfmt_extraArgs(source_root_id).clone(),
enable_range_formatting: *self.rustfmt_rangeFormatting_enable(), enable_range_formatting: *self.rustfmt_rangeFormatting_enable(source_root_id),
}, },
} }
} }
@ -2555,24 +2555,20 @@ macro_rules! _impl_for_config_data {
$vis fn $field(&self, source_root: Option<SourceRootId>) -> &$ty { $vis fn $field(&self, source_root: Option<SourceRootId>) -> &$ty {
let mut source_root = source_root.as_ref(); let mut source_root = source_root.as_ref();
while let Some(sr) = source_root { while let Some(sr) = source_root {
if let Some((file, _)) = self.ratoml_file.get(&sr) { if let Some((RatomlFile::Workspace(config), _)) = self.ratoml_file.get(&sr) {
match file {
RatomlFile::Workspace(config) => {
if let Some(v) = config.workspace.$field.as_ref() { if let Some(v) = config.workspace.$field.as_ref() {
return &v; return &v;
} }
},
}
} }
source_root = self.source_root_parent_map.get(&sr); source_root = self.source_root_parent_map.get(&sr);
} }
if let Some(v) = self.client_config.0.local.$field.as_ref() { if let Some(v) = self.client_config.0.workspace.$field.as_ref() {
return &v; return &v;
} }
if let Some((user_config, _)) = self.user_config.as_ref() { if let Some((user_config, _)) = self.user_config.as_ref() {
if let Some(v) = user_config.local.$field.as_ref() { if let Some(v) = user_config.workspace.$field.as_ref() {
return &v; return &v;
} }
} }
@ -2591,7 +2587,6 @@ macro_rules! _impl_for_config_data {
$( $(
$($doc)* $($doc)*
#[allow(non_snake_case)] #[allow(non_snake_case)]
// TODO Remove source_root
$vis fn $field(&self) -> &$ty { $vis fn $field(&self) -> &$ty {
if let Some(v) = self.client_config.0.global.$field.as_ref() { if let Some(v) = self.client_config.0.global.$field.as_ref() {
return &v; return &v;
@ -2730,6 +2725,7 @@ use _config_data as config_data;
#[derive(Default, Debug, Clone)] #[derive(Default, Debug, Clone)]
struct DefaultConfigData { struct DefaultConfigData {
global: GlobalDefaultConfigData, global: GlobalDefaultConfigData,
workspace: WorkspaceDefaultConfigData,
local: LocalDefaultConfigData, local: LocalDefaultConfigData,
client: ClientDefaultConfigData, client: ClientDefaultConfigData,
} }
@ -2740,6 +2736,7 @@ struct DefaultConfigData {
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
struct FullConfigInput { struct FullConfigInput {
global: GlobalConfigInput, global: GlobalConfigInput,
workspace: WorkspaceConfigInput,
local: LocalConfigInput, local: LocalConfigInput,
client: ClientConfigInput, client: ClientConfigInput,
} }
@ -2753,6 +2750,7 @@ impl FullConfigInput {
global: GlobalConfigInput::from_json(&mut json, error_sink), global: GlobalConfigInput::from_json(&mut json, error_sink),
local: LocalConfigInput::from_json(&mut json, error_sink), local: LocalConfigInput::from_json(&mut json, error_sink),
client: ClientConfigInput::from_json(&mut json, error_sink), client: ClientConfigInput::from_json(&mut json, error_sink),
workspace: WorkspaceConfigInput::from_json(&mut json, error_sink),
} }
} }
@ -2783,26 +2781,28 @@ impl FullConfigInput {
/// some rust-analyzer.toml file or JSON blob. An empty rust-analyzer.toml corresponds to /// some rust-analyzer.toml file or JSON blob. An empty rust-analyzer.toml corresponds to
/// all fields being None. /// all fields being None.
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
struct GlobalLocalConfigInput { struct GlobalWorkspaceLocalConfigInput {
global: GlobalConfigInput, global: GlobalConfigInput,
local: LocalConfigInput, local: LocalConfigInput,
workspace: WorkspaceConfigInput,
} }
impl GlobalLocalConfigInput { impl GlobalWorkspaceLocalConfigInput {
const FIELDS: &'static [&'static [&'static str]] = const FIELDS: &'static [&'static [&'static str]] =
&[GlobalConfigInput::FIELDS, LocalConfigInput::FIELDS]; &[GlobalConfigInput::FIELDS, LocalConfigInput::FIELDS];
fn from_toml( fn from_toml(
toml: toml::Table, toml: toml::Table,
error_sink: &mut Vec<(String, toml::de::Error)>, error_sink: &mut Vec<(String, toml::de::Error)>,
) -> GlobalLocalConfigInput { ) -> GlobalWorkspaceLocalConfigInput {
GlobalLocalConfigInput { GlobalWorkspaceLocalConfigInput {
global: GlobalConfigInput::from_toml(&toml, error_sink), global: GlobalConfigInput::from_toml(&toml, error_sink),
local: LocalConfigInput::from_toml(&toml, error_sink), local: LocalConfigInput::from_toml(&toml, error_sink),
workspace: WorkspaceConfigInput::from_toml(&toml, error_sink),
} }
} }
} }
/// All of the config levels, all fields `Option<T>`, to describe fields that are actually set by /// Workspace and local 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 /// some rust-analyzer.toml file or JSON blob. An empty rust-analyzer.toml corresponds to
/// all fields being None. /// all fields being None.
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]

View file

@ -2113,8 +2113,9 @@ fn run_rustfmt(
let edition = editions.iter().copied().max(); let edition = editions.iter().copied().max();
let line_index = snap.file_line_index(file_id)?; let line_index = snap.file_line_index(file_id)?;
let source_root_id = snap.analysis.source_root_id(file_id).ok();
let mut command = match snap.config.rustfmt() { let mut command = match snap.config.rustfmt(source_root_id) {
RustfmtConfig::Rustfmt { extra_args, enable_range_formatting } => { RustfmtConfig::Rustfmt { extra_args, enable_range_formatting } => {
// FIXME: Set RUSTUP_TOOLCHAIN // FIXME: Set RUSTUP_TOOLCHAIN
let mut cmd = process::Command::new(toolchain::Tool::Rustfmt.path()); let mut cmd = process::Command::new(toolchain::Tool::Rustfmt.path());
@ -2302,9 +2303,8 @@ pub(crate) fn internal_testing_fetch_config(
.transpose()?; .transpose()?;
serde_json::to_value(match &*params.config { serde_json::to_value(match &*params.config {
"local" => state.config.assist(source_root).assist_emit_must_use, "local" => state.config.assist(source_root).assist_emit_must_use,
// TODO Most probably will fail because it was not renamed to workspace "workspace" => matches!(
"global" => matches!( state.config.rustfmt(source_root),
state.config.rustfmt(),
RustfmtConfig::Rustfmt { enable_range_formatting: true, .. } RustfmtConfig::Rustfmt { enable_range_formatting: true, .. }
), ),
_ => return Err(anyhow::anyhow!("Unknown test config key: {}", params.config)), _ => return Err(anyhow::anyhow!("Unknown test config key: {}", params.config)),

View file

@ -67,7 +67,7 @@ pub fn server_capabilities(config: &Config) -> ServerCapabilities {
code_action_provider: Some(config.caps().code_action_capabilities()), code_action_provider: Some(config.caps().code_action_capabilities()),
code_lens_provider: Some(CodeLensOptions { resolve_provider: Some(true) }), code_lens_provider: Some(CodeLensOptions { resolve_provider: Some(true) }),
document_formatting_provider: Some(OneOf::Left(true)), document_formatting_provider: Some(OneOf::Left(true)),
document_range_formatting_provider: match config.rustfmt() { document_range_formatting_provider: match config.rustfmt(None) {
RustfmtConfig::Rustfmt { enable_range_formatting: true, .. } => Some(OneOf::Left(true)), RustfmtConfig::Rustfmt { enable_range_formatting: true, .. } => Some(OneOf::Left(true)),
_ => Some(OneOf::Left(false)), _ => Some(OneOf::Left(false)),
}, },

View file

@ -17,7 +17,7 @@ enum QueryType {
/// A query whose config key is a part of the global configs, so that /// A query whose config key is a part of the global configs, so that
/// testing for changes to this config means testing if global changes /// testing for changes to this config means testing if global changes
/// take affect. /// take affect.
Global, Workspace,
} }
struct RatomlTest { struct RatomlTest {
@ -165,7 +165,7 @@ impl RatomlTest {
fn query(&self, query: QueryType, source_file_idx: usize) -> bool { fn query(&self, query: QueryType, source_file_idx: usize) -> bool {
let config = match query { let config = match query {
QueryType::Local => "local".to_owned(), QueryType::Local => "local".to_owned(),
QueryType::Global => "global".to_owned(), QueryType::Workspace => "workspace".to_owned(),
}; };
let res = self.server.send_request::<InternalTestingFetchConfig>( let res = self.server.send_request::<InternalTestingFetchConfig>(
InternalTestingFetchConfigParams { InternalTestingFetchConfigParams {
@ -823,10 +823,8 @@ fn ratoml_multiple_ratoml_in_single_source_root() {
// assert!(!server.query(QueryType::AssistEmitMustUse, 5)); // assert!(!server.query(QueryType::AssistEmitMustUse, 5));
// } // }
/// Having a ratoml file at the root of a project enables
/// configuring global level configurations as well.
#[test] #[test]
fn ratoml_in_root_is_global() { fn ratoml_in_root_is_workspace() {
if skip_slow_tests() { if skip_slow_tests() {
return; return;
} }
@ -854,7 +852,7 @@ fn main() {
None, None,
); );
assert!(server.query(QueryType::Global, 2)); assert!(server.query(QueryType::Workspace, 2));
} }
#[test] #[test]
@ -886,9 +884,9 @@ fn main() {
None, None,
); );
assert!(server.query(QueryType::Global, 2)); assert!(server.query(QueryType::Workspace, 2));
server.edit(1, "rustfmt.rangeFormatting.enable = false".to_owned()); server.edit(1, "rustfmt.rangeFormatting.enable = false".to_owned());
assert!(!server.query(QueryType::Global, 2)); assert!(!server.query(QueryType::Workspace, 2));
} }
#[test] #[test]
@ -920,7 +918,7 @@ fn main() {
None, None,
); );
assert!(server.query(QueryType::Global, 2)); assert!(server.query(QueryType::Workspace, 2));
server.delete(1); server.delete(1);
assert!(!server.query(QueryType::Global, 2)); assert!(!server.query(QueryType::Workspace, 2));
} }

View file

@ -878,27 +878,6 @@ crates must set `[package.metadata.rust-analyzer] rustc_private=true` to use it.
This option does not take effect until rust-analyzer is restarted. This option does not take effect until rust-analyzer is restarted.
-- --
[[rust-analyzer.rustfmt.extraArgs]]rust-analyzer.rustfmt.extraArgs (default: `[]`)::
+
--
Additional arguments to `rustfmt`.
--
[[rust-analyzer.rustfmt.overrideCommand]]rust-analyzer.rustfmt.overrideCommand (default: `null`)::
+
--
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.
--
[[rust-analyzer.rustfmt.rangeFormatting.enable]]rust-analyzer.rustfmt.rangeFormatting.enable (default: `false`)::
+
--
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.
--
[[rust-analyzer.semanticHighlighting.doc.comment.inject.enable]]rust-analyzer.semanticHighlighting.doc.comment.inject.enable (default: `true`):: [[rust-analyzer.semanticHighlighting.doc.comment.inject.enable]]rust-analyzer.semanticHighlighting.doc.comment.inject.enable (default: `true`)::
+ +
-- --

View file

@ -2358,45 +2358,6 @@
} }
} }
}, },
{
"title": "rustfmt",
"properties": {
"rust-analyzer.rustfmt.extraArgs": {
"markdownDescription": "Additional arguments to `rustfmt`.",
"default": [],
"type": "array",
"items": {
"type": "string"
}
}
}
},
{
"title": "rustfmt",
"properties": {
"rust-analyzer.rustfmt.overrideCommand": {
"markdownDescription": "Advanced option, fully override the command rust-analyzer uses for\nformatting. This should be the equivalent of `rustfmt` here, and\nnot that of `cargo fmt`. The file contents will be passed on the\nstandard input and the formatted result will be read from the\nstandard output.",
"default": null,
"type": [
"null",
"array"
],
"items": {
"type": "string"
}
}
}
},
{
"title": "rustfmt",
"properties": {
"rust-analyzer.rustfmt.rangeFormatting.enable": {
"markdownDescription": "Enables the use of rustfmt's unstable range formatting command for the\n`textDocument/rangeFormatting` request. The rustfmt option is unstable and only\navailable on a nightly build.",
"default": false,
"type": "boolean"
}
}
},
{ {
"title": "semanticHighlighting", "title": "semanticHighlighting",
"properties": { "properties": {