fish completion fails without a second level password

Eric D. nospamthankyou at ericdeis.com
Sat Jul 13 04:32:08 CEST 2019


Thanks Benjamin.

The autocompletion for the password names wasn't working for me in your 
revision. Not sure why. However, some of the bugs I reported where still 
in there.

I did take a look at some of the improvements you made, specifically 
enhancing autocompletion of commands, and also fixed the bugs I 
reported, with the exception of not having any passwords in the store. 
That one still throws an error, and is kinda redundant anyways.

I also put in some addition hints for some commands such as `show`. Very 
user friendly and quick now.

Code below if it helps you out:

#!/usr/bin/env fish

# Copyright (C) 2012-2014 Dmitry Medvinsky <me at dmedvinsky.name>. All 
Rights Reserved.
# This file is licensed under the GPLv2+. Please see COPYING for more 
information.

# Updated 2019.

set PROG 'pass'

function __fish_pass_get_prefix
     set -l prefix "$PASSWORD_STORE_DIR"
     if [ -z "$prefix" ]
         set prefix "$HOME/.password-store"
     end
     echo "$prefix"
end

function __fish_pass_needs_command
     set -l cmd (commandline -opc)
     if [ (count $cmd) -eq 1 -a $cmd[1] = $PROG ]
         return 0
     end
     return 1
end

function __fish_pass_uses_command
     set cmd (commandline -opc)
     if [ (count $cmd) -gt 1 ]
         if [ $argv[1] = $cmd[2] ]
             return 0
         end
     end
     return 1
end

function __fish_pass_print_gpg_keys
     gpg2 --list-keys | grep uid | sed 's/.*<\(.*\)>/\1/'
end

function __fish_pass_print
     set -l ext $argv[1]
     set -l strip $argv[2]
     set -l prefix (__fish_pass_get_prefix)
     printf '%s\n' "$prefix"/**"$ext" | sed "s#$prefix/\(.*\)$strip#\1#"
end

function __fish_pass_print_entry_dirs
     # print directories if they exist
     set -l prefix (__fish_pass_get_prefix)
     set -l subdircount (find "$prefix" -maxdepth 1 -type d | wc -l)
     if [ $subdircount -gt 2 ]
         __fish_pass_print "/"
     end
end

function __fish_pass_print_entries
     __fish_pass_print ".gpg" ".gpg"
end


function __fish_pass_print_entries_and_dirs
     __fish_pass_print_entry_dirs
     __fish_pass_print_entries
end


complete -c $PROG -e

# help
complete -c $PROG -f -A -n '__fish_pass_needs_command' -a 
0__autocomplete_tip__0 -d 'TIP: type `-` then tab to get list of options 
on each command'

# help
complete -c $PROG -f -A -n '__fish_pass_needs_command' -a help -d 
'Command: show usage help'

# version
complete -c $PROG -f -A -n '__fish_pass_needs_command' -a version -d 
'Command: show program version'

# init
complete -c $PROG -f -A -n '__fish_pass_needs_command' -a init -d 
'Command: initialize new password storage'
complete -c $PROG -f -A -n '__fish_pass_uses_command init' -s p -l path 
-d 'Assign gpg-id for specified sub folder of password store'

# ls or list
complete -c $PROG -f -A -n '__fish_pass_needs_command' -a "ls list" -d 
'Command: list passwords'
complete -c $PROG -f -A -n '__fish_pass_uses_command ls' -a 
"(__fish_pass_print_entry_dirs)"
complete -c $PROG -f -A -n '__fish_pass_uses_command list' -a 
"(__fish_pass_print_entry_dirs)"

# insert or add
complete -c $PROG -f -A -n '__fish_pass_needs_command' -a "insert add" 
-d 'Command: insert new password'
complete -c $PROG -f -A -n '__fish_pass_uses_command insert' -s e -l 
echo -d 'Echo the password on console'
complete -c $PROG -f -A -n '__fish_pass_uses_command insert' -s m -l 
multiline -d 'Provide multiline password entry'
complete -c $PROG -f -A -n '__fish_pass_uses_command insert' -s f -l 
force -d 'Do not prompt before overwritting'
complete -c $PROG -f -A -n '__fish_pass_uses_command insert' -a 
"(__fish_pass_print_entry_dirs)"
complete -c $PROG -f -A -n '__fish_pass_uses_command add' -s e -l echo 
-d 'Echo the password on console'
complete -c $PROG -f -A -n '__fish_pass_uses_command add' -s m -l 
multiline -d 'Provide multiline password entry'
complete -c $PROG -f -A -n '__fish_pass_uses_command add' -s f -l force 
-d 'Do not prompt before overwritting'
complete -c $PROG -f -A -n '__fish_pass_uses_command add' -a 
"(__fish_pass_print_entry_dirs)"

# generate
complete -c $PROG -f -A -n '__fish_pass_needs_command' -a generate -d 
'Command: generate new password'
complete -c $PROG -f -A -n '__fish_pass_uses_command generate' -s n -l 
no-symbols -d 'Do not use special symbols'
complete -c $PROG -f -A -n '__fish_pass_uses_command generate' -s c -l 
clip -d 'Put the password in clipboard'
complete -c $PROG -f -A -n '__fish_pass_uses_command generate' -s f -l 
force -d 'Do not prompt before overwritting'
complete -c $PROG -f -A -n '__fish_pass_uses_command generate' -s i -l 
in-place -d 'Replace only the first line with the generated password'
complete -c $PROG -f -A -n '__fish_pass_uses_command generate' -a 
"(__fish_pass_print_entry_dirs)"

# mv
complete -c $PROG -f -A -n '__fish_pass_needs_command' -a mv -d 
'Command: rename existing password'
complete -c $PROG -f -A -n '__fish_pass_uses_command mv' -s f -l force 
-d 'Force rename'
complete -c $PROG -f -A -n '__fish_pass_uses_command mv' -a 
"(__fish_pass_print_entries_and_dirs)"

# cp
complete -c $PROG -f -A -n '__fish_pass_needs_command' -a cp -d 
'Command: copy existing password'
complete -c $PROG -f -A -n '__fish_pass_uses_command cp' -s f -l force 
-d 'Force copy'
complete -c $PROG -f -A -n '__fish_pass_uses_command cp' -a 
"(__fish_pass_print_entries_and_dirs)"

# rm
complete -c $PROG -f -A -n '__fish_pass_needs_command' -a rm -d 
'Command: remove existing password'
complete -c $PROG -f -A -n '__fish_pass_uses_command rm' -s r -l 
recursive -d 'Remove password groups recursively'
complete -c $PROG -f -A -n '__fish_pass_uses_command rm' -s f -l force 
-d 'Force removal'
complete -c $PROG -f -A -n '__fish_pass_uses_command rm' -a 
"(__fish_pass_print_entries_and_dirs)"

# edit
complete -c $PROG -f -A -n '__fish_pass_needs_command' -a edit -d 
'Command: edit password using text editor'
complete -c $PROG -f -A -n '__fish_pass_uses_command edit' -a 
"(__fish_pass_print_entries)"

# show
complete -c $PROG -f -A -n '__fish_pass_needs_command' -a show -d 
'Command: show existing password. Options: --clip -c'
complete -c $PROG -f -A -n '__fish_pass_uses_command show' -s c -l clip 
-d 'Put password in clipboard. Use -c1 to clip first line of a 
multiline. Usage: -c[line-number]'
complete -c $PROG -f -A -n '__fish_pass_uses_command show' -a 
"(__fish_pass_print_entries)"

# When no command is given, `show` is defaulted.
# DISABLED for better usability. Auto complete on pass command itself 
should only show the available commands, and not all the keys in the folder!
# complete -c $PROG -f -A -n '__fish_pass_needs_command' -s c -l clip -d 
'Put password in clipboard'
# complete -c $PROG -f -A -n '__fish_pass_needs_command' -a 
"(__fish_pass_print_entries)"
# complete -c $PROG -f -A -n '__fish_pass_uses_command -c' -a 
"(__fish_pass_print_entries)"
# complete -c $PROG -f -A -n '__fish_pass_uses_command --clip' -a 
"(__fish_pass_print_entries)"

# git
complete -c $PROG -f -A -n '__fish_pass_needs_command' -a git -d 
'Command: execute a git command'
complete -c $PROG -f -A -n '__fish_pass_uses_command git' -a 'init' -d 
'Initialize git repository'
complete -c $PROG -f -A -n '__fish_pass_uses_command git' -a 'status' -d 
'Show status of the repo'
complete -c $PROG -f -A -n '__fish_pass_uses_command git' -a 'add' -d 
'Add changes to the index'
complete -c $PROG -f -A -n '__fish_pass_uses_command git' -a 'commit' -d 
'Commit changes to the repo'
complete -c $PROG -f -A -n '__fish_pass_uses_command git' -a 'push' -d 
'Push changes to remote repo'
complete -c $PROG -f -A -n '__fish_pass_uses_command git' -a 'pull' -d 
'Pull changes from remote repo'
complete -c $PROG -f -A -n '__fish_pass_uses_command git' -a 'log' -d 
'View changelog'

# find or search
complete -f -c pass -n '__fish_pass_needs_command' -a "find search" -d 
'find a password file or directory matching pattern'
complete -x -c pass -n '__fish_pass_uses_command search'
complete -x -c pass -n '__fish_pass_uses_command find'

# grep
complete -c $PROG -f -A -n '__fish_pass_needs_command' -a grep -d 
'Command: search inside of decrypted password files for matching pattern'





On 2019-07-12 01:17, Benjamin Martin wrote:
> Hey Eric,
>
> The fish completions available from 
> https://git.zx2c4.com/password-store/tree/src/completion/pass.fish-completion are 
> quite broken. I sent an email a long time ago on this mailing list 
> with a fixed version of the fish completions, but nobody seemed to 
> care nor were the broken completions ever fixed. If you want working 
> fish completions save the below text in 
> ~/.config/fish/completions/pass.fish (it does require you have both 
> awk and find in your path, let me know if you run into any bugs):
>
> function __fish_pass_get_prefix
>     set -l prefix "$PASSWORD_STORE_DIR"
>     if [ -z "$prefix" ]
>         set prefix "$HOME/.password-store"
>     end
>     echo "$prefix"
> end
>
> function __fish_pass_needs_command
>     set -l cmd (commandline -opc)
>     if [ (count $cmd) -eq 1 -a $cmd[1] = pass ]
>         return 0
>     end
>     return 1
> end
>
> function __fish_pass_uses_command
>     set cmd (commandline -opc)
>     if [ (count $cmd) -gt 1 ]
>         if [ $argv[1] = $cmd[2] ]
>             return 0
>         end
>     end
>     return 1
> end
>
> function __fish_pass_print_gpg_keys
>     gpg2 --list-secret-keys | awk '/sec/{getline l1; getline l2; 
> gsub(/ /, "",l1); print l1 "\011" l2}'
> end
>
> function __fish_pass_print_entry_dirs
>     cd (__fish_pass_get_prefix); ls -d **/
> end
>
> function __fish_pass_print_entries
>     cd (__fish_pass_get_prefix); find . -type f -name "*.gpg" | sed 
> "s/\.\/\|.gpg//g"
> end
>
> function __fish_pass_print_entries_and_dirs
>     __fish_pass_print_entry_dirs
>     __fish_pass_print_entries
> end
>
> # init
> complete -f -c pass -n '__fish_pass_needs_command' -a init -d 
> 'initialize new password storage'
> complete -x -c pass -n '__fish_pass_uses_command init' -s p -l path -a 
> '(__fish_pass_print_entry_dirs)' -d 'Assign gpg-id for specified sub 
> folder of password store'
> complete -f -k -c pass -n '__fish_pass_uses_command init' -a 
> '(__fish_pass_print_gpg_keys)'
>
> # ls
> complete -f -c pass -n '__fish_pass_needs_command' -a ls -d 'list 
> passwords'
> complete -x -c pass -n '__fish_pass_uses_command ls' -a 
> '(__fish_pass_print_entry_dirs)'
>
> # grep
> complete -f -c pass -n '__fish_pass_needs_command' -a grep -d 'search 
> inside of decrypted password files for matching pattern'
> complete -x -c pass -n '__fish_pass_uses_command grep'
>
> # find or search
> complete -f -c pass -n '__fish_pass_needs_command' -a "find search" -d 
> 'find a password file or directory matching pattern'
> complete -x -c pass -n '__fish_pass_uses_command search'
> complete -x -c pass -n '__fish_pass_uses_command find'
>
> # show
> complete -f -c pass -n '__fish_pass_needs_command' -a show -d 'show 
> existing password'
> complete -f -c pass -n '__fish_pass_uses_command show' -s c -l clip -d 
> 'copy first (or otherwise specified) line to the clipboard'
> complete -f -c pass -n '__fish_pass_uses_command show' -s q -l qrcode 
> -d 'display a QR code of the (or otherwise specified) first line'
> complete -f -c pass -n '__fish_pass_uses_command show' -a 
> '(__fish_pass_print_entries)'
>
> # insert
> complete -f -c pass -n '__fish_pass_needs_command' -a insert -d 
> 'insert new password'
> complete -f -c pass -n '__fish_pass_uses_command insert' -s e -l echo 
> -d 'Echo the password on console'
> complete -f -c pass -n '__fish_pass_uses_command insert' -s m -l 
> multiline -d 'Provide multiline password entry'
> complete -f -c pass -n '__fish_pass_uses_command insert' -s f -l force 
> -d 'Do not prompt before overwritting'
> complete -f -c pass -n '__fish_pass_uses_command insert' -a 
> "(__fish_pass_print_entry_dirs)"
>
> # edit
> complete -f -c pass -n '__fish_pass_needs_command' -a edit -d 'edit 
> password using text editor'
> complete -f -c pass -n '__fish_pass_uses_command edit' -a 
> "(__fish_pass_print_entries)"
>
> # generate
> complete -f -c pass -n '__fish_pass_needs_command' -a generate -d 
> 'generate new password'
> complete -f -c pass -n '__fish_pass_uses_command generate' -s n -l 
> no-symbols -d 'Do not use special symbols'
> complete -f -c pass -n '__fish_pass_uses_command generate' -s c -l 
> clip -d 'Put the password in clipboard'
> complete -f -c pass -n '__fish_pass_uses_command generate' -s f -l 
> force -d 'Do not prompt before overwritting'
> complete -f -c pass -n '__fish_pass_uses_command generate' -s i -l 
> in-place -d 'Replace only the first line with the generated password'
> complete -f -c pass -n '__fish_pass_uses_command generate' -a 
> "(__fish_pass_print_entries_and_dirs)"
>
> # rm
> complete -f -c pass -n '__fish_pass_needs_command' -a rm -d 'remove 
> existing password'
> complete -f -c pass -n '__fish_pass_uses_command rm' -s r -l recursive 
> -d 'Remove password groups recursively'
> complete -f -c pass -n '__fish_pass_uses_command rm' -s f -l force -d 
> 'Force removal'
> complete -f -c pass -n '__fish_pass_uses_command rm' -a 
> "(__fish_pass_print_entries_and_dirs)"
>
> # mv
> complete -f -c pass -n '__fish_pass_needs_command' -a mv -d 'rename 
> existing password'
> complete -f -c pass -n '__fish_pass_uses_command mv' -s f -l force -d 
> 'Force rename'
> complete -f -c pass -n '__fish_pass_uses_command mv' -a 
> "(__fish_pass_print_entries_and_dirs)"
>
> # cp
> complete -f -c pass -n '__fish_pass_needs_command' -a cp -d 'copy 
> existing password'
> complete -f -c pass -n '__fish_pass_uses_command cp' -s f -l force -d 
> 'Force copy'
> complete -f -c pass -n '__fish_pass_uses_command cp' -a 
> "(__fish_pass_print_entries_and_dirs)"
>
> # git
> complete -f -c pass -n '__fish_pass_needs_command' -a git -d 'execute 
> a git command'
> complete -f -c pass -f -n '__fish_pass_uses_command git' -a 'init' -d 
> 'Initialize git repository'
> complete -f -c pass -f -n '__fish_pass_uses_command git' -a 'status' 
> -d 'Show status of the repo'
> complete -f -c pass -f -n '__fish_pass_uses_command git' -a 'add' -d 
> 'Add changes to the index'
> complete -f -c pass -f -n '__fish_pass_uses_command git' -a 'commit' 
> -d 'Commit changes to the repo'
> complete -f -c pass -f -n '__fish_pass_uses_command git' -a 'push' -d 
> 'Push changes to remote repo'
> complete -f -c pass -f -n '__fish_pass_uses_command git' -a 'pull' -d 
> 'Pull changes from remote repo'
> complete -f -c pass -f -n '__fish_pass_uses_command git' -a 'log' -d 
> 'View changelog'
>
> # help
> complete -f -c pass -n '__fish_pass_needs_command' -a help -d 'show 
> usage help'
>
> # version
> complete -f -c pass -n '__fish_pass_needs_command' -a version -d 'show 
> program version'
>
>
>> On 12 Jul 2019, at 4:52 pm, Eric D. <nospamthankyou at ericdeis.com 
>> <mailto:nospamthankyou at ericdeis.com>> wrote:
>>
>> Given the following passwords, without any folders:
>> Password Store
>> ├── app1
>> ├── app2
>> ├── test
>> ├── test2
>> └── test3
>>
>> Autocompletion fails via rm command.
>> $ pass rm t[tab]
>> ~/.config/fish/completions/pass.fish (line 4): No matches for 
>> wildcard '"$prefix"/**"$ext"'. See `help expand`.        23:37:31
>>     printf '%s\n' "$prefix"/**"$ext" | sed "s#$prefix/\(.*\)$strip#\1#"
>>                   ^
>> in function '__fish_pass_print'
>>     called on line 50 of file ~/.config/fish/completions/pass.fish
>>     with parameter list '.gpg .gpg'
>>
>> in function '__fish_pass_print_entries'
>>     called on standard input
>>
>> Given the following passwords, with one folder:
>> Password Store
>> ├── app1
>> ├── app2
>> ├── foo
>> │   └── bar
>> ├── test
>> ├── test2
>> └── test3
>>
>> $ pass rm t[tab]
>> Autocompletion now works!
>>
>> Also if there are zero passwords in the store, Autocompletion throws 
>> the same error below.
>> $ pass fo[tab]
>> ~/.config/fish/completions/pass.fish (line 4): No matches for 
>> wildcard '"$prefix"/**"$ext"'. See `help expand`.           23:47:40
>>     printf '%s\n' "$prefix"/**"$ext" | sed "s#$prefix/\(.*\)$strip#\1#"
>>
>> _______________________________________________
>> Password-Store mailing list
>> Password-Store at lists.zx2c4.com <mailto:Password-Store at lists.zx2c4.com>
>> https://lists.zx2c4.com/mailman/listinfo/password-store
>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.zx2c4.com/pipermail/password-store/attachments/20190712/47d27296/attachment-0001.html>


More information about the Password-Store mailing list