about summary refs log tree commit diff
path: root/Functions/Misc
diff options
context:
space:
mode:
Diffstat (limited to 'Functions/Misc')
-rw-r--r--Functions/Misc/add-zle-hook-widget186
-rw-r--r--Functions/Misc/add-zsh-hook2
-rw-r--r--Functions/Misc/run-help-ip4
-rw-r--r--Functions/Misc/zcalc345
-rw-r--r--Functions/Misc/zed4
5 files changed, 445 insertions, 96 deletions
diff --git a/Functions/Misc/add-zle-hook-widget b/Functions/Misc/add-zle-hook-widget
new file mode 100644
index 000000000..d8a3950fb
--- /dev/null
+++ b/Functions/Misc/add-zle-hook-widget
@@ -0,0 +1,186 @@
+# Add to HOOK the given WIDGET
+# 
+# HOOK is one of isearch-exit, isearch-update, line-pre-redraw, line-init,
+# line-finish, history-line-set, keymap-select (the zle- prefix is allowed
+# but not required).  If a widget corresponding to HOOK already exists, it
+# is preserved and called first in the new set of HOOK widgets.
+#
+# With -d, remove the WIDGET from the hook instead; deletes the hook
+# linkage if it is empty.
+#
+# -D behaves like -d, but pattern characters are active in WIDGET, so
+# any matching widget will be deleted from the hook.
+#
+# Without -d, if the WIDGET is not already defined, a function having the
+# same name is marked for autoload; -U is passed down to autoload if that
+# is given, as are -z and -k.  (This is harmless if the function is
+# already defined.)  The WIDGET is then created with zle -N.
+#
+# The -L option lists the hooks and their associated widgets.
+
+# This is probably more safeguarding than necessary
+zmodload -e zsh/zle || return 1
+{ zmodload zsh/parameter && zmodload zsh/zleparameter } || {
+    print -u2 "add-zle-hook-widget: Need parameter modules for zle hooks"
+    return 1
+}
+
+() { # Preserve caller global option settings
+
+emulate -L zsh
+
+# Setup - create the base functions for hook widgets that call the others
+
+local -a hooktypes=( zle-isearch-exit zle-isearch-update
+                     zle-line-pre-redraw zle-line-init zle-line-finish
+                     zle-history-line-set zle-keymap-select )
+# Stash in zstyle to make it global
+zstyle zle-hook types ${hooktypes#zle-}
+
+# Relying on multifuncdef option here
+function azhw:${^hooktypes} {
+    local -a hook_widgets
+    local hook
+    # Values of these styles look like number:name
+    # and we run them in number order
+    zstyle -a $WIDGET widgets hook_widgets
+    for hook in "${(@)${(@on)hook_widgets[@]}#<->:}"; do
+	if [[ "$hook" = user:* ]]; then
+	    # Preserve $WIDGET within the renamed widget
+	    zle "$hook" -N -- "$@"
+	else
+	    zle "$hook" -Nw -- "$@"
+	fi || return
+    done
+    return 0
+}
+
+# Redefine ourself with the setup left out
+
+function add-zle-hook-widget {
+    local -a hooktypes
+    zstyle -a zle-hook types hooktypes
+
+    # This part copied from add-zsh-hook
+    local usage="Usage: $funcstack[1] hook widgetname\nValid hooks are:\n  $hooktypes"
+
+    local opt
+    local -a autoopts
+    integer del list help
+
+    while getopts "dDhLUzk" opt; do
+	case $opt in
+	    (d)
+	    del=1
+	    ;;
+
+	    (D)
+	    del=2
+	    ;;
+
+	    (h)
+	    help=1
+	    ;;
+
+	    (L)
+	    list=1
+	    ;;
+
+	    ([Uzk])
+	    autoopts+=(-$opt)
+	    ;;
+
+	    (*)
+	    return 1
+	    ;;
+	esac
+    done
+    shift $(( OPTIND - 1 ))
+
+    1=${1#zle-}	# Strip prefix not stored in zle-hook types style
+
+    if (( list )); then
+	zstyle -L "zle-(${1:-${(@j:|:)hooktypes[@]}})" widgets
+	return $?
+    elif (( help || $# != 2 || ${hooktypes[(I)$1]} == 0 )); then
+	print -u$(( 2 - help )) $usage
+	return $(( 1 - help ))
+    fi
+
+    local -aU extant_hooks
+    local hook="zle-$1"
+    local fn="$2"
+
+    if (( del )); then
+        # delete, if hook is set
+	if zstyle -g extant_hooks "$hook" widgets; then
+	    if (( del == 2 )); then
+		set -A extant_hooks ${extant_hooks[@]:#(<->:|)${~fn}}
+	    else
+		set -A extant_hooks ${extant_hooks[@]:#(<->:|)$fn}
+	    fi
+            # unset if no remaining entries
+	    if (( ${#extant_hooks} )); then
+		zstyle "$hook" widgets "${extant_hooks[@]}"
+	    else
+		zstyle -d "$hook" widgets
+	    fi
+	fi
+    else
+	# Check whether attempting to add a widget named for the hook
+	if [[ "$fn" = "$hook" ]]; then
+	    if [[ -n "${widgets[$fn]}" ]]; then
+		print -u2 "$funcstack[1]: Cannot hook $fn to itself"
+		return 1
+	    fi
+	    # No point in building the array until another is added
+	    autoload "${autoopts[@]}" -- "$fn"
+	    zle -N "$fn"
+	    return 0
+	fi
+	integer i=${#options[ksharrays]}-2
+	zstyle -g extant_hooks "$hook" widgets
+        # Check for an existing widget, add it as the first hook
+	if [[ ${widgets[$hook]} != "user:azhw:$hook" ]]; then
+	    if [[ -n ${widgets[$hook]} ]]; then
+		zle -A "$hook" "${widgets[$hook]}"
+		extant_hooks=(0:"${widgets[$hook]}" "${extant_hooks[@]}")
+	    fi
+	    zle -N "$hook" azhw:"$hook"
+	fi
+	# Add new widget only if not already in the hook list
+	if [[ -z ${(M)extant_hooks[@]:#(<->:|)$fn} ]]; then
+       	    # no index and not already hooked
+            # assign largest existing index plus 1
+	    i=${${(On@)${(@M)extant_hooks[@]#<->:}%:}[i]}+1
+	else
+	    return 0
+	fi
+	extant_hooks+=("${i}:${fn}")
+	zstyle -- "$hook" widgets "${extant_hooks[@]}"
+	if [[ -z "${widgets[$fn]}" ]]; then
+	    autoload "${autoopts[@]}" -- "$fn"
+	    zle -N -- "$fn"
+	fi
+	if [[ -z "${widgets[$hook]}" ]]; then
+	    zle -N "$hook" azhw:"$hook"
+	fi
+    fi
+}
+
+} "$@" # Resume caller global options
+
+# Handle zsh autoloading conventions:
+# - "file" appears last in zsh_eval_context when "source"-ing
+# - "evalautofunc" appears with kshautoload set or autoload -k
+# - "loadautofunc" appears with kshautoload unset or autoload -z
+# - use of autoload +X cannot reliably be detected, use best guess
+case "$zsh_eval_context" in
+*file) ;;
+*evalautofunc) ;;
+*loadautofunc) add-zle-hook-widget "$@";;
+*) [[ -o kshautoload ]] || add-zle-hook-widget "$@";;
+esac
+# Note fallback here is equivalent to the usual best-guess used by
+# functions written for zsh before $zsh_eval_context was available
+# so this case-statement is backward-compatible.
diff --git a/Functions/Misc/add-zsh-hook b/Functions/Misc/add-zsh-hook
index fc39659ae..3bc952e2f 100644
--- a/Functions/Misc/add-zsh-hook
+++ b/Functions/Misc/add-zsh-hook
@@ -19,7 +19,7 @@ hooktypes=(
   chpwd precmd preexec periodic zshaddhistory zshexit
   zsh_directory_name
 )
-local usage="Usage: $0 hook function\nValid hooks are:\n  $hooktypes"
+local usage="Usage: add-zsh-hook hook function\nValid hooks are:\n  $hooktypes"
 
 local opt
 local -a autoopts
diff --git a/Functions/Misc/run-help-ip b/Functions/Misc/run-help-ip
index 740af52b5..8807f9ef1 100644
--- a/Functions/Misc/run-help-ip
+++ b/Functions/Misc/run-help-ip
@@ -19,8 +19,8 @@ while [[ $# != 0 && $1 == -* ]]; do
 done
 
 case $1 in
-    (addr*) man ip-address ;;
-    (addrlabel) man ip-addrlabel ;;
+    (addrl*) man ip-addrlabel ;;
+    (a*) man ip-address ;;
     (l2*) man ip-l2tp ;;
     (li*) man ip-link ;;
     (ma*) man ip-maddress ;;
diff --git a/Functions/Misc/zcalc b/Functions/Misc/zcalc
index 857007a94..480373345 100644
--- a/Functions/Misc/zcalc
+++ b/Functions/Misc/zcalc
@@ -94,24 +94,53 @@
 # sequentially just as if read automatically.
 
 emulate -L zsh
-setopt extendedglob
+setopt extendedglob typesetsilent
+
+zcalc_show_value() {
+  if [[ -n $_base ]]; then
+    print -- $(( $_base $1 ))
+  elif [[ $1 = *.* ]] || (( _outdigits )); then
+    # With normal output, ensure trailing "." doesn't get lost.
+    if [[ -z $_forms[_outform] || ($_outform -eq 1 && $1 = *.) ]]; then
+      print -- $(( $1 ))
+    else
+      printf "$_forms[_outform]\n" $_outdigits $1
+    fi
+  else
+    printf "%d\n" $1
+  fi
+}
 
 # For testing in ZLE functions.
 local ZCALC_ACTIVE=1
 
 # TODO: make local variables that shouldn't be visible in expressions
 # begin with _.
-local line ans base defbase forms match mbegin mend psvar optlist opt arg
+local _line ans _base _defbase _forms match mbegin mend
+local psvar _optlist _opt _arg _tmp
 local compcontext="-zcalc-line-"
-integer num outdigits outform=1 expression_mode
-local -a expressions
+integer _num _outdigits _outform=1 _expression_mode
+integer _rpn_mode _matched _show_stack _i _n
+integer _max_stack _push
+local -a _expressions stack
 
 # We use our own history file with an automatic pop on exit.
 history -ap "${ZDOTDIR:-$HOME}/.zcalc_history"
 
-forms=( '%2$g' '%.*g' '%.*f' '%.*E' '')
+_forms=( '%2$g' '%.*g' '%.*f' '%.*E' '')
 
-zmodload -i zsh/mathfunc 2>/dev/null
+local _mathfuncs
+if zmodload -i zsh/mathfunc 2>/dev/null; then
+  zmodload -P _mathfuncs -FL zsh/mathfunc
+  _mathfuncs="("${(j.|.)${_mathfuncs##f:}}")"
+fi
+local -A _userfuncs
+for _line in ${(f)"$(functions -M)"}; do
+  match=(${=_line})
+  # get minimum number of arguments
+  _userfuncs[${match[3]}]=${match[4]}
+done
+_line=
 autoload -Uz zmathfuncdef
 
 if (( ! ${+ZCALCPROMPT} )); then
@@ -127,111 +156,119 @@ if [[ -f "${ZDOTDIR:-$HOME}/.zcalcrc" ]]; then
 fi
 
 # Process command line
-while [[ -n $1 && $1 = -(|[#-]*|f|e) ]]; do
-  optlist=${1[2,-1]}
+while [[ -n $1 && $1 = -(|[#-]*|f|e|r(<->|)) ]]; do
+  _optlist=${1[2,-1]}
   shift
-  [[ $optlist = (|-) ]] && break
-  while [[ -n $optlist ]]; do
-    opt=${optlist[1]}
-    optlist=${optlist[2,-1]}
-    case $opt in
+  [[ $_optlist = (|-) ]] && break
+  while [[ -n $_optlist ]]; do
+    _opt=${_optlist[1]}
+    _optlist=${_optlist[2,-1]}
+    case $_opt in
       ('#') # Default base
-            if [[ -n $optlist ]]; then
-	       arg=$optlist
-	       optlist=
+            if [[ -n $_optlist ]]; then
+	       _arg=$_optlist
+	       _optlist=
 	    elif [[ -n $1 ]]; then
-	       arg=$1
+	       _arg=$1
 	       shift
 	    else
 	       print -- "-# requires an argument" >&2
 	       return 1
 	    fi
-	    if [[ $arg != (|\#)[[:digit:]]## ]]; then
+	    if [[ $_arg != (|\#)[[:digit:]]## ]]; then
 	      print -- "-# requires a decimal number as an argument" >&2
 	      return 1
 	    fi
-            defbase="[#${arg}]"
+            _defbase="[#${_arg}]"
 	    ;;
 	(f) # Force floating point operation
 	    setopt forcefloat
 	    ;;
         (e) # Arguments are expressions
-	    (( expression_mode = 1 ));
+	    (( _expression_mode = 1 ));
+	    ;;
+        (r) # RPN mode.
+	    (( _rpn_mode = 1 ))
+	    ZCALC_ACTIVE=rpn
+	    if [[ $_optlist = (#b)(<->)* ]]; then
+	       (( _show_stack = ${match[1]} ))
+               _optlist=${_optlist[${#match[1]}+1,-2]}
+	    fi
 	    ;;
     esac
   done
 done
 
-if (( expression_mode )); then
-  expressions=("$@")
+if (( _expression_mode )); then
+  _expressions=("$@")
   argv=()
 fi
 
-for (( num = 1; num <= $#; num++ )); do
+for (( _num = 1; _num <= $#; _num++ )); do
   # Make sure all arguments have been evaluated.
   # The `$' before the second argv forces string rather than numeric
   # substitution.
-  (( argv[$num] = $argv[$num] ))
-  print "$num> $argv[$num]"
+  (( argv[$_num] = $argv[$_num] ))
+  print "$_num> $argv[$_num]"
 done
 
-psvar[1]=$num
-local prev_line cont_prompt
-while (( expression_mode )) ||
-  vared -cehp "${cont_prompt}${ZCALCPROMPT}" line; do
-  if (( expression_mode )); then
-    (( ${#expressions} )) || break
-    line=$expressions[1]
-    shift expressions
+psvar[1]=$_num
+local _prev_line _cont_prompt
+while (( _expression_mode )) ||
+  vared -cehp "${_cont_prompt}${ZCALCPROMPT}" _line; do
+  if (( _expression_mode )); then
+    (( ${#_expressions} )) || break
+    _line=$_expressions[1]
+    shift _expressions
   fi
-  if [[ $line = (|*[^\\])('\\')#'\' ]]; then
-    prev_line+=$line[1,-2]
-    cont_prompt="..."
-    line=
+  if [[ $_line = (|*[^\\])('\\')#'\' ]]; then
+    _prev_line+=$_line[1,-2]
+    _cont_prompt="..."
+    _line=
     continue
   fi
-  line="$prev_line$line"
-  prev_line=
-  cont_prompt=
+  _line="$_prev_line$_line"
+  _prev_line=
+  _cont_prompt=
   # Test whether there are as many open as close
-  # parentheses in the line so far.
-  if [[ ${#line//[^\(]} -gt ${#line//[^\)]} ]]; then
-      prev_line+=$line
-      cont_prompt="..."
-      line=
+  # parentheses in the _line so far.
+  if [[ ${#_line//[^\(]} -gt ${#_line//[^\)]} ]]; then
+      _prev_line+=$_line
+      _cont_prompt="..."
+      _line=
       continue
   fi
-  [[ -z $line ]] && break
+  [[ -z $_line ]] && break
   # special cases
   # Set default base if `[#16]' or `[##16]' etc. on its own.
   # Unset it if `[#]' or `[##]'.
-  if [[ $line = (#b)[[:blank:]]#('[#'(\#|)((<->|)(|_|_<->))']')[[:blank:]]#(*) ]]; then
+  if [[ $_line = (#b)[[:blank:]]#('[#'(\#|)((<->|)(|_|_<->))']')[[:blank:]]#(*) ]]; then
     if [[ -z $match[6] ]]; then
       if [[ -z $match[3] ]]; then
-	defbase=
+	_defbase=
       else
-	defbase=$match[1]
+	_defbase=$match[1]
       fi
-      print -s -- $line
-      print -- $(( ${defbase} ans ))
-      line=
+      print -s -- $_line
+      print -- $(( ${_defbase} ans ))
+      _line=
       continue
     else
-      base=$match[1]
+      _base=$match[1]
     fi
   else
-    base=$defbase
+    _base=$_defbase
   fi
 
-  print -s -- $line
+  print -s -- $_line
 
-  line="${${line##[[:blank:]]#}%%[[:blank:]]#}"
-  case "$line" in
+  _line="${${_line##[[:blank:]]#}%%[[:blank:]]#}"
+  case "$_line" in
     # Escapes begin with a colon
     (:(\\|)\!*)
     # shell escape: handle completion's habit of quoting the !
-    eval ${line##:(\\|)\![[:blank:]]#}
-    line=
+    eval ${_line##:(\\|)\![[:blank:]]#}
+    _line=
     continue
     ;;
 
@@ -241,72 +278,196 @@ while (( expression_mode )) ||
     ;;
 
     ((:|)norm) # restore output format to default
-      outform=1
+      _outform=1
     ;;
 
     ((:|)sci[[:blank:]]#(#b)(<->)(#B))
-      outdigits=$match[1]
-      outform=2
+      _outdigits=$match[1]
+      _outform=2
     ;;
 
     ((:|)fix[[:blank:]]#(#b)(<->)(#B))
-      outdigits=$match[1]
-      outform=3
+      _outdigits=$match[1]
+      _outform=3
     ;;
 
     ((:|)eng[[:blank:]]#(#b)(<->)(#B))
-      outdigits=$match[1]
-      outform=4
+      _outdigits=$match[1]
+      _outform=4
     ;;
 
     (:raw)
-    outform=5
+    _outform=5
     ;;
 
     ((:|)local([[:blank:]]##*|))
-      eval $line
-      line=
+      eval ${_line##:}
+      _line=
       continue
     ;;
 
     ((function|:f(unc(tion|)|))[[:blank:]]##(#b)([^[:blank:]]##)(|[[:blank:]]##([^[:blank:]]*)))
       zmathfuncdef $match[1] $match[3]
-      line=
+      _userfuncs[$match[1]]=${$(functions -Mm $match[1])[4]}
+      _line=
       continue
     ;;
 
     (:*)
     print "Unrecognised escape"
-    line=
+    _line=
+    continue
+    ;;
+
+    (\$[[:IDENT:]]##)
+    # Display only, no calculation
+    _line=${_line##\$}
+    print -r -- ${(P)_line}
+    _line=
     continue
     ;;
 
     (*)
-      # Latest value is stored as a string, because it might be floating
-      # point or integer --- we don't know till after the evaluation, and
-      # arrays always store scalars anyway.
-      #
-      # Since it's a string, we'd better make sure we know which
-      # base it's in, so don't change that until we actually print it.
-      eval "ans=\$(( $line ))"
-      # on error $ans is not set; let user re-edit line
-      [[ -n $ans ]] || continue
-      argv[num++]=$ans
-      psvar[1]=$num
+      _line=${${_line##[[:blank:]]##}%%[[:blank:]]##}
+      if [[ _rpn_mode -ne 0 && $_line != '' ]]; then
+	_push=1
+	_matched=1
+	case $_line in
+	  (\<[[:IDENT:]]##)
+	  ans=${(P)${_line##\<}}
+	  ;;
+
+	  (\=|pop|\>[[:IDENT:]]#)
+	  if (( ${#stack} < 1 )); then
+	    print -r -- "${_line}: not enough values on stack" >&2
+	    _line=
+	    continue
+	  fi
+	  case $_line in
+	    (=)
+	    ans=${stack[1]}
+	    ;;
+	    (pop|\>)
+	    _push=0
+	    shift stack
+	    ;;
+	    (\>[[:IDENT:]]##)
+	    if [[ ${_line##\>} = (_*|stack|ans|PI|E) ]]; then
+	      print "${_line##\>}: reserved variable" >&2
+	      _line=
+	      continue
+	    fi
+	    local ${_line##\>}
+	    (( ${_line##\>} = ${stack[1]} ))
+	    _push=0
+	    shift stack
+	    ;;
+	    (*)
+	    print "BUG in special RPN functions" >&2
+	    _line=
+	    continue
+	    ;;
+	  esac
+	  ;;
+
+	  (+|-|\^|\||\&|\*|/|\*\*|\>\>|\<\</)
+	  # Operators with two arguments
+	  if (( ${#stack} < 2 )); then
+	    print -r -- "${_line}: not enough values on stack" >&2
+	    _line=
+	    continue
+	  fi
+	  eval "(( ans = \${stack[2]} $_line \${stack[1]} ))"
+	  shift 2 stack
+	  ;;
+
+	  (ldexp|jn|yn|scalb|xy|\<\>)
+	  # Functions with two arguments
+	  if (( ${#stack} < 2 )); then
+	    print -r -- "${_line}: not enough values on stack" >&2
+	    _line=
+	    continue
+	  fi
+	  if [[ $_line = (xy|\<\>) ]]; then
+	    _tmp=${stack[1]}
+	    stack[1]=${stack[2]}
+	    stack[2]=$_tmp
+	    _push=0
+	  else
+	    eval "(( ans = ${_line}(\${stack[2]},\${stack[1]}) ))"
+	    shift 2 stack
+	  fi
+	  ;;
+
+	  (${~_mathfuncs})
+	  # Functions with a single argument.
+	  # This is actually a superset, but we should have matched
+	  # any that shouldn't be in it in previous cases.
+	  if (( ${#stack} < 1 )); then
+	    print -r -- "${_line}: not enough values on stack" >&2
+	    _line=
+	    continue
+	  fi
+	  eval "(( ans = ${_line}(\${stack[1]}) ))"
+	  shift stack
+	  ;;
+
+	  (${(kj.|.)~_userfuncs})
+	  # Get minimum number of arguments to user function
+	  _n=${_userfuncs[$_line]}
+	  if (( ${#stack} < n_ )); then
+	    print -r -- "${_line}: not enough values ($_n) on stack" >&2
+	    _line=
+	    continue
+	  fi
+	  _line+="("
+	  # least recent elements on stack are earlier arguments
+	  for (( _i = _n; _i > 0; _i-- )); do
+	    _line+=${stack[_i]}
+	    (( _i > 1 )) && _line+=","
+	  done
+	  _line+=")"
+	  shift $_n stack
+	  eval "(( ans = $_line ))"
+	  ;;
+
+	  (*)
+	  # Treat as expression evaluating to new value to go on stack.
+	  _matched=0
+	  ;;
+	esac
+      else
+	_matched=0
+      fi
+      if (( ! _matched )); then
+	# Latest value is stored` as a string, because it might be floating
+	# point or integer --- we don't know till after the evaluation, and
+	# arrays always store scalars anyway.
+	#
+	# Since it's a string, we'd better make sure we know which
+	# base it's in, so don't change that until we actually print it.
+	if ! eval "ans=\$(( $_line ))"; then
+	  _line=
+	  continue
+	fi
+	# on error $ans is not set; let user re-edit _line
+	[[ -n $ans ]] || continue
+      fi
+      argv[_num++]=$ans
+      psvar[1]=$_num
+      (( _push )) && stack=($ans $stack)
     ;;
   esac
-  if [[ -n $base ]]; then
-    print -- $(( $base $ans ))
-  elif [[ $ans = *.* ]] || (( outdigits )); then
-    if [[ -z $forms[outform] ]]; then
-      print -- $(( $ans ))
-    else
-      printf "$forms[outform]\n" $outdigits $ans
-    fi
+  if (( _show_stack )); then
+    (( _max_stack = (_show_stack > ${#stack}) ? ${#stack} : _show_stack ))
+    for (( _i = _max_stack; _i > 0; _i-- )); do
+      printf "%3d: " $_i
+      zcalc_show_value ${stack[_i]}
+    done
   else
-    printf "%d\n" $ans
+    zcalc_show_value $ans
   fi
-  line=
+  _line=
 done
 
 return 0
diff --git a/Functions/Misc/zed b/Functions/Misc/zed
index eb8f557ea..77d392bc3 100644
--- a/Functions/Misc/zed
+++ b/Functions/Misc/zed
@@ -6,6 +6,8 @@
 # Use ^X^W to save, ^C to abort.
 # Option -f: edit shell functions.  (Also if called as fned.)
 
+setopt localoptions noksharrays
+
 local var opts zed_file_name
 # We do not want timeout while we are editing a file
 integer TMOUT=0 okargs=1 fun bind
@@ -74,7 +76,7 @@ if ((fun)) then
   if [[ $var = *\#\ undefined* ]] then
     var="$(autoload +X $1; functions -- $1)"
   elif [[ -z $var ]] then
-    var="$1() {
+    var="${(q-)1} () {
 }"
   fi
   vared -M zed -m zed-vicmd var && eval function "$var"