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}
end end
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 # # Utilities for IOBuffer #
########################## ##########################

12
src/main.jl

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

6
src/runestone.jl

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

5
test/runtests.jl

@ -711,6 +711,11 @@ end
# Functors # Functors
@test format_string("function$(sp)(a::A)(b)\nx\nend") == @test format_string("function$(sp)(a::A)(b)\nx\nend") ==
"function (a::A)(b)\n x\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
end end

Loading…
Cancel
Save