pub mod list_tui;
pub mod plan_tui;
pub mod qc_tui;
#[cfg(feature = "sim")]
pub mod sim_tui;
pub mod stat_tui;
pub mod ui;
use std::io::{self, IsTerminal};
pub const BATCH_ENV: &str = "DATA_BEANS_BATCH";
pub fn tui_available() -> bool {
can_draw(
io::stdin().is_terminal() && io::stdout().is_terminal(),
std::env::var("TERM").ok().as_deref(),
)
}
fn can_draw(tty: bool, term: Option<&str>) -> bool {
tty && term != Some("dumb")
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum NoView {
Batch,
NoTerminal,
}
fn decide(flag: bool, env: Option<&str>, terminal: bool) -> Result<(), NoView> {
let asked = flag || env.is_some_and(|v| !v.is_empty() && v != "0");
match (asked, terminal) {
(true, _) => Err(NoView::Batch),
(false, false) => Err(NoView::NoTerminal),
(false, true) => Ok(()),
}
}
fn decide_here(flag: bool) -> Result<(), NoView> {
decide(
flag,
std::env::var(BATCH_ENV).ok().as_deref(),
tui_available(),
)
}
fn no_terminal_line(command: &str) -> String {
format!(
"{command}: no terminal to draw a view on (stdin or stdout is not one, or \
TERM=dumb): running straight through; --batch-process or {BATCH_ENV}=1 \
does this without this line"
)
}
pub fn opens_view(command: &str, batch: bool) -> bool {
match decide_here(batch) {
Ok(()) => true,
Err(NoView::Batch) => false,
Err(NoView::NoTerminal) => {
eprintln!("{}", no_terminal_line(command));
false
}
}
}
pub fn picks(command: &str, batch: bool, selected: bool, options: &str) -> anyhow::Result<bool> {
if selected {
return Ok(false);
}
match decide_here(batch) {
Ok(()) => Ok(true),
Err(why) => anyhow::bail!("{}", pick_refused(command, options, why)),
}
}
fn pick_refused(command: &str, options: &str, why: NoView) -> String {
match why {
NoView::Batch => {
format!("{command}: give {options}; run in batch, it has no view to pick them in")
}
NoView::NoTerminal => {
format!("{command}: give {options}, or run it on a terminal to pick them in a view")
}
}
}
pub const TOOL: legume_tui::Tool = legume_tui::Tool::new("data-beans");
pub fn session_keys() -> Vec<(String, String)> {
legume_tui::help_keys()
.into_iter()
.map(|k| (k.key.to_lowercase(), k.short))
.collect()
}
pub fn session_help(lead: Option<&str>, more: &str) -> String {
let help = legume_tui::cli::SessionHelp::new()
.what_goes_on("the command goes on")
.resume_hint(Some(
"Starting it again starts a new one (naming the detached ones); \
`data-beans attach` with no name",
))
.more(more);
let help = match lead {
Some(lead) => help.lead(lead),
None => help,
};
legume_tui::cli::session_help(&TOOL, help)
}
#[cfg(test)]
#[path = "tests/session.rs"]
mod tests;