Skip to content

Commit

Permalink
Update CLI structure and refactor commands handling
Browse files Browse the repository at this point in the history
- Increment version of "rusty-buddy" from 0.2.0 to 0.2.1.
- Introduced a modular command handling with the creation of separate argument structures (ChatArgs, CommitMessageArgs, CreateIconArgs, WishArgs) using Clap.
- Added a new file `args.rs` for centralized argument parsing using the Clap `Parser` and `Subcommand` derive macros.
- Refactored repetitive command execution logic in `main.rs` to utilize the unified `Cli` struct.
- Moved `chat.rs`, `commitmessage.rs`, `createicon.rs`, and `wish.rs` into subdirectories within `cli/` and updated their respective mod files.
- Updated `utils.rs` to fix a minor print format error in `get_user_input`.
- Simplified main program entry by removing manual CLI command creation, relying on the new modular design for argument parsing and command execution.
  • Loading branch information
Christian Stolz committed Sep 28, 2024
1 parent 77ee3ad commit 8f2ab58
Show file tree
Hide file tree
Showing 18 changed files with 159 additions and 154 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rusty-buddy"
version = "0.2.0"
version = "0.2.1"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand Down
38 changes: 38 additions & 0 deletions src/args.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use crate::cli::chat::ChatArgs;
use crate::cli::commitmessage::CommitMessageArgs;
use crate::cli::createicon::CreateIconArgs;
use crate::cli::wish::WishArgs;
use clap::{Parser, Subcommand};
use clap_complete::aot::Shell;

#[derive(Parser)]
#[command(
name = "rusty-buddy",
version = "0.2.0",
author = "Christian Stolz <[email protected]>",
about = "A command line interface for various tasks",
version
)]
pub struct Cli {
/// Activate shell completion generation
#[arg(long, value_enum)]
pub completion: Option<Shell>,

#[command(subcommand)]
pub command: Option<Commands>,
}

#[derive(Subcommand)]
pub enum Commands {
/// Summarize the output of `git diff`.
CommitMessage(CommitMessageArgs),

/// Start, continue, or load a chat session.
Chat(ChatArgs),

/// Create an icon using DALL·E based on user input
CreateIcon(CreateIconArgs),

/// Collect files from a specified directory and create a context for chat.
Wish(WishArgs),
}
File renamed without changes.
24 changes: 24 additions & 0 deletions src/cli/chat/chat_args.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use clap::Args;

#[derive(Args)]
pub struct ChatArgs {
/// Start a new chat session
#[arg(short, long)]
pub new: bool,

/// Continue the last chat session
#[arg(short, long, action)]
pub continue_last: bool,

/// Load a specific chat session by name
#[arg(short, long)]
pub load: Option<String>,

/// Directory to add to the chat context
#[arg(short, long)]
pub directory: Option<String>,

/// Specify a persona for the chat session
#[arg(short, long)]
pub persona: Option<String>,
}
15 changes: 15 additions & 0 deletions src/cli/chat/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
pub mod chat;
mod chat_args;

pub use chat_args::ChatArgs;

pub async fn run(args: ChatArgs) -> Result<(), Box<dyn std::error::Error>> {
chat::run_chat(
args.new,
args.continue_last,
args.load,
args.directory,
args.persona,
)
.await
}
4 changes: 4 additions & 0 deletions src/cli/commitmessage/cm_args.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
use clap::Args;

#[derive(Args)]
pub struct CommitMessageArgs;
File renamed without changes.
9 changes: 9 additions & 0 deletions src/cli/commitmessage/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
mod cm_args;
pub mod commitmessage;

pub use cm_args::CommitMessageArgs;


pub async fn run(_args: CommitMessageArgs) -> Result<(), Box<dyn std::error::Error>> {
commitmessage::run_commitmessage().await
}
12 changes: 12 additions & 0 deletions src/cli/createicon/ci_args.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use clap::Args;

#[derive(Args)]
pub struct CreateIconArgs {
/// Output directory for the generated icons
#[arg(short, long, default_value = "./icons")]
pub output: String,

/// Comma-separated list of icon sizes to generate
#[arg(short, long, default_value = "16,32,64,128,256,512")]
pub sizes: Vec<u32>,
}
File renamed without changes.
8 changes: 8 additions & 0 deletions src/cli/createicon/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
mod ci_args;
pub mod createicon;

pub use ci_args::CreateIconArgs;

pub async fn run(args: CreateIconArgs) -> Result<(), Box<dyn std::error::Error>> {
crate::cli::createicon::createicon::run_createicon(args.output.as_str(), args.sizes).await
}
27 changes: 1 addition & 26 deletions src/cli/mod.rs
Original file line number Diff line number Diff line change
@@ -1,32 +1,7 @@
pub mod chat;
pub mod commitmessage;
mod createicon;
pub mod createicon;
mod spinner;
mod style;
pub mod utils;
pub mod wish;

pub async fn run_chat(
start_new: bool,
continue_last: bool,
load_name: Option<String>,
directory: Option<String>,
persona_name: Option<String>,
) -> Result<(), Box<dyn std::error::Error>> {
chat::run_chat(start_new, continue_last, load_name, directory, persona_name).await
}

pub async fn run_commitmessage() -> Result<(), Box<dyn std::error::Error>> {
commitmessage::run_commitmessage().await
}

pub async fn run_wish(directory: &str, use_tools: bool) -> Result<(), Box<dyn std::error::Error>> {
wish::run_wish(directory, use_tools).await
}

pub async fn run_createicon(
output_dir: &str,
sizes: Vec<u32>,
) -> Result<(), Box<dyn std::error::Error>> {
createicon::run_createicon(output_dir, sizes).await
}
2 changes: 1 addition & 1 deletion src/cli/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub fn get_user_input(prompt: &str) -> Result<String, Box<dyn Error>> {
// Create a MadSkin for styling the prompt
let skin = configure_mad_skin();
// Use termimad to print a horizontal line and a colored prompt
skin.print_text("-------------------------------");
skin.print_text("-------------------------------\n");
skin.print_text(&format!("**{}**", prompt)); // Make the prompt bold and colored

loop {
Expand Down
10 changes: 10 additions & 0 deletions src/cli/wish/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
pub mod wish;
mod wish_args;

pub use wish_args::WishArgs;


pub async fn run(args: WishArgs) -> Result<(), Box<dyn std::error::Error>> {
wish::run_wish(args.directory.as_str(), args.tools).await
}

File renamed without changes.
11 changes: 11 additions & 0 deletions src/cli/wish/wish_args.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use clap::Args;

#[derive(Args)]
pub struct WishArgs {
/// The directory to collect files from
pub directory: String,

/// Activate the usage of tools
#[arg(short, long)]
pub tools: bool,
}
149 changes: 24 additions & 125 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,146 +1,45 @@
use clap::{value_parser, Arg, ArgAction, Command, ValueHint};
use clap_complete::aot::{generate, Generator, Shell};
use dotenvy::dotenv;
use std::io;

mod args;
mod chat;
mod cli; // Import the CLI module
mod cli;
mod config;
mod openai_api;
mod persona;

use clap::{Command, Parser, CommandFactory};
use clap_complete::{generate, Generator};
use std::io;
use dotenvy::dotenv;

#[tokio::main]
async fn main() {
dotenv()
.map_err(|e| eprintln!("Failed to load .env file: {}", e))
.unwrap();

let cmd = build_cli();
let matches = cmd.get_matches();
if let Some(generator) = matches.get_one::<Shell>("completion").copied() {
print_completions(generator, &mut build_cli());
} else if let Some(createicon_matches) = matches.subcommand_matches("createicon") {
let output_dir = createicon_matches.get_one::<String>("output").unwrap();
let sizes = createicon_matches
.get_one::<String>("sizes")
.unwrap()
.split(',')
.filter_map(|s| s.trim().parse::<u32>().ok())
.collect::<Vec<_>>();
cli::run_createicon(output_dir, sizes).await.unwrap();
} else if let Some(_) = matches.subcommand_matches("commitmessage") {
cli::run_commitmessage().await.unwrap();
} else if let Some(chat_matches) = matches.subcommand_matches("chat") {
let start_new = chat_matches.get_flag("new");
let continue_last = chat_matches.get_flag("continue");
let load_name = chat_matches.get_one::<String>("load").cloned();
let directory = chat_matches.get_one::<String>("directory").cloned();
let persona_name = chat_matches.get_one::<String>("persona").cloned();
let cli = args::Cli::parse(); // Parse command line arguments with the new CLI struct

cli::run_chat(start_new, continue_last, load_name, directory, persona_name)
.await
.unwrap();
} else if let Some(wish_matches) = matches.subcommand_matches("wish") {
if let Some(directory) = wish_matches.get_one::<String>("directory") {
let use_tools = wish_matches.get_flag("tools");
cli::run_wish(directory, use_tools).await.unwrap();
if let Some(completion) = cli.completion {
print_completions(completion, &mut args::Cli::command());
} else if let Some(command) = cli.command {
match command {
args::Commands::CommitMessage(args) => {
cli::commitmessage::run(args).await.unwrap();
}
args::Commands::Chat(args) => {
cli::chat::run(args).await.unwrap();
}
args::Commands::CreateIcon(args) => {
cli::createicon::run(args).await.unwrap();
}
args::Commands::Wish(args) => {
cli::wish::run(args).await.unwrap();
}
}
} else {
println!("No valid command given. Use `rusty-buddy help` for more information.");
}
}

fn build_cli() -> Command {
Command::new("rusty-buddy")
.version(env!("CARGO_PKG_VERSION"))
.author("Christian Stolz <[email protected]>")
.about("A command line interface for various tasks")
.arg(
Arg::new("completion")
.long("completion")
.action(ArgAction::Set)
.value_parser(value_parser!(Shell)),
)
.subcommand(Command::new("commitmessage").about("Summarize the output of `git diff`."))
.subcommand(
Command::new("chat")
.about("Start, continue, or load a chat session.")
.arg(
Arg::new("new")
.short('n')
.long("new")
.action(ArgAction::SetTrue)
.help("Start a new chat session"),
)
.arg(
Arg::new("continue")
.short('c')
.long("continue")
.action(ArgAction::SetTrue)
.help("Continue the last chat session"),
)
.arg(
Arg::new("load")
.short('l')
.long("load")
.help("Load a specific chat session by name"),
)
.arg(
Arg::new("directory")
.short('d')
.long("directory")
.required(false)
.help("Directory to add to the chat context")
.value_hint(ValueHint::AnyPath),
)
.arg(
Arg::new("persona")
.short('p')
.long("persona")
.value_name("PERSONA")
.help("Specify a persona for the chat session")
.required(false),
),
)
.subcommand(
Command::new("createicon")
.about("Create an icon using DALL·E based on user input")
.arg(
Arg::new("output")
.short('o')
.long("output")
.value_name("DIRECTORY")
.default_value("./icons")
.help("Output directory for the generated icons"),
)
.arg(
Arg::new("sizes")
.short('s')
.long("sizes")
.value_name("SIZES")
.help("Comma-separated list of icon sizes to generate")
.default_value("16,32,64,128,256,512")
.action(ArgAction::Set),
),
)
.subcommand(
Command::new("wish")
.arg(
Arg::new("directory")
.required(true)
.help("The directory to collect files from"),
)
.arg(
Arg::new("tools")
.short('t')
.long("tools")
.action(ArgAction::SetTrue)
.help("Activate the usage of tools"),
)
.about("Collect files from a specified directory and create a context for chat."),
)
}

fn print_completions<G: Generator>(gen: G, cmd: &mut Command) {
generate(gen, cmd, cmd.get_name().to_string(), &mut io::stdout());
}

0 comments on commit 8f2ab58

Please sign in to comment.