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

Re: stderr from _call_program (Re: rsync --progress stops completion)

On Sep 23,  4:41pm, Oliver Kiddle wrote:
} I think we can safely append 2>/dev/null to the eval. If the command
} (either from a zstyle preference or the function) uses 2>&1, output
} should be captured:
}   % eval 'unknown 2>&1' 2>/dev/null 
}   zsh: command not found: unknown

Right, in the 2>&1 case you'll get (zsh: command not found: unknown) as
the list of completions, which isn't ideal either.

The body of _call_program is just one big "if ... fi" with several
"eval"s; I propose simply redirecting the stderr of that entire thing.

} Another possibility along similar lines would be to install a
} command_not_found_handler function for the duration of the completion
} system. Avoiding command not found errors is the main (but not only)
} reason for redirecting stderr with _call_program.

Sadly this doesn't work either.  Aside from it being difficult to save
and restore the user's command_not_found handler (tricks that used to
mostly work for this now break for functions that use sticky options),
the actual use of _call_program is almost always inside $(...) or as
the left side of a pipe to "while read ...", so the not-found handler
can't do anything useful like calling _message -- it can only print a
set of dummy completions, which doesn't really help.

The only cases of _call_program I've found that aren't executed in a
subshell are in guard functions in _git, and two calls in _texinfo that
look like mistakes to me.

} We should also consider _complete_debug, perhaps directing stderr to the
} log file instead of /dev/null.

Good thought.  It's amazingly difficult to do a conditional redirection.

diff --git a/Completion/Base/Utility/_call_program b/Completion/Base/Utility/_call_program
index b038a80..b657648 100644
--- a/Completion/Base/Utility/_call_program
+++ b/Completion/Base/Utility/_call_program
@@ -1,6 +1,13 @@
 #autoload +X
-local tmp
+local tmp err_fd=-1
+if (( ${debug_fd:--1} > 2 ))
+then exec {err_fd}>&2	# debug_fd is saved stderr, 2 is log file
+else exec {err_fd}>/dev/null
+{	# Begin "always" block
 if zstyle -s ":completion:${curcontext}:${1}" command tmp; then
   if [[ "$tmp" = -* ]]; then
@@ -10,4 +17,10 @@ if zstyle -s ":completion:${curcontext}:${1}" command tmp; then
   eval "$argv[2,-1]"
+fi 2>&$err_fd
+} always {
+exec {err_fd}>&-
diff --git a/Completion/Unix/Command/_texinfo b/Completion/Unix/Command/_texinfo
index 12d964e..025b7b9 100644
--- a/Completion/Unix/Command/_texinfo
+++ b/Completion/Unix/Command/_texinfo
@@ -6,7 +6,7 @@ local -a info
 case $service in
-    info=( _call_program info ${words[1]} )
+    info=( $(_call_program info ${words[1]}) )
     _arguments -C -s \
       '(: -)--apropos=[look up string in indices]:search string: ' \
       '(-f --file)'{\*-d,\*--directory=}'[add directory to infopath]:info dir:_files -/' \
@@ -140,7 +140,7 @@ case $service in
       '-file:info file:_files -g "*.info(|.gz|.bz2)(-.)"' \
       '-node:info node:->item' \
       '*::menu items:->item' && ret=0
-    info=( _call_program info info ${(kv)opt_args[(I)-file]/-file/-f} )
+    info=( $(_call_program info info ${(kv)opt_args[(I)-file]/-file/-f}) )

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