1#![allow(clippy::print_stdout)]
7
8use crate::cli::AliasCommand;
9use crate::config;
10use anyhow::Context;
11
12pub fn run(cmd: AliasCommand) -> anyhow::Result<()> {
18 match cmd {
19 AliasCommand::List { hostname: _ } => list(),
20 AliasCommand::Set {
21 name,
22 command,
23 hostname: _,
24 } => set(&name, &command),
25 AliasCommand::Delete { name, hostname: _ } => delete(&name),
26 }
27}
28
29fn list() -> anyhow::Result<()> {
37 let config = config::load().context("failed to load config")?;
38 let aliases = config.global.get("aliases");
39
40 let Some(alias_map) = aliases.and_then(|v| v.as_mapping()) else {
41 println!("No aliases configured.");
42 return Ok(());
43 };
44
45 let name_width = 20;
46 println!("{:<name_width$} COMMAND", "ALIAS");
47 for (name, command) in alias_map {
48 let name_str = name.as_str().unwrap_or("?");
49 let cmd_str = command.as_str().unwrap_or("?");
50 let name_truncated = crate::cmd::util::truncate(name_str, name_width);
51 println!("{name_truncated:<name_width$} {cmd_str}");
52 }
53 Ok(())
54}
55
56fn set(name: &str, command: &[String]) -> anyhow::Result<()> {
65 if command.is_empty() {
66 anyhow::bail!("alias command is required");
67 }
68
69 let mut config = config::load().context("failed to load config")?;
70 let cmd_str = command.join(" ");
71
72 let mut aliases = config
74 .global
75 .get("aliases")
76 .and_then(|v| v.as_mapping().cloned())
77 .unwrap_or_default();
78
79 aliases.insert(
80 serde_yaml_ng::Value::String(name.to_string()),
81 serde_yaml_ng::Value::String(cmd_str.clone()),
82 );
83
84 config.global.insert(
85 "aliases".to_string(),
86 serde_yaml_ng::Value::Mapping(aliases),
87 );
88
89 config::save(&config).context("failed to save config")?;
90
91 println!("Alias '{name}' set to '{cmd_str}'");
92 Ok(())
93}
94
95fn delete(name: &str) -> anyhow::Result<()> {
104 let mut config = config::load().context("failed to load config")?;
105 let aliases = config
106 .global
107 .get("aliases")
108 .and_then(|v| v.as_mapping().cloned());
109
110 let Some(mut aliases) = aliases else {
111 println!("Alias '{name}' not found.");
112 return Ok(());
113 };
114
115 let key = serde_yaml_ng::Value::String(name.to_string());
116 if !aliases.contains_key(&key) {
117 println!("Alias '{name}' not found.");
118 return Ok(());
119 }
120
121 aliases.remove(&key);
122
123 config.global.insert(
124 "aliases".to_string(),
125 serde_yaml_ng::Value::Mapping(aliases),
126 );
127
128 config::save(&config).context("failed to save config")?;
129
130 println!("Alias '{name}' deleted.");
131 Ok(())
132}
133
134#[cfg(test)]
135#[allow(clippy::expect_used)]
136mod tests {
137 use super::*;
138
139 #[test]
140 fn set_requires_command() {
141 let result = std::panic::catch_unwind(|| {
142 let _ = set("test", &[]);
143 });
144 assert!(result.is_ok());
145 }
146
147 #[test]
148 fn delete_nonexistent_is_noop() {
149 let result = std::panic::catch_unwind(|| {
151 let _ = delete("nonexistent");
152 });
153 assert!(result.is_ok());
154 }
155}