mirror of
				git://git.code.sf.net/p/zsh/code
				synced 2025-10-31 06:00:54 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			255 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			255 lines
		
	
	
	
		
			10 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
| #compdef sed gsed psed s2p
 | |
| 
 | |
| local variant inplace extended ign sep separator
 | |
| local -i nest=0
 | |
| local -a args aopts sedexpr cmds_none cmds_slash cmds_end substflags expl bsnl nl labels excl dedup
 | |
| local -a step range negate mods
 | |
| aopts=( -A '-*' )
 | |
| bsnl=( $'\\\n' )
 | |
| nl=$'\n'
 | |
| compquote nl
 | |
| 
 | |
| cmds_none=(
 | |
|   '{:start group'
 | |
|   'q:quit after printing pattern space'
 | |
|   'h:copy pattern space to hold space'
 | |
|   '\::place label'
 | |
|   '#:comment'
 | |
|   '=:print current line number'
 | |
|   'a:append text'
 | |
|   'i:insert text'
 | |
|   'r:append contents of file'
 | |
|   'b:branch'
 | |
|   't:branch if s command has been successful'
 | |
|   'c:replace line with text'
 | |
|   'l:list current line in visually unambiguous form'
 | |
|   'w:write pattern space to file'
 | |
| )
 | |
| cmds_slash=(
 | |
|   's:substitute regex'
 | |
|   'y:transliterate characters'
 | |
| )
 | |
| cmds_end=(
 | |
|   'd:delete pattern space'
 | |
|   'D:delete up to the first newline in the pattern space'
 | |
|   'g:copy hold space to pattern space'
 | |
|   'G:append hold space to pattern space'
 | |
|   'H:append pattern space to hold space'
 | |
|   'n:read the next line of input into pattern space'
 | |
|   'N:append the next line of input to the pattern space'
 | |
|   'p:print the current pattern space'
 | |
|   'P:print up to the first newline of the current pattern space'
 | |
|   'x:exchange hold and pattern spaces'
 | |
|   '}:end group'
 | |
| )
 | |
| substflags=(
 | |
|   'g:replace all matches to the regular expression'
 | |
|   'p:print new pattern space if substitution made'
 | |
|   'w:write result to named file if substitution made'
 | |
| )
 | |
| args=(
 | |
|   '(-n --quiet --silent)'{-n,--quiet,--silent}'[suppress automatic printing of pattern space]'
 | |
|   '(1)*'{-e+,--expression=}'[specify sed commands to run]:sed script:_sed_expressions'
 | |
|   '(1)*'{-f+,--file=}'[add contents of file to commands to run]:file:_files'
 | |
|   '(-e)1:sed script:_sed_expressions'
 | |
|   '*:input file:_files'
 | |
| )
 | |
| inplace='[edit files in-place, running scripts separately for each file]:: :_guard "^(*[@/; ]*|?(#c6,)|-*)" "suffix for backup"'
 | |
| extended='[use extended regular expressions]'
 | |
| 
 | |
| if [[ $service = (psed|s2p) ]]; then
 | |
|   args=(
 | |
|     "${(@)args:#(|\(*\))(|\*)--*}"
 | |
|     '-a[delay opening files listed with w function]'
 | |
|   )
 | |
| elif _pick_variant -r variant gnu=GNU unix --version; then
 | |
|   aopts=( )
 | |
|   (( $#words > 2 )) && ign='!'
 | |
|   args+=(
 | |
|     '--debug[annotate program execution]'
 | |
|     '--follow-symlinks[follow symlinks when processing in place]'
 | |
|     '(-i --in-place -s --separate)'{-i-,--in-place=-}$inplace
 | |
|     '(-c --copy)'{-c,--copy}'[copy instead of rename when shuffling files in in-place mode]'
 | |
|     '(-l --line-length)'{-l+,--line-length=}'[specify line-wrap length for the l command]'
 | |
|     '(-r)--posix[disable GNU extensions]'
 | |
|     '(-E -r --regexp-extended)'{-E,-r,--regexp-extended}$extended
 | |
|     '(-s --separate)'{-s,--separate}'[consider files separately instead of as a combined stream]'
 | |
|     '--sandbox[block commands that can affect the system (r/w/W/e)]'
 | |
|     '(-u --unbuffered)'{-u,--unbuffered}'[disable data buffering]'
 | |
|     '(-z --null-data)'{-z,--null-data}'[separate lines by NUL characters]'
 | |
|     "${ign}(- 1 :)--help[print program usage]"
 | |
|     "${ign}(- 1 :)--version[print program version]"
 | |
|   )
 | |
|   if [[ -z ${words[(r)--posix]} ]]; then
 | |
|     cmds_none+=(
 | |
|       'R:append a line from file'
 | |
|       'T:branch if no s command has been successful'
 | |
|       'W:write the first line of pattern space to file'
 | |
|       'v:fail if GNU extensions not supported or older than specified version'
 | |
|     )
 | |
|     cmds_end+=(
 | |
|       "e:execute a command and include it's output"
 | |
|       'F:print the filename of the current input file'
 | |
|       'Q:quit'
 | |
|       'z:empty the pattern space'
 | |
|     )
 | |
|     substflags+=(
 | |
|       'e:execute pattern space as a command and replace with result'
 | |
|       {i,I}':case-insensitive regular expression matching'
 | |
|       {m,M}':multi-line matching'
 | |
|     )
 | |
|   fi
 | |
| else
 | |
|   args=( "${(@)args:#(|\(*\))(|\*)--*}" )
 | |
|   case $OSTYPE in
 | |
|     openbsd*|freebsd*|netbsd*|darwin*|dragonfly*)
 | |
|       args+=(
 | |
| 	'(-r -E)'-E$extended
 | |
| 	'-a[delay opening files listed with w function]'
 | |
|       )
 | |
|     ;|
 | |
|     openbsd*|freebsd*|netbsd*|dragonfly*) args+=( '(-r -E)'-r$extended ) ;|
 | |
|     darwin*|freebsd*|netbsd*|openbsd*) args+=( '-i+'$inplace ) ;|
 | |
|     darwin*|freebsd*|netbsd*) args+=( '-l[make output line buffered]' ) ;|
 | |
|     freebsd*) args+=( '-u[disable data buffering]' ) ;|
 | |
|     freebsd*|netbsd*)
 | |
|       args+=(
 | |
|         '-I+[edit files in-place, treating all files as a single input stream]:: :_guard "^(*[@/; \\\]*|?(#c6,)|-*)" "suffix for backup"'
 | |
|       )
 | |
|     ;;
 | |
|     openbsd*) args+=( '-u[make output line buffered]' ) ;;
 | |
|   esac
 | |
| fi
 | |
| 
 | |
| zstyle -s ":completion:${curcontext}:address-forms" list-separator separator || separator=--
 | |
| step=( "~ $separator step" )
 | |
| negate=( "! $separator negated" )
 | |
| range=( ", $separator range" )
 | |
| mods=( "I $separator case-insensitive" "M $separator multi-line" )
 | |
| 
 | |
| sedexpr=(
 | |
|   \( /$'*\0[ \t\n]#'/ \) # strip off any preceding arguments - handled by _arguments
 | |
|   \(
 | |
|     # Handle an optional address range
 | |
|     \(
 | |
|       \(
 | |
|         \(
 | |
|           '///' '/[^/]#//' ':regexes:regex:' # skip /pattern/
 | |
|         \|
 | |
|           '/\\(?)/' -'sep=${match#?}' # handle \xpatternx
 | |
|           \( '/\?/' \| '/?/' -'[[ $match != $sep ]]' \) \# '/?/' -'[[ $match = $sep ]]' ':regexes:regex:'
 | |
|         \)
 | |
|         $'/[ \t]#/'
 | |
|         \( \| '/[IM]##/' -'dedup=( ${(s..)match} )' ':address-forms:address form:compadd -S "" -d mods -F dedup I M' \) \#
 | |
|       \|
 | |
|         '/([0-9]##|$)[ \t]#/' # line number
 | |
|         \(
 | |
|           '/\~[ \t]#/' # addr1~N
 | |
|           '/[0-9]##[ \t]#/' ': _message -e steps "number - match where line number is a multiple"'
 | |
|         \| '//' ':address-forms:address form:compadd -S "" -d step \~' \)
 | |
|       \|
 | |
|         '/[]/' ': _guard "^([sy]|[^0-9$/\\\]*)" "address - line number or /pattern/"'
 | |
|       \)
 | |
|       \( # range end, also optional
 | |
|         '/[ \t]#,[ \t]#/' -'excl=( \\\# : )' # exclude comments and labels after ranges
 | |
|         \(
 | |
|           '///' '/[^/]#//' ':regexes:regex:' # handle /pattern/
 | |
|         \|
 | |
|           '/\\(?)/' -'sep=${match#?}' # handle \xpatternx
 | |
|           \( '/\?/' \| '/?/' -'[[ $match != $sep ]]' \) \# '/?/' -'[[ $match = $sep ]]' ':regexes:regex - 2:'
 | |
|         \|
 | |
|           '/+[ \t]#/' # addr1,+N
 | |
|           '/[0-9]##/' ': _message -e number "number of following lines"'
 | |
|         \|
 | |
|           '/\~[ \t]#/' # addr1,~N
 | |
|           '/[0-9]##/' ': _message -e number "following lines until line number is a multiple of specified number"'
 | |
|         \|
 | |
|           '/([0-9]##|$)/' # line number
 | |
|         \|
 | |
|           '/[]/' ': _message -e ranges "ending line - [+~]number, $ or /pattern/"'
 | |
|         \)
 | |
|       \|
 | |
|         '//' -'excl=( \\\# : )' ':address-forms:address form:compadd -S "" -d range ,'
 | |
|       \)
 | |
|       \(
 | |
|         '/!/' ':address-forms:address form:compadd -S "" -d negate !'
 | |
|       \| \)
 | |
|     \| // -'excl=( \{ )' \) # { ... } is only useful following a range so exclude {
 | |
| 
 | |
|     $'/[ \t]#/' -'(( nest )) || excl+=( \} )' # whitespace + exclude } without preceding {
 | |
|     \( # First commands, for which the pattern fully terminates them
 | |
|       '/e[ \t]#/' $'/((\\\n|\\[^\n]|[^\\\n])##\n|[\n;])/' ':commands:command:_cmdstring' # GNU extension
 | |
|     \|
 | |
|       $'/{[ ;\t\n]#/' -'((++nest,1))' # opening brace
 | |
|     \|
 | |
|       '/\#/' # comments
 | |
|       $'/[^\n]##\n[\n; \t]#/' ':comments:comment:'
 | |
|     \|
 | |
|       $'/[aci]/' # a, c and i commands
 | |
|       \(
 | |
|         $'/[ \t]#/' -'[[ $variant = gnu && $+opt_args[--posix] = 0 ]]' # GNU allows, e.g. 'c string'
 | |
|       \|
 | |
|         $'/[ \t]#/' $'/\\\n/' ':newlines:newline:compadd -Q -S "" "$bsnl"'
 | |
|       \)
 | |
|       $'/(\\\n|\\[^\n]|[^\\\n])##\n[\n; \t]#/' ':strings:string:'
 | |
|     \|
 | |
|       $'/[RrwW][ \t]#/' $'/[^\n]##\n[\n; \t]#/' ':files:file:_files -S ""'
 | |
|     \| # Now commands with shared termination handling
 | |
|       \(
 | |
|         # branches/labels, GNU sed allows an empty label
 | |
|         $'/[:btT][ \t]#/' $'/[^ \t\n;]#/' $'%[ \t\n;]%' -'labels+=( $match )'
 | |
|             ':labels:label: _wanted -x labels expl label compadd -S "" -a labels'
 | |
|       \|
 | |
|         '/l/' $'/[ \t]#<->/' ':width:width:'
 | |
|       \|
 | |
|         '/s(?)/' -'sep=${match#s}' # Substitutions
 | |
|         \( '/\\?/' \| '/?/' -'[[ $match != $sep ]]' \) \#
 | |
|         '/?/' -'[[ $match = $sep ]]' ':regexes:source regex:'
 | |
|         \( '/\\?/' \| '/?/' -'[[ $match != $sep ]]' \) \#
 | |
|         '/?/' -'[[ $match = $sep ]]' ':regexes:substitute string (back-references with & and \1 .. \9):'
 | |
|         \( # Substitution flags
 | |
|           $'/w[ \t]#/' $'/[^\n]##/' $'%\n%' ':files:file:_files -S ""'
 | |
|         \|
 | |
|           # pass existing flags, building exclusion list from them
 | |
|           $'/[gpiImM0-9]#/' -'excl=( ${(s..)${${${match/[iI]/iI}/[mM]/mM}}/e/ew} )'
 | |
|           \(
 | |
|             '//' -'[[ -z ${excl[(r)[0-9]]} ]]' # exclude if numbers already there
 | |
|             '//' '%[^egpiImM0-9]%' ': _message -e numbers "number - substitute nth match"'
 | |
|           \|
 | |
|             '//' '%[^egpiImM0-9]%' $':flags:flag: _describe -t flags flag substflags -S "" -F excl'
 | |
|           \)
 | |
|         \)
 | |
|       \|
 | |
|         '/y(?)/' -'sep=${match#y}' # Character transliterations
 | |
|         \( '/\?/' \| '/?/' -'[[ $match != $sep ]]' \) \# '/?/' -'[[ $match = $sep ]]' ':source:source:'
 | |
|         \( '/\?/' \| '/?/' -'[[ $match != $sep ]]' \) \# '/?/' -'[[ $match = $sep ]]' ':dest:dest:'
 | |
|       \|
 | |
|         '/[qQ]/' -'[[ $variant = gnu && $+opt_args[--posix] = 0 ]]'
 | |
|         $'/[\t ]#<->/' '%[^0-9]%' ':exit-codes:exit code:'
 | |
|       \|
 | |
|         '/[=dDFhHgGnNpPqQxz]/' # stand-alone commands that take no argument
 | |
|         \( $'/[ \t]#/' $'%[#\n;}]%' \| $'/[ \t]/' '/[]/' ': _message "no arguments"' \| \)
 | |
|       \|
 | |
|         $'/v[ \t]#/' $'/[^\n;}]#/' $'%[\n;}]%' ':versions:version:'
 | |
|       \|
 | |
|         $'/}[ \t]#/' -'((--nest,1))' # closing }
 | |
|       \|
 | |
|         /'[]'/ ':commands:command: _describe -t sed-commands "sed command" cmds_none -S "" -F excl -- cmds_slash -S / -- cmds_end -F excl -r \; -S $nl'
 | |
|       \)
 | |
|       $'/[ \t]#/'
 | |
|       \( $'/}[ \t]#/' -'((--nest,1))' \| \) # closing } is allowed by GNU sed without preceding ; or newline
 | |
|       \(
 | |
|        '/\#/' $'/[^\n]##\n[\n; \t]#/' ':comments:comment:' # line end comments
 | |
|       \|
 | |
|         # add in and auto-removable newline if command is terminated
 | |
|         $'/[;\n][ ;\t\n]#/' $':separators:separator:compadd -r ";" -S $nl ""'
 | |
|       \|
 | |
|         $'/{[ \t]#/' -'((++nest,1))' # opening {, keep count of nesting level
 | |
|       \)
 | |
|     \)
 | |
|   \) \#
 | |
| )
 | |
| 
 | |
| _regex_arguments _sed_expressions "$sedexpr[@]"
 | |
| 
 | |
| _arguments -s -S $aopts : "$args[@]"
 |