use anyhow::Result; use dialoguer::{Input, Select}; use std::time::Duration; use crate::config::{Accelerator, Config, OverlayPosition, PasteMethod, RecordingMode}; use crate::hotkey::capture_hotkey; pub fn show() -> Result<()> { let config = Config::load()?; let yaml = serde_yaml::to_string(&config)?; println!("{yaml}"); Ok(()) } pub fn reset() -> Result<()> { let config = Config::default(); config.save()?; println!("Config reset to defaults at {}", Config::path()?.display()); Ok(()) } pub fn interactive() -> Result<()> { let mut config = Config::load()?; config.hotkey = prompt_hotkey("Hotkey", &config.hotkey)?; let mode_idx = Select::new() .with_prompt("Recording mode") .items(&["push_to_talk", "toggle"]) .default(match config.mode { RecordingMode::PushToTalk => 0, RecordingMode::Toggle => 1, }) .interact()?; config.mode = match mode_idx { 0 => RecordingMode::PushToTalk, _ => RecordingMode::Toggle, }; config.cancel_key = prompt_hotkey("Cancel key", &config.cancel_key)?; config.model = Input::new() .with_prompt("Model") .default(config.model) .interact_text()?; let accel_idx = Select::new() .with_prompt("Accelerator") .items(&["auto", "cpu", "cuda", "directml"]) .default(match config.accelerator { Accelerator::Auto => 0, Accelerator::Cpu => 1, Accelerator::Cuda => 2, Accelerator::DirectMl => 3, }) .interact()?; config.accelerator = match accel_idx { 0 => Accelerator::Auto, 1 => Accelerator::Cpu, 2 => Accelerator::Cuda, _ => Accelerator::DirectMl, }; config.gpu_device = Input::new() .with_prompt("GPU device index") .default(config.gpu_device) .interact_text()?; let paste_idx = Select::new() .with_prompt("Paste method") .items(&["ctrl_v", "shift_insert", "ctrl_shift_v", "clipboard_only"]) .default(match config.paste_method { PasteMethod::CtrlV => 0, PasteMethod::ShiftInsert => 1, PasteMethod::CtrlShiftV => 2, PasteMethod::ClipboardOnly => 3, }) .interact()?; config.paste_method = match paste_idx { 0 => PasteMethod::CtrlV, 1 => PasteMethod::ShiftInsert, 2 => PasteMethod::CtrlShiftV, _ => PasteMethod::ClipboardOnly, }; let overlay_idx = Select::new() .with_prompt("Overlay position") .items(&["top", "bottom", "none"]) .default(match config.overlay_position { OverlayPosition::Top => 0, OverlayPosition::Bottom => 1, OverlayPosition::None => 2, }) .interact()?; config.overlay_position = match overlay_idx { 0 => OverlayPosition::Top, 1 => OverlayPosition::Bottom, _ => OverlayPosition::None, }; let feedback_idx = Select::new() .with_prompt("Audio feedback") .items(&["yes", "no"]) .default(if config.audio_feedback { 0 } else { 1 }) .interact()?; config.audio_feedback = feedback_idx == 0; let vad_idx = Select::new() .with_prompt("VAD (voice activity detection)") .items(&["enabled", "disabled"]) .default(if config.vad_enabled { 0 } else { 1 }) .interact()?; config.vad_enabled = vad_idx == 0; config.language = Input::new() .with_prompt("Language") .default(config.language) .interact_text()?; config.save()?; println!("\nConfig saved to {}", Config::path()?.display()); Ok(()) } /// Prompt the user to either press a key combination or type it manually. fn prompt_hotkey(label: &str, current: &str) -> Result { let choice = Select::new() .with_prompt(format!("{label} (current: {current})")) .items(&["Press the key combination", "Type it manually", "Keep current"]) .default(0) .interact()?; match choice { 0 => { println!("Press your desired key combination (timeout: 10s)..."); match capture_hotkey(Duration::from_secs(10)) { Some(hotkey) => { println!(" Captured: {hotkey}"); Ok(hotkey) } None => { println!(" No keypress detected, keeping current: {current}"); Ok(current.to_string()) } } } 1 => { let value = Input::new() .with_prompt(label) .default(current.to_string()) .interact_text()?; Ok(value) } _ => Ok(current.to_string()), } }