diff --git a/crates/ruff_dev/src/generate_options.rs b/crates/ruff_dev/src/generate_options.rs index 11cf7c8423f510..ea135d5ba44de8 100644 --- a/crates/ruff_dev/src/generate_options.rs +++ b/crates/ruff_dev/src/generate_options.rs @@ -16,6 +16,12 @@ pub(crate) fn generate() -> String { fn generate_set(output: &mut String, set: &Set) { writeln!(output, "### {title}\n", title = set.title()).unwrap(); + if let Some(documentation) = set.metadata().documentation() { + output.push_str(documentation); + output.push('\n'); + output.push('\n'); + } + let mut visitor = CollectOptionsVisitor::default(); set.metadata().record(&mut visitor); diff --git a/crates/ruff_macros/src/config.rs b/crates/ruff_macros/src/config.rs index 5cd13ea7cfd8ac..5e48b2f5bfd62a 100644 --- a/crates/ruff_macros/src/config.rs +++ b/crates/ruff_macros/src/config.rs @@ -10,7 +10,12 @@ use syn::{ }; pub(crate) fn derive_impl(input: DeriveInput) -> syn::Result { - let DeriveInput { ident, data, .. } = input; + let DeriveInput { + ident, + data, + attrs: struct_attributes, + .. + } = input; match data { Data::Struct(DataStruct { @@ -50,12 +55,39 @@ pub(crate) fn derive_impl(input: DeriveInput) -> syn::Result = struct_attributes + .iter() + .filter(|attr| attr.path().is_ident("doc")) + .collect(); + + // Convert the list of `doc` attributes into a single string. + let doc = dedent( + &docs + .into_iter() + .map(parse_doc) + .collect::>>()? + .join("\n"), + ) + .trim_matches('\n') + .to_string(); + + let documentation = if doc.is_empty() { + None + } else { + Some(quote!( + fn documentation() -> Option<&'static str> { + Some(&#doc) + } + )) + }; + Ok(quote! { impl crate::options_base::OptionsMetadata for #ident { fn record(visit: &mut dyn crate::options_base::Visit) { #(#output);* } + + #documentation } }) } diff --git a/crates/ruff_workspace/src/options.rs b/crates/ruff_workspace/src/options.rs index 33069bbc90fff9..8de33d824e85d8 100644 --- a/crates/ruff_workspace/src/options.rs +++ b/crates/ruff_workspace/src/options.rs @@ -2412,8 +2412,15 @@ impl OptionsMetadata for FormatOrOutputFormat { fn record(visit: &mut dyn Visit) { FormatOptions::record(visit); } + + fn documentation() -> Option<&'static str> { + FormatOptions::documentation() + } } +/// Experimental: Configures how `ruff format` formats your code. +/// +/// Please provide feedback in [this discussion](https://github.com/astral-sh/ruff/discussions/7310). #[derive( Debug, PartialEq, Eq, Default, Serialize, Deserialize, ConfigurationOptions, CombineOptions, )] diff --git a/crates/ruff_workspace/src/options_base.rs b/crates/ruff_workspace/src/options_base.rs index 60269a72ca0ed8..8bf095598976ea 100644 --- a/crates/ruff_workspace/src/options_base.rs +++ b/crates/ruff_workspace/src/options_base.rs @@ -16,6 +16,10 @@ pub trait OptionsMetadata { /// Visits the options metadata of this object by calling `visit` for each option. fn record(visit: &mut dyn Visit); + fn documentation() -> Option<&'static str> { + None + } + /// Returns the extracted metadata. fn metadata() -> OptionSet where @@ -51,6 +55,7 @@ impl Display for OptionEntry { #[derive(Copy, Clone, Eq, PartialEq)] pub struct OptionSet { record: fn(&mut dyn Visit), + doc: fn() -> Option<&'static str>, } impl OptionSet { @@ -58,7 +63,10 @@ impl OptionSet { where T: OptionsMetadata + 'static, { - Self { record: T::record } + Self { + record: T::record, + doc: T::documentation, + } } /// Visits the options in this set by calling `visit` for each option. @@ -67,6 +75,11 @@ impl OptionSet { record(visit); } + pub fn documentation(&self) -> Option<&'static str> { + let documentation = self.doc; + documentation() + } + /// Returns `true` if this set has an option that resolves to `name`. /// /// The name can be separated by `.` to find a nested option.