// Copyright 2019-2024 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT use crate::Result; use anyhow::Context; use clap::{Command, Parser}; use clap_complete::{generate, Shell}; use std::{fs::write, path::PathBuf}; const PKG_MANAGERS: &[&str] = &["cargo", "pnpm", "npm", "yarn", "bun"]; #[derive(Debug, Clone, Parser)] #[clap(about = "Generate Tauri CLI shell completions for Bash, Zsh, PowerShell or Fish")] pub struct Options { /// Shell to generate a completion script for. #[clap(short, long, verbatim_doc_comment)] shell: Shell, /// Output file for the shell completions. By default the completions are printed to stdout. #[clap(short, long)] output: Option, } fn completions_for(shell: Shell, manager: &'static str, cmd: Command) -> Vec { let tauri = cmd.name("tauri"); let mut command = if manager == "npm" || manager == "bun" { Command::new(manager) .bin_name(manager) .subcommand(Command::new("run").subcommand(tauri)) } else { Command::new(manager).bin_name(manager).subcommand(tauri) }; let mut buf = Vec::new(); generate(shell, &mut command, manager, &mut buf); buf } fn get_completions(shell: Shell, cmd: Command) -> Result { let completions = if shell == Shell::Bash { let mut completions = String::from_utf8_lossy(&completions_for(shell, "cargo", cmd)).into_owned(); for manager in PKG_MANAGERS { completions.push_str(&format!( "complete -F _cargo -o bashdefault -o default {} tauri\n", if manager == &"npm" { "npm run" } else if manager == &"bun" { "bun run" } else { manager } )); } completions } else { let mut buffer = String::new(); for (i, manager) in PKG_MANAGERS.iter().enumerate() { let buf = String::from_utf8_lossy(&completions_for(shell, manager, cmd.clone())).into_owned(); let completions = match shell { Shell::PowerShell => { if i != 0 { // namespaces have already been imported buf .replace("using namespace System.Management.Automation.Language", "") .replace("using namespace System.Management.Automation", "") } else { buf } } _ => buf, }; buffer.push_str(&completions); buffer.push('\n'); } buffer }; Ok(completions) } pub fn command(options: Options, cmd: Command) -> Result<()> { log::info!("Generating completion file for {}...", options.shell); let completions = get_completions(options.shell, cmd)?; if let Some(output) = options.output { write(output, completions).context("failed to write to output path")?; } else { print!("{completions}"); } Ok(()) }