agentic_vision/cli/
repl.rs1use rustyline::error::ReadlineError;
4use rustyline::Editor;
5
6use super::repl_commands::ReplState;
7use super::repl_complete::{bind_keys, AvisHelper};
8use crate::types::VisionResult;
9
10fn history_path() -> std::path::PathBuf {
11 let home = std::env::var("HOME").unwrap_or_else(|_| ".".to_string());
12 std::path::PathBuf::from(home).join(".avis_history")
13}
14
15pub fn run() -> VisionResult<()> {
16 println!("avis -- AgenticVision interactive shell");
17 println!("Type /help for commands, /exit to quit.\n");
18
19 let helper = AvisHelper::new();
20 let mut rl = Editor::new()
21 .map_err(|e| crate::types::VisionError::Io(std::io::Error::other(e.to_string())))?;
22 rl.set_helper(Some(helper));
23 bind_keys(&mut rl);
24
25 let hist = history_path();
26 let _ = rl.load_history(&hist);
27
28 let mut state = ReplState::new();
29
30 loop {
31 let prompt = if let Some(ref p) = state.file_path {
32 format!(
33 "avis({})> ",
34 p.file_name().unwrap_or_default().to_string_lossy()
35 )
36 } else {
37 "avis> ".to_string()
38 };
39
40 match rl.readline(&prompt) {
41 Ok(line) => {
42 let line = line.trim().to_string();
43 if line.is_empty() {
44 continue;
45 }
46 rl.add_history_entry(&line).ok();
47 if let Err(e) = state.dispatch(&line) {
48 eprintln!("Error: {}", e);
49 }
50 }
51 Err(ReadlineError::Interrupted | ReadlineError::Eof) => {
52 println!("Goodbye.");
53 break;
54 }
55 Err(e) => {
56 eprintln!("Readline error: {}", e);
57 break;
58 }
59 }
60 }
61
62 let _ = rl.save_history(&hist);
63 Ok(())
64}