summaryrefslogtreecommitdiff
path: root/Functions/MIME/zsh-mime-handler
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2003-09-14 19:37:32 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2003-09-14 19:37:32 +0000
commit3efb2ec3948910bbcf004dcddae0afcf46603ee6 (patch)
tree21d707574bc828c51a58ea29a56705f620b8c725 /Functions/MIME/zsh-mime-handler
parentcd89b92a0de7c2ef66c8aeec260377a1643a18d7 (diff)
downloadzsh-3efb2ec3948910bbcf004dcddae0afcf46603ee6.tar.gz
zsh-3efb2ec3948910bbcf004dcddae0afcf46603ee6.zip
19053 modified, c.f. 19056
Diffstat (limited to 'Functions/MIME/zsh-mime-handler')
-rw-r--r--Functions/MIME/zsh-mime-handler142
1 files changed, 142 insertions, 0 deletions
diff --git a/Functions/MIME/zsh-mime-handler b/Functions/MIME/zsh-mime-handler
new file mode 100644
index 000000000..b64fd54cd
--- /dev/null
+++ b/Functions/MIME/zsh-mime-handler
@@ -0,0 +1,142 @@
+# Handler for MIME types using associative arrays
+# zsh_mime_handlers and zsh_mime_flags set up by zsh-mime-setup.
+#
+# The only flags it handles are copiousoutput and needsterminal.
+# copiousoutput is assumed to imply needsterminal. Apart from
+# those, it tries to be a bit cunning about quoting, which
+# can be a nightmare in MIME handling. If it sees something like
+# netscape %s
+# and it only has one file to handle (the usual case then it will handle it
+# internally just by appending a file.)
+#
+# Anything else is handled by passing to sh -c, which is the only think
+# with a high probability of working. If it sees something with
+# quotes, e.g.
+# /usr/bin/links "%s"
+# it will assume someone else has tried to fix the quoting problem and not
+# do that. If it sees something with no quotes but other metacharacters,
+# e.g.
+# cat %s | handler
+# then it will do any quoting and pass the result to sh -c.
+# So for example if the argument is "My File", the command executed
+# is supposedly
+# sh -c 'cat My\ File | handler'
+#
+# This note is mostly here so you can work out what I tried to do when
+# it goes horribly wrong.
+
+emulate -L zsh
+setopt extendedglob cbases
+
+# We need zformat from zsh/zutil for %s replacement.
+zmodload -i zsh/zutil
+
+# 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
+# just as well pass them all down. However, we just take the
+# suffix from the first since that's what invoked us via suffix -s.
+
+local suffix context
+local -a match mbegin mend
+
+[[ $1 = (#b)*.([^.]##) ]] || return 1
+suffix=$match[1]
+context=":mime:.${suffix}:"
+
+local handler flags
+
+zstyle -s $context handler handler ||
+ handler="${zsh_mime_handlers[$suffix]}"
+zstyle -s $context flags flags ||
+ flags="${zsh_mime_flags[$suffix]}"
+
+local -a files
+local hasmeta stdin
+
+# See if the handler has shell metacharacters in.
+# Don't count whitespace since we can split that when it's unquoted.
+if [[ $handler = *[\\\;\*\?\|\"\'\`\$]* ]]; then
+ hasmeta=1
+fi
+
+local -a execargs
+
+if [[ $handler = *%s* ]]; then
+ # We need to replace %s with the file(s).
+ local command
+ if [[ -n $hasmeta || $# -gt 1 ]]; then
+ # The handler is complicated, either due to special
+ # characters or multiple files. We are going to pass it
+ # down to sh, since it's probably written for sh syntax.
+ #
+ # See if it's a good idea to quote the filename(s).
+ # It isn't if there are already quotes in the handler, since
+ # that means somebody already tried to take account of that.
+ if [[ $handler = *[\'\"]* ]]; 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"
+ else
+ files=(${(q)argv})
+ zformat -f command $handler s:"$files"
+ fi
+ execargs=(sh -c $command)
+ else
+ # Simple command, one filename.
+ # Split and add the file without extra quoting,
+ # since later we will just execute the array as is.
+ for command in ${=handler}; do
+ zformat -f command $command s:"$1"
+ execargs+=($command)
+ done
+ fi
+else
+ # If there's no %s, the input is supposed to come from stdin.
+ stdin=1
+ if [[ -n $hasmeta ]]; then
+ execargs=(sh -c "$handler")
+ else
+ execargs=(${=handler})
+ fi
+fi
+
+# Now execute the command in the appropriate fashion.
+if [[ $flags = *copiousoutput* ]]; then
+ # We need to page the output.
+ # Careful in case PAGER is a set of commands and arguments.
+ local -a pager
+ zstyle -a $context pager pager || pager=(${=PAGER:-more})
+ if [[ -n $stdin ]]; then
+ cat $argv | $execargs | $pager
+ else
+ $execargs | eval ${PAGER:-more}
+ fi
+elif [[ $flags = *needsterminal* || -z $DISPLAY ]]; then
+ # Needs a terminal, so run synchronously.
+ # Obviously, if $DISPLAY is empty but the handler needs a
+ # GUI we are in trouble anyway. However, it's possible for
+ # the handler to be smart about this, like pick-web-browser,
+ # and even if it just produces an error message it's better to
+ # have it run synchronously.
+ if [[ -n $stdin ]]; then
+ cat $argv | $execargs
+ else
+ $execargs
+ fi
+else
+ # Doesn't need a terminal and we have a $DISPLAY, so run
+ # it in the background. sh probably isn't smart enough to
+ # exec the last command in the list, but it's not a big deal.
+ #
+ # The following Rococo construction is to try to make
+ # the job output for the backgrounded command descriptive.
+ # Otherwise it's equivalent to removing the eval and all the quotes,
+ # including the (q) flags.
+ if [[ -n $stdin ]]; then
+ eval cat ${(q)argv} "|" ${(q)execargs} "&"
+ else
+ eval ${(q)execargs} "&"
+ fi
+fi