<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body text="#FFFFFF" bgcolor="#333333">
Thanks Benjamin.<br>
<br>
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.<br>
<br>
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.<br>
<br>
I also put in some addition hints for some commands such as `show`.
Very user friendly and quick now. <br>
<br>
Code below if it helps you out:<br>
<br>
#!/usr/bin/env fish<br>
<br>
# Copyright (C) 2012-2014 Dmitry Medvinsky
<a class="moz-txt-link-rfc2396E" href="mailto:me@dmedvinsky.name"><me@dmedvinsky.name></a>. All Rights Reserved.<br>
# This file is licensed under the GPLv2+. Please see COPYING for
more information.<br>
<br>
# Updated 2019.<br>
<br>
set PROG 'pass'<br>
<br>
function __fish_pass_get_prefix<br>
set -l prefix "$PASSWORD_STORE_DIR"<br>
if [ -z "$prefix" ]<br>
set prefix "$HOME/.password-store"<br>
end<br>
echo "$prefix"<br>
end<br>
<br>
function __fish_pass_needs_command<br>
set -l cmd (commandline -opc)<br>
if [ (count $cmd) -eq 1 -a $cmd[1] = $PROG ]<br>
return 0<br>
end<br>
return 1<br>
end<br>
<br>
function __fish_pass_uses_command<br>
set cmd (commandline -opc)<br>
if [ (count $cmd) -gt 1 ]<br>
if [ $argv[1] = $cmd[2] ]<br>
return 0<br>
end<br>
end<br>
return 1<br>
end<br>
<br>
function __fish_pass_print_gpg_keys<br>
gpg2 --list-keys | grep uid | sed 's/.*<\(.*\)>/\1/'<br>
end<br>
<br>
function __fish_pass_print<br>
set -l ext $argv[1]<br>
set -l strip $argv[2]<br>
set -l prefix (__fish_pass_get_prefix)<br>
printf '%s\n' "$prefix"/**"$ext" | sed
"s#$prefix/\(.*\)$strip#\1#"<br>
end<br>
<br>
function __fish_pass_print_entry_dirs<br>
# print directories if they exist<br>
set -l prefix (__fish_pass_get_prefix)<br>
set -l subdircount (find "$prefix" -maxdepth 1 -type d | wc -l)<br>
if [ $subdircount -gt 2 ]<br>
__fish_pass_print "/"<br>
end<br>
end<br>
<br>
function __fish_pass_print_entries<br>
__fish_pass_print ".gpg" ".gpg"<br>
end<br>
<br>
<br>
function __fish_pass_print_entries_and_dirs<br>
__fish_pass_print_entry_dirs<br>
__fish_pass_print_entries<br>
end<br>
<br>
<br>
complete -c $PROG -e<br>
<br>
# help<br>
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'<br>
<br>
# help<br>
complete -c $PROG -f -A -n '__fish_pass_needs_command' -a help -d
'Command: show usage help'<br>
<br>
# version<br>
complete -c $PROG -f -A -n '__fish_pass_needs_command' -a version -d
'Command: show program version'<br>
<br>
# init<br>
complete -c $PROG -f -A -n '__fish_pass_needs_command' -a init -d
'Command: initialize new password storage'<br>
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'<br>
<br>
# ls or list <br>
complete -c $PROG -f -A -n '__fish_pass_needs_command' -a "ls list"
-d 'Command: list passwords'<br>
complete -c $PROG -f -A -n '__fish_pass_uses_command ls' -a
"(__fish_pass_print_entry_dirs)"<br>
complete -c $PROG -f -A -n '__fish_pass_uses_command list' -a
"(__fish_pass_print_entry_dirs)"<br>
<br>
# insert or add<br>
complete -c $PROG -f -A -n '__fish_pass_needs_command' -a "insert
add" -d 'Command: insert new password'<br>
complete -c $PROG -f -A -n '__fish_pass_uses_command insert' -s e -l
echo -d 'Echo the password on console'<br>
complete -c $PROG -f -A -n '__fish_pass_uses_command insert' -s m -l
multiline -d 'Provide multiline password entry'<br>
complete -c $PROG -f -A -n '__fish_pass_uses_command insert' -s f -l
force -d 'Do not prompt before overwritting'<br>
complete -c $PROG -f -A -n '__fish_pass_uses_command insert' -a
"(__fish_pass_print_entry_dirs)"<br>
complete -c $PROG -f -A -n '__fish_pass_uses_command add' -s e -l
echo -d 'Echo the password on console'<br>
complete -c $PROG -f -A -n '__fish_pass_uses_command add' -s m -l
multiline -d 'Provide multiline password entry'<br>
complete -c $PROG -f -A -n '__fish_pass_uses_command add' -s f -l
force -d 'Do not prompt before overwritting'<br>
complete -c $PROG -f -A -n '__fish_pass_uses_command add' -a
"(__fish_pass_print_entry_dirs)"<br>
<br>
# generate<br>
complete -c $PROG -f -A -n '__fish_pass_needs_command' -a generate
-d 'Command: generate new password'<br>
complete -c $PROG -f -A -n '__fish_pass_uses_command generate' -s n
-l no-symbols -d 'Do not use special symbols'<br>
complete -c $PROG -f -A -n '__fish_pass_uses_command generate' -s c
-l clip -d 'Put the password in clipboard'<br>
complete -c $PROG -f -A -n '__fish_pass_uses_command generate' -s f
-l force -d 'Do not prompt before overwritting'<br>
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'<br>
complete -c $PROG -f -A -n '__fish_pass_uses_command generate' -a
"(__fish_pass_print_entry_dirs)"<br>
<br>
# mv<br>
complete -c $PROG -f -A -n '__fish_pass_needs_command' -a mv -d
'Command: rename existing password'<br>
complete -c $PROG -f -A -n '__fish_pass_uses_command mv' -s f -l
force -d 'Force rename'<br>
complete -c $PROG -f -A -n '__fish_pass_uses_command mv' -a
"(__fish_pass_print_entries_and_dirs)"<br>
<br>
# cp<br>
complete -c $PROG -f -A -n '__fish_pass_needs_command' -a cp -d
'Command: copy existing password'<br>
complete -c $PROG -f -A -n '__fish_pass_uses_command cp' -s f -l
force -d 'Force copy'<br>
complete -c $PROG -f -A -n '__fish_pass_uses_command cp' -a
"(__fish_pass_print_entries_and_dirs)"<br>
<br>
# rm<br>
complete -c $PROG -f -A -n '__fish_pass_needs_command' -a rm -d
'Command: remove existing password'<br>
complete -c $PROG -f -A -n '__fish_pass_uses_command rm' -s r -l
recursive -d 'Remove password groups recursively'<br>
complete -c $PROG -f -A -n '__fish_pass_uses_command rm' -s f -l
force -d 'Force removal'<br>
complete -c $PROG -f -A -n '__fish_pass_uses_command rm' -a
"(__fish_pass_print_entries_and_dirs)"<br>
<br>
# edit<br>
complete -c $PROG -f -A -n '__fish_pass_needs_command' -a edit -d
'Command: edit password using text editor'<br>
complete -c $PROG -f -A -n '__fish_pass_uses_command edit' -a
"(__fish_pass_print_entries)"<br>
<br>
# show<br>
complete -c $PROG -f -A -n '__fish_pass_needs_command' -a show -d
'Command: show existing password. Options: --clip -c'<br>
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]'<br>
complete -c $PROG -f -A -n '__fish_pass_uses_command show' -a
"(__fish_pass_print_entries)"<br>
<br>
# When no command is given, `show` is defaulted.<br>
# DISABLED for better usability. Auto complete on pass command
itself should only show the available commands, and not all the keys
in the folder!<br>
# complete -c $PROG -f -A -n '__fish_pass_needs_command' -s c -l
clip -d 'Put password in clipboard'<br>
# complete -c $PROG -f -A -n '__fish_pass_needs_command' -a
"(__fish_pass_print_entries)"<br>
# complete -c $PROG -f -A -n '__fish_pass_uses_command -c' -a
"(__fish_pass_print_entries)"<br>
# complete -c $PROG -f -A -n '__fish_pass_uses_command --clip' -a
"(__fish_pass_print_entries)"<br>
<br>
# git<br>
complete -c $PROG -f -A -n '__fish_pass_needs_command' -a git -d
'Command: execute a git command'<br>
complete -c $PROG -f -A -n '__fish_pass_uses_command git' -a 'init'
-d 'Initialize git repository'<br>
complete -c $PROG -f -A -n '__fish_pass_uses_command git' -a
'status' -d 'Show status of the repo'<br>
complete -c $PROG -f -A -n '__fish_pass_uses_command git' -a 'add'
-d 'Add changes to the index'<br>
complete -c $PROG -f -A -n '__fish_pass_uses_command git' -a
'commit' -d 'Commit changes to the repo'<br>
complete -c $PROG -f -A -n '__fish_pass_uses_command git' -a 'push'
-d 'Push changes to remote repo'<br>
complete -c $PROG -f -A -n '__fish_pass_uses_command git' -a 'pull'
-d 'Pull changes from remote repo'<br>
complete -c $PROG -f -A -n '__fish_pass_uses_command git' -a 'log'
-d 'View changelog'<br>
<br>
# find or search<br>
complete -f -c pass -n '__fish_pass_needs_command' -a "find search"
-d 'find a password file or directory matching pattern'<br>
complete -x -c pass -n '__fish_pass_uses_command search' <br>
complete -x -c pass -n '__fish_pass_uses_command find'<br>
<br>
# grep<br>
complete -c $PROG -f -A -n '__fish_pass_needs_command' -a grep -d
'Command: search inside of decrypted password files for matching
pattern'<br>
<br>
<br>
<br>
<br>
<br>
<div class="moz-cite-prefix">On 2019-07-12 01:17, Benjamin Martin
wrote:<br>
</div>
<blockquote type="cite"
cite="mid:9F778B26-6503-4980-9C60-04A6513DB7DD@gmail.com">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
Hey Eric,
<div class=""><br class="">
</div>
<div class="">The fish completions available from <a
href="https://git.zx2c4.com/password-store/tree/src/completion/pass.fish-completion"
class="" moz-do-not-send="true">https://git.zx2c4.com/password-store/tree/src/completion/pass.fish-completion</a> 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):</div>
<div class=""><br class="">
</div>
<div class="">
<div class="">function __fish_pass_get_prefix</div>
<div class=""> set -l prefix "$PASSWORD_STORE_DIR"</div>
<div class=""> if [ -z "$prefix" ]</div>
<div class=""> set prefix "$HOME/.password-store"</div>
<div class=""> end</div>
<div class=""> echo "$prefix"</div>
<div class="">end</div>
<div class=""><br class="">
</div>
<div class="">function __fish_pass_needs_command</div>
<div class=""> set -l cmd (commandline -opc)</div>
<div class=""> if [ (count $cmd) -eq 1 -a $cmd[1] = pass ]</div>
<div class=""> return 0</div>
<div class=""> end</div>
<div class=""> return 1</div>
<div class="">end</div>
<div class=""><br class="">
</div>
<div class="">function __fish_pass_uses_command</div>
<div class=""> set cmd (commandline -opc)</div>
<div class=""> if [ (count $cmd) -gt 1 ]</div>
<div class=""> if [ $argv[1] = $cmd[2] ]</div>
<div class=""> return 0</div>
<div class=""> end</div>
<div class=""> end</div>
<div class=""> return 1</div>
<div class="">end</div>
<div class=""><br class="">
</div>
<div class="">function __fish_pass_print_gpg_keys</div>
<div class=""> gpg2 --list-secret-keys | awk '/sec/{getline
l1; getline l2; gsub(/ /, "",l1); print l1 "\011" l2}'</div>
<div class="">end</div>
<div class=""><br class="">
</div>
<div class="">function __fish_pass_print_entry_dirs</div>
<div class=""> cd (__fish_pass_get_prefix); ls -d **/</div>
<div class="">end</div>
<div class=""><br class="">
</div>
<div class="">function __fish_pass_print_entries</div>
<div class=""> cd (__fish_pass_get_prefix); find . -type f
-name "*.gpg" | sed "s/\.\/\|.gpg//g"</div>
<div class="">end</div>
<div class=""><br class="">
</div>
<div class="">function __fish_pass_print_entries_and_dirs</div>
<div class=""> __fish_pass_print_entry_dirs</div>
<div class=""> __fish_pass_print_entries</div>
<div class="">end</div>
<div class=""><br class="">
</div>
<div class=""># init</div>
<div class="">complete -f -c pass -n '__fish_pass_needs_command'
-a init -d 'initialize new password storage'</div>
<div class="">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'</div>
<div class="">complete -f -k -c pass -n
'__fish_pass_uses_command init' -a
'(__fish_pass_print_gpg_keys)'</div>
<div class=""><br class="">
</div>
<div class=""># ls</div>
<div class="">complete -f -c pass -n '__fish_pass_needs_command'
-a ls -d 'list passwords'</div>
<div class="">complete -x -c pass -n '__fish_pass_uses_command
ls' -a '(__fish_pass_print_entry_dirs)'</div>
<div class=""><br class="">
</div>
<div class=""># grep</div>
<div class="">complete -f -c pass -n '__fish_pass_needs_command'
-a grep -d 'search inside of decrypted password files for
matching pattern'</div>
<div class="">complete -x -c pass -n '__fish_pass_uses_command
grep' </div>
<div class=""><br class="">
</div>
<div class=""># find or search</div>
<div class="">complete -f -c pass -n '__fish_pass_needs_command'
-a "find search" -d 'find a password file or directory
matching pattern'</div>
<div class="">complete -x -c pass -n '__fish_pass_uses_command
search' </div>
<div class="">complete -x -c pass -n '__fish_pass_uses_command
find'</div>
<div class=""><br class="">
</div>
<div class=""># show</div>
<div class="">complete -f -c pass -n '__fish_pass_needs_command'
-a show -d 'show existing password'</div>
<div class="">complete -f -c pass -n '__fish_pass_uses_command
show' -s c -l clip -d 'copy first (or otherwise specified)
line to the clipboard'</div>
<div class="">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'</div>
<div class="">complete -f -c pass -n '__fish_pass_uses_command
show' -a '(__fish_pass_print_entries)' </div>
<div class=""><br class="">
</div>
<div class=""># insert</div>
<div class="">complete -f -c pass -n '__fish_pass_needs_command'
-a insert -d 'insert new password'</div>
<div class="">complete -f -c pass -n '__fish_pass_uses_command
insert' -s e -l echo -d 'Echo the password on console'</div>
<div class="">complete -f -c pass -n '__fish_pass_uses_command
insert' -s m -l multiline -d 'Provide multiline password
entry'</div>
<div class="">complete -f -c pass -n '__fish_pass_uses_command
insert' -s f -l force -d 'Do not prompt before overwritting'</div>
<div class="">complete -f -c pass -n '__fish_pass_uses_command
insert' -a "(__fish_pass_print_entry_dirs)"</div>
<div class=""><br class="">
</div>
<div class=""># edit</div>
<div class="">complete -f -c pass -n '__fish_pass_needs_command'
-a edit -d 'edit password using text editor'</div>
<div class="">complete -f -c pass -n '__fish_pass_uses_command
edit' -a "(__fish_pass_print_entries)"</div>
<div class=""><br class="">
</div>
<div class=""># generate</div>
<div class="">complete -f -c pass -n '__fish_pass_needs_command'
-a generate -d 'generate new password'</div>
<div class="">complete -f -c pass -n '__fish_pass_uses_command
generate' -s n -l no-symbols -d 'Do not use special symbols'</div>
<div class="">complete -f -c pass -n '__fish_pass_uses_command
generate' -s c -l clip -d 'Put the password in clipboard'</div>
<div class="">complete -f -c pass -n '__fish_pass_uses_command
generate' -s f -l force -d 'Do not prompt before overwritting'</div>
<div class="">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'</div>
<div class="">complete -f -c pass -n '__fish_pass_uses_command
generate' -a "(__fish_pass_print_entries_and_dirs)"</div>
<div class=""><br class="">
</div>
<div class=""># rm</div>
<div class="">complete -f -c pass -n '__fish_pass_needs_command'
-a rm -d 'remove existing password'</div>
<div class="">complete -f -c pass -n '__fish_pass_uses_command
rm' -s r -l recursive -d 'Remove password groups recursively'</div>
<div class="">complete -f -c pass -n '__fish_pass_uses_command
rm' -s f -l force -d 'Force removal'</div>
<div class="">complete -f -c pass -n '__fish_pass_uses_command
rm' -a "(__fish_pass_print_entries_and_dirs)"</div>
<div class=""><br class="">
</div>
<div class=""># mv</div>
<div class="">complete -f -c pass -n '__fish_pass_needs_command'
-a mv -d 'rename existing password'</div>
<div class="">complete -f -c pass -n '__fish_pass_uses_command
mv' -s f -l force -d 'Force rename'</div>
<div class="">complete -f -c pass -n '__fish_pass_uses_command
mv' -a "(__fish_pass_print_entries_and_dirs)"</div>
<div class=""><br class="">
</div>
<div class=""># cp</div>
<div class="">complete -f -c pass -n '__fish_pass_needs_command'
-a cp -d 'copy existing password'</div>
<div class="">complete -f -c pass -n '__fish_pass_uses_command
cp' -s f -l force -d 'Force copy'</div>
<div class="">complete -f -c pass -n '__fish_pass_uses_command
cp' -a "(__fish_pass_print_entries_and_dirs)"</div>
<div class=""><br class="">
</div>
<div class=""># git</div>
<div class="">complete -f -c pass -n '__fish_pass_needs_command'
-a git -d 'execute a git command'</div>
<div class="">complete -f -c pass -f -n
'__fish_pass_uses_command git' -a 'init' -d 'Initialize git
repository'</div>
<div class="">complete -f -c pass -f -n
'__fish_pass_uses_command git' -a 'status' -d 'Show status of
the repo'</div>
<div class="">complete -f -c pass -f -n
'__fish_pass_uses_command git' -a 'add' -d 'Add changes to the
index'</div>
<div class="">complete -f -c pass -f -n
'__fish_pass_uses_command git' -a 'commit' -d 'Commit changes
to the repo'</div>
<div class="">complete -f -c pass -f -n
'__fish_pass_uses_command git' -a 'push' -d 'Push changes to
remote repo'</div>
<div class="">complete -f -c pass -f -n
'__fish_pass_uses_command git' -a 'pull' -d 'Pull changes from
remote repo'</div>
<div class="">complete -f -c pass -f -n
'__fish_pass_uses_command git' -a 'log' -d 'View changelog'</div>
<div class=""><br class="">
</div>
<div class=""># help</div>
<div class="">complete -f -c pass -n '__fish_pass_needs_command'
-a help -d 'show usage help'</div>
<div class=""><br class="">
</div>
<div class=""># version</div>
<div class="">complete -f -c pass -n '__fish_pass_needs_command'
-a version -d 'show program version'</div>
<div class=""><br class="">
</div>
<div><br class="">
<blockquote type="cite" class="">
<div class="">On 12 Jul 2019, at 4:52 pm, Eric D. <<a
href="mailto:nospamthankyou@ericdeis.com" class=""
moz-do-not-send="true">nospamthankyou@ericdeis.com</a>>
wrote:</div>
<br class="Apple-interchange-newline">
<div class="">
<meta http-equiv="content-type" content="text/html;
charset=UTF-8" class="">
<div text="#FFFFFF" bgcolor="#333333" class=""> Given the
following passwords, without any folders:<br class="">
Password Store<br class="">
├── app1<br class="">
├── app2<br class="">
├── test<br class="">
├── test2<br class="">
└── test3<br class="">
<br class="">
Autocompletion fails via rm command.<br class="">
$ pass rm t[tab]<br class="">
~/.config/fish/completions/pass.fish (line 4): No
matches for wildcard '"$prefix"/**"$ext"'. See `help
expand`. 23:37:31<br class="">
printf '%s\n' "$prefix"/**"$ext" | sed
"s#$prefix/\(.*\)$strip#\1#"<br class="">
^<br class="">
in function '__fish_pass_print'<br class="">
called on line 50 of file
~/.config/fish/completions/pass.fish<br class="">
with parameter list '.gpg .gpg'<br class="">
<br class="">
in function '__fish_pass_print_entries'<br class="">
called on standard input<br class="">
<br class="">
Given the following passwords, with one folder:<br
class="">
Password Store<br class="">
├── app1<br class="">
├── app2<br class="">
├── foo<br class="">
│ └── bar<br class="">
├── test<br class="">
├── test2<br class="">
└── test3<br class="">
<br class="">
$ pass rm t[tab]<br class="">
Autocompletion now works!<br class="">
<br class="">
Also if there are zero passwords in the store,
Autocompletion throws the same error below. <br
class="">
$ pass fo[tab]<br class="">
~/.config/fish/completions/pass.fish (line 4): No
matches for wildcard '"$prefix"/**"$ext"'. See `help
expand`. 23:47:40<br class="">
printf '%s\n' "$prefix"/**"$ext" | sed
"s#$prefix/\(.*\)$strip#\1#"<br class="">
<br class="">
</div>
_______________________________________________<br
class="">
Password-Store mailing list<br class="">
<a href="mailto:Password-Store@lists.zx2c4.com" class=""
moz-do-not-send="true">Password-Store@lists.zx2c4.com</a><br
class="">
<a class="moz-txt-link-freetext" href="https://lists.zx2c4.com/mailman/listinfo/password-store">https://lists.zx2c4.com/mailman/listinfo/password-store</a><br
class="">
</div>
</blockquote>
</div>
<br class="">
</div>
</blockquote>
<br>
</body>
</html>