mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-11-24 14:01:03 +01:00
Merge of 22394: execute-as-is style for MIME suffixes.
This commit is contained in:
parent
5cb2dcae41
commit
a490e36d27
1 changed files with 171 additions and 0 deletions
171
Functions/MIME/zsh-mime-handler
Normal file
171
Functions/MIME/zsh-mime-handler
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
# 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 no_sh no_bg
|
||||
local -a exec_asis
|
||||
|
||||
# Set to a list of patterns which are ignored and executed as they are,
|
||||
# despite being called for interpretation by the mime handler.
|
||||
# Defaults to executable files, which ensures that they are executed as
|
||||
# they are, even if they have a suffix.
|
||||
zstyle -a $context execute-as-is exec_asis || exec_asis=('*(*)')
|
||||
|
||||
local pattern
|
||||
|
||||
for pattern in $exec_asis; do
|
||||
if [[ $1 = ${~pattern} ]]; then
|
||||
"$@"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
zstyle -s $context handler handler ||
|
||||
handler="${zsh_mime_handlers[$suffix]}"
|
||||
zstyle -s $context flags flags ||
|
||||
flags="${zsh_mime_flags[$suffix]}"
|
||||
|
||||
# Set to yes if we use eval instead of sh -c for complicated mailcap lines
|
||||
# Can possibly break some mailcap entries which expect sh compatibility,
|
||||
# but is faster, as a new process is not spawned.
|
||||
zstyle -t $context current-shell && no_sh=yes
|
||||
|
||||
# Set to yes if the process shouldn't be backgrounded even if it doesn't need a
|
||||
# terminal and display is set.
|
||||
zstyle -t $context never-background && no_bg=yes
|
||||
|
||||
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
|
||||
if [[ $no_sh = yes ]]; then
|
||||
execargs=(eval $command)
|
||||
else
|
||||
execargs=(sh -c $command)
|
||||
fi
|
||||
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 && $no_sh != yes ]]; 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 [[ $no_bg = yes || $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
|
||||
Loading…
Add table
Add a link
Reference in a new issue