use std::{io, path::Path, time::Duration};
use omp_tui::{AppOptions, Key, Ui, UiContext, dom};
fn build(source: &str, width: u16, ctx: &UiContext) -> Ui {
match Ui::from_markup(source, width, ctx.clone()) {
Ok(ui) => ui,
Err(error) => {
let message = error.to_string();
Ui::from_root(
dom! {
<box border=round bc=err title="parse error" pad="0 1">
<text fg=err>{message}</text>
</box>
},
width,
ctx.clone(),
)
},
}
}
fn modified(path: &Path) -> Option<std::time::SystemTime> {
std::fs::metadata(path)
.and_then(|meta| meta.modified())
.ok()
}
#[tokio::main]
async fn main() -> io::Result<()> {
let path = std::env::args()
.nth(1)
.unwrap_or_else(|| "example.tml".into());
let source = std::fs::read_to_string(&path)?;
let mut ctx = None;
let mut app = AppOptions::new()
.quit([Key::Ctrl('c'), Key::Char('q'), Key::Esc])
.start(|env| {
let ui = build(&source, env.viewport.width, &env.ctx);
ctx = Some(env.ctx);
ui
})
.await?;
let ctx = ctx.expect("start ran the builder");
let handle = app.handle();
tokio::spawn(async move {
let mut seen = modified(path.as_ref());
loop {
tokio::time::sleep(Duration::from_millis(150)).await;
let stamp = modified(path.as_ref());
if stamp == seen {
continue;
}
seen = stamp;
let Ok(source) = std::fs::read_to_string(&path) else {
continue;
};
let ctx = ctx.clone();
handle.update(move |ui| *ui = build(&source, ui.frame().size().width, &ctx));
}
});
while app.next().await?.is_some() {}
Ok(())
}