auto completion with tab: separate commands and tree structure
J Rt
jean.rblt at gmail.com
Sat Mar 28 16:13:09 CET 2020
FYI, here is the new autocompletion script I am now using on my
machine. It shows in order 1) the commands 2) the options 3) the paths
/ files. Each of 1) 2) and 3) is internally sorted. Let me know if you
want to merge into master / how I should perform a push request on
your self-hosted repo :)
# completion file for bash
# Copyright (C) 2012 - 2014 Jason A. Donenfeld <Jason at zx2c4.com> and
# Brian Mattern <rephorm at rephorm.com>. All Rights Reserved.
# This file is licensed under the GPLv2+. Please see COPYING for more
information.
# Edited by Jean Rabault 2020
_sort_entries_string () {
# local sorted_list=$(echo $1 | xargs -n1 | sort | xargs)
local sorted_list=$(echo $1 | tr ' ' '\n' | sort | tr '\n' ' ')
echo $sorted_list
}
_setup_tmp_compreply () {
TMP_COMPREPLY=()
}
_append_tmp_compreply () {
# sort the TMP_COMPREPLY array
IFS=$'\n' TMP_COMPREPLY=($(sort <<<"${TMP_COMPREPLY[*]}")); unset IFS
# append the tmp array to the COMPREPLY
COMPREPLY+=( "${TMP_COMPREPLY[@]}" )
}
_pass_complete_entries () {
_setup_tmp_compreply
prefix="${PASSWORD_STORE_DIR:-$HOME/.password-store/}"
prefix="${prefix%/}/"
suffix=".gpg"
autoexpand=${1:-0}
local IFS=$'\n'
local items=($(compgen -f $prefix$cur))
# Remember the value of the first item, to see if it is a directory. If
# it is a directory, then don't add a space to the completion
local firstitem=""
# Use counter, can't use ${#items[@]} as we skip hidden directories
local i=0
for item in ${items[@]}; do
[[ $item =~ /\.[^/]*$ ]] && continue
# if there is a unique match, and it is a directory with one entry
# autocomplete the subentry as well (recursively)
if [[ ${#items[@]} -eq 1 && $autoexpand -eq 1 ]]; then
while [[ -d $item ]]; do
local subitems=($(compgen -f "$item/"))
local filtereditems=( )
for item2 in "${subitems[@]}"; do
[[ $item2 =~ /\.[^/]*$ ]] && continue
filtereditems+=( "$item2" )
done
if [[ ${#filtereditems[@]} -eq 1 ]]; then
item="${filtereditems[0]}"
else
break
fi
done
fi
# append / to directories
[[ -d $item ]] && item="$item/"
item="${item%$suffix}"
TMP_COMPREPLY+=("${item#$prefix}")
if [[ $i -eq 0 ]]; then
firstitem=$item
fi
let i+=1
done
# The only time we want to add a space to the end is if there is only
# one match, and it is not a directory
if [[ $i -gt 1 || ( $i -eq 1 && -d $firstitem ) ]]; then
compopt -o nospace
fi
_append_tmp_compreply
}
_pass_complete_folders () {
_setup_tmp_compreply
prefix="${PASSWORD_STORE_DIR:-$HOME/.password-store/}"
prefix="${prefix%/}/"
local IFS=$'\n'
local items=($(compgen -d $prefix$cur))
for item in ${items[@]}; do
[[ $item == $prefix.* ]] && continue
TMP_COMPREPLY+=("${item#$prefix}/")
done
_append_tmp_compreply
}
_pass_complete_keys () {
_setup_tmp_compreply
local IFS=$'\n'
local GPG=gpg2
which $GPG >/dev/null || GPG=gpg
# Extract names and email addresses from gpg --list-keys
local keys="$($GPG --list-secret-keys --with-colons | cut -d : -f
10 | sort -u | sed '/^$/d')"
TMP_COMPREPLY+=($(compgen -W "${keys}" -- ${cur}))
_append_tmp_compreply
}
_pass()
{
COMPREPLY=()
local cur="${COMP_WORDS[COMP_CWORD]}"
local commands=$(_sort_entries_string "init ls find grep show
insert generate edit rm mv cp git help version")
if [[ $COMP_CWORD -gt 1 ]]; then
local lastarg="${COMP_WORDS[$COMP_CWORD-1]}"
case "${COMP_WORDS[1]}" in
init)
if [[ $lastarg == "-p" || $lastarg == "--path" ]]; then
_pass_complete_folders
compopt -o nospace
else
COMPREPLY+=($(compgen -W "-p --path" -- ${cur}))
_pass_complete_keys
fi
;;
ls|list|edit)
_pass_complete_entries
;;
show|-*)
COMPREPLY+=($(compgen -W "-c --clip" -- ${cur}))
_pass_complete_entries 1
;;
insert)
COMPREPLY+=($(compgen -W "-e --echo -m --multiline -f
--force" -- ${cur}))
_pass_complete_entries
;;
generate)
COMPREPLY+=($(compgen -W "-n --no-symbols -c --clip -f
--force -i --in-place" -- ${cur}))
_pass_complete_entries
;;
cp|copy|mv|rename)
COMPREPLY+=($(compgen -W "-f --force" -- ${cur}))
_pass_complete_entries
;;
rm|remove|delete)
COMPREPLY+=($(compgen -W "-r --recursive -f --force" -- ${cur}))
_pass_complete_entries
;;
git)
COMPREPLY+=($(compgen -W "init push pull config log
reflog rebase" -- ${cur}))
;;
esac
else
COMPREPLY+=($(compgen -W "${commands}" -- ${cur}))
_pass_complete_entries 1
fi
}
complete -o nosort -o filenames -F _pass pass
On Sat, Mar 28, 2020 at 2:45 PM J Rt <jean.rblt at gmail.com> wrote:
>
> Thanks for your help, got it to work now. All was needed is change the
> last line of the autocomplete script to:
>
> complete -o nosort -o filenames -F _pass pass
>
> the nosort option cancels the sorting done in the background by bash.
> Found it there, should be ok with bash 4.4 and higher:
>
> https://unix.stackexchange.com/questions/215937/disable-sorting-of-compreply-in-bash-complete-function
>
> now when hitting tab tab I get first the (1){pass commands or
> options}, then the (2){folders / files}.
>
> The sets (1) and (2) are not sorted though, but I think I will get it
> done easily.
>
> On Sat, Mar 28, 2020 at 8:50 AM Reed Wade <reedwade at misterbanal.net> wrote:
> >
> > > Ok, sounds good. Do you agree that this would be a bit nicer tab
> > > autocompletion? Or do you mind a lot having to type 'show' to get the
> > > second autocompletion? :) .
> >
> > I just always type 'show' so it only giving me the tree.
> >
> > > Do you think you would be able to implement the change you described
> > > in your last message?
> >
> > I don't think anyone want to remove the command shortcut show sorry :D
> >
> > > If not I can give it a look / try, but I do not
> > > have too much experience with this sort of scripting.
> >
> > I think the better thing to do in this case, is downloading the
> > pass script and the autocompletion script, putting them in your ~/bin
> > and .local/share/bash-completion/completions/ pathes and customize them.
> >
> > Removing the shortcut probably is easy, adapting the autocompletion
> > script will need a little more understanding.
> >
> > A little tuto I use myself is :
> > https://opensource.com/article/18/3/creating-bash-completion-script
More information about the Password-Store
mailing list