snippy 0.1.3

A command-line tool for that makes using LLMs for code generation a breeze
Documentation
use clap::{Parser, Subcommand};
use snippy::copy::ClipboardCopierConfig;
use snippy::copy_files_to_clipboard;
use snippy::extractor::markdown::MarkdownExtractor;
use snippy::logger::initialize_logger;
use snippy::watch::{ClipboardWatcher, WatcherConfig};
use std::path::PathBuf;
use tracing::{error, info};

#[derive(Parser)]
#[command(author, version, about, long_about = None)]
struct CliArgs {
    #[command(subcommand)]
    cmd: SubCommands,
}

#[derive(Subcommand, Debug, Clone)]
enum SubCommands {
    Copy(CopyArgs),
    Watch(WatchArgs),
}

#[derive(Parser, Debug, Clone)]
struct CopyArgs {
    #[arg(required = true)]
    files: Vec<String>,
    #[arg(short = 'm', long, default_value = "false")]
    no_markdown: bool,
    #[arg(short = 'l', long, default_value = None)]
    line_number: Option<usize>,
    #[arg(short = 'p', long, default_value = "|")]
    prefix: String,
    #[arg(short = 'M', long, default_value = "gpt-4o")]
    model: String,
    #[arg(short = 's', long, default_value = "false")]
    no_stats: bool,
    #[arg(long, default_value = "MarkdownHeading")]
    filename_format: Option<String>,
    #[arg(long, default_value = "# Relevant Code\n")]
    pub first_line: String,
    #[arg(long, help = "Format the output as XML")]
    pub xml: bool,
}

#[derive(Parser, Debug, Clone)]
struct WatchArgs {
    #[arg(short = 'x', long)]
    watch_path: Option<String>,
    #[arg(short = 'i', long, default_value_t = 1000)]
    interval_ms: u64,
    #[arg(long, default_value = "# Relevant Code")]
    pub first_line: String,
}

#[tokio::main]
async fn main() {
    let cli_args = CliArgs::parse();
    initialize_logger();

    match cli_args.cmd {
        SubCommands::Copy(args) => {
            let copier_config = ClipboardCopierConfig {
                no_markdown: args.no_markdown,
                line_number: args.line_number,
                prefix: args.prefix.clone(),
                model: args.model.clone(),
                no_stats: args.no_stats,
                filename_format: args
                    .filename_format
                    .clone()
                    .unwrap_or_else(|| "None".to_owned()),
                first_line: args.first_line,
                xml: args.xml,
            };
            if let Err(e) = copy_files_to_clipboard(copier_config, args.files).await {
                eprintln!("Error copying files to clipboard: {}", e);
            }
        }
        SubCommands::Watch(args) => {
            info!("Starting Clipboard Watcher");

            let watcher_config = WatcherConfig {
                interval_ms: args.interval_ms,
                watch_path: PathBuf::from(args.watch_path.unwrap_or_else(|| ".".to_owned())),
                first_line_identifier: args.first_line,
            };

            let watcher = ClipboardWatcher::new(watcher_config, MarkdownExtractor::new());

            if let Err(e) = watcher.run().await {
                error!("Clipboard watcher terminated with error: {}", e);
            }

            info!("Clipboard Watcher has stopped.");
        }
    }
}