aboutsummaryrefslogtreecommitdiff
path: root/src/cli.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/cli.rs')
-rw-r--r--src/cli.rs116
1 files changed, 115 insertions, 1 deletions
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<CommandOutcome> {
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<i32> {
}
}
+fn run_config_command(args: &[String]) -> std::io::Result<i32> {
+ 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<i32> {
+ 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::<toml::Value>() {
+ 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::<toml::Value>() {
+ 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");