use clap::Subcommand; use rustyline::{error::ReadlineError, DefaultEditor}; use thiserror::Error; use crate::hlwm::{ command::{CommandParseError, HlwmCommand}, key::Key, parser::{FromCommandArgs, ParseError}, }; #[derive(Subcommand, Debug, Clone)] pub enum Add { /// Add a new keybind to the existing hlctl config #[clap(arg_required_else_help = true)] Keybind { #[arg(short, long)] interactive: bool, }, } #[derive(Debug, Clone, Error)] pub enum Error { #[error("readline error: [{0}]")] ReadlineError(String), #[error("parse error: [{0}]")] KeyParseError(#[from] ParseError), #[error("could not parse command: [{0}]")] CommandParseError(#[from] CommandParseError), } impl From for Error { fn from(value: ReadlineError) -> Self { Self::ReadlineError(value.to_string()) } } impl Add { pub fn run(self) -> Result<(), Error> { match self { Add::Keybind { interactive } => { if interactive { keybind_interactive() } else { todo!() } } } } } fn keybind_interactive() -> Result<(), Error> { let mut read = DefaultEditor::new()?; let keys = read .readline("Keys (Separated by spaces, tabs, +, or -): ")? .trim() .split([' ', '\t', '+', '-']) .map(|l| l.trim()) .filter(|l| !l.is_empty()) .map(|k| Key::from_str_case_insensitive(k)) .collect::, _>>()?; let command = { let read = read.readline("Command (Arguments separated by tabs or spaces): ")?; let mut args = read .trim() .split([' ', '\t']) .map(|a| a.trim()) .filter(|a| !a.is_empty()) .map(|a| a.to_string()); match args.next() { Some(cmd) => HlwmCommand::from_command_args(&cmd, args)?, None => { println!("No command provided"); std::process::exit(1); } } }; println!("{keys:?} -> {command:?}"); Ok(()) }