1use anyhow::{Result, bail};
2
3const ZSH_INIT: &str = r#"# tmx shell integration (zsh)
4twt() {
5 emulate -L zsh
6 local sub="${1:-}"
7 case "$sub" in
8 ""|list)
9 # `list --plain` is a text dump → pass through and never cd, even
10 # when only one entry exists (command substitution would strip the
11 # trailing newline, defeating a multi-line heuristic).
12 local arg
13 for arg in "${@:2}"; do
14 if [[ "$arg" == "--plain" ]]; then
15 command tmx worktree list "${@:2}"
16 return $?
17 fi
18 done
19 # Picker (or `list <target>`) → cd into the printed path.
20 local out
21 out=$(command tmx worktree list "${@:2}")
22 local rc=$?
23 (( rc != 0 )) && return $rc
24 [[ -z "$out" ]] && return 0
25 cd "$out"
26 ;;
27 rm|create|help|-h|--help)
28 command tmx worktree "$@"
29 ;;
30 *)
31 # Implicit `create <branch>` shorthand: create and cd (or -p print).
32 local print_only=0 args=() a
33 for a in "$@"; do
34 case "$a" in
35 -p|--print) print_only=1 ;;
36 *) args+=("$a") ;;
37 esac
38 done
39 local out
40 out=$(command tmx worktree create "${args[@]}")
41 local rc=$?
42 (( rc != 0 )) && return $rc
43 [[ -z "$out" ]] && return 0
44 if (( print_only )); then
45 printf '%s\n' "$out"
46 return 0
47 fi
48 cd "$out"
49 ;;
50 esac
51}
52"#;
53
54pub fn emit(shell: &str) -> Result<&'static str> {
55 match shell {
56 "zsh" => Ok(ZSH_INIT),
57 other => bail!("unsupported shell: {other} (supported: zsh)"),
58 }
59}
60
61#[cfg(test)]
62mod tests {
63 use super::*;
64
65 #[test]
66 fn emit_zsh_contains_function_definition() {
67 let out = emit("zsh").unwrap();
68 assert!(out.contains("twt()"));
69 assert!(out.contains("tmx worktree create"));
70 assert!(out.contains("tmx worktree list"));
71 assert!(out.contains("rm|create|help"));
73 assert!(out.contains("--plain"));
75 }
76
77 #[test]
78 fn emit_unknown_shell_errors() {
79 let err = emit("fish").unwrap_err();
80 assert!(err.to_string().contains("unsupported shell"));
81 assert!(err.to_string().contains("fish"));
82 }
83}