///|
priv struct MoonfmtOptions {
path : String
overwrite : Bool
}
///|
#cfg(target="native")
extern "C" fn exit(code : Int32) = "exit"
///|
#cfg(target="wasm")
fn exit(code : UInt32) = "wasi_snapshot_preview1" "proc_exit"
///|
async fn[T] die(message : String) -> T {
@stdio.stderr.write("\{message}\n") catch {
_ => ()
}
exit(1)
panic()
}
///|
async fn write_stdout(message : String) -> Unit {
@stdio.stdout.write(message) catch {
err => die("error: failed to write stdout: \{err}")
}
}
///|
async fn overwrite_if_changed(
path : String,
source : String,
result : String,
) -> Bool {
if source == result {
return false
}
@fs.write_file(path, result, create_mode=CreateOrTruncate, sync=Full)
true
}
///|
fn moonfmt_command() -> @argparse.Command {
Command(
"moonfmt",
about="Format a MoonBit source file.",
flags=[
FlagArg(
"overwrite",
short='w',
long="overwrite",
about="Overwrite the input file.",
),
],
positionals=[
PositionArg(
"path",
about="MoonBit source file to format.",
num_args=@argparse.ValueRange::single(),
),
],
)
}
///|
fn parse_moonfmt_args(args : ArrayView[String]) -> MoonfmtOptions raise {
let matches = moonfmt_command().parse(argv=args, env=Map([]))
let path = match matches.values.get("path") {
Some([path]) => path
_ => panic()
}
{ path, overwrite: matches.flags.get("overwrite").unwrap_or(false), }
}
///|
async fn moonfmt(args : ArrayView[String]) -> Unit {
let options = parse_moonfmt_args(args) catch { err => die("\{err}") }
let source = @fs.read_file(options.path).text() catch { err => die("\{err}") }
let result = @fmt.format(source)
if options.overwrite {
let second = @fmt.format(result)
if second != result {
die(
"error: formatter output is not stable; left `\{options.path}` unchanged",
)
}
ignore(overwrite_if_changed(options.path, source, result)) catch {
err => die("error: failed to overwrite `\{options.path}`: \{err}")
}
} else {
write_stdout(result)
}
}
///|
fn program_args() -> ArrayView[String] {
let args = @env.args()
if args.length() > 1 {
args[1:]
} else {
[]
}
}
///|
async fn main {
moonfmt(program_args())
}
///|
test "parse moonfmt args" {
let parsed = parse_moonfmt_args(["--overwrite", "input.mbt"]) catch {
_ => panic()
}
inspect(parsed.path, content="input.mbt")
inspect(parsed.overwrite, content="true")
let short = parse_moonfmt_args(["-w", "input.mbt"]) catch { _ => panic() }
inspect(short.path, content="input.mbt")
inspect(short.overwrite, content="true")
}