From 08e0b2492cbc9d0e4b0db39866607a9a257550a3 Mon Sep 17 00:00:00 2001 From: Vincent de Phily Date: Sun, 17 Mar 2024 22:59:21 +0000 Subject: [PATCH 01/12] completion: Make shell completion generation optional at compile time The future goal is to enable manual patches to the completion files, instead of using clap_complete directly. We can use clap_complete during development, but the end user doesn't need it anymore (saving on compile time and binary size). --- Cargo.toml | 5 +- completion.bash | 587 ++++++++++++++++++++++++++++++++++++++++++++++ completion.fish | 96 ++++++++ completion.zsh | 237 +++++++++++++++++++ src/commands.rs | 19 +- src/config.rs | 4 +- src/config/cli.rs | 30 +-- 7 files changed, 958 insertions(+), 20 deletions(-) create mode 100644 completion.bash create mode 100644 completion.fish create mode 100644 completion.zsh diff --git a/Cargo.toml b/Cargo.toml index be6ad63..c091c67 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ missing_const_for_fn = "warn" anyhow = "1.0.32" atoi = "2.0.0" clap = { version = "~4.4.11", features = ["cargo", "derive"] } -clap_complete = "~4.4.4" +clap_complete = { version = "~4.4.4", optional = true } crossbeam-channel = "0.5.0" env_logger = { version = "0.11.0", default-features = false, features = ["auto-color"] } flate2 = "1.0.28" @@ -49,6 +49,9 @@ path = "benches/exec_compare.rs" # Experimental features, may require nightly compiler. # Currently only benchmarking. unstable = [] +# Generate shell completions at runtime instead of using static version. +# Only intended for developers. +clap_complete = ["dep:clap_complete"] [profile.release] debug = false diff --git a/completion.bash b/completion.bash new file mode 100644 index 0000000..0f5b6b4 --- /dev/null +++ b/completion.bash @@ -0,0 +1,587 @@ +_emlop() { + local i cur prev opts cmd + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}" + cmd="" + opts="" + + for i in ${COMP_WORDS[@]} + do + case "${cmd},${i}" in + ",$1") + cmd="emlop" + ;; + emlop,accuracy) + cmd="emlop__accuracy" + ;; + emlop,complete) + cmd="emlop__complete" + ;; + emlop,log) + cmd="emlop__log" + ;; + emlop,predict) + cmd="emlop__predict" + ;; + emlop,stats) + cmd="emlop__stats" + ;; + *) + ;; + esac + done + + case "${cmd}" in + emlop) + opts="-f -t -H -o -F -v -h -V --from --to --header --duration --date --utc --color --output --logfile --help --version log predict stats accuracy complete" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --from) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -f) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --to) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -t) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --header) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -H) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --duration) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --date) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --utc) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --color) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --output) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -o) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --logfile) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -F) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + emlop__accuracy) + opts="-e -s -n -f -t -H -o -F -v -h --exact --show --last --avg --limit --from --to --header --duration --date --utc --color --output --logfile --help [search]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --show) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -s) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --last) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -n) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --avg) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --limit) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --from) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -f) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --to) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -t) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --header) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -H) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --duration) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --date) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --utc) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --color) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --output) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -o) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --logfile) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -F) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + emlop__complete) + opts="-f -t -H -o -F -v -h --shell --from --to --header --duration --date --utc --color --output --logfile --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --shell) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --from) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -f) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --to) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -t) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --header) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -H) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --duration) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --date) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --utc) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --color) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --output) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -o) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --logfile) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -F) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + emlop__log) + opts="-N -n -s -e -f -t -H -o -F -v -h --starttime --first --last --show --exact --from --to --header --duration --date --utc --color --output --logfile --help [search]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --starttime) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --first) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -N) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --last) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -n) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --show) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -s) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --from) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -f) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --to) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -t) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --header) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -H) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --duration) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --date) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --utc) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --color) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --output) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -o) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --logfile) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -F) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + emlop__predict) + opts="-s -N -n -f -t -H -o -F -v -h --show --first --last --tmpdir --resume --unknown --avg --limit --from --to --header --duration --date --utc --color --output --logfile --help" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --show) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -s) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --first) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -N) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --last) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -n) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --tmpdir) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --resume) + COMPREPLY=($(compgen -W "auto either main backup no" -- "${cur}")) + return 0 + ;; + --unknown) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --avg) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --limit) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --from) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -f) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --to) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -t) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --header) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -H) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --duration) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --date) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --utc) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --color) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --output) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -o) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --logfile) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -F) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + emlop__stats) + opts="-s -g -e -f -t -H -o -F -v -h --show --groupby --exact --avg --limit --from --to --header --duration --date --utc --color --output --logfile --help [search]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --show) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -s) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --groupby) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -g) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --avg) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --limit) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --from) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -f) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --to) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -t) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --header) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -H) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --duration) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --date) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --utc) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --color) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --output) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -o) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --logfile) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -F) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + esac +} + +if [[ "${BASH_VERSINFO[0]}" -eq 4 && "${BASH_VERSINFO[1]}" -ge 4 || "${BASH_VERSINFO[0]}" -gt 4 ]]; then + complete -F _emlop -o nosort -o bashdefault -o default emlop +else + complete -F _emlop -o bashdefault -o default emlop +fi diff --git a/completion.fish b/completion.fish new file mode 100644 index 0000000..c7c9c3b --- /dev/null +++ b/completion.fish @@ -0,0 +1,96 @@ +complete -c emlop -n "__fish_use_subcommand" -s f -l from -d 'Only parse log entries after ' -r +complete -c emlop -n "__fish_use_subcommand" -s t -l to -d 'Only parse log entries before ' -r +complete -c emlop -n "__fish_use_subcommand" -s H -l header -d 'Show table header' -r +complete -c emlop -n "__fish_use_subcommand" -l duration -d 'Output durations in different formats' -r +complete -c emlop -n "__fish_use_subcommand" -l date -d 'Output dates in different formats' -r +complete -c emlop -n "__fish_use_subcommand" -l utc -d 'Parse/display dates in UTC instead of local time' -r +complete -c emlop -n "__fish_use_subcommand" -l color -d 'Enable color (yes/no/auto)' -r +complete -c emlop -n "__fish_use_subcommand" -s o -l output -d 'Ouput format (columns/tab/auto)' -r +complete -c emlop -n "__fish_use_subcommand" -s F -l logfile -d 'Location of emerge log file' -r +complete -c emlop -n "__fish_use_subcommand" -s v -d 'Increase verbosity (can be given multiple times)' +complete -c emlop -n "__fish_use_subcommand" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c emlop -n "__fish_use_subcommand" -s V -l version -d 'Print version' +complete -c emlop -n "__fish_use_subcommand" -f -a "log" -d 'Show log of sucessful merges, unmerges and syncs' +complete -c emlop -n "__fish_use_subcommand" -f -a "predict" -d 'Predict merge times for current or pretended merges' +complete -c emlop -n "__fish_use_subcommand" -f -a "stats" -d 'Show statistics about syncs, per-package (un)merges, and total (un)merges' +complete -c emlop -n "__fish_use_subcommand" -f -a "accuracy" -d 'Compare actual merge time against predicted merge time' +complete -c emlop -n "__fish_use_subcommand" -f -a "complete" -d 'Shell completion helper' +complete -c emlop -n "__fish_seen_subcommand_from log" -l starttime -d 'Display start time instead of end time' -r +complete -c emlop -n "__fish_seen_subcommand_from log" -s N -l first -d 'Show only the first entries' -r +complete -c emlop -n "__fish_seen_subcommand_from log" -s n -l last -d 'Show only the last entries' -r +complete -c emlop -n "__fish_seen_subcommand_from log" -s s -l show -d 'Show (m)erges, (u)nmerges, (s)yncs, and/or (a)ll' -r +complete -c emlop -n "__fish_seen_subcommand_from log" -s f -l from -d 'Only parse log entries after ' -r +complete -c emlop -n "__fish_seen_subcommand_from log" -s t -l to -d 'Only parse log entries before ' -r +complete -c emlop -n "__fish_seen_subcommand_from log" -s H -l header -d 'Show table header' -r +complete -c emlop -n "__fish_seen_subcommand_from log" -l duration -d 'Output durations in different formats' -r +complete -c emlop -n "__fish_seen_subcommand_from log" -l date -d 'Output dates in different formats' -r +complete -c emlop -n "__fish_seen_subcommand_from log" -l utc -d 'Parse/display dates in UTC instead of local time' -r +complete -c emlop -n "__fish_seen_subcommand_from log" -l color -d 'Enable color (yes/no/auto)' -r +complete -c emlop -n "__fish_seen_subcommand_from log" -s o -l output -d 'Ouput format (columns/tab/auto)' -r +complete -c emlop -n "__fish_seen_subcommand_from log" -s F -l logfile -d 'Location of emerge log file' -r +complete -c emlop -n "__fish_seen_subcommand_from log" -s e -l exact -d 'Match using plain string' +complete -c emlop -n "__fish_seen_subcommand_from log" -s v -d 'Increase verbosity (can be given multiple times)' +complete -c emlop -n "__fish_seen_subcommand_from log" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c emlop -n "__fish_seen_subcommand_from predict" -s s -l show -d 'Show (e)emerge processes, (m)erges, (t)otal, and/or (a)ll' -r +complete -c emlop -n "__fish_seen_subcommand_from predict" -s N -l first -d 'Show only the first entries' -r +complete -c emlop -n "__fish_seen_subcommand_from predict" -s n -l last -d 'Show only the last entries' -r +complete -c emlop -n "__fish_seen_subcommand_from predict" -l tmpdir -d 'Location of portage tmpdir' -r -F +complete -c emlop -n "__fish_seen_subcommand_from predict" -l resume -d 'Use main, backup, either, or no portage resume list' -r -f -a "{auto '',either '',main '',backup '',no ''}" +complete -c emlop -n "__fish_seen_subcommand_from predict" -l unknown -d 'Assume unkown packages take seconds to merge' -r +complete -c emlop -n "__fish_seen_subcommand_from predict" -l avg -d 'Select function used to predict durations' -r +complete -c emlop -n "__fish_seen_subcommand_from predict" -l limit -d 'Use the last merge times to predict durations' -r +complete -c emlop -n "__fish_seen_subcommand_from predict" -s f -l from -d 'Only parse log entries after ' -r +complete -c emlop -n "__fish_seen_subcommand_from predict" -s t -l to -d 'Only parse log entries before ' -r +complete -c emlop -n "__fish_seen_subcommand_from predict" -s H -l header -d 'Show table header' -r +complete -c emlop -n "__fish_seen_subcommand_from predict" -l duration -d 'Output durations in different formats' -r +complete -c emlop -n "__fish_seen_subcommand_from predict" -l date -d 'Output dates in different formats' -r +complete -c emlop -n "__fish_seen_subcommand_from predict" -l utc -d 'Parse/display dates in UTC instead of local time' -r +complete -c emlop -n "__fish_seen_subcommand_from predict" -l color -d 'Enable color (yes/no/auto)' -r +complete -c emlop -n "__fish_seen_subcommand_from predict" -s o -l output -d 'Ouput format (columns/tab/auto)' -r +complete -c emlop -n "__fish_seen_subcommand_from predict" -s F -l logfile -d 'Location of emerge log file' -r +complete -c emlop -n "__fish_seen_subcommand_from predict" -s v -d 'Increase verbosity (can be given multiple times)' +complete -c emlop -n "__fish_seen_subcommand_from predict" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c emlop -n "__fish_seen_subcommand_from stats" -s s -l show -d 'Show (p)ackages, (t)otals, (s)yncs, and/or (a)ll' -r +complete -c emlop -n "__fish_seen_subcommand_from stats" -s g -l groupby -d 'Group by (y)ear, (m)onth, (w)eek, (d)ay, (n)one' -r +complete -c emlop -n "__fish_seen_subcommand_from stats" -l avg -d 'Select function used to predict durations' -r +complete -c emlop -n "__fish_seen_subcommand_from stats" -l limit -d 'Use the last merge times to predict durations' -r +complete -c emlop -n "__fish_seen_subcommand_from stats" -s f -l from -d 'Only parse log entries after ' -r +complete -c emlop -n "__fish_seen_subcommand_from stats" -s t -l to -d 'Only parse log entries before ' -r +complete -c emlop -n "__fish_seen_subcommand_from stats" -s H -l header -d 'Show table header' -r +complete -c emlop -n "__fish_seen_subcommand_from stats" -l duration -d 'Output durations in different formats' -r +complete -c emlop -n "__fish_seen_subcommand_from stats" -l date -d 'Output dates in different formats' -r +complete -c emlop -n "__fish_seen_subcommand_from stats" -l utc -d 'Parse/display dates in UTC instead of local time' -r +complete -c emlop -n "__fish_seen_subcommand_from stats" -l color -d 'Enable color (yes/no/auto)' -r +complete -c emlop -n "__fish_seen_subcommand_from stats" -s o -l output -d 'Ouput format (columns/tab/auto)' -r +complete -c emlop -n "__fish_seen_subcommand_from stats" -s F -l logfile -d 'Location of emerge log file' -r +complete -c emlop -n "__fish_seen_subcommand_from stats" -s e -l exact -d 'Match using plain string' +complete -c emlop -n "__fish_seen_subcommand_from stats" -s v -d 'Increase verbosity (can be given multiple times)' +complete -c emlop -n "__fish_seen_subcommand_from stats" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c emlop -n "__fish_seen_subcommand_from accuracy" -s s -l show -d 'Show (m)erges, (t)otals, and/or (a)ll' -r +complete -c emlop -n "__fish_seen_subcommand_from accuracy" -s n -l last -d 'Show only the last entries' -r +complete -c emlop -n "__fish_seen_subcommand_from accuracy" -l avg -d 'Select function used to predict durations' -r +complete -c emlop -n "__fish_seen_subcommand_from accuracy" -l limit -d 'Use the last merge times to predict durations' -r +complete -c emlop -n "__fish_seen_subcommand_from accuracy" -s f -l from -d 'Only parse log entries after ' -r +complete -c emlop -n "__fish_seen_subcommand_from accuracy" -s t -l to -d 'Only parse log entries before ' -r +complete -c emlop -n "__fish_seen_subcommand_from accuracy" -s H -l header -d 'Show table header' -r +complete -c emlop -n "__fish_seen_subcommand_from accuracy" -l duration -d 'Output durations in different formats' -r +complete -c emlop -n "__fish_seen_subcommand_from accuracy" -l date -d 'Output dates in different formats' -r +complete -c emlop -n "__fish_seen_subcommand_from accuracy" -l utc -d 'Parse/display dates in UTC instead of local time' -r +complete -c emlop -n "__fish_seen_subcommand_from accuracy" -l color -d 'Enable color (yes/no/auto)' -r +complete -c emlop -n "__fish_seen_subcommand_from accuracy" -s o -l output -d 'Ouput format (columns/tab/auto)' -r +complete -c emlop -n "__fish_seen_subcommand_from accuracy" -s F -l logfile -d 'Location of emerge log file' -r +complete -c emlop -n "__fish_seen_subcommand_from accuracy" -s e -l exact -d 'Match using plain string' +complete -c emlop -n "__fish_seen_subcommand_from accuracy" -s v -d 'Increase verbosity (can be given multiple times)' +complete -c emlop -n "__fish_seen_subcommand_from accuracy" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c emlop -n "__fish_seen_subcommand_from complete" -l shell -d 'Write shell completion script to stdout' -r +complete -c emlop -n "__fish_seen_subcommand_from complete" -s f -l from -d 'Only parse log entries after ' -r +complete -c emlop -n "__fish_seen_subcommand_from complete" -s t -l to -d 'Only parse log entries before ' -r +complete -c emlop -n "__fish_seen_subcommand_from complete" -s H -l header -d 'Show table header' -r +complete -c emlop -n "__fish_seen_subcommand_from complete" -l duration -d 'Output durations in different formats' -r +complete -c emlop -n "__fish_seen_subcommand_from complete" -l date -d 'Output dates in different formats' -r +complete -c emlop -n "__fish_seen_subcommand_from complete" -l utc -d 'Parse/display dates in UTC instead of local time' -r +complete -c emlop -n "__fish_seen_subcommand_from complete" -l color -d 'Enable color (yes/no/auto)' -r +complete -c emlop -n "__fish_seen_subcommand_from complete" -s o -l output -d 'Ouput format (columns/tab/auto)' -r +complete -c emlop -n "__fish_seen_subcommand_from complete" -s F -l logfile -d 'Location of emerge log file' -r +complete -c emlop -n "__fish_seen_subcommand_from complete" -s v -d 'Increase verbosity (can be given multiple times)' +complete -c emlop -n "__fish_seen_subcommand_from complete" -s h -l help -d 'Print help (see more with \'--help\')' diff --git a/completion.zsh b/completion.zsh new file mode 100644 index 0000000..2c59125 --- /dev/null +++ b/completion.zsh @@ -0,0 +1,237 @@ +#compdef emlop + +autoload -U is-at-least + +_emlop() { + typeset -A opt_args + typeset -a _arguments_options + local ret=1 + + if is-at-least 5.2; then + _arguments_options=(-s -S -C) + else + _arguments_options=(-s -C) + fi + + local context curcontext="$curcontext" state line + _arguments "${_arguments_options[@]}" \ +'-f+[Only parse log entries after ]:date: ' \ +'--from=[Only parse log entries after ]:date: ' \ +'-t+[Only parse log entries before ]:date: ' \ +'--to=[Only parse log entries before ]:date: ' \ +'-H+[Show table header]' \ +'--header=[Show table header]' \ +'--duration=[Output durations in different formats]:format: ' \ +'--date=[Output dates in different formats]:format: ' \ +'--utc=[Parse/display dates in UTC instead of local time]' \ +'--color=[Enable color (yes/no/auto)]' \ +'-o+[Ouput format (columns/tab/auto)]:format: ' \ +'--output=[Ouput format (columns/tab/auto)]:format: ' \ +'-F+[Location of emerge log file]:file: ' \ +'--logfile=[Location of emerge log file]:file: ' \ +'*-v[Increase verbosity (can be given multiple times)]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +'-V[Print version]' \ +'--version[Print version]' \ +":: :_emlop_commands" \ +"*::: :->emlop" \ +&& ret=0 + case $state in + (emlop) + words=($line[1] "${words[@]}") + (( CURRENT += 1 )) + curcontext="${curcontext%:*:*}:emlop-command-$line[1]:" + case $line[1] in + (log) +_arguments "${_arguments_options[@]}" \ +'--starttime=[Display start time instead of end time]' \ +'-N+[Show only the first entries]' \ +'--first=[Show only the first entries]' \ +'-n+[Show only the last entries]' \ +'--last=[Show only the last entries]' \ +'-s+[Show (m)erges, (u)nmerges, (s)yncs, and/or (a)ll]:m,u,s,a: ' \ +'--show=[Show (m)erges, (u)nmerges, (s)yncs, and/or (a)ll]:m,u,s,a: ' \ +'-f+[Only parse log entries after ]:date: ' \ +'--from=[Only parse log entries after ]:date: ' \ +'-t+[Only parse log entries before ]:date: ' \ +'--to=[Only parse log entries before ]:date: ' \ +'-H+[Show table header]' \ +'--header=[Show table header]' \ +'--duration=[Output durations in different formats]:format: ' \ +'--date=[Output dates in different formats]:format: ' \ +'--utc=[Parse/display dates in UTC instead of local time]' \ +'--color=[Enable color (yes/no/auto)]' \ +'-o+[Ouput format (columns/tab/auto)]:format: ' \ +'--output=[Ouput format (columns/tab/auto)]:format: ' \ +'-F+[Location of emerge log file]:file: ' \ +'--logfile=[Location of emerge log file]:file: ' \ +'-e[Match using plain string]' \ +'--exact[Match using plain string]' \ +'*-v[Increase verbosity (can be given multiple times)]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +'*::search -- Show only packages/repos matching :' \ +&& ret=0 +;; +(predict) +_arguments "${_arguments_options[@]}" \ +'-s+[Show (e)emerge processes, (m)erges, (t)otal, and/or (a)ll]:e,m,t,a: ' \ +'--show=[Show (e)emerge processes, (m)erges, (t)otal, and/or (a)ll]:e,m,t,a: ' \ +'-N+[Show only the first entries]' \ +'--first=[Show only the first entries]' \ +'-n+[Show only the last entries]' \ +'--last=[Show only the last entries]' \ +'*--tmpdir=[Location of portage tmpdir]:dir:_files' \ +'--resume=[Use main, backup, either, or no portage resume list]' \ +'--unknown=[Assume unkown packages take seconds to merge]:secs: ' \ +'--avg=[Select function used to predict durations]:fn: ' \ +'--limit=[Use the last merge times to predict durations]:num: ' \ +'-f+[Only parse log entries after ]:date: ' \ +'--from=[Only parse log entries after ]:date: ' \ +'-t+[Only parse log entries before ]:date: ' \ +'--to=[Only parse log entries before ]:date: ' \ +'-H+[Show table header]' \ +'--header=[Show table header]' \ +'--duration=[Output durations in different formats]:format: ' \ +'--date=[Output dates in different formats]:format: ' \ +'--utc=[Parse/display dates in UTC instead of local time]' \ +'--color=[Enable color (yes/no/auto)]' \ +'-o+[Ouput format (columns/tab/auto)]:format: ' \ +'--output=[Ouput format (columns/tab/auto)]:format: ' \ +'-F+[Location of emerge log file]:file: ' \ +'--logfile=[Location of emerge log file]:file: ' \ +'*-v[Increase verbosity (can be given multiple times)]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +&& ret=0 +;; +(stats) +_arguments "${_arguments_options[@]}" \ +'-s+[Show (p)ackages, (t)otals, (s)yncs, and/or (a)ll]:p,t,s,a: ' \ +'--show=[Show (p)ackages, (t)otals, (s)yncs, and/or (a)ll]:p,t,s,a: ' \ +'-g+[Group by (y)ear, (m)onth, (w)eek, (d)ay, (n)one]:y,m,w,d,n: ' \ +'--groupby=[Group by (y)ear, (m)onth, (w)eek, (d)ay, (n)one]:y,m,w,d,n: ' \ +'--avg=[Select function used to predict durations]:fn: ' \ +'--limit=[Use the last merge times to predict durations]:num: ' \ +'-f+[Only parse log entries after ]:date: ' \ +'--from=[Only parse log entries after ]:date: ' \ +'-t+[Only parse log entries before ]:date: ' \ +'--to=[Only parse log entries before ]:date: ' \ +'-H+[Show table header]' \ +'--header=[Show table header]' \ +'--duration=[Output durations in different formats]:format: ' \ +'--date=[Output dates in different formats]:format: ' \ +'--utc=[Parse/display dates in UTC instead of local time]' \ +'--color=[Enable color (yes/no/auto)]' \ +'-o+[Ouput format (columns/tab/auto)]:format: ' \ +'--output=[Ouput format (columns/tab/auto)]:format: ' \ +'-F+[Location of emerge log file]:file: ' \ +'--logfile=[Location of emerge log file]:file: ' \ +'-e[Match using plain string]' \ +'--exact[Match using plain string]' \ +'*-v[Increase verbosity (can be given multiple times)]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +'*::search -- Show only packages/repos matching :' \ +&& ret=0 +;; +(accuracy) +_arguments "${_arguments_options[@]}" \ +'-s+[Show (m)erges, (t)otals, and/or (a)ll]:m,t,a: ' \ +'--show=[Show (m)erges, (t)otals, and/or (a)ll]:m,t,a: ' \ +'-n+[Show only the last entries]' \ +'--last=[Show only the last entries]' \ +'--avg=[Select function used to predict durations]:fn: ' \ +'--limit=[Use the last merge times to predict durations]:num: ' \ +'-f+[Only parse log entries after ]:date: ' \ +'--from=[Only parse log entries after ]:date: ' \ +'-t+[Only parse log entries before ]:date: ' \ +'--to=[Only parse log entries before ]:date: ' \ +'-H+[Show table header]' \ +'--header=[Show table header]' \ +'--duration=[Output durations in different formats]:format: ' \ +'--date=[Output dates in different formats]:format: ' \ +'--utc=[Parse/display dates in UTC instead of local time]' \ +'--color=[Enable color (yes/no/auto)]' \ +'-o+[Ouput format (columns/tab/auto)]:format: ' \ +'--output=[Ouput format (columns/tab/auto)]:format: ' \ +'-F+[Location of emerge log file]:file: ' \ +'--logfile=[Location of emerge log file]:file: ' \ +'-e[Match using plain string]' \ +'--exact[Match using plain string]' \ +'*-v[Increase verbosity (can be given multiple times)]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +'*::search -- Show only packages/repos matching :' \ +&& ret=0 +;; +(complete) +_arguments "${_arguments_options[@]}" \ +'--shell=[Write shell completion script to stdout]: : ' \ +'-f+[Only parse log entries after ]:date: ' \ +'--from=[Only parse log entries after ]:date: ' \ +'-t+[Only parse log entries before ]:date: ' \ +'--to=[Only parse log entries before ]:date: ' \ +'-H+[Show table header]' \ +'--header=[Show table header]' \ +'--duration=[Output durations in different formats]:format: ' \ +'--date=[Output dates in different formats]:format: ' \ +'--utc=[Parse/display dates in UTC instead of local time]' \ +'--color=[Enable color (yes/no/auto)]' \ +'-o+[Ouput format (columns/tab/auto)]:format: ' \ +'--output=[Ouput format (columns/tab/auto)]:format: ' \ +'-F+[Location of emerge log file]:file: ' \ +'--logfile=[Location of emerge log file]:file: ' \ +'*-v[Increase verbosity (can be given multiple times)]' \ +'-h[Print help (see more with '\''--help'\'')]' \ +'--help[Print help (see more with '\''--help'\'')]' \ +&& ret=0 +;; + esac + ;; +esac +} + +(( $+functions[_emlop_commands] )) || +_emlop_commands() { + local commands; commands=( +'log:Show log of sucessful merges, unmerges and syncs' \ +'predict:Predict merge times for current or pretended merges' \ +'stats:Show statistics about syncs, per-package (un)merges, and total (un)merges' \ +'accuracy:Compare actual merge time against predicted merge time' \ +'complete:Shell completion helper' \ + ) + _describe -t commands 'emlop commands' commands "$@" +} +(( $+functions[_emlop__accuracy_commands] )) || +_emlop__accuracy_commands() { + local commands; commands=() + _describe -t commands 'emlop accuracy commands' commands "$@" +} +(( $+functions[_emlop__complete_commands] )) || +_emlop__complete_commands() { + local commands; commands=() + _describe -t commands 'emlop complete commands' commands "$@" +} +(( $+functions[_emlop__log_commands] )) || +_emlop__log_commands() { + local commands; commands=() + _describe -t commands 'emlop log commands' commands "$@" +} +(( $+functions[_emlop__predict_commands] )) || +_emlop__predict_commands() { + local commands; commands=() + _describe -t commands 'emlop predict commands' commands "$@" +} +(( $+functions[_emlop__stats_commands] )) || +_emlop__stats_commands() { + local commands; commands=() + _describe -t commands 'emlop stats commands' commands "$@" +} + +if [ "$funcstack[1]" = "_emlop" ]; then + _emlop "$@" +else + compdef _emlop emlop +fi diff --git a/src/commands.rs b/src/commands.rs index 3599f01..8e954e3 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -481,8 +481,23 @@ pub fn cmd_accuracy(gc: &Conf, sc: &ConfAccuracy) -> Result { } pub fn cmd_complete(sc: &ConfComplete) -> Result { - let mut cli = build_cli_nocomplete(); - clap_complete::generate(sc.shell, &mut cli, "emlop", &mut std::io::stdout()); + if let Some(s) = &sc.shell { + #[cfg(feature = "clap_complete")] + { + let mut cli = build_cli(); + let shell = clap_complete::Shell::from_str(s).expect("Unsupported shell"); + clap_complete::generate(shell, &mut cli, "emlop", &mut std::io::stdout()); + } + #[cfg(not(feature = "clap_complete"))] + { + match s.as_str() { + "bash" => print!("{}", std::include_str!("../completion.bash")), + "zsh" => print!("{}", std::include_str!("../completion.zsh")), + "fish" => print!("{}", std::include_str!("../completion.fish")), + o => println!("Shell {o:?} not supported"), + } + } + } Ok(true) } diff --git a/src/config.rs b/src/config.rs index ded973a..7c2278b 100644 --- a/src/config.rs +++ b/src/config.rs @@ -72,7 +72,7 @@ pub struct ConfAccuracy { pub lim: u16, } pub struct ConfComplete { - pub shell: clap_complete::Shell, + pub shell: Option, } impl Configs { @@ -226,6 +226,6 @@ impl ConfAccuracy { impl ConfComplete { fn try_new(cli: &ArgMatches) -> Result { - Ok(Self { shell: *cli.get_one("shell").unwrap() }) + Ok(Self { shell: cli.get_one("shell").cloned() }) } } diff --git a/src/config/cli.rs b/src/config/cli.rs index 6243e06..d478a42 100644 --- a/src/config/cli.rs +++ b/src/config/cli.rs @@ -2,7 +2,7 @@ use clap::{builder::styling, crate_version, value_parser, Arg, ArgAction::*, Com use std::path::PathBuf; /// Generate cli argument parser without the `complete` subcommand. -pub fn build_cli_nocomplete() -> Command { +pub fn build_cli() -> Command { //////////////////////////////////////////////////////////// // Filter arguments //////////////////////////////////////////////////////////// @@ -284,6 +284,15 @@ pub fn build_cli_nocomplete() -> Command { -v: show warnings\n \ -vv: show info\n \ -vvv: show debug"); + let h = "Write shell completion script to stdout\n\n\ + You should redirect the output to a file that will be sourced by your shell\n\ + For example: `emlop complete --shell bash > ~/.bash_completion.d/emlop`\n\ + To apply the changes, either restart you shell or `source` the generated file"; + let shell = Arg::new("shell").long("shell") + .help(h.split_once('\n').unwrap().0) + .long_help(h) + .num_args(1) + .display_order(34); //////////////////////////////////////////////////////////// // Subcommands @@ -335,6 +344,10 @@ pub fn build_cli_nocomplete() -> Command { .arg(last) .arg(avg) .arg(limit); + let h = "Shell completion helper\n\n\ + See README to install shell completions."; + let cmd_complete = + Command::new("complete").about(h.split_once('\n').unwrap().0).long_about(h).arg(shell); //////////////////////////////////////////////////////////// // Main command @@ -377,22 +390,9 @@ pub fn build_cli_nocomplete() -> Command { .subcommand(cmd_pred) .subcommand(cmd_stats) .subcommand(cmd_accuracy) + .subcommand(cmd_complete) } -/// Generate cli argument parser. -pub fn build_cli() -> Command { - let labout = "Write shell completion script to stdout\n\n\ - You should redirect the output to a file that will be sourced by your shell\n\ - For example: `emlop complete bash > ~/.bash_completion.d/emlop`\n\ - To apply the changes, either restart you shell or `source` the generated file"; - let shell = Arg::new("shell").help("Target shell") - .required(true) - .value_parser(value_parser!(clap_complete::Shell)); - let cmd = Command::new("complete").about("Generate shell completion script") - .long_about(labout) - .arg(shell); - build_cli_nocomplete().subcommand(cmd) -} #[cfg(test)] mod test { From 5ba5bd9efdb23a43767b73ebbfcb9ce0038f867b Mon Sep 17 00:00:00 2001 From: Vincent de Phily Date: Mon, 18 Mar 2024 00:12:53 +0000 Subject: [PATCH 02/12] completion: Don't complete the complete command This is what we already did before the refactor with optional clap_complete. --- completion.bash | 79 +------------------------------------------------ completion.fish | 13 -------- completion.zsh | 28 ------------------ 3 files changed, 1 insertion(+), 119 deletions(-) diff --git a/completion.bash b/completion.bash index 0f5b6b4..af5a039 100644 --- a/completion.bash +++ b/completion.bash @@ -15,9 +15,6 @@ _emlop() { emlop,accuracy) cmd="emlop__accuracy" ;; - emlop,complete) - cmd="emlop__complete" - ;; emlop,log) cmd="emlop__log" ;; @@ -34,7 +31,7 @@ _emlop() { case "${cmd}" in emlop) - opts="-f -t -H -o -F -v -h -V --from --to --header --duration --date --utc --color --output --logfile --help --version log predict stats accuracy complete" + opts="-f -t -H -o -F -v -h -V --from --to --header --duration --date --utc --color --output --logfile --help --version log predict stats accuracy" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -197,80 +194,6 @@ _emlop() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - emlop__complete) - opts="-f -t -H -o -F -v -h --shell --from --to --header --duration --date --utc --color --output --logfile --help" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - --shell) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --from) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -f) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --to) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -t) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --header) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -H) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --duration) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --date) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --utc) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --color) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --output) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -o) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --logfile) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -F) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; emlop__log) opts="-N -n -s -e -f -t -H -o -F -v -h --starttime --first --last --show --exact --from --to --header --duration --date --utc --color --output --logfile --help [search]..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then diff --git a/completion.fish b/completion.fish index c7c9c3b..af04fae 100644 --- a/completion.fish +++ b/completion.fish @@ -14,7 +14,6 @@ complete -c emlop -n "__fish_use_subcommand" -f -a "log" -d 'Show log of sucessf complete -c emlop -n "__fish_use_subcommand" -f -a "predict" -d 'Predict merge times for current or pretended merges' complete -c emlop -n "__fish_use_subcommand" -f -a "stats" -d 'Show statistics about syncs, per-package (un)merges, and total (un)merges' complete -c emlop -n "__fish_use_subcommand" -f -a "accuracy" -d 'Compare actual merge time against predicted merge time' -complete -c emlop -n "__fish_use_subcommand" -f -a "complete" -d 'Shell completion helper' complete -c emlop -n "__fish_seen_subcommand_from log" -l starttime -d 'Display start time instead of end time' -r complete -c emlop -n "__fish_seen_subcommand_from log" -s N -l first -d 'Show only the first entries' -r complete -c emlop -n "__fish_seen_subcommand_from log" -s n -l last -d 'Show only the last entries' -r @@ -82,15 +81,3 @@ complete -c emlop -n "__fish_seen_subcommand_from accuracy" -s F -l logfile -d ' complete -c emlop -n "__fish_seen_subcommand_from accuracy" -s e -l exact -d 'Match using plain string' complete -c emlop -n "__fish_seen_subcommand_from accuracy" -s v -d 'Increase verbosity (can be given multiple times)' complete -c emlop -n "__fish_seen_subcommand_from accuracy" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c emlop -n "__fish_seen_subcommand_from complete" -l shell -d 'Write shell completion script to stdout' -r -complete -c emlop -n "__fish_seen_subcommand_from complete" -s f -l from -d 'Only parse log entries after ' -r -complete -c emlop -n "__fish_seen_subcommand_from complete" -s t -l to -d 'Only parse log entries before ' -r -complete -c emlop -n "__fish_seen_subcommand_from complete" -s H -l header -d 'Show table header' -r -complete -c emlop -n "__fish_seen_subcommand_from complete" -l duration -d 'Output durations in different formats' -r -complete -c emlop -n "__fish_seen_subcommand_from complete" -l date -d 'Output dates in different formats' -r -complete -c emlop -n "__fish_seen_subcommand_from complete" -l utc -d 'Parse/display dates in UTC instead of local time' -r -complete -c emlop -n "__fish_seen_subcommand_from complete" -l color -d 'Enable color (yes/no/auto)' -r -complete -c emlop -n "__fish_seen_subcommand_from complete" -s o -l output -d 'Ouput format (columns/tab/auto)' -r -complete -c emlop -n "__fish_seen_subcommand_from complete" -s F -l logfile -d 'Location of emerge log file' -r -complete -c emlop -n "__fish_seen_subcommand_from complete" -s v -d 'Increase verbosity (can be given multiple times)' -complete -c emlop -n "__fish_seen_subcommand_from complete" -s h -l help -d 'Print help (see more with \'--help\')' diff --git a/completion.zsh b/completion.zsh index 2c59125..9498803 100644 --- a/completion.zsh +++ b/completion.zsh @@ -165,28 +165,6 @@ _arguments "${_arguments_options[@]}" \ '--help[Print help (see more with '\''--help'\'')]' \ '*::search -- Show only packages/repos matching :' \ && ret=0 -;; -(complete) -_arguments "${_arguments_options[@]}" \ -'--shell=[Write shell completion script to stdout]: : ' \ -'-f+[Only parse log entries after ]:date: ' \ -'--from=[Only parse log entries after ]:date: ' \ -'-t+[Only parse log entries before ]:date: ' \ -'--to=[Only parse log entries before ]:date: ' \ -'-H+[Show table header]' \ -'--header=[Show table header]' \ -'--duration=[Output durations in different formats]:format: ' \ -'--date=[Output dates in different formats]:format: ' \ -'--utc=[Parse/display dates in UTC instead of local time]' \ -'--color=[Enable color (yes/no/auto)]' \ -'-o+[Ouput format (columns/tab/auto)]:format: ' \ -'--output=[Ouput format (columns/tab/auto)]:format: ' \ -'-F+[Location of emerge log file]:file: ' \ -'--logfile=[Location of emerge log file]:file: ' \ -'*-v[Increase verbosity (can be given multiple times)]' \ -'-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -&& ret=0 ;; esac ;; @@ -200,7 +178,6 @@ _emlop_commands() { 'predict:Predict merge times for current or pretended merges' \ 'stats:Show statistics about syncs, per-package (un)merges, and total (un)merges' \ 'accuracy:Compare actual merge time against predicted merge time' \ -'complete:Shell completion helper' \ ) _describe -t commands 'emlop commands' commands "$@" } @@ -209,11 +186,6 @@ _emlop__accuracy_commands() { local commands; commands=() _describe -t commands 'emlop accuracy commands' commands "$@" } -(( $+functions[_emlop__complete_commands] )) || -_emlop__complete_commands() { - local commands; commands=() - _describe -t commands 'emlop complete commands' commands "$@" -} (( $+functions[_emlop__log_commands] )) || _emlop__log_commands() { local commands; commands=() From 8beaea14383631cb6008d37378e76f5a506712b9 Mon Sep 17 00:00:00 2001 From: Vincent de Phily Date: Sat, 6 Apr 2024 13:03:04 +0100 Subject: [PATCH 03/12] completion: Add function to complete package names My original approach was to use walkdir to list the packages, but * It requires some configuration/heuristic to find the repos * It adds a dependency on `walkdir` (though I could have reimplemented it locally) * It's actually slower than reading `emerge.log` (with 18k merges, and just the gentoo repo) * Not listing packages that have never been merged seems like a nicer behaviour Making use of this in shell completion is a work in progress, but the Rust part looks done. Tweaked docs too. --- README.md | 10 +++++----- src/commands.rs | 20 ++++++++++++++++++-- src/config.rs | 7 ++++--- src/config/cli.rs | 18 ++++++++++++------ src/main.rs | 2 +- 5 files changed, 40 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 0a081c1..379a9d1 100644 --- a/README.md +++ b/README.md @@ -87,8 +87,8 @@ Stats-specific arguments: ### Other commands -* `complete` generates shell completions -* `accuracy` helps analizing predictions accuracy +* `complete`: shell completion helper +* `accuracy`: analize predictions accuracy ### Configuration file @@ -132,9 +132,9 @@ you might need to pass `--locked` to `cargo install`, to use explicitly tested d #### Shell completion - emlop complete bash > /usr/share/bash-completion/completions/emlop - emlop complete zsh > /usr/share/zsh/site-functions/_emlop - emlop complete fish > /usr/share/fish/vendor_completions.d/emlop.fish + emlop complete --shell bash > /usr/share/bash-completion/completions/emlop + emlop complete --shell zsh > /usr/share/zsh/site-functions/_emlop + emlop complete --shell fish > /usr/share/fish/vendor_completions.d/emlop.fish ## Contributing diff --git a/src/commands.rs b/src/commands.rs index 8e954e3..1fe876b 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -1,5 +1,5 @@ use crate::{datetime::*, parse::*, table::*, *}; -use std::{collections::{BTreeMap, HashMap}, +use std::{collections::{BTreeMap, HashMap, HashSet}, io::{stdin, IsTerminal}}; /// Straightforward display of merge events @@ -480,14 +480,16 @@ pub fn cmd_accuracy(gc: &Conf, sc: &ConfAccuracy) -> Result { Ok(found) } -pub fn cmd_complete(sc: &ConfComplete) -> Result { +pub fn cmd_complete(gc: &Conf, sc: &ConfComplete) -> Result { if let Some(s) = &sc.shell { + // Generate standard clap completions #[cfg(feature = "clap_complete")] { let mut cli = build_cli(); let shell = clap_complete::Shell::from_str(s).expect("Unsupported shell"); clap_complete::generate(shell, &mut cli, "emlop", &mut std::io::stdout()); } + // Use tweaked completions files from git #[cfg(not(feature = "clap_complete"))] { match s.as_str() { @@ -497,6 +499,20 @@ pub fn cmd_complete(sc: &ConfComplete) -> Result { o => println!("Shell {o:?} not supported"), } } + } else { + // Look for (un)merged matching packages in the log and print each once + let term: Vec<_> = sc.pkg.iter().cloned().collect(); + let hist = get_hist(&gc.logfile, gc.from, gc.to, Show::m(), &term, false)?; + let mut pkgs: HashSet = HashSet::new(); + for p in hist { + if let Hist::MergeStart { .. } = p { + let e = p.ebuild(); + if !pkgs.contains(e) { + println!("{}", e); + pkgs.insert(e.to_string()); + } + } + } } Ok(true) } diff --git a/src/config.rs b/src/config.rs index 7c2278b..fedcb23 100644 --- a/src/config.rs +++ b/src/config.rs @@ -13,7 +13,7 @@ pub enum Configs { Stats(Conf, ConfStats), Predict(Conf, ConfPred), Accuracy(Conf, ConfAccuracy), - Complete(ConfComplete), + Complete(Conf, ConfComplete), } /// Global config @@ -73,6 +73,7 @@ pub struct ConfAccuracy { } pub struct ConfComplete { pub shell: Option, + pub pkg: Option, } impl Configs { @@ -95,7 +96,7 @@ impl Configs { Some(("stats", sub)) => Self::Stats(conf, ConfStats::try_new(sub, &toml)?), Some(("predict", sub)) => Self::Predict(conf, ConfPred::try_new(sub, &toml)?), Some(("accuracy", sub)) => Self::Accuracy(conf, ConfAccuracy::try_new(sub, &toml)?), - Some(("complete", sub)) => Self::Complete(ConfComplete::try_new(sub)?), + Some(("complete", sub)) => Self::Complete(conf, ConfComplete::try_new(sub)?), _ => unreachable!("clap should have exited already"), }) } @@ -226,6 +227,6 @@ impl ConfAccuracy { impl ConfComplete { fn try_new(cli: &ArgMatches) -> Result { - Ok(Self { shell: cli.get_one("shell").cloned() }) + Ok(Self { shell: cli.get_one("shell").cloned(), pkg: cli.get_one("pkg").cloned() }) } } diff --git a/src/config/cli.rs b/src/config/cli.rs index d478a42..c09cf69 100644 --- a/src/config/cli.rs +++ b/src/config/cli.rs @@ -284,7 +284,7 @@ pub fn build_cli() -> Command { -v: show warnings\n \ -vv: show info\n \ -vvv: show debug"); - let h = "Write shell completion script to stdout\n\n\ + let h = "Write completion script to stdout\n\n\ You should redirect the output to a file that will be sourced by your shell\n\ For example: `emlop complete --shell bash > ~/.bash_completion.d/emlop`\n\ To apply the changes, either restart you shell or `source` the generated file"; @@ -293,6 +293,13 @@ pub fn build_cli() -> Command { .long_help(h) .num_args(1) .display_order(34); + let h = "List matching packages from emerge.log\n\n\ + It uses the same semantics as `log ` filtering. \ + An empty search lists everything."; + let onepkg = Arg::new("pkg").help(h.split_once('\n').unwrap().0) + .long_help(h) + .num_args(1) + .display_order(35); //////////////////////////////////////////////////////////// // Subcommands @@ -344,10 +351,8 @@ pub fn build_cli() -> Command { .arg(last) .arg(avg) .arg(limit); - let h = "Shell completion helper\n\n\ - See README to install shell completions."; let cmd_complete = - Command::new("complete").about(h.split_once('\n').unwrap().0).long_about(h).arg(shell); + Command::new("complete").about("Shell completion helper").arg(onepkg).arg(shell); //////////////////////////////////////////////////////////// // Main command @@ -358,8 +363,9 @@ pub fn build_cli() -> Command { concat!("Commands and long args can be abbreviated (eg `emlop l -ss --head -f1w`)\n\ Commands have their own -h / --help\n\ Exit code is 0 if sucessful, 1 if search found nothing, 2 in case of other errors\n\ - Config can be set in $HOME/.config/emlop.toml, see example in /usr/share/doc/emlop-", - crate_version!()); + Config can be set in $HOME/.config/emlop.toml\n\ + See readme, changelog, and sample config in /usr/share/doc/emlop-", + crate_version!(), "/"); let styles = styling::Styles::styled().header(styling::AnsiColor::Blue.on_default() | styling::Effects::BOLD) diff --git a/src/main.rs b/src/main.rs index 9f51af7..9012528 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,7 +17,7 @@ fn main() { Ok(Configs::Stats(gc, sc)) => commands::cmd_stats(&gc, &sc), Ok(Configs::Predict(gc, sc)) => commands::cmd_predict(&gc, &sc), Ok(Configs::Accuracy(gc, sc)) => commands::cmd_accuracy(&gc, &sc), - Ok(Configs::Complete(sc)) => commands::cmd_complete(&sc), + Ok(Configs::Complete(gc, sc)) => commands::cmd_complete(&gc, &sc), Err(e) => Err(e), }; match res { From 5426dab180c64ea76dc70263cba9beb4a6cff483 Mon Sep 17 00:00:00 2001 From: Vincent de Phily Date: Tue, 9 Apr 2024 17:41:37 +0100 Subject: [PATCH 04/12] output: Use short ANSI clr sequence --- src/config.rs | 4 ++-- src/table.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/config.rs b/src/config.rs index fedcb23..1816e01 100644 --- a/src/config.rs +++ b/src/config.rs @@ -157,8 +157,8 @@ impl Conf { unmerge: AnsiStr::from(if color { "\x1B[1;31m" } else { "<<< " }), dur: AnsiStr::from(if color { "\x1B[1;35m" } else { "" }), cnt: AnsiStr::from(if color { "\x1B[2;33m" } else { "" }), - clr: AnsiStr::from(if color { "\x1B[0m" } else { "" }), - lineend: if color { b"\x1B[0m\n" } else { b"\n" }, + clr: AnsiStr::from(if color { "\x1B[m" } else { "" }), + lineend: if color { b"\x1B[m\n" } else { b"\n" }, header: sel!(cli, toml, header, (), false)?, dur_t: sel!(cli, toml, duration, (), DurationStyle::Hms)?, date_offset: offset, diff --git a/src/table.rs b/src/table.rs index 3fc1292..967c536 100644 --- a/src/table.rs +++ b/src/table.rs @@ -249,8 +249,8 @@ mod test { let mut t = Table::<2>::new(&conf).align_left(0); t.row([&[&"123"], &[&1]]); t.row([&[&conf.merge, &1, &conf.dur, &2, &conf.cnt, &3, &conf.clr], &[&1]]); - let res = "123 1\x1B[0m\n\ - \x1B[1;32m1\x1B[1;35m2\x1B[2;33m3\x1B[0m 1\x1B[0m\n"; + let res = "123 1\x1B[m\n\ + \x1B[1;32m1\x1B[1;35m2\x1B[2;33m3\x1B[m 1\x1B[m\n"; let (l1, l2) = res.split_once('\n').expect("two lines"); assert_eq!(Ansi::strip(l1, 100), "123 1"); assert_eq!(Ansi::strip(l1, 100), Ansi::strip(l2, 100)); From 07650637a45928b4c2efcc9356e73d3effad5588 Mon Sep 17 00:00:00 2001 From: Vincent de Phily Date: Wed, 29 May 2024 09:44:46 +0100 Subject: [PATCH 05/12] deps: update time Fixes build on nightly. https://github.com/rust-lang/rust/issues/125319 --- Cargo.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b34d367..21ab90b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -536,9 +536,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.34" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "itoa", @@ -559,9 +559,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ "num-conv", "time-core", From 4292d63ccab17edfc243f82f2a44ca4d858c4a99 Mon Sep 17 00:00:00 2001 From: Vincent de Phily Date: Tue, 3 Sep 2024 19:02:38 +0100 Subject: [PATCH 06/12] completion: Don't include shell completion scripts in the binary Most users install those files via the ebuild, and the others can ignore the files, or grab them from other sources. This simplifies the UI, and reduces the binary size by ~30k. --- README.md | 10 ++++++---- src/commands.rs | 46 +++++++++++++++++----------------------------- src/config.rs | 5 ++++- src/config/cli.rs | 24 ++++++++++++------------ 4 files changed, 39 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index 379a9d1..81f8e67 100644 --- a/README.md +++ b/README.md @@ -130,11 +130,13 @@ you might need to pass `--locked` to `cargo install`, to use explicitly tested d cargo test cargo install -f --path . -#### Shell completion +#### Misc files - emlop complete --shell bash > /usr/share/bash-completion/completions/emlop - emlop complete --shell zsh > /usr/share/zsh/site-functions/_emlop - emlop complete --shell fish > /usr/share/fish/vendor_completions.d/emlop.fish +Cargo only installs the binary, which is all you really need, but you may want to manualy install +some files fetched from [github](https://github.com/vincentdephily/emlop) or the [crates.io +page](https://crates.io/crates/emlop): [bash completion](completion.bash), [zsh +completion](completion.zsh), [fish completion](completion.fish), and [example config +file](emlop.toml). ## Contributing diff --git a/src/commands.rs b/src/commands.rs index 1fe876b..8e2179d 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -481,36 +481,24 @@ pub fn cmd_accuracy(gc: &Conf, sc: &ConfAccuracy) -> Result { } pub fn cmd_complete(gc: &Conf, sc: &ConfComplete) -> Result { + // Generate standard clap completions + #[cfg(feature = "clap_complete")] if let Some(s) = &sc.shell { - // Generate standard clap completions - #[cfg(feature = "clap_complete")] - { - let mut cli = build_cli(); - let shell = clap_complete::Shell::from_str(s).expect("Unsupported shell"); - clap_complete::generate(shell, &mut cli, "emlop", &mut std::io::stdout()); - } - // Use tweaked completions files from git - #[cfg(not(feature = "clap_complete"))] - { - match s.as_str() { - "bash" => print!("{}", std::include_str!("../completion.bash")), - "zsh" => print!("{}", std::include_str!("../completion.zsh")), - "fish" => print!("{}", std::include_str!("../completion.fish")), - o => println!("Shell {o:?} not supported"), - } - } - } else { - // Look for (un)merged matching packages in the log and print each once - let term: Vec<_> = sc.pkg.iter().cloned().collect(); - let hist = get_hist(&gc.logfile, gc.from, gc.to, Show::m(), &term, false)?; - let mut pkgs: HashSet = HashSet::new(); - for p in hist { - if let Hist::MergeStart { .. } = p { - let e = p.ebuild(); - if !pkgs.contains(e) { - println!("{}", e); - pkgs.insert(e.to_string()); - } + let mut cli = build_cli(); + let shell = clap_complete::Shell::from_str(s).expect("Unsupported shell"); + clap_complete::generate(shell, &mut cli, "emlop", &mut std::io::stdout()); + return Ok(true); + } + // Look for (un)merged matching packages in the log and print each once + let term: Vec<_> = sc.pkg.iter().cloned().collect(); + let hist = get_hist(&gc.logfile, gc.from, gc.to, Show::m(), &term, false)?; + let mut pkgs: HashSet = HashSet::new(); + for p in hist { + if let Hist::MergeStart { .. } = p { + let e = p.ebuild(); + if !pkgs.contains(e) { + println!("{}", e); + pkgs.insert(e.to_string()); } } } diff --git a/src/config.rs b/src/config.rs index 1816e01..6ab2e6f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -72,6 +72,7 @@ pub struct ConfAccuracy { pub lim: u16, } pub struct ConfComplete { + #[cfg(feature = "clap_complete")] pub shell: Option, pub pkg: Option, } @@ -227,6 +228,8 @@ impl ConfAccuracy { impl ConfComplete { fn try_new(cli: &ArgMatches) -> Result { - Ok(Self { shell: cli.get_one("shell").cloned(), pkg: cli.get_one("pkg").cloned() }) + Ok(Self { #[cfg(feature = "clap_complete")] + shell: cli.get_one("shell").cloned(), + pkg: cli.get_one("pkg").cloned() }) } } diff --git a/src/config/cli.rs b/src/config/cli.rs index c09cf69..63ef855 100644 --- a/src/config/cli.rs +++ b/src/config/cli.rs @@ -284,17 +284,14 @@ pub fn build_cli() -> Command { -v: show warnings\n \ -vv: show info\n \ -vvv: show debug"); - let h = "Write completion script to stdout\n\n\ - You should redirect the output to a file that will be sourced by your shell\n\ - For example: `emlop complete --shell bash > ~/.bash_completion.d/emlop`\n\ - To apply the changes, either restart you shell or `source` the generated file"; - let shell = Arg::new("shell").long("shell") - .help(h.split_once('\n').unwrap().0) - .long_help(h) - .num_args(1) - .display_order(34); - let h = "List matching packages from emerge.log\n\n\ - It uses the same semantics as `log ` filtering. \ + #[cfg(feature = "clap_complete")] + let shell = + Arg::new("shell").long("shell") + .help("Write generated (development) completion script to stdout") + .num_args(1) + .display_order(34); + let h = "List matching packages from emerge.log\n\ + Uses the same semantics as `log ` filtering. \ An empty search lists everything."; let onepkg = Arg::new("pkg").help(h.split_once('\n').unwrap().0) .long_help(h) @@ -351,8 +348,11 @@ pub fn build_cli() -> Command { .arg(last) .arg(avg) .arg(limit); + #[cfg(feature = "clap_complete")] let cmd_complete = - Command::new("complete").about("Shell completion helper").arg(onepkg).arg(shell); + Command::new("complete").about("Shell completion helper").arg(shell).arg(onepkg); + #[cfg(not(feature = "clap_complete"))] + let cmd_complete = Command::new("complete").about("Shell completion helper").arg(onepkg); //////////////////////////////////////////////////////////// // Main command From 8c93383fd5debdb3242b0fc88af225da698f92a2 Mon Sep 17 00:00:00 2001 From: Vincent de Phily Date: Tue, 3 Sep 2024 19:10:52 +0100 Subject: [PATCH 07/12] completions: Refactor fish shell completion * Add completion for ebuild names * Add docstrings for many enums * Reduce redundant calls Fish completions are really nice to write, maybe at the cost of flexibility: I couldn't figure out how to easily complete on abbreviated commands, and I'm sometimes getting weird completions on single-letter or unknown options. --- completion.fish | 116 +++++++++++++++++------------------------------- 1 file changed, 41 insertions(+), 75 deletions(-) diff --git a/completion.fish b/completion.fish index af04fae..16d5ae0 100644 --- a/completion.fish +++ b/completion.fish @@ -1,83 +1,49 @@ -complete -c emlop -n "__fish_use_subcommand" -s f -l from -d 'Only parse log entries after ' -r -complete -c emlop -n "__fish_use_subcommand" -s t -l to -d 'Only parse log entries before ' -r -complete -c emlop -n "__fish_use_subcommand" -s H -l header -d 'Show table header' -r -complete -c emlop -n "__fish_use_subcommand" -l duration -d 'Output durations in different formats' -r -complete -c emlop -n "__fish_use_subcommand" -l date -d 'Output dates in different formats' -r -complete -c emlop -n "__fish_use_subcommand" -l utc -d 'Parse/display dates in UTC instead of local time' -r -complete -c emlop -n "__fish_use_subcommand" -l color -d 'Enable color (yes/no/auto)' -r -complete -c emlop -n "__fish_use_subcommand" -s o -l output -d 'Ouput format (columns/tab/auto)' -r -complete -c emlop -n "__fish_use_subcommand" -s F -l logfile -d 'Location of emerge log file' -r -complete -c emlop -n "__fish_use_subcommand" -s v -d 'Increase verbosity (can be given multiple times)' -complete -c emlop -n "__fish_use_subcommand" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c emlop -e +complete -c emlop -f +complete -c emlop -s f -l from -d 'Only parse log entries after ' -x -a "{1y 'One year ago',1m 'One month ago',1w 'One week ago',1d 'One day ago',1h 'One hour ago',(date -Is) 'Exact date'}" +complete -c emlop -s t -l to -d 'Only parse log entries before ' -x -a "{1y 'One year ago',1m 'One month ago',1w 'One week ago',1d 'One day ago',1h 'One hour ago',(date -Is) 'Exact date'}" +complete -c emlop -s H -l header -d 'Show table header' -f -a "yes no" +complete -c emlop -l duration -d 'Output durations in different formats' -x -a "hms hmsfixed human secs" +complete -c emlop -l date -d 'Output dates in different formats' -x -a "ymd ymdhms ymdhmso rfc3339 rfc2822 compact unix" +complete -c emlop -l utc -d 'Parse/display dates in UTC instead of local time' -f -a "yes no" +complete -c emlop -l color -d 'Enable color (yes/no/auto)' -f -a "{yes Enabled,no Disabled,auto 'Enabled on terminal'}" +complete -c emlop -s o -l output -d 'Ouput format' -x -a "columns tab auto" +complete -c emlop -s F -l logfile -d 'Location of emerge log file' -r -F +complete -c emlop -s v -x -a "{ 'Show warnings',v 'Show info',vv 'Show debug',vvv 'Show trace'}" -d 'Increase verbosity' +complete -c emlop -s h -d 'Print short help' +complete -c emlop -l help -d 'Print long help' complete -c emlop -n "__fish_use_subcommand" -s V -l version -d 'Print version' + complete -c emlop -n "__fish_use_subcommand" -f -a "log" -d 'Show log of sucessful merges, unmerges and syncs' complete -c emlop -n "__fish_use_subcommand" -f -a "predict" -d 'Predict merge times for current or pretended merges' complete -c emlop -n "__fish_use_subcommand" -f -a "stats" -d 'Show statistics about syncs, per-package (un)merges, and total (un)merges' complete -c emlop -n "__fish_use_subcommand" -f -a "accuracy" -d 'Compare actual merge time against predicted merge time' -complete -c emlop -n "__fish_seen_subcommand_from log" -l starttime -d 'Display start time instead of end time' -r -complete -c emlop -n "__fish_seen_subcommand_from log" -s N -l first -d 'Show only the first entries' -r -complete -c emlop -n "__fish_seen_subcommand_from log" -s n -l last -d 'Show only the last entries' -r -complete -c emlop -n "__fish_seen_subcommand_from log" -s s -l show -d 'Show (m)erges, (u)nmerges, (s)yncs, and/or (a)ll' -r -complete -c emlop -n "__fish_seen_subcommand_from log" -s f -l from -d 'Only parse log entries after ' -r -complete -c emlop -n "__fish_seen_subcommand_from log" -s t -l to -d 'Only parse log entries before ' -r -complete -c emlop -n "__fish_seen_subcommand_from log" -s H -l header -d 'Show table header' -r -complete -c emlop -n "__fish_seen_subcommand_from log" -l duration -d 'Output durations in different formats' -r -complete -c emlop -n "__fish_seen_subcommand_from log" -l date -d 'Output dates in different formats' -r -complete -c emlop -n "__fish_seen_subcommand_from log" -l utc -d 'Parse/display dates in UTC instead of local time' -r -complete -c emlop -n "__fish_seen_subcommand_from log" -l color -d 'Enable color (yes/no/auto)' -r -complete -c emlop -n "__fish_seen_subcommand_from log" -s o -l output -d 'Ouput format (columns/tab/auto)' -r -complete -c emlop -n "__fish_seen_subcommand_from log" -s F -l logfile -d 'Location of emerge log file' -r + +complete -c emlop -n "__fish_seen_subcommand_from log" -l starttime -d 'Display start time instead of end time' -f -a "yes no" +complete -c emlop -n "__fish_seen_subcommand_from log" -s N -l first -d 'Show only the first entries' -f -a "{ 'Show only first entry',5 'Show only first 5 entries',10 'Show only first 10 entries'}" +complete -c emlop -n "__fish_seen_subcommand_from log" -s n -l last -d 'Show only the last entries' -f -a "{ 'Show only last entry',5 'Show only last 5 entries',10 'Show only last 10 entries'}" +complete -c emlop -n "__fish_seen_subcommand_from log" -s s -l show -d 'Show (m)erges, (u)nmerges, (s)yncs, and/or (a)ll' -x -a "musa" complete -c emlop -n "__fish_seen_subcommand_from log" -s e -l exact -d 'Match using plain string' -complete -c emlop -n "__fish_seen_subcommand_from log" -s v -d 'Increase verbosity (can be given multiple times)' -complete -c emlop -n "__fish_seen_subcommand_from log" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c emlop -n "__fish_seen_subcommand_from predict" -s s -l show -d 'Show (e)emerge processes, (m)erges, (t)otal, and/or (a)ll' -r -complete -c emlop -n "__fish_seen_subcommand_from predict" -s N -l first -d 'Show only the first entries' -r -complete -c emlop -n "__fish_seen_subcommand_from predict" -s n -l last -d 'Show only the last entries' -r -complete -c emlop -n "__fish_seen_subcommand_from predict" -l tmpdir -d 'Location of portage tmpdir' -r -F -complete -c emlop -n "__fish_seen_subcommand_from predict" -l resume -d 'Use main, backup, either, or no portage resume list' -r -f -a "{auto '',either '',main '',backup '',no ''}" -complete -c emlop -n "__fish_seen_subcommand_from predict" -l unknown -d 'Assume unkown packages take seconds to merge' -r -complete -c emlop -n "__fish_seen_subcommand_from predict" -l avg -d 'Select function used to predict durations' -r -complete -c emlop -n "__fish_seen_subcommand_from predict" -l limit -d 'Use the last merge times to predict durations' -r -complete -c emlop -n "__fish_seen_subcommand_from predict" -s f -l from -d 'Only parse log entries after ' -r -complete -c emlop -n "__fish_seen_subcommand_from predict" -s t -l to -d 'Only parse log entries before ' -r -complete -c emlop -n "__fish_seen_subcommand_from predict" -s H -l header -d 'Show table header' -r -complete -c emlop -n "__fish_seen_subcommand_from predict" -l duration -d 'Output durations in different formats' -r -complete -c emlop -n "__fish_seen_subcommand_from predict" -l date -d 'Output dates in different formats' -r -complete -c emlop -n "__fish_seen_subcommand_from predict" -l utc -d 'Parse/display dates in UTC instead of local time' -r -complete -c emlop -n "__fish_seen_subcommand_from predict" -l color -d 'Enable color (yes/no/auto)' -r -complete -c emlop -n "__fish_seen_subcommand_from predict" -s o -l output -d 'Ouput format (columns/tab/auto)' -r -complete -c emlop -n "__fish_seen_subcommand_from predict" -s F -l logfile -d 'Location of emerge log file' -r -complete -c emlop -n "__fish_seen_subcommand_from predict" -s v -d 'Increase verbosity (can be given multiple times)' -complete -c emlop -n "__fish_seen_subcommand_from predict" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c emlop -n "__fish_seen_subcommand_from stats" -s s -l show -d 'Show (p)ackages, (t)otals, (s)yncs, and/or (a)ll' -r -complete -c emlop -n "__fish_seen_subcommand_from stats" -s g -l groupby -d 'Group by (y)ear, (m)onth, (w)eek, (d)ay, (n)one' -r -complete -c emlop -n "__fish_seen_subcommand_from stats" -l avg -d 'Select function used to predict durations' -r -complete -c emlop -n "__fish_seen_subcommand_from stats" -l limit -d 'Use the last merge times to predict durations' -r -complete -c emlop -n "__fish_seen_subcommand_from stats" -s f -l from -d 'Only parse log entries after ' -r -complete -c emlop -n "__fish_seen_subcommand_from stats" -s t -l to -d 'Only parse log entries before ' -r -complete -c emlop -n "__fish_seen_subcommand_from stats" -s H -l header -d 'Show table header' -r -complete -c emlop -n "__fish_seen_subcommand_from stats" -l duration -d 'Output durations in different formats' -r -complete -c emlop -n "__fish_seen_subcommand_from stats" -l date -d 'Output dates in different formats' -r -complete -c emlop -n "__fish_seen_subcommand_from stats" -l utc -d 'Parse/display dates in UTC instead of local time' -r -complete -c emlop -n "__fish_seen_subcommand_from stats" -l color -d 'Enable color (yes/no/auto)' -r -complete -c emlop -n "__fish_seen_subcommand_from stats" -s o -l output -d 'Ouput format (columns/tab/auto)' -r -complete -c emlop -n "__fish_seen_subcommand_from stats" -s F -l logfile -d 'Location of emerge log file' -r +complete -c emlop -n "__fish_seen_subcommand_from log" -a "(emlop complete '$1')" + +complete -c emlop -n "__fish_seen_subcommand_from predict" -s s -l show -d 'Show (e)emerge processes, (m)erges, (t)otal, and/or (a)ll' -x -a "emta" +complete -c emlop -n "__fish_seen_subcommand_from predict" -s N -l first -d 'Show only the first entries' -f -a "{ 'Show only first entry',5 'Show only first 5 entries',10 'Show only first 10 entries'}" +complete -c emlop -n "__fish_seen_subcommand_from predict" -s n -l last -d 'Show only the last entries' -f -a "{ 'Show only last entry',5 'Show only last 5 entries',10 'Show only last 10 entries'}" +complete -c emlop -n "__fish_seen_subcommand_from predict" -l tmpdir -d 'Location of portage tmpdir' -x -a "(__fish_complete_directories '$1')" +complete -c emlop -n "__fish_seen_subcommand_from predict" -l resume -d 'Use main, backup, either, or no portage resume list' -f -a "{auto '',either '',main '',backup '',no ''}" +complete -c emlop -n "__fish_seen_subcommand_from predict" -l unknown -d 'Assume unkown packages take seconds to merge' -x -a "0 5 10 20 60" +complete -c emlop -n "__fish_seen_subcommand_from predict" -l avg -d 'Select function used to predict durations' -x -a "arith median weighted-arith weighted-median" +complete -c emlop -n "__fish_seen_subcommand_from predict" -l limit -d 'Use the last merge times to predict durations' -x -a "1 5 20 999" + +complete -c emlop -n "__fish_seen_subcommand_from stats" -s s -l show -d 'Show (p)ackages, (t)otals, (s)yncs, and/or (a)ll' -x -a "ptsa" +complete -c emlop -n "__fish_seen_subcommand_from stats" -s g -l groupby -d 'Group by (y)ear, (m)onth, (w)eek, (d)ay, (n)one' -x -a "year month week day none" +complete -c emlop -n "__fish_seen_subcommand_from stats" -l avg -d 'Select function used to predict durations' -x -a "arith median weighted-arith weighted-median" +complete -c emlop -n "__fish_seen_subcommand_from stats" -l limit -d 'Use the last merge times to predict durations' -x -a "1 5 20 999" complete -c emlop -n "__fish_seen_subcommand_from stats" -s e -l exact -d 'Match using plain string' -complete -c emlop -n "__fish_seen_subcommand_from stats" -s v -d 'Increase verbosity (can be given multiple times)' -complete -c emlop -n "__fish_seen_subcommand_from stats" -s h -l help -d 'Print help (see more with \'--help\')' -complete -c emlop -n "__fish_seen_subcommand_from accuracy" -s s -l show -d 'Show (m)erges, (t)otals, and/or (a)ll' -r -complete -c emlop -n "__fish_seen_subcommand_from accuracy" -s n -l last -d 'Show only the last entries' -r -complete -c emlop -n "__fish_seen_subcommand_from accuracy" -l avg -d 'Select function used to predict durations' -r -complete -c emlop -n "__fish_seen_subcommand_from accuracy" -l limit -d 'Use the last merge times to predict durations' -r -complete -c emlop -n "__fish_seen_subcommand_from accuracy" -s f -l from -d 'Only parse log entries after ' -r -complete -c emlop -n "__fish_seen_subcommand_from accuracy" -s t -l to -d 'Only parse log entries before ' -r -complete -c emlop -n "__fish_seen_subcommand_from accuracy" -s H -l header -d 'Show table header' -r -complete -c emlop -n "__fish_seen_subcommand_from accuracy" -l duration -d 'Output durations in different formats' -r -complete -c emlop -n "__fish_seen_subcommand_from accuracy" -l date -d 'Output dates in different formats' -r -complete -c emlop -n "__fish_seen_subcommand_from accuracy" -l utc -d 'Parse/display dates in UTC instead of local time' -r -complete -c emlop -n "__fish_seen_subcommand_from accuracy" -l color -d 'Enable color (yes/no/auto)' -r -complete -c emlop -n "__fish_seen_subcommand_from accuracy" -s o -l output -d 'Ouput format (columns/tab/auto)' -r -complete -c emlop -n "__fish_seen_subcommand_from accuracy" -s F -l logfile -d 'Location of emerge log file' -r +complete -c emlop -n "__fish_seen_subcommand_from stats" -a "(emlop complete '$1')" + +complete -c emlop -n "__fish_seen_subcommand_from accuracy" -s s -l show -d 'Show (m)erges, (t)otals, and/or (a)ll' -x -a "mta" +complete -c emlop -n "__fish_seen_subcommand_from accuracy" -s n -l last -d 'Show only the last entries' -x -a "{ 'Show only last entry',5 'Show only last 5 entries',10 'Show only last 10 entries'}" +complete -c emlop -n "__fish_seen_subcommand_from accuracy" -l avg -d 'Select function used to predict durations' -x -a "arith median weighted-arith weighted-median" +complete -c emlop -n "__fish_seen_subcommand_from accuracy" -l limit -d 'Use the last merge times to predict durations' -x -a "1 5 20 999" complete -c emlop -n "__fish_seen_subcommand_from accuracy" -s e -l exact -d 'Match using plain string' -complete -c emlop -n "__fish_seen_subcommand_from accuracy" -s v -d 'Increase verbosity (can be given multiple times)' -complete -c emlop -n "__fish_seen_subcommand_from accuracy" -s h -l help -d 'Print help (see more with \'--help\')' From 61451fbb110a3c41f7eb9d00fba10f0c384947d5 Mon Sep 17 00:00:00 2001 From: Vincent de Phily Date: Thu, 5 Sep 2024 15:06:12 +0100 Subject: [PATCH 08/12] completions: Refactor bash shell completion * Add completion for ebuild names * Add proper enum values * Recognize/complete abbreviated commands * Reduce redundant cases * Ignore bash version < 4 (masked in gentoo) Writing bash completions is more labor intensive, but looks less magical and ismore versatile (I got closer to ideal completion than with fish). Not supporting docstrings is a real weak point though, and the UI for selecting between a large number of options is meh. --- completion.bash | 505 +++++++++++++----------------------------------- 1 file changed, 139 insertions(+), 366 deletions(-) diff --git a/completion.bash b/completion.bash index af5a039..bdaf7be 100644 --- a/completion.bash +++ b/completion.bash @@ -3,508 +3,281 @@ _emlop() { COMPREPLY=() cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD-1]}" - cmd="" + cmd="emlop" opts="" - for i in ${COMP_WORDS[@]} - do - case "${cmd},${i}" in - ",$1") - cmd="emlop" - ;; - emlop,accuracy) - cmd="emlop__accuracy" - ;; - emlop,log) - cmd="emlop__log" - ;; - emlop,predict) - cmd="emlop__predict" - ;; - emlop,stats) - cmd="emlop__stats" + i=0 + for w in ${COMP_WORDS[@]}; do + found=$(compgen -W 'accuracy log predict stats' -- "${w}") + case ${found} in + "") ;; *) + if [[ $i == $COMP_CWORD ]]; then + COMPREPLY=($found) + return 0 + else + cmd="emlop__$found" + break + fi ;; esac + let i=$i+1 done case "${cmd}" in emlop) - opts="-f -t -H -o -F -v -h -V --from --to --header --duration --date --utc --color --output --logfile --help --version log predict stats accuracy" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then + opts="log predict stats accuracy -f -t -H -o -F -v -h -V --from --to --header --duration --date --utc --color --output --logfile --help --version" + if [[ ${cur} == -* ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --from) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -f) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + --from|--to|-f|-t) + COMPREPLY=($(compgen -W "1h 1d 1w 1m 1h $(date -Is)" "${cur}")) ;; - --to) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -t) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --header) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -H) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + --header|-H) + COMPREPLY=($(compgen -W "yes no" "${cur}")) ;; --duration) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + COMPREPLY=($(compgen -W "hms secs hmsfixed human" "${cur}")) ;; --date) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + COMPREPLY=($(compgen -W "ymd ymdhms ymdhmso rfc3339 rfc2822 compact unix" "${cur}")) ;; --utc) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + COMPREPLY=($(compgen -W "yes no" "${cur}")) ;; --color) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --output) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -o) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + COMPREPLY=($(compgen -W "yes no auto" "${cur}")) ;; - --logfile) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + --output|-o) + COMPREPLY=($(compgen -W "tab columns auto" "${cur}")) ;; - -F) + --logfile|-F) COMPREPLY=($(compgen -f "${cur}")) - return 0 ;; *) - COMPREPLY=() + COMPREPLY=($(compgen -W "${opts}" -- "${cur}")) ;; esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; emlop__accuracy) - opts="-e -s -n -f -t -H -o -F -v -h --exact --show --last --avg --limit --from --to --header --duration --date --utc --color --output --logfile --help [search]..." - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + opts="[search]... -e -s -n -f -t -H -o -F -v -h --exact --show --last --avg --limit --from --to --header --duration --date --utc --color --output --logfile --help" + if [[ ${cur} == -* ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --show) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -s) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --last) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + --from|--to|-f|-t) + COMPREPLY=($(compgen -W "1h 1d 1w 1m 1h $(date -Is)" "${cur}")) ;; - -n) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --avg) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --limit) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --from) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -f) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --to) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -t) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --header) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -H) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + --header|-H) + COMPREPLY=($(compgen -W "yes no" "${cur}")) ;; --duration) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + COMPREPLY=($(compgen -W "hms secs hmsfixed human" "${cur}")) ;; --date) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + COMPREPLY=($(compgen -W "ymd ymdhms ymdhmso rfc3339 rfc2822 compact unix" "${cur}")) ;; --utc) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + COMPREPLY=($(compgen -W "yes no" "${cur}")) ;; --color) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + COMPREPLY=($(compgen -W "yes no auto" "${cur}")) ;; - --output) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + --output|-o) + COMPREPLY=($(compgen -W "tab columns auto" "${cur}")) ;; - -o) + --logfile|-F) COMPREPLY=($(compgen -f "${cur}")) - return 0 ;; - --logfile) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + --show|-s) + COMPREPLY=($(compgen -W "mta" "${cur}")) ;; - -F) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + --last|-n) + COMPREPLY=($(compgen -W "1 5 10 20 100" "${cur}")) + ;; + --avg) + COMPREPLY=($(compgen -W "arith median weighted-arith weighted-median" "${cur}")) + ;; + --limit) + COMPREPLY=($(compgen -W "1 5 20 999" "${cur}")) ;; *) - COMPREPLY=() + if [[ -z "${cur}" ]]; then + COMPREPLY=($(compgen -W "${opts}" -- "${cur}")) + else + COMPREPLY=($(emlop complete -- "${cur}")) + fi ;; esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; emlop__log) - opts="-N -n -s -e -f -t -H -o -F -v -h --starttime --first --last --show --exact --from --to --header --duration --date --utc --color --output --logfile --help [search]..." - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + opts=" [search]... -N -n -s -e -f -t -H -o -F -v -h --starttime --first --last --show --exact --from --to --header --duration --date --utc --color --output --logfile --help" + if [[ ${cur} == -* ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --starttime) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + --from|--to|-f|-t) + COMPREPLY=($(compgen -W "1h 1d 1w 1m 1h $(date -Is)" "${cur}")) ;; - --first) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -N) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --last) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -n) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --show) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -s) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --from) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -f) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --to) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -t) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --header) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -H) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + --header|-H) + COMPREPLY=($(compgen -W "yes no ${opts}" "${cur}")) ;; --duration) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + COMPREPLY=($(compgen -W "hms secs hmsfixed human" "${cur}")) ;; --date) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + COMPREPLY=($(compgen -W "ymd ymdhms ymdhmso rfc3339 rfc2822 compact unix" "${cur}")) ;; --utc) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + COMPREPLY=($(compgen -W "yes no" "${cur}")) ;; --color) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + COMPREPLY=($(compgen -W "yes no auto" "${cur}")) ;; - --output) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + --output|-o) + COMPREPLY=($(compgen -W "tab columns auto" "${cur}")) ;; - -o) + --logfile|-F) COMPREPLY=($(compgen -f "${cur}")) - return 0 ;; - --logfile) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + --starttime) + COMPREPLY=($(compgen -W "yes no" "${cur}")) ;; - -F) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + --first|-N|--last|-n) + COMPREPLY=($(compgen -W "1 5 10 20 100" "${cur}")) + ;; + --show|-s) + COMPREPLY=($(compgen -W "musa" "${cur}")) ;; *) - COMPREPLY=() + if [[ -z "${cur}" ]]; then + COMPREPLY=($(compgen -W "${opts}" -- "${cur}")) + else + COMPREPLY=($(emlop complete -- "${cur}")) + fi ;; esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; emlop__predict) opts="-s -N -n -f -t -H -o -F -v -h --show --first --last --tmpdir --resume --unknown --avg --limit --from --to --header --duration --date --utc --color --output --logfile --help" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + if [[ ${cur} == -* ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --show) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + --from|--to|-f|-t) + COMPREPLY=($(compgen -W "1h 1d 1w 1m 1h $(date -Is)" "${cur}")) ;; - -s) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + --header|-H) + COMPREPLY=($(compgen -W "yes no" "${cur}")) ;; - --first) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + --duration) + COMPREPLY=($(compgen -W "hms secs hmsfixed human" "${cur}")) ;; - -N) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + --date) + COMPREPLY=($(compgen -W "ymd ymdhms ymdhmso rfc3339 rfc2822 compact unix" "${cur}")) ;; - --last) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + --utc) + COMPREPLY=($(compgen -W "yes no" "${cur}")) ;; - -n) + --color) + COMPREPLY=($(compgen -W "yes no auto" "${cur}")) + ;; + --output|-o) + COMPREPLY=($(compgen -W "tab columns auto" "${cur}")) + ;; + --logfile|-F) COMPREPLY=($(compgen -f "${cur}")) - return 0 + ;; + --show|-s) + COMPREPLY=($(compgen -W "emta" "${cur}")) + ;; + --first|-N|--last|-n) + COMPREPLY=($(compgen -W "1 5 10 20 100" "${cur}")) ;; --tmpdir) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + COMPREPLY=($(compgen -d "${cur}")) ;; --resume) COMPREPLY=($(compgen -W "auto either main backup no" -- "${cur}")) - return 0 ;; --unknown) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + COMPREPLY=($(compgen -W "0 5 10 20 60" "${cur}")) ;; --avg) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + COMPREPLY=($(compgen -W "arith median weighted-arith weighted-median" "${cur}")) ;; --limit) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --from) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -f) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --to) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -t) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --header) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -H) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --duration) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --date) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --utc) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --color) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --output) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -o) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --logfile) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -F) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + COMPREPLY=($(compgen -W "1 5 20 999" "${cur}")) ;; *) - COMPREPLY=() + COMPREPLY=($(compgen -W "${opts}" -- "${cur}")) ;; esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; emlop__stats) - opts="-s -g -e -f -t -H -o -F -v -h --show --groupby --exact --avg --limit --from --to --header --duration --date --utc --color --output --logfile --help [search]..." - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + opts="[search]... -s -g -e -f -t -H -o -F -v -h --show --groupby --exact --avg --limit --from --to --header --duration --date --utc --color --output --logfile --help" + if [[ ${cur} == -* ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in - --show) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + --from|--to|-f|-t) + COMPREPLY=($(compgen -W "1h 1d 1w 1m 1h $(date -Is)" "${cur}")) ;; - -s) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --groupby) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -g) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --avg) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --limit) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --from) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -f) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --to) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -t) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - --header) - COMPREPLY=($(compgen -f "${cur}")) - return 0 - ;; - -H) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + --header|-H) + COMPREPLY=($(compgen -W "yes no" "${cur}")) ;; --duration) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + COMPREPLY=($(compgen -W "hms secs hmsfixed human" "${cur}")) ;; --date) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + COMPREPLY=($(compgen -W "ymd ymdhms ymdhmso rfc3339 rfc2822 compact unix" "${cur}")) ;; --utc) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + COMPREPLY=($(compgen -W "yes no" "${cur}")) ;; --color) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + COMPREPLY=($(compgen -W "yes no auto" "${cur}")) ;; - --output) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + --output|-o) + COMPREPLY=($(compgen -W "tab columns auto" "${cur}")) ;; - -o) + --logfile|-F) COMPREPLY=($(compgen -f "${cur}")) - return 0 ;; - --logfile) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + --show|-s) + COMPREPLY=($(compgen -W "ptsa" "${cur}")) ;; - -F) - COMPREPLY=($(compgen -f "${cur}")) - return 0 + --groupby|-g) + COMPREPLY=($(compgen -W "year month week day none" "${cur}")) + ;; + --avg) + COMPREPLY=($(compgen -W "arith median weighted-arith weighted-median" "${cur}")) + ;; + --limit) + COMPREPLY=($(compgen -W "1 5 20 999" "${cur}")) ;; *) - COMPREPLY=() + if [[ -z "${cur}" ]]; then + COMPREPLY=($(compgen -W "${opts}" -- "${cur}")) + else + COMPREPLY=($(emlop complete -- "${cur}")) + fi ;; esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; esac } -if [[ "${BASH_VERSINFO[0]}" -eq 4 && "${BASH_VERSINFO[1]}" -ge 4 || "${BASH_VERSINFO[0]}" -gt 4 ]]; then - complete -F _emlop -o nosort -o bashdefault -o default emlop -else - complete -F _emlop -o bashdefault -o default emlop -fi +complete -F _emlop -o nosort -o bashdefault -o default emlop From 36f1cd54da69e389787bc4ccb6ada6c3d1206090 Mon Sep 17 00:00:00 2001 From: Vincent de Phily Date: Sun, 8 Sep 2024 12:17:46 +0100 Subject: [PATCH 09/12] completions: Improve zsh shell completion * Add completion for ebuild names * Ignore zsh version < 5.2 (not packaged in gentoo) What a mess, zsh completion system is really complex, the docs is a wall of text, the tutorials didn't help much. The clap-generated completion was buggy. This works better now, but is not as good as bash and fish completions. I'm not a zsh user so I'll leave it at that, help welcome. --- completion.zsh | 55 ++++++++++++++++++-------------------------------- 1 file changed, 20 insertions(+), 35 deletions(-) diff --git a/completion.zsh b/completion.zsh index 9498803..ff8928b 100644 --- a/completion.zsh +++ b/completion.zsh @@ -1,20 +1,10 @@ #compdef emlop -autoload -U is-at-least - _emlop() { typeset -A opt_args - typeset -a _arguments_options - local ret=1 - - if is-at-least 5.2; then - _arguments_options=(-s -S -C) - else - _arguments_options=(-s -C) - fi - local context curcontext="$curcontext" state line - _arguments "${_arguments_options[@]}" \ + + _arguments -s -S -C \ '-f+[Only parse log entries after ]:date: ' \ '--from=[Only parse log entries after ]:date: ' \ '-t+[Only parse log entries before ]:date: ' \ @@ -35,8 +25,7 @@ _emlop() { '-V[Print version]' \ '--version[Print version]' \ ":: :_emlop_commands" \ -"*::: :->emlop" \ -&& ret=0 +"*::: :->emlop" case $state in (emlop) words=($line[1] "${words[@]}") @@ -44,7 +33,7 @@ _emlop() { curcontext="${curcontext%:*:*}:emlop-command-$line[1]:" case $line[1] in (log) -_arguments "${_arguments_options[@]}" \ + _arguments -s -S -C \ '--starttime=[Display start time instead of end time]' \ '-N+[Show only the first entries]' \ '--first=[Show only the first entries]' \ @@ -71,11 +60,10 @@ _arguments "${_arguments_options[@]}" \ '*-v[Increase verbosity (can be given multiple times)]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'*::search -- Show only packages/repos matching :' \ -&& ret=0 -;; -(predict) -_arguments "${_arguments_options[@]}" \ +'*::search:($(emlop complete))' + ;; + (predict) + _arguments -s -S -C \ '-s+[Show (e)emerge processes, (m)erges, (t)otal, and/or (a)ll]:e,m,t,a: ' \ '--show=[Show (e)emerge processes, (m)erges, (t)otal, and/or (a)ll]:e,m,t,a: ' \ '-N+[Show only the first entries]' \ @@ -103,11 +91,10 @@ _arguments "${_arguments_options[@]}" \ '--logfile=[Location of emerge log file]:file: ' \ '*-v[Increase verbosity (can be given multiple times)]' \ '-h[Print help (see more with '\''--help'\'')]' \ -'--help[Print help (see more with '\''--help'\'')]' \ -&& ret=0 -;; -(stats) -_arguments "${_arguments_options[@]}" \ +'--help[Print help (see more with '\''--help'\'')]' + ;; + (stats) + _arguments -s -S -C \ '-s+[Show (p)ackages, (t)otals, (s)yncs, and/or (a)ll]:p,t,s,a: ' \ '--show=[Show (p)ackages, (t)otals, (s)yncs, and/or (a)ll]:p,t,s,a: ' \ '-g+[Group by (y)ear, (m)onth, (w)eek, (d)ay, (n)one]:y,m,w,d,n: ' \ @@ -133,11 +120,10 @@ _arguments "${_arguments_options[@]}" \ '*-v[Increase verbosity (can be given multiple times)]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'*::search -- Show only packages/repos matching :' \ -&& ret=0 -;; -(accuracy) -_arguments "${_arguments_options[@]}" \ +'*::search:($(emlop complete))' + ;; + (accuracy) + _arguments -s -S -C \ '-s+[Show (m)erges, (t)otals, and/or (a)ll]:m,t,a: ' \ '--show=[Show (m)erges, (t)otals, and/or (a)ll]:m,t,a: ' \ '-n+[Show only the last entries]' \ @@ -163,12 +149,11 @@ _arguments "${_arguments_options[@]}" \ '*-v[Increase verbosity (can be given multiple times)]' \ '-h[Print help (see more with '\''--help'\'')]' \ '--help[Print help (see more with '\''--help'\'')]' \ -'*::search -- Show only packages/repos matching :' \ -&& ret=0 -;; +'*::search:($(emlop complete))' + ;; esac - ;; -esac + ;; + esac } (( $+functions[_emlop_commands] )) || From 91b9a052b1ab1e14420fa215f7014d7dd9298783 Mon Sep 17 00:00:00 2001 From: Vincent de Phily Date: Mon, 9 Sep 2024 10:56:05 +0100 Subject: [PATCH 10/12] qa: Clippy fixes and comments --- Cargo.toml | 2 +- src/config.rs | 12 ++++++------ src/parse/history.rs | 4 ++-- src/table.rs | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c091c67..6e50dbf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ env_logger = { version = "0.11.0", default-features = false, features = ["auto-c flate2 = "1.0.28" libc = { version = "0.2.126", default-features = false } log = "0.4.11" -regex = { version = "1.10.0", default_features = false, features = ["std", "perf-inline", "perf-literal", "unicode-case"] } +regex = { version = "1.10.0", default-features = false, features = ["std", "perf-inline", "perf-literal", "unicode-case"] } rev_lines = "0.3.0" serde = { version = "1.0.184", features = ["derive"] } serde_json = "1.0.89" diff --git a/src/config.rs b/src/config.rs index 6ab2e6f..ac5890f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,3 +1,6 @@ +/// Runtime config +/// +/// Order of precedance is command line (clap), config file (toml), default. mod cli; mod toml; mod types; @@ -7,7 +10,7 @@ use crate::{config::toml::Toml, parse::AnsiStr, *}; use clap::ArgMatches; use std::{io::IsTerminal, path::PathBuf}; - +/// Global config, one enum variant per command pub enum Configs { Log(Conf, ConfLog), Stats(Conf, ConfStats), @@ -15,11 +18,9 @@ pub enum Configs { Accuracy(Conf, ConfAccuracy), Complete(Conf, ConfComplete), } - -/// Global config +/// Common config /// -/// Colors use `prefix/suffix()` instead of `paint()` because `paint()` doesn't handle `'{:>9}'` -/// alignments properly. +/// Using raw `set/clear` ANSI colors instead of some `paint()` method to simplify alignment. pub struct Conf { pub pkg: AnsiStr, pub merge: AnsiStr, @@ -141,7 +142,6 @@ macro_rules! sel { } } - impl Conf { pub fn try_new(cli: &ArgMatches, toml: &Toml) -> Result { let isterm = std::io::stdout().is_terminal(); diff --git a/src/parse/history.rs b/src/parse/history.rs index 4f6e583..81cdab1 100644 --- a/src/parse/history.rs +++ b/src/parse/history.rs @@ -168,7 +168,7 @@ fn filter_ts(min: Option, max: Option) -> Result<(i64, i64), Error> { fmt_utctime(b)) }, } - Ok((min.unwrap_or(std::i64::MIN), max.unwrap_or(std::i64::MAX))) + Ok((min.unwrap_or(i64::MIN), max.unwrap_or(i64::MAX))) } /// Matches package/repo depending on options. @@ -484,7 +484,7 @@ mod tests { #[test] /// Filtering by timestamp fn parse_hist_filter_ts() { - let (umin, umax, fmin, fmax) = (std::i64::MIN, std::i64::MAX, 1517609348, 1520891098); + let (umin, umax, fmin, fmax) = (i64::MIN, i64::MAX, 1517609348, 1520891098); #[rustfmt::skip] let t = vec![(Some(umin), None, 889, 832, 832, 832, 326, 150), (Some(fmin), None, 889, 832, 832, 832, 326, 150), diff --git a/src/table.rs b/src/table.rs index 967c536..a4d3947 100644 --- a/src/table.rs +++ b/src/table.rs @@ -53,17 +53,17 @@ impl<'a, const N: usize> Table<'a, N> { last: usize::MAX } } /// Specify column alignment - pub fn align_left(mut self, col: usize) -> Self { + pub const fn align_left(mut self, col: usize) -> Self { self.aligns[col] = Align::Left; self } /// Specify column left margin (1st printted column never has a left margin) - pub fn margin(mut self, col: usize, margin: &'static str) -> Self { + pub const fn margin(mut self, col: usize, margin: &'static str) -> Self { self.margins[col] = margin; self } /// Specify column left margin (1st printted column never has a left margin) - pub fn last(mut self, last: usize) -> Self { + pub const fn last(mut self, last: usize) -> Self { self.last = last; self } From febd71aa60ccac669e0803ddfbe622b1315638f1 Mon Sep 17 00:00:00 2001 From: Vincent de Phily Date: Mon, 9 Sep 2024 12:26:54 +0100 Subject: [PATCH 11/12] doc: Update changelog, comparison --- CHANGELOG.md | 9 +++++++++ docs/COMPARISON.md | 18 +++++++++--------- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a377afe..694eb96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +# Unreleased + +* Improved shell completion + - Complete on package names + - Various usability tweaks + - Completion files are now distributed in git, not in the compiled binary +* Updated deps + - Notably needed to compile with Rust >= 1.80 + # 0.7.0 2024-03-04 Feature release: Multi-term search, config file, and many goodies diff --git a/docs/COMPARISON.md b/docs/COMPARISON.md index c47b0e9..3a12e94 100644 --- a/docs/COMPARISON.md +++ b/docs/COMPARISON.md @@ -160,12 +160,12 @@ the terminal emulator). Genlop is noticably slow for basic tasks, and can be pro ## misc -| | genlop | qlop | emlop | -|:---------------------------|:------------:|:------:|:-----------------:| -| Shell completion | bash | none | bash/zsh/fish/... | -| Complete package name | yes | n/a | no | -| Configuration file | no | no | yes | -| Read compressed emerge.log | yes | no | yes | -| Unittests | no | yes | yes | -| Documentation and help | ok | good | good | -| Development activity | unmaintained | active | active | +| | genlop | qlop | emlop | +|:---------------------------|:------------:|:------:|:-------------:| +| Shell completion | bash | none | bash/zsh/fish | +| Complete package name | yes | n/a | yes | +| Configuration file | no | no | yes | +| Read compressed emerge.log | yes | no | yes | +| Unittests | no | yes | yes | +| Documentation and help | ok | good | good | +| Development activity | unmaintained | active | active | From 12cc703b964dec4bbd89968b3d0f63fb84487ccf Mon Sep 17 00:00:00 2001 From: Vincent de Phily Date: Mon, 9 Sep 2024 12:52:15 +0100 Subject: [PATCH 12/12] deps: Update Bit of manual work needed to find that assert_cmd and predicates can't be updated due to msrv. `cargo update -Zmsrv-policy` not doing its job ? Removing adler v1.0.2 Adding adler2 v2.0.0 Updating aho-corasick v1.1.2 -> v1.1.3 Updating anstream v0.6.13 -> v0.6.15 Updating anstyle v1.0.6 -> v1.0.8 Updating anstyle-parse v0.2.3 -> v0.2.5 Updating anstyle-query v1.0.2 -> v1.1.1 Updating anstyle-wincon v3.0.2 -> v3.0.4 Updating anyhow v1.0.80 -> v1.0.87 Updating autocfg v1.1.0 -> v1.3.0 Updating bstr v1.9.1 -> v1.10.0 Updating colorchoice v1.0.0 -> v1.0.2 Updating crc32fast v1.4.0 -> v1.4.2 Updating crossbeam-channel v0.5.12 -> v0.5.13 Updating crossbeam-utils v0.8.19 -> v0.8.20 Updating env_filter v0.1.0 -> v0.1.2 Updating env_logger v0.11.2 -> v0.11.5 Updating flate2 v1.0.28 -> v1.0.33 Adding float-cmp v0.9.0 Updating hashbrown v0.14.3 -> v0.14.5 Updating indexmap v2.2.5 -> v2.5.0 Adding is_terminal_polyfill v1.70.1 Updating itoa v1.0.10 -> v1.0.11 Updating libc v0.2.153 -> v0.2.158 Updating log v0.4.21 -> v0.4.22 Updating memchr v2.7.1 -> v2.7.4 Updating miniz_oxide v0.7.2 -> v0.8.0 Adding normalize-line-endings v0.3.0 Updating num-traits v0.2.18 -> v0.2.19 Updating proc-macro2 v1.0.78 -> v1.0.86 Updating quote v1.0.35 -> v1.0.37 Updating regex v1.10.3 -> v1.10.6 Updating regex-automata v0.4.6 -> v0.4.7 Updating regex-syntax v0.8.2 -> v0.8.4 Updating ryu v1.0.17 -> v1.0.18 Updating serde v1.0.197 -> v1.0.210 Updating serde_derive v1.0.197 -> v1.0.210 Updating serde_json v1.0.114 -> v1.0.128 Updating serde_spanned v0.6.5 -> v0.6.7 Updating syn v2.0.52 -> v2.0.77 Updating thiserror v1.0.57 -> v1.0.63 Updating thiserror-impl v1.0.57 -> v1.0.63 Updating toml v0.8.10 -> v0.8.19 Updating toml_datetime v0.6.5 -> v0.6.8 Updating toml_edit v0.22.6 -> v0.22.20 Updating utf8parse v0.2.1 -> v0.2.2 Updating windows-targets v0.52.4 -> v0.52.6 Updating windows_aarch64_gnullvm v0.52.4 -> v0.52.6 Updating windows_aarch64_msvc v0.52.4 -> v0.52.6 Updating windows_i686_gnu v0.52.4 -> v0.52.6 Adding windows_i686_gnullvm v0.52.6 Updating windows_i686_msvc v0.52.4 -> v0.52.6 Updating windows_x86_64_gnu v0.52.4 -> v0.52.6 Updating windows_x86_64_gnullvm v0.52.4 -> v0.52.6 Updating windows_x86_64_msvc v0.52.4 -> v0.52.6 Updating winnow v0.6.5 -> v0.6.18 --- Cargo.lock | 244 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 140 insertions(+), 104 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 21ab90b..ac83d7e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,63 +3,64 @@ version = 3 [[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "anstream" -version = "0.6.13" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-parse" -version = "0.2.3" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.2" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ "windows-sys", ] [[package]] name = "anstyle-wincon" -version = "3.0.2" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", "windows-sys", @@ -67,9 +68,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.80" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" +checksum = "10f00e1f6e58a40e807377c75c6a7f97bf9044fab57816f2414e6f5f4499d7b8" [[package]] name = "assert_cmd" @@ -97,15 +98,15 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "bstr" -version = "1.9.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" +checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" dependencies = [ "memchr", "regex-automata", @@ -169,33 +170,33 @@ checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" [[package]] name = "colorchoice" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "crc32fast" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] [[package]] name = "crossbeam-channel" -version = "0.5.12" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "deranged" @@ -232,6 +233,9 @@ dependencies = [ "flate2", "libc", "log", + "predicates", + "predicates-core", + "predicates-tree", "regex", "rev_lines", "serde", @@ -242,18 +246,18 @@ dependencies = [ [[package]] name = "env_filter" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" +checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" dependencies = [ "log", ] [[package]] name = "env_logger" -version = "0.11.2" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c012a26a7f605efc424dd53697843a72be7dc86ad2d01f7814337794a12231d" +checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" dependencies = [ "anstream", "anstyle", @@ -269,19 +273,28 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "flate2" -version = "1.0.28" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" dependencies = [ "crc32fast", "miniz_oxide", ] +[[package]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" +dependencies = [ + "num-traits", +] + [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "heck" @@ -291,47 +304,59 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "indexmap" -version = "2.2.5" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" dependencies = [ "equivalent", "hashbrown", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "miniz_oxide" -version = "0.7.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" dependencies = [ - "adler", + "adler2", ] +[[package]] +name = "normalize-line-endings" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" + [[package]] name = "num-conv" version = "0.1.0" @@ -340,9 +365,9 @@ checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] name = "num-traits" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] @@ -370,7 +395,10 @@ checksum = "68b87bfd4605926cdfefc1c3b5f8fe560e3feca9d5552cf68c466d3d8236c7e8" dependencies = [ "anstyle", "difflib", + "float-cmp", + "normalize-line-endings", "predicates-core", + "regex", ] [[package]] @@ -391,27 +419,27 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.35" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] [[package]] name = "regex" -version = "1.10.3" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", @@ -421,9 +449,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", @@ -432,9 +460,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "rev_lines" @@ -447,24 +475,24 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "serde" -version = "1.0.197" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", @@ -473,20 +501,21 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.114" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] [[package]] name = "serde_spanned" -version = "0.6.5" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" dependencies = [ "serde", ] @@ -499,9 +528,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "2.0.52" +version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", @@ -516,18 +545,18 @@ checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" [[package]] name = "thiserror" -version = "1.0.57" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.57" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", @@ -569,9 +598,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.10" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a9aad4a3066010876e8dcf5a8a06e70a558751117a145c6ce2b82c2e2054290" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ "serde", "serde_spanned", @@ -581,18 +610,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.5" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.6" +version = "0.22.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c1b5fd4128cc8d3e0cb74d4ed9a9cc7c7284becd4df68f5f940e1ad123606f6" +checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" dependencies = [ "indexmap", "serde", @@ -609,9 +638,9 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "wait-timeout" @@ -633,13 +662,14 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", + "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", @@ -648,51 +678,57 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.52.4" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.5" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dffa400e67ed5a4dd237983829e66475f0a4a26938c4b04c21baede6262215b8" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" dependencies = [ "memchr", ]