Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ensure single space before more keywords #82

Merged
merged 1 commit into from
Oct 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 32 additions & 6 deletions src/runestone.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1222,11 +1222,11 @@ end
# Single space around keywords:
# Both sides of: `where`, `do` (if followed by arguments)
# Right hand side of: `mutable`, `struct`, `abstract`, `primitive`, `type`, `function` (if
# named function), `if`, `elseif`, `catch` (if followed by variable)
# TODO: local, const
# named function), `if`, `elseif`, `catch` and `return` (if followed by something), local,
# global, const
function spaces_around_keywords(ctx::Context, node::Node)
is_leaf(node) && return nothing
keyword_set = KSet"where do mutable struct abstract primitive type function if elseif catch while"
keyword_set = KSet"where do mutable struct abstract primitive type function if elseif catch while return local global const"
if !(kind(node) in keyword_set)
return nothing
end
Expand Down Expand Up @@ -1289,10 +1289,10 @@ function spaces_around_keywords(ctx::Context, node::Node)
end
elseif state === :looking_for_space
if (kind(kid) === K"Whitespace" && span(kid) == 1) ||
kind(kid) === K"NewlineWs"
kind(kid) === K"NewlineWs" || kind(first_leaf(kid)) === K"NewlineWs"
if kind(kid) === K"NewlineWs"
# Is a newline instead of a space accepted for any other case?
@assert kind(node) === K"where"
@assert kind(node) in KSet"where local global const"
end
accept_node!(ctx, kid)
any_changes && push!(kids′, kid)
Expand Down Expand Up @@ -1325,7 +1325,7 @@ function spaces_around_keywords(ctx::Context, node::Node)
@assert false # Unreachable?
else
# Reachable in e.g. `T where{T}`, `if(`, ... insert space
@assert kind(node) in KSet"where if elseif while do function"
@assert kind(node) in KSet"where if elseif while do function return local global"
any_changes = true
if kids′ === kids
kids′ = kids[1:(i - 1)]
Expand Down Expand Up @@ -3046,6 +3046,30 @@ function indent_toplevel(ctx::Context, node::Node)
return any_kid_changed ? make_node(node, kids) : nothing
end

function indent_local_global(ctx::Context, node::Node)
@assert kind(node) in KSet"local global"
@assert !is_global_local_list(node)
# Something like `local x = 1` or `global function foo(...)`. Continue all newlines
# between the keyword and the next non-whitespace node.
kids = verified_kids(node)
kw = findfirst(x -> is_leaf(x) && kind(x) in KSet"local global", kids)::Int
nonws = findnext(!JuliaSyntax.is_whitespace, kids, kw + 1)::Int
changed = false
for i in (kw + 1):nonws
if kind(kids[i]) === K"NewlineWs" && !has_tag(kids[i], TAG_LINE_CONT)
kids[i] = add_tag(kids[i], TAG_LINE_CONT)
changed = true
elseif i == nonws && kind(first_leaf(kids[i])) === K"NewlineWs" &&
!has_tag(first_leaf(kids[i]), TAG_LINE_CONT)
kid′ = replace_first_leaf(kids[i], add_tag(first_leaf(kids[i]), TAG_LINE_CONT))
@assert kid′ !== nothing
kids[i] = kid′
changed = true
end
end
return changed ? make_node(node, kids) : nothing
end

function insert_delete_mark_newlines(ctx::Context, node::Node)
if is_leaf(node)
return nothing
Expand Down Expand Up @@ -3079,6 +3103,8 @@ function insert_delete_mark_newlines(ctx::Context, node::Node)
return indent_short_circuit(ctx, node)
elseif kind(node) in KSet"using import export public" || is_global_local_list(node)
return indent_using_import_export_public(ctx, node)
elseif kind(node) in KSet"local global"
return indent_local_global(ctx, node)
elseif is_variable_assignment(ctx, node)
return indent_assignment(ctx, node)
elseif kind(node) === K"parameters"
Expand Down
16 changes: 15 additions & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,18 @@ end
@test format_string("f()$(sp)do$(sp)x\ny\nend") == "f() do x\n y\nend"
@test format_string("f()$(sp)do\ny\nend") == "f() do\n y\nend"
@test format_string("f()$(sp)do; y end") == "f() do;\n y\nend"
# After `where` (anywhere else?) a newline can be used instead of a space
@test format_string("function f()\n return$(sp)1\nend") == "function f()\n return 1\nend"
@test format_string("function f()\n return$(sp)\nend") == "function f()\n return\nend"
for word in ("local", "global"), rhs in ("a", "a, b", "a = 1", "a, b = 1, 2")
word == "const" && rhs in ("a", "a, b") && continue
@test format_string("$(word)$(sp)$(rhs)") == "$(word) $(rhs)"
# After `local`, `global`, and `const` a newline can be used instead of a space
@test format_string("$(word)$(sp)\n$(sp)$(rhs)") == "$(word)\n $(rhs)"
end
@test_broken format_string("global\n\nx = 1") == "global\n\n x = 1" # TODO: Fix double peek
@test_broken format_string("lobal\n\nx = 1") == "local\n\n x = 1" # TODO: Fix double peek
@test format_string("const$(sp)x = 1") == "const x = 1"
# After `where` a newline can be used instead of a space
@test format_string("A$(sp)where$(sp)\n{A}") == "A where\n{A}"
end
@test format_string("try\nerror()\ncatch\nend") == "try\n error()\ncatch\nend"
Expand All @@ -504,6 +515,9 @@ end
# Some keywords can have a parenthesized expression directly after without the space...
@test format_string("if(a)\nelseif(b)\nend") == "if (a)\nelseif (b)\nend"
@test format_string("while(a)\nend") == "while (a)\nend"
@test format_string("function f()\n return(1)\nend") == "function f()\n return (1)\nend"
@test format_string("local(a)") == "local (a)"
@test format_string("global(a)") == "global (a)"
end

@testset "replace ∈ and = with in in for loops and generators" begin
Expand Down
Loading