mod git; mod parser; use clap::Parser; use parser::*; use rustyline::{error::ReadlineError, DefaultEditor}; use std::{io, ops::ControlFlow}; use thiserror::Error; /// Shackle Shell - A replacement for git-shell with repo management commands built in. #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] struct Args { /// Run a single shell command and exit #[arg(short, long)] command: Option, } fn main() -> Result<(), ShackleError> { let args = Args::parse(); match args.command { Some(user_input) => { run_command(user_input)?; } None => { run_interactive_loop()?; } } Ok(()) } fn run_command(user_input: String) -> Result, ShackleError> { match user_input.parse::() { Err(parse_error) => { println!("{}", parse_error); } Ok(ShackleCommand::Whitespace) => {} Ok(ShackleCommand::Exit) => { return Ok(ControlFlow::Break(())); } Ok(ShackleCommand::GitInit(GitInitArgs { repo_name })) => { git::init(&repo_name)?; println!("Successfully created \"{}.git\"", repo_name); } Ok(ShackleCommand::GitUploadPack(upload_pack_args)) => { git::upload_pack(&upload_pack_args)?; } Ok(ShackleCommand::GitReceivePack(receive_pack_args)) => { git::receive_pack(&receive_pack_args)?; } } Ok(ControlFlow::Continue(())) } fn run_interactive_loop() -> Result<(), ShackleError> { let mut rl = DefaultEditor::new()?; loop { let readline = rl.readline("> "); match readline { Ok(user_input) => { rl.add_history_entry(user_input.as_str())?; match run_command(user_input) { Ok(control_flow) => { if control_flow.is_break() { break; } } Err(e) => { println!("{:?}", e); } } } Err(ReadlineError::Interrupted) => { println!("Interrupted"); break; } Err(ReadlineError::Eof) => { break; } Err(err) => { println!("Error: {:?}", err); break; } } } Ok(()) } pub enum FlowControl {} #[derive(Error, Debug)] pub enum ShackleError { #[error(transparent)] IoError(#[from] io::Error), #[error(transparent)] GitError(#[from] git2::Error), #[error(transparent)] ReadlineError(#[from] ReadlineError), }