Skip to content

Commit

Permalink
Prune spaces around :, ^, and ::.
Browse files Browse the repository at this point in the history
  • Loading branch information
fredrikekre committed May 27, 2024
1 parent 1bb9480 commit d688710
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 20 deletions.
1 change: 1 addition & 0 deletions src/Runic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ function format_node!(ctx::Context, node::JuliaSyntax.GreenNode)::Union{JuliaSyn
@return_something format_float_literals(ctx, node)
@return_something spaces_around_operators(ctx, node)
@return_something spaces_around_assignments(ctx, node)
@return_something no_spaces_around_colon_etc(ctx, node)

# If the node is unchanged at this point, just keep going.

Expand Down
69 changes: 68 additions & 1 deletion src/runestone.jl
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,8 @@ function spaces_around_x(ctx::Context, node::JuliaSyntax.GreenNode, is_x::F) whe
end
end

# This pass handles spaces around infix operator calls and comparison chains
# This pass handles spaces around infix operator calls, comparison chains, and
# <: and >: operators.
function spaces_around_operators(ctx::Context, node::JuliaSyntax.GreenNode)
if !(
(is_infix_op_call(node) && !(JuliaSyntax.kind(infix_op_call_op(node)) in KSet": ^")) ||
Expand All @@ -289,3 +290,69 @@ function spaces_around_assignments(ctx::Context, node::JuliaSyntax.GreenNode)
is_x = x -> is_assignment(x) || JuliaSyntax.kind(x) === K"in"
return spaces_around_x(ctx, node, is_x)
end

# Opposite of `spaces_around_x`: remove spaces around `x`
function no_spaces_around_x(ctx::Context, node::JuliaSyntax.GreenNode, is_x::F) where F
@assert JuliaSyntax.haschildren(node)
# TODO: Can't handle NewlineWs here right now
if any(JuliaSyntax.kind(c) === K"NewlineWs" for c in JuliaSyntax.children(node))
return nothing
end

children = JuliaSyntax.children(node)::AbstractVector
children′ = children
any_changes = false
original_bytes = node_bytes(ctx, node)
span_sum = 0
pos = position(ctx.fmt_io)

looking_for_x = false

for (i, child) in pairs(children)
span_sum += JuliaSyntax.span(child)
if (i == 1 || i == length(children)) && JuliaSyntax.kind(child) === K"Whitespace"
accept_node!(ctx, child)
any_changes && push!(children′, child)
elseif JuliaSyntax.kind(child) === K"Whitespace"
# Ignore it but need to copy children and re-write bytes
any_changes = true
if children′ === children
children′ = children[1:i - 1]
end
remaining_bytes = @view original_bytes[(span_sum + 1):end]
write_and_reset(ctx, remaining_bytes)
else
@assert JuliaSyntax.kind(child) !== K"Whitespace"
if looking_for_x
@assert is_x(child)::Bool
end
any_changes && push!(children′, child)
accept_node!(ctx, child)
looking_for_x = !looking_for_x
end
end
# Reset stream
seek(ctx.fmt_io, pos)
if any_changes
# Create new node and return it
span′ = mapreduce(JuliaSyntax.span, +, children′; init = 0)
@assert span′ < JuliaSyntax.span(node)
node′ = JuliaSyntax.GreenNode(JuliaSyntax.head(node), span′, children′)
return node′
else
return nothing
end
end

# no spaces around `:`, `^`, and `::`
function no_spaces_around_colon_etc(ctx::Context, node::JuliaSyntax.GreenNode)
if !(
(is_infix_op_call(node) && JuliaSyntax.kind(infix_op_call_op(node)) in KSet": ^") ||
(JuliaSyntax.kind(node) === K"::" && !is_leaf(node))
)
return nothing
end
@assert JuliaSyntax.kind(node) in KSet"call ::"
is_x = x -> is_leaf(x) && JuliaSyntax.kind(x) in KSet": ^ ::"
return no_spaces_around_x(ctx, node, is_x)
end
30 changes: 11 additions & 19 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -116,24 +116,16 @@ end
"$(sp)sin(α) $(op) cos(β) $(op) tan(γ)$(sp)"
end
# Exceptions to the rule: `:` and `^`
if sp == ""
# a:b
@test format_string("$(sp)a$(sp):$(sp)b$(sp)") == "a:b"
@test format_string("$(sp)(1 + 2)$(sp):$(sp)(1 + 3)$(sp)") == "(1 + 2):(1 + 3)"
# a:b:c
@test format_string("$(sp)a$(sp):$(sp)b$(sp):$(sp)c$(sp)") == "a:b:c"
@test format_string("$(sp)(1 + 2)$(sp):$(sp)(1 + 3)$(sp):$(sp)(1 + 4)$(sp)") ==
"(1 + 2):(1 + 3):(1 + 4)"
# a^b
@test format_string("$(sp)a$(sp)^$(sp)b$(sp)") == "a^b"
else
@test_broken format_string("$(sp)a$(sp):$(sp)b$(sp)") == "a:b"
@test_broken format_string("$(sp)(1 + 2)$(sp):$(sp)(1 + 3)$(sp)") == "(1 + 2):(1 + 3)"
@test_broken format_string("$(sp)a$(sp):$(sp)b$(sp):$(sp)c$(sp)") == "a:b:c"
@test_broken format_string("$(sp)(1 + 2)$(sp):$(sp)(1 + 3)$(sp):$(sp)(1 + 4)$(sp)") ==
"(1 + 2):(1 + 3):(1 + 4)"
@test_broken format_string("$(sp)a$(sp)^$(sp)b$(sp)") == "a^b"
end
# a:b
@test format_string("$(sp)a$(sp):$(sp)b$(sp)") == "$(sp)a:b$(sp)"
@test format_string("$(sp)(1 + 2)$(sp):$(sp)(1 + 3)$(sp)") ==
"$(sp)(1 + 2):(1 + 3)$(sp)"
# a:b:c
@test format_string("$(sp)a$(sp):$(sp)b$(sp):$(sp)c$(sp)") == "$(sp)a:b:c$(sp)"
@test format_string("$(sp)(1 + 2)$(sp):$(sp)(1 + 3)$(sp):$(sp)(1 + 4)$(sp)") ==
"$(sp)(1 + 2):(1 + 3):(1 + 4)$(sp)"
# a^b
@test format_string("$(sp)a$(sp)^$(sp)b$(sp)") == "$(sp)a^b$(sp)"
end
end

Expand Down Expand Up @@ -178,7 +170,7 @@ end
# K"::"
@test format_string("a::T") == "a::T"
@test format_string("a::T::S") == "a::T::S"
@test_broken format_string("a :: T") == "a::T" # TODO: Eliminate spaces instead
@test format_string("a :: T") == "a::T"
# K"<:" and K">:"
@test format_string("a<:T") == "a <: T"
@test format_string("a>:T") == "a >: T"
Expand Down

0 comments on commit d688710

Please sign in to comment.