From 836fd7e585af15cc1ccb0d4f04586ffec28d2a3c Mon Sep 17 00:00:00 2001 From: Ogulcan Celik Date: Wed, 20 May 2026 18:55:41 +0300 Subject: feat: add keybinding v2 refs #154 refs #201 refs #202 refs #219 --- src/cli.rs | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 115 insertions(+), 1 deletion(-) (limited to 'src/cli.rs') diff --git a/src/cli.rs b/src/cli.rs index 3e07ab2c..e9fe6e81 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,6 +1,6 @@ use std::io::{BufRead, BufReader, Write}; use std::os::unix::net::UnixStream; -use std::time::Duration; +use std::time::{Duration, SystemTime, UNIX_EPOCH}; use serde::Serialize; @@ -33,6 +33,7 @@ pub fn maybe_run(args: &[String]) -> std::io::Result { exit_code } "status" => run_status_command(&args[2..])?, + "config" => run_config_command(&args[2..])?, "workspace" => run_workspace_command(&args[2..])?, "tab" => run_tab_command(&args[2..])?, "agent" => run_agent_command(&args[2..])?, @@ -95,6 +96,114 @@ fn run_status_command(args: &[String]) -> std::io::Result { } } +fn run_config_command(args: &[String]) -> std::io::Result { + let Some(subcommand) = args.first().map(|arg| arg.as_str()) else { + print_config_help(); + return Ok(2); + }; + + match subcommand { + "reset-keys" => config_reset_keys(&args[1..]), + "help" | "--help" | "-h" => { + print_config_help(); + Ok(0) + } + _ => { + print_config_help(); + Ok(2) + } + } +} + +fn config_reset_keys(args: &[String]) -> std::io::Result { + if !args.is_empty() { + eprintln!("usage: herdr config reset-keys"); + return Ok(2); + } + + let path = crate::config::config_path(); + if !path.exists() { + println!( + "No config file found at {}. Built-in v2 keybindings already apply.", + path.display() + ); + return Ok(0); + } + + let content = std::fs::read_to_string(&path)?; + let parsed = match content.parse::() { + Ok(value) => value, + Err(err) => { + eprintln!( + "config file at {} is invalid TOML: {err}. Fix it manually or move it aside to use defaults.", + path.display() + ); + return Ok(1); + } + }; + let Some(table) = parsed.as_table() else { + eprintln!( + "config file at {} is invalid TOML: top-level config must be a table.", + path.display() + ); + return Ok(1); + }; + + if !table.contains_key("keys") { + println!( + "No [keys] config found in {}. Built-in v2 keybindings already apply.", + path.display() + ); + return Ok(0); + } + + let (updated, removed) = crate::config::remove_keybinding_config_sections(&content); + if !removed { + eprintln!( + "could not safely remove keybinding config from {} without rewriting comments; edit the file manually or remove the top-level keys setting.", + path.display() + ); + return Ok(1); + } + if let Err(err) = updated.parse::() { + eprintln!( + "removing keybinding config would make {} invalid TOML: {err}; leaving config unchanged", + path.display() + ); + return Ok(1); + } + + let backup_path = key_config_backup_path(&path); + std::fs::copy(&path, &backup_path)?; + std::fs::write(&path, updated)?; + + println!("Created backup: {}", backup_path.display()); + println!( + "Removed [keys], [keys.indexed], and [[keys.command]] from {}.", + path.display() + ); + println!("Built-in v2 keybindings will apply after Herdr restarts or reloads config."); + println!("If a Herdr server is running, run `herdr server reload-config` to apply this now."); + println!( + "To restore: cp {} {}", + backup_path.display(), + path.display() + ); + Ok(0) +} + +fn key_config_backup_path(path: &std::path::Path) -> std::path::PathBuf { + let timestamp = SystemTime::now() + .duration_since(UNIX_EPOCH) + .map(|duration| duration.as_secs()) + .unwrap_or(0); + let file_name = path + .file_name() + .and_then(|name| name.to_str()) + .unwrap_or("config.toml"); + path.with_file_name(format!("{file_name}.bak-keybind-v2-{timestamp}")) +} + #[derive(Debug, Clone, PartialEq, Eq)] enum ServerRuntimeStatus { Running { @@ -2071,6 +2180,11 @@ fn print_status_help() { eprintln!(" herdr status client show local client binary status"); } +fn print_config_help() { + eprintln!("herdr config commands:"); + eprintln!(" herdr config reset-keys back up config.toml and remove custom keybindings"); +} + fn print_workspace_help() { eprintln!("herdr workspace commands:"); eprintln!(" herdr workspace list"); -- cgit v1.2.3