@@ -3,12 +3,15 @@ use std::path::{Path, PathBuf};
33use std:: process:: Command ;
44
55use anyhow:: { Context , Result , bail} ;
6- use clap:: { CommandFactory , Parser } ;
6+ use clap:: { CommandFactory , Parser , ValueEnum } ;
77use rand:: Rng ;
88
99#[ derive( Parser ) ]
1010#[ command( name = "terris" , version, about = "Git worktree manager" ) ]
1111struct Cli {
12+ /// Print shell completion script (bash or zsh)
13+ #[ arg( long, value_enum, conflicts_with_all = [ "list" , "delete" , "branch" ] ) ]
14+ completions : Option < CompletionShell > ,
1215 /// List worktrees for the current repository
1316 #[ arg( long, conflicts_with_all = [ "delete" , "branch" ] ) ]
1417 list : bool ,
@@ -20,6 +23,13 @@ struct Cli {
2023 branch : Option < String > ,
2124}
2225
26+ #[ derive( Clone , Copy , Debug , ValueEnum ) ]
27+ enum CompletionShell {
28+ Bash ,
29+ Zsh ,
30+ Fish ,
31+ }
32+
2333#[ derive( Debug , Default ) ]
2434struct Worktree {
2535 path : PathBuf ,
@@ -32,6 +42,10 @@ struct Worktree {
3242
3343fn main ( ) -> Result < ( ) > {
3444 let cli = Cli :: parse ( ) ;
45+ if let Some ( shell) = cli. completions {
46+ print_completions ( shell) ;
47+ return Ok ( ( ) ) ;
48+ }
3549 if cli. list {
3650 return cmd_list ( ) ;
3751 }
@@ -46,6 +60,73 @@ fn main() -> Result<()> {
4660 Ok ( ( ) )
4761}
4862
63+ fn print_completions ( shell : CompletionShell ) {
64+ match shell {
65+ CompletionShell :: Bash => {
66+ println ! (
67+ r#"_terris_branches() {{
68+ git for-each-ref --format='%(refname:short)' refs/heads 2>/dev/null
69+ }}
70+
71+ _terris_complete() {{
72+ local cur prev
73+ cur="${{COMP_WORDS[COMP_CWORD]}}"
74+ prev="${{COMP_WORDS[COMP_CWORD-1]}}"
75+
76+ if [[ "$cur" == -* ]]; then
77+ COMPREPLY=($(compgen -W "--list --delete" -- "$cur"))
78+ return 0
79+ fi
80+
81+ if [[ $COMP_CWORD -eq 1 || "$prev" == "--delete" ]]; then
82+ COMPREPLY=($(compgen -W "$(_terris_branches)" -- "$cur"))
83+ return 0
84+ fi
85+
86+ COMPREPLY=()
87+ }}
88+
89+ complete -F _terris_complete terris
90+ "#
91+ ) ;
92+ }
93+ CompletionShell :: Zsh => {
94+ println ! (
95+ r#"#compdef terris
96+
97+ _terris_branches() {{
98+ git for-each-ref --format='%(refname:short)' refs/heads 2>/dev/null
99+ }}
100+
101+ _arguments -s \
102+ '--list[List worktrees]' \
103+ '--delete[Remove a worktree by branch name]:branch:->branches' \
104+ '1:branch:->branches' \
105+ '*: :->args'
106+
107+ case $state in
108+ branches)
109+ _values 'branches' $(_terris_branches)
110+ ;;
111+ esac
112+ "#
113+ ) ;
114+ }
115+ CompletionShell :: Fish => {
116+ println ! (
117+ r#"function __terris_branches
118+ command git for-each-ref --format='%(refname:short)' refs/heads 2>/dev/null
119+ end
120+
121+ complete -c terris -l list -d 'List worktrees'
122+ complete -c terris -l delete -d 'Remove a worktree by branch name' -a "(__terris_branches)"
123+ complete -c terris -f -a "(__terris_branches)"
124+ "#
125+ ) ;
126+ }
127+ }
128+ }
129+
49130fn cmd_list ( ) -> Result < ( ) > {
50131 let root = git_root ( ) ?;
51132 let worktrees = list_worktrees ( & root) ?;
0 commit comments