diff --git a/src/Runic.jl b/src/Runic.jl index 0b32a3e..fd688f6 100644 --- a/src/Runic.jl +++ b/src/Runic.jl @@ -432,6 +432,7 @@ function format_node!(ctx::Context, node::Node)::Union{Node, Nothing, NullNode} @return_something spaces_around_keywords(ctx, node) @return_something spaces_in_import_using(ctx, node) @return_something spaces_in_export_public(ctx, node) + @return_something spaces_around_comments(ctx, node) @return_something no_spaces_around_colon_etc(ctx, node) @return_something parens_around_op_calls_in_colon(ctx, node) @return_something for_loop_use_in(ctx, node) diff --git a/src/runestone.jl b/src/runestone.jl index be89d25..d149c32 100644 --- a/src/runestone.jl +++ b/src/runestone.jl @@ -3355,3 +3355,43 @@ function remove_trailing_semicolon(ctx::Context, node::Node) seek(ctx.fmt_io, pos) return any_changed ? make_node(node, kids′) : nothing end + +function spaces_around_comments(ctx::Context, node::Node) + is_leaf(node) && return + pos = position(ctx.fmt_io) + kids = verified_kids(node) + kids′ = kids + # We assume that the previous node ends with ws, which should be true since the same + # pass here adds it if the first kid is a comment. + prev_kid_ends_with_ws = true + ws = Node(JuliaSyntax.SyntaxHead(K"Whitespace", JuliaSyntax.TRIVIA_FLAG), 1) + for (i, kid) in pairs(kids) + if kind(kid) === K"Comment" || + (fl = first_leaf(kid); fl !== nothing && kind(fl) === K"Comment") + # TODO: In the case where the comment is found within the kid the whitespace + # should maybe be added right before the comment in the tree (which is how + # JuliaSyntax would have parsed the source if the space was already there). I + # don't know if this really matters though since it is already pretty random + # where whitespace ends up. + if !prev_kid_ends_with_ws + kids′ = kids′ === kids ? kids[1:(i - 1)] : kids′ + push!(kids′, ws) + replace_bytes!(ctx, " ", 0) + accept_node!(ctx, ws) + end + end + if kids′ !== kids + push!(kids′, kid) + end + accept_node!(ctx, kid) + prev_kid_ends_with_ws = kind(kid) in KSet"Whitespace NewlineWs" || + (ll = last_leaf(kid); ll !== nothing && kind(ll) in KSet"Whitespace NewlineWs") + end + # Reset the stream and return + seek(ctx.fmt_io, pos) + if kids === kids′ + return nothing + else + return make_node(node, kids′) + end +end diff --git a/test/runtests.jl b/test/runtests.jl index fa4539d..c32586d 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -76,6 +76,22 @@ end format_string("# comment \t ") == format_string("# comment\t \t") == "# comment" end +@testset "space before comment" begin + for sp in ("", " ", " ") + csp = sp == "" ? " " : sp + @test format_string("a$(sp)# comment") == "a$(csp)# comment" + @test format_string("1 + 1$(sp)# comment") == "1 + 1$(csp)# comment" + @test format_string("(a,$(sp)# comment\nb)") == + "(\n a,$(csp)# comment\n b,\n)" + # Edgecase where the comment ends up as the first leaf inside the call + @test format_string("(a,$(sp)# comment\nb + b)") == + "(\n a,$(csp)# comment\n b + b,\n)" + end + let str = "a = 1 # a comment\nab = 2 # ab comment\n" + @test format_string(str) == str + end +end + @testset "Hex/oct/bin literal integers" begin z(n) = "0"^n test_cases = [ @@ -193,6 +209,7 @@ end @testset "spaces in listlike" begin for sp in ("", " ", " "), a in ("a", "a + a", "a(x)"), b in ("b", "b + b", "b(y)") + csp = sp == "" ? " " : sp # at least one space before comment (but more allowed) # tuple, call, dotcall, vect, ref for (o, c) in (("(", ")"), ("f(", ")"), ("@f(", ")"), ("f.(", ")"), ("[", "]"), ("T[", "]")) tr = o in ("f(", "@f(", "f.(") ? "" : "," @@ -235,9 +252,9 @@ end "$(o)\n $(a),\n $(b),\n$(c)" # trailing comments @test format_string("$(o)$(sp)# x\n$(sp)$(a)$(sp),$(sp)# a\n$(sp)$(b)$(sp)# b\n$(c)") == - "$(o)\n # x\n $(a),$(sp)# a\n $(b)$(tr)$(sp)# b\n$(c)" + "$(o)\n # x\n $(a),$(csp)# a\n $(b)$(tr)$(csp)# b\n$(c)" @test format_string("$(o)$(sp)# x\n$(sp)$(a)$(sp),$(sp)# a\n$(sp)$(b),$(sp)# b\n$(c)") == - "$(o)\n # x\n $(a),$(sp)# a\n $(b),$(sp)# b\n$(c)" + "$(o)\n # x\n $(a),$(csp)# a\n $(b),$(csp)# b\n$(c)" # comments on separate lines between items @test format_string("$(o)\n# a\n$(a)$(sp),\n# b\n$(b)\n$(c)") == "$(o)\n # a\n $(a),\n # b\n $(b)$(tr)\n$(c)" @@ -259,7 +276,7 @@ end @test format_string("$(a)$(sp),\n$(sp)$(b)") == "$(a),\n $(b)" # trailing comments @test format_string("$(a)$(sp),$(sp)# a\n$(sp)$(b)$(sp)# b") == - "$(a),$(sp)# a\n $(b)$(sp)# b" + "$(a),$(csp)# a\n $(b)$(csp)# b" @test format_string("# a\n$(a)$(sp),\n# b\n$(b)") == "# a\n$(a),\n # b\n $(b)" end