voirs_cli/completion/
mod.rs1use clap::CommandFactory;
6use clap_complete::{generate, Generator, Shell};
7use std::io::{self, Write};
8use std::path::Path;
9
10use crate::CliApp;
11
12pub fn generate_completion<G: Generator>(
14 shell: G,
15 mut output: impl Write,
16) -> Result<(), io::Error> {
17 let mut app = CliApp::command();
18 generate(shell, &mut app, "voirs", &mut output);
19 Ok(())
20}
21
22pub fn generate_completion_to_file<P: AsRef<Path>>(
24 shell: Shell,
25 output_path: P,
26) -> Result<(), io::Error> {
27 let file = std::fs::File::create(output_path)?;
28 generate_completion(shell, file)
29}
30
31pub fn generate_completion_to_stdout(shell: Shell) -> Result<(), io::Error> {
33 let stdout = io::stdout();
34 generate_completion(shell, stdout.lock())
35}
36
37pub fn get_installation_instructions(shell: Shell) -> String {
39 match shell {
40 Shell::Bash => r#"# Installation instructions for Bash completion:
41
421. Save the completion script:
43 voirs generate-completion bash > ~/.local/share/bash-completion/completions/voirs
44
452. Or for system-wide installation:
46 sudo voirs generate-completion bash > /usr/share/bash-completion/completions/voirs
47
483. Restart your shell or source the completion:
49 source ~/.local/share/bash-completion/completions/voirs
50
51Note: Make sure bash-completion is installed on your system."#
52 .to_string(),
53 Shell::Zsh => r#"# Installation instructions for Zsh completion:
54
551. Save the completion script to a directory in your $fpath:
56 voirs generate-completion zsh > ~/.local/share/zsh/site-functions/_voirs
57
582. Or add to your .zshrc:
59 # Add this line to your .zshrc
60 fpath=(~/.local/share/zsh/site-functions $fpath)
61 autoload -Uz compinit && compinit
62
633. Restart your shell or reload completions:
64 exec zsh
65
66Alternative: Place in any directory in your $fpath and run 'compinit'."#
67 .to_string(),
68 Shell::Fish => r#"# Installation instructions for Fish completion:
69
701. Save the completion script:
71 voirs generate-completion fish > ~/.config/fish/completions/voirs.fish
72
732. Restart fish or reload completions:
74 exec fish
75
76Fish will automatically load completions from the completions directory."#
77 .to_string(),
78 Shell::PowerShell => r#"# Installation instructions for PowerShell completion:
79
801. Check your PowerShell profile location:
81 $PROFILE
82
832. Create the profile directory if it doesn't exist:
84 New-Item -ItemType Directory -Path (Split-Path $PROFILE) -Force
85
863. Add the completion to your profile:
87 voirs generate-completion powershell >> $PROFILE
88
894. Restart PowerShell or reload your profile:
90 . $PROFILE
91
92Note: You may need to adjust PowerShell execution policy to load the profile."#
93 .to_string(),
94 Shell::Elvish => r#"# Installation instructions for Elvish completion:
95
961. Save the completion script:
97 voirs generate-completion elvish > ~/.elvish/lib/voirs-completion.elv
98
992. Add to your rc.elv:
100 use ./voirs-completion
101
1023. Restart Elvish:
103 exec elvish"#
104 .to_string(),
105 _ => "Completion installation instructions not available for this shell.".to_string(),
106 }
107}
108
109pub fn generate_install_script() -> String {
111 r#"#!/bin/bash
112# VoiRS CLI Completion Installation Script
113# Automatically installs shell completions for VoiRS CLI
114
115set -e
116
117# Colors for output
118RED='\033[0;31m'
119GREEN='\033[0;32m'
120YELLOW='\033[1;33m'
121BLUE='\033[0;34m'
122NC='\033[0m' # No Color
123
124# Logging functions
125log_info() {
126 echo -e "${BLUE}[INFO]${NC} $1"
127}
128
129log_success() {
130 echo -e "${GREEN}[SUCCESS]${NC} $1"
131}
132
133log_warn() {
134 echo -e "${YELLOW}[WARN]${NC} $1"
135}
136
137log_error() {
138 echo -e "${RED}[ERROR]${NC} $1"
139}
140
141# Check if voirs is available
142check_voirs() {
143 if ! command -v voirs &> /dev/null; then
144 log_error "voirs command not found. Please install VoiRS CLI first."
145 exit 1
146 fi
147 log_info "VoiRS CLI found: $(which voirs)"
148}
149
150# Install bash completion
151install_bash() {
152 log_info "Installing Bash completion..."
153
154 # Check for bash-completion package
155 if [ -d "/usr/share/bash-completion/completions" ]; then
156 # System-wide installation
157 sudo voirs generate-completion bash > /tmp/voirs_completion_bash
158 sudo mv /tmp/voirs_completion_bash /usr/share/bash-completion/completions/voirs
159 log_success "Bash completion installed system-wide"
160 elif [ -d "$HOME/.local/share/bash-completion/completions" ]; then
161 # User installation
162 mkdir -p "$HOME/.local/share/bash-completion/completions"
163 voirs generate-completion bash > "$HOME/.local/share/bash-completion/completions/voirs"
164 log_success "Bash completion installed for user"
165 else
166 log_warn "Bash completion directory not found. Creating user directory..."
167 mkdir -p "$HOME/.local/share/bash-completion/completions"
168 voirs generate-completion bash > "$HOME/.local/share/bash-completion/completions/voirs"
169 log_success "Bash completion installed for user"
170 fi
171}
172
173# Install zsh completion
174install_zsh() {
175 log_info "Installing Zsh completion..."
176
177 # Find zsh fpath directory
178 local zsh_dir=""
179 if [ -n "$ZSH" ] && [ -d "$ZSH/completions" ]; then
180 zsh_dir="$ZSH/completions"
181 elif [ -d "/usr/local/share/zsh/site-functions" ]; then
182 zsh_dir="/usr/local/share/zsh/site-functions"
183 elif [ -d "$HOME/.zsh/completions" ]; then
184 zsh_dir="$HOME/.zsh/completions"
185 else
186 mkdir -p "$HOME/.zsh/completions"
187 zsh_dir="$HOME/.zsh/completions"
188 fi
189
190 voirs generate-completion zsh > "$zsh_dir/_voirs"
191 log_success "Zsh completion installed to $zsh_dir"
192}
193
194# Install fish completion
195install_fish() {
196 log_info "Installing Fish completion..."
197
198 local fish_dir="$HOME/.config/fish/completions"
199 mkdir -p "$fish_dir"
200 voirs generate-completion fish > "$fish_dir/voirs.fish"
201 log_success "Fish completion installed to $fish_dir"
202}
203
204# Install PowerShell completion
205install_powershell() {
206 log_info "Installing PowerShell completion..."
207
208 if command -v pwsh &> /dev/null; then
209 local ps_profile=$(pwsh -NoProfile -Command 'Write-Host $PROFILE')
210 local ps_dir=$(dirname "$ps_profile")
211 mkdir -p "$ps_dir"
212 voirs generate-completion powershell > "$ps_dir/voirs_completion.ps1"
213 log_success "PowerShell completion installed to $ps_dir"
214 log_warn "You may need to update your PowerShell profile to source the completion"
215 else
216 log_warn "PowerShell not found. Skipping PowerShell completion."
217 fi
218}
219
220# Install all completions
221install_all() {
222 log_info "Installing completions for all available shells..."
223
224 command -v bash &> /dev/null && install_bash
225 command -v zsh &> /dev/null && install_zsh
226 command -v fish &> /dev/null && install_fish
227 command -v pwsh &> /dev/null && install_powershell
228
229 log_success "Installation complete!"
230 log_info "You may need to restart your shell or source the completions."
231}
232
233# Show usage
234show_usage() {
235 echo "VoiRS CLI Completion Installation Script"
236 echo ""
237 echo "Usage: $0 [OPTION]"
238 echo ""
239 echo "Options:"
240 echo " bash Install Bash completion"
241 echo " zsh Install Zsh completion"
242 echo " fish Install Fish completion"
243 echo " powershell Install PowerShell completion"
244 echo " all Install completions for all available shells"
245 echo " help Show this help message"
246 echo ""
247 echo "If no option is provided, 'all' is assumed."
248}
249
250# Main function
251main() {
252 check_voirs
253
254 case "${1:-all}" in
255 bash)
256 install_bash
257 ;;
258 zsh)
259 install_zsh
260 ;;
261 fish)
262 install_fish
263 ;;
264 powershell)
265 install_powershell
266 ;;
267 all)
268 install_all
269 ;;
270 help)
271 show_usage
272 ;;
273 *)
274 log_error "Unknown option: $1"
275 show_usage
276 exit 1
277 ;;
278 esac
279}
280
281main "$@"
282"#
283 .to_string()
284}
285
286pub fn display_completion_status() -> String {
288 let mut output = String::new();
289
290 output.push_str("VoiRS CLI Shell Completion Status\n");
291 output.push_str("==================================\n\n");
292
293 let shells = [
294 ("bash", "Bash"),
295 ("zsh", "Zsh"),
296 ("fish", "Fish"),
297 ("pwsh", "PowerShell"),
298 ];
299
300 for (cmd, name) in shells.iter() {
301 let status = if std::process::Command::new(cmd)
302 .arg("--version")
303 .output()
304 .is_ok()
305 {
306 "✓ Available"
307 } else {
308 "✗ Not installed"
309 };
310
311 output.push_str(&format!("{:12} {}\n", name, status));
312 }
313
314 output.push_str("\nTo generate completion scripts:\n");
315 output.push_str(" voirs generate-completion <shell> > completion_file\n\n");
316 output.push_str("Supported shells: bash, zsh, fish, powershell, elvish\n\n");
317 output.push_str("For installation instructions:\n");
318 output.push_str(" voirs generate-completion <shell> --help\n");
319
320 output
321}
322
323#[cfg(test)]
324mod tests {
325 use super::*;
326 use std::io::Cursor;
327
328 #[test]
329 fn test_generate_bash_completion() {
330 let mut output = Cursor::new(Vec::new());
331 generate_completion(Shell::Bash, &mut output).unwrap();
332
333 let result = String::from_utf8(output.into_inner()).unwrap();
334 assert!(result.contains("voirs"));
335 assert!(result.contains("_voirs"));
336 }
337
338 #[test]
339 fn test_installation_instructions() {
340 let bash_instructions = get_installation_instructions(Shell::Bash);
341 assert!(bash_instructions.contains("bash-completion"));
342 assert!(bash_instructions.contains("~/.local/share"));
343
344 let zsh_instructions = get_installation_instructions(Shell::Zsh);
345 assert!(zsh_instructions.contains("$fpath"));
346 assert!(zsh_instructions.contains("_voirs"));
347 }
348
349 #[test]
350 fn test_install_script_generation() {
351 let script = generate_install_script();
352 assert!(script.contains("#!/bin/bash"));
353 assert!(script.contains("voirs generate-completion"));
354 assert!(script.contains("install_bash"));
355 assert!(script.contains("install_zsh"));
356 }
357
358 #[test]
359 fn test_completion_status() {
360 let status = display_completion_status();
361 assert!(status.contains("VoiRS CLI Shell Completion Status"));
362 assert!(status.contains("Bash"));
363 assert!(status.contains("Zsh"));
364 assert!(status.contains("Fish"));
365 }
366}