use abstracttui::app::{request_screenshot, App, Driver, RunConfig};
use abstracttui::prelude::*;
use abstracttui::render::Screenshot;
use abstracttui::testing::CaptureTerm;
use abstracttui::ui::text;
fn scene(cx: Scope, quitter: Quitter, note: Signal<String>) -> View {
let theme = use_theme(cx);
Element::new()
.style(LayoutStyle::column().padding(Edges::all(1)))
.shortcut(KeyChord::plain(Key::Char('q')), move |_| quitter.quit())
.shortcut(KeyChord::plain(Key::Char('s')), move |_| {
request_screenshot(move |shot| {
let stem = std::env::temp_dir().join("screenshot-demo");
let mut wrote = Vec::new();
for (ext, result) in [
("txt", shot.write_text(stem.with_extension("txt"))),
("ansi", shot.write_ansi(stem.with_extension("ansi"))),
("svg", shot.write_svg(stem.with_extension("svg"))),
] {
match result {
Ok(()) => wrote.push(ext),
Err(e) => {
note.set(format!("write failed ({ext}): {e}"));
return;
}
}
}
note.set(format!(
"wrote screenshot-demo.{{{}}} in {}",
wrote.join(","),
stem.parent()
.map(|p| p.display().to_string())
.unwrap_or_default(),
));
});
})
.child(dyn_view(LayoutStyle::default().grow(1.0), move || {
let t = theme.get().tokens;
Block::new()
.border(BorderKind::Rounded)
.title("screenshot")
.fill(t.surface)
.layout(LayoutStyle::column().gap(1).padding(Edges::all(1)))
.child(text("A themed scene worth capturing: 世界 🚀"))
.child(dyn_view(LayoutStyle::line(2), move || text(note.get())))
.child(text("s · capture q · quit"))
.element(&t)
.build()
}))
.build()
}
fn main() -> abstracttui::base::Result<()> {
if !abstracttui::term::have_tty() {
return headless_demo();
}
let mut app = App::new(Size::new(72, 12));
let quitter = app.quitter();
app.mount(move |cx| {
let note = cx.signal(String::from("press s to capture"));
scene(cx, quitter, note)
})?;
app.run()
}
fn headless_demo() -> abstracttui::base::Result<()> {
let size = Size::new(72, 12);
let mut app = App::new(size);
let quitter = app.quitter();
app.mount(move |cx| {
let note = cx.signal(String::from("headless capture"));
scene(cx, quitter, note)
})?;
let mut term = CaptureTerm::new(size);
let caps = abstracttui::term::Capabilities::with(|c| {
c.truecolor = true;
c.colors_256 = true;
});
let cfg = RunConfig {
caps: Some(caps),
enter: None,
probe: false,
};
let mut driver = Driver::new(&mut app, &mut term, cfg)?;
for _ in 0..16 {
if driver.turn(&mut app, &mut term)?.idle {
break;
}
}
let from_frame: Screenshot = driver.screenshot();
let from_bytes: Screenshot = term.screen().screenshot();
assert_eq!(
from_frame.to_text(),
from_bytes.to_text(),
"both capture surfaces must agree"
);
let stem = std::env::temp_dir().join("screenshot-demo");
from_frame.write_text(stem.with_extension("txt"))?;
from_frame.write_ansi(stem.with_extension("ansi"))?;
from_frame.write_svg(stem.with_extension("svg"))?;
println!(
"screenshot: headless capture ok — wrote {}.{{txt,ansi,svg}} ({}x{})",
stem.display(),
from_frame.width(),
from_frame.height()
);
Ok(())
}