Browse Source

main: help message, check mode

pull/19/head
Fredrik Ekre 2 years ago
parent
commit
32ba9d345b
No known key found for this signature in database
GPG Key ID: DE82E6D5E364C0A2
  1. 11
      src/Runic.jl
  2. 128
      src/main.jl

11
src/Runic.jl

@ -36,6 +36,8 @@ mutable struct Context
verbose::Bool verbose::Bool
assert::Bool assert::Bool
debug::Bool debug::Bool
check::Bool
diff::Bool
# Current state # Current state
# node::Union{JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}, Nothing} # node::Union{JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}, Nothing}
prev_sibling::Union{JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}, Nothing} prev_sibling::Union{JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}, Nothing}
@ -43,7 +45,10 @@ mutable struct Context
# parent::Union{JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}, Nothing} # parent::Union{JuliaSyntax.GreenNode{JuliaSyntax.SyntaxHead}, Nothing}
end end
function Context(src_str; assert::Bool = true, debug::Bool = false, verbose::Bool = debug) function Context(
src_str; assert::Bool = true, debug::Bool = false, verbose::Bool = debug,
diff::Bool = false, check::Bool = false,
)
src_io = IOBuffer(src_str) src_io = IOBuffer(src_str)
src_tree = JuliaSyntax.parseall(JuliaSyntax.GreenNode, src_str; ignore_warnings = true) src_tree = JuliaSyntax.parseall(JuliaSyntax.GreenNode, src_str; ignore_warnings = true)
fmt_io = IOBuffer() fmt_io = IOBuffer()
@ -52,8 +57,8 @@ function Context(src_str; assert::Bool = true, debug::Bool = false, verbose::Boo
verbose = debug ? true : verbose verbose = debug ? true : verbose
assert = debug ? true : assert assert = debug ? true : assert
return Context( return Context(
src_str, src_tree, src_io, fmt_io, fmt_tree, verbose, assert, debug, nothing, src_str, src_tree, src_io, fmt_io, fmt_tree,
nothing, verbose, assert, debug, check, diff, nothing, nothing,
) )
end end

128
src/main.jl

@ -20,65 +20,147 @@ function panic(msg...)
return errno return errno
end end
# Print a typical cli program help message
function print_help()
io = stdout
printstyled(io, "NAME\n", bold = true)
println(io, " Runic.main - format Julia source code")
println(io)
printstyled(io, "SYNOPSIS\n", bold = true)
println(io, " julia -m Runic [<options>] <path>...")
println(io)
printstyled(io, "DESCRIPTION\n", bold = true)
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, """
<path>...
Input path(s) (files and/or directories) to process. For directories,
all files (recursively) with the '*.jl' suffix are used as input files.
If no path is given, or if path is `-`, input is read from stdin.
-c, --check
Do not write output and exit with a non-zero code if the input is not
formatted correctly.
-d, --diff
Print the diff between the input and formatted output to stderr.
Requires `git` or `diff` to be installed.
--help
Print this message.
-i, --inplace
Edit files in place. This option is required when passing multiple input
paths.
-o, --output <file>
Output file to write formatted code to. If no output file is given, or
if the specified file is `-`, output is written to stdout. This option
can not be used together with multiple input paths.
""")
return
end
function maybe_expand_directory!(outfiles, dir)
if !isdir(dir)
# Assumed a file, checked when using it
push!(outfiles, dir)
return
end
for (root, _, files) in walkdir(dir; onerror = (err) -> nothing)
for file in files
if endswith(file, ".jl")
push!(outfiles, joinpath(root, file))
end
end
end
end
function main(argv) function main(argv)
# Reset errno # Reset errno
global errno = 0 global errno = 0
# Split argv entries with `=`
argv = mapreduce(x -> split(x, "="; limit = 2), append!, argv; init = String[])
# Default values # Default values
inputfiles = String[] inputfiles = String[]
outputfile = nothing outputfile = nothing
verbose = false verbose = false
debug = false debug = false
inplace = false inplace = false
diff = false
check = false
# Parse the arguments # Parse the arguments
while length(argv) > 0 while length(argv) > 0
x = popfirst!(argv) x = popfirst!(argv)
if x == "-i" if x == "-i" || x == "--inplace"
inplace = true inplace = true
elseif x == "-v" elseif x == "-v" || x == "--verbose"
verbose = true verbose = true
elseif x == "-vv" elseif x == "-d" || x == "--diff"
diff = true
elseif x == "c" || x == "--check"
check = true
elseif x == "-vv" || x == "--debug"
debug = verbose = true debug = verbose = true
elseif x == "-o" elseif x == "-o" || x == "--output"
if length(argv) < 1 if length(argv) < 1
return panic("expected output file as argument after `-o`") return panic("expected output file as argument after `-o, --output`")
end end
outputfile = popfirst!(argv) outputfile = popfirst!(argv)
else else
# Remaining arguments must be inputfile(s) # Remaining arguments must be inputfile(s)
push!(inputfiles, x) maybe_expand_directory!(inputfiles, x)
for x in argv for x in argv
if x == "-" if x == "-"
return panic("input \"-\" can not be used with multiple files") return panic("input `-` can not be used with multiple files")
else
maybe_expand_directory!(inputfiles, x)
end end
push!(inputfiles, x)
end end
break break
end end
end end
# one of --check, --diff, --inplace, or --output must be specified
if !(inplace || check || diff || outputfile !== nothing)
return panic(
"at least one of options `-c, --check`, `-d, --diff`, `-i, --inplace`, " *
"or `-o, --output` must be specified",
)
end
# --check can not be used with --inplace
if inplace && check
return panic("options `-c, --check` and `-i, --inplace` are mutually exclusive")
end
# stdin is the default input # stdin is the default input
if isempty(inputfiles) if isempty(inputfiles)
push!(inputfiles, "-") push!(inputfiles, "-")
end end
# multiple files require -i and no -o # multiple files require --inplace or --check and no --output
if length(inputfiles) > 1 if length(inputfiles) > 1
if !inplace if !(inplace || check)
return panic("option `-i` is required for multiple input files") return panic("option `-i, --inplace` or `-c, --check` is required for multiple input files")
elseif outputfile !== nothing elseif outputfile !== nothing
return panic("option `-o` is incompatible with multiple input files") return panic("option `-o, --output` can not be used together with multiple input files")
end end
end end
# inplace = true is incompatible with given output # --inplace can not be used when specifying output
if inplace && outputfile !== nothing if inplace && outputfile !== nothing
@assert length(inputfiles) == 1 @assert length(inputfiles) == 1
return panic("option `-i` is incompatible with option `-o $(outputfile)`") return panic("options `-i, --inplace` and `-o, --output` are mutually exclusive")
end end
# inplace = true is incompatible with stdin as input # --inplace is incompatible with stdin as input
if inplace && first(inputfiles) == "-" if inplace && first(inputfiles) == "-"
return panic("option `-i` is incompatible with stdin as input") return panic("option `-i` is incompatible with stdin as input")
end end
@ -113,6 +195,9 @@ function main(argv)
@assert input_is_file @assert input_is_file
# @assert length(inputfiles) == 1 # checked above # @assert length(inputfiles) == 1 # checked above
output = inputfile output = inputfile
elseif check
@assert outputfile === nothing
output = devnull
else else
@assert length(inputfiles) == 1 @assert length(inputfiles) == 1
if outputfile === nothing || outputfile == "-" if outputfile === nothing || outputfile == "-"
@ -126,7 +211,7 @@ function main(argv)
# Call the library to format the text # Call the library to format the text
ctx = try ctx = try
ctx = Context(sourcetext; verbose = verbose, debug = debug) ctx = Context(sourcetext; verbose = verbose, debug = debug, diff = diff, check = check)
format_tree!(ctx) format_tree!(ctx)
ctx ctx
catch err catch err
@ -134,9 +219,13 @@ function main(argv)
continue continue
end end
# Write the output, but skip if inplace and it didn't change # Output the result
changed = ctx.fmt_tree !== ctx.src_tree changed = ctx.fmt_tree !== ctx.src_tree
if changed || !inplace if check
if changed
global errno = 1
end
elseif changed || !inplace
try try
write(output, take!(ctx.fmt_io)) write(output, take!(ctx.fmt_io))
catch err catch err
@ -145,6 +234,9 @@ function main(argv)
else else
# Log if verbose perhaps # Log if verbose perhaps
end end
if diff
error("todo")
end
end # inputfile loop end # inputfile loop

Loading…
Cancel
Save