dnslib/cli/
completions.rs1#[cfg(any(
2 feature = "technitium",
3 feature = "pangolin",
4 feature = "cloudflare",
5 feature = "unifi"
6))]
7pub fn generate_completions(shell: clap_complete::Shell) {
8 use clap::CommandFactory;
9 use clap_complete::generate;
10 use std::io::{self, Write};
11
12 use crate::cli::Cli;
13
14 let mut cmd = Cli::command();
15 let bin_name = std::env::current_exe()
16 .ok()
17 .and_then(|p| p.file_name().map(|n| n.to_string_lossy().into_owned()))
18 .unwrap_or_else(|| cmd.get_name().to_string());
19 let fn_name = bin_name.replace('-', "_");
20
21 let mut out = io::stdout();
22
23 if shell == clap_complete::Shell::Zsh {
26 let mut buf: Vec<u8> = Vec::new();
27 generate(shell, &mut cmd, &bin_name, &mut buf);
28 let raw = String::from_utf8_lossy(&buf);
29 let patched: String = raw
30 .lines()
31 .map(|line| {
32 if line.contains("'*--server=") {
33 line.replace(":_default'", &format!(":_{fn_name}_server_ids'"))
34 } else {
35 line.to_string()
36 }
37 })
38 .collect::<Vec<_>>()
39 .join("\n");
40 let patched = if raw.ends_with('\n') {
41 patched + "\n"
42 } else {
43 patched
44 };
45 out.write_all(patched.as_bytes()).ok();
46 let helper = format!(
47 "\n# Dynamic --server completion from config\n\
48 _{fn_name}_server_ids() {{\n\
49 \tlocal -a ids=(\"${{(@f)$({bin_name} _servers 2>/dev/null)}}\")\n\
50 \t_describe 'server ID' ids\n\
51 }}\n"
52 );
53 out.write_all(helper.as_bytes()).ok();
54 return;
55 }
56
57 generate(shell, &mut cmd, &bin_name, &mut out);
58
59 let dynamic = match shell {
60 clap_complete::Shell::Fish => format!(
61 "\n# Dynamic --server completion from config\n\
62 complete -e -c {bin_name} -l server\n\
63 complete -c {bin_name} -l server -r -a '({bin_name} _servers 2>/dev/null)'\n"
64 ),
65 clap_complete::Shell::Bash => format!(
66 "\n# Dynamic --server completion from config\n\
67 __{fn_name}_complete() {{\n\
68 \tlocal cur prev\n\
69 \tcur=\"${{COMP_WORDS[COMP_CWORD]}}\"\n\
70 \tprev=\"${{COMP_WORDS[COMP_CWORD-1]}}\"\n\
71 \tif [[ \"$prev\" == \"--server\" ]]; then\n\
72 \t\tmapfile -t COMPREPLY < <(compgen -W \"$({bin_name} _servers 2>/dev/null)\" -- \"$cur\")\n\
73 \t\treturn\n\
74 \tfi\n\
75 \t_{fn_name} \"$@\"\n\
76 }}\n\
77 complete -F __{fn_name}_complete {bin_name}\n"
78 ),
79 _ => String::new(),
80 };
81
82 if !dynamic.is_empty() {
83 out.write_all(dynamic.as_bytes()).ok();
84 }
85}