v0.4.1 : Phase 1 complete (17/17) - dashboard TUI (#33), favoris/notes/tags (#39), profils d'environnement (#40), completions dynamiques + man pages (#41), packaging officiel + CI (#42), self-update Gitea, state v3, 212 tests
This commit is contained in:
@@ -1,13 +1,152 @@
|
||||
//! completion: generate shell completion scripts (bash, zsh, fish,
|
||||
//! powershell, elvish) via clap_complete.
|
||||
//! powershell, elvish) via clap_complete. With --installed, a dynamic
|
||||
//! layer is appended: Tab then queries 'am _agents --installed' at runtime,
|
||||
//! so only installed agents, aliases and groups are proposed (issue #41).
|
||||
|
||||
use crate::cli::Cli;
|
||||
use anyhow::Result;
|
||||
use clap::CommandFactory;
|
||||
use clap_complete::{generate, Shell};
|
||||
use std::io::Write;
|
||||
|
||||
pub fn run(shell: Shell) -> Result<i32> {
|
||||
pub fn run(shell: Shell, installed: bool) -> Result<i32> {
|
||||
let mut cmd = Cli::command();
|
||||
generate(shell, &mut cmd, "am", &mut std::io::stdout());
|
||||
let mut buf: Vec<u8> = Vec::new();
|
||||
generate(shell, &mut cmd, "am", &mut buf);
|
||||
if installed {
|
||||
let mut text = String::from_utf8_lossy(&buf).to_string();
|
||||
match shell {
|
||||
Shell::PowerShell => {
|
||||
// Re-bind the base completer to a variable so the wrapper
|
||||
// can delegate to it.
|
||||
let marker = "Register-ArgumentCompleter -Native -CommandName 'am' -ScriptBlock {";
|
||||
if let Some(pos) = text.find(marker) {
|
||||
text.replace_range(pos..pos + marker.len(), "$amBase = {");
|
||||
text.push('\n');
|
||||
text.push_str(powershell_snippet());
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
text.push('\n');
|
||||
text.push_str(snippet(shell));
|
||||
}
|
||||
}
|
||||
std::io::stdout().write_all(text.as_bytes())?;
|
||||
} else {
|
||||
std::io::stdout().write_all(&buf)?;
|
||||
}
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
pub fn snippet(shell: Shell) -> &'static str {
|
||||
match shell {
|
||||
Shell::Bash => bash_snippet(),
|
||||
Shell::Zsh => zsh_snippet(),
|
||||
Shell::Fish => fish_snippet(),
|
||||
Shell::Elvish => elvish_snippet(),
|
||||
Shell::PowerShell => powershell_snippet(),
|
||||
_ => "",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bash_snippet() -> &'static str {
|
||||
r#"# --- dynamic completion of installed agents, aliases and groups (--installed) ---
|
||||
_am_installed() {
|
||||
local cur cmd
|
||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
cmd="${COMP_WORDS[1]}"
|
||||
case "${cmd}" in
|
||||
start|stop|restart|run|info|logs|open|install|uninstall|update|watch|favorite|unfavorite|note|tag|untag|status|sessions|stats|log)
|
||||
if [[ ${COMP_CWORD} -eq 2 ]]; then
|
||||
COMPREPLY=( $(compgen -W "$(am _agents --installed 2>/dev/null)" -- "${cur}") )
|
||||
return 0
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
_am "$@"
|
||||
}
|
||||
complete -F _am_installed -o nosort -o bashdefault -o default am
|
||||
"#
|
||||
}
|
||||
|
||||
pub fn zsh_snippet() -> &'static str {
|
||||
r#"# --- dynamic completion of installed agents, aliases and groups (--installed) ---
|
||||
_am_installed() {
|
||||
local -a agents
|
||||
if [[ ${CURRENT} -eq 3 ]] && [[ ${words[2]} =~ ^(start|stop|restart|run|info|logs|open|install|uninstall|update|watch|favorite|unfavorite|note|tag|untag|status|sessions|stats|log)$ ]]; then
|
||||
agents=("${(@f)$(am _agents --installed 2>/dev/null)}")
|
||||
_describe -t agents 'agent' agents
|
||||
return
|
||||
fi
|
||||
_am "$@"
|
||||
}
|
||||
compdef _am_installed am
|
||||
"#
|
||||
}
|
||||
|
||||
pub fn fish_snippet() -> &'static str {
|
||||
r#"# --- dynamic completion of installed agents, aliases and groups (--installed) ---
|
||||
complete -c am -n "__fish_seen_subcommand_from start stop restart run info logs open install uninstall update watch favorite unfavorite note tag untag status sessions stats log" -f -a "(am _agents --installed 2>/dev/null)"
|
||||
"#
|
||||
}
|
||||
|
||||
pub fn elvish_snippet() -> &'static str {
|
||||
r#"# --- dynamic completion of installed agents, aliases and groups (--installed) ---
|
||||
var am-base = $edit:completion:arg-completer[am]
|
||||
set edit:completion:arg-completer[am] = {|@words|
|
||||
if (and (>= (count $words) 2) (<= (count $words) 3) (has-value [start stop restart run info logs open install uninstall update watch favorite unfavorite note tag untag status sessions stats log] $words[1])) {
|
||||
put $@(am _agents --installed)
|
||||
} else {
|
||||
$am-base $@words
|
||||
}
|
||||
}
|
||||
"#
|
||||
}
|
||||
|
||||
pub fn powershell_snippet() -> &'static str {
|
||||
r#"
|
||||
# --- dynamic completion of installed agents, aliases and groups (--installed) ---
|
||||
Register-ArgumentCompleter -Native -CommandName 'am' -ScriptBlock {
|
||||
param($wordToComplete, $commandAst, $cursorPosition)
|
||||
$tokens = $commandAst.CommandElements | ForEach-Object { $_.Extent.Text }
|
||||
$agentCommands = @('start','stop','restart','run','info','logs','open','install','uninstall','update','watch','favorite','unfavorite','note','tag','untag','status','sessions','stats','log')
|
||||
if ($tokens.Count -ge 2 -and $agentCommands -contains $tokens[1]) {
|
||||
(am _agents --installed 2>$null) | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {
|
||||
[System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
|
||||
}
|
||||
return
|
||||
}
|
||||
& $amBase $wordToComplete $commandAst $cursorPosition
|
||||
}
|
||||
"#
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn dynamic_snippets_are_produced_for_every_shell() {
|
||||
for shell in [
|
||||
Shell::Bash,
|
||||
Shell::Zsh,
|
||||
Shell::Fish,
|
||||
Shell::Elvish,
|
||||
Shell::PowerShell,
|
||||
] {
|
||||
let text = snippet(shell);
|
||||
assert!(text.contains("_agents --installed"), "{shell:?}");
|
||||
assert!(text.contains("favorite"), "{shell:?}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn base_script_has_no_dynamic_layer() {
|
||||
let mut cmd = Cli::command();
|
||||
let mut buf: Vec<u8> = Vec::new();
|
||||
generate(Shell::Bash, &mut cmd, "am", &mut buf);
|
||||
let base = String::from_utf8(buf).unwrap();
|
||||
assert!(!base.contains("_am_installed"));
|
||||
assert!(base.contains("complete -F _am "));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user