Skip to content

Commit 87fc69e

Browse files
Hang at equals token in table field if comments before value (#982)
* Add test case * Hang after equals in table if comments present * Update changelog * Update snapshots * Add another test case * Clippy
1 parent d1a6a51 commit 87fc69e

File tree

7 files changed

+141
-37
lines changed

7 files changed

+141
-37
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2525
- Fixed panic when attempting to format a file outside of the current working directory when `--respect-ignores` is enabled ([#969](https://github.com/JohnnyMorganz/StyLua/pull/969))
2626
- Fixed unnecessary semicolons being introduced at the end of statements when incorrectly determined as ambiguous ([#963](https://github.com/JohnnyMorganz/StyLua/issues/963))
2727
- Fixed malformed formatting of function calls where parentheses are removed but there are comments in between the parentheses and the expression. Now, we will keep the parentheses in these cases, except for trailing comments ([#964](https://github.com/JohnnyMorganz/StyLua/issues/964))
28+
- Fixed malformed formatting of table field expression when there are comments in between the equals and the value ([#942](https://github.com/JohnnyMorganz/StyLua/issues/942))
2829

2930
## [2.0.2] - 2024-12-07
3031

src/formatters/assignment.rs

Lines changed: 44 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,48 @@ fn prevent_equals_hanging(expression: &Expression) -> bool {
162162
}
163163
}
164164

165+
pub fn hang_at_equals_due_to_comments(
166+
ctx: &Context,
167+
equal_token: &TokenReference,
168+
expression: &Expression,
169+
shape: Shape,
170+
) -> (TokenReference, Expression) {
171+
// We will hang at the equals token, and then format the expression as necessary
172+
let equal_token = hang_equal_token(ctx, equal_token, shape, false);
173+
174+
let shape = shape.reset().increment_additional_indent();
175+
176+
// As we know that there is only a single element in the list, we can extract it to work with it
177+
// Format the expression given - if it contains comments, make sure to hang the expression
178+
// Ignore the leading comments though (as they are solved by hanging at the equals), and the
179+
// trailing comments, as they don't affect anything
180+
let expression = if strip_trivia(expression).has_inline_comments() {
181+
hang_expression(ctx, expression, shape, None)
182+
} else {
183+
format_expression(ctx, expression, shape)
184+
};
185+
186+
// We need to take all the leading trivia from the expr_list
187+
let (expression, leading_comments) = trivia_util::take_leading_comments(&expression);
188+
189+
// Indent each comment and trail them with a newline
190+
let leading_comments = leading_comments
191+
.iter()
192+
.flat_map(|x| {
193+
vec![
194+
create_indent_trivia(ctx, shape),
195+
x.to_owned(),
196+
create_newline_trivia(ctx),
197+
]
198+
})
199+
.chain(std::iter::once(create_indent_trivia(ctx, shape)))
200+
.collect();
201+
202+
let expression = expression.update_leading_trivia(FormatTriviaType::Replace(leading_comments));
203+
204+
(equal_token, expression)
205+
}
206+
165207
/// Attempts different formatting tactics on an expression list being assigned (`= foo, bar`), to find the best
166208
/// formatting output.
167209
fn attempt_assignment_tactics(
@@ -240,39 +282,8 @@ fn attempt_assignment_tactics(
240282
if trivia_util::token_contains_comments(&equal_token)
241283
|| expression.has_leading_comments(CommentSearch::Single)
242284
{
243-
// We will hang at the equals token, and then format the expression as necessary
244-
let equal_token = hang_equal_token(ctx, &equal_token, shape, false);
245-
246-
let shape = shape.reset().increment_additional_indent();
247-
248-
// As we know that there is only a single element in the list, we can extract it to work with it
249-
// Format the expression given - if it contains comments, make sure to hang the expression
250-
// Ignore the leading comments though (as they are solved by hanging at the equals), and the
251-
// trailing comments, as they don't affect anything
252-
let expression = if strip_trivia(expression).has_inline_comments() {
253-
hang_expression(ctx, expression, shape, None)
254-
} else {
255-
format_expression(ctx, expression, shape)
256-
};
257-
258-
// We need to take all the leading trivia from the expr_list
259-
let (expression, leading_comments) = trivia_util::take_leading_comments(&expression);
260-
261-
// Indent each comment and trail them with a newline
262-
let leading_comments = leading_comments
263-
.iter()
264-
.flat_map(|x| {
265-
vec![
266-
create_indent_trivia(ctx, shape),
267-
x.to_owned(),
268-
create_newline_trivia(ctx),
269-
]
270-
})
271-
.chain(std::iter::once(create_indent_trivia(ctx, shape)))
272-
.collect();
273-
274-
let expression =
275-
expression.update_leading_trivia(FormatTriviaType::Replace(leading_comments));
285+
let (equal_token, expression) =
286+
hang_at_equals_due_to_comments(ctx, &equal_token, expression, shape);
276287

277288
// Rebuild expression back into a list
278289
let expr_list = std::iter::once(Pair::new(expression, None)).collect();

src/formatters/table.rs

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ use full_moon::{
2323
tokenizer::{Token, TokenReference, TokenType},
2424
};
2525

26+
use super::{assignment::hang_at_equals_due_to_comments, trivia_util::GetLeadingTrivia};
27+
2628
/// Used to provide information about the table
2729
#[derive(Debug, Clone, Copy)]
2830
pub enum TableType {
@@ -68,6 +70,25 @@ fn format_field_expression_value(
6870
}
6971
}
7072

73+
fn hang_field_value_at_equals_due_to_comments(
74+
ctx: &Context,
75+
equal: &TokenReference,
76+
expression: &Expression,
77+
shape: Shape,
78+
) -> (TokenReference, Expression) {
79+
// Remove singleline comments from the output expression as it will be moved after the comma
80+
// Retain multiline comments in place
81+
let multiline_comments = expression.trailing_comments_search(CommentSearch::Multiline);
82+
let trailing_trivia = FormatTriviaType::Replace(multiline_comments);
83+
84+
let (equal_token, expression) = hang_at_equals_due_to_comments(ctx, equal, expression, shape);
85+
86+
(
87+
equal_token,
88+
expression.update_trailing_trivia(trailing_trivia),
89+
)
90+
}
91+
7192
/// Handles the formatting of the comments around a key and the equals sign in a field of a table.
7293
/// Takes in the key as a node (so that we can handle both expression key brackets and name keys)
7394
/// as well as the equals sign, then outputs the new leading trivia of the key + new equals token. The trailing trivia of the key should be emptied.
@@ -177,8 +198,14 @@ fn format_field(
177198
.update_trailing_trivia(FormatTriviaType::Replace(vec![]))
178199
.update_leading_trivia(leading_trivia);
179200

180-
let shape = shape.take_last_line(&key) + (2 + 3 + if space_brackets { 2 } else { 0 }); // 2 = brackets, 3 = " = ", 2 = spaces around brackets if necessary
181-
let value = format_field_expression_value(ctx, value, shape);
201+
let (equal, value) = if value.has_leading_comments(CommentSearch::Single) {
202+
hang_field_value_at_equals_due_to_comments(ctx, &equal, value, shape)
203+
} else {
204+
let shape =
205+
shape.take_last_line(&key) + (2 + 3 + if space_brackets { 2 } else { 0 }); // 2 = brackets, 3 = " = ", 2 = spaces around brackets if necessary
206+
let value = format_field_expression_value(ctx, value, shape);
207+
(equal, value)
208+
};
182209

183210
Field::ExpressionKey {
184211
brackets,
@@ -202,8 +229,13 @@ fn format_field(
202229
.update_trailing_trivia(FormatTriviaType::Replace(vec![]))
203230
.update_leading_trivia(leading_trivia);
204231

205-
let shape = shape + (strip_trivia(&key).to_string().len() + 3); // 3 = " = "
206-
let value = format_field_expression_value(ctx, value, shape);
232+
let (equal, value) = if value.has_leading_comments(CommentSearch::Single) {
233+
hang_field_value_at_equals_due_to_comments(ctx, &equal, value, shape)
234+
} else {
235+
let shape = shape + (strip_trivia(&key).to_string().len() + 3); // 3 = " = "
236+
let value = format_field_expression_value(ctx, value, shape);
237+
(equal, value)
238+
};
207239

208240
Field::NameKey { key, equal, value }
209241
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
-- https://github.com/JohnnyMorganz/StyLua/issues/942
2+
local t = {
3+
plus_one =
4+
---@param n number
5+
---@return number
6+
function(n)
7+
return n + 1
8+
end ,
9+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
-- https://github.com/JohnnyMorganz/StyLua/issues/942
2+
local mixed = {
3+
--- identity
4+
---@param n number
5+
---@return number
6+
function(n)
7+
return n
8+
end,
9+
plus_one =
10+
---@param n number
11+
---@return number
12+
function(n)
13+
return n + 1
14+
end,
15+
}

tests/snapshots/[email protected]

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
source: tests/tests.rs
3+
expression: "format(&contents, LuaVersion::Lua51)"
4+
input_file: tests/inputs/table-field-comments-2.lua
5+
snapshot_kind: text
6+
---
7+
-- https://github.com/JohnnyMorganz/StyLua/issues/942
8+
local t = {
9+
plus_one =
10+
---@param n number
11+
---@return number
12+
function(n)
13+
return n + 1
14+
end,
15+
}

tests/snapshots/[email protected]

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
source: tests/tests.rs
3+
expression: "format(&contents, LuaVersion::Lua51)"
4+
input_file: tests/inputs/table-field-comments-3.lua
5+
snapshot_kind: text
6+
---
7+
-- https://github.com/JohnnyMorganz/StyLua/issues/942
8+
local mixed = {
9+
--- identity
10+
---@param n number
11+
---@return number
12+
function(n)
13+
return n
14+
end,
15+
plus_one =
16+
---@param n number
17+
---@return number
18+
function(n)
19+
return n + 1
20+
end,
21+
}

0 commit comments

Comments
 (0)