mirror of
git://git.code.sf.net/p/zsh/code
synced 2024-11-15 13:34:18 +01:00
b26b6b3fe0
Output multiple function definitions using "function" form. Note exceptions to errors with NO_MULTI_FUNC_DEF
637 lines
13 KiB
Plaintext
637 lines
13 KiB
Plaintext
%prep
|
|
|
|
mkdir funcdef.tmp
|
|
cd funcdef.tmp
|
|
setopt chaselinks
|
|
cd .
|
|
unsetopt chaselinks
|
|
mydir=$PWD
|
|
|
|
%test
|
|
|
|
fn1() { return 1; }
|
|
fn2() {
|
|
fn1
|
|
print $?
|
|
return 2
|
|
}
|
|
fn2
|
|
2:Basic status returns from functions
|
|
>1
|
|
|
|
fnz() { }
|
|
false
|
|
fnz
|
|
0:Empty function body resets status
|
|
|
|
fn3() { return 3; }
|
|
fnstat() { print $?; }
|
|
fn3
|
|
fnstat
|
|
0:Status is not reset on non-empty function body
|
|
>3
|
|
|
|
function f$$ () {
|
|
print regress expansion of function names
|
|
}
|
|
f$$
|
|
0:Regression test: 'function f$$ () { ... }'
|
|
>regress expansion of function names
|
|
|
|
function foo () print bar
|
|
foo
|
|
0:Function definition without braces
|
|
>bar
|
|
|
|
a a b() {
|
|
read word
|
|
print $0: $word
|
|
} <<<redirection
|
|
b
|
|
a
|
|
0:Multiple function definition with duplicate name and redirection
|
|
>b: redirection
|
|
>a: redirection
|
|
|
|
define_multiple() {
|
|
fn1 fn2 fn3() {
|
|
print This is $0
|
|
}
|
|
}
|
|
which -x2 define_multiple
|
|
define_multiple
|
|
fn1
|
|
fn2
|
|
fn3
|
|
0: Safe output of multiple function definitions
|
|
>define_multiple () {
|
|
> function fn1 fn2 fn3 {
|
|
> print This is $0
|
|
> }
|
|
>}
|
|
>This is fn1
|
|
>This is fn2
|
|
>This is fn3
|
|
|
|
functions -M m1
|
|
m1() { (( $# )) }
|
|
print $(( m1() ))
|
|
print $(( m1(1) ))
|
|
print $(( m1(1,2) ))
|
|
0:User-defined math functions, argument handling
|
|
>0
|
|
>1
|
|
>2
|
|
|
|
functions -M m2
|
|
m2() {
|
|
integer sum
|
|
local val
|
|
for val in $*; do
|
|
(( sum += $val ))
|
|
done
|
|
}
|
|
print $(( m2(1) ))
|
|
print $(( m2(1,3+3,4**2) ))
|
|
0:User-defined math functions, complex argument handling
|
|
>1
|
|
>23
|
|
|
|
functions -M m3 1 2
|
|
m3() { (( 1 )) }
|
|
print zero
|
|
(print $(( m3() )))
|
|
print one
|
|
print $(( m3(1) ))
|
|
print two
|
|
print $(( m3(1,2) ))
|
|
print three
|
|
(print $(( m3(1,2,3) )))
|
|
1:User-defined math functions, argument checking
|
|
>zero
|
|
>one
|
|
>1
|
|
>two
|
|
>1
|
|
>three
|
|
?(eval):4: wrong number of arguments: m3()
|
|
?(eval):10: wrong number of arguments: m3(1,2,3)
|
|
|
|
functions -M m4 0 0 testmathfunc
|
|
functions -M m5 0 0 testmathfunc
|
|
testmathfunc() {
|
|
if [[ $0 = m4 ]]; then
|
|
(( 4 ))
|
|
else
|
|
(( 5 ))
|
|
fi
|
|
}
|
|
print $(( m4() ))
|
|
print $(( m5() ))
|
|
0:User-defined math functions, multiple interfaces
|
|
>4
|
|
>5
|
|
|
|
strmathfunc() {
|
|
if [[ $0 = stralpha ]]; then
|
|
set -- ${1//[^[:alpha:]]}
|
|
fi
|
|
(( $#1 ))
|
|
}
|
|
functions -Ms strlen 1 1 strmathfunc
|
|
functions -Ms stralpha 1 1 strmathfunc
|
|
print $(( strlen(this, is, a, raw, string) ))
|
|
print $(( strlen() ))
|
|
print $(( stralpha(this, is, a, raw, string) ))
|
|
print $(( stralpha() ))
|
|
0:User-defined math functions, string arguments
|
|
>24
|
|
>0
|
|
>16
|
|
>0
|
|
|
|
command_not_found_handler() {
|
|
print "Great News! I've handled the command:"
|
|
print "$1"
|
|
print "with arguments:"
|
|
print -l ${argv[2,-1]}
|
|
}
|
|
ACommandWhichHadBetterNotExistOnTheSystem and some "really useful" args
|
|
0:Command not found handler, success
|
|
>Great News! I've handled the command:
|
|
>ACommandWhichHadBetterNotExistOnTheSystem
|
|
>with arguments:
|
|
>and
|
|
>some
|
|
>really useful
|
|
>args
|
|
|
|
# ' deconfuse emacs
|
|
|
|
command_not_found_handler() {
|
|
print "Your command:" >&2
|
|
print "$1" >&2
|
|
print "has gone down the tubes. Sorry." >&2
|
|
return 42
|
|
}
|
|
ThisCommandDoesNotExistEither
|
|
42:Command not found handler, failure
|
|
?Your command:
|
|
?ThisCommandDoesNotExistEither
|
|
?has gone down the tubes. Sorry.
|
|
|
|
local variable=outside
|
|
print "I am $variable"
|
|
function {
|
|
local variable=inside
|
|
print "I am $variable"
|
|
}
|
|
print "I am $variable"
|
|
() {
|
|
local variable="inside again"
|
|
print "I am $variable"
|
|
}
|
|
print "I am $variable"
|
|
0:Anonymous function scope
|
|
>I am outside
|
|
>I am inside
|
|
>I am outside
|
|
>I am inside again
|
|
>I am outside
|
|
|
|
integer i
|
|
for (( i = 0; i < 10; i++ )); do function {
|
|
case $i in
|
|
([13579])
|
|
print $i is odd
|
|
;|
|
|
([2468])
|
|
print $i is even
|
|
;|
|
|
([2357])
|
|
print $i is prime
|
|
;;
|
|
esac
|
|
}; done
|
|
0:Anonymous function with patterns in loop
|
|
>1 is odd
|
|
>2 is even
|
|
>2 is prime
|
|
>3 is odd
|
|
>3 is prime
|
|
>4 is even
|
|
>5 is odd
|
|
>5 is prime
|
|
>6 is even
|
|
>7 is odd
|
|
>7 is prime
|
|
>8 is even
|
|
>9 is odd
|
|
|
|
echo stuff in file >file.in
|
|
function {
|
|
sed 's/stuff/rubbish/'
|
|
} <file.in >file.out
|
|
cat file.out
|
|
0:Anonymous function redirection
|
|
>rubbish in file
|
|
|
|
variable="Do be do"
|
|
print $variable
|
|
function {
|
|
print $variable
|
|
local variable="Da de da"
|
|
print $variable
|
|
function {
|
|
print $variable
|
|
local variable="Dum da dum"
|
|
print $variable
|
|
}
|
|
print $variable
|
|
}
|
|
print $variable
|
|
0:Nested anonymous functions
|
|
>Do be do
|
|
>Do be do
|
|
>Da de da
|
|
>Da de da
|
|
>Dum da dum
|
|
>Da de da
|
|
>Do be do
|
|
|
|
() (cat $1 $2) <(print process expanded) =(print expanded to file)
|
|
0:Process substitution with anonymous functions
|
|
>process expanded
|
|
>expanded to file
|
|
|
|
() { print This has arguments $*; } of all sorts; print After the function
|
|
function { print More stuff $*; } and why not; print Yet more
|
|
0:Anonymous function with arguments
|
|
>This has arguments of all sorts
|
|
>After the function
|
|
>More stuff and why not
|
|
>Yet more
|
|
|
|
fn() {
|
|
(){ print Anonymous function 1 $*; } with args
|
|
function { print Anonymous function 2 $*; } with more args
|
|
print Following bit
|
|
}
|
|
functions fn
|
|
0:Text representation of anonymous function with arguments
|
|
>fn () {
|
|
> () {
|
|
> print Anonymous function 1 $*
|
|
> } with args
|
|
> () {
|
|
> print Anonymous function 2 $*
|
|
> } with more args
|
|
> print Following bit
|
|
>}
|
|
|
|
touch yes no
|
|
() { echo $1 } (y|z)*
|
|
(echo here)
|
|
() { echo $* } some (y|z)*
|
|
() { echo empty };(echo here)
|
|
0:Anonymous function arguments and command arguments
|
|
>yes
|
|
>here
|
|
>some yes
|
|
>empty
|
|
>here
|
|
|
|
if true; then f() { echo foo1; } else f() { echo bar1; } fi; f
|
|
if false; then f() { echo foo2; } else f() { echo bar2; } fi; f
|
|
0:Compatibility with other shells when not anonymous functions
|
|
>foo1
|
|
>bar2
|
|
|
|
(
|
|
setopt ignorebraces
|
|
fpath=(.)
|
|
print "{ echo OK }\n[[ -o ignorebraces ]] || print 'ignorebraces is off'" \
|
|
>emufunctest
|
|
(autoload -z emufunctest; emufunctest) 2>&1
|
|
emulate zsh -c 'autoload -Uz emufunctest'
|
|
emufunctest
|
|
[[ -o ignorebraces ]] && print 'ignorebraces is still on here'
|
|
)
|
|
0:sticky emulation applies to autoloads and autoloaded function execution
|
|
>emufunctest:3: parse error near `\n'
|
|
>OK
|
|
>ignorebraces is off
|
|
>ignorebraces is still on here
|
|
#` (matching error message for editors parsing the file)
|
|
|
|
# lsfoo should not be expanded as an anonymous function argument
|
|
alias lsfoo='This is not ls.'
|
|
() (echo anon func; echo "$@") lsfoo
|
|
0:Anonymous function with arguments in a form nobody sane would ever use but unfortunately we have to support anyway
|
|
>anon func
|
|
>lsfoo
|
|
|
|
print foo | () cat
|
|
0:Simple anonymous function should not simplify enclosing pipeline
|
|
>foo
|
|
|
|
alias fooalias=barexpansion
|
|
funcwithalias() { echo $(fooalias); }
|
|
functions funcwithalias
|
|
barexpansion() { print This is the correct output.; }
|
|
funcwithalias
|
|
0:Alias expanded in command substitution does not appear expanded in text
|
|
>funcwithalias () {
|
|
> echo $(fooalias)
|
|
>}
|
|
>This is the correct output.
|
|
|
|
unfunction command_not_found_handler # amusing but unhelpful
|
|
alias first='firstfn1 firstfn2' second='secondfn1 secondfn2'
|
|
function first second { print This is function $0; }
|
|
first
|
|
second
|
|
firstfn1
|
|
secondfn1
|
|
127:No alias expansion after "function" keyword
|
|
>This is function first
|
|
>This is function second
|
|
?(eval):6: command not found: firstfn1
|
|
?(eval):7: command not found: secondfn1
|
|
|
|
(
|
|
fpath=(.)
|
|
print "print oops was successfully autoloaded" >oops
|
|
oops() { eval autoload -X }
|
|
oops
|
|
which -x2 oops
|
|
)
|
|
0:autoload containing eval
|
|
>oops was successfully autoloaded
|
|
>oops () {
|
|
> print oops was successfully autoloaded
|
|
>}
|
|
|
|
(
|
|
fpath=(.)
|
|
printf '%s\n' 'oops(){}' 'ninjas-earring(){}' 'oops "$@"' >oops
|
|
autoload oops
|
|
oops
|
|
whence -v oops
|
|
)
|
|
0q:whence -v of zsh-style autoload
|
|
>oops is a shell function from $mydir/oops
|
|
|
|
(
|
|
fpath=(.)
|
|
mkdir extra
|
|
print 'print "I have been loaded by explicit path."' >extra/spec
|
|
autoload -Uz $PWD/extra/spec
|
|
spec
|
|
)
|
|
0:autoload with explicit path
|
|
>I have been loaded by explicit path.
|
|
|
|
(
|
|
fpath=(.)
|
|
print 'print "I have been loaded by default path."' >def
|
|
autoload -Uz $PWD/extra/def
|
|
def
|
|
)
|
|
1:autoload with explicit path with function in normal path, no -d
|
|
?(eval):5: def: function definition file not found
|
|
|
|
(
|
|
fpath=(.)
|
|
autoload -dUz $PWD/extra/def
|
|
def
|
|
)
|
|
0:autoload with explicit path with function in normal path, with -d
|
|
>I have been loaded by default path.
|
|
|
|
(
|
|
cd extra
|
|
fpath=(.)
|
|
autoload -r spec
|
|
cd ..
|
|
spec
|
|
)
|
|
0:autoload -r
|
|
>I have been loaded by explicit path.
|
|
|
|
(
|
|
cd extra
|
|
fpath=(.)
|
|
autoload -r def
|
|
cd ..
|
|
def
|
|
)
|
|
0:autoload -r is permissive
|
|
>I have been loaded by default path.
|
|
|
|
(
|
|
cd extra
|
|
fpath=(.)
|
|
autoload -R def
|
|
)
|
|
1:autoload -R is not permissive
|
|
?(eval):4: def: function definition file not found
|
|
|
|
(
|
|
spec() { autoload -XUz $PWD/extra; }
|
|
spec
|
|
)
|
|
0:autoload -X with path
|
|
>I have been loaded by explicit path.
|
|
|
|
# The line number 1 here and in the next test seems suspect,
|
|
# but this example proves it's not down to the new features
|
|
# being tested here.
|
|
(
|
|
fpath=(.)
|
|
cod() { autoload -XUz; }
|
|
cod
|
|
)
|
|
1:autoload -X with no path, failure
|
|
?(eval):1: cod: function definition file not found
|
|
|
|
(
|
|
fpath=(.)
|
|
def() { autoload -XUz $PWD/extra; }
|
|
def
|
|
)
|
|
1:autoload -X with wrong path and no -d
|
|
?(eval):1: def: function definition file not found
|
|
|
|
(
|
|
fpath=(.)
|
|
def() { autoload -dXUz $PWD/extra; }
|
|
def
|
|
)
|
|
0:autoload -dX with path
|
|
>I have been loaded by default path.
|
|
|
|
(
|
|
fpath=(.)
|
|
print 'loadthisfunc() { autoload -X }' >loadthisfunc_sourceme
|
|
print 'print Function was loaded correctly.' >loadthisfunc
|
|
source $PWD/loadthisfunc_sourceme
|
|
loadthisfunc
|
|
)
|
|
0: autoload -X interaction with absolute filename used for source location
|
|
>Function was loaded correctly.
|
|
|
|
(
|
|
fpath=()
|
|
mkdir extra2
|
|
for f in fun2a fun2b; do
|
|
print "print $f" >extra2/$f
|
|
done
|
|
repeat 3; do
|
|
autoload $PWD/extra2/fun2{a,b} $PWD/extra/spec
|
|
fun2a
|
|
fun2b
|
|
spec
|
|
unfunction fun2a fun2b spec
|
|
autoload $PWD/extra2/fun2{a,b} $PWD/extra/spec
|
|
spec
|
|
fun2b
|
|
fun2a
|
|
unfunction fun2a fun2b spec
|
|
done
|
|
)
|
|
0: Exercise the directory name cache for autoloads
|
|
>fun2a
|
|
>fun2b
|
|
>I have been loaded by explicit path.
|
|
>I have been loaded by explicit path.
|
|
>fun2b
|
|
>fun2a
|
|
>fun2a
|
|
>fun2b
|
|
>I have been loaded by explicit path.
|
|
>I have been loaded by explicit path.
|
|
>fun2b
|
|
>fun2a
|
|
>fun2a
|
|
>fun2b
|
|
>I have been loaded by explicit path.
|
|
>I have been loaded by explicit path.
|
|
>fun2b
|
|
>fun2a
|
|
|
|
not_trashed() { print This function was not trashed; }
|
|
autoload -Uz /foo/bar/not_trashed
|
|
not_trashed
|
|
0:autoload with absolute path does not trash loaded function
|
|
>This function was not trashed
|
|
|
|
# keep spec from getting loaded in parent shell for simplicity
|
|
(
|
|
if [[ $(whence -v spec) = 'spec is a shell function from '$PWD/* ]]
|
|
then print spec already loaded >&2; exit 1; fi
|
|
autoload -Uz $PWD/spec
|
|
autoload -Uz $PWD/extra/spec
|
|
spec
|
|
)
|
|
0:autoload with absolute path can be overridden if not yet loaded
|
|
>I have been loaded by explicit path.
|
|
|
|
(
|
|
if [[ $(whence -v spec) = 'spec is a shell function from '$PWD/* ]]
|
|
then print spec already loaded >&2; exit 1; fi
|
|
autoload -Uz $PWD/extra/spec
|
|
autoload spec
|
|
spec
|
|
)
|
|
0:autoload with absolute path not cancelled by bare autoload
|
|
>I have been loaded by explicit path.
|
|
|
|
(
|
|
FUNCNEST=0
|
|
fn() { true; }
|
|
fn
|
|
)
|
|
1:
|
|
?fn:4: maximum nested function level reached; increase FUNCNEST?
|
|
|
|
(
|
|
fpath=(.)
|
|
print "foo-bar() { print this should run automatically; }" >foo-bar
|
|
autoload -Uz foo-bar
|
|
foo-bar
|
|
)
|
|
0:autoload containing dash
|
|
>this should run automatically
|
|
|
|
tbc() {
|
|
print This function is called $0.
|
|
}
|
|
tbc
|
|
functions -c tbc newcopy
|
|
newcopy
|
|
unfunction tbc
|
|
newcopy
|
|
0:functions -c
|
|
>This function is called tbc.
|
|
>This function is called newcopy.
|
|
>This function is called newcopy.
|
|
|
|
(
|
|
fpath=(.)
|
|
print >tbc_auto 'print This autoloaded function is called $0.'
|
|
autoload -Uz tbc_auto
|
|
functions -c tbc_auto newcopy_auto
|
|
newcopy_auto
|
|
tbc_auto
|
|
)
|
|
0:functions -c with autoload
|
|
>This autoloaded function is called newcopy_auto.
|
|
>This autoloaded function is called tbc_auto.
|
|
|
|
(
|
|
fpath=(.)
|
|
print >tbc_redef "print This is the core of the old function."
|
|
autoload -Uz tbc_redef
|
|
functions -c tbc_redef tbc_original
|
|
tbc_redef() {
|
|
print About to call the original.
|
|
tbc_original
|
|
print Stopped calling the original because once is enough.
|
|
}
|
|
tbc_redef
|
|
)
|
|
0:function -c with redefinition
|
|
>About to call the original.
|
|
>This is the core of the old function.
|
|
>Stopped calling the original because once is enough.
|
|
|
|
(
|
|
fpath=(.)
|
|
print >line_info '\nprint -P "%1x:%I is where we are."'
|
|
autoload -Uz line_info
|
|
functions -c line_info preserve_file
|
|
preserve_file
|
|
)
|
|
0:functions -c preserves file information
|
|
>line_info:2 is where we are.
|
|
|
|
(
|
|
fpath=(.)
|
|
print >func_info '\nprint -P "%N:%i is where we are."'
|
|
autoload -Uz func_info
|
|
functions -c func_info change_output
|
|
change_output
|
|
)
|
|
0:functions -c updates non-file function information
|
|
>change_output:2 is where we are.
|
|
|
|
autoload -Uz cant_autoload_for_copying
|
|
functions -c cant_autoload_for_copying not_copied
|
|
1:functions -c gracefully rejects failed autoload
|
|
?(eval):2: cant_autoload_for_copying: function definition file not found
|
|
|
|
%clean
|
|
|
|
rm -f file.in file.out
|