diff --git a/README.md b/README.md index 5af9d615..1fe11fe2 100644 --- a/README.md +++ b/README.md @@ -275,6 +275,23 @@ If not found, we search for an `.editorconfig` file, otherwise fall back to the This feature can be disabled using `--no-editorconfig`. See [EditorConfig](https://editorconfig.org/) for more details. +The following EditorConfig properties are supported: + +| EditorConfig Property | Maps to | +| --------------------------------- | ---------------------------- | +| `end_of_line` | `line_endings` | +| `indent_style` | `indent_type` | +| `indent_size` | `indent_width` | +| `max_line_length` | `column_width` | +| `quote_type` | `quote_style` | +| `call_parentheses` | `call_parentheses` | +| `space_after_function_names` | `space_after_function_names` | +| `collapse_simple_statement` | `collapse_simple_statement` | +| `sort_requires` | `sort_requires.enabled` | +| `stylua_syntax` | `syntax` | +| `stylua_block_newline_gaps` | `block_newline_gaps` | +| `stylua_trailing_comment_spacing` | `trailing_comment_spacing` | + Use `--config-path ` to provide a custom path to the configuration. If the file provided is not found/malformed, StyLua will exit with an error. @@ -319,6 +336,7 @@ StyLua only offers the following options: | `call_parentheses` | `Always` | Whether parentheses should be applied on function calls with a single string/table argument. Possible options: `Always`, `NoSingleString`, `NoSingleTable`, `None`, `Input`. `Always` applies parentheses in all cases. `NoSingleString` omits parentheses on calls with a single string argument. Similarly, `NoSingleTable` omits parentheses on calls with a single table argument. `None` omits parentheses in both cases. Note: parentheses are still kept in situations where removal can lead to obscurity (e.g. `foo "bar".setup -> foo("bar").setup`, since the index is on the call result, not the string). `Input` removes all automation and preserves parentheses only if they were present in input code: consistency is not enforced. | | `space_after_function_names` | `Never` | Specify whether to add a space between the function name and parentheses. Possible options: `Never`, `Definitions`, `Calls`, or `Always` | | `block_newline_gaps` | `Never` | Specify whether to preserve leading and trailing newline gaps for blocks. Possible options: `Never`, `Preserve` | +| `trailing_comment_spacing` | `Compress` | Specify whether to preserve the original spacing before trailing inline comments. Possible options: `Compress` (always use a single space), `Preserve` (keep original spacing) | | `collapse_simple_statement` | `Never` | Specify whether to collapse simple statements. Possible options: `Never`, `FunctionOnly`, `ConditionalOnly`, or `Always` | Default `stylua.toml`, note you do not need to explicitly specify each option if you want to use the defaults: @@ -334,6 +352,7 @@ call_parentheses = "Always" collapse_simple_statement = "Never" space_after_function_names = "Never" block_newline_gaps = "Never" +trailing_comment_spacing = "Compress" [sort_requires] enabled = false diff --git a/src/cli/config.rs b/src/cli/config.rs index 4b8591a2..4e4483b3 100644 --- a/src/cli/config.rs +++ b/src/cli/config.rs @@ -292,6 +292,9 @@ fn load_overrides(config: Config, opt: &Opt) -> Config { if let Some(preserve_block_newline_gaps) = opt.format_opts.preserve_block_newline_gaps { new_config.block_newline_gaps = preserve_block_newline_gaps.into(); }; + if let Some(trailing_comment_spacing) = opt.format_opts.trailing_comment_spacing { + new_config.trailing_comment_spacing = trailing_comment_spacing.into(); + }; if opt.format_opts.sort_requires { new_config.sort_requires = SortRequiresConfig { enabled: true } } diff --git a/src/cli/opt.rs b/src/cli/opt.rs index b9d8499b..59ba2284 100644 --- a/src/cli/opt.rs +++ b/src/cli/opt.rs @@ -2,7 +2,7 @@ use clap::{ArgEnum, StructOpt}; use std::path::PathBuf; use stylua_lib::{ BlockNewlineGaps, CallParenType, CollapseSimpleStatement, IndentType, LineEndings, LuaVersion, - QuoteStyle, SpaceAfterFunctionNames, + QuoteStyle, SpaceAfterFunctionNames, TrailingCommentSpacing, }; lazy_static::lazy_static! { @@ -202,6 +202,9 @@ pub struct FormatOpts { pub sort_requires: bool, #[structopt(long, arg_enum, ignore_case = true)] pub space_after_function_names: Option, + /// Specify whether to preserve spacing before trailing comments. + #[structopt(long, arg_enum, ignore_case = true)] + pub trailing_comment_spacing: Option, } // Convert [`stylua_lib::Config`] enums into clap-friendly enums @@ -295,6 +298,11 @@ convert_enum!(SpaceAfterFunctionNames, ArgSpaceAfterFunctionNames, { Always, }); +convert_enum!(TrailingCommentSpacing, ArgTrailingCommentSpacing, { + Compress, + Preserve, +}); + #[cfg(test)] mod tests { use super::Opt; diff --git a/src/editorconfig.rs b/src/editorconfig.rs index 1dfb4fc8..184231dd 100644 --- a/src/editorconfig.rs +++ b/src/editorconfig.rs @@ -1,6 +1,6 @@ use crate::{ BlockNewlineGaps, CallParenType, CollapseSimpleStatement, Config, IndentType, LineEndings, - LuaVersion, QuoteStyle, SortRequiresConfig, SpaceAfterFunctionNames, + LuaVersion, QuoteStyle, SortRequiresConfig, SpaceAfterFunctionNames, TrailingCommentSpacing, }; use ec4rs::{ properties_of, @@ -106,6 +106,12 @@ property_choice! { (Preserve, "preserve") } +property_choice! { + StyluaTrailingCommentSpacingChoice, "stylua_trailing_comment_spacing"; + (Compress, "compress"), + (Preserve, "preserve") +} + // Override StyLua config with EditorConfig properties fn load(mut config: Config, properties: &Properties) -> Config { if let Ok(end_of_line) = properties.get::() { @@ -202,6 +208,12 @@ fn load(mut config: Config, properties: &Properties) -> Config { StyluaBlockNewlineGapsChoice::Preserve => BlockNewlineGaps::Preserve, }; } + if let Ok(trailing_comment_spacing) = properties.get::() { + config.trailing_comment_spacing = match trailing_comment_spacing { + StyluaTrailingCommentSpacingChoice::Compress => TrailingCommentSpacing::Compress, + StyluaTrailingCommentSpacingChoice::Preserve => TrailingCommentSpacing::Preserve, + }; + } config } diff --git a/src/formatters/general.rs b/src/formatters/general.rs index ba57d1e2..b3283dc4 100644 --- a/src/formatters/general.rs +++ b/src/formatters/general.rs @@ -12,7 +12,7 @@ use crate::{ }, }, shape::Shape, - QuoteStyle, + QuoteStyle, TrailingCommentSpacing, }; use full_moon::node::Node; use full_moon::tokenizer::{StringLiteralQuoteType, Token, TokenKind, TokenReference, TokenType}; @@ -236,8 +236,10 @@ pub fn format_token( trailing_trivia = Some(vec![create_newline_trivia(ctx)]); } FormatTokenType::TrailingTrivia => { - // Add a space before the comment - leading_trivia = Some(vec![Token::new(TokenType::spaces(1))]); + // Add a space before the comment (unless preserving original spacing) + if ctx.config().trailing_comment_spacing == TrailingCommentSpacing::Compress { + leading_trivia = Some(vec![Token::new(TokenType::spaces(1))]); + } } _ => (), } @@ -308,12 +310,31 @@ fn load_token_trivia( } } FormatTokenType::TrailingTrivia => { - // If the next trivia is a MultiLineComment, and this whitespace is just spacing, then we - // will preserve a single space - if let Some(next_trivia) = trivia_iter.peek() { - if let TokenType::MultiLineComment { .. } = next_trivia.token_type() { - if !characters.contains('\n') { - token_trivia.push(Token::new(TokenType::spaces(1))) + // If the next trivia is a comment, preserve original spacing if configured + if ctx.config().trailing_comment_spacing == TrailingCommentSpacing::Preserve + { + if let Some(next_trivia) = trivia_iter.peek() { + match next_trivia.token_type() { + TokenType::SingleLineComment { .. } + | TokenType::MultiLineComment { .. } => { + if !characters.contains('\n') { + token_trivia.push(Token::new(TokenType::Whitespace { + characters: characters.to_owned(), + })); + } + } + _ => (), + } + } + } else { + // If the next trivia is a MultiLineComment, and this whitespace is just spacing, then we + // will preserve a single space + if let Some(next_trivia) = trivia_iter.peek() { + if let TokenType::MultiLineComment { .. } = next_trivia.token_type() + { + if !characters.contains('\n') { + token_trivia.push(Token::new(TokenType::spaces(1))) + } } } } diff --git a/src/lib.rs b/src/lib.rs index 7ca7a77f..2e67ff54 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -166,6 +166,19 @@ pub enum BlockNewlineGaps { Preserve, } +/// How to handle spacing before trailing inline comments. +#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Deserialize)] +#[cfg_attr(all(target_arch = "wasm32", feature = "wasm-bindgen"), wasm_bindgen)] +#[cfg_attr(feature = "serialize", derive(serde::Serialize))] +#[cfg_attr(feature = "fromstr", derive(strum::EnumString))] +pub enum TrailingCommentSpacing { + /// Always use a single space before trailing comments + #[default] + Compress, + /// Preserve the original spacing before trailing comments + Preserve, +} + /// An optional formatting range. /// If provided, only content within these boundaries (inclusive) will be formatted. /// Both boundaries are optional, and are given as byte offsets from the beginning of the file. @@ -279,6 +292,10 @@ pub struct Config { /// * if space_after_function_names is set to [`SpaceAfterFunctionNames::Calls`] a space is used only for calls. /// * if space_after_function_names is set to [`SpaceAfterFunctionNames::Always`] a space is used for both definitions and calls. pub space_after_function_names: SpaceAfterFunctionNames, + /// How to handle spacing before trailing inline comments. + /// * if set to [`TrailingCommentSpacing::Compress`] a single space is always used before trailing comments. + /// * if set to [`TrailingCommentSpacing::Preserve`] the original spacing before trailing comments is preserved. + pub trailing_comment_spacing: TrailingCommentSpacing, } #[cfg_attr(all(target_arch = "wasm32", feature = "wasm-bindgen"), wasm_bindgen)] @@ -305,6 +322,7 @@ impl Default for Config { sort_requires: SortRequiresConfig::default(), space_after_function_names: SpaceAfterFunctionNames::default(), block_newline_gaps: BlockNewlineGaps::default(), + trailing_comment_spacing: TrailingCommentSpacing::default(), } } } diff --git a/tests/inputs-preserve-trailing-comment-spacing/aligned-comments.lua b/tests/inputs-preserve-trailing-comment-spacing/aligned-comments.lua new file mode 100644 index 00000000..341c94e1 --- /dev/null +++ b/tests/inputs-preserve-trailing-comment-spacing/aligned-comments.lua @@ -0,0 +1,3 @@ +local x = 1 -- x value +local y = 2 -- y value +local longname = 3 -- long name diff --git a/tests/inputs-preserve-trailing-comment-spacing/varying-spacing.lua b/tests/inputs-preserve-trailing-comment-spacing/varying-spacing.lua new file mode 100644 index 00000000..825c6eac --- /dev/null +++ b/tests/inputs-preserve-trailing-comment-spacing/varying-spacing.lua @@ -0,0 +1,3 @@ +local a = 1 -- single space +local b = 2 -- two spaces +local c = 3 -- four spaces diff --git a/tests/snapshots/tests__preserve_trailing_comment_spacing@aligned-comments.lua.snap b/tests/snapshots/tests__preserve_trailing_comment_spacing@aligned-comments.lua.snap new file mode 100644 index 00000000..44404059 --- /dev/null +++ b/tests/snapshots/tests__preserve_trailing_comment_spacing@aligned-comments.lua.snap @@ -0,0 +1,10 @@ +--- +source: tests/tests.rs +assertion_line: 140 +expression: "format_code(&contents, Config\n{\n trailing_comment_spacing: TrailingCommentSpacing::Preserve,\n ..Config::default()\n}, None, OutputVerification::None).unwrap()" +input_file: tests/inputs-preserve-trailing-comment-spacing/aligned-comments.lua +--- +local x = 1 -- x value +local y = 2 -- y value +local longname = 3 -- long name + diff --git a/tests/snapshots/tests__preserve_trailing_comment_spacing@varying-spacing.lua.snap b/tests/snapshots/tests__preserve_trailing_comment_spacing@varying-spacing.lua.snap new file mode 100644 index 00000000..02942eb4 --- /dev/null +++ b/tests/snapshots/tests__preserve_trailing_comment_spacing@varying-spacing.lua.snap @@ -0,0 +1,10 @@ +--- +source: tests/tests.rs +assertion_line: 140 +expression: "format_code(&contents, Config\n{\n trailing_comment_spacing: TrailingCommentSpacing::Preserve,\n ..Config::default()\n}, None, OutputVerification::None).unwrap()" +input_file: tests/inputs-preserve-trailing-comment-spacing/varying-spacing.lua +--- +local a = 1 -- single space +local b = 2 -- two spaces +local c = 3 -- four spaces + diff --git a/tests/tests.rs b/tests/tests.rs index af513e38..6e0b3d3f 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -1,6 +1,6 @@ use stylua_lib::{ format_code, BlockNewlineGaps, CollapseSimpleStatement, Config, LuaVersion, OutputVerification, - SortRequiresConfig, + SortRequiresConfig, TrailingCommentSpacing, }; fn format(input: &str, syntax: LuaVersion) -> String { @@ -133,6 +133,23 @@ fn test_preserve_block_newline_gaps() { }) } +#[test] +fn test_preserve_trailing_comment_spacing() { + insta::glob!("inputs-preserve-trailing-comment-spacing/*.lua", |path| { + let contents = std::fs::read_to_string(path).unwrap(); + insta::assert_snapshot!(format_code( + &contents, + Config { + trailing_comment_spacing: TrailingCommentSpacing::Preserve, + ..Config::default() + }, + None, + OutputVerification::None + ) + .unwrap()); + }) +} + // Collapse simple statement for goto #[test] #[cfg(feature = "lua52")]