mirror of
				git://git.code.sf.net/p/zsh/code
				synced 2025-10-31 06:00:54 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			206 lines
		
	
	
	
		
			6.5 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			206 lines
		
	
	
	
		
			6.5 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
| # 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.
 | |
| 
 | |
| local autocd
 | |
| [[ -o autocd ]] && autocd=autocd
 | |
| 
 | |
| emulate -L zsh
 | |
| setopt extendedglob cbases nullglob $autocd
 | |
| 
 | |
| # 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 hand_nonex
 | |
| 
 | |
| # 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=('*(*)' '*(/)')
 | |
| 
 | |
| # Set to a list of patterns for which the handler will be used even
 | |
| # if the file doesn't exist on the disk.
 | |
| zstyle -a $context handle-nonexistent hand_nonex ||
 | |
|   hand_nonex=('[[:alpha:]]#:/*')
 | |
| 
 | |
| local pattern
 | |
| local -a files
 | |
| 
 | |
| # In case the pattern contains glob qualifiers, as it does by default,
 | |
| # we need to do real globbing, not just pattern matching.
 | |
| # The strategy is to glob the files in the directory using the
 | |
| # pattern and see if the one we've been passed is in the list.
 | |
| local dirpref=${1%/*}
 | |
| if [[ $dirpref = $1 ]]; then
 | |
|   dirpref=
 | |
| else
 | |
|   dirpref+=/
 | |
| fi
 | |
| 
 | |
| for pattern in $exec_asis; do
 | |
|   files=(${dirpref}${~pattern})
 | |
|   if [[ -n ${files[(r)$1]} ]]; then
 | |
|     "$@"
 | |
|     return
 | |
|   fi
 | |
| done
 | |
| 
 | |
| if [[ ! -e $1 ]]; then
 | |
|   local nonex_ok
 | |
|   for pattern in $hand_nonex; do
 | |
|     if [[ $1 = ${~pattern} ]]; then
 | |
|       nonex_ok=1
 | |
|       break
 | |
|     fi
 | |
|   done
 | |
|   if [[ -z $nonex_ok ]]; then
 | |
|     "$@"
 | |
|     return
 | |
|   fi
 | |
| fi
 | |
| 
 | |
| 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
 |