feat(cli): readline history

This commit is contained in:
Khaïs COLIN 2025-05-10 10:20:26 +02:00
parent fe66326956
commit 9b75cb6144
Signed by: logistic-bot
SSH key fingerprint: SHA256:3zI3/tx0ZpCLHCLPmEaGR4oeYCPMCzQxXhXutBmtOAU
3 changed files with 58 additions and 9 deletions

View file

@ -189,24 +189,24 @@ CLOCK: [2025-05-04 dim. 14:01]--[2025-05-04 dim. 14:14] => 0:13
* DONE remove old FromStr parser implementation * DONE remove old FromStr parser implementation
* TODO use a better readline impl * DONE use a better readline impl
** DONE inform myself on the different alternatives and decide on one ** DONE inform myself on the different alternatives and decide on one
i will use rustyline, since it seems like the most feature-complete i will use rustyline, since it seems like the most feature-complete
** DONE do the impl ** DONE do the impl
** TODO make history work ** DONE make history work
*** DONE have the rl instance be spawned from main *** DONE have the rl instance be spawned from main
*** TODO figure out how to locate the app data directory on linux *** DONE figure out how to locate the app data directory on linux
*** TODO create our own app data directory *** DONE create our own app data directory
*** TODO load and save the history from a file in this directory *** DONE load and save the history from a file in this directory
* TODO handle non-interactive input better * DONE handle non-interactive input better
* TODO cli tests using insta-cmd * TODO cli tests using insta-cmd
https://insta.rs/docs/cmd/ https://insta.rs/docs/cmd/

View file

@ -1,5 +1,46 @@
use rustyline::{Editor, history::FileHistory}; use std::path::PathBuf;
use rustyline::{history::FileHistory, Editor};
fn xdg_state_dir() -> Option<PathBuf> {
if let Ok(dir) = std::env::var("XDG_STATE_DIR") {
Some(PathBuf::from(dir))
} else if let Ok(home) = std::env::var("HOME") {
if home.is_empty() {
None
} else {
Some(PathBuf::from(home).join(".local/state"))
}
} else {
None
}
}
fn state_dir() -> Option<PathBuf> {
if let Some(dir) = xdg_state_dir() {
let dir = dir.join("osdb");
std::fs::create_dir_all(&dir).ok()?;
Some(dir)
} else {
None
}
}
pub fn history_file() -> Option<std::path::PathBuf> {
if let Some(state) = state_dir() {
Some(state.join("cli_history"))
} else {
eprintln!("Warning: failed to find or create XDG_STATE_DIR for osdb.");
eprintln!("Warning: either set XDG_STATE_DIR or HOME, and ensure osdb has write permissions to that directory.");
None
}
}
pub fn read_input(rl: &mut Editor<(), FileHistory>) -> Option<String> { pub fn read_input(rl: &mut Editor<(), FileHistory>) -> Option<String> {
rl.readline("osdb> ").ok() if let Ok(result) = rl.readline("osdb> ") {
let _ = rl.add_history_entry(&result);
Some(result)
} else {
None
}
} }

View file

@ -1,10 +1,14 @@
use osdb::branding::startup_msg; use osdb::branding::startup_msg;
use osdb::cli::read_input; use osdb::cli::{history_file, read_input};
use osdb::error_display::OSDBError as _; use osdb::error_display::OSDBError as _;
use osdb::parser::parse; use osdb::parser::parse;
fn main() { fn main() {
let mut rl = rustyline::DefaultEditor::new().expect("failed to create stdin reader"); let mut rl = rustyline::DefaultEditor::new().expect("failed to create stdin reader");
let history_file = history_file();
if let Some(history_file) = &history_file {
let _ = rl.load_history(history_file);
}
println!("{}", startup_msg()); println!("{}", startup_msg());
@ -29,5 +33,9 @@ fn main() {
} }
} }
if let Some(history_file) = &history_file {
let _ = rl.save_history(history_file);
}
println!("Good-bye"); println!("Good-bye");
} }