data_beans/interactive/
mod.rs1pub mod cutoff_tui;
23pub mod stat_tui;
24pub mod ui;
25
26use std::io::{self, IsTerminal, Write};
27
28pub fn tui_available() -> bool {
31 io::stdin().is_terminal() && io::stdout().is_terminal()
32}
33
34pub const TOOL: legume_tui::Tool = legume_tui::Tool::new("data-beans");
38
39pub fn session_keys() -> Vec<(String, String)> {
43 legume_tui::help_keys()
44 .into_iter()
45 .map(|k| (k.key.to_lowercase(), k.short))
46 .collect()
47}
48
49pub fn session_help(lead: Option<&str>, more: &str) -> String {
56 let help = legume_tui::cli::SessionHelp::new()
57 .what_goes_on("the command goes on")
58 .resume_hint(Some(
59 "Starting it again starts a new one (naming the detached ones); \
60 `data-beans attach` with no name",
61 ))
62 .more(more);
63 let help = match lead {
64 Some(lead) => help.lead(lead),
65 None => help,
66 };
67 legume_tui::cli::session_help(&TOOL, help)
68}
69
70#[derive(Debug, Clone)]
72pub enum UserAction {
73 Proceed,
74 AdjustCutoffs(usize, usize),
75 Cancel,
76}
77
78pub fn prompt_user_action(
80 current_row_cutoff: usize,
81 current_col_cutoff: usize,
82) -> anyhow::Result<UserAction> {
83 println!("\nOptions:");
84 println!(" [p] Proceed with current cutoffs");
85 println!(" [a] Adjust cutoffs");
86 println!(" [c] Cancel");
87 print!("\nChoose an option (p/a/c): ");
88 io::stdout().flush()?;
89
90 let mut input = String::new();
91 io::stdin().read_line(&mut input)?;
92 let choice = input.trim().to_lowercase();
93
94 match choice.as_str() {
95 "p" | "proceed" | "y" | "yes" => Ok(UserAction::Proceed),
96 "c" | "cancel" | "n" | "no" => Ok(UserAction::Cancel),
97 "a" | "adjust" => {
98 let new_row_cutoff = prompt_cutoff_value("row", current_row_cutoff)?;
99 let new_col_cutoff = prompt_cutoff_value("column", current_col_cutoff)?;
100 Ok(UserAction::AdjustCutoffs(new_row_cutoff, new_col_cutoff))
101 }
102 _ => {
103 println!("Invalid choice. Cancelling operation.");
104 Ok(UserAction::Cancel)
105 }
106 }
107}
108
109fn prompt_cutoff_value(label: &str, current: usize) -> anyhow::Result<usize> {
111 print!("\nEnter new {} nnz cutoff (current: {}): ", label, current);
112 io::stdout().flush()?;
113
114 let mut input = String::new();
115 io::stdin().read_line(&mut input)?;
116
117 let value = input.trim().parse::<usize>().unwrap_or(current);
118 Ok(value)
119}
120
121pub fn confirm(message: &str) -> anyhow::Result<bool> {
123 print!("{} (y/n): ", message);
124 io::stdout().flush()?;
125
126 let mut input = String::new();
127 io::stdin().read_line(&mut input)?;
128 let choice = input.trim().to_lowercase();
129
130 Ok(matches!(choice.as_str(), "y" | "yes"))
131}
132
133#[cfg(test)]
134#[path = "tests/session.rs"]
135mod tests;