Skip to content

Commit f4ba32c

Browse files
authored
Fix YAS reindentation issues (#1221)
Closes #1219 Closes #1220 Closes #1103
1 parent b47d694 commit f4ba32c

8 files changed

Lines changed: 134 additions & 47 deletions

File tree

HISTORY_v2.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
# v2.11.1
2+
3+
Fixed a bug where formatting a do-block with no argument after the `do` would cause YASStyle to crash. (#1219, #1221)
4+
5+
Fixed a number of YASStyle issues with indentation of the right-hand side of binary operators. (#1103, #1220, #1221)
6+
17
# v2.11.0
28

39
Added a new formatting option, `enforce_triplequoted_docstrings`, which controls whether single-quoted docstrings are expanded to triple-quoted docstrings.

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "JuliaFormatter"
22
uuid = "98e50ef6-434e-11e9-1051-2b60c6c9e899"
3-
version = "2.11.0"
3+
version = "2.11.1"
44
authors = ["Dominique Luna <dluna132@gmail.com> and contributors"]
55

66
[workspace]

src/nest_utils.jl

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ function nl_to_ws!(fst::FST, s::State)
103103
return
104104
end
105105

106-
function dedent!(::AbstractStyle, fst::FST, s::State)
106+
function dedent!(fst::FST, s::State)
107107
if is_closer(fst) || fst.typ === NOTCODE
108108
fst.indent -= s.opts.indent
109109
elseif is_leaf(fst) || fst.typ === StringN
@@ -113,30 +113,13 @@ function dedent!(::AbstractStyle, fst::FST, s::State)
113113
end
114114
end
115115

116-
function dedent!(::YASStyle, fst::FST, s::State)
117-
if is_closer(fst) || fst.typ === NOTCODE
118-
fst.indent -= s.opts.indent
119-
elseif is_leaf(fst) || fst.typ === StringN
120-
return
121-
elseif is_unnamed_iterable(fst)
122-
fst.indent = s.line_offset
123-
if is_opener(fst[1])
124-
fst.indent += 1
125-
end
126-
elseif is_named_iterable(fst)
127-
fst.indent = s.line_offset + length(fst[1]) + length(fst[2])
128-
else
129-
fst.indent = s.line_offset
130-
end
131-
end
132-
133116
function unnest!(style::AbstractStyle, fst::FST, s::State; dedent::Bool)
134117
if is_leaf(fst)
135118
s.line_offset += length(fst)
136119
end
137120

138121
if dedent
139-
dedent!(style, fst, s)
122+
dedent!(fst, s)
140123
end
141124

142125
if is_leaf(fst) || fst.typ === StringN || !can_nest(fst)

src/styles/default/nest.jl

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -897,13 +897,11 @@ function n_binaryopcall!(
897897
# If there are no top-level placeholders in the FST, the binary call itself is not
898898
# nestable (although its children, i.e. the operands, might be).
899899
nodes = fst.nodes::Vector
900-
idxs = findall(n -> n.typ === PLACEHOLDER, nodes)
900+
placeholder_idxs = findall(n -> n.typ === PLACEHOLDER, nodes)
901901

902902
rhs = fst[end]
903903
if rhs.typ === Block
904-
(rhs = rhs[1])
905-
else
906-
false
904+
rhs = rhs[1]
907905
end
908906

909907
# is the LHS on a different line than the RHS ?
@@ -912,10 +910,10 @@ function n_binaryopcall!(
912910

913911
nested = false
914912

915-
if length(idxs) == 2 &&
913+
if length(placeholder_idxs) == 2 &&
916914
(line_margin > s.opts.margin || must_nest(fst) || must_nest(rhs) || src_diff_line)
917-
i1 = idxs[1]
918-
i2 = idxs[2]
915+
i1 = placeholder_idxs[1]
916+
i2 = placeholder_idxs[2]
919917
fst[i1] = Newline(; length = fst[i1].len)
920918
nested = true
921919

@@ -952,14 +950,17 @@ function n_binaryopcall!(
952950
# "lhs op" rhs
953951
s.line_offset = line_offset
954952

955-
# extra margin for " op"
953+
# Nest the LHS, but first update the extra margin corresponding to " op"
956954
fst[1].extra_margin = length(fst[2]) + length(fst[3])
957-
nest!(style, fst[1], s, lineage) # lhs
955+
nest!(style, fst[1], s, lineage)
956+
# Nest everything up to the operator
958957
for n in fst[2:i1]
959958
nest!(style, n, s, lineage)
960959
end
961960

962-
# Undo nest if possible
961+
# It's possible that nesting the LHS means that it's shorter, and thus we might not
962+
# need to nest the entire binaryop (i.e., we might not need newlines around the
963+
# operator). Attempt to undo the nesting here.
963964
if can_nest(fst) && !no_unnest(rhs) && !src_diff_line
964965
line_margin = s.line_offset
965966

@@ -981,6 +982,7 @@ function n_binaryopcall!(
981982
line_margin += sum(length.(rhs[1:(idx-1)]))
982983
end
983984
else
985+
# Calculate how much of the RHS we need to fit on the current line
984986
rw, _ = length_to(fst, (NEWLINE,); start = i2 + 1)
985987
line_margin += rw
986988
end
@@ -989,7 +991,24 @@ function n_binaryopcall!(
989991
fst[i1] = Whitespace(1)
990992
if indent_nest || style isa YASStyle
991993
fst[i2] = Whitespace(0)
994+
line_offset = s.line_offset
992995
walk(unnest!(style; dedent = true), rhs, s)
996+
# Iterables in YASStyle need to be aligned with the
997+
# open bracket
998+
if style isa YASStyle
999+
if is_unnamed_iterable(rhs)
1000+
extra_indent = if !isempty(rhs.nodes) && is_opener(rhs[1])
1001+
line_offset - rhs.indent + 1
1002+
else
1003+
line_offset - rhs.indent
1004+
end
1005+
add_indent!(rhs, s, extra_indent)
1006+
elseif is_named_iterable(rhs)
1007+
extra_indent =
1008+
line_offset - rhs.indent + length(rhs[1]) + length(rhs[2])
1009+
add_indent!(rhs, s, extra_indent)
1010+
end
1011+
end
9931012
end
9941013
end
9951014
end
@@ -1024,6 +1043,20 @@ function n_binaryopcall!(
10241043
nested |= nest!(style, n, s, lineage)
10251044
elseif i == length(nodes)
10261045
# rhs
1046+
if style isa YASStyle
1047+
if is_unnamed_iterable(rhs)
1048+
extra_indent = if !isempty(rhs.nodes) && is_opener(rhs[1])
1049+
s.line_offset - fst.indent + 1
1050+
else
1051+
s.line_offset - fst.indent
1052+
end
1053+
add_indent!(rhs, s, extra_indent)
1054+
elseif is_named_iterable(rhs)
1055+
extra_indent =
1056+
s.line_offset - fst.indent + length(rhs[1]) + length(rhs[2])
1057+
add_indent!(rhs, s, extra_indent)
1058+
end
1059+
end
10271060
n.extra_margin = fst.extra_margin
10281061
nested |= nest!(style, n, s, lineage)
10291062
else

src/styles/yas/nest.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,8 @@ function n_binaryopcall!(
455455
)
456456
style = getstyle(ys)
457457
nodes = fst.nodes::Vector
458-
if findfirst(n -> n.typ === PLACEHOLDER, nodes) !== nothing
458+
459+
if any(n -> n.typ === PLACEHOLDER, nodes)
459460
return n_binaryopcall!(DefaultStyle(style), fst, s, lineage; indent = indent)
460461
end
461462

test/format_repo.jl

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,28 @@ using JuliaFormatter: format
44
using Test
55

66
@testset "Format repo" begin
7-
try
8-
sandbox_dir = joinpath(tempdir(), join(rand('a':'z', 40)))
9-
@info "formatting in directory" sandbox_dir
10-
mkdir(sandbox_dir)
11-
cp(@__DIR__, sandbox_dir; force = true)
12-
13-
# initial format
14-
format(sandbox_dir)
15-
16-
# follow up formats should be the same
17-
@test format(sandbox_dir; join_lines_based_on_source = true) == true
18-
@test format(sandbox_dir; join_lines_based_on_source = true, margin = 10_000) ==
19-
true
20-
finally
7+
@testset "$name" for (name, kwargs) in (
8+
("empty", (;)),
9+
("jlbos", (; join_lines_based_on_source=true)),
10+
("jlbos+margin", (; join_lines_based_on_source=true, margin=10_000))
11+
)
2112
try
22-
rm(sandbox_dir; recursive = true)
23-
catch
13+
sandbox_dir = joinpath(tempdir(), join(rand('a':'z', 40)))
14+
if isdir(sandbox_dir)
15+
rm(sandbox_dir; recursive=true)
16+
end
17+
mkdir(sandbox_dir)
18+
cp(@__DIR__, sandbox_dir; force=true)
19+
format(sandbox_dir; kwargs...)
20+
# directly doing `@test format(...)` is broken on 1.13, see
21+
# https://github.com/JuliaLang/julia/issues/62296
22+
res = format(sandbox_dir; kwargs...)
23+
@test res
24+
finally
25+
try
26+
rm(sandbox_dir; recursive=true)
27+
catch
28+
end
2429
end
2530
end
2631
end

test/issues.jl

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2810,6 +2810,28 @@ end
28102810
end
28112811
end
28122812

2813+
@testset "1103 YAS indentation after =>" begin
2814+
for s in (
2815+
"""
2816+
long_name => [
2817+
#
2818+
1,
2819+
2,
2820+
3
2821+
#
2822+
]""",
2823+
2824+
"""
2825+
ccc => function ()
2826+
return f() do x
2827+
return aaaaaaaaaaaaa
2828+
end
2829+
end""",
2830+
)
2831+
test_format(s, s, YASStyle())
2832+
end
2833+
end
2834+
28132835
@testset "1105 typed comprehension idempotence" begin
28142836
s = """
28152837
function f()
@@ -3549,6 +3571,16 @@ end
35493571
)"""
35503572
test_format(s, expected; separate_kwargs_with_semicolon=true)
35513573
end
3574+
3575+
@testset "1219 dedenting empty do-block argument" begin
3576+
s = """
3577+
ccc => function ()
3578+
return f() do
3579+
return aaaaaaaaaaaaa
3580+
end
3581+
end"""
3582+
test_format(s, s, YASStyle(); margin=30)
3583+
end
35523584
end
35533585

35543586
end

test/yas_style.jl

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,33 @@ using JuliaFormatter: format_text
774774
test_format(str, formatted_str1, YASStyle(); variable_call_indent = ["test"])
775775
test_format(str, formatted_str2, YASStyle(); variable_call_indent = ["SVector", "test"])
776776
end
777+
778+
@testset "indentation of binary ops" begin
779+
s1 = """
780+
begin
781+
@test aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa == ["theta[1]",
782+
"theta[2]",
783+
"theta[3]",
784+
"theta[4]",
785+
"tau"]
786+
end"""
787+
# different margins have different code paths so test both
788+
for margin in (80, 2000)
789+
test_format(s1, s1, YASStyle(); margin=margin)
790+
end
791+
792+
s2 = """
793+
begin
794+
@test ccc => function ()
795+
return f() do x
796+
return aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
797+
end
798+
end
799+
end"""
800+
for margin in (80, 2000)
801+
test_format(s2, s2, YASStyle(); margin=margin)
802+
end
803+
end
777804
end
778805

779806
end

0 commit comments

Comments
 (0)