agentic_codebase/cli/
repl.rs1use crate::cli::output::Styled;
7use crate::cli::repl_commands;
8use crate::cli::repl_complete;
9use rustyline::config::CompletionType;
10use rustyline::error::ReadlineError;
11use rustyline::{Config, Editor};
12
13fn history_path() -> std::path::PathBuf {
15 let home = std::env::var("HOME")
16 .or_else(|_| std::env::var("USERPROFILE"))
17 .unwrap_or_else(|_| ".".to_string());
18 std::path::PathBuf::from(home).join(".acb_history")
19}
20
21fn print_banner() {
23 let s = Styled::auto();
24
25 eprintln!();
26 eprintln!(
27 " {} {} {}",
28 s.green("\u{25c9}"),
29 s.bold(&format!("acb v{}", env!("CARGO_PKG_VERSION"))),
30 s.dim("\u{2014} Semantic Code Compiler for AI Agents")
31 );
32 eprintln!();
33 eprintln!(
34 " Press {} to browse commands, {} to complete, {} to quit.",
35 s.cyan("/"),
36 s.dim("Tab"),
37 s.dim("/exit")
38 );
39 eprintln!();
40}
41
42pub fn run() -> Result<(), Box<dyn std::error::Error>> {
44 print_banner();
45
46 let config = Config::builder()
48 .history_ignore_space(true)
49 .auto_add_history(true)
50 .completion_type(CompletionType::List)
51 .completion_prompt_limit(20)
52 .build();
53
54 let helper = repl_complete::AcbHelper::new();
55 let mut rl: Editor<repl_complete::AcbHelper, rustyline::history::DefaultHistory> =
56 Editor::with_config(config)?;
57 rl.set_helper(Some(helper));
58
59 repl_complete::bind_keys(&mut rl);
61
62 let hist_path = history_path();
64 if hist_path.exists() {
65 let _ = rl.load_history(&hist_path);
66 }
67
68 let mut state = repl_commands::ReplState::new();
70
71 let prompt = if Styled::auto().ok() == "OK" {
73 " acb> ".to_string()
74 } else {
75 " \x1b[36macb>\x1b[0m ".to_string()
76 };
77
78 loop {
80 match rl.readline(&prompt) {
81 Ok(line) => {
82 let line = line.trim();
83 if line.is_empty() {
84 continue;
85 }
86
87 match repl_commands::execute(line, &mut state) {
88 Ok(true) => {
89 let s = Styled::auto();
90 eprintln!(" {} Goodbye!", s.dim("\u{2728}"));
91 break;
92 }
93 Ok(false) => {}
94 Err(e) => {
95 let s = Styled::auto();
96 eprintln!(" {} {e}", s.fail());
97 }
98 }
99 }
100 Err(ReadlineError::Interrupted) => {
101 let s = Styled::auto();
102 eprintln!(" {} Type {} to quit.", s.dim("(Ctrl+C)"), s.bold("/exit"));
103 }
104 Err(ReadlineError::Eof) => {
105 let s = Styled::auto();
106 eprintln!(" {} Goodbye!", s.dim("\u{2728}"));
107 break;
108 }
109 Err(err) => {
110 eprintln!(" Error: {err}");
111 break;
112 }
113 }
114 }
115
116 let _ = std::fs::create_dir_all(hist_path.parent().unwrap_or(std::path::Path::new(".")));
118 let _ = rl.save_history(&hist_path);
119
120 Ok(())
121}