Skip to content

Commit

Permalink
feat: Add more granular control over call parentheses (#330)
Browse files Browse the repository at this point in the history
* feat: Add more granular control over call parentheses

Adds new option call_parentheses with possible values Always, NoString, NoTable,
     None (Default: Always)

When call_parentheses is set to Always stylua applies call parentheses
all the time.
```lua
xyz({ a = 1, b = 2 })
abc('Hello')
When set to NoString it omits parentheses on function call with
single table argument.
```lua
xyz({a = 1, b = 2 })
abc 'Hello'
```
```
Similarly when set to NoTable it omits parentheses on function call with
single table argument.
```lua
xyz { a = 1, b = 2 }
abc('Hello')
```
And when it's None stylua omits parentheses on function call with
single table or string argument. This is same as `no_call_parentheses =
true`
```lua
xyz { a = 1, b = 2 }
abc 'Hello'
```

* rename NoString->NoSingleString NoTable->NoSingleTable
  • Loading branch information
shadmansaleh committed Jan 10, 2022
1 parent 3b2c724 commit 6272fdf
Show file tree
Hide file tree
Showing 8 changed files with 390 additions and 20 deletions.
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Added
- Added option `call_parentheses`
Specify whether to apply parentheses on function calls with single string or table arg. Possible options:`Always`, `NoSingleString`, `NoSingleTable`, `None`.

### Fixed
- Fixed generic variadics not being handled under the `luau` feature flag. ([#333](https://github.com/JohnnyMorganz/StyLua/issues/333))

### Deprecated
- Option `no_call_parentheses` has been deprecated. Use `call_parentheses = "None"` instead.

## [0.11.3] - 2022-01-01
### Fixed
- Fixed comments preceding a comma within a function call or parameter list for a function definition being mistransformed leading to a syntax error. ([#307](https://github.com/JohnnyMorganz/StyLua/issues/307))
Expand Down Expand Up @@ -314,4 +321,4 @@ For example, using `stylua -g *.lua -g !*.spec.lua .` will format all Lua files
- Double quotes are now escaped when converting from single quote to double quote strings

## [0.1.0-alpha] - 2020-12-22
Initial alpha release
Initial alpha release
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ StyLua only offers the following options:
| `indent_type` | `Tabs` | Type of indents to use. Possible options: `Tabs` or `Spaces`
| `indent_width` | `4` | The number of characters a single indent takes. If `indent_type` is set to `Tabs`, this option is used as a heuristic to determine column width only.
| `quote_style` | `AutoPreferDouble` | Types of quotes to use for string literals. Possible options: `AutoPreferDouble`, `AutoPreferSingle`, `ForceDouble`, `ForceSingle`. In `AutoPrefer` styles, we prefer the quote type specified, but fall back to the opposite if it leads to fewer escapes in the string. `Force` styles always use the style specified regardless of escapes.
| `no_call_parentheses` | `false` | A style option added for adoption purposes. When enabled, parentheses are removed around function arguments where a single string literal/table is passed. Note: parentheses are still kept in some situations if removing them will make the syntax become obscure (e.g. `foo "bar".setup -> foo("bar").setup`, as we are indexing the call result, not the string)
| `call_parentheses` | `Always` | Specify whether to apply parentheses on function calls with a single string or table argument. Possible options: [`Always`, `NoSingleString`, `NoSingleTable`, `None`]. When `call_parentheses` is set to `Always`, StyLua applies call parentheses all the time.When it's set to `NoSingleString` it omits parentheses on function calls with single string argument. Similarly when set to `NoSingleTable` it omits parentheses on function calls with a single table argument. And when it's `None` StyLua omits parentheses on function call with single table or string argument (originally as `no_call_parentheses`). Note: parentheses are still kept in some situations if removing them will make the syntax become obscure (e.g. `foo "bar".setup -> foo("bar").setup`, as we are indexing the call result, not the string).

Default `stylua.toml`, note you do not need to explicitly specify each option if you want to use the defaults:
```toml
Expand All @@ -153,5 +153,5 @@ line_endings = "Unix"
indent_type = "Tabs"
indent_width = 4
quote_style = "AutoPreferDouble"
no_call_parentheses = false
call_parentheses = "Always"
```
3 changes: 3 additions & 0 deletions src/cli/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,9 @@ pub fn load_overrides(config: Config, opt: &Opt) -> Config {
if let Some(quote_style) = opt.format_opts.quote_style {
new_config = new_config.with_quote_style(quote_style.into());
};
if let Some(call_parentheses) = opt.format_opts.call_parentheses {
new_config = new_config.with_call_parentheses(call_parentheses.into());
};

new_config
}
12 changes: 11 additions & 1 deletion src/cli/opt.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::path::PathBuf;
use structopt::{clap::arg_enum, StructOpt};
use stylua_lib::{IndentType, LineEndings, QuoteStyle};
use stylua_lib::{CallParenType, IndentType, LineEndings, QuoteStyle};

lazy_static::lazy_static! {
static ref NUM_CPUS: String = num_cpus::get().to_string();
Expand Down Expand Up @@ -114,6 +114,9 @@ pub struct FormatOpts {
/// The style of quotes to use in string literals.
#[structopt(long, possible_values = &ArgQuoteStyle::variants(), case_insensitive = true, )]
pub quote_style: Option<ArgQuoteStyle>,
/// Specify whether to apply parentheses on function calls with signle string or table arg.
#[structopt(long, possible_values = &ArgCallParenType::variants(), case_insensitive = true, )]
pub call_parentheses: Option<ArgCallParenType>,
}

// Convert [`stylua_lib::Config`] enums into clap-friendly enums
Expand Down Expand Up @@ -166,3 +169,10 @@ convert_enum!(QuoteStyle, ArgQuoteStyle, {
ForceDouble,
ForceSingle,
});

convert_enum!(CallParenType, ArgCallParenType, {
Always,
NoSingleString,
NoSingleTable,
None,
});
14 changes: 13 additions & 1 deletion src/context.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{shape::Shape, Config, IndentType, LineEndings, Range as FormatRange};
use crate::{shape::Shape, CallParenType, Config, IndentType, LineEndings, Range as FormatRange};
use full_moon::{
node::Node,
tokenizer::{Token, TokenType},
Expand Down Expand Up @@ -117,6 +117,18 @@ impl Context {
true
}
}

pub fn should_omit_string_parens(&self) -> bool {
self.config().no_call_parentheses
|| self.config().call_parentheses == CallParenType::None
|| self.config().call_parentheses == CallParenType::NoSingleString
}

pub fn should_omit_table_parens(&self) -> bool {
self.config().no_call_parentheses
|| self.config().call_parentheses == CallParenType::None
|| self.config().call_parentheses == CallParenType::NoSingleTable
}
}

#[macro_export]
Expand Down
34 changes: 19 additions & 15 deletions src/formatters/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,28 +107,32 @@ pub fn format_function_args(
arguments,
} => {
// Handle config where parentheses are omitted, and there is only one argument
if ctx.config().no_call_parentheses
if (ctx.should_omit_string_parens() || ctx.should_omit_table_parens())
&& arguments.len() == 1
&& !matches!(call_next_node, FunctionCallNextNode::ObscureWithoutParens)
{
let argument = arguments.iter().next().unwrap();
if let Expression::Value { value, .. } = argument {
match &**value {
Value::String(token_reference) => {
return format_function_args(
ctx,
&FunctionArgs::String(token_reference.to_owned()),
shape,
call_next_node,
);
if ctx.should_omit_string_parens() {
return format_function_args(
ctx,
&FunctionArgs::String(token_reference.to_owned()),
shape,
call_next_node,
);
}
}
Value::TableConstructor(table_constructor) => {
return format_function_args(
ctx,
&FunctionArgs::TableConstructor(table_constructor.to_owned()),
shape,
call_next_node,
);
if ctx.should_omit_table_parens() {
return format_function_args(
ctx,
&FunctionArgs::TableConstructor(table_constructor.to_owned()),
shape,
call_next_node,
);
}
}
_ => (),
}
Expand Down Expand Up @@ -464,7 +468,7 @@ pub fn format_function_args(
}

FunctionArgs::String(token_reference) => {
if ctx.config().no_call_parentheses
if ctx.should_omit_string_parens()
&& !matches!(call_next_node, FunctionCallNextNode::ObscureWithoutParens)
{
let token_reference = format_token_reference(ctx, token_reference, shape)
Expand Down Expand Up @@ -506,7 +510,7 @@ pub fn format_function_args(
}

FunctionArgs::TableConstructor(table_constructor) => {
if ctx.config().no_call_parentheses
if ctx.should_omit_table_parens()
&& !matches!(call_next_node, FunctionCallNextNode::ObscureWithoutParens)
{
let table_constructor = format_table_constructor(ctx, table_constructor, shape)
Expand Down
36 changes: 36 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,25 @@ impl Default for QuoteStyle {
}
}

/// When to use call parentheses
#[derive(Debug, Copy, Clone, PartialEq, Deserialize)]
pub enum CallParenType {
/// Use call parentheses all the time
Always,
/// Skip call parentheses when only a string argument is used.
NoSingleString,
/// Skip call parentheses when only a table argument is used.
NoSingleTable,
/// Skip call parentheses when only a table or string argument is used.
None,
}

impl Default for CallParenType {
fn default() -> Self {
CallParenType::Always
}
}

/// 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.
Expand Down Expand Up @@ -94,6 +113,15 @@ pub struct Config {
/// Whether to omit parentheses around function calls which take a single string literal or table.
/// This is added for adoption reasons only, and is not recommended for new work.
no_call_parentheses: bool,
/// When to use call parentheses.
/// if call_parentheses is set to [`CallParenType::Always`] call parentheses is always applied.
/// if call_parentheses is set to [`CallParenType::NoSingleTable`] call parentheses is omitted when
/// function is called with only one string argument.
/// if call_parentheses is set to [`CallParenType::NoSingleTable`] call parentheses is omitted when
/// function is called with only one table argument.
/// if call_parentheses is set to [`CallParenType::None`] call parentheses is omitted when
/// function is called with only one table or string argument (same as no_call_parentheses).
call_parentheses: CallParenType,
}

impl Config {
Expand Down Expand Up @@ -149,6 +177,13 @@ impl Config {
..self
}
}
/// Returns a new config with the given call parentheses type
pub fn with_call_parentheses(self, call_parentheses: CallParenType) -> Self {
Self {
call_parentheses,
..self
}
}
}

impl Default for Config {
Expand All @@ -160,6 +195,7 @@ impl Default for Config {
indent_width: 4,
quote_style: QuoteStyle::default(),
no_call_parentheses: false,
call_parentheses: CallParenType::default(),
}
}
}
Expand Down

0 comments on commit 6272fdf

Please sign in to comment.