Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: [FEATURE][PATCH] Complete local executables with ./ prefix, if prefix-needed is false

Marlon Richert wrote:
> This allows local executables to be completed more easily, without the
> need for . in $path.

This is the type of thing which often can already be achieved with
styles and, where not, a few tweaks may enable it. The nearest example
from my own config involves using the fake style and a matcher to ignore
the prefix. But that's for a more specific context[1].

In this case for the style context, the tag 'commands' is used for a lot
of commands that aren't external Unix commands. The 'executables' tag is
better but guarded by a condition that will evaluate to false:

[[ -n "$path[(r).]" || $PREFIX = */* ]] &&
    defs+=( 'executables:executable file:_files -g \*\(-\*\)' 

The fake style is looked up in _description so a dummy call to it is one
option. The patch below adds that but I'd be interested in any thoughts
on that. With caveats[2], that allows:

  zstyle -e ':completion:*:executables' fake 'reply=( ./*(-*) )'
  zstyle ':completion:*:executables' matcher 'b:=./'

There is a command-path style looked up by _command_names to override
$path. But that doesn't entirely help for a couple of reasons. External
commands are completed based on keys of the commands association but
that will not contain commands based on relative directories listed in
$path. Even if it did, they can't be identified to add back a ./ prefix
so that they actually work. In the patch below, I do change it to use
path=( $cmdpath:A ) when the command-path style is set. That resolves
only the first of these issues and allows for relative paths in the
command-path style to work as intended, even if that isn't especially


[1] If anyone's interested, that example is for ssh public keys. Just
the fake and matcher style are needed but it looks like this:
zstyle -e ':completion:*:((ssh|scp|sftp):*:option-i-1|ssh-add:*:argument-rest)' fake '[[ -prefix - ]] || reply=( ~/.ssh/id^*.pub(-.) )'
zstyle -e ':completion:*:((ssh|scp|sftp):*:option-i-1|ssh-add:*:argument-rest)' matcher '[[ -prefix - ]] || reply=( "l:|=*" )'
zstyle ':completion:*:((ssh|scp|sftp):*:option-i-1|ssh-add:*:argument-rest)' menu yes=0 search
zstyle ':completion:*:((ssh|scp|sftp):*:option-i-1|ssh-add:*:argument-rest)' list-colors "=(#b)(*/)(*)==38;5;208=0"

[2] With the fake style in general, the return status of the calling
completion function doesn't account for fake matches which may mean
unwanted later completers are invoked (e.g. _approximate).

diff --git a/Completion/Zsh/Type/_command_names b/Completion/Zsh/Type/_command_names
index b1c35f013..12cbd69c1 100644
--- a/Completion/Zsh/Type/_command_names
+++ b/Completion/Zsh/Type/_command_names
@@ -4,7 +4,7 @@
 # complete only external commands and executable files. This and a
 # `-' as the first argument is then removed from the arguments.
-local args defs ffilt
+local args defs expl ffilt
 zstyle -t ":completion:${curcontext}:commands" rehash && rehash
@@ -16,8 +16,12 @@ defs=(
   'commands:external command:_path_commands'
-[[ -n "$path[(r).]" || $PREFIX = */* ]] &&
-    defs+=( 'executables:executable file:_files -g \*\(-\*\)' )
+if [[ -n "$path[(r).]" || $PREFIX = */* ]]; then
+  defs+=( 'executables:executable file:_files -g \*\(-\*\)' )
+  # this is ignored but exists to facilitate the use of the fake style
+  _description executables expl 'executable file'
 if [[ "$1" = -e ]]; then
@@ -58,7 +62,7 @@ fi
 if (( $#cmdpath )); then
   local -a +h path
   local -A +h commands
-  path=( $cmdpath )
+  path=( $cmdpath:A )
 _alternative -O args "$defs[@]"

Messages sorted by: Reverse Date, Date, Thread, Author