// The status of the `watch` command (upstream `typst-cli/src/watch.rs`, its
// `Status`). It is a file of its own because `compile_once` prints it on
// every target, while `watch` itself only exists where files can be
// watched (`watch.mbt`, `watch_unsupported.mbt`).
///|
/// The status in which the watcher can be.
priv enum Status {
Compiling
/// (The duration in nanoseconds.)
Success(Int64)
/// (The duration in nanoseconds.)
PartialSuccess(Int64)
Error
}
///|
/// Clear the terminal and render the status message.
fn Status::print(self : Status, config : CompileConfig) -> Unit {
let out = terminal_out()
if config.fullscreen {
self.print_fullscreen(out, config)
} else {
self.print_message(out)
if !(self is Compiling) {
out.write("\n")
}
}
flush_terminal(out)
}
///|
fn Status::print_fullscreen(
self : Status,
out : @kit.ColorWriter,
config : CompileConfig,
) -> Unit {
let color = self.color()
clear_screen(out)
out.set_color(color)
out.write("watching")
out.reset()
match config.input {
Stdin => out.writeln(" ")
Path(path) => out.writeln(" \{path}")
}
out.set_color(color)
out.write("writing to")
out.reset()
out.writeln(" \{config.output.to_string()}")
// (Upstream prints "serving at" here if it serves the output over HTTP.)
out.write("\n")
self.print_message(out)
out.write("\n")
}
///|
fn Status::print_message(self : Status, out : @kit.ColorWriter) -> Unit {
let timestamp = local_time(@platform.now_ms())
out.writeln("[\{timestamp}] \{self.message()}")
}
///|
fn Status::message(self : Status) -> String {
match self {
Compiling => "compiling ..."
Success(duration) =>
"compiled successfully in \{@library.format_duration(duration)}"
PartialSuccess(duration) =>
"compiled with warnings in \{@library.format_duration(duration)}"
Error => "compiled with errors"
}
}
///|
fn Status::color(self : Status) -> @kit.ColorSpec {
match self {
Error => header_error_style()
PartialSuccess(_) => header_warning_style()
_ => header_note_style()
}
}
///|
/// The local time of day as `%H:%M:%S`
/// (`chrono::offset::Local::now().format("%H:%M:%S")`), given the
/// milliseconds since the UNIX epoch.
fn local_time(now_ms : Int64) -> String {
let secs = floor_div(now_ms, 1000L)
time_of_day(secs + @platform.local_offset(secs).to_int64())
}
///|
/// The time of day of a number of seconds since some midnight, as
/// `%H:%M:%S`.
fn time_of_day(secs : Int64) -> String {
let of_day = secs - floor_div(secs, 86400L) * 86400L
let two = (n : Int64) => if n < 10L { "0\{n}" } else { n.to_string() }
"\{two(of_day / 3600L)}:\{two(of_day % 3600L / 60L)}:\{two(of_day % 60L)}"
}
///|
/// Division rounding towards negative infinity.
fn floor_div(a : Int64, b : Int64) -> Int64 {
let q = a / b
if a % b != 0L && (a < 0L) != (b < 0L) {
q - 1L
} else {
q
}
}