Browse Source

Multiline list classification: recurse into multiline triple strings

pull/30/head
Fredrik Ekre 1 year ago
parent
commit
836d498c2d
No known key found for this signature in database
GPG Key ID: DE82E6D5E364C0A2
  1. 70
      src/chisels.jl
  2. 12
      src/main.jl
  3. 6
      src/runestone.jl
  4. 5
      test/runtests.jl

70
src/chisels.jl

@ -471,6 +471,76 @@ function any_leaf(pred::F, node::Node) where {F} @@ -471,6 +471,76 @@ function any_leaf(pred::F, node::Node) where {F}
end
end
# TODO: Alternative non-recursive definition that only looks at the current layer
# ```
# contains_outer_newline(kids, opening_leaf_idx, closing_leaf_idx)
# ```
function is_multiline_between_idxs(ctx, node::Node, opening_idx::Int, closing_idx::Int)
@assert !is_leaf(node)
kids = verified_kids(node)
# Check for newline nodes
if any(y -> any_leaf(x -> kind(x) === K"NewlineWs", kids[y]), (opening_idx + 1):(closing_idx - 1))
return true
end
# Recurse into multiline triple-strings
pos = position(ctx.fmt_io)
for i in 1:opening_idx
accept_node!(ctx, kids[i])
end
for i in (opening_idx + 1):(closing_idx - 1)
kid = kids[i]
ipos = position(ctx.fmt_io)
if contains_multiline_triple_string(ctx, kid)
seek(ctx.fmt_io, pos)
return true
end
seek(ctx.fmt_io, ipos)
accept_node!(ctx, kid)
end
seek(ctx.fmt_io, pos)
return false
end
function contains_multiline_triple_string(ctx, node::Node)
# If this is a leaf just advance the stream
if is_leaf(node)
accept_node!(ctx, node)
return false
end
kids = verified_kids(node)
pos = position(ctx.fmt_io)
# If this is a triple string we inspect it
if kind(node) in KSet"string cmdstring" && JuliaSyntax.has_flags(node, JuliaSyntax.TRIPLE_STRING_FLAG)
triplekind, triplestring, itemkind = kind(node) === K"string" ?
(K"\"\"\"", "\"\"\"", K"String") : (K"```", "```", K"CmdString")
# Look for K"String"s ending in `\n`
for (i, kid) in pairs(kids)
if i === firstindex(kids) || i === lastindex(kids)
@assert kind(kid) === triplekind
@assert String(read_bytes(ctx, kid)) == triplestring
end
if kind(kid) === itemkind
if endswith(String(read_bytes(ctx, kid)), "\n")
return true
end
else
accept_node!(ctx, kid)
end
end
@assert position(ctx.fmt_io) == pos + span(node)
else
for kid in kids
kpos = position(ctx.fmt_io)
if contains_multiline_triple_string(ctx, kid)
return true
end
seek(ctx.fmt_io, kpos)
accept_node!(ctx, kid)
end
end
return false
end
##########################
# Utilities for IOBuffer #
##########################

12
src/main.jl

@ -35,12 +35,15 @@ function print_help() @@ -35,12 +35,15 @@ function print_help()
println(io, " julia -m Runic [<options>] <path>...")
println(io)
printstyled(io, "DESCRIPTION\n", bold = true)
println(io, """
println(
io, """
`Runic.main` (typically invoked as `julia -m Runic`) formats Julia source
code using the Runic.jl formatter.
""")
""",
)
printstyled(io, "OPTIONS\n", bold = true)
println(io, """
println(
io, """
<path>...
Input path(s) (files and/or directories) to process. For directories,
all files (recursively) with the '*.jl' suffix are used as input files.
@ -69,7 +72,8 @@ function print_help() @@ -69,7 +72,8 @@ function print_help()
Output file to write formatted code to. If the specified file is `-`
output is written to stdout. This option can not be used together with
multiple input paths.
""")
""",
)
return
end

6
src/runestone.jl

@ -387,7 +387,8 @@ function spaces_in_listlike(ctx::Context, node::Node) @@ -387,7 +387,8 @@ function spaces_in_listlike(ctx::Context, node::Node)
# Multiline lists require leading and trailing newline
# multiline = contains_outer_newline(kids, opening_leaf_idx, closing_leaf_idx)
multiline = any(y -> any_leaf(x -> kind(x) === K"NewlineWs", kids[y]), (opening_leaf_idx + 1):(closing_leaf_idx - 1))
# multiline = any(y -> any_leaf(x -> kind(x) === K"NewlineWs", kids[y]), (opening_leaf_idx + 1):(closing_leaf_idx - 1))
multiline = is_multiline_between_idxs(ctx, node, opening_leaf_idx, closing_leaf_idx)
is_named_tuple = kind(node) === K"tuple" && n_items == 1 && kind(kids[first_item_idx]) === K"parameters"
@ -2126,7 +2127,8 @@ function indent_listlike( @@ -2126,7 +2127,8 @@ function indent_listlike(
open_idx == close_idx && return nothing
# Check whether we expect leading/trailing newlines
# multiline = contains_outer_newline(kids, open_idx, close_idx)
multiline = any(y -> any_leaf(x -> kind(x) === K"NewlineWs", kids[y]), (open_idx + 1):(close_idx - 1))
# multiline = any(y -> any_leaf(x -> kind(x) === K"NewlineWs", kids[y]), (open_idx + 1):(close_idx - 1))
multiline = is_multiline_between_idxs(ctx, node, open_idx, close_idx)
if !multiline
# TODO: This should be fine? If there are no newlines it should be safe to just
# don't indent anything in this node?

5
test/runtests.jl

@ -711,6 +711,11 @@ end @@ -711,6 +711,11 @@ end
# Functors
@test format_string("function$(sp)(a::A)(b)\nx\nend") ==
"function (a::A)(b)\n x\nend"
# Multiline strings inside lists
for trip in ("\"\"\"", "```")
@test format_string("println(io, $(trip)\n$(sp)a\n$(sp)\n$(sp)b\n$(sp)$(trip))") ==
"println(\n io, $(trip)\n a\n\n b\n $(trip),\n)"
end
end
end

Loading…
Cancel
Save