use std::process::ExitCode;
use conch_shell_core::{Shell, exec_command_list};
use conch_shell_parser::parse;
use rustyline::DefaultEditor;
use rustyline::error::ReadlineError;
fn main() -> ExitCode {
let mut shell = Shell::new();
conch_shell_builtins::register_all(&mut shell);
let args: Vec<String> = std::env::args().skip(1).collect();
let status = match args.first().map(String::as_str) {
Some("-c") => {
let Some(command) = args.get(1) else {
eprintln!("conch: -c requires a command string");
return ExitCode::from(2);
};
run_source(command, &mut shell)
}
Some(script_path) => match std::fs::read_to_string(script_path) {
Ok(source) => run_source(&source, &mut shell),
Err(err) => {
eprintln!("conch: {script_path}: {err}");
127
}
},
None => run_interactive(&mut shell),
};
ExitCode::from(status.rem_euclid(256) as u8)
}
fn run_source(source: &str, shell: &mut Shell) -> i32 {
match parse(source) {
Ok(list) => exec_command_list(&list, shell),
Err(err) => {
eprintln!("conch: {err}");
2
}
}
}
fn run_interactive(shell: &mut Shell) -> i32 {
let mut editor = match DefaultEditor::new() {
Ok(editor) => editor,
Err(err) => {
eprintln!("conch: failed to start line editor: {err}");
return 1;
}
};
loop {
let prompt = format!("conch {} $ ", shell.cwd.display());
match editor.readline(&prompt) {
Ok(line) => {
if line.trim().is_empty() {
continue;
}
let _ = editor.add_history_entry(line.as_str());
match parse(&line) {
Ok(list) => {
shell.last_status = exec_command_list(&list, shell);
}
Err(err) => eprintln!("conch: {err}"),
}
}
Err(ReadlineError::Interrupted) => {
continue;
}
Err(ReadlineError::Eof) => {
break;
}
Err(err) => {
eprintln!("conch: {err}");
break;
}
}
}
shell.last_status
}