From 5b57a2bbc467780814da00f3500369bbbb377bbc Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 25 Jul 2025 15:24:19 -0700 Subject: [PATCH 1/3] Add `doc_comment_code_block_small_heuristics` This allows overriding `use_small_heuristics` in doc code. This is particularly useful for code that wants to use `use_small_heuristics = "Max"` internally but present doctests and examples using `use_small_heuristics = "Default"`. --- Configurations.md | 8 ++++++++ src/comment.rs | 8 ++++++++ src/config/mod.rs | 5 +++++ src/config/options.rs | 26 ++++++++++++++++++++++++++ 4 files changed, 47 insertions(+) diff --git a/Configurations.md b/Configurations.md index fce37eecac3..e0e4c87b2c2 100644 --- a/Configurations.md +++ b/Configurations.md @@ -1051,6 +1051,14 @@ Max width for code snippets included in doc comments. Only used if [`format_code - **Possible values**: any positive integer that is less than or equal to the value specified for [`max_width`](#max_width) - **Stable**: No (tracking issue: [#5359](https://github.com/rust-lang/rustfmt/issues/5359)) +## `doc_comment_code_block_small_heuristics` + +Value for [`use_small_heuristics`](#use_small_heuristics) for use in code blocks in doc comments. Only used if [`format_code_in_doc_comments`](#format_code_in_doc_comments) is true. + +- **Default value**: `"Default"` +- **Possible values**: `"Default"`, `"Off"`, `"Max"` +- **Stable**: No (tracking issue: [#FIXME](https://github.com/rust-lang/rustfmt/issues/FIXME)) + ## `format_generated_files` Format generated files. A file is considered generated if any of the first several lines contain a `@generated` comment marker. The number of lines to check is configured by `generated_marker_line_search_limit`. diff --git a/src/comment.rs b/src/comment.rs index 709031dda44..03e2f12c443 100644 --- a/src/comment.rs +++ b/src/comment.rs @@ -764,6 +764,14 @@ impl<'a> CommentRewrite<'a> { .doc_comment_code_block_width() .min(config.max_width()); config.set().max_width(comment_max_width); + if let Some(comment_use_small_heuristics) = config + .doc_comment_code_block_small_heuristics() + .to_heuristics() + { + config + .set() + .use_small_heuristics(comment_use_small_heuristics); + } if let Some(s) = crate::format_code_block(&self.code_block_buffer, &config, false) { diff --git a/src/config/mod.rs b/src/config/mod.rs index b03674b6b3c..2e6c80201a8 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -65,6 +65,9 @@ create_config! { doc comments."; doc_comment_code_block_width: DocCommentCodeBlockWidth, false, "Maximum width for code \ snippets in doc comments. No effect unless format_code_in_doc_comments = true"; + doc_comment_code_block_small_heuristics: DocUseSmallHeuristics, false, + "Value for use_small_heuristics for code blocks in doc comments. \ + No effect unless format_code_in_doc_comments = true"; comment_width: CommentWidth, false, "Maximum length of comments. No effect unless wrap_comments = true"; normalize_comments: NormalizeComments, false, "Convert /* */ comments to // comments where \ @@ -772,6 +775,7 @@ single_line_let_else_max_width = 50 wrap_comments = false format_code_in_doc_comments = false doc_comment_code_block_width = 100 +doc_comment_code_block_small_heuristics = "Inherit" comment_width = 80 normalize_comments = false normalize_doc_attributes = false @@ -864,6 +868,7 @@ single_line_let_else_max_width = 50 wrap_comments = false format_code_in_doc_comments = false doc_comment_code_block_width = 100 +doc_comment_code_block_small_heuristics = "Inherit" comment_width = 80 normalize_comments = false normalize_doc_attributes = false diff --git a/src/config/options.rs b/src/config/options.rs index 00f9c3f7ec1..3f970ed4bd7 100644 --- a/src/config/options.rs +++ b/src/config/options.rs @@ -95,6 +95,31 @@ pub enum Heuristics { Default, } +#[config_type] +/// Heuristic settings for doc comments. Same as `Heuristics`, but `Inherit` will inherit the value +/// from the top-level configuration. +pub enum DocCodeHeuristics { + /// Inherit from the top-level configuration + Inherit, + /// Turn off any heuristics + Off, + /// Turn on max heuristics + Max, + /// Use scaled values based on the value of `max_width` + Default, +} + +impl DocCodeHeuristics { + pub fn to_heuristics(self) -> Option { + match self { + DocCodeHeuristics::Inherit => None, + DocCodeHeuristics::Off => Some(Heuristics::Off), + DocCodeHeuristics::Max => Some(Heuristics::Max), + DocCodeHeuristics::Default => Some(Heuristics::Default), + } + } +} + impl Density { pub fn to_list_tactic(self, len: usize) -> ListTactic { match self { @@ -620,6 +645,7 @@ config_option_with_style_edition_default!( WrapComments, bool, _ => false; FormatCodeInDocComments, bool, _ => false; DocCommentCodeBlockWidth, usize, _ => 100; + DocUseSmallHeuristics, DocCodeHeuristics, _ => DocCodeHeuristics::Inherit; CommentWidth, usize, _ => 80; NormalizeComments, bool, _ => false; NormalizeDocAttributes, bool, _ => false; From a0dc0420a6f4d3b6a01507850a3c244750f8b583 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 25 Jul 2025 15:35:39 -0700 Subject: [PATCH 2/3] Add test for `doc_comment_code_block_small_heuristics` This test is based on the `use_small_heuristics` tests. It tests that the code *outside* the doc comment gets formatted using `Max`, while the code inside doc comments gets formatted using `Default`. --- .../max-to-default.rs | 68 ++++++++++++++++++ .../max-to-default.rs | 71 +++++++++++++++++++ 2 files changed, 139 insertions(+) create mode 100644 tests/source/configs/doc_comment_code_block_small_heuristics/max-to-default.rs create mode 100644 tests/target/configs/doc_comment_code_block_small_heuristics/max-to-default.rs diff --git a/tests/source/configs/doc_comment_code_block_small_heuristics/max-to-default.rs b/tests/source/configs/doc_comment_code_block_small_heuristics/max-to-default.rs new file mode 100644 index 00000000000..b9aa3211aaf --- /dev/null +++ b/tests/source/configs/doc_comment_code_block_small_heuristics/max-to-default.rs @@ -0,0 +1,68 @@ +// rustfmt-format_code_in_doc_comments: true +// rustfmt-use_small_heuristics: Max +// rustfmt-doc_comment_code_block_small_heuristics: Default + +/// Start of a doc comment. +/// +/// ``` +/// enum Lorem { +/// Ipsum, +/// Dolor(bool), +/// Sit { amet: Consectetur, adipiscing: Elit }, +/// } +/// +/// fn main() { +/// lorem("lorem", "ipsum", "dolor", "sit", "amet", "consectetur", "adipiscing"); +/// +/// let lorem = Lorem { ipsum: dolor, sit: amet }; +/// +/// let lorem = if ipsum { dolor } else { sit }; +/// } +/// +/// fn format_let_else() { +/// let Some(a) = opt else {}; +/// +/// let Some(b) = opt else { return }; +/// +/// let Some(c) = opt else { return }; +/// +/// let Some(d) = some_very_very_very_very_long_name else { return }; +/// } +/// ``` +/// +/// End of a doc comment. +struct S; + +enum Lorem { + Ipsum, + Dolor(bool), + Sit { + amet: Consectetur, + adipiscing: Elit, + }, +} + +fn main() { + lorem("lorem", "ipsum", "dolor", "sit", "amet", "consectetur", "adipiscing"); + + let lorem = Lorem { + ipsum: dolor, + sit: amet, + }; + + let lorem = if ipsum { + dolor + } else { + sit + }; +} + +fn format_let_else() { + let Some(a) = opt else {}; + + let Some(b) = opt else { return }; + + let Some(c) = opt else { return }; + + let Some(d) = some_very_very_very_very_long_name else { return }; +} diff --git a/tests/target/configs/doc_comment_code_block_small_heuristics/max-to-default.rs b/tests/target/configs/doc_comment_code_block_small_heuristics/max-to-default.rs new file mode 100644 index 00000000000..b18878ce8e8 --- /dev/null +++ b/tests/target/configs/doc_comment_code_block_small_heuristics/max-to-default.rs @@ -0,0 +1,71 @@ +// rustfmt-format_code_in_doc_comments: true +// rustfmt-use_small_heuristics: Max +// rustfmt-doc_comment_code_block_small_heuristics: Default + +/// Start of a doc comment. +/// +/// ``` +/// enum Lorem { +/// Ipsum, +/// Dolor(bool), +/// Sit { amet: Consectetur, adipiscing: Elit }, +/// } +/// +/// fn main() { +/// lorem( +/// "lorem", +/// "ipsum", +/// "dolor", +/// "sit", +/// "amet", +/// "consectetur", +/// "adipiscing", +/// ); +/// +/// let lorem = Lorem { +/// ipsum: dolor, +/// sit: amet, +/// }; +/// +/// let lorem = if ipsum { dolor } else { sit }; +/// } +/// +/// fn format_let_else() { +/// let Some(a) = opt else {}; +/// +/// let Some(b) = opt else { return }; +/// +/// let Some(c) = opt else { return }; +/// +/// let Some(d) = some_very_very_very_very_long_name else { +/// return; +/// }; +/// } +/// ``` +/// +/// End of a doc comment. +struct S; + +enum Lorem { + Ipsum, + Dolor(bool), + Sit { amet: Consectetur, adipiscing: Elit }, +} + +fn main() { + lorem("lorem", "ipsum", "dolor", "sit", "amet", "consectetur", "adipiscing"); + + let lorem = Lorem { ipsum: dolor, sit: amet }; + + let lorem = if ipsum { dolor } else { sit }; +} + +fn format_let_else() { + let Some(a) = opt else {}; + + let Some(b) = opt else { return }; + + let Some(c) = opt else { return }; + + let Some(d) = some_very_very_very_very_long_name else { return }; +} From cc8b67446415c26b189a835b8f34b847cc0149cb Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Tue, 5 Aug 2025 23:06:08 -0700 Subject: [PATCH 3/3] Add another test for `doc_comment_code_block_small_heuristics` This test goes from Default to Max heuristics. --- .../default-to-max.rs | 71 ++++++++++++++++++ .../default-to-max.rs | 73 +++++++++++++++++++ 2 files changed, 144 insertions(+) create mode 100644 tests/source/configs/doc_comment_code_block_small_heuristics/default-to-max.rs create mode 100644 tests/target/configs/doc_comment_code_block_small_heuristics/default-to-max.rs diff --git a/tests/source/configs/doc_comment_code_block_small_heuristics/default-to-max.rs b/tests/source/configs/doc_comment_code_block_small_heuristics/default-to-max.rs new file mode 100644 index 00000000000..dcaa89367f8 --- /dev/null +++ b/tests/source/configs/doc_comment_code_block_small_heuristics/default-to-max.rs @@ -0,0 +1,71 @@ +// rustfmt-format_code_in_doc_comments: true +// rustfmt-use_small_heuristics: Default +// rustfmt-doc_comment_code_block_small_heuristics: Max + +/// Start of a doc comment. +/// +/// ``` +/// enum Lorem { +/// Ipsum, +/// Dolor(bool), +/// Sit { amet: Consectetur, adipiscing: Elit }, +/// } +/// +/// fn main() { +/// lorem( +/// "lorem", +/// "ipsum", +/// "dolor", +/// "sit", +/// "amet", +/// "consectetur", +/// "adipiscing", +/// ); +/// +/// let lorem = Lorem { +/// ipsum: dolor, +/// sit: amet, +/// }; +/// +/// let lorem = if ipsum { dolor } else { sit }; +/// } +/// +/// fn format_let_else() { +/// let Some(a) = opt else {}; +/// +/// let Some(b) = opt else { return }; +/// +/// let Some(c) = opt else { return }; +/// +/// let Some(d) = some_very_very_very_very_long_name else { +/// return; +/// }; +/// } +/// ``` +/// +/// End of a doc comment. +struct S; + +enum Lorem { + Ipsum, + Dolor(bool), + Sit { amet: Consectetur, adipiscing: Elit }, +} + +fn main() { + lorem("lorem", "ipsum", "dolor", "sit", "amet", "consectetur", "adipiscing"); + + let lorem = Lorem { ipsum: dolor, sit: amet }; + + let lorem = if ipsum { dolor } else { sit }; +} + +fn format_let_else() { + let Some(a) = opt else {}; + + let Some(b) = opt else { return }; + + let Some(c) = opt else { return }; + + let Some(d) = some_very_very_very_very_long_name else { return }; +} diff --git a/tests/target/configs/doc_comment_code_block_small_heuristics/default-to-max.rs b/tests/target/configs/doc_comment_code_block_small_heuristics/default-to-max.rs new file mode 100644 index 00000000000..a4ec39c63c4 --- /dev/null +++ b/tests/target/configs/doc_comment_code_block_small_heuristics/default-to-max.rs @@ -0,0 +1,73 @@ +// rustfmt-format_code_in_doc_comments: true +// rustfmt-use_small_heuristics: Default +// rustfmt-doc_comment_code_block_small_heuristics: Max + +/// Start of a doc comment. +/// +/// ``` +/// enum Lorem { +/// Ipsum, +/// Dolor(bool), +/// Sit { amet: Consectetur, adipiscing: Elit }, +/// } +/// +/// fn main() { +/// lorem("lorem", "ipsum", "dolor", "sit", "amet", "consectetur", "adipiscing"); +/// +/// let lorem = Lorem { ipsum: dolor, sit: amet }; +/// +/// let lorem = if ipsum { dolor } else { sit }; +/// } +/// +/// fn format_let_else() { +/// let Some(a) = opt else {}; +/// +/// let Some(b) = opt else { return }; +/// +/// let Some(c) = opt else { return }; +/// +/// let Some(d) = some_very_very_very_very_long_name else { +/// return; +/// }; +/// } +/// ``` +/// +/// End of a doc comment. +struct S; + +enum Lorem { + Ipsum, + Dolor(bool), + Sit { amet: Consectetur, adipiscing: Elit }, +} + +fn main() { + lorem( + "lorem", + "ipsum", + "dolor", + "sit", + "amet", + "consectetur", + "adipiscing", + ); + + let lorem = Lorem { + ipsum: dolor, + sit: amet, + }; + + let lorem = if ipsum { dolor } else { sit }; +} + +fn format_let_else() { + let Some(a) = opt else {}; + + let Some(b) = opt else { return }; + + let Some(c) = opt else { return }; + + let Some(d) = some_very_very_very_very_long_name else { + return; + }; +}