majordomus_cli/command_graph/
shell.rs1pub const BIN_ENV: &str = "MAJORDOMUS_COMPLETION_BIN";
29
30pub const ZSH: &str = r#"# majordomus — shell completion, generated by `majordomus completion init --shell zsh`.
37# Carries no command, no flag and no identifier: every candidate comes from
38# `majordomus completion query`, which answers from the command graph of the repository the
39# shell is in. Load it once; it serves every repository.
40_majordomus_query() {
41 local surface="$1"
42 local bin="${MAJORDOMUS_COMPLETION_BIN:-majordomus}"
43 local -a lines items
44 lines=("${(@f)$(command "$bin" completion query --surface "$surface" --format text --cursor "$((CURRENT-1))" -- "${words[@]}" 2>/dev/null)}")
45 local line value description
46 for line in "${lines[@]}"; do
47 [[ -z "$line" ]] && continue
48 value="${line%% *}"
49 description="${line#* }"
50 [[ "$description" == "$line" ]] && description=""
51 items+=("${value}:${description}")
52 done
53 if (( ${#items} )); then
54 _describe -t majordomus 'candidate' items
55 else
56 _files
57 fi
58}
59_majordomus_complete() { _majordomus_query cli }
60_majordomus_workflow_complete() { _majordomus_query workflow }
61compdef _majordomus_complete majordomus
62compdef _majordomus_complete majordomus-cli
63compdef _majordomus_workflow_complete just
64"#;
65
66pub const BASH: &str = r#"# majordomus — shell completion, generated by `majordomus completion init --shell bash`.
68# Carries no command, no flag and no identifier: every candidate comes from
69# `majordomus completion query`.
70_majordomus_complete() {
71 local surface=cli
72 case "${COMP_WORDS[0]}" in just) surface=workflow ;; esac
73 local bin="${MAJORDOMUS_COMPLETION_BIN:-majordomus}"
74 local line value
75 COMPREPLY=()
76 while IFS= read -r line; do
77 [ -z "$line" ] && continue
78 value="${line%% *}"
79 COMPREPLY+=("$value")
80 done < <(command "$bin" completion query --surface "$surface" --format text --cursor "$COMP_CWORD" -- "${COMP_WORDS[@]}" 2>/dev/null)
81 if [ ${#COMPREPLY[@]} -eq 0 ]; then
82 while IFS= read -r line; do COMPREPLY+=("$line"); done < <(compgen -f -- "${COMP_WORDS[COMP_CWORD]}")
83 fi
84}
85complete -F _majordomus_complete majordomus
86complete -F _majordomus_complete majordomus-cli
87complete -F _majordomus_complete just
88"#;
89
90pub const FISH: &str = r#"# majordomus — shell completion, generated by `majordomus completion init --shell fish`.
96# Carries no command, no flag and no identifier: every candidate comes from
97# `majordomus completion query`.
98function __majordomus_complete
99 set -l bin majordomus
100 if set -q MAJORDOMUS_COMPLETION_BIN
101 set bin $MAJORDOMUS_COMPLETION_BIN
102 end
103 set -l words (commandline -opc)
104 set -l current (commandline -ct)
105 set -l surface cli
106 if test (count $words) -gt 0; and test $words[1] = just
107 set surface workflow
108 end
109 command $bin completion query --surface $surface --format text --cursor (count $words) -- $words $current 2>/dev/null
110end
111complete -c majordomus -f -a '(__majordomus_complete)'
112complete -c majordomus-cli -f -a '(__majordomus_complete)'
113complete -c just -f -a '(__majordomus_complete)'
114"#;
115
116pub const ALL: &[(&str, &str)] = &[("zsh", ZSH), ("bash", BASH), ("fish", FISH)];
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122 use crate::command_graph::{build, Inputs};
123
124 #[test]
125 fn no_adapter_carries_a_command_name() {
126 let graph = build(&Inputs::default());
127 for (shell, script) in ALL {
128 let code: String = script
131 .lines()
132 .filter(|l| !l.trim_start().starts_with('#'))
133 .collect::<Vec<_>>()
134 .join("\n");
135 let code = code.replace("completion query", "");
138 for node in &graph.commands {
139 if node.id.as_str().starts_with("executable.completion") {
140 continue;
141 }
142 for word in node.path.iter().filter(|w| w.len() > 3) {
143 assert!(
144 !code.contains(&format!(" {word} ")),
145 "the {shell} adapter names the command word `{word}`"
146 );
147 }
148 }
149 }
150 }
151
152 #[test]
153 fn every_adapter_asks_the_same_question() {
154 for (shell, script) in ALL {
155 assert!(
156 script.contains("completion query"),
157 "the {shell} adapter does not ask"
158 );
159 assert!(
160 script.contains(BIN_ENV),
161 "the {shell} adapter cannot be pointed at a checkout's own launcher"
162 );
163 assert!(
164 script.contains("--surface"),
165 "the {shell} adapter does not say which surface it is completing"
166 );
167 }
168 }
169}