From 682b785d60d19ffd4156553a3cc12f587a0c2e7e Mon Sep 17 00:00:00 2001 From: Caleb Maclennan Date: Sat, 23 Dec 2023 15:48:01 +0300 Subject: [PATCH 1/5] Add option to define space after function definitions and calls --- README.md | 2 ++ src/cli/opt.rs | 14 +++++++++++++- src/editorconfig.rs | 26 +++++++++++++++++++++++++- src/formatters/functions.rs | 1 + src/lib.rs | 24 ++++++++++++++++++++++++ 5 files changed, 65 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d4207e3a..9c4a4a76 100644 --- a/README.md +++ b/README.md @@ -259,6 +259,7 @@ StyLua only offers the following options: | `indent_width` | `4` | Character size of single indentation. If `indent_type` is set to `Tabs`, this option is used as a heuristic to determine column width only. | | `quote_style` | `AutoPreferDouble` | Quote style for string literals. Possible options: `AutoPreferDouble`, `AutoPreferSingle`, `ForceDouble`, `ForceSingle`. `AutoPrefer` styles will prefer the specified quote style, but fall back to the alternative if it has fewer string escapes. `Force` styles always use the specified style regardless of escapes. | | `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_functions` | `Never` | Specify whether to add a space between the function name and parentheses. Possible options: `Never`, `Definitions`, `Calls`, or `Always` | | `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: @@ -271,6 +272,7 @@ indent_width = 4 quote_style = "AutoPreferDouble" call_parentheses = "Always" collapse_simple_statement = "Never" +space_after_functions = "Never" [sort_requires] enabled = false diff --git a/src/cli/opt.rs b/src/cli/opt.rs index 6a75f470..10f0c699 100644 --- a/src/cli/opt.rs +++ b/src/cli/opt.rs @@ -1,6 +1,9 @@ use clap::{ArgEnum, StructOpt}; use std::path::PathBuf; -use stylua_lib::{CallParenType, CollapseSimpleStatement, IndentType, LineEndings, QuoteStyle}; +use stylua_lib::{ + CallParenType, CollapseSimpleStatement, IndentType, LineEndings, QuoteStyle, + SpaceAfterFunctions, +}; lazy_static::lazy_static! { static ref NUM_CPUS: String = num_cpus::get().to_string(); @@ -183,6 +186,8 @@ pub struct FormatOpts { /// Enable requires sorting #[structopt(long)] pub sort_requires: bool, + #[structopt(long, arg_enum, ignore_case = true)] + pub space_after_functions: Option, } // Convert [`stylua_lib::Config`] enums into clap-friendly enums @@ -250,6 +255,13 @@ convert_enum!(CollapseSimpleStatement, ArgCollapseSimpleStatement, { Always, }); +convert_enum!(SpaceAfterFunctions, ArgSpaceAfterFunctions, { + Never, + Definitions, + Calls, + Always, +}); + #[cfg(test)] mod tests { use super::Opt; diff --git a/src/editorconfig.rs b/src/editorconfig.rs index 32ea6cfd..c215d289 100644 --- a/src/editorconfig.rs +++ b/src/editorconfig.rs @@ -1,6 +1,6 @@ use crate::{ CallParenType, CollapseSimpleStatement, Config, IndentType, LineEndings, QuoteStyle, - SortRequiresConfig, + SortRequiresConfig, SpaceAfterFunctions, }; use ec4rs::{ properties_of, @@ -65,6 +65,14 @@ property_choice! { (None, "none") } +property_choice! { + SpaceAfterFunctionsChoice, "space_after_functions"; + (Always, "always"), + (Definitions, "definitions"), + (Calls, "calls"), + (Never, "never") +} + property_choice! { CollapseSimpleStatementChoice, "collapse_simple_statement"; (Never, "never"), @@ -128,6 +136,22 @@ fn load(mut config: Config, properties: &Properties) -> Config { CallParenthesesChoice::None => config.call_parentheses = CallParenType::None, } } + if let Ok(space_after_functions) = properties.get::() { + match space_after_functions { + SpaceAfterFunctionsChoice::Always => { + config.space_after_functions = SpaceAfterFunctions::Always + } + SpaceAfterFunctionsChoice::Definitions => { + config.space_after_functions = SpaceAfterFunctions::Definitions + } + SpaceAfterFunctionsChoice::Calls => { + config.space_after_functions = SpaceAfterFunctions::Calls + } + SpaceAfterFunctionsChoice::Never => { + config.space_after_functions = SpaceAfterFunctions::Never + } + } + } if let Ok(collapse_simple_statement) = properties.get::() { match collapse_simple_statement { CollapseSimpleStatementChoice::Never => { diff --git a/src/formatters/functions.rs b/src/formatters/functions.rs index 0ceb814d..5e3c2604 100644 --- a/src/formatters/functions.rs +++ b/src/formatters/functions.rs @@ -31,6 +31,7 @@ use crate::{ }, shape::Shape, CallParenType, + SpaceAfterFunctions, }; /// Formats an Anonymous Function diff --git a/src/lib.rs b/src/lib.rs index 75b12487..d84dd7db 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -139,6 +139,23 @@ impl SortRequiresConfig { } } +/// When to use spaces after function names +#[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 SpaceAfterFunctions { + /// Never use spaces after function nomes. + #[default] + Never, + /// Use spaces after function names only for function definitions. + Definitions, + /// Use spaces after function names only for function calls. + Calls, + /// Use spaces after function names in definitions and calls. + Always, +} + /// The configuration to use when formatting. #[derive(Copy, Clone, Debug, Deserialize)] #[serde(default, deny_unknown_fields)] @@ -178,6 +195,12 @@ pub struct Config { pub collapse_simple_statement: CollapseSimpleStatement, /// Configuration for the sort requires codemod pub sort_requires: SortRequiresConfig, + /// Whether we should include a space between the function name and arguments. + /// * if space_after_functions is set to [`SpaceAfterFunctions::Never`] a space is never used. + /// * if space_after_functions is set to [`SpaceAfterFunctions::Definitions`] a space is used only for definitions. + /// * if space_after_functions is set to [`SpaceAfterFunctions::Calls`] a space is used only for calls. + /// * if space_after_functions is set to [`SpaceAfterFunctions::Always`] a space is used for both definitions and calls. + pub space_after_functions: SpaceAfterFunctions, } #[cfg_attr(all(target_arch = "wasm32", feature = "wasm-bindgen"), wasm_bindgen)] @@ -346,6 +369,7 @@ impl Default for Config { call_parentheses: CallParenType::default(), collapse_simple_statement: CollapseSimpleStatement::default(), sort_requires: SortRequiresConfig::default(), + space_after_functions: SpaceAfterFunctions::default(), } } } From 3359ced0bba42261cc37319c3de7ac11c7dd3156 Mon Sep 17 00:00:00 2001 From: Caleb Maclennan Date: Sat, 23 Dec 2023 15:48:01 +0300 Subject: [PATCH 2/5] Add tests for new space after function name option --- src/editorconfig.rs | 35 +++++++ tests/test_spaces_after_functions.rs | 134 +++++++++++++++++++++++++++ 2 files changed, 169 insertions(+) create mode 100644 tests/test_spaces_after_functions.rs diff --git a/src/editorconfig.rs b/src/editorconfig.rs index c215d289..cdd2320a 100644 --- a/src/editorconfig.rs +++ b/src/editorconfig.rs @@ -333,6 +333,41 @@ mod tests { assert_eq!(config.call_parentheses, CallParenType::None); } + #[test] + fn test_space_after_functions_always() { + let mut properties = Properties::new(); + properties.insert_raw_for_key("space_after_functions", "Always"); + let config = Config::from(&properties); + assert_eq!(config.space_after_functions, SpaceAfterFunctions::Always); + } + + #[test] + fn test_space_after_functions_definitions() { + let mut properties = Properties::new(); + properties.insert_raw_for_key("space_after_functions", "Definitions"); + let config = Config::from(&properties); + assert_eq!( + config.space_after_functions, + SpaceAfterFunctions::Definitions + ); + } + + #[test] + fn test_space_after_functions_calls() { + let mut properties = Properties::new(); + properties.insert_raw_for_key("space_after_functions", "Calls"); + let config = Config::from(&properties); + assert_eq!(config.space_after_functions, SpaceAfterFunctions::Calls); + } + + #[test] + fn test_space_after_functions_never() { + let mut properties = Properties::new(); + properties.insert_raw_for_key("space_after_functions", "Never"); + let config = Config::from(&properties); + assert_eq!(config.space_after_functions, SpaceAfterFunctions::Never); + } + #[test] fn test_collapse_simple_statement_never() { let mut properties = Properties::new(); diff --git a/tests/test_spaces_after_functions.rs b/tests/test_spaces_after_functions.rs new file mode 100644 index 00000000..c332f3b5 --- /dev/null +++ b/tests/test_spaces_after_functions.rs @@ -0,0 +1,134 @@ +use stylua_lib::{format_code, Config, OutputVerification, SpaceAfterFunctions}; + +fn format(input: &str, space_after_functions: SpaceAfterFunctions) -> String { + format_code( + input, + Config { + space_after_functions, + ..Config::default() + }, + None, + OutputVerification::None, + ) + .unwrap() +} + +const STARTINGCODE: &str = r###" +local foo = function() end +local function bar () end +function baz() end +a = {} +function a:b () end +function a.c () end +function qiz () return function () end end +foo() +bar () +baz() +a:b () +a.c () +qiz()() +"###; + +#[test] +fn test_never_space_after_functions() { + insta::assert_snapshot!( + format(STARTINGCODE, + SpaceAfterFunctions::Never + ), + @r###" +local foo = function() end +local function bar() end +function baz() end +a = {} +function a:b() end +function a.c() end +function qiz() + return function() end +end +foo() +bar() +baz() +a:b() +a.c() +qiz()() + "### + ); +} + +#[test] +fn test_space_after_function_definitions() { + insta::assert_snapshot!( + format(STARTINGCODE, + SpaceAfterFunctions::Definitions + ), + @r###" +local foo = function () end +local function bar () end +function baz () end +a = {} +function a:b () end +function a.c () end +function qiz () + return function () end +end +foo() +bar() +baz() +a:b() +a.c() +qiz()() + "### + ); +} + +#[test] +fn test_space_after_function_calls() { + insta::assert_snapshot!( + format(STARTINGCODE, + SpaceAfterFunctions::Calls + ), + @r###" +local foo = function() end +local function bar() end +function baz() end +a = {} +function a:b() end +function a.c() end +function qiz() + return function() end +end +foo () +bar () +baz () +a:b () +a.c () +qiz () () + "### + ); +} + +#[test] +fn test_always_space_after_functions() { + insta::assert_snapshot!( + format(STARTINGCODE, + SpaceAfterFunctions::Always + ), + @r###" +local foo = function () end +local function bar () end +function baz () end +a = {} +function a:b () end +function a.c () end +function qiz () + return function () end +end +foo () +bar () +baz () +a:b () +a.c () +qiz () () + "### + ); +} From 6cef63c9dfa7ddf52e9ab16edf5abe3f6dbcea35 Mon Sep 17 00:00:00 2001 From: Caleb Maclennan Date: Wed, 29 May 2024 14:08:22 +0300 Subject: [PATCH 3/5] Implement formatting for new space after function name option --- src/cli/config.rs | 3 +++ src/context.rs | 24 +++++++++++++++++++++++- src/formatters/functions.rs | 35 +++++++++++++++++++++++------------ 3 files changed, 49 insertions(+), 13 deletions(-) diff --git a/src/cli/config.rs b/src/cli/config.rs index 1b7ae4af..ecdcb33c 100644 --- a/src/cli/config.rs +++ b/src/cli/config.rs @@ -174,6 +174,9 @@ pub fn load_overrides(config: Config, opt: &Opt) -> Config { if let Some(call_parentheses) = opt.format_opts.call_parentheses { new_config.call_parentheses = call_parentheses.into(); }; + if let Some(space_after_functions) = opt.format_opts.space_after_functions { + new_config.space_after_functions = space_after_functions.into(); + }; if let Some(collapse_simple_statement) = opt.format_opts.collapse_simple_statement { new_config.collapse_simple_statement = collapse_simple_statement.into(); } diff --git a/src/context.rs b/src/context.rs index d6d21314..d30a2725 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,6 +1,6 @@ use crate::{ shape::Shape, CallParenType, CollapseSimpleStatement, Config, IndentType, LineEndings, - Range as FormatRange, + Range as FormatRange, SpaceAfterFunctions, }; use full_moon::{ node::Node, @@ -181,6 +181,28 @@ pub fn create_plain_indent_trivia(ctx: &Context, indent_level: usize) -> Token { } } +/// Creates a new Token containing whitespace used after function declarations +pub fn create_function_definition_trivia(ctx: &Context) -> Token { + match ctx.config().space_after_functions { + SpaceAfterFunctions::Always | SpaceAfterFunctions::Definitions => { + Token::new(TokenType::spaces(1)) + } + SpaceAfterFunctions::Never | SpaceAfterFunctions::Calls => Token::new(TokenType::spaces(0)), + } +} + +/// Creates a new Token containing whitespace used after function calls +pub fn create_function_call_trivia(ctx: &Context) -> Token { + match ctx.config().space_after_functions { + SpaceAfterFunctions::Always | SpaceAfterFunctions::Calls => { + Token::new(TokenType::spaces(1)) + } + SpaceAfterFunctions::Never | SpaceAfterFunctions::Definitions => { + Token::new(TokenType::spaces(0)) + } + } +} + /// Creates a new Token containing new line whitespace, used for trivia pub fn create_newline_trivia(ctx: &Context) -> Token { Token::new(TokenType::Whitespace { diff --git a/src/formatters/functions.rs b/src/formatters/functions.rs index 5e3c2604..f3d7fb7c 100644 --- a/src/formatters/functions.rs +++ b/src/formatters/functions.rs @@ -10,7 +10,10 @@ use full_moon::tokenizer::{Token, TokenKind, TokenReference, TokenType}; #[cfg(feature = "luau")] use crate::formatters::luau::{format_generic_declaration, format_type_specifier}; use crate::{ - context::{create_indent_trivia, create_newline_trivia, Context}, + context::{ + create_function_call_trivia, create_function_definition_trivia, create_indent_trivia, + create_newline_trivia, Context, + }, fmt_symbol, formatters::{ block::{format_block, format_last_stmt_no_trivia}, @@ -31,7 +34,6 @@ use crate::{ }, shape::Shape, CallParenType, - SpaceAfterFunctions, }; /// Formats an Anonymous Function @@ -43,7 +45,9 @@ pub fn format_anonymous_function( shape: Shape, ) -> (TokenReference, FunctionBody) { const FUNCTION_LEN: usize = "function".len(); - let function_token = fmt_symbol!(ctx, function_token, "function", shape); + let function_definition_trivia = vec![create_function_definition_trivia(ctx)]; + let function_token = fmt_symbol!(ctx, function_token, "function", shape) + .update_trailing_trivia(FormatTriviaType::Append(function_definition_trivia)); let function_body = format_function_body(ctx, function_body, shape.add_width(FUNCTION_LEN)); (function_token, function_body) @@ -74,13 +78,14 @@ pub fn format_call( shape: Shape, call_next_node: FunctionCallNextNode, ) -> Call { + let function_call_trivia = vec![create_function_call_trivia(ctx)]; match call { - Call::AnonymousCall(function_args) => Call::AnonymousCall(format_function_args( - ctx, - function_args, - shape, - call_next_node, - )), + Call::AnonymousCall(function_args) => { + let formatted_function_args = + format_function_args(ctx, function_args, shape, call_next_node) + .update_leading_trivia(FormatTriviaType::Append(function_call_trivia)); + Call::AnonymousCall(formatted_function_args) + } Call::MethodCall(method_call) => { Call::MethodCall(format_method_call(ctx, method_call, shape, call_next_node)) } @@ -1151,6 +1156,7 @@ pub fn format_function_declaration( // Calculate trivia let leading_trivia = vec![create_indent_trivia(ctx, shape)]; let trailing_trivia = vec![create_newline_trivia(ctx)]; + let function_definition_trivia = vec![create_function_definition_trivia(ctx)]; let function_token = fmt_symbol!( ctx, @@ -1159,7 +1165,8 @@ pub fn format_function_declaration( shape ) .update_leading_trivia(FormatTriviaType::Append(leading_trivia)); - let formatted_function_name = format_function_name(ctx, function_declaration.name(), shape); + let formatted_function_name = format_function_name(ctx, function_declaration.name(), shape) + .update_trailing_trivia(FormatTriviaType::Append(function_definition_trivia)); let shape = shape + (9 + strip_trivia(&formatted_function_name).to_string().len()); // 9 = "function " let function_body = format_function_body(ctx, function_declaration.body(), shape) @@ -1179,11 +1186,13 @@ pub fn format_local_function( // Calculate trivia let leading_trivia = vec![create_indent_trivia(ctx, shape)]; let trailing_trivia = vec![create_newline_trivia(ctx)]; + let function_definition_trivia = vec![create_function_definition_trivia(ctx)]; let local_token = fmt_symbol!(ctx, local_function.local_token(), "local ", shape) .update_leading_trivia(FormatTriviaType::Append(leading_trivia)); let function_token = fmt_symbol!(ctx, local_function.function_token(), "function ", shape); - let formatted_name = format_token_reference(ctx, local_function.name(), shape); + let formatted_name = format_token_reference(ctx, local_function.name(), shape) + .update_trailing_trivia(FormatTriviaType::Append(function_definition_trivia)); let shape = shape + (6 + 9 + strip_trivia(&formatted_name).to_string().len()); // 6 = "local ", 9 = "function " let function_body = format_function_body(ctx, local_function.body(), shape) @@ -1202,12 +1211,14 @@ pub fn format_method_call( shape: Shape, call_next_node: FunctionCallNextNode, ) -> MethodCall { + let function_call_trivia = vec![create_function_call_trivia(ctx)]; let formatted_colon_token = format_token_reference(ctx, method_call.colon_token(), shape); let formatted_name = format_token_reference(ctx, method_call.name(), shape); let shape = shape + (formatted_colon_token.to_string().len() + formatted_name.to_string().len()); let formatted_function_args = - format_function_args(ctx, method_call.args(), shape, call_next_node); + format_function_args(ctx, method_call.args(), shape, call_next_node) + .update_leading_trivia(FormatTriviaType::Append(function_call_trivia)); MethodCall::new(formatted_name, formatted_function_args).with_colon_token(formatted_colon_token) } From 3bc340475684da38a78688387e30dc314c7df3cf Mon Sep 17 00:00:00 2001 From: JohnnyMorganz Date: Sat, 26 Oct 2024 13:08:29 -0500 Subject: [PATCH 4/5] Rename option to `space_after_function_names` --- README.md | 22 +++---- src/cli/config.rs | 4 +- src/cli/opt.rs | 6 +- src/context.rs | 16 ++--- src/editorconfig.rs | 59 +++++++++++-------- src/lib.rs | 16 ++--- ...rs => test_spaces_after_function_names.rs} | 18 +++--- 7 files changed, 76 insertions(+), 65 deletions(-) rename tests/{test_spaces_after_functions.rs => test_spaces_after_function_names.rs} (81%) diff --git a/README.md b/README.md index 9c4a4a76..90a3ef2c 100644 --- a/README.md +++ b/README.md @@ -251,16 +251,16 @@ If a project uses the default configuration of StyLua without a configuration fi StyLua only offers the following options: -| Option | Default | Description | -| --------------------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `column_width` | `120` | Approximate line length for printing. Used as a guide for line wrapping - this is not a hard requirement: lines may fall under or over the limit. | -| `line_endings` | `Unix` | Line endings type. Possible options: `Unix` (LF) or `Windows` (CRLF) | -| `indent_type` | `Tabs` | Indent type. Possible options: `Tabs` or `Spaces` | -| `indent_width` | `4` | Character size of single indentation. If `indent_type` is set to `Tabs`, this option is used as a heuristic to determine column width only. | -| `quote_style` | `AutoPreferDouble` | Quote style for string literals. Possible options: `AutoPreferDouble`, `AutoPreferSingle`, `ForceDouble`, `ForceSingle`. `AutoPrefer` styles will prefer the specified quote style, but fall back to the alternative if it has fewer string escapes. `Force` styles always use the specified style regardless of escapes. | -| `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_functions` | `Never` | Specify whether to add a space between the function name and parentheses. Possible options: `Never`, `Definitions`, `Calls`, or `Always` | -| `collapse_simple_statement` | `Never` | Specify whether to collapse simple statements. Possible options: `Never`, `FunctionOnly`, `ConditionalOnly`, or `Always` | +| Option | Default | Description | +| ---------------------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `column_width` | `120` | Approximate line length for printing. Used as a guide for line wrapping - this is not a hard requirement: lines may fall under or over the limit. | +| `line_endings` | `Unix` | Line endings type. Possible options: `Unix` (LF) or `Windows` (CRLF) | +| `indent_type` | `Tabs` | Indent type. Possible options: `Tabs` or `Spaces` | +| `indent_width` | `4` | Character size of single indentation. If `indent_type` is set to `Tabs`, this option is used as a heuristic to determine column width only. | +| `quote_style` | `AutoPreferDouble` | Quote style for string literals. Possible options: `AutoPreferDouble`, `AutoPreferSingle`, `ForceDouble`, `ForceSingle`. `AutoPrefer` styles will prefer the specified quote style, but fall back to the alternative if it has fewer string escapes. `Force` styles always use the specified style regardless of escapes. | +| `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` | +| `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: @@ -272,7 +272,7 @@ indent_width = 4 quote_style = "AutoPreferDouble" call_parentheses = "Always" collapse_simple_statement = "Never" -space_after_functions = "Never" +space_after_function_names = "Never" [sort_requires] enabled = false diff --git a/src/cli/config.rs b/src/cli/config.rs index ecdcb33c..c3fe9bb2 100644 --- a/src/cli/config.rs +++ b/src/cli/config.rs @@ -174,8 +174,8 @@ pub fn load_overrides(config: Config, opt: &Opt) -> Config { if let Some(call_parentheses) = opt.format_opts.call_parentheses { new_config.call_parentheses = call_parentheses.into(); }; - if let Some(space_after_functions) = opt.format_opts.space_after_functions { - new_config.space_after_functions = space_after_functions.into(); + if let Some(space_after_function_names) = opt.format_opts.space_after_function_names { + new_config.space_after_function_names = space_after_function_names.into(); }; if let Some(collapse_simple_statement) = opt.format_opts.collapse_simple_statement { new_config.collapse_simple_statement = collapse_simple_statement.into(); diff --git a/src/cli/opt.rs b/src/cli/opt.rs index 10f0c699..5ba37150 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::{ CallParenType, CollapseSimpleStatement, IndentType, LineEndings, QuoteStyle, - SpaceAfterFunctions, + SpaceAfterFunctionNames, }; lazy_static::lazy_static! { @@ -187,7 +187,7 @@ pub struct FormatOpts { #[structopt(long)] pub sort_requires: bool, #[structopt(long, arg_enum, ignore_case = true)] - pub space_after_functions: Option, + pub space_after_function_names: Option, } // Convert [`stylua_lib::Config`] enums into clap-friendly enums @@ -255,7 +255,7 @@ convert_enum!(CollapseSimpleStatement, ArgCollapseSimpleStatement, { Always, }); -convert_enum!(SpaceAfterFunctions, ArgSpaceAfterFunctions, { +convert_enum!(SpaceAfterFunctionNames, ArgSpaceAfterFunctionNames, { Never, Definitions, Calls, diff --git a/src/context.rs b/src/context.rs index d30a2725..ea2a1066 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,6 +1,6 @@ use crate::{ shape::Shape, CallParenType, CollapseSimpleStatement, Config, IndentType, LineEndings, - Range as FormatRange, SpaceAfterFunctions, + Range as FormatRange, SpaceAfterFunctionNames, }; use full_moon::{ node::Node, @@ -183,21 +183,23 @@ pub fn create_plain_indent_trivia(ctx: &Context, indent_level: usize) -> Token { /// Creates a new Token containing whitespace used after function declarations pub fn create_function_definition_trivia(ctx: &Context) -> Token { - match ctx.config().space_after_functions { - SpaceAfterFunctions::Always | SpaceAfterFunctions::Definitions => { + match ctx.config().space_after_function_names { + SpaceAfterFunctionNames::Always | SpaceAfterFunctionNames::Definitions => { Token::new(TokenType::spaces(1)) } - SpaceAfterFunctions::Never | SpaceAfterFunctions::Calls => Token::new(TokenType::spaces(0)), + SpaceAfterFunctionNames::Never | SpaceAfterFunctionNames::Calls => { + Token::new(TokenType::spaces(0)) + } } } /// Creates a new Token containing whitespace used after function calls pub fn create_function_call_trivia(ctx: &Context) -> Token { - match ctx.config().space_after_functions { - SpaceAfterFunctions::Always | SpaceAfterFunctions::Calls => { + match ctx.config().space_after_function_names { + SpaceAfterFunctionNames::Always | SpaceAfterFunctionNames::Calls => { Token::new(TokenType::spaces(1)) } - SpaceAfterFunctions::Never | SpaceAfterFunctions::Definitions => { + SpaceAfterFunctionNames::Never | SpaceAfterFunctionNames::Definitions => { Token::new(TokenType::spaces(0)) } } diff --git a/src/editorconfig.rs b/src/editorconfig.rs index cdd2320a..6cc12968 100644 --- a/src/editorconfig.rs +++ b/src/editorconfig.rs @@ -1,6 +1,6 @@ use crate::{ CallParenType, CollapseSimpleStatement, Config, IndentType, LineEndings, QuoteStyle, - SortRequiresConfig, SpaceAfterFunctions, + SortRequiresConfig, SpaceAfterFunctionNames, }; use ec4rs::{ properties_of, @@ -66,7 +66,7 @@ property_choice! { } property_choice! { - SpaceAfterFunctionsChoice, "space_after_functions"; + SpaceAfterFunctionNamesChoice, "space_after_function_names"; (Always, "always"), (Definitions, "definitions"), (Calls, "calls"), @@ -136,19 +136,19 @@ fn load(mut config: Config, properties: &Properties) -> Config { CallParenthesesChoice::None => config.call_parentheses = CallParenType::None, } } - if let Ok(space_after_functions) = properties.get::() { - match space_after_functions { - SpaceAfterFunctionsChoice::Always => { - config.space_after_functions = SpaceAfterFunctions::Always + if let Ok(space_after_function_names) = properties.get::() { + match space_after_function_names { + SpaceAfterFunctionNamesChoice::Always => { + config.space_after_function_names = SpaceAfterFunctionNames::Always } - SpaceAfterFunctionsChoice::Definitions => { - config.space_after_functions = SpaceAfterFunctions::Definitions + SpaceAfterFunctionNamesChoice::Definitions => { + config.space_after_function_names = SpaceAfterFunctionNames::Definitions } - SpaceAfterFunctionsChoice::Calls => { - config.space_after_functions = SpaceAfterFunctions::Calls + SpaceAfterFunctionNamesChoice::Calls => { + config.space_after_function_names = SpaceAfterFunctionNames::Calls } - SpaceAfterFunctionsChoice::Never => { - config.space_after_functions = SpaceAfterFunctions::Never + SpaceAfterFunctionNamesChoice::Never => { + config.space_after_function_names = SpaceAfterFunctionNames::Never } } } @@ -334,38 +334,47 @@ mod tests { } #[test] - fn test_space_after_functions_always() { + fn test_space_after_function_names_always() { let mut properties = Properties::new(); - properties.insert_raw_for_key("space_after_functions", "Always"); + properties.insert_raw_for_key("space_after_function_names", "Always"); let config = Config::from(&properties); - assert_eq!(config.space_after_functions, SpaceAfterFunctions::Always); + assert_eq!( + config.space_after_function_names, + SpaceAfterFunctionNames::Always + ); } #[test] - fn test_space_after_functions_definitions() { + fn test_space_after_function_names_definitions() { let mut properties = Properties::new(); - properties.insert_raw_for_key("space_after_functions", "Definitions"); + properties.insert_raw_for_key("space_after_function_names", "Definitions"); let config = Config::from(&properties); assert_eq!( - config.space_after_functions, - SpaceAfterFunctions::Definitions + config.space_after_function_names, + SpaceAfterFunctionNames::Definitions ); } #[test] - fn test_space_after_functions_calls() { + fn test_space_after_function_names_calls() { let mut properties = Properties::new(); - properties.insert_raw_for_key("space_after_functions", "Calls"); + properties.insert_raw_for_key("space_after_function_names", "Calls"); let config = Config::from(&properties); - assert_eq!(config.space_after_functions, SpaceAfterFunctions::Calls); + assert_eq!( + config.space_after_function_names, + SpaceAfterFunctionNames::Calls + ); } #[test] - fn test_space_after_functions_never() { + fn test_space_after_function_names_never() { let mut properties = Properties::new(); - properties.insert_raw_for_key("space_after_functions", "Never"); + properties.insert_raw_for_key("space_after_function_names", "Never"); let config = Config::from(&properties); - assert_eq!(config.space_after_functions, SpaceAfterFunctions::Never); + assert_eq!( + config.space_after_function_names, + SpaceAfterFunctionNames::Never + ); } #[test] diff --git a/src/lib.rs b/src/lib.rs index d84dd7db..bfb97bb0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -144,8 +144,8 @@ impl SortRequiresConfig { #[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 SpaceAfterFunctions { - /// Never use spaces after function nomes. +pub enum SpaceAfterFunctionNames { + /// Never use spaces after function names. #[default] Never, /// Use spaces after function names only for function definitions. @@ -196,11 +196,11 @@ pub struct Config { /// Configuration for the sort requires codemod pub sort_requires: SortRequiresConfig, /// Whether we should include a space between the function name and arguments. - /// * if space_after_functions is set to [`SpaceAfterFunctions::Never`] a space is never used. - /// * if space_after_functions is set to [`SpaceAfterFunctions::Definitions`] a space is used only for definitions. - /// * if space_after_functions is set to [`SpaceAfterFunctions::Calls`] a space is used only for calls. - /// * if space_after_functions is set to [`SpaceAfterFunctions::Always`] a space is used for both definitions and calls. - pub space_after_functions: SpaceAfterFunctions, + /// * if space_after_function_names is set to [`SpaceAfterFunctions::Never`] a space is never used. + /// * if space_after_function_names is set to [`SpaceAfterFunctions::Definitions`] a space is used only for definitions. + /// * if space_after_function_names is set to [`SpaceAfterFunctions::Calls`] a space is used only for calls. + /// * if space_after_function_names is set to [`SpaceAfterFunctions::Always`] a space is used for both definitions and calls. + pub space_after_function_names: SpaceAfterFunctionNames, } #[cfg_attr(all(target_arch = "wasm32", feature = "wasm-bindgen"), wasm_bindgen)] @@ -369,7 +369,7 @@ impl Default for Config { call_parentheses: CallParenType::default(), collapse_simple_statement: CollapseSimpleStatement::default(), sort_requires: SortRequiresConfig::default(), - space_after_functions: SpaceAfterFunctions::default(), + space_after_function_names: SpaceAfterFunctionNames::default(), } } } diff --git a/tests/test_spaces_after_functions.rs b/tests/test_spaces_after_function_names.rs similarity index 81% rename from tests/test_spaces_after_functions.rs rename to tests/test_spaces_after_function_names.rs index c332f3b5..5bd97269 100644 --- a/tests/test_spaces_after_functions.rs +++ b/tests/test_spaces_after_function_names.rs @@ -1,10 +1,10 @@ -use stylua_lib::{format_code, Config, OutputVerification, SpaceAfterFunctions}; +use stylua_lib::{format_code, Config, OutputVerification, SpaceAfterFunctionNames}; -fn format(input: &str, space_after_functions: SpaceAfterFunctions) -> String { +fn format(input: &str, space_after_function_names: SpaceAfterFunctionNames) -> String { format_code( input, Config { - space_after_functions, + space_after_function_names, ..Config::default() }, None, @@ -30,10 +30,10 @@ qiz()() "###; #[test] -fn test_never_space_after_functions() { +fn test_never_space_after_function_names() { insta::assert_snapshot!( format(STARTINGCODE, - SpaceAfterFunctions::Never + SpaceAfterFunctionNames::Never ), @r###" local foo = function() end @@ -59,7 +59,7 @@ qiz()() fn test_space_after_function_definitions() { insta::assert_snapshot!( format(STARTINGCODE, - SpaceAfterFunctions::Definitions + SpaceAfterFunctionNames::Definitions ), @r###" local foo = function () end @@ -85,7 +85,7 @@ qiz()() fn test_space_after_function_calls() { insta::assert_snapshot!( format(STARTINGCODE, - SpaceAfterFunctions::Calls + SpaceAfterFunctionNames::Calls ), @r###" local foo = function() end @@ -108,10 +108,10 @@ qiz () () } #[test] -fn test_always_space_after_functions() { +fn test_always_space_after_function_names() { insta::assert_snapshot!( format(STARTINGCODE, - SpaceAfterFunctions::Always + SpaceAfterFunctionNames::Always ), @r###" local foo = function () end From 73b5788205777fd7661eb4d8d09eab8ebcae8559 Mon Sep 17 00:00:00 2001 From: JohnnyMorganz Date: Sat, 26 Oct 2024 13:09:27 -0500 Subject: [PATCH 5/5] Update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 59fd2f6b..ea8d3a2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Added configuration option `space_after_function_names` to specify whether to include a space between a function name and parentheses ([#839](https://github.com/JohnnyMorganz/StyLua/issues/839)) + ## [0.20.0] - 2024-01-20 ### Added