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

Re: Bug#582258: zsh-mime-setup disables usual completions



On Wed, 19 May 2010 13:37:04 +0000
Clint Adams <schizo@xxxxxxxxxx> wrote:
> On Wed, May 19, 2010 at 05:18:59PM +0400, Nikolay A. Panov wrote:
> > Using zsh-mime-setup I have no completions for, say, django:
> > 
> > $ zsh -f 
> > laptop% autoload -U compinit;compinit
> > laptop% ./manage.py
> > tags in context :completion::complete:manage.py::
> >     argument-1 options  (_arguments _django (eval)) 
> >     subcommands         (_describe _django (eval))
>
> You could do `unalias -s py' to get your manage.py completion back.

"alias -s py=python" would also work around the problem without creating
any new symptoms---this makes python execute the file directly, instead
of via zsh-mime-handler, and the python completion function is smart
enough to know about looking for completion for scripts.  However, it
ought to be able to work without you doing that.

The problem is that the alias gets expanded to

zsh-mime-handler ./manage.py <completing here>

(I'm guessing---you don't say specifically but this is the obvious thing
the MIME system would do that would confuse completion without screwing
up execution) and there's no special zsh-mime-handler completion
function.  There should be one that translates the command line into
what would be executed by the handler and then completes based on that.

I think the following does the basics.  I'm sure you'll let me know
politely if it doesn't.

Index: Completion/Zsh/Function/.distfiles
===================================================================
RCS file: Completion/Zsh/Function/.distfiles
diff -N Completion/Zsh/Function/.distfiles
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ Completion/Zsh/Function/.distfiles	23 May 2010 19:23:31 -0000
@@ -0,0 +1,4 @@
+DISTFILES_SRC='
+.distfiles
+zsh-mime-handler
+'
Index: Completion/Zsh/Function/_zsh-mime-handler
===================================================================
RCS file: Completion/Zsh/Function/_zsh-mime-handler
diff -N Completion/Zsh/Function/_zsh-mime-handler
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ Completion/Zsh/Function/_zsh-mime-handler	23 May 2010 19:23:31 -0000
@@ -0,0 +1,9 @@
+#compdef zsh-mime-handler
+
+# zsh-mime-handler -l is supposed to print out the command line
+# with quoting to turn it into a full executable line.  So
+# we need to use shell splitting to turn it into words and
+# then unquoting on those words.
+words=(${(Q)${(z)"$(zsh-mime-handler -l ${words[2,-1]})"}})
+
+_normal
Index: Doc/Zsh/contrib.yo
===================================================================
RCS file: /cvsroot/zsh/zsh/Doc/Zsh/contrib.yo,v
retrieving revision 1.114
diff -p -u -r1.114 contrib.yo
--- Doc/Zsh/contrib.yo	14 May 2010 07:58:37 -0000	1.114
+++ Doc/Zsh/contrib.yo	23 May 2010 19:23:32 -0000
@@ -2411,7 +2411,7 @@ startitem()
 findex(zsh-mime-setup)
 findex(zsh-mime-handler)
 xitem(tt(zsh-mime-setup) [ tt(-fv) ] [ tt(-l) [ var(suffix ...) ] ])
-item(tt(zsh-mime-handler))(
+item(tt(zsh-mime-handler [-l] var(command arguments ...)))(
 These two functions use the files tt(~/.mime.types) and tt(/etc/mime.types),
 which associate types and extensions, as well as tt(~/.mailcap) and
 tt(/etc/mailcap) files, which associate types and the programs that
@@ -2635,6 +2635,12 @@ terminal; the second flag is used if the
 An example of a suitable tt(mailcap) entry for such a program is:
 
 example(text/html; /usr/bin/lynx '%s'; needsterminal)
+
+Running `tt(zsh-mime-handler -l) var(command line)' prints the command
+line that would be executed, simplified to remove the effect of any
+flags, and quoted so that the output can be run as a complete zsh
+command line.  This is used by the completion system to decide how to
+complete after a file handled by tt(zsh-mime-setup).
 )
 findex(pick-web-browser)
 item(tt(pick-web-browser))(
Index: Functions/MIME/zsh-mime-handler
===================================================================
RCS file: /cvsroot/zsh/zsh/Functions/MIME/zsh-mime-handler,v
retrieving revision 1.11
diff -p -u -r1.11 zsh-mime-handler
--- Functions/MIME/zsh-mime-handler	20 Nov 2008 18:12:32 -0000	1.11
+++ Functions/MIME/zsh-mime-handler	23 May 2010 19:23:32 -0000
@@ -34,6 +34,28 @@ setopt extendedglob cbases nullglob $aut
 # We need zformat from zsh/zutil for %s replacement.
 zmodload -i zsh/zutil
 
+# Look for options.  Because of the way this is usually invoked,
+# (there is always a command to be handled), only handle options
+# up to second last argument.
+local opt
+integer list
+while (( $# - $OPTIND > 0 )); do
+  if getopts "l" opt; then
+    case $opt in
+      (l)
+      list=1
+      ;;
+
+      (*)
+      return 1
+      ;;
+    esac
+  else
+    break
+  fi
+done
+shift $(( OPTIND - 1 ))
+
 # Always called with a filename argument first.
 # There might be other arguments; don't really know what to do
 # with these, but if they came from e.g. `*.ps' then we might
@@ -47,7 +69,8 @@ local -a match mbegin mend
 suffix=${(L)match[1]}
 context=":mime:.${suffix}:"
 
-local handler flags no_sh no_bg
+local handler flags no_sh no_bg arg
+integer i
 local -a exec_asis hand_nonex
 
 # Set to a list of patterns which are ignored and executed as they are,
@@ -94,7 +117,20 @@ fi
 for pattern in $exec_asis; do
   files=(${dirpref}${~pattern})
   if [[ -n ${files[(r)$1]} ]]; then
-    "$@"
+    if (( list )); then
+      for (( i = 1; i <= $#; i++ )); do
+	(( i == 1 )) || print -n " "
+	arg=${argv[i]}
+	if [[ -n $arg ]]; then
+	  print -rn -- ${(q)arg}
+	else
+	  print "''"
+	fi
+      done
+      print
+    else
+      "$@"
+    fi
     return
   fi
 done
@@ -152,12 +188,13 @@ if [[ $handler = *%s* ]]; then
       # Probably we ought not even to handle multiple
       # arguments, but at least the error message ought
       # to make it obvious what's going on.
-      zformat -f command $handler s:"$argv"
+      zformat -f command $handler s:"$argv[0]"
     else
-      files=(${(q)argv})
-      zformat -f command $handler s:"$files"
+      zformat -f command $handler s:"${(q)argv[0]}"
     fi
-    if [[ $no_sh = yes ]]; then
+    if (( list )); then
+      execargs=(${(Q)${(z)command}} ${argv[1,-1]})
+    elif [[ $no_sh = yes ]]; then
       execargs=(eval $command)
     else
       execargs=(sh -c $command)
@@ -174,13 +211,27 @@ if [[ $handler = *%s* ]]; then
 else
   # If there's no %s, the input is supposed to come from stdin.
   stdin=1
-  if [[ -n $hasmeta && $no_sh != yes ]]; then
+  if [[ -n $hasmeta && $no_sh != yes && list -eq 0 ]]; then
     execargs=(sh -c "$handler")
   else
     execargs=(${=handler})
   fi
 fi
 
+if (( list )); then
+  for (( i = 1; i <= ${#execargs}; i++ )); do
+    (( i == 1 )) || print -n " "
+    arg=${execargs[i]}
+    if [[ -n $arg ]]; then
+      print -rn -- ${(q)arg}
+    else
+      print -n "''"
+    fi
+  done
+  print
+  return 0
+fi
+
 # Now execute the command in the appropriate fashion.
 if [[ $flags = *copiousoutput* ]]; then
   # We need to page the output.


-- 
Peter Stephenson <p.w.stephenson@xxxxxxxxxxxx>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/



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