openbsd-dotfiles

Base configurations for my Openbsd desktop
git clone https://git.kausban.com/openbsd-dotfiles/raw/.git
Log | Files | Refs

.zshrc (129933B)


      1 # Filename:      /etc/zsh/zshrc
      2 # Purpose:       config file for zsh (z shell)
      3 # Authors:       grml-team (grml.org), (c) Michael Prokop <mika@grml.org>
      4 # Bug-Reports:   see http://grml.org/bugs/
      5 # License:       This file is licensed under the GPL v2.
      6 ################################################################################
      7 # This file is sourced only for interactive shells. It
      8 # should contain commands to set up aliases, functions,
      9 # options, key bindings, etc.
     10 #
     11 # Global Order: zshenv, zprofile, zshrc, zlogin
     12 ################################################################################
     13 
     14 # USAGE
     15 # If you are using this file as your ~/.zshrc file, please use ~/.zshrc.pre
     16 # and ~/.zshrc.local for your own customisations. The former file is read
     17 # before ~/.zshrc, the latter is read after it. Also, consider reading the
     18 # refcard and the reference manual for this setup, both available from:
     19 #     <http://grml.org/zsh/>
     20 
     21 # Contributing:
     22 # If you want to help to improve grml's zsh setup, clone the grml-etc-core
     23 # repository from git.grml.org:
     24 #   git clone git://git.grml.org/grml-etc-core.git
     25 #
     26 # Make your changes, commit them; use 'git format-patch' to create a series
     27 # of patches and send those to the following address via 'git send-email':
     28 #   grml-etc-core@grml.org
     29 #
     30 # Doing so makes sure the right people get your patches for review and
     31 # possibly inclusion.
     32 
     33 # zsh-refcard-tag documentation:
     34 #   You may notice strange looking comments in this file.
     35 #   These are there for a purpose. grml's zsh-refcard can now be
     36 #   automatically generated from the contents of the actual configuration
     37 #   file. However, we need a little extra information on which comments
     38 #   and what lines of code to take into account (and for what purpose).
     39 #
     40 # Here is what they mean:
     41 #
     42 # List of tags (comment types) used:
     43 #   #a#     Next line contains an important alias, that should
     44 #           be included in the grml-zsh-refcard.
     45 #           (placement tag: @@INSERT-aliases@@)
     46 #   #f#     Next line contains the beginning of an important function.
     47 #           (placement tag: @@INSERT-functions@@)
     48 #   #v#     Next line contains an important variable.
     49 #           (placement tag: @@INSERT-variables@@)
     50 #   #k#     Next line contains an important keybinding.
     51 #           (placement tag: @@INSERT-keybindings@@)
     52 #   #d#     Hashed directories list generation:
     53 #               start   denotes the start of a list of 'hash -d'
     54 #                       definitions.
     55 #               end     denotes its end.
     56 #           (placement tag: @@INSERT-hasheddirs@@)
     57 #   #A#     Abbreviation expansion list generation:
     58 #               start   denotes the beginning of abbreviations.
     59 #               end     denotes their end.
     60 #           Lines within this section that end in '#d .*' provide
     61 #           extra documentation to be included in the refcard.
     62 #           (placement tag: @@INSERT-abbrev@@)
     63 #   #m#     This tag allows you to manually generate refcard entries
     64 #           for code lines that are hard/impossible to parse.
     65 #               Example:
     66 #                   #m# k ESC-h Call the run-help function
     67 #               That would add a refcard entry in the keybindings table
     68 #               for 'ESC-h' with the given comment.
     69 #           So the syntax is: #m# <section> <argument> <comment>
     70 #   #o#     This tag lets you insert entries to the 'other' hash.
     71 #           Generally, this should not be used. It is there for
     72 #           things that cannot be done easily in another way.
     73 #           (placement tag: @@INSERT-other-foobar@@)
     74 #
     75 #   All of these tags (except for m and o) take two arguments, the first
     76 #   within the tag, the other after the tag:
     77 #
     78 #   #<tag><section># <comment>
     79 #
     80 #   Where <section> is really just a number, which are defined by the
     81 #   @secmap array on top of 'genrefcard.pl'. The reason for numbers
     82 #   instead of names is, that for the reader, the tag should not differ
     83 #   much from a regular comment. For zsh, it is a regular comment indeed.
     84 #   The numbers have got the following meanings:
     85 #         0 -> "default"
     86 #         1 -> "system"
     87 #         2 -> "user"
     88 #         3 -> "debian"
     89 #         4 -> "search"
     90 #         5 -> "shortcuts"
     91 #         6 -> "services"
     92 #
     93 #   So, the following will add an entry to the 'functions' table in the
     94 #   'system' section, with a (hopefully) descriptive comment:
     95 #       #f1# Edit an alias via zle
     96 #       edalias() {
     97 #
     98 #   It will then show up in the @@INSERT-aliases-system@@ replacement tag
     99 #   that can be found in 'grml-zsh-refcard.tex.in'.
    100 #   If the section number is omitted, the 'default' section is assumed.
    101 #   Furthermore, in 'grml-zsh-refcard.tex.in' @@INSERT-aliases@@ is
    102 #   exactly the same as @@INSERT-aliases-default@@. If you want a list of
    103 #   *all* aliases, for example, use @@INSERT-aliases-all@@.
    104 
    105 # zsh profiling
    106 # just execute 'ZSH_PROFILE_RC=1 zsh' and run 'zprof' to get the details
    107 if [[ $ZSH_PROFILE_RC -gt 0 ]] ; then
    108     zmodload zsh/zprof
    109 fi
    110 
    111 typeset -A GRML_STATUS_FEATURES
    112 
    113 function grml_status_feature () {
    114     emulate -L zsh
    115     local f=$1
    116     local -i success=$2
    117     if (( success == 0 )); then
    118         GRML_STATUS_FEATURES[$f]=success
    119     else
    120         GRML_STATUS_FEATURES[$f]=failure
    121     fi
    122     return 0
    123 }
    124 
    125 function grml_status_features () {
    126     emulate -L zsh
    127     local mode=${1:-+-}
    128     local this
    129     if [[ $mode == -h ]] || [[ $mode == --help ]]; then
    130         cat <<EOF
    131 grml_status_features [-h|--help|-|+|+-|FEATURE]
    132 
    133 Prints a summary of features the grml setup is trying to load. The
    134 result of loading a feature is recorded. This function lets you query
    135 the result.
    136 
    137 The function takes one argument: "-h" or "--help" to display this help
    138 text, "+" to display a list of all successfully loaded features, "-" for
    139 a list of all features that failed to load. "+-" to show a list of all
    140 features with their statuses.
    141 
    142 Any other word is considered to by a feature and prints its status.
    143 
    144 The default mode is "+-".
    145 EOF
    146         return 0
    147     fi
    148     if [[ $mode != - ]] && [[ $mode != + ]] && [[ $mode != +- ]]; then
    149         this="${GRML_STATUS_FEATURES[$mode]}"
    150         if [[ -z $this ]]; then
    151             printf 'unknown\n'
    152             return 1
    153         else
    154             printf '%s\n' $this
    155         fi
    156         return 0
    157     fi
    158     for key in ${(ok)GRML_STATUS_FEATURES}; do
    159         this="${GRML_STATUS_FEATURES[$key]}"
    160         if [[ $this == success ]] && [[ $mode == *+* ]]; then
    161             printf '%-16s %s\n' $key $this
    162         fi
    163         if [[ $this == failure ]] && [[ $mode == *-* ]]; then
    164             printf '%-16s %s\n' $key $this
    165         fi
    166     done
    167     return 0
    168 }
    169 
    170 # load .zshrc.pre to give the user the chance to overwrite the defaults
    171 [[ -r ${ZDOTDIR:-${HOME}}/.zshrc.pre ]] && source ${ZDOTDIR:-${HOME}}/.zshrc.pre
    172 
    173 # check for version/system
    174 # check for versions (compatibility reasons)
    175 function is51 () {
    176     [[ $ZSH_VERSION == 5.<1->* ]] && return 0
    177     return 1
    178 }
    179 
    180 function is4 () {
    181     [[ $ZSH_VERSION == <4->* ]] && return 0
    182     return 1
    183 }
    184 
    185 function is41 () {
    186     [[ $ZSH_VERSION == 4.<1->* || $ZSH_VERSION == <5->* ]] && return 0
    187     return 1
    188 }
    189 
    190 function is42 () {
    191     [[ $ZSH_VERSION == 4.<2->* || $ZSH_VERSION == <5->* ]] && return 0
    192     return 1
    193 }
    194 
    195 function is425 () {
    196     [[ $ZSH_VERSION == 4.2.<5->* || $ZSH_VERSION == 4.<3->* || $ZSH_VERSION == <5->* ]] && return 0
    197     return 1
    198 }
    199 
    200 function is43 () {
    201     [[ $ZSH_VERSION == 4.<3->* || $ZSH_VERSION == <5->* ]] && return 0
    202     return 1
    203 }
    204 
    205 function is433 () {
    206     [[ $ZSH_VERSION == 4.3.<3->* || $ZSH_VERSION == 4.<4->* \
    207                                  || $ZSH_VERSION == <5->* ]] && return 0
    208     return 1
    209 }
    210 
    211 function is437 () {
    212     [[ $ZSH_VERSION == 4.3.<7->* || $ZSH_VERSION == 4.<4->* \
    213                                  || $ZSH_VERSION == <5->* ]] && return 0
    214     return 1
    215 }
    216 
    217 function is439 () {
    218     [[ $ZSH_VERSION == 4.3.<9->* || $ZSH_VERSION == 4.<4->* \
    219                                  || $ZSH_VERSION == <5->* ]] && return 0
    220     return 1
    221 }
    222 
    223 #f1# Checks whether or not you're running grml
    224 function isgrml () {
    225     [[ -f /etc/grml_version ]] && return 0
    226     return 1
    227 }
    228 
    229 #f1# Checks whether or not you're running a grml cd
    230 function isgrmlcd () {
    231     [[ -f /etc/grml_cd ]] && return 0
    232     return 1
    233 }
    234 
    235 if isgrml ; then
    236 #f1# Checks whether or not you're running grml-small
    237     function isgrmlsmall () {
    238         if [[ ${${${(f)"$(</etc/grml_version)"}%% *}##*-} == 'small' ]]; then
    239             return 0
    240         fi
    241         return 1
    242     }
    243 else
    244     function isgrmlsmall () { return 1 }
    245 fi
    246 
    247 GRML_OSTYPE=$(uname -s)
    248 
    249 function islinux () {
    250     [[ $GRML_OSTYPE == "Linux" ]]
    251 }
    252 
    253 function isdarwin () {
    254     [[ $GRML_OSTYPE == "Darwin" ]]
    255 }
    256 
    257 function isfreebsd () {
    258     [[ $GRML_OSTYPE == "FreeBSD" ]]
    259 }
    260 
    261 function isopenbsd () {
    262     [[ $GRML_OSTYPE == "OpenBSD" ]]
    263 }
    264 
    265 function issolaris () {
    266     [[ $GRML_OSTYPE == "SunOS" ]]
    267 }
    268 
    269 #f1# are we running within an utf environment?
    270 function isutfenv () {
    271     case "$LANG $CHARSET $LANGUAGE" in
    272         *utf*) return 0 ;;
    273         *UTF*) return 0 ;;
    274         *)     return 1 ;;
    275     esac
    276 }
    277 
    278 # check for user, if not running as root set $SUDO to sudo
    279 (( EUID != 0 )) && SUDO='sudo' || SUDO=''
    280 
    281 # change directory to home on first invocation of zsh
    282 # important for rungetty -> autologin
    283 # Thanks go to Bart Schaefer!
    284 isgrml && function checkhome () {
    285     if [[ -z "$ALREADY_DID_CD_HOME" ]] ; then
    286         export ALREADY_DID_CD_HOME=$HOME
    287         cd
    288     fi
    289 }
    290 
    291 # check for zsh v3.1.7+
    292 
    293 if ! [[ ${ZSH_VERSION} == 3.1.<7->*      \
    294      || ${ZSH_VERSION} == 3.<2->.<->*    \
    295      || ${ZSH_VERSION} == <4->.<->*   ]] ; then
    296 
    297     printf '-!-\n'
    298     printf '-!- In this configuration we try to make use of features, that only\n'
    299     printf '-!- require version 3.1.7 of the shell; That way this setup can be\n'
    300     printf '-!- used with a wide range of zsh versions, while using fairly\n'
    301     printf '-!- advanced features in all supported versions.\n'
    302     printf '-!-\n'
    303     printf '-!- However, you are running zsh version %s.\n' "$ZSH_VERSION"
    304     printf '-!-\n'
    305     printf '-!- While this *may* work, it might as well fail.\n'
    306     printf '-!- Please consider updating to at least version 3.1.7 of zsh.\n'
    307     printf '-!-\n'
    308     printf '-!- DO NOT EXPECT THIS TO WORK FLAWLESSLY!\n'
    309     printf '-!- If it does today, you'\''ve been lucky.\n'
    310     printf '-!-\n'
    311     printf '-!- Ye been warned!\n'
    312     printf '-!-\n'
    313 
    314     function zstyle () { : }
    315 fi
    316 
    317 # autoload wrapper - use this one instead of autoload directly
    318 # We need to define this function as early as this, because autoloading
    319 # 'is-at-least()' needs it.
    320 function zrcautoload () {
    321     emulate -L zsh
    322     setopt extended_glob
    323     local fdir ffile
    324     local -i ffound
    325 
    326     ffile=$1
    327     (( ffound = 0 ))
    328     for fdir in ${fpath} ; do
    329         [[ -e ${fdir}/${ffile} ]] && (( ffound = 1 ))
    330     done
    331 
    332     (( ffound == 0 )) && return 1
    333     if [[ $ZSH_VERSION == 3.1.<6-> || $ZSH_VERSION == <4->* ]] ; then
    334         autoload -U ${ffile} || return 1
    335     else
    336         autoload ${ffile} || return 1
    337     fi
    338     return 0
    339 }
    340 
    341 # The following is the ‘add-zsh-hook’ function from zsh upstream. It is
    342 # included here to make the setup work with older versions of zsh (prior to
    343 # 4.3.7) in which this function had a bug that triggers annoying errors during
    344 # shell startup. This is exactly upstreams code from f0068edb4888a4d8fe94def,
    345 # with just a few adjustments in coding style to make the function look more
    346 # compact. This definition can be removed as soon as we raise the minimum
    347 # version requirement to 4.3.7 or newer.
    348 function add-zsh-hook () {
    349     # Add to HOOK the given FUNCTION.
    350     # HOOK is one of chpwd, precmd, preexec, periodic, zshaddhistory,
    351     # zshexit, zsh_directory_name (the _functions subscript is not required).
    352     #
    353     # With -d, remove the function from the hook instead; delete the hook
    354     # variable if it is empty.
    355     #
    356     # -D behaves like -d, but pattern characters are active in the function
    357     # name, so any matching function will be deleted from the hook.
    358     #
    359     # Without -d, the FUNCTION is marked for autoload; -U is passed down to
    360     # autoload if that is given, as are -z and -k. (This is harmless if the
    361     # function is actually defined inline.)
    362     emulate -L zsh
    363     local -a hooktypes
    364     hooktypes=(
    365         chpwd precmd preexec periodic zshaddhistory zshexit
    366         zsh_directory_name
    367     )
    368     local usage="Usage: $0 hook function\nValid hooks are:\n  $hooktypes"
    369     local opt
    370     local -a autoopts
    371     integer del list help
    372     while getopts "dDhLUzk" opt; do
    373         case $opt in
    374         (d) del=1 ;;
    375         (D) del=2 ;;
    376         (h) help=1 ;;
    377         (L) list=1 ;;
    378         ([Uzk]) autoopts+=(-$opt) ;;
    379         (*) return 1 ;;
    380         esac
    381     done
    382     shift $(( OPTIND - 1 ))
    383     if (( list )); then
    384         typeset -mp "(${1:-${(@j:|:)hooktypes}})_functions"
    385         return $?
    386     elif (( help || $# != 2 || ${hooktypes[(I)$1]} == 0 )); then
    387         print -u$(( 2 - help )) $usage
    388         return $(( 1 - help ))
    389     fi
    390     local hook="${1}_functions"
    391     local fn="$2"
    392     if (( del )); then
    393         # delete, if hook is set
    394         if (( ${(P)+hook} )); then
    395             if (( del == 2 )); then
    396                 set -A $hook ${(P)hook:#${~fn}}
    397             else
    398                 set -A $hook ${(P)hook:#$fn}
    399             fi
    400             # unset if no remaining entries --- this can give better
    401             # performance in some cases
    402             if (( ! ${(P)#hook} )); then
    403                 unset $hook
    404             fi
    405         fi
    406     else
    407         if (( ${(P)+hook} )); then
    408             if (( ${${(P)hook}[(I)$fn]} == 0 )); then
    409                 set -A $hook ${(P)hook} $fn
    410             fi
    411         else
    412             set -A $hook $fn
    413         fi
    414         autoload $autoopts -- $fn
    415     fi
    416 }
    417 
    418 # Load is-at-least() for more precise version checks Note that this test will
    419 # *always* fail, if the is-at-least function could not be marked for
    420 # autoloading.
    421 zrcautoload is-at-least || function is-at-least () { return 1 }
    422 
    423 # set some important options (as early as possible)
    424 
    425 # append history list to the history file; this is the default but we make sure
    426 # because it's required for share_history.
    427 setopt append_history
    428 
    429 # import new commands from the history file also in other zsh-session
    430 is4 && setopt share_history
    431 
    432 # save each command's beginning timestamp and the duration to the history file
    433 setopt extended_history
    434 
    435 # If a new command line being added to the history list duplicates an older
    436 # one, the older command is removed from the list
    437 is4 && setopt histignorealldups
    438 
    439 # remove command lines from the history list when the first character on the
    440 # line is a space
    441 setopt histignorespace
    442 
    443 # if a command is issued that can't be executed as a normal command, and the
    444 # command is the name of a directory, perform the cd command to that directory.
    445 setopt auto_cd
    446 
    447 # in order to use #, ~ and ^ for filename generation grep word
    448 # *~(*.gz|*.bz|*.bz2|*.zip|*.Z) -> searches for word not in compressed files
    449 # don't forget to quote '^', '~' and '#'!
    450 setopt extended_glob
    451 
    452 # display PID when suspending processes as well
    453 setopt longlistjobs
    454 
    455 # report the status of backgrounds jobs immediately
    456 setopt notify
    457 
    458 # whenever a command completion is attempted, make sure the entire command path
    459 # is hashed first.
    460 setopt hash_list_all
    461 
    462 # not just at the end
    463 setopt completeinword
    464 
    465 # Don't send SIGHUP to background processes when the shell exits.
    466 setopt nohup
    467 
    468 # make cd push the old directory onto the directory stack.
    469 setopt auto_pushd
    470 
    471 # avoid "beep"ing
    472 setopt nobeep
    473 
    474 # don't push the same dir twice.
    475 setopt pushd_ignore_dups
    476 
    477 # * shouldn't match dotfiles. ever.
    478 setopt noglobdots
    479 
    480 # use zsh style word splitting
    481 setopt noshwordsplit
    482 
    483 # don't error out when unset parameters are used
    484 setopt unset
    485 
    486 # setting some default values
    487 NOCOR=${NOCOR:-0}
    488 NOMENU=${NOMENU:-0}
    489 NOPRECMD=${NOPRECMD:-0}
    490 COMMAND_NOT_FOUND=${COMMAND_NOT_FOUND:-0}
    491 GRML_ZSH_CNF_HANDLER=${GRML_ZSH_CNF_HANDLER:-/usr/share/command-not-found/command-not-found}
    492 GRML_DISPLAY_BATTERY=${GRML_DISPLAY_BATTERY:-${BATTERY:-0}}
    493 GRMLSMALL_SPECIFIC=${GRMLSMALL_SPECIFIC:-1}
    494 ZSH_NO_DEFAULT_LOCALE=${ZSH_NO_DEFAULT_LOCALE:-0}
    495 
    496 typeset -ga ls_options
    497 typeset -ga grep_options
    498 
    499 # Colors on GNU ls(1)
    500 if ls --color=auto / >/dev/null 2>&1; then
    501     ls_options+=( --color=auto )
    502 # Colors on FreeBSD and OSX ls(1)
    503 elif ls -G / >/dev/null 2>&1; then
    504     ls_options+=( -G )
    505 fi
    506 
    507 # Natural sorting order on GNU ls(1)
    508 # OSX and IllumOS have a -v option that is not natural sorting
    509 if ls --version |& grep -q 'GNU' >/dev/null 2>&1 && ls -v / >/dev/null 2>&1; then
    510     ls_options+=( -v )
    511 fi
    512 
    513 # Color on GNU and FreeBSD grep(1)
    514 if grep --color=auto -q "a" <<< "a" >/dev/null 2>&1; then
    515     grep_options+=( --color=auto )
    516 fi
    517 
    518 # utility functions
    519 # this function checks if a command exists and returns either true
    520 # or false. This avoids using 'which' and 'whence', which will
    521 # avoid problems with aliases for which on certain weird systems. :-)
    522 # Usage: check_com [-c|-g] word
    523 #   -c  only checks for external commands
    524 #   -g  does the usual tests and also checks for global aliases
    525 function check_com () {
    526     emulate -L zsh
    527     local -i comonly gatoo
    528     comonly=0
    529     gatoo=0
    530 
    531     if [[ $1 == '-c' ]] ; then
    532         comonly=1
    533         shift 1
    534     elif [[ $1 == '-g' ]] ; then
    535         gatoo=1
    536         shift 1
    537     fi
    538 
    539     if (( ${#argv} != 1 )) ; then
    540         printf 'usage: check_com [-c|-g] <command>\n' >&2
    541         return 1
    542     fi
    543 
    544     if (( comonly > 0 )) ; then
    545         (( ${+commands[$1]}  )) && return 0
    546         return 1
    547     fi
    548 
    549     if     (( ${+commands[$1]}    )) \
    550         || (( ${+functions[$1]}   )) \
    551         || (( ${+aliases[$1]}     )) \
    552         || (( ${+reswords[(r)$1]} )) ; then
    553         return 0
    554     fi
    555 
    556     if (( gatoo > 0 )) && (( ${+galiases[$1]} )) ; then
    557         return 0
    558     fi
    559 
    560     return 1
    561 }
    562 
    563 # creates an alias and precedes the command with
    564 # sudo if $EUID is not zero.
    565 function salias () {
    566     emulate -L zsh
    567     local only=0 ; local multi=0
    568     local key val
    569     while getopts ":hao" opt; do
    570         case $opt in
    571             o) only=1 ;;
    572             a) multi=1 ;;
    573             h)
    574                 printf 'usage: salias [-hoa] <alias-expression>\n'
    575                 printf '  -h      shows this help text.\n'
    576                 printf '  -a      replace '\'' ; '\'' sequences with '\'' ; sudo '\''.\n'
    577                 printf '          be careful using this option.\n'
    578                 printf '  -o      only sets an alias if a preceding sudo would be needed.\n'
    579                 return 0
    580                 ;;
    581             *) salias -h >&2; return 1 ;;
    582         esac
    583     done
    584     shift "$((OPTIND-1))"
    585 
    586     if (( ${#argv} > 1 )) ; then
    587         printf 'Too many arguments %s\n' "${#argv}"
    588         return 1
    589     fi
    590 
    591     key="${1%%\=*}" ;  val="${1#*\=}"
    592     if (( EUID == 0 )) && (( only == 0 )); then
    593         alias -- "${key}=${val}"
    594     elif (( EUID > 0 )) ; then
    595         (( multi > 0 )) && val="${val// ; / ; sudo }"
    596         alias -- "${key}=sudo ${val}"
    597     fi
    598 
    599     return 0
    600 }
    601 
    602 # Check if we can read given files and source those we can.
    603 function xsource () {
    604     if (( ${#argv} < 1 )) ; then
    605         printf 'usage: xsource FILE(s)...\n' >&2
    606         return 1
    607     fi
    608 
    609     while (( ${#argv} > 0 )) ; do
    610         [[ -r "$1" ]] && source "$1"
    611         shift
    612     done
    613     return 0
    614 }
    615 
    616 # Check if we can read a given file and 'cat(1)' it.
    617 function xcat () {
    618     emulate -L zsh
    619     if (( ${#argv} != 1 )) ; then
    620         printf 'usage: xcat FILE\n' >&2
    621         return 1
    622     fi
    623 
    624     [[ -r $1 ]] && cat $1
    625     return 0
    626 }
    627 
    628 # Remove these functions again, they are of use only in these
    629 # setup files. This should be called at the end of .zshrc.
    630 function xunfunction () {
    631     emulate -L zsh
    632     local -a funcs
    633     local func
    634     funcs=(salias xcat xsource xunfunction zrcautoload zrcautozle)
    635     for func in $funcs ; do
    636         [[ -n ${functions[$func]} ]] \
    637             && unfunction $func
    638     done
    639     return 0
    640 }
    641 
    642 # this allows us to stay in sync with grml's zshrc and put own
    643 # modifications in ~/.zshrc.local
    644 function zrclocal () {
    645     xsource "/etc/zsh/zshrc.local"
    646     xsource "${ZDOTDIR:-${HOME}}/.zshrc.local"
    647     return 0
    648 }
    649 
    650 # locale setup
    651 if (( ZSH_NO_DEFAULT_LOCALE == 0 )); then
    652     xsource "/etc/default/locale"
    653 fi
    654 
    655 for var in LANG LC_ALL LC_MESSAGES ; do
    656     [[ -n ${(P)var} ]] && export $var
    657 done
    658 builtin unset -v var
    659 
    660 # set some variables
    661 if check_com -c vim ; then
    662 #v#
    663     export EDITOR=${EDITOR:-vim}
    664 else
    665     export EDITOR=${EDITOR:-vi}
    666 fi
    667 
    668 #v#
    669 export PAGER=${PAGER:-less}
    670 
    671 #v#
    672 export MAIL=${MAIL:-/var/mail/$USER}
    673 
    674 # color setup for ls:
    675 check_com -c dircolors && eval $(dircolors -b)
    676 # color setup for ls on OS X / FreeBSD:
    677 isdarwin && export CLICOLOR=1
    678 isfreebsd && export CLICOLOR=1
    679 
    680 # do MacPorts setup on darwin
    681 if isdarwin && [[ -d /opt/local ]]; then
    682     # Note: PATH gets set in /etc/zprofile on Darwin, so this can't go into
    683     # zshenv.
    684     PATH="/opt/local/bin:/opt/local/sbin:$PATH"
    685     MANPATH="/opt/local/share/man:$MANPATH"
    686 fi
    687 # do Fink setup on darwin
    688 isdarwin && xsource /sw/bin/init.sh
    689 
    690 # load our function and completion directories
    691 for fdir in /usr/share/grml/zsh/completion /usr/share/grml/zsh/functions; do
    692     fpath=( ${fdir} ${fdir}/**/*(/N) ${fpath} )
    693 done
    694 typeset -aU ffiles
    695 ffiles=(/usr/share/grml/zsh/functions/**/[^_]*[^~](N.:t))
    696 (( ${#ffiles} > 0 )) && autoload -U "${ffiles[@]}"
    697 unset -v fdir ffiles
    698 
    699 # support colors in less
    700 export LESS_TERMCAP_mb=$'\E[01;31m'
    701 export LESS_TERMCAP_md=$'\E[01;31m'
    702 export LESS_TERMCAP_me=$'\E[0m'
    703 export LESS_TERMCAP_se=$'\E[0m'
    704 export LESS_TERMCAP_so=$'\E[01;44;33m'
    705 export LESS_TERMCAP_ue=$'\E[0m'
    706 export LESS_TERMCAP_us=$'\E[01;32m'
    707 
    708 # mailchecks
    709 MAILCHECK=30
    710 
    711 # report about cpu-/system-/user-time of command if running longer than
    712 # 5 seconds
    713 REPORTTIME=5
    714 
    715 # watch for everyone but me and root
    716 watch=(notme root)
    717 
    718 # automatically remove duplicates from these arrays
    719 typeset -U path PATH cdpath CDPATH fpath FPATH manpath MANPATH
    720 
    721 # Load a few modules
    722 is4 && \
    723 for mod in parameter complist deltochar mathfunc ; do
    724     zmodload -i zsh/${mod} 2>/dev/null
    725     grml_status_feature mod:$mod $?
    726 done && builtin unset -v mod
    727 
    728 # autoload zsh modules when they are referenced
    729 if is4 ; then
    730     zmodload -a  zsh/stat    zstat
    731     zmodload -a  zsh/zpty    zpty
    732     zmodload -ap zsh/mapfile mapfile
    733 fi
    734 
    735 # completion system
    736 COMPDUMPFILE=${COMPDUMPFILE:-${ZDOTDIR:-${HOME}}/.zcompdump}
    737 if zrcautoload compinit ; then
    738     typeset -a tmp
    739     zstyle -a ':grml:completion:compinit' arguments tmp
    740     compinit -d ${COMPDUMPFILE} "${tmp[@]}"
    741     grml_status_feature compinit $?
    742     unset tmp
    743 else
    744     grml_status_feature compinit 1
    745     function compdef { }
    746 fi
    747 
    748 # completion system
    749 
    750 # called later (via is4 && grmlcomp)
    751 # note: use 'zstyle' for getting current settings
    752 #         press ^xh (control-x h) for getting tags in context; ^x? (control-x ?) to run complete_debug with trace output
    753 function grmlcomp () {
    754     # TODO: This could use some additional information
    755 
    756     # Make sure the completion system is initialised
    757     (( ${+_comps} )) || return 1
    758 
    759     # allow one error for every three characters typed in approximate completer
    760     zstyle ':completion:*:approximate:'    max-errors 'reply=( $((($#PREFIX+$#SUFFIX)/3 )) numeric )'
    761 
    762     # don't complete backup files as executables
    763     zstyle ':completion:*:complete:-command-::commands' ignored-patterns '(aptitude-*|*\~)'
    764 
    765     # start menu completion only if it could find no unambiguous initial string
    766     zstyle ':completion:*:correct:*'       insert-unambiguous true
    767     zstyle ':completion:*:corrections'     format $'%{\e[0;31m%}%d (errors: %e)%{\e[0m%}'
    768     zstyle ':completion:*:correct:*'       original true
    769 
    770     # activate color-completion
    771     zstyle ':completion:*:default'         list-colors ${(s.:.)LS_COLORS}
    772 
    773     # format on completion
    774     zstyle ':completion:*:descriptions'    format $'%{\e[0;31m%}completing %B%d%b%{\e[0m%}'
    775 
    776     # automatically complete 'cd -<tab>' and 'cd -<ctrl-d>' with menu
    777     # zstyle ':completion:*:*:cd:*:directory-stack' menu yes select
    778 
    779     # insert all expansions for expand completer
    780     zstyle ':completion:*:expand:*'        tag-order all-expansions
    781     zstyle ':completion:*:history-words'   list false
    782 
    783     # activate menu
    784     zstyle ':completion:*:history-words'   menu yes
    785 
    786     # ignore duplicate entries
    787     zstyle ':completion:*:history-words'   remove-all-dups yes
    788     zstyle ':completion:*:history-words'   stop yes
    789 
    790     # match uppercase from lowercase
    791     zstyle ':completion:*'                 matcher-list 'm:{a-z}={A-Z}'
    792 
    793     # separate matches into groups
    794     zstyle ':completion:*:matches'         group 'yes'
    795     zstyle ':completion:*'                 group-name ''
    796 
    797     if [[ "$NOMENU" -eq 0 ]] ; then
    798         # if there are more than 5 options allow selecting from a menu
    799         zstyle ':completion:*'               menu select=5
    800     else
    801         # don't use any menus at all
    802         setopt no_auto_menu
    803     fi
    804 
    805     zstyle ':completion:*:messages'        format '%d'
    806     zstyle ':completion:*:options'         auto-description '%d'
    807 
    808     # describe options in full
    809     zstyle ':completion:*:options'         description 'yes'
    810 
    811     # on processes completion complete all user processes
    812     zstyle ':completion:*:processes'       command 'ps -au$USER'
    813 
    814     # offer indexes before parameters in subscripts
    815     zstyle ':completion:*:*:-subscript-:*' tag-order indexes parameters
    816 
    817     # provide verbose completion information
    818     zstyle ':completion:*'                 verbose true
    819 
    820     # recent (as of Dec 2007) zsh versions are able to provide descriptions
    821     # for commands (read: 1st word in the line) that it will list for the user
    822     # to choose from. The following disables that, because it's not exactly fast.
    823     zstyle ':completion:*:-command-:*:'    verbose false
    824 
    825     # set format for warnings
    826     zstyle ':completion:*:warnings'        format $'%{\e[0;31m%}No matches for:%{\e[0m%} %d'
    827 
    828     # define files to ignore for zcompile
    829     zstyle ':completion:*:*:zcompile:*'    ignored-patterns '(*~|*.zwc)'
    830     zstyle ':completion:correct:'          prompt 'correct to: %e'
    831 
    832     # Ignore completion functions for commands you don't have:
    833     zstyle ':completion::(^approximate*):*:functions' ignored-patterns '_*'
    834 
    835     # Provide more processes in completion of programs like killall:
    836     zstyle ':completion:*:processes-names' command 'ps c -u ${USER} -o command | uniq'
    837 
    838     # complete manual by their section
    839     zstyle ':completion:*:manuals'    separate-sections true
    840     zstyle ':completion:*:manuals.*'  insert-sections   true
    841     zstyle ':completion:*:man:*'      menu yes select
    842 
    843     # Search path for sudo completion
    844     zstyle ':completion:*:sudo:*' command-path /usr/local/sbin \
    845                                                /usr/local/bin  \
    846                                                /usr/sbin       \
    847                                                /usr/bin        \
    848                                                /sbin           \
    849                                                /bin            \
    850                                                /usr/X11R6/bin
    851 
    852     # provide .. as a completion
    853     zstyle ':completion:*' special-dirs ..
    854 
    855     # run rehash on completion so new installed program are found automatically:
    856     function _force_rehash () {
    857         (( CURRENT == 1 )) && rehash
    858         return 1
    859     }
    860 
    861     ## correction
    862     # some people don't like the automatic correction - so run 'NOCOR=1 zsh' to deactivate it
    863     if [[ "$NOCOR" -gt 0 ]] ; then
    864         zstyle ':completion:*' completer _oldlist _expand _force_rehash _complete _files _ignored
    865         setopt nocorrect
    866     else
    867         # try to be smart about when to use what completer...
    868         setopt correct
    869         zstyle -e ':completion:*' completer '
    870             if [[ $_last_try != "$HISTNO$BUFFER$CURSOR" ]] ; then
    871                 _last_try="$HISTNO$BUFFER$CURSOR"
    872                 reply=(_complete _match _ignored _prefix _files)
    873             else
    874                 if [[ $words[1] == (rm|mv) ]] ; then
    875                     reply=(_complete _files)
    876                 else
    877                     reply=(_oldlist _expand _force_rehash _complete _ignored _correct _approximate _files)
    878                 fi
    879             fi'
    880     fi
    881 
    882     # command for process lists, the local web server details and host completion
    883     zstyle ':completion:*:urls' local 'www' '/var/www/' 'public_html'
    884 
    885     # Some functions, like _apt and _dpkg, are very slow. We can use a cache in
    886     # order to speed things up
    887     if [[ ${GRML_COMP_CACHING:-yes} == yes ]]; then
    888         GRML_COMP_CACHE_DIR=${GRML_COMP_CACHE_DIR:-${ZDOTDIR:-$HOME}/.cache}
    889         if [[ ! -d ${GRML_COMP_CACHE_DIR} ]]; then
    890             command mkdir -p "${GRML_COMP_CACHE_DIR}"
    891         fi
    892         zstyle ':completion:*' use-cache  yes
    893         zstyle ':completion:*:complete:*' cache-path "${GRML_COMP_CACHE_DIR}"
    894     fi
    895 
    896     # host completion
    897     if is42 ; then
    898         [[ -r ~/.ssh/config ]] && _ssh_config_hosts=(${${(s: :)${(ps:\t:)${${(@M)${(f)"$(<$HOME/.ssh/config)"}:#Host *}#Host }}}:#*[*?]*}) || _ssh_config_hosts=()
    899         [[ -r ~/.ssh/known_hosts ]] && _ssh_hosts=(${${${${(f)"$(<$HOME/.ssh/known_hosts)"}:#[\|]*}%%\ *}%%,*}) || _ssh_hosts=()
    900         [[ -r /etc/hosts ]] && : ${(A)_etc_hosts:=${(s: :)${(ps:\t:)${${(f)~~"$(</etc/hosts)"}%%\#*}##[:blank:]#[^[:blank:]]#}}} || _etc_hosts=()
    901     else
    902         _ssh_config_hosts=()
    903         _ssh_hosts=()
    904         _etc_hosts=()
    905     fi
    906 
    907     local localname
    908     if check_com hostname ; then
    909       localname=$(hostname)
    910     elif check_com hostnamectl ; then
    911       localname=$(hostnamectl --static)
    912     else
    913       localname="$(uname -n)"
    914     fi
    915 
    916     hosts=(
    917         "${localname}"
    918         "$_ssh_config_hosts[@]"
    919         "$_ssh_hosts[@]"
    920         "$_etc_hosts[@]"
    921         localhost
    922     )
    923     zstyle ':completion:*:hosts' hosts $hosts
    924     # TODO: so, why is this here?
    925     #  zstyle '*' hosts $hosts
    926 
    927     # use generic completion system for programs not yet defined; (_gnu_generic works
    928     # with commands that provide a --help option with "standard" gnu-like output.)
    929     for compcom in cp deborphan df feh fetchipac gpasswd head hnb ipacsum mv \
    930                    pal stow uname ; do
    931         [[ -z ${_comps[$compcom]} ]] && compdef _gnu_generic ${compcom}
    932     done; unset compcom
    933 
    934     # see upgrade function in this file
    935     compdef _hosts upgrade
    936 }
    937 
    938 # Keyboard setup: The following is based on the same code, we wrote for
    939 # debian's setup. It ensures the terminal is in the right mode, when zle is
    940 # active, so the values from $terminfo are valid. Therefore, this setup should
    941 # work on all systems, that have support for `terminfo'. It also requires the
    942 # zsh in use to have the `zsh/terminfo' module built.
    943 #
    944 # If you are customising your `zle-line-init()' or `zle-line-finish()'
    945 # functions, make sure you call the following utility functions in there:
    946 #
    947 #     - zle-line-init():      zle-smkx
    948 #     - zle-line-finish():    zle-rmkx
    949 
    950 # Use emacs-like key bindings by default:
    951 bindkey -e
    952 
    953 # Custom widgets:
    954 
    955 ## beginning-of-line OR beginning-of-buffer OR beginning of history
    956 ## by: Bart Schaefer <schaefer@brasslantern.com>, Bernhard Tittelbach
    957 function beginning-or-end-of-somewhere () {
    958     local hno=$HISTNO
    959     if [[ ( "${LBUFFER[-1]}" == $'\n' && "${WIDGET}" == beginning-of* ) || \
    960       ( "${RBUFFER[1]}" == $'\n' && "${WIDGET}" == end-of* ) ]]; then
    961         zle .${WIDGET:s/somewhere/buffer-or-history/} "$@"
    962     else
    963         zle .${WIDGET:s/somewhere/line-hist/} "$@"
    964         if (( HISTNO != hno )); then
    965             zle .${WIDGET:s/somewhere/buffer-or-history/} "$@"
    966         fi
    967     fi
    968 }
    969 zle -N beginning-of-somewhere beginning-or-end-of-somewhere
    970 zle -N end-of-somewhere beginning-or-end-of-somewhere
    971 
    972 # add a command line to the shells history without executing it
    973 function commit-to-history () {
    974     print -rs ${(z)BUFFER}
    975     zle send-break
    976 }
    977 zle -N commit-to-history
    978 
    979 # only slash should be considered as a word separator:
    980 function slash-backward-kill-word () {
    981     local WORDCHARS="${WORDCHARS:s@/@}"
    982     # zle backward-word
    983     zle backward-kill-word
    984 }
    985 zle -N slash-backward-kill-word
    986 
    987 # a generic accept-line wrapper
    988 
    989 # This widget can prevent unwanted autocorrections from command-name
    990 # to _command-name, rehash automatically on enter and call any number
    991 # of builtin and user-defined widgets in different contexts.
    992 #
    993 # For a broader description, see:
    994 # <http://bewatermyfriend.org/posts/2007/12-26.11-50-38-tooltime.html>
    995 #
    996 # The code is imported from the file 'zsh/functions/accept-line' from
    997 # <http://ft.bewatermyfriend.org/comp/zsh/zsh-dotfiles.tar.bz2>, which
    998 # distributed under the same terms as zsh itself.
    999 
   1000 # A newly added command will may not be found or will cause false
   1001 # correction attempts, if you got auto-correction set. By setting the
   1002 # following style, we force accept-line() to rehash, if it cannot
   1003 # find the first word on the command line in the $command[] hash.
   1004 zstyle ':acceptline:*' rehash true
   1005 
   1006 function Accept-Line () {
   1007     setopt localoptions noksharrays
   1008     local -a subs
   1009     local -xi aldone
   1010     local sub
   1011     local alcontext=${1:-$alcontext}
   1012 
   1013     zstyle -a ":acceptline:${alcontext}" actions subs
   1014 
   1015     (( ${#subs} < 1 )) && return 0
   1016 
   1017     (( aldone = 0 ))
   1018     for sub in ${subs} ; do
   1019         [[ ${sub} == 'accept-line' ]] && sub='.accept-line'
   1020         zle ${sub}
   1021 
   1022         (( aldone > 0 )) && break
   1023     done
   1024 }
   1025 
   1026 function Accept-Line-getdefault () {
   1027     emulate -L zsh
   1028     local default_action
   1029 
   1030     zstyle -s ":acceptline:${alcontext}" default_action default_action
   1031     case ${default_action} in
   1032         ((accept-line|))
   1033             printf ".accept-line"
   1034             ;;
   1035         (*)
   1036             printf ${default_action}
   1037             ;;
   1038     esac
   1039 }
   1040 
   1041 function Accept-Line-HandleContext () {
   1042     zle Accept-Line
   1043 
   1044     default_action=$(Accept-Line-getdefault)
   1045     zstyle -T ":acceptline:${alcontext}" call_default \
   1046         && zle ${default_action}
   1047 }
   1048 
   1049 function accept-line () {
   1050     setopt localoptions noksharrays
   1051     local -a cmdline
   1052     local -x alcontext
   1053     local buf com fname format msg default_action
   1054 
   1055     alcontext='default'
   1056     buf="${BUFFER}"
   1057     cmdline=(${(z)BUFFER})
   1058     com="${cmdline[1]}"
   1059     fname="_${com}"
   1060 
   1061     Accept-Line 'preprocess'
   1062 
   1063     zstyle -t ":acceptline:${alcontext}" rehash \
   1064         && [[ -z ${commands[$com]} ]]           \
   1065         && rehash
   1066 
   1067     if    [[ -n ${com}               ]] \
   1068        && [[ -n ${reswords[(r)$com]} ]] \
   1069        || [[ -n ${aliases[$com]}     ]] \
   1070        || [[ -n ${functions[$com]}   ]] \
   1071        || [[ -n ${builtins[$com]}    ]] \
   1072        || [[ -n ${commands[$com]}    ]] ; then
   1073 
   1074         # there is something sensible to execute, just do it.
   1075         alcontext='normal'
   1076         Accept-Line-HandleContext
   1077 
   1078         return
   1079     fi
   1080 
   1081     if    [[ -o correct              ]] \
   1082        || [[ -o correctall           ]] \
   1083        && [[ -n ${functions[$fname]} ]] ; then
   1084 
   1085         # nothing there to execute but there is a function called
   1086         # _command_name; a completion widget. Makes no sense to
   1087         # call it on the commandline, but the correct{,all} options
   1088         # will ask for it nevertheless, so warn the user.
   1089         if [[ ${LASTWIDGET} == 'accept-line' ]] ; then
   1090             # Okay, we warned the user before, he called us again,
   1091             # so have it his way.
   1092             alcontext='force'
   1093             Accept-Line-HandleContext
   1094 
   1095             return
   1096         fi
   1097 
   1098         if zstyle -t ":acceptline:${alcontext}" nocompwarn ; then
   1099             alcontext='normal'
   1100             Accept-Line-HandleContext
   1101         else
   1102             # prepare warning message for the user, configurable via zstyle.
   1103             zstyle -s ":acceptline:${alcontext}" compwarnfmt msg
   1104 
   1105             if [[ -z ${msg} ]] ; then
   1106                 msg="%c will not execute and completion %f exists."
   1107             fi
   1108 
   1109             zformat -f msg "${msg}" "c:${com}" "f:${fname}"
   1110 
   1111             zle -M -- "${msg}"
   1112         fi
   1113         return
   1114     elif [[ -n ${buf//[$' \t\n']##/} ]] ; then
   1115         # If we are here, the commandline contains something that is not
   1116         # executable, which is neither subject to _command_name correction
   1117         # and is not empty. might be a variable assignment
   1118         alcontext='misc'
   1119         Accept-Line-HandleContext
   1120 
   1121         return
   1122     fi
   1123 
   1124     # If we got this far, the commandline only contains whitespace, or is empty.
   1125     alcontext='empty'
   1126     Accept-Line-HandleContext
   1127 }
   1128 
   1129 zle -N accept-line
   1130 zle -N Accept-Line
   1131 zle -N Accept-Line-HandleContext
   1132 
   1133 # power completion / abbreviation expansion / buffer expansion
   1134 # see http://zshwiki.org/home/examples/zleiab for details
   1135 # less risky than the global aliases but powerful as well
   1136 # just type the abbreviation key and afterwards 'ctrl-x .' to expand it
   1137 declare -A abk
   1138 setopt extendedglob
   1139 setopt interactivecomments
   1140 abk=(
   1141 #   key   # value                  (#d additional doc string)
   1142 #A# start
   1143     '...'  '../..'
   1144     '....' '../../..'
   1145     'BG'   '& exit'
   1146     'C'    '| wc -l'
   1147     'G'    '|& grep '${grep_options:+"${grep_options[*]}"}
   1148     'H'    '| head'
   1149     'Hl'   ' --help |& less -r'    #d (Display help in pager)
   1150     'L'    '| less'
   1151     'LL'   '|& less -r'
   1152     'M'    '| most'
   1153     'N'    '&>/dev/null'           #d (No Output)
   1154     'R'    '| tr A-z N-za-m'       #d (ROT13)
   1155     'SL'   '| sort | less'
   1156     'S'    '| sort -u'
   1157     'T'    '| tail'
   1158     'V'    '|& vim -'
   1159 #A# end
   1160     'co'   './configure && make && sudo make install'
   1161 )
   1162 
   1163 function zleiab () {
   1164     emulate -L zsh
   1165     setopt extendedglob
   1166     local MATCH
   1167 
   1168     LBUFFER=${LBUFFER%%(#m)[.\-+:|_a-zA-Z0-9]#}
   1169     LBUFFER+=${abk[$MATCH]:-$MATCH}
   1170 }
   1171 
   1172 zle -N zleiab
   1173 
   1174 function help-show-abk () {
   1175   zle -M "$(print "Available abbreviations for expansion:"; print -a -C 2 ${(kv)abk})"
   1176 }
   1177 
   1178 zle -N help-show-abk
   1179 
   1180 # press "ctrl-x d" to insert the actual date in the form yyyy-mm-dd
   1181 function insert-datestamp () { LBUFFER+=${(%):-'%D{%Y-%m-%d}'}; }
   1182 zle -N insert-datestamp
   1183 
   1184 # press esc-m for inserting last typed word again (thanks to caphuso!)
   1185 function insert-last-typed-word () { zle insert-last-word -- 0 -1 };
   1186 zle -N insert-last-typed-word;
   1187 
   1188 function grml-zsh-fg () {
   1189   if (( ${#jobstates} )); then
   1190     zle .push-input
   1191     [[ -o hist_ignore_space ]] && BUFFER=' ' || BUFFER=''
   1192     BUFFER="${BUFFER}fg"
   1193     zle .accept-line
   1194   else
   1195     zle -M 'No background jobs. Doing nothing.'
   1196   fi
   1197 }
   1198 zle -N grml-zsh-fg
   1199 
   1200 # run command line as user root via sudo:
   1201 function sudo-command-line () {
   1202     [[ -z $BUFFER ]] && zle up-history
   1203     if [[ $BUFFER != sudo\ * ]]; then
   1204         BUFFER="sudo $BUFFER"
   1205         CURSOR=$(( CURSOR+5 ))
   1206     fi
   1207 }
   1208 zle -N sudo-command-line
   1209 
   1210 ### jump behind the first word on the cmdline.
   1211 ### useful to add options.
   1212 function jump_after_first_word () {
   1213     local words
   1214     words=(${(z)BUFFER})
   1215 
   1216     if (( ${#words} <= 1 )) ; then
   1217         CURSOR=${#BUFFER}
   1218     else
   1219         CURSOR=${#${words[1]}}
   1220     fi
   1221 }
   1222 zle -N jump_after_first_word
   1223 
   1224 #f5# Create directory under cursor or the selected area
   1225 function inplaceMkDirs () {
   1226     # Press ctrl-xM to create the directory under the cursor or the selected area.
   1227     # To select an area press ctrl-@ or ctrl-space and use the cursor.
   1228     # Use case: you type "mv abc ~/testa/testb/testc/" and remember that the
   1229     # directory does not exist yet -> press ctrl-XM and problem solved
   1230     local PATHTOMKDIR
   1231     if ((REGION_ACTIVE==1)); then
   1232         local F=$MARK T=$CURSOR
   1233         if [[ $F -gt $T ]]; then
   1234             F=${CURSOR}
   1235             T=${MARK}
   1236         fi
   1237         # get marked area from buffer and eliminate whitespace
   1238         PATHTOMKDIR=${BUFFER[F+1,T]%%[[:space:]]##}
   1239         PATHTOMKDIR=${PATHTOMKDIR##[[:space:]]##}
   1240     else
   1241         local bufwords iword
   1242         bufwords=(${(z)LBUFFER})
   1243         iword=${#bufwords}
   1244         bufwords=(${(z)BUFFER})
   1245         PATHTOMKDIR="${(Q)bufwords[iword]}"
   1246     fi
   1247     [[ -z "${PATHTOMKDIR}" ]] && return 1
   1248     PATHTOMKDIR=${~PATHTOMKDIR}
   1249     if [[ -e "${PATHTOMKDIR}" ]]; then
   1250         zle -M " path already exists, doing nothing"
   1251     else
   1252         zle -M "$(mkdir -p -v "${PATHTOMKDIR}")"
   1253         zle end-of-line
   1254     fi
   1255 }
   1256 
   1257 zle -N inplaceMkDirs
   1258 
   1259 #v1# set number of lines to display per page
   1260 HELP_LINES_PER_PAGE=20
   1261 #v1# set location of help-zle cache file
   1262 HELP_ZLE_CACHE_FILE=~/.cache/zsh_help_zle_lines.zsh
   1263 # helper function for help-zle, actually generates the help text
   1264 function help_zle_parse_keybindings () {
   1265     emulate -L zsh
   1266     setopt extendedglob
   1267     unsetopt ksharrays  #indexing starts at 1
   1268 
   1269     #v1# choose files that help-zle will parse for keybindings
   1270     ((${+HELPZLE_KEYBINDING_FILES})) || HELPZLE_KEYBINDING_FILES=( /etc/zsh/zshrc ~/.zshrc.pre ~/.zshrc ~/.zshrc.local )
   1271 
   1272     if [[ -r $HELP_ZLE_CACHE_FILE ]]; then
   1273         local load_cache=0
   1274         local f
   1275         for f ($HELPZLE_KEYBINDING_FILES) [[ $f -nt $HELP_ZLE_CACHE_FILE ]] && load_cache=1
   1276         [[ $load_cache -eq 0 ]] && . $HELP_ZLE_CACHE_FILE && return
   1277     fi
   1278 
   1279     #fill with default keybindings, possibly to be overwritten in a file later
   1280     #Note that due to zsh inconsistency on escaping assoc array keys, we encase the key in '' which we will remove later
   1281     local -A help_zle_keybindings
   1282     help_zle_keybindings['<Ctrl>@']="set MARK"
   1283     help_zle_keybindings['<Ctrl>x<Ctrl>j']="vi-join lines"
   1284     help_zle_keybindings['<Ctrl>x<Ctrl>b']="jump to matching brace"
   1285     help_zle_keybindings['<Ctrl>x<Ctrl>u']="undo"
   1286     help_zle_keybindings['<Ctrl>_']="undo"
   1287     help_zle_keybindings['<Ctrl>x<Ctrl>f<c>']="find <c> in cmdline"
   1288     help_zle_keybindings['<Ctrl>a']="goto beginning of line"
   1289     help_zle_keybindings['<Ctrl>e']="goto end of line"
   1290     help_zle_keybindings['<Ctrl>t']="transpose charaters"
   1291     help_zle_keybindings['<Alt>t']="transpose words"
   1292     help_zle_keybindings['<Alt>s']="spellcheck word"
   1293     help_zle_keybindings['<Ctrl>k']="backward kill buffer"
   1294     help_zle_keybindings['<Ctrl>u']="forward kill buffer"
   1295     help_zle_keybindings['<Ctrl>y']="insert previously killed word/string"
   1296     help_zle_keybindings["<Alt>'"]="quote line"
   1297     help_zle_keybindings['<Alt>"']="quote from mark to cursor"
   1298     help_zle_keybindings['<Alt><arg>']="repeat next cmd/char <arg> times (<Alt>-<Alt>1<Alt>0a -> -10 times 'a')"
   1299     help_zle_keybindings['<Alt>u']="make next word Uppercase"
   1300     help_zle_keybindings['<Alt>l']="make next word lowercase"
   1301     help_zle_keybindings['<Ctrl>xG']="preview expansion under cursor"
   1302     help_zle_keybindings['<Alt>q']="push current CL into background, freeing it. Restore on next CL"
   1303     help_zle_keybindings['<Alt>.']="insert (and interate through) last word from prev CLs"
   1304     help_zle_keybindings['<Alt>,']="complete word from newer history (consecutive hits)"
   1305     help_zle_keybindings['<Alt>m']="repeat last typed word on current CL"
   1306     help_zle_keybindings['<Ctrl>v']="insert next keypress symbol literally (e.g. for bindkey)"
   1307     help_zle_keybindings['!!:n*<Tab>']="insert last n arguments of last command"
   1308     help_zle_keybindings['!!:n-<Tab>']="insert arguments n..N-2 of last command (e.g. mv s s d)"
   1309     help_zle_keybindings['<Alt>h']="show help/manpage for current command"
   1310 
   1311     #init global variables
   1312     unset help_zle_lines help_zle_sln
   1313     typeset -g -a help_zle_lines
   1314     typeset -g help_zle_sln=1
   1315 
   1316     local k v f cline
   1317     local lastkeybind_desc contents     #last description starting with #k# that we found
   1318     local num_lines_elapsed=0            #number of lines between last description and keybinding
   1319     #search config files in the order they a called (and thus the order in which they overwrite keybindings)
   1320     for f in $HELPZLE_KEYBINDING_FILES; do
   1321         [[ -r "$f" ]] || continue   #not readable ? skip it
   1322         contents="$(<$f)"
   1323         for cline in "${(f)contents}"; do
   1324             #zsh pattern: matches lines like: #k# ..............
   1325             if [[ "$cline" == (#s)[[:space:]]#\#k\#[[:space:]]##(#b)(*)[[:space:]]#(#e) ]]; then
   1326                 lastkeybind_desc="$match[*]"
   1327                 num_lines_elapsed=0
   1328             #zsh pattern: matches lines that set a keybinding using bind2map, bindkey or compdef -k
   1329             #             ignores lines that are commentend out
   1330             #             grabs first in '' or "" enclosed string with length between 1 and 6 characters
   1331             elif [[ "$cline" == [^#]#(bind2maps[[:space:]](*)-s|bindkey|compdef -k)[[:space:]](*)(#b)(\"((?)(#c1,6))\"|\'((?)(#c1,6))\')(#B)(*)  ]]; then
   1332                 #description previously found ? description not more than 2 lines away ? keybinding not empty ?
   1333                 if [[ -n $lastkeybind_desc && $num_lines_elapsed -lt 2 && -n $match[1] ]]; then
   1334                     #substitute keybinding string with something readable
   1335                     k=${${${${${${${match[1]/\\e\^h/<Alt><BS>}/\\e\^\?/<Alt><BS>}/\\e\[5~/<PageUp>}/\\e\[6~/<PageDown>}//(\\e|\^\[)/<Alt>}//\^/<Ctrl>}/3~/<Alt><Del>}
   1336                     #put keybinding in assoc array, possibly overwriting defaults or stuff found in earlier files
   1337                     #Note that we are extracting the keybinding-string including the quotes (see Note at beginning)
   1338                     help_zle_keybindings[${k}]=$lastkeybind_desc
   1339                 fi
   1340                 lastkeybind_desc=""
   1341             else
   1342               ((num_lines_elapsed++))
   1343             fi
   1344         done
   1345     done
   1346     unset contents
   1347     #calculate length of keybinding column
   1348     local kstrlen=0
   1349     for k (${(k)help_zle_keybindings[@]}) ((kstrlen < ${#k})) && kstrlen=${#k}
   1350     #convert the assoc array into preformated lines, which we are able to sort
   1351     for k v in ${(kv)help_zle_keybindings[@]}; do
   1352         #pad keybinding-string to kstrlen chars and remove outermost characters (i.e. the quotes)
   1353         help_zle_lines+=("${(r:kstrlen:)k[2,-2]}${v}")
   1354     done
   1355     #sort lines alphabetically
   1356     help_zle_lines=("${(i)help_zle_lines[@]}")
   1357     [[ -d ${HELP_ZLE_CACHE_FILE:h} ]] || mkdir -p "${HELP_ZLE_CACHE_FILE:h}"
   1358     echo "help_zle_lines=(${(q)help_zle_lines[@]})" >| $HELP_ZLE_CACHE_FILE
   1359     zcompile $HELP_ZLE_CACHE_FILE
   1360 }
   1361 typeset -g help_zle_sln
   1362 typeset -g -a help_zle_lines
   1363 
   1364 # Provides (partially autogenerated) help on keybindings and the zsh line editor
   1365 function help-zle () {
   1366     emulate -L zsh
   1367     unsetopt ksharrays  #indexing starts at 1
   1368     #help lines already generated ? no ? then do it
   1369     [[ ${+functions[help_zle_parse_keybindings]} -eq 1 ]] && {help_zle_parse_keybindings && unfunction help_zle_parse_keybindings}
   1370     #already displayed all lines ? go back to the start
   1371     [[ $help_zle_sln -gt ${#help_zle_lines} ]] && help_zle_sln=1
   1372     local sln=$help_zle_sln
   1373     #note that help_zle_sln is a global var, meaning we remember the last page we viewed
   1374     help_zle_sln=$((help_zle_sln + HELP_LINES_PER_PAGE))
   1375     zle -M "${(F)help_zle_lines[sln,help_zle_sln-1]}"
   1376 }
   1377 zle -N help-zle
   1378 
   1379 ## complete word from currently visible Screen or Tmux buffer.
   1380 if check_com -c screen || check_com -c tmux; then
   1381     function _complete_screen_display () {
   1382         [[ "$TERM" != "screen" ]] && return 1
   1383 
   1384         local TMPFILE=$(mktemp)
   1385         local -U -a _screen_display_wordlist
   1386         trap "rm -f $TMPFILE" EXIT
   1387 
   1388         # fill array with contents from screen hardcopy
   1389         if ((${+TMUX})); then
   1390             #works, but crashes tmux below version 1.4
   1391             #luckily tmux -V option to ask for version, was also added in 1.4
   1392             tmux -V &>/dev/null || return
   1393             tmux -q capture-pane \; save-buffer -b 0 $TMPFILE \; delete-buffer -b 0
   1394         else
   1395             screen -X hardcopy $TMPFILE
   1396             # screen sucks, it dumps in latin1, apparently always. so recode it
   1397             # to system charset
   1398             check_com recode && recode latin1 $TMPFILE
   1399         fi
   1400         _screen_display_wordlist=( ${(QQ)$(<$TMPFILE)} )
   1401         # remove PREFIX to be completed from that array
   1402         _screen_display_wordlist[${_screen_display_wordlist[(i)$PREFIX]}]=""
   1403         compadd -a _screen_display_wordlist
   1404     }
   1405     #m# k CTRL-x\,\,\,S Complete word from GNU screen buffer
   1406     bindkey -r "^xS"
   1407     compdef -k _complete_screen_display complete-word '^xS'
   1408 fi
   1409 
   1410 # Load a few more functions and tie them to widgets, so they can be bound:
   1411 
   1412 function zrcautozle () {
   1413     emulate -L zsh
   1414     local fnc=$1
   1415     zrcautoload $fnc && zle -N $fnc
   1416 }
   1417 
   1418 function zrcgotwidget () {
   1419     (( ${+widgets[$1]} ))
   1420 }
   1421 
   1422 function zrcgotkeymap () {
   1423     [[ -n ${(M)keymaps:#$1} ]]
   1424 }
   1425 
   1426 zrcautozle insert-files
   1427 zrcautozle edit-command-line
   1428 zrcautozle insert-unicode-char
   1429 if zrcautoload history-search-end; then
   1430     zle -N history-beginning-search-backward-end history-search-end
   1431     zle -N history-beginning-search-forward-end  history-search-end
   1432 fi
   1433 zle -C hist-complete complete-word _generic
   1434 zstyle ':completion:hist-complete:*' completer _history
   1435 
   1436 # The actual terminal setup hooks and bindkey-calls:
   1437 
   1438 # An array to note missing features to ease diagnosis in case of problems.
   1439 typeset -ga grml_missing_features
   1440 
   1441 function zrcbindkey () {
   1442     if (( ARGC )) && zrcgotwidget ${argv[-1]}; then
   1443         bindkey "$@"
   1444     fi
   1445 }
   1446 
   1447 function bind2maps () {
   1448     local i sequence widget
   1449     local -a maps
   1450 
   1451     while [[ "$1" != "--" ]]; do
   1452         maps+=( "$1" )
   1453         shift
   1454     done
   1455     shift
   1456 
   1457     if [[ "$1" == "-s" ]]; then
   1458         shift
   1459         sequence="$1"
   1460     else
   1461         sequence="${key[$1]}"
   1462     fi
   1463     widget="$2"
   1464 
   1465     [[ -z "$sequence" ]] && return 1
   1466 
   1467     for i in "${maps[@]}"; do
   1468         zrcbindkey -M "$i" "$sequence" "$widget"
   1469     done
   1470 }
   1471 
   1472 if (( ${+terminfo[smkx]} )) && (( ${+terminfo[rmkx]} )); then
   1473     function zle-smkx () {
   1474         emulate -L zsh
   1475         printf '%s' ${terminfo[smkx]}
   1476     }
   1477     function zle-rmkx () {
   1478         emulate -L zsh
   1479         printf '%s' ${terminfo[rmkx]}
   1480     }
   1481     function zle-line-init () {
   1482         zle-smkx
   1483     }
   1484     function zle-line-finish () {
   1485         zle-rmkx
   1486     }
   1487     zle -N zle-line-init
   1488     zle -N zle-line-finish
   1489 else
   1490     for i in {s,r}mkx; do
   1491         (( ${+terminfo[$i]} )) || grml_missing_features+=($i)
   1492     done
   1493     unset i
   1494 fi
   1495 
   1496 typeset -A key
   1497 key=(
   1498     Home     "${terminfo[khome]}"
   1499     End      "${terminfo[kend]}"
   1500     Insert   "${terminfo[kich1]}"
   1501     Delete   "${terminfo[kdch1]}"
   1502     Up       "${terminfo[kcuu1]}"
   1503     Down     "${terminfo[kcud1]}"
   1504     Left     "${terminfo[kcub1]}"
   1505     Right    "${terminfo[kcuf1]}"
   1506     PageUp   "${terminfo[kpp]}"
   1507     PageDown "${terminfo[knp]}"
   1508     BackTab  "${terminfo[kcbt]}"
   1509 )
   1510 
   1511 # Guidelines for adding key bindings:
   1512 #
   1513 #   - Do not add hardcoded escape sequences, to enable non standard key
   1514 #     combinations such as Ctrl-Meta-Left-Cursor. They are not easily portable.
   1515 #
   1516 #   - Adding Ctrl characters, such as '^b' is okay; note that '^b' and '^B' are
   1517 #     the same key.
   1518 #
   1519 #   - All keys from the $key[] mapping are obviously okay.
   1520 #
   1521 #   - Most terminals send "ESC x" when Meta-x is pressed. Thus, sequences like
   1522 #     '\ex' are allowed in here as well.
   1523 
   1524 bind2maps emacs             -- Home   beginning-of-somewhere
   1525 bind2maps       viins vicmd -- Home   vi-beginning-of-line
   1526 bind2maps emacs             -- End    end-of-somewhere
   1527 bind2maps       viins vicmd -- End    vi-end-of-line
   1528 bind2maps emacs viins       -- Insert overwrite-mode
   1529 bind2maps             vicmd -- Insert vi-insert
   1530 bind2maps emacs             -- Delete delete-char
   1531 bind2maps       viins vicmd -- Delete vi-delete-char
   1532 bind2maps emacs viins vicmd -- Up     up-line-or-search
   1533 bind2maps emacs viins vicmd -- Down   down-line-or-search
   1534 bind2maps emacs             -- Left   backward-char
   1535 bind2maps       viins vicmd -- Left   vi-backward-char
   1536 bind2maps emacs             -- Right  forward-char
   1537 bind2maps       viins vicmd -- Right  vi-forward-char
   1538 #k# Perform abbreviation expansion
   1539 bind2maps emacs viins       -- -s '^x.' zleiab
   1540 #k# Display list of abbreviations that would expand
   1541 bind2maps emacs viins       -- -s '^xb' help-show-abk
   1542 #k# mkdir -p <dir> from string under cursor or marked area
   1543 bind2maps emacs viins       -- -s '^xM' inplaceMkDirs
   1544 #k# display help for keybindings and ZLE
   1545 bind2maps emacs viins       -- -s '^xz' help-zle
   1546 #k# Insert files and test globbing
   1547 bind2maps emacs viins       -- -s "^xf" insert-files
   1548 #k# Edit the current line in \kbd{\$EDITOR}
   1549 bind2maps emacs viins       -- -s '\ee' edit-command-line
   1550 #k# search history backward for entry beginning with typed text
   1551 bind2maps emacs viins       -- -s '^xp' history-beginning-search-backward-end
   1552 #k# search history forward for entry beginning with typed text
   1553 bind2maps emacs viins       -- -s '^xP' history-beginning-search-forward-end
   1554 #k# search history backward for entry beginning with typed text
   1555 bind2maps emacs viins       -- PageUp history-beginning-search-backward-end
   1556 #k# search history forward for entry beginning with typed text
   1557 bind2maps emacs viins       -- PageDown history-beginning-search-forward-end
   1558 bind2maps emacs viins       -- -s "^x^h" commit-to-history
   1559 #k# Kill left-side word or everything up to next slash
   1560 bind2maps emacs viins       -- -s '\ev' slash-backward-kill-word
   1561 #k# Kill left-side word or everything up to next slash
   1562 bind2maps emacs viins       -- -s '\e^h' slash-backward-kill-word
   1563 #k# Kill left-side word or everything up to next slash
   1564 bind2maps emacs viins       -- -s '\e^?' slash-backward-kill-word
   1565 # Do history expansion on space:
   1566 bind2maps emacs viins       -- -s ' ' magic-space
   1567 #k# Trigger menu-complete
   1568 bind2maps emacs viins       -- -s '\ei' menu-complete  # menu completion via esc-i
   1569 #k# Insert a timestamp on the command line (yyyy-mm-dd)
   1570 bind2maps emacs viins       -- -s '^xd' insert-datestamp
   1571 #k# Insert last typed word
   1572 bind2maps emacs viins       -- -s "\em" insert-last-typed-word
   1573 #k# A smart shortcut for \kbd{fg<enter>}
   1574 bind2maps emacs viins       -- -s '^z' grml-zsh-fg
   1575 #k# prepend the current command with "sudo"
   1576 bind2maps emacs viins       -- -s "^os" sudo-command-line
   1577 #k# jump to after first word (for adding options)
   1578 bind2maps emacs viins       -- -s '^x1' jump_after_first_word
   1579 #k# complete word from history with menu
   1580 bind2maps emacs viins       -- -s "^x^x" hist-complete
   1581 
   1582 # insert unicode character
   1583 # usage example: 'ctrl-x i' 00A7 'ctrl-x i' will give you an §
   1584 # See for example http://unicode.org/charts/ for unicode characters code
   1585 #k# Insert Unicode character
   1586 bind2maps emacs viins       -- -s '^xi' insert-unicode-char
   1587 
   1588 # use the new *-pattern-* widgets for incremental history search
   1589 if zrcgotwidget history-incremental-pattern-search-backward; then
   1590     for seq wid in '^r' history-incremental-pattern-search-backward \
   1591                    '^s' history-incremental-pattern-search-forward
   1592     do
   1593         bind2maps emacs viins vicmd -- -s $seq $wid
   1594     done
   1595     builtin unset -v seq wid
   1596 fi
   1597 
   1598 if zrcgotkeymap menuselect; then
   1599     #m# k Shift-tab Perform backwards menu completion
   1600     bind2maps menuselect -- BackTab reverse-menu-complete
   1601 
   1602     #k# menu selection: pick item but stay in the menu
   1603     bind2maps menuselect -- -s '\e^M' accept-and-menu-complete
   1604     # also use + and INSERT since it's easier to press repeatedly
   1605     bind2maps menuselect -- -s '+' accept-and-menu-complete
   1606     bind2maps menuselect -- Insert accept-and-menu-complete
   1607 
   1608     # accept a completion and try to complete again by using menu
   1609     # completion; very useful with completing directories
   1610     # by using 'undo' one's got a simple file browser
   1611     bind2maps menuselect -- -s '^o' accept-and-infer-next-history
   1612 fi
   1613 
   1614 # Finally, here are still a few hardcoded escape sequences; Special sequences
   1615 # like Ctrl-<Cursor-key> etc do suck a fair bit, because they are not
   1616 # standardised and most of the time are not available in a terminals terminfo
   1617 # entry.
   1618 #
   1619 # While we do not encourage adding bindings like these, we will keep these for
   1620 # backward compatibility.
   1621 
   1622 ## use Ctrl-left-arrow and Ctrl-right-arrow for jumping to word-beginnings on
   1623 ## the command line.
   1624 # URxvt sequences:
   1625 bind2maps emacs viins vicmd -- -s '\eOc' forward-word
   1626 bind2maps emacs viins vicmd -- -s '\eOd' backward-word
   1627 # These are for xterm:
   1628 bind2maps emacs viins vicmd -- -s '\e[1;5C' forward-word
   1629 bind2maps emacs viins vicmd -- -s '\e[1;5D' backward-word
   1630 ## the same for alt-left-arrow and alt-right-arrow
   1631 # URxvt again:
   1632 bind2maps emacs viins vicmd -- -s '\e\e[C' forward-word
   1633 bind2maps emacs viins vicmd -- -s '\e\e[D' backward-word
   1634 # Xterm again:
   1635 bind2maps emacs viins vicmd -- -s '^[[1;3C' forward-word
   1636 bind2maps emacs viins vicmd -- -s '^[[1;3D' backward-word
   1637 # Also try ESC Left/Right:
   1638 bind2maps emacs viins vicmd -- -s '\e'${key[Right]} forward-word
   1639 bind2maps emacs viins vicmd -- -s '\e'${key[Left]}  backward-word
   1640 
   1641 # autoloading
   1642 
   1643 zrcautoload zmv
   1644 zrcautoload zed
   1645 
   1646 # we don't want to quote/espace URLs on our own...
   1647 # if autoload -U url-quote-magic ; then
   1648 #    zle -N self-insert url-quote-magic
   1649 #    zstyle ':url-quote-magic:*' url-metas '*?[]^()~#{}='
   1650 # else
   1651 #    print 'Notice: no url-quote-magic available :('
   1652 # fi
   1653 if is51 ; then
   1654   # url-quote doesn't work without bracketed-paste-magic since Zsh 5.1
   1655   alias url-quote='autoload -U bracketed-paste-magic url-quote-magic;
   1656                    zle -N bracketed-paste bracketed-paste-magic; zle -N self-insert url-quote-magic'
   1657 else
   1658   alias url-quote='autoload -U url-quote-magic ; zle -N self-insert url-quote-magic'
   1659 fi
   1660 
   1661 #m# k ESC-h Call \kbd{run-help} for the 1st word on the command line
   1662 alias run-help >&/dev/null && unalias run-help
   1663 for rh in run-help{,-git,-ip,-openssl,-p4,-sudo,-svk,-svn}; do
   1664     zrcautoload $rh
   1665 done; unset rh
   1666 
   1667 # command not found handling
   1668 
   1669 (( ${COMMAND_NOT_FOUND} == 1 )) &&
   1670 function command_not_found_handler () {
   1671     emulate -L zsh
   1672     if [[ -x ${GRML_ZSH_CNF_HANDLER} ]] ; then
   1673         ${GRML_ZSH_CNF_HANDLER} $1
   1674     fi
   1675     return 1
   1676 }
   1677 
   1678 # history
   1679 
   1680 #v#
   1681 HISTFILE=${HISTFILE:-${ZDOTDIR:-${HOME}}/.zsh_history}
   1682 isgrmlcd && HISTSIZE=500  || HISTSIZE=5000
   1683 isgrmlcd && SAVEHIST=1000 || SAVEHIST=10000 # useful for setopt append_history
   1684 
   1685 # dirstack handling
   1686 
   1687 DIRSTACKSIZE=${DIRSTACKSIZE:-20}
   1688 DIRSTACKFILE=${DIRSTACKFILE:-${ZDOTDIR:-${HOME}}/.zdirs}
   1689 
   1690 if zstyle -T ':grml:chpwd:dirstack' enable; then
   1691     typeset -gaU GRML_PERSISTENT_DIRSTACK
   1692     function grml_dirstack_filter () {
   1693         local -a exclude
   1694         local filter entry
   1695         if zstyle -s ':grml:chpwd:dirstack' filter filter; then
   1696             $filter $1 && return 0
   1697         fi
   1698         if zstyle -a ':grml:chpwd:dirstack' exclude exclude; then
   1699             for entry in "${exclude[@]}"; do
   1700                 [[ $1 == ${~entry} ]] && return 0
   1701             done
   1702         fi
   1703         return 1
   1704     }
   1705 
   1706     function chpwd () {
   1707         (( ZSH_SUBSHELL )) && return
   1708         (( $DIRSTACKSIZE <= 0 )) && return
   1709         [[ -z $DIRSTACKFILE ]] && return
   1710         grml_dirstack_filter $PWD && return
   1711         GRML_PERSISTENT_DIRSTACK=(
   1712             $PWD "${(@)GRML_PERSISTENT_DIRSTACK[1,$DIRSTACKSIZE]}"
   1713         )
   1714         builtin print -l ${GRML_PERSISTENT_DIRSTACK} >! ${DIRSTACKFILE}
   1715     }
   1716 
   1717     if [[ -f ${DIRSTACKFILE} ]]; then
   1718         # Enabling NULL_GLOB via (N) weeds out any non-existing
   1719         # directories from the saved dir-stack file.
   1720         dirstack=( ${(f)"$(< $DIRSTACKFILE)"}(N) )
   1721         # "cd -" won't work after login by just setting $OLDPWD, so
   1722         [[ -d $dirstack[1] ]] && cd -q $dirstack[1] && cd -q $OLDPWD
   1723     fi
   1724 
   1725     if zstyle -t ':grml:chpwd:dirstack' filter-on-load; then
   1726         for i in "${dirstack[@]}"; do
   1727             if ! grml_dirstack_filter "$i"; then
   1728                 GRML_PERSISTENT_DIRSTACK=(
   1729                     "${GRML_PERSISTENT_DIRSTACK[@]}"
   1730                     $i
   1731                 )
   1732             fi
   1733         done
   1734     else
   1735         GRML_PERSISTENT_DIRSTACK=( "${dirstack[@]}" )
   1736     fi
   1737 fi
   1738 
   1739 # directory based profiles
   1740 
   1741 if is433 ; then
   1742 
   1743 # chpwd_profiles(): Directory Profiles, Quickstart:
   1744 #
   1745 # In .zshrc.local:
   1746 #
   1747 #   zstyle ':chpwd:profiles:/usr/src/grml(|/|/*)'   profile grml
   1748 #   zstyle ':chpwd:profiles:/usr/src/debian(|/|/*)' profile debian
   1749 #   chpwd_profiles
   1750 #
   1751 # For details see the `grmlzshrc.5' manual page.
   1752 function chpwd_profiles () {
   1753     local profile context
   1754     local -i reexecute
   1755 
   1756     context=":chpwd:profiles:$PWD"
   1757     zstyle -s "$context" profile profile || profile='default'
   1758     zstyle -T "$context" re-execute && reexecute=1 || reexecute=0
   1759 
   1760     if (( ${+parameters[CHPWD_PROFILE]} == 0 )); then
   1761         typeset -g CHPWD_PROFILE
   1762         local CHPWD_PROFILES_INIT=1
   1763         (( ${+functions[chpwd_profiles_init]} )) && chpwd_profiles_init
   1764     elif [[ $profile != $CHPWD_PROFILE ]]; then
   1765         (( ${+functions[chpwd_leave_profile_$CHPWD_PROFILE]} )) \
   1766             && chpwd_leave_profile_${CHPWD_PROFILE}
   1767     fi
   1768     if (( reexecute )) || [[ $profile != $CHPWD_PROFILE ]]; then
   1769         (( ${+functions[chpwd_profile_$profile]} )) && chpwd_profile_${profile}
   1770     fi
   1771 
   1772     CHPWD_PROFILE="${profile}"
   1773     return 0
   1774 }
   1775 
   1776 chpwd_functions=( ${chpwd_functions} chpwd_profiles )
   1777 
   1778 fi # is433
   1779 
   1780 # Prompt setup for grml:
   1781 
   1782 # set colors for use in prompts (modern zshs allow for the use of %F{red}foo%f
   1783 # in prompts to get a red "foo" embedded, but it's good to keep these for
   1784 # backwards compatibility).
   1785 if is437; then
   1786     BLUE="%F{blue}"
   1787     RED="%F{red}"
   1788     GREEN="%F{green}"
   1789     CYAN="%F{cyan}"
   1790     MAGENTA="%F{magenta}"
   1791     YELLOW="%F{yellow}"
   1792     WHITE="%F{white}"
   1793     NO_COLOR="%f"
   1794 elif zrcautoload colors && colors 2>/dev/null ; then
   1795     BLUE="%{${fg[blue]}%}"
   1796     RED="%{${fg_bold[red]}%}"
   1797     GREEN="%{${fg[green]}%}"
   1798     CYAN="%{${fg[cyan]}%}"
   1799     MAGENTA="%{${fg[magenta]}%}"
   1800     YELLOW="%{${fg[yellow]}%}"
   1801     WHITE="%{${fg[white]}%}"
   1802     NO_COLOR="%{${reset_color}%}"
   1803 else
   1804     BLUE=$'%{\e[1;34m%}'
   1805     RED=$'%{\e[1;31m%}'
   1806     GREEN=$'%{\e[1;32m%}'
   1807     CYAN=$'%{\e[1;36m%}'
   1808     WHITE=$'%{\e[1;37m%}'
   1809     MAGENTA=$'%{\e[1;35m%}'
   1810     YELLOW=$'%{\e[1;33m%}'
   1811     NO_COLOR=$'%{\e[0m%}'
   1812 fi
   1813 
   1814 # First, the easy ones: PS2..4:
   1815 
   1816 # secondary prompt, printed when the shell needs more information to complete a
   1817 # command.
   1818 PS2='\`%_> '
   1819 # selection prompt used within a select loop.
   1820 PS3='?# '
   1821 # the execution trace prompt (setopt xtrace). default: '+%N:%i>'
   1822 PS4='+%N:%i:%_> '
   1823 
   1824 # Some additional features to use with our prompt:
   1825 #
   1826 #    - battery status
   1827 #    - debian_chroot
   1828 #    - vcs_info setup and version specific fixes
   1829 
   1830 # display battery status on right side of prompt using 'GRML_DISPLAY_BATTERY=1' in .zshrc.pre
   1831 
   1832 function battery () {
   1833 if [[ $GRML_DISPLAY_BATTERY -gt 0 ]] ; then
   1834     if islinux ; then
   1835         batterylinux
   1836     elif isopenbsd ; then
   1837         batteryopenbsd
   1838     elif isfreebsd ; then
   1839         batteryfreebsd
   1840     elif isdarwin ; then
   1841         batterydarwin
   1842     else
   1843         #not yet supported
   1844         GRML_DISPLAY_BATTERY=0
   1845     fi
   1846 fi
   1847 }
   1848 
   1849 function batterylinux () {
   1850 GRML_BATTERY_LEVEL=''
   1851 local batteries bat capacity
   1852 batteries=( /sys/class/power_supply/BAT*(N) )
   1853 if (( $#batteries > 0 )) ; then
   1854     for bat in $batteries ; do
   1855         if [[ -e $bat/capacity ]]; then
   1856             capacity=$(< $bat/capacity)
   1857         else
   1858             typeset -F energy_full=$(< $bat/energy_full)
   1859             typeset -F energy_now=$(< $bat/energy_now)
   1860             typeset -i capacity=$(( 100 * $energy_now / $energy_full))
   1861         fi
   1862         case $(< $bat/status) in
   1863         Charging)
   1864             GRML_BATTERY_LEVEL+=" ^"
   1865             ;;
   1866         Discharging)
   1867             if (( capacity < 20 )) ; then
   1868                 GRML_BATTERY_LEVEL+=" !v"
   1869             else
   1870                 GRML_BATTERY_LEVEL+=" v"
   1871             fi
   1872             ;;
   1873         *) # Full, Unknown
   1874             GRML_BATTERY_LEVEL+=" ="
   1875             ;;
   1876         esac
   1877         GRML_BATTERY_LEVEL+="${capacity}%%"
   1878     done
   1879 fi
   1880 }
   1881 
   1882 function batteryopenbsd () {
   1883 GRML_BATTERY_LEVEL=''
   1884 local bat batfull batwarn batnow num
   1885 for num in 0 1 ; do
   1886     bat=$(sysctl -n hw.sensors.acpibat${num} 2>/dev/null)
   1887     if [[ -n $bat ]]; then
   1888         batfull=${"$(sysctl -n hw.sensors.acpibat${num}.amphour0)"%% *}
   1889         batwarn=${"$(sysctl -n hw.sensors.acpibat${num}.amphour1)"%% *}
   1890         batnow=${"$(sysctl -n hw.sensors.acpibat${num}.amphour3)"%% *}
   1891         case "$(sysctl -n hw.sensors.acpibat${num}.raw0)" in
   1892             *" discharging"*)
   1893                 if (( batnow < batwarn )) ; then
   1894                     GRML_BATTERY_LEVEL+=" !v"
   1895                 else
   1896                     GRML_BATTERY_LEVEL+=" v"
   1897                 fi
   1898                 ;;
   1899             *" charging"*)
   1900                 GRML_BATTERY_LEVEL+=" ^"
   1901                 ;;
   1902             *)
   1903                 GRML_BATTERY_LEVEL+=" ="
   1904                 ;;
   1905         esac
   1906         GRML_BATTERY_LEVEL+="${$(( 100 * batnow / batfull ))%%.*}%%"
   1907     fi
   1908 done
   1909 }
   1910 
   1911 function batteryfreebsd () {
   1912 GRML_BATTERY_LEVEL=''
   1913 local num
   1914 local -A table
   1915 for num in 0 1 ; do
   1916     table=( ${=${${${${${(M)${(f)"$(acpiconf -i $num 2>&1)"}:#(State|Remaining capacity):*}%%( ##|%)}//:[ $'\t']##/@}// /-}//@/ }} )
   1917     if [[ -n $table ]] && [[ $table[State] != "not-present" ]] ; then
   1918         case $table[State] in
   1919             *discharging*)
   1920                 if (( $table[Remaining-capacity] < 20 )) ; then
   1921                     GRML_BATTERY_LEVEL+=" !v"
   1922                 else
   1923                     GRML_BATTERY_LEVEL+=" v"
   1924                 fi
   1925                 ;;
   1926             *charging*)
   1927                 GRML_BATTERY_LEVEL+=" ^"
   1928                 ;;
   1929             *)
   1930                 GRML_BATTERY_LEVEL+=" ="
   1931                 ;;
   1932         esac
   1933         GRML_BATTERY_LEVEL+="$table[Remaining-capacity]%%"
   1934     fi
   1935 done
   1936 }
   1937 
   1938 function batterydarwin () {
   1939 GRML_BATTERY_LEVEL=''
   1940 local -a table
   1941 table=( ${$(pmset -g ps)[(w)8,9]%%(\%|);} )
   1942 if [[ -n $table[2] ]] ; then
   1943     case $table[2] in
   1944         charging)
   1945             GRML_BATTERY_LEVEL+=" ^"
   1946             ;;
   1947         discharging)
   1948             if (( $table[1] < 20 )) ; then
   1949                 GRML_BATTERY_LEVEL+=" !v"
   1950             else
   1951                 GRML_BATTERY_LEVEL+=" v"
   1952             fi
   1953             ;;
   1954         *)
   1955             GRML_BATTERY_LEVEL+=" ="
   1956             ;;
   1957     esac
   1958     GRML_BATTERY_LEVEL+="$table[1]%%"
   1959 fi
   1960 }
   1961 
   1962 # set variable debian_chroot if running in a chroot with /etc/debian_chroot
   1963 if [[ -z "$debian_chroot" ]] && [[ -r /etc/debian_chroot ]] ; then
   1964     debian_chroot=$(</etc/debian_chroot)
   1965 fi
   1966 
   1967 # gather version control information for inclusion in a prompt
   1968 
   1969 if zrcautoload vcs_info; then
   1970     # `vcs_info' in zsh versions 4.3.10 and below have a broken `_realpath'
   1971     # function, which can cause a lot of trouble with our directory-based
   1972     # profiles. So:
   1973     if [[ ${ZSH_VERSION} == 4.3.<-10> ]] ; then
   1974         function VCS_INFO_realpath () {
   1975             setopt localoptions NO_shwordsplit chaselinks
   1976             ( builtin cd -q $1 2> /dev/null && pwd; )
   1977         }
   1978     fi
   1979 
   1980     zstyle ':vcs_info:*' max-exports 2
   1981 
   1982     if [[ -o restricted ]]; then
   1983         zstyle ':vcs_info:*' enable NONE
   1984     fi
   1985 fi
   1986 
   1987 typeset -A grml_vcs_coloured_formats
   1988 typeset -A grml_vcs_plain_formats
   1989 
   1990 grml_vcs_plain_formats=(
   1991     format "(%s%)-[%b] "    "zsh: %r"
   1992     actionformat "(%s%)-[%b|%a] " "zsh: %r"
   1993     rev-branchformat "%b:%r"
   1994 )
   1995 
   1996 grml_vcs_coloured_formats=(
   1997     format "${MAGENTA}(${NO_COLOR}%s${MAGENTA})${YELLOW}-${MAGENTA}[${GREEN}%b${MAGENTA}]${NO_COLOR} "
   1998     actionformat "${MAGENTA}(${NO_COLOR}%s${MAGENTA})${YELLOW}-${MAGENTA}[${GREEN}%b${YELLOW}|${RED}%a${MAGENTA}]${NO_COLOR} "
   1999     rev-branchformat "%b${RED}:${YELLOW}%r"
   2000 )
   2001 
   2002 typeset GRML_VCS_COLOUR_MODE=xxx
   2003 
   2004 function grml_vcs_info_toggle_colour () {
   2005     emulate -L zsh
   2006     if [[ $GRML_VCS_COLOUR_MODE == plain ]]; then
   2007         grml_vcs_info_set_formats coloured
   2008     else
   2009         grml_vcs_info_set_formats plain
   2010     fi
   2011     return 0
   2012 }
   2013 
   2014 function grml_vcs_info_set_formats () {
   2015     emulate -L zsh
   2016     #setopt localoptions xtrace
   2017     local mode=$1 AF F BF
   2018     if [[ $mode == coloured ]]; then
   2019         AF=${grml_vcs_coloured_formats[actionformat]}
   2020         F=${grml_vcs_coloured_formats[format]}
   2021         BF=${grml_vcs_coloured_formats[rev-branchformat]}
   2022         GRML_VCS_COLOUR_MODE=coloured
   2023     else
   2024         AF=${grml_vcs_plain_formats[actionformat]}
   2025         F=${grml_vcs_plain_formats[format]}
   2026         BF=${grml_vcs_plain_formats[rev-branchformat]}
   2027         GRML_VCS_COLOUR_MODE=plain
   2028     fi
   2029 
   2030     zstyle ':vcs_info:*'              actionformats "$AF" "zsh: %r"
   2031     zstyle ':vcs_info:*'              formats       "$F"  "zsh: %r"
   2032     zstyle ':vcs_info:(sv[nk]|bzr):*' branchformat  "$BF"
   2033     return 0
   2034 }
   2035 
   2036 # Change vcs_info formats for the grml prompt. The 2nd format sets up
   2037 # $vcs_info_msg_1_ to contain "zsh: repo-name" used to set our screen title.
   2038 if [[ "$TERM" == dumb ]] ; then
   2039     grml_vcs_info_set_formats plain
   2040 else
   2041     grml_vcs_info_set_formats coloured
   2042 fi
   2043 
   2044 # Now for the fun part: The grml prompt themes in `promptsys' mode of operation
   2045 
   2046 # This actually defines three prompts:
   2047 #
   2048 #    - grml
   2049 #    - grml-large
   2050 #    - grml-chroot
   2051 #
   2052 # They all share the same code and only differ with respect to which items they
   2053 # contain. The main source of documentation is the `prompt_grml_help' function
   2054 # below, which gets called when the user does this: prompt -h grml
   2055 
   2056 function prompt_grml_help () {
   2057     <<__EOF0__
   2058   prompt grml
   2059 
   2060     This is the prompt as used by the grml-live system <http://grml.org>. It is
   2061     a rather simple one-line prompt, that by default looks something like this:
   2062 
   2063         <user>@<host> <current-working-directory>[ <vcs_info-data>]%
   2064 
   2065     The prompt itself integrates with zsh's prompt themes system (as you are
   2066     witnessing right now) and is configurable to a certain degree. In
   2067     particular, these aspects are customisable:
   2068 
   2069         - The items used in the prompt (e.g. you can remove \`user' from
   2070           the list of activated items, which will cause the user name to
   2071           be omitted from the prompt string).
   2072 
   2073         - The attributes used with the items are customisable via strings
   2074           used before and after the actual item.
   2075 
   2076     The available items are: at, battery, change-root, date, grml-chroot,
   2077     history, host, jobs, newline, path, percent, rc, rc-always, sad-smiley,
   2078     shell-level, time, user, vcs
   2079 
   2080     The actual configuration is done via zsh's \`zstyle' mechanism. The
   2081     context, that is used while looking up styles is:
   2082 
   2083         ':prompt:grml:<left-or-right>:<subcontext>'
   2084 
   2085     Here <left-or-right> is either \`left' or \`right', signifying whether the
   2086     style should affect the left or the right prompt. <subcontext> is either
   2087     \`setup' or 'items:<item>', where \`<item>' is one of the available items.
   2088 
   2089     The styles:
   2090 
   2091         - use-rprompt (boolean): If \`true' (the default), print a sad smiley
   2092           in $RPROMPT if the last command a returned non-successful error code.
   2093           (This in only valid if <left-or-right> is "right"; ignored otherwise)
   2094 
   2095         - items (list): The list of items used in the prompt. If \`vcs' is
   2096           present in the list, the theme's code invokes \`vcs_info'
   2097           accordingly. Default (left): rc change-root user at host path vcs
   2098           percent; Default (right): sad-smiley
   2099 
   2100         - strip-sensitive-characters (boolean): If the \`prompt_subst' option
   2101           is active in zsh, the shell performs lots of expansions on prompt
   2102           variable strings, including command substitution. So if you don't
   2103           control where some of your prompt strings is coming from, this is
   2104           an exploitable weakness. Grml's zsh setup does not set this option
   2105           and it is off in the shell in zsh-mode by default. If it *is* turned
   2106           on however, this style becomes active, and there are two flavours of
   2107           it: On per default is a global variant in the '*:setup' context. This
   2108           strips characters after the whole prompt string was constructed. There
   2109           is a second variant in the '*:items:<item>', that is off by default.
   2110           It allows fine grained control over which items' data is stripped.
   2111           The characters that are stripped are: \$ and \`.
   2112 
   2113     Available styles in 'items:<item>' are: pre, post. These are strings that
   2114     are inserted before (pre) and after (post) the item in question. Thus, the
   2115     following would cause the user name to be printed in red instead of the
   2116     default blue:
   2117 
   2118         zstyle ':prompt:grml:*:items:user' pre '%F{red}'
   2119 
   2120     Note, that the \`post' style may remain at its default value, because its
   2121     default value is '%f', which turns the foreground text attribute off (which
   2122     is exactly, what is still required with the new \`pre' value).
   2123 __EOF0__
   2124 }
   2125 
   2126 function prompt_grml-chroot_help () {
   2127     <<__EOF0__
   2128   prompt grml-chroot
   2129 
   2130     This is a variation of the grml prompt, see: prompt -h grml
   2131 
   2132     The main difference is the default value of the \`items' style. The rest
   2133     behaves exactly the same. Here are the defaults for \`grml-chroot':
   2134 
   2135         - left: grml-chroot user at host path percent
   2136         - right: (empty list)
   2137 __EOF0__
   2138 }
   2139 
   2140 function prompt_grml-large_help () {
   2141     <<__EOF0__
   2142   prompt grml-large
   2143 
   2144     This is a variation of the grml prompt, see: prompt -h grml
   2145 
   2146     The main difference is the default value of the \`items' style. In
   2147     particular, this theme uses _two_ lines instead of one with the plain
   2148     \`grml' theme. The rest behaves exactly the same. Here are the defaults
   2149     for \`grml-large':
   2150 
   2151         - left: rc jobs history shell-level change-root time date newline user
   2152                 at host path vcs percent
   2153         - right: sad-smiley
   2154 __EOF0__
   2155 }
   2156 
   2157 function grml_prompt_setup () {
   2158     emulate -L zsh
   2159     autoload -Uz vcs_info
   2160     # The following autoload is disabled for now, since this setup includes a
   2161     # static version of the ‘add-zsh-hook’ function above. It needs to be
   2162     # re-enabled as soon as that static definition is removed again.
   2163     #autoload -Uz add-zsh-hook
   2164     add-zsh-hook precmd prompt_$1_precmd
   2165 }
   2166 
   2167 function prompt_grml_setup () {
   2168     grml_prompt_setup grml
   2169 }
   2170 
   2171 function prompt_grml-chroot_setup () {
   2172     grml_prompt_setup grml-chroot
   2173 }
   2174 
   2175 function prompt_grml-large_setup () {
   2176     grml_prompt_setup grml-large
   2177 }
   2178 
   2179 # These maps define default tokens and pre-/post-decoration for items to be
   2180 # used within the themes. All defaults may be customised in a context sensitive
   2181 # matter by using zsh's `zstyle' mechanism.
   2182 typeset -gA grml_prompt_pre_default \
   2183             grml_prompt_post_default \
   2184             grml_prompt_token_default \
   2185             grml_prompt_token_function
   2186 
   2187 grml_prompt_pre_default=(
   2188     at                ''
   2189     battery           ' '
   2190     change-root       ''
   2191     date              '%F{blue}'
   2192     grml-chroot       '%F{red}'
   2193     history           '%F{green}'
   2194     host              ''
   2195     jobs              '%F{cyan}'
   2196     newline           ''
   2197     path              '%B'
   2198     percent           ''
   2199     rc                '%B%F{red}'
   2200     rc-always         ''
   2201     sad-smiley        ''
   2202     shell-level       '%F{red}'
   2203     time              '%F{blue}'
   2204     user              '%B%F{blue}'
   2205     vcs               ''
   2206 )
   2207 
   2208 grml_prompt_post_default=(
   2209     at                ''
   2210     battery           ''
   2211     change-root       ''
   2212     date              '%f'
   2213     grml-chroot       '%f '
   2214     history           '%f'
   2215     host              ''
   2216     jobs              '%f'
   2217     newline           ''
   2218     path              '%b'
   2219     percent           ''
   2220     rc                '%f%b'
   2221     rc-always         ''
   2222     sad-smiley        ''
   2223     shell-level       '%f'
   2224     time              '%f'
   2225     user              '%f%b'
   2226     vcs               ''
   2227 )
   2228 
   2229 grml_prompt_token_default=(
   2230     at                '@'
   2231     battery           'GRML_BATTERY_LEVEL'
   2232     change-root       'debian_chroot'
   2233     date              '%D{%Y-%m-%d}'
   2234     grml-chroot       'GRML_CHROOT'
   2235     history           '{history#%!} '
   2236     host              '%m '
   2237     jobs              '[%j running job(s)] '
   2238     newline           $'\n'
   2239     path              '%40<..<%~%<< '
   2240     percent           '%# '
   2241     rc                '%(?..%? )'
   2242     rc-always         '%?'
   2243     sad-smiley        '%(?..:()'
   2244     shell-level       '%(3L.+ .)'
   2245     time              '%D{%H:%M:%S} '
   2246     user              '%n'
   2247     vcs               '0'
   2248 )
   2249 
   2250 function grml_theme_has_token () {
   2251     if (( ARGC != 1 )); then
   2252         printf 'usage: grml_theme_has_token <name>\n'
   2253         return 1
   2254     fi
   2255     (( ${+grml_prompt_token_default[$1]} ))
   2256 }
   2257 
   2258 function GRML_theme_add_token_usage () {
   2259     <<__EOF0__
   2260   Usage: grml_theme_add_token <name> [-f|-i] <token/function> [<pre> <post>]
   2261 
   2262     <name> is the name for the newly added token. If the \`-f' or \`-i' options
   2263     are used, <token/function> is the name of the function (see below for
   2264     details). Otherwise it is the literal token string to be used. <pre> and
   2265     <post> are optional.
   2266 
   2267   Options:
   2268 
   2269     -f <function>   Use a function named \`<function>' each time the token
   2270                     is to be expanded.
   2271 
   2272     -i <function>   Use a function named \`<function>' to initialise the
   2273                     value of the token _once_ at runtime.
   2274 
   2275     The functions are called with one argument: the token's new name. The
   2276     return value is expected in the \$REPLY parameter. The use of these
   2277     options is mutually exclusive.
   2278 
   2279     There is a utility function \`grml_theme_has_token', which you can use
   2280     to test if a token exists before trying to add it. This can be a guard
   2281     for situations in which a \`grml_theme_add_token' call may happen more
   2282     than once.
   2283 
   2284   Example:
   2285 
   2286     To add a new token \`day' that expands to the current weekday in the
   2287     current locale in green foreground colour, use this:
   2288 
   2289       grml_theme_add_token day '%D{%A}' '%F{green}' '%f'
   2290 
   2291     Another example would be support for \$VIRTUAL_ENV:
   2292 
   2293       function virtual_env_prompt () {
   2294         REPLY=\${VIRTUAL_ENV+\${VIRTUAL_ENV:t} }
   2295       }
   2296       grml_theme_add_token virtual-env -f virtual_env_prompt
   2297 
   2298     After that, you will be able to use a changed \`items' style to
   2299     assemble your prompt.
   2300 __EOF0__
   2301 }
   2302 
   2303 function grml_theme_add_token () {
   2304     emulate -L zsh
   2305     local name token pre post
   2306     local -i init funcall
   2307 
   2308     if (( ARGC == 0 )); then
   2309         GRML_theme_add_token_usage
   2310         return 0
   2311     fi
   2312 
   2313     init=0
   2314     funcall=0
   2315     pre=''
   2316     post=''
   2317     name=$1
   2318     shift
   2319     if [[ $1 == '-f' ]]; then
   2320         funcall=1
   2321         shift
   2322     elif [[ $1 == '-i' ]]; then
   2323         init=1
   2324         shift
   2325     fi
   2326 
   2327     if (( ARGC == 0 )); then
   2328         printf '
   2329 grml_theme_add_token: No token-string/function-name provided!\n\n'
   2330         GRML_theme_add_token_usage
   2331         return 1
   2332     fi
   2333     token=$1
   2334     shift
   2335     if (( ARGC != 0 && ARGC != 2 )); then
   2336         printf '
   2337 grml_theme_add_token: <pre> and <post> need to by specified _both_!\n\n'
   2338         GRML_theme_add_token_usage
   2339         return 1
   2340     fi
   2341     if (( ARGC )); then
   2342         pre=$1
   2343         post=$2
   2344         shift 2
   2345     fi
   2346 
   2347     if grml_theme_has_token $name; then
   2348         printf '
   2349 grml_theme_add_token: Token `%s'\'' exists! Giving up!\n\n' $name
   2350         GRML_theme_add_token_usage
   2351         return 2
   2352     fi
   2353     if (( init )); then
   2354         REPLY=''
   2355         $token $name
   2356         token=$REPLY
   2357     fi
   2358     grml_prompt_pre_default[$name]=$pre
   2359     grml_prompt_post_default[$name]=$post
   2360     if (( funcall )); then
   2361         grml_prompt_token_function[$name]=$token
   2362         grml_prompt_token_default[$name]=23
   2363     else
   2364         grml_prompt_token_default[$name]=$token
   2365     fi
   2366 }
   2367 
   2368 function grml_wrap_reply () {
   2369     emulate -L zsh
   2370     local target="$1"
   2371     local new="$2"
   2372     local left="$3"
   2373     local right="$4"
   2374 
   2375     if (( ${+parameters[$new]} )); then
   2376         REPLY="${left}${(P)new}${right}"
   2377     else
   2378         REPLY=''
   2379     fi
   2380 }
   2381 
   2382 function grml_prompt_addto () {
   2383     emulate -L zsh
   2384     local target="$1"
   2385     local lr it apre apost new v REPLY
   2386     local -a items
   2387     shift
   2388 
   2389     [[ $target == PS1 ]] && lr=left || lr=right
   2390     zstyle -a ":prompt:${grmltheme}:${lr}:setup" items items || items=( "$@" )
   2391     typeset -g "${target}="
   2392     for it in "${items[@]}"; do
   2393         zstyle -s ":prompt:${grmltheme}:${lr}:items:$it" pre apre \
   2394             || apre=${grml_prompt_pre_default[$it]}
   2395         zstyle -s ":prompt:${grmltheme}:${lr}:items:$it" post apost \
   2396             || apost=${grml_prompt_post_default[$it]}
   2397         zstyle -s ":prompt:${grmltheme}:${lr}:items:$it" token new \
   2398             || new=${grml_prompt_token_default[$it]}
   2399         if (( ${+grml_prompt_token_function[$it]} )); then
   2400             REPLY=''
   2401             ${grml_prompt_token_function[$it]} $it
   2402         else
   2403             case $it in
   2404             battery)
   2405                 grml_wrap_reply $target $new '' ''
   2406                 ;;
   2407             change-root)
   2408                 grml_wrap_reply $target $new '(' ')'
   2409                 ;;
   2410             grml-chroot)
   2411                 if [[ -n ${(P)new} ]]; then
   2412                     REPLY="$CHROOT"
   2413                 else
   2414                     REPLY=''
   2415                 fi
   2416                 ;;
   2417             vcs)
   2418                 v="vcs_info_msg_${new}_"
   2419                 if (( ! vcscalled )); then
   2420                     vcs_info
   2421                     vcscalled=1
   2422                 fi
   2423                 if (( ${+parameters[$v]} )) && [[ -n "${(P)v}" ]]; then
   2424                     REPLY="${(P)v}"
   2425                 else
   2426                     REPLY=''
   2427                 fi
   2428                 ;;
   2429             *) REPLY="$new" ;;
   2430             esac
   2431         fi
   2432         # Strip volatile characters per item. This is off by default. See the
   2433         # global stripping code a few lines below for details.
   2434         if [[ -o prompt_subst ]] && zstyle -t ":prompt:${grmltheme}:${lr}:items:$it" \
   2435                                            strip-sensitive-characters
   2436         then
   2437             REPLY="${REPLY//[$\`]/}"
   2438         fi
   2439         typeset -g "${target}=${(P)target}${apre}${REPLY}${apost}"
   2440     done
   2441 
   2442     # Per default, strip volatile characters (in the prompt_subst case)
   2443     # globally. If the option is off, the style has no effect. For more
   2444     # control, this can be turned off and stripping can be configured on a
   2445     # per-item basis (see above).
   2446     if [[ -o prompt_subst ]] && zstyle -T ":prompt:${grmltheme}:${lr}:setup" \
   2447                                        strip-sensitive-characters
   2448     then
   2449         typeset -g "${target}=${${(P)target}//[$\`]/}"
   2450     fi
   2451 }
   2452 
   2453 function prompt_grml_precmd () {
   2454     emulate -L zsh
   2455     local grmltheme=grml
   2456     local -a left_items right_items
   2457     left_items=(rc change-root user at host path vcs percent)
   2458     right_items=(sad-smiley)
   2459 
   2460     prompt_grml_precmd_worker
   2461 }
   2462 
   2463 function prompt_grml-chroot_precmd () {
   2464     emulate -L zsh
   2465     local grmltheme=grml-chroot
   2466     local -a left_items right_items
   2467     left_items=(grml-chroot user at host path percent)
   2468     right_items=()
   2469 
   2470     prompt_grml_precmd_worker
   2471 }
   2472 
   2473 function prompt_grml-large_precmd () {
   2474     emulate -L zsh
   2475     local grmltheme=grml-large
   2476     local -a left_items right_items
   2477     left_items=(rc jobs history shell-level change-root time date newline
   2478                 user at host path vcs percent)
   2479     right_items=(sad-smiley)
   2480 
   2481     prompt_grml_precmd_worker
   2482 }
   2483 
   2484 function prompt_grml_precmd_worker () {
   2485     emulate -L zsh
   2486     local -i vcscalled=0
   2487 
   2488     grml_prompt_addto PS1 "${left_items[@]}"
   2489     if zstyle -T ":prompt:${grmltheme}:right:setup" use-rprompt; then
   2490         grml_prompt_addto RPS1 "${right_items[@]}"
   2491     fi
   2492 }
   2493 
   2494 function grml_prompt_fallback () {
   2495     setopt prompt_subst
   2496     local p0 p1
   2497 
   2498     p0="${RED}%(?..%? )${WHITE}${debian_chroot:+($debian_chroot)}"
   2499     p1="${BLUE}%n${NO_COLOR}@%m %40<...<%B%~%b%<< "'${vcs_info_msg_0_}'"%# "
   2500     if (( EUID == 0 )); then
   2501         PROMPT="${BLUE}${p0}${RED}${p1}"
   2502     else
   2503         PROMPT="${RED}${p0}${BLUE}${p1}"
   2504     fi
   2505 }
   2506 
   2507 if zrcautoload promptinit && promptinit 2>/dev/null ; then
   2508     grml_status_feature promptinit 0
   2509     # Since we define the required functions in here and not in files in
   2510     # $fpath, we need to stick the theme's name into `$prompt_themes'
   2511     # ourselves, since promptinit does not pick them up otherwise.
   2512     prompt_themes+=( grml grml-chroot grml-large )
   2513     # Also, keep the array sorted...
   2514     prompt_themes=( "${(@on)prompt_themes}" )
   2515 else
   2516     grml_status_feature promptinit 1
   2517     grml_prompt_fallback
   2518     function precmd () { (( ${+functions[vcs_info]} )) && vcs_info; }
   2519 fi
   2520 
   2521 if is437; then
   2522     # The prompt themes use modern features of zsh, that require at least
   2523     # version 4.3.7 of the shell. Use the fallback otherwise.
   2524     if [[ $GRML_DISPLAY_BATTERY -gt 0 ]]; then
   2525         zstyle ':prompt:grml:right:setup' items sad-smiley battery
   2526         add-zsh-hook precmd battery
   2527     fi
   2528     if [[ "$TERM" == dumb ]] ; then
   2529         zstyle ":prompt:grml(|-large|-chroot):*:items:grml-chroot" pre ''
   2530         zstyle ":prompt:grml(|-large|-chroot):*:items:grml-chroot" post ' '
   2531         for i in rc user path jobs history date time shell-level; do
   2532             zstyle ":prompt:grml(|-large|-chroot):*:items:$i" pre ''
   2533             zstyle ":prompt:grml(|-large|-chroot):*:items:$i" post ''
   2534         done
   2535         unset i
   2536         zstyle ':prompt:grml(|-large|-chroot):right:setup' use-rprompt false
   2537     elif (( EUID == 0 )); then
   2538         zstyle ':prompt:grml(|-large|-chroot):*:items:user' pre '%B%F{red}'
   2539     fi
   2540 
   2541     # Finally enable one of the prompts.
   2542     if [[ -n $GRML_CHROOT ]]; then
   2543         prompt grml-chroot
   2544     elif [[ $GRMLPROMPT -gt 0 ]]; then
   2545         prompt grml-large
   2546     else
   2547         prompt grml
   2548     fi
   2549 else
   2550     grml_prompt_fallback
   2551     function precmd () { (( ${+functions[vcs_info]} )) && vcs_info; }
   2552 fi
   2553 
   2554 # make sure to use right prompt only when not running a command
   2555 is41 && setopt transient_rprompt
   2556 
   2557 # Terminal-title wizardry
   2558 
   2559 function ESC_print () {
   2560     info_print $'\ek' $'\e\\' "$@"
   2561 }
   2562 function set_title () {
   2563     info_print  $'\e]0;' $'\a' "$@"
   2564 }
   2565 
   2566 function info_print () {
   2567     local esc_begin esc_end
   2568     esc_begin="$1"
   2569     esc_end="$2"
   2570     shift 2
   2571     printf '%s' ${esc_begin}
   2572     printf '%s' "$*"
   2573     printf '%s' "${esc_end}"
   2574 }
   2575 
   2576 function grml_reset_screen_title () {
   2577     # adjust title of xterm
   2578     # see http://www.faqs.org/docs/Linux-mini/Xterm-Title.html
   2579     [[ ${NOTITLE:-} -gt 0 ]] && return 0
   2580     case $TERM in
   2581         (xterm*|rxvt*|alacritty)
   2582             set_title ${(%):-"%n@%m: %~"}
   2583             ;;
   2584     esac
   2585 }
   2586 
   2587 function grml_vcs_to_screen_title () {
   2588     if [[ $TERM == screen* ]] ; then
   2589         if [[ -n ${vcs_info_msg_1_} ]] ; then
   2590             ESC_print ${vcs_info_msg_1_}
   2591         else
   2592             ESC_print "zsh"
   2593         fi
   2594     fi
   2595 }
   2596 
   2597 function grml_maintain_name () {
   2598     local localname
   2599     localname="$(uname -n)"
   2600 
   2601     # set hostname if not running on local machine
   2602     if [[ -n "$HOSTNAME" ]] && [[ "$HOSTNAME" != "${localname}" ]] ; then
   2603        NAME="@$HOSTNAME"
   2604     fi
   2605 }
   2606 
   2607 function grml_cmd_to_screen_title () {
   2608     # get the name of the program currently running and hostname of local
   2609     # machine set screen window title if running in a screen
   2610     if [[ "$TERM" == screen* ]] ; then
   2611         local CMD="${1[(wr)^(*=*|sudo|ssh|-*)]}$NAME"
   2612         ESC_print ${CMD}
   2613     fi
   2614 }
   2615 
   2616 function grml_control_xterm_title () {
   2617     case $TERM in
   2618         (xterm*|rxvt*|alacritty)
   2619             set_title "${(%):-"%n@%m:"}" "$2"
   2620             ;;
   2621     esac
   2622 }
   2623 
   2624 # The following autoload is disabled for now, since this setup includes a
   2625 # static version of the ‘add-zsh-hook’ function above. It needs to be
   2626 # re-enabled as soon as that static definition is removed again.
   2627 #zrcautoload add-zsh-hook || add-zsh-hook () { :; }
   2628 if [[ $NOPRECMD -eq 0 ]]; then
   2629     add-zsh-hook precmd grml_reset_screen_title
   2630     add-zsh-hook precmd grml_vcs_to_screen_title
   2631     add-zsh-hook preexec grml_maintain_name
   2632     add-zsh-hook preexec grml_cmd_to_screen_title
   2633     if [[ $NOTITLE -eq 0 ]]; then
   2634         add-zsh-hook preexec grml_control_xterm_title
   2635     fi
   2636 fi
   2637 
   2638 # 'hash' some often used directories
   2639 #d# start
   2640 hash -d deb=/var/cache/apt/archives
   2641 hash -d doc=/usr/share/doc
   2642 hash -d linux=/lib/modules/$(command uname -r)/build/
   2643 hash -d log=/var/log
   2644 hash -d slog=/var/log/syslog
   2645 hash -d src=/usr/src
   2646 hash -d www=/var/www
   2647 #d# end
   2648 
   2649 # some aliases
   2650 if check_com -c screen ; then
   2651     if [[ $UID -eq 0 ]] ; then
   2652         if [[ -r /etc/grml/screenrc ]]; then
   2653             alias screen='screen -c /etc/grml/screenrc'
   2654         fi
   2655     elif [[ ! -r $HOME/.screenrc ]] ; then
   2656         if [[ -r /etc/grml/screenrc_grml ]]; then
   2657             alias screen='screen -c /etc/grml/screenrc_grml'
   2658         else
   2659             if [[ -r /etc/grml/screenrc ]]; then
   2660                 alias screen='screen -c /etc/grml/screenrc'
   2661             fi
   2662         fi
   2663     fi
   2664 fi
   2665 
   2666 # do we have GNU ls with color-support?
   2667 if [[ "$TERM" != dumb ]]; then
   2668     #a1# List files with colors (\kbd{ls \ldots})
   2669     alias ls="command ls ${ls_options:+${ls_options[*]}}"
   2670     #a1# List all files, with colors (\kbd{ls -la \ldots})
   2671     alias la="command ls -la ${ls_options:+${ls_options[*]}}"
   2672     #a1# List files with long colored list, without dotfiles (\kbd{ls -l \ldots})
   2673     alias ll="command ls -l ${ls_options:+${ls_options[*]}}"
   2674     #a1# List files with long colored list, human readable sizes (\kbd{ls -hAl \ldots})
   2675     alias lh="command ls -hAl ${ls_options:+${ls_options[*]}}"
   2676     #a1# List files with long colored list, append qualifier to filenames (\kbd{ls -l \ldots})\\&\quad(\kbd{/} for directories, \kbd{@} for symlinks ...)
   2677     alias l="command ls -l ${ls_options:+${ls_options[*]}}"
   2678 else
   2679     alias la='command ls -la'
   2680     alias ll='command ls -l'
   2681     alias lh='command ls -hAl'
   2682     alias l='command ls -l'
   2683 fi
   2684 
   2685 if [[ -r /proc/mdstat ]]; then
   2686     alias mdstat='cat /proc/mdstat'
   2687 fi
   2688 
   2689 alias ...='cd ../../'
   2690 
   2691 # generate alias named "$KERNELVERSION-reboot" so you can use boot with kexec:
   2692 if [[ -x /sbin/kexec ]] && [[ -r /proc/cmdline ]] ; then
   2693     alias "$(uname -r)-reboot"="kexec -l --initrd=/boot/initrd.img-"$(uname -r)" --command-line=\"$(cat /proc/cmdline)\" /boot/vmlinuz-"$(uname -r)""
   2694 fi
   2695 
   2696 # see http://www.cl.cam.ac.uk/~mgk25/unicode.html#term for details
   2697 alias term2iso="echo 'Setting terminal to iso mode' ; print -n '\e%@'"
   2698 alias term2utf="echo 'Setting terminal to utf-8 mode'; print -n '\e%G'"
   2699 
   2700 # make sure it is not assigned yet
   2701 [[ -n ${aliases[utf2iso]} ]] && unalias utf2iso
   2702 function utf2iso () {
   2703     if isutfenv ; then
   2704         local ENV
   2705         for ENV in $(env | command grep -i '.utf') ; do
   2706             eval export "$(echo $ENV | sed 's/UTF-8/iso885915/ ; s/utf8/iso885915/')"
   2707         done
   2708     fi
   2709 }
   2710 
   2711 # make sure it is not assigned yet
   2712 [[ -n ${aliases[iso2utf]} ]] && unalias iso2utf
   2713 function iso2utf () {
   2714     if ! isutfenv ; then
   2715         local ENV
   2716         for ENV in $(env | command grep -i '\.iso') ; do
   2717             eval export "$(echo $ENV | sed 's/iso.*/UTF-8/ ; s/ISO.*/UTF-8/')"
   2718         done
   2719     fi
   2720 }
   2721 
   2722 # especially for roadwarriors using GNU screen and ssh:
   2723 if ! check_com asc &>/dev/null ; then
   2724   function asc () { autossh -t "$@" 'screen -RdU' }
   2725   compdef asc=ssh
   2726 fi
   2727 
   2728 #f1# Hints for the use of zsh on grml
   2729 function zsh-help () {
   2730     print "$bg[white]$fg[black]
   2731 zsh-help - hints for use of zsh on grml
   2732 =======================================$reset_color"
   2733 
   2734     print '
   2735 Main configuration of zsh happens in /etc/zsh/zshrc.
   2736 That file is part of the package grml-etc-core, if you want to
   2737 use them on a non-grml-system just get the tar.gz from
   2738 http://deb.grml.org/ or (preferably) get it from the git repository:
   2739 
   2740   http://git.grml.org/f/grml-etc-core/etc/zsh/zshrc
   2741 
   2742 This version of grml'\''s zsh setup does not use skel/.zshrc anymore.
   2743 The file is still there, but it is empty for backwards compatibility.
   2744 
   2745 For your own changes use these two files:
   2746     $HOME/.zshrc.pre
   2747     $HOME/.zshrc.local
   2748 
   2749 The former is sourced very early in our zshrc, the latter is sourced
   2750 very lately.
   2751 
   2752 System wide configuration without touching configuration files of grml
   2753 can take place in /etc/zsh/zshrc.local.
   2754 
   2755 For information regarding zsh start at http://grml.org/zsh/
   2756 
   2757 Take a look at grml'\''s zsh refcard:
   2758 % xpdf =(zcat /usr/share/doc/grml-docs/zsh/grml-zsh-refcard.pdf.gz)
   2759 
   2760 Check out the main zsh refcard:
   2761 % '$BROWSER' http://www.bash2zsh.com/zsh_refcard/refcard.pdf
   2762 
   2763 And of course visit the zsh-lovers:
   2764 % man zsh-lovers
   2765 
   2766 You can adjust some options through environment variables when
   2767 invoking zsh without having to edit configuration files.
   2768 Basically meant for bash users who are not used to the power of
   2769 the zsh yet. :)
   2770 
   2771   "NOCOR=1    zsh" => deactivate automatic correction
   2772   "NOMENU=1   zsh" => do not use auto menu completion
   2773                       (note: use ctrl-d for completion instead!)
   2774   "NOPRECMD=1 zsh" => disable the precmd + preexec commands (set GNU screen title)
   2775   "NOTITLE=1  zsh" => disable setting the title of xterms without disabling
   2776                       preexec() and precmd() completely
   2777   "GRML_DISPLAY_BATTERY=1  zsh"
   2778                    => activate battery status on right side of prompt (WIP)
   2779   "COMMAND_NOT_FOUND=1 zsh"
   2780                    => Enable a handler if an external command was not found
   2781                       The command called in the handler can be altered by setting
   2782                       the GRML_ZSH_CNF_HANDLER variable, the default is:
   2783                       "/usr/share/command-not-found/command-not-found"
   2784 
   2785 A value greater than 0 is enables a feature; a value equal to zero
   2786 disables it. If you like one or the other of these settings, you can
   2787 add them to ~/.zshrc.pre to ensure they are set when sourcing grml'\''s
   2788 zshrc.'
   2789 
   2790     print "
   2791 $bg[white]$fg[black]
   2792 Please report wishes + bugs to the grml-team: http://grml.org/bugs/
   2793 Enjoy your grml system with the zsh!$reset_color"
   2794 }
   2795 
   2796 # debian stuff
   2797 if [[ -r /etc/debian_version ]] ; then
   2798     if [[ -z "$GRML_NO_APT_ALIASES" ]]; then
   2799         #a3# Execute \kbd{apt-cache policy}
   2800         alias acp='apt-cache policy'
   2801         if check_com -c apt ; then
   2802           #a3# Execute \kbd{apt search}
   2803           alias acs='apt search'
   2804           #a3# Execute \kbd{apt show}
   2805           alias acsh='apt show'
   2806           #a3# Execute \kbd{apt dist-upgrade}
   2807           salias adg="apt dist-upgrade"
   2808           #a3# Execute \kbd{apt upgrade}
   2809           salias ag="apt upgrade"
   2810           #a3# Execute \kbd{apt install}
   2811           salias agi="apt install"
   2812           #a3# Execute \kbd{apt update}
   2813           salias au="apt update"
   2814         else
   2815           alias acs='apt-cache search'
   2816           alias acsh='apt-cache show'
   2817           salias adg="apt-get dist-upgrade"
   2818           salias ag="apt-get upgrade"
   2819           salias agi="apt-get install"
   2820           salias au="apt-get update"
   2821         fi
   2822         #a3# Execute \kbd{aptitude install}
   2823         salias ati="aptitude install"
   2824         #a3# Execute \kbd{aptitude update ; aptitude safe-upgrade}
   2825         salias -a up="aptitude update ; aptitude safe-upgrade"
   2826         #a3# Execute \kbd{dpkg-buildpackage}
   2827         alias dbp='dpkg-buildpackage'
   2828         #a3# Execute \kbd{grep-excuses}
   2829         alias ge='grep-excuses'
   2830     fi
   2831 
   2832     # get a root shell as normal user in live-cd mode:
   2833     if isgrmlcd && [[ $UID -ne 0 ]] ; then
   2834        alias su="sudo su"
   2835     fi
   2836 
   2837 fi
   2838 
   2839 # use /var/log/syslog iff present, fallback to journalctl otherwise
   2840 if [ -e /var/log/syslog ] ; then
   2841   #a1# Take a look at the syslog: \kbd{\$PAGER /var/log/syslog || journalctl}
   2842   salias llog="$PAGER /var/log/syslog"     # take a look at the syslog
   2843   #a1# Take a look at the syslog: \kbd{tail -f /var/log/syslog || journalctl}
   2844   salias tlog="tail -f /var/log/syslog"    # follow the syslog
   2845 elif check_com -c journalctl ; then
   2846   salias llog="journalctl"
   2847   salias tlog="journalctl -f"
   2848 fi
   2849 
   2850 # sort installed Debian-packages by size
   2851 if check_com -c dpkg-query ; then
   2852     #a3# List installed Debian-packages sorted by size
   2853     alias debs-by-size="dpkg-query -Wf 'x \${Installed-Size} \${Package} \${Status}\n' | sed -ne '/^x  /d' -e '/^x \(.*\) install ok installed$/s//\1/p' | sort -nr"
   2854 fi
   2855 
   2856 # if cdrecord is a symlink (to wodim) or isn't present at all warn:
   2857 if [[ -L /usr/bin/cdrecord ]] || ! check_com -c cdrecord; then
   2858     if check_com -c wodim; then
   2859         function cdrecord () {
   2860             <<__EOF0__
   2861 cdrecord is not provided under its original name by Debian anymore.
   2862 See #377109 in the BTS of Debian for more details.
   2863 
   2864 Please use the wodim binary instead
   2865 __EOF0__
   2866             return 1
   2867         }
   2868     fi
   2869 fi
   2870 
   2871 if isgrmlcd; then
   2872     # No core dumps: important for a live-cd-system
   2873     limit -s core 0
   2874 fi
   2875 
   2876 # grmlstuff
   2877 function grmlstuff () {
   2878 # people should use 'grml-x'!
   2879     if check_com -c 915resolution; then
   2880         function 855resolution () {
   2881             echo "Please use 915resolution as resolution modifying tool for Intel \
   2882 graphic chipset."
   2883             return -1
   2884         }
   2885     fi
   2886 
   2887     #a1# Output version of running grml
   2888     alias grml-version='cat /etc/grml_version'
   2889 
   2890     if check_com -c grml-debootstrap ; then
   2891         function debian2hd () {
   2892             echo "Installing debian to harddisk is possible by using grml-debootstrap."
   2893             return 1
   2894         }
   2895     fi
   2896 
   2897     if check_com -c tmate && check_com -c qrencode ; then
   2898         function grml-remote-support() {
   2899             tmate -L grml-remote-support new -s grml-remote-support -d
   2900             tmate -L grml-remote-support wait tmate-ready
   2901             tmate -L grml-remote-support display -p '#{tmate_ssh}' | qrencode -t ANSI
   2902             echo "tmate session: $(tmate -L grml-remote-support display -p '#{tmate_ssh}')"
   2903             echo
   2904             echo "Scan this QR code and send it to your support team."
   2905         }
   2906     fi
   2907 }
   2908 
   2909 # now run the functions
   2910 isgrml && checkhome
   2911 is4    && isgrml    && grmlstuff
   2912 is4    && grmlcomp
   2913 
   2914 # keephack
   2915 is4 && xsource "/etc/zsh/keephack"
   2916 
   2917 # wonderful idea of using "e" glob qualifier by Peter Stephenson
   2918 # You use it as follows:
   2919 # $ NTREF=/reference/file
   2920 # $ ls -l *(e:nt:)
   2921 # This lists all the files in the current directory newer than the reference file.
   2922 # You can also specify the reference file inline; note quotes:
   2923 # $ ls -l *(e:'nt ~/.zshenv':)
   2924 is4 && function nt () {
   2925     if [[ -n $1 ]] ; then
   2926         local NTREF=${~1}
   2927     fi
   2928     [[ $REPLY -nt $NTREF ]]
   2929 }
   2930 
   2931 # shell functions
   2932 
   2933 #f1# Reload an autoloadable function
   2934 function freload () { while (( $# )); do; unfunction $1; autoload -U $1; shift; done }
   2935 compdef _functions freload
   2936 
   2937 #
   2938 # Usage:
   2939 #
   2940 #      e.g.:   a -> b -> c -> d  ....
   2941 #
   2942 #      sll a
   2943 #
   2944 #
   2945 #      if parameter is given with leading '=', lookup $PATH for parameter and resolve that
   2946 #
   2947 #      sll =java
   2948 #
   2949 #      Note: limit for recursive symlinks on linux:
   2950 #            http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/fs/namei.c?id=refs/heads/master#l808
   2951 #            This limits recursive symlink follows to 8,
   2952 #            while limiting consecutive symlinks to 40.
   2953 #
   2954 #      When resolving and displaying information about symlinks, no check is made
   2955 #      that the displayed information does make any sense on your OS.
   2956 #      We leave that decission to the user.
   2957 #
   2958 #      The zstat module is used to detect symlink loops. zstat is available since zsh4.
   2959 #      With an older zsh you will need to abort with <C-c> in that case.
   2960 #      When a symlink loop is detected, a warning ist printed and further processing is stopped.
   2961 #
   2962 #      Module zstat is loaded by default in grml zshrc, no extra action needed for that.
   2963 #
   2964 #      Known bugs:
   2965 #      If you happen to come across a symlink that points to a destination on another partition
   2966 #      with the same inode number, that will be marked as symlink loop though it is not.
   2967 #      Two hints for this situation:
   2968 #      I)  Play lottery the same day, as you seem to be rather lucky right now.
   2969 #      II) Send patches.
   2970 #
   2971 #      return status:
   2972 #      0 upon success
   2973 #      1 file/dir not accesible
   2974 #      2 symlink loop detected
   2975 #
   2976 #f1# List symlinks in detail (more detailed version of 'readlink -f', 'whence -s' and 'namei -l')
   2977 function sll () {
   2978     if [[ -z ${1} ]] ; then
   2979         printf 'Usage: %s <symlink(s)>\n' "${0}"
   2980         return 1
   2981     fi
   2982 
   2983     local file jumpd curdir
   2984     local -i 10 RTN LINODE i
   2985     local -a    SEENINODES
   2986     curdir="${PWD}"
   2987     RTN=0
   2988 
   2989     for file in "${@}" ; do
   2990         SEENINODES=()
   2991         ls -l "${file:a}"   || RTN=1
   2992 
   2993         while [[ -h "$file" ]] ; do
   2994             if is4 ; then
   2995                 LINODE=$(zstat -L +inode "${file}")
   2996                 for i in ${SEENINODES} ; do
   2997                     if (( ${i} == ${LINODE} )) ; then
   2998                         builtin cd -q "${curdir}"
   2999                         print 'link loop detected, aborting!'
   3000                         return 2
   3001                     fi
   3002                 done
   3003                 SEENINODES+=${LINODE}
   3004             fi
   3005             jumpd="${file:h}"
   3006             file="${file:t}"
   3007 
   3008             if [[ -d ${jumpd} ]] ; then
   3009                 builtin cd -q "${jumpd}"  || RTN=1
   3010             fi
   3011             file=$(readlink "$file")
   3012 
   3013             jumpd="${file:h}"
   3014             file="${file:t}"
   3015 
   3016             if [[ -d ${jumpd} ]] ; then
   3017                 builtin cd -q "${jumpd}"  || RTN=1
   3018             fi
   3019 
   3020             ls -l "${PWD}/${file}"     || RTN=1
   3021         done
   3022         shift 1
   3023         if (( ${#} >= 1 )) ; then
   3024             print ""
   3025         fi
   3026         builtin cd -q "${curdir}"
   3027     done
   3028     return ${RTN}
   3029 }
   3030 
   3031 if check_com -c $PAGER ; then
   3032     #f3# View Debian's changelog of given package(s)
   3033     function dchange () {
   3034         emulate -L zsh
   3035         [[ -z "$1" ]] && printf 'Usage: %s <package_name(s)>\n' "$0" && return 1
   3036 
   3037         local package
   3038 
   3039         # `less` as $PAGER without e.g. `|lesspipe %s` inside $LESSOPEN can't properly
   3040         # read *.gz files, try to detect this to use vi instead iff available
   3041         local viewer
   3042 
   3043         if [[ ${$(typeset -p PAGER)[2]} = -a ]] ; then
   3044           viewer=($PAGER)    # support PAGER=(less -Mr) but leave array untouched
   3045         else
   3046           viewer=(${=PAGER}) # support PAGER='less -Mr'
   3047         fi
   3048 
   3049         if [[ ${viewer[1]:t} = less ]] && [[ -z "${LESSOPEN}" ]] && check_com vi ; then
   3050           viewer='vi'
   3051         fi
   3052 
   3053         for package in "$@" ; do
   3054             if [[ -r /usr/share/doc/${package}/changelog.Debian.gz ]] ; then
   3055                 $viewer /usr/share/doc/${package}/changelog.Debian.gz
   3056             elif [[ -r /usr/share/doc/${package}/changelog.gz ]] ; then
   3057                 $viewer /usr/share/doc/${package}/changelog.gz
   3058             elif [[ -r /usr/share/doc/${package}/changelog ]] ; then
   3059                 $viewer /usr/share/doc/${package}/changelog
   3060             else
   3061                 if check_com -c aptitude ; then
   3062                     echo "No changelog for package $package found, using aptitude to retrieve it."
   3063                     aptitude changelog "$package"
   3064                 elif check_com -c apt-get ; then
   3065                     echo "No changelog for package $package found, using apt-get to retrieve it."
   3066                     apt-get changelog "$package"
   3067                 else
   3068                     echo "No changelog for package $package found, sorry."
   3069                 fi
   3070             fi
   3071         done
   3072     }
   3073     function _dchange () { _files -W /usr/share/doc -/ }
   3074     compdef _dchange dchange
   3075 
   3076     #f3# View Debian's NEWS of a given package
   3077     function dnews () {
   3078         emulate -L zsh
   3079         if [[ -r /usr/share/doc/$1/NEWS.Debian.gz ]] ; then
   3080             $PAGER /usr/share/doc/$1/NEWS.Debian.gz
   3081         else
   3082             if [[ -r /usr/share/doc/$1/NEWS.gz ]] ; then
   3083                 $PAGER /usr/share/doc/$1/NEWS.gz
   3084             else
   3085                 echo "No NEWS file for package $1 found, sorry."
   3086                 return 1
   3087             fi
   3088         fi
   3089     }
   3090     function _dnews () { _files -W /usr/share/doc -/ }
   3091     compdef _dnews dnews
   3092 
   3093     #f3# View Debian's copyright of a given package
   3094     function dcopyright () {
   3095         emulate -L zsh
   3096         if [[ -r /usr/share/doc/$1/copyright ]] ; then
   3097             $PAGER /usr/share/doc/$1/copyright
   3098         else
   3099             echo "No copyright file for package $1 found, sorry."
   3100             return 1
   3101         fi
   3102     }
   3103     function _dcopyright () { _files -W /usr/share/doc -/ }
   3104     compdef _dcopyright dcopyright
   3105 
   3106     #f3# View upstream's changelog of a given package
   3107     function uchange () {
   3108         emulate -L zsh
   3109         if [[ -r /usr/share/doc/$1/changelog.gz ]] ; then
   3110             $PAGER /usr/share/doc/$1/changelog.gz
   3111         else
   3112             echo "No changelog for package $1 found, sorry."
   3113             return 1
   3114         fi
   3115     }
   3116     function _uchange () { _files -W /usr/share/doc -/ }
   3117     compdef _uchange uchange
   3118 fi
   3119 
   3120 # zsh profiling
   3121 function profile () {
   3122     ZSH_PROFILE_RC=1 zsh "$@"
   3123 }
   3124 
   3125 #f1# Edit an alias via zle
   3126 function edalias () {
   3127     [[ -z "$1" ]] && { echo "Usage: edalias <alias_to_edit>" ; return 1 } || vared aliases'[$1]' ;
   3128 }
   3129 compdef _aliases edalias
   3130 
   3131 #f1# Edit a function via zle
   3132 function edfunc () {
   3133     [[ -z "$1" ]] && { echo "Usage: edfunc <function_to_edit>" ; return 1 } || zed -f "$1" ;
   3134 }
   3135 compdef _functions edfunc
   3136 
   3137 # use it e.g. via 'Restart apache2'
   3138 #m# f6 Start() \kbd{service \em{process}}\quad\kbd{start}
   3139 #m# f6 Restart() \kbd{service \em{process}}\quad\kbd{restart}
   3140 #m# f6 Stop() \kbd{service \em{process}}\quad\kbd{stop}
   3141 #m# f6 Reload() \kbd{service \em{process}}\quad\kbd{reload}
   3142 #m# f6 Force-Reload() \kbd{service \em{process}}\quad\kbd{force-reload}
   3143 #m# f6 Status() \kbd{service \em{process}}\quad\kbd{status}
   3144 if [[ -d /etc/init.d || -d /etc/service ]] ; then
   3145     function __start_stop () {
   3146         local action_="${1:l}"  # e.g Start/Stop/Restart
   3147         local service_="$2"
   3148         local param_="$3"
   3149 
   3150         local service_target_="$(readlink /etc/init.d/$service_)"
   3151         if [[ $service_target_ == "/usr/bin/sv" ]]; then
   3152             # runit
   3153             case "${action_}" in
   3154                 start) if [[ ! -e /etc/service/$service_ ]]; then
   3155                            $SUDO ln -s "/etc/sv/$service_" "/etc/service/"
   3156                        else
   3157                            $SUDO "/etc/init.d/$service_" "${action_}" "$param_"
   3158                        fi ;;
   3159                 # there is no reload in runits sysv emulation
   3160                 reload) $SUDO "/etc/init.d/$service_" "force-reload" "$param_" ;;
   3161                 *) $SUDO "/etc/init.d/$service_" "${action_}" "$param_" ;;
   3162             esac
   3163         else
   3164             # sysv/sysvinit-utils, upstart
   3165             if check_com -c service ; then
   3166               $SUDO service "$service_" "${action_}" "$param_"
   3167             else
   3168               $SUDO "/etc/init.d/$service_" "${action_}" "$param_"
   3169             fi
   3170         fi
   3171     }
   3172 
   3173     function _grmlinitd () {
   3174         local -a scripts
   3175         scripts=( /etc/init.d/*(x:t) )
   3176         _describe "service startup script" scripts
   3177     }
   3178 
   3179     for i in Start Restart Stop Force-Reload Reload Status ; do
   3180         eval "function $i () { __start_stop $i \"\$1\" \"\$2\" ; }"
   3181         compdef _grmlinitd $i
   3182     done
   3183     builtin unset -v i
   3184 fi
   3185 
   3186 #f1# Provides useful information on globbing
   3187 function H-Glob () {
   3188     echo -e "
   3189     /      directories
   3190     .      plain files
   3191     @      symbolic links
   3192     =      sockets
   3193     p      named pipes (FIFOs)
   3194     *      executable plain files (0100)
   3195     %      device files (character or block special)
   3196     %b     block special files
   3197     %c     character special files
   3198     r      owner-readable files (0400)
   3199     w      owner-writable files (0200)
   3200     x      owner-executable files (0100)
   3201     A      group-readable files (0040)
   3202     I      group-writable files (0020)
   3203     E      group-executable files (0010)
   3204     R      world-readable files (0004)
   3205     W      world-writable files (0002)
   3206     X      world-executable files (0001)
   3207     s      setuid files (04000)
   3208     S      setgid files (02000)
   3209     t      files with the sticky bit (01000)
   3210 
   3211   print *(m-1)          # Files modified up to a day ago
   3212   print *(a1)           # Files accessed a day ago
   3213   print *(@)            # Just symlinks
   3214   print *(Lk+50)        # Files bigger than 50 kilobytes
   3215   print *(Lk-50)        # Files smaller than 50 kilobytes
   3216   print **/*.c          # All *.c files recursively starting in \$PWD
   3217   print **/*.c~file.c   # Same as above, but excluding 'file.c'
   3218   print (foo|bar).*     # Files starting with 'foo' or 'bar'
   3219   print *~*.*           # All Files that do not contain a dot
   3220   chmod 644 *(.^x)      # make all plain non-executable files publically readable
   3221   print -l *(.c|.h)     # Lists *.c and *.h
   3222   print **/*(g:users:)  # Recursively match all files that are owned by group 'users'
   3223   echo /proc/*/cwd(:h:t:s/self//) # Analogous to >ps ax | awk '{print $1}'<"
   3224 }
   3225 alias help-zshglob=H-Glob
   3226 
   3227 # grep for running process, like: 'any vim'
   3228 function any () {
   3229     emulate -L zsh
   3230     unsetopt KSH_ARRAYS
   3231     if [[ -z "$1" ]] ; then
   3232         echo "any - grep for process(es) by keyword" >&2
   3233         echo "Usage: any <keyword>" >&2 ; return 1
   3234     else
   3235         ps xauwww | grep -i "${grep_options[@]}" "[${1[1]}]${1[2,-1]}"
   3236     fi
   3237 }
   3238 
   3239 
   3240 # After resuming from suspend, system is paging heavily, leading to very bad interactivity.
   3241 # taken from $LINUX-KERNELSOURCE/Documentation/power/swsusp.txt
   3242 [[ -r /proc/1/maps ]] && \
   3243 function deswap () {
   3244     print 'Reading /proc/[0-9]*/maps and sending output to /dev/null, this might take a while.'
   3245     cat $(sed -ne 's:.* /:/:p' /proc/[0-9]*/maps | sort -u | grep -v '^/dev/')  > /dev/null
   3246     print 'Finished, running "swapoff -a; swapon -a" may also be useful.'
   3247 }
   3248 
   3249 # a wrapper for vim, that deals with title setting
   3250 #   VIM_OPTIONS
   3251 #       set this array to a set of options to vim you always want
   3252 #       to have set when calling vim (in .zshrc.local), like:
   3253 #           VIM_OPTIONS=( -p )
   3254 #       This will cause vim to send every file given on the
   3255 #       commandline to be send to it's own tab (needs vim7).
   3256 if check_com vim; then
   3257     function vim () {
   3258         VIM_PLEASE_SET_TITLE='yes' command vim ${VIM_OPTIONS} "$@"
   3259     }
   3260 fi
   3261 
   3262 ssl_hashes=( sha512 sha256 sha1 md5 )
   3263 
   3264 for sh in ${ssl_hashes}; do
   3265     eval 'ssl-cert-'${sh}'() {
   3266         emulate -L zsh
   3267         if [[ -z $1 ]] ; then
   3268             printf '\''usage: %s <file>\n'\'' "ssh-cert-'${sh}'"
   3269             return 1
   3270         fi
   3271         openssl x509 -noout -fingerprint -'${sh}' -in $1
   3272     }'
   3273 done; unset sh
   3274 
   3275 function ssl-cert-fingerprints () {
   3276     emulate -L zsh
   3277     local i
   3278     if [[ -z $1 ]] ; then
   3279         printf 'usage: ssl-cert-fingerprints <file>\n'
   3280         return 1
   3281     fi
   3282     for i in ${ssl_hashes}
   3283         do ssl-cert-$i $1;
   3284     done
   3285 }
   3286 
   3287 function ssl-cert-info () {
   3288     emulate -L zsh
   3289     if [[ -z $1 ]] ; then
   3290         printf 'usage: ssl-cert-info <file>\n'
   3291         return 1
   3292     fi
   3293     openssl x509 -noout -text -in $1
   3294     ssl-cert-fingerprints $1
   3295 }
   3296 
   3297 # make sure our environment is clean regarding colors
   3298 builtin unset -v BLUE RED GREEN CYAN YELLOW MAGENTA WHITE NO_COLOR
   3299 
   3300 # "persistent history"
   3301 # just write important commands you always need to $GRML_IMPORTANT_COMMANDS
   3302 # defaults for backward compatibility to ~/.important_commands
   3303 if [[ -r ~/.important_commands ]] ; then
   3304     GRML_IMPORTANT_COMMANDS=~/.important_commands
   3305 else
   3306     GRML_IMPORTANT_COMMANDS=${GRML_IMPORTANT_COMMANDS:-${ZDOTDIR:-${HOME}}/.important_commands}
   3307 fi
   3308 [[ -r ${GRML_IMPORTANT_COMMANDS} ]] && builtin fc -R ${GRML_IMPORTANT_COMMANDS}
   3309 
   3310 # load the lookup subsystem if it's available on the system
   3311 zrcautoload lookupinit && lookupinit
   3312 
   3313 # variables
   3314 
   3315 # set terminal property (used e.g. by msgid-chooser)
   3316 export COLORTERM="yes"
   3317 
   3318 # aliases
   3319 
   3320 # general
   3321 #a2# Execute \kbd{du -sch}
   3322 [[ -n "$GRML_NO_SMALL_ALIASES" ]] || alias da='du -sch'
   3323 
   3324 # listing stuff
   3325 #a2# Execute \kbd{ls -lSrah}
   3326 alias dir="command ls -lSrah"
   3327 #a2# Only show dot-directories
   3328 alias lad='command ls -d .*(/)'
   3329 #a2# Only show dot-files
   3330 alias lsa='command ls -a .*(.)'
   3331 #a2# Only files with setgid/setuid/sticky flag
   3332 alias lss='command ls -l *(s,S,t)'
   3333 #a2# Only show symlinks
   3334 alias lsl='command ls -l *(@)'
   3335 #a2# Display only executables
   3336 alias lsx='command ls -l *(*)'
   3337 #a2# Display world-{readable,writable,executable} files
   3338 alias lsw='command ls -ld *(R,W,X.^ND/)'
   3339 #a2# Display the ten biggest files
   3340 alias lsbig="command ls -flh *(.OL[1,10])"
   3341 #a2# Only show directories
   3342 alias lsd='command ls -d *(/)'
   3343 #a2# Only show empty directories
   3344 alias lse='command ls -d *(/^F)'
   3345 #a2# Display the ten newest files
   3346 alias lsnew="command ls -rtlh *(D.om[1,10])"
   3347 #a2# Display the ten oldest files
   3348 alias lsold="command ls -rtlh *(D.Om[1,10])"
   3349 #a2# Display the ten smallest files
   3350 alias lssmall="command ls -Srl *(.oL[1,10])"
   3351 #a2# Display the ten newest directories and ten newest .directories
   3352 alias lsnewdir="command ls -rthdl *(/om[1,10]) .*(D/om[1,10])"
   3353 #a2# Display the ten oldest directories and ten oldest .directories
   3354 alias lsolddir="command ls -rthdl *(/Om[1,10]) .*(D/Om[1,10])"
   3355 
   3356 # some useful aliases
   3357 #a2# Remove current empty directory. Execute \kbd{cd ..; rmdir \$OLDCWD}
   3358 alias rmcdir='cd ..; rmdir $OLDPWD || cd $OLDPWD'
   3359 
   3360 #a2# ssh with StrictHostKeyChecking=no \\&\quad and UserKnownHostsFile unset
   3361 alias insecssh='ssh -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null"'
   3362 #a2# scp with StrictHostKeyChecking=no \\&\quad and UserKnownHostsFile unset
   3363 alias insecscp='scp -o "StrictHostKeyChecking=no" -o "UserKnownHostsFile=/dev/null"'
   3364 
   3365 # work around non utf8 capable software in utf environment via $LANG and luit
   3366 if check_com isutfenv && check_com luit ; then
   3367     if check_com -c mrxvt ; then
   3368         isutfenv && [[ -n "$LANG" ]] && \
   3369             alias mrxvt="LANG=${LANG/(#b)(*)[.@]*/$match[1].iso885915} luit mrxvt"
   3370     fi
   3371 
   3372     if check_com -c aterm ; then
   3373         isutfenv && [[ -n "$LANG" ]] && \
   3374             alias aterm="LANG=${LANG/(#b)(*)[.@]*/$match[1].iso885915} luit aterm"
   3375     fi
   3376 
   3377     if check_com -c centericq ; then
   3378         isutfenv && [[ -n "$LANG" ]] && \
   3379             alias centericq="LANG=${LANG/(#b)(*)[.@]*/$match[1].iso885915} luit centericq"
   3380     fi
   3381 fi
   3382 
   3383 # useful functions
   3384 
   3385 #f5# Backup \kbd{file_or_folder {\rm to} file_or_folder\_timestamp}
   3386 function bk () {
   3387     emulate -L zsh
   3388     local current_date=$(date -u "+%Y%m%dT%H%M%SZ")
   3389     local clean keep move verbose result all to_bk
   3390     setopt extended_glob
   3391     keep=1
   3392     while getopts ":hacmrv" opt; do
   3393         case $opt in
   3394             a) (( all++ ));;
   3395             c) unset move clean && (( ++keep ));;
   3396             m) unset keep clean && (( ++move ));;
   3397             r) unset move keep && (( ++clean ));;
   3398             v) verbose="-v";;
   3399             h) <<__EOF0__
   3400 bk [-hcmv] FILE [FILE ...]
   3401 bk -r [-av] [FILE [FILE ...]]
   3402 Backup a file or folder in place and append the timestamp
   3403 Remove backups of a file or folder, or all backups in the current directory
   3404 
   3405 Usage:
   3406 -h    Display this help text
   3407 -c    Keep the file/folder as is, create a copy backup using cp(1) (default)
   3408 -m    Move the file/folder, using mv(1)
   3409 -r    Remove backups of the specified file or directory, using rm(1). If none
   3410       is provided, remove all backups in the current directory.
   3411 -a    Remove all (even hidden) backups.
   3412 -v    Verbose
   3413 
   3414 The -c, -r and -m options are mutually exclusive. If specified at the same time,
   3415 the last one is used.
   3416 
   3417 The return code is the sum of all cp/mv/rm return codes.
   3418 __EOF0__
   3419 return 0;;
   3420             \?) bk -h >&2; return 1;;
   3421         esac
   3422     done
   3423     shift "$((OPTIND-1))"
   3424     if (( keep > 0 )); then
   3425         if islinux || isfreebsd; then
   3426             for to_bk in "$@"; do
   3427                 cp $verbose -a "${to_bk%/}" "${to_bk%/}_$current_date"
   3428                 (( result += $? ))
   3429             done
   3430         else
   3431             for to_bk in "$@"; do
   3432                 cp $verbose -pR "${to_bk%/}" "${to_bk%/}_$current_date"
   3433                 (( result += $? ))
   3434             done
   3435         fi
   3436     elif (( move > 0 )); then
   3437         while (( $# > 0 )); do
   3438             mv $verbose "${1%/}" "${1%/}_$current_date"
   3439             (( result += $? ))
   3440             shift
   3441         done
   3442     elif (( clean > 0 )); then
   3443         if (( $# > 0 )); then
   3444             for to_bk in "$@"; do
   3445                 rm $verbose -rf "${to_bk%/}"_[0-9](#c8)T([0-1][0-9]|2[0-3])([0-5][0-9])(#c2)Z
   3446                 (( result += $? ))
   3447             done
   3448         else
   3449             if (( all > 0 )); then
   3450                 rm $verbose -rf *_[0-9](#c8)T([0-1][0-9]|2[0-3])([0-5][0-9])(#c2)Z(D)
   3451             else
   3452                 rm $verbose -rf *_[0-9](#c8)T([0-1][0-9]|2[0-3])([0-5][0-9])(#c2)Z
   3453             fi
   3454             (( result += $? ))
   3455         fi
   3456     fi
   3457     return $result
   3458 }
   3459 
   3460 #f5# cd to directory and list files
   3461 function cl () {
   3462     emulate -L zsh
   3463     cd $1 && ls -a
   3464 }
   3465 
   3466 # smart cd function, allows switching to /etc when running 'cd /etc/fstab'
   3467 function cd () {
   3468     if (( ${#argv} == 1 )) && [[ -f ${1} ]]; then
   3469         [[ ! -e ${1:h} ]] && return 1
   3470         print "Correcting ${1} to ${1:h}"
   3471         builtin cd ${1:h}
   3472     else
   3473         builtin cd "$@"
   3474     fi
   3475 }
   3476 
   3477 #f5# Create Directory and \kbd{cd} to it
   3478 function mkcd () {
   3479     if (( ARGC != 1 )); then
   3480         printf 'usage: mkcd <new-directory>\n'
   3481         return 1;
   3482     fi
   3483     if [[ ! -d "$1" ]]; then
   3484         command mkdir -p "$1"
   3485     else
   3486         printf '`%s'\'' already exists: cd-ing.\n' "$1"
   3487     fi
   3488     builtin cd "$1"
   3489 }
   3490 
   3491 #f5# Create temporary directory and \kbd{cd} to it
   3492 function cdt () {
   3493     builtin cd "$(mktemp -d)"
   3494     builtin pwd
   3495 }
   3496 
   3497 #f5# List files which have been accessed within the last {\it n} days, {\it n} defaults to 1
   3498 function accessed () {
   3499     emulate -L zsh
   3500     print -l -- *(a-${1:-1})
   3501 }
   3502 
   3503 #f5# List files which have been changed within the last {\it n} days, {\it n} defaults to 1
   3504 function changed () {
   3505     emulate -L zsh
   3506     print -l -- *(c-${1:-1})
   3507 }
   3508 
   3509 #f5# List files which have been modified within the last {\it n} days, {\it n} defaults to 1
   3510 function modified () {
   3511     emulate -L zsh
   3512     print -l -- *(m-${1:-1})
   3513 }
   3514 # modified() was named new() in earlier versions, add an alias for backwards compatibility
   3515 check_com new || alias new=modified
   3516 
   3517 # use colors when GNU grep with color-support
   3518 if (( $#grep_options > 0 )); then
   3519     o=${grep_options:+"${grep_options[*]}"}
   3520     #a2# Execute \kbd{grep -{}-color=auto}
   3521     alias grep='grep '$o
   3522     alias egrep='egrep '$o
   3523     unset o
   3524 fi
   3525 
   3526 # Translate DE<=>EN
   3527 # 'translate' looks up a word in a file with language-to-language
   3528 # translations (field separator should be " : "). A typical wordlist looks
   3529 # like the following:
   3530 #  | english-word : german-translation
   3531 # It's also only possible to translate english to german but not reciprocal.
   3532 # Use the following oneliner to reverse the sort order:
   3533 #  $ awk -F ':' '{ print $2" : "$1" "$3 }' \
   3534 #    /usr/local/lib/words/en-de.ISO-8859-1.vok > ~/.translate/de-en.ISO-8859-1.vok
   3535 #f5# Translates a word
   3536 function trans () {
   3537     emulate -L zsh
   3538     case "$1" in
   3539         -[dD]*)
   3540             translate -l de-en $2
   3541             ;;
   3542         -[eE]*)
   3543             translate -l en-de $2
   3544             ;;
   3545         *)
   3546             echo "Usage: $0 { -D | -E }"
   3547             echo "         -D == German to English"
   3548             echo "         -E == English to German"
   3549     esac
   3550 }
   3551 
   3552 # Usage: simple-extract <file>
   3553 # Using option -d deletes the original archive file.
   3554 #f5# Smart archive extractor
   3555 function simple-extract () {
   3556     emulate -L zsh
   3557     setopt extended_glob noclobber
   3558     local ARCHIVE DELETE_ORIGINAL DECOMP_CMD USES_STDIN USES_STDOUT GZTARGET WGET_CMD
   3559     local RC=0
   3560     zparseopts -D -E "d=DELETE_ORIGINAL"
   3561     for ARCHIVE in "${@}"; do
   3562         case $ARCHIVE in
   3563             *(tar.bz2|tbz2|tbz))
   3564                 DECOMP_CMD="tar -xvjf -"
   3565                 USES_STDIN=true
   3566                 USES_STDOUT=false
   3567                 ;;
   3568             *(tar.gz|tgz))
   3569                 DECOMP_CMD="tar -xvzf -"
   3570                 USES_STDIN=true
   3571                 USES_STDOUT=false
   3572                 ;;
   3573             *(tar.xz|txz|tar.lzma))
   3574                 DECOMP_CMD="tar -xvJf -"
   3575                 USES_STDIN=true
   3576                 USES_STDOUT=false
   3577                 ;;
   3578             *tar.zst)
   3579                 DECOMP_CMD="tar --zstd -xvf -"
   3580                 USES_STDIN=true
   3581                 USES_STDOUT=false
   3582                 ;;
   3583             *tar.lrz)
   3584                 DECOMP_CMD="lrzuntar"
   3585                 USES_STDIN=false
   3586                 USES_STDOUT=false
   3587                 ;;
   3588             *tar)
   3589                 DECOMP_CMD="tar -xvf -"
   3590                 USES_STDIN=true
   3591                 USES_STDOUT=false
   3592                 ;;
   3593             *rar)
   3594                 DECOMP_CMD="unrar x"
   3595                 USES_STDIN=false
   3596                 USES_STDOUT=false
   3597                 ;;
   3598             *lzh)
   3599                 DECOMP_CMD="lha x"
   3600                 USES_STDIN=false
   3601                 USES_STDOUT=false
   3602                 ;;
   3603             *7z)
   3604                 DECOMP_CMD="7z x"
   3605                 USES_STDIN=false
   3606                 USES_STDOUT=false
   3607                 ;;
   3608             *(zip|jar))
   3609                 DECOMP_CMD="unzip"
   3610                 USES_STDIN=false
   3611                 USES_STDOUT=false
   3612                 ;;
   3613             *deb)
   3614                 DECOMP_CMD="ar -x"
   3615                 USES_STDIN=false
   3616                 USES_STDOUT=false
   3617                 ;;
   3618             *bz2)
   3619                 DECOMP_CMD="bzip2 -d -c -"
   3620                 USES_STDIN=true
   3621                 USES_STDOUT=true
   3622                 ;;
   3623             *(gz|Z))
   3624                 DECOMP_CMD="gzip -d -c -"
   3625                 USES_STDIN=true
   3626                 USES_STDOUT=true
   3627                 ;;
   3628             *(xz|lzma))
   3629                 DECOMP_CMD="xz -d -c -"
   3630                 USES_STDIN=true
   3631                 USES_STDOUT=true
   3632                 ;;
   3633             *zst)
   3634                 DECOMP_CMD="zstd -d -c -"
   3635                 USES_STDIN=true
   3636                 USES_STDOUT=true
   3637                 ;;
   3638             *lrz)
   3639                 DECOMP_CMD="lrunzip -"
   3640                 USES_STDIN=true
   3641                 USES_STDOUT=true
   3642                 ;;
   3643             *)
   3644                 print "ERROR: '$ARCHIVE' has unrecognized archive type." >&2
   3645                 RC=$((RC+1))
   3646                 continue
   3647                 ;;
   3648         esac
   3649 
   3650         if ! check_com ${DECOMP_CMD[(w)1]}; then
   3651             echo "ERROR: ${DECOMP_CMD[(w)1]} not installed." >&2
   3652             RC=$((RC+2))
   3653             continue
   3654         fi
   3655 
   3656         GZTARGET="${ARCHIVE:t:r}"
   3657         if [[ -f $ARCHIVE ]] ; then
   3658 
   3659             print "Extracting '$ARCHIVE' ..."
   3660             if $USES_STDIN; then
   3661                 if $USES_STDOUT; then
   3662                     ${=DECOMP_CMD} < "$ARCHIVE" > $GZTARGET
   3663                 else
   3664                     ${=DECOMP_CMD} < "$ARCHIVE"
   3665                 fi
   3666             else
   3667                 if $USES_STDOUT; then
   3668                     ${=DECOMP_CMD} "$ARCHIVE" > $GZTARGET
   3669                 else
   3670                     ${=DECOMP_CMD} "$ARCHIVE"
   3671                 fi
   3672             fi
   3673             [[ $? -eq 0 && -n "$DELETE_ORIGINAL" ]] && rm -f "$ARCHIVE"
   3674 
   3675         elif [[ "$ARCHIVE" == (#s)(https|http|ftp)://* ]] ; then
   3676             if check_com curl; then
   3677                 WGET_CMD="curl -L -s -o -"
   3678             elif check_com wget; then
   3679                 WGET_CMD="wget -q -O -"
   3680             elif check_com fetch; then
   3681                 WGET_CMD="fetch -q -o -"
   3682             else
   3683                 print "ERROR: neither wget, curl nor fetch is installed" >&2
   3684                 RC=$((RC+4))
   3685                 continue
   3686             fi
   3687             print "Downloading and Extracting '$ARCHIVE' ..."
   3688             if $USES_STDIN; then
   3689                 if $USES_STDOUT; then
   3690                     ${=WGET_CMD} "$ARCHIVE" | ${=DECOMP_CMD} > $GZTARGET
   3691                     RC=$((RC+$?))
   3692                 else
   3693                     ${=WGET_CMD} "$ARCHIVE" | ${=DECOMP_CMD}
   3694                     RC=$((RC+$?))
   3695                 fi
   3696             else
   3697                 if $USES_STDOUT; then
   3698                     ${=DECOMP_CMD} =(${=WGET_CMD} "$ARCHIVE") > $GZTARGET
   3699                 else
   3700                     ${=DECOMP_CMD} =(${=WGET_CMD} "$ARCHIVE")
   3701                 fi
   3702             fi
   3703 
   3704         else
   3705             print "ERROR: '$ARCHIVE' is neither a valid file nor a supported URI." >&2
   3706             RC=$((RC+8))
   3707         fi
   3708     done
   3709     return $RC
   3710 }
   3711 
   3712 function __archive_or_uri () {
   3713     _alternative \
   3714         'files:Archives:_files -g "*.(#l)(tar.bz2|tbz2|tbz|tar.gz|tgz|tar.xz|txz|tar.lzma|tar|rar|lzh|7z|zip|jar|deb|bz2|gz|Z|xz|lzma)"' \
   3715         '_urls:Remote Archives:_urls'
   3716 }
   3717 
   3718 function _simple_extract () {
   3719     _arguments \
   3720         '-d[delete original archivefile after extraction]' \
   3721         '*:Archive Or Uri:__archive_or_uri'
   3722 }
   3723 compdef _simple_extract simple-extract
   3724 [[ -n "$GRML_NO_SMALL_ALIASES" ]] || alias se=simple-extract
   3725 
   3726 #f5# Change the xterm title from within GNU-screen
   3727 function xtrename () {
   3728     emulate -L zsh
   3729     if [[ $1 != "-f" ]] ; then
   3730         if [[ -z ${DISPLAY} ]] ; then
   3731             printf 'xtrename only makes sense in X11.\n'
   3732             return 1
   3733         fi
   3734     else
   3735         shift
   3736     fi
   3737     if [[ -z $1 ]] ; then
   3738         printf 'usage: xtrename [-f] "title for xterm"\n'
   3739         printf '  renames the title of xterm from _within_ screen.\n'
   3740         printf '  also works without screen.\n'
   3741         printf '  will not work if DISPLAY is unset, use -f to override.\n'
   3742         return 0
   3743     fi
   3744     print -n "\eP\e]0;${1}\C-G\e\\"
   3745     return 0
   3746 }
   3747 
   3748 # Create small urls via http://goo.gl using curl(1).
   3749 # API reference: https://code.google.com/apis/urlshortener/
   3750 function zurl () {
   3751     emulate -L zsh
   3752     setopt extended_glob
   3753 
   3754     if [[ -z $1 ]]; then
   3755         print "USAGE: zurl <URL>"
   3756         return 1
   3757     fi
   3758 
   3759     local PN url prog api json contenttype item
   3760     local -a data
   3761     PN=$0
   3762     url=$1
   3763 
   3764     # Prepend 'http://' to given URL where necessary for later output.
   3765     if [[ ${url} != http(s|)://* ]]; then
   3766         url='http://'${url}
   3767     fi
   3768 
   3769     if check_com -c curl; then
   3770         prog=curl
   3771     else
   3772         print "curl is not available, but mandatory for ${PN}. Aborting."
   3773         return 1
   3774     fi
   3775     api='https://www.googleapis.com/urlshortener/v1/url'
   3776     contenttype="Content-Type: application/json"
   3777     json="{\"longUrl\": \"${url}\"}"
   3778     data=(${(f)"$($prog --silent -H ${contenttype} -d ${json} $api)"})
   3779     # Parse the response
   3780     for item in "${data[@]}"; do
   3781         case "$item" in
   3782             ' '#'"id":'*)
   3783                 item=${item#*: \"}
   3784                 item=${item%\",*}
   3785                 printf '%s\n' "$item"
   3786                 return 0
   3787                 ;;
   3788         esac
   3789     done
   3790     return 1
   3791 }
   3792 
   3793 #f2# Find history events by search pattern and list them by date.
   3794 function whatwhen () {
   3795     emulate -L zsh
   3796     local usage help ident format_l format_s first_char remain first last
   3797     usage='USAGE: whatwhen [options] <searchstring> <search range>'
   3798     help='Use `whatwhen -h'\'' for further explanations.'
   3799     ident=${(l,${#${:-Usage: }},, ,)}
   3800     format_l="${ident}%s\t\t\t%s\n"
   3801     format_s="${format_l//(\\t)##/\\t}"
   3802     # Make the first char of the word to search for case
   3803     # insensitive; e.g. [aA]
   3804     first_char=[${(L)1[1]}${(U)1[1]}]
   3805     remain=${1[2,-1]}
   3806     # Default search range is `-100'.
   3807     first=${2:-\-100}
   3808     # Optional, just used for `<first> <last>' given.
   3809     last=$3
   3810     case $1 in
   3811         ("")
   3812             printf '%s\n\n' 'ERROR: No search string specified. Aborting.'
   3813             printf '%s\n%s\n\n' ${usage} ${help} && return 1
   3814         ;;
   3815         (-h)
   3816             printf '%s\n\n' ${usage}
   3817             print 'OPTIONS:'
   3818             printf $format_l '-h' 'show help text'
   3819             print '\f'
   3820             print 'SEARCH RANGE:'
   3821             printf $format_l "'0'" 'the whole history,'
   3822             printf $format_l '-<n>' 'offset to the current history number; (default: -100)'
   3823             printf $format_s '<[-]first> [<last>]' 'just searching within a give range'
   3824             printf '\n%s\n' 'EXAMPLES:'
   3825             printf ${format_l/(\\t)/} 'whatwhen grml' '# Range is set to -100 by default.'
   3826             printf $format_l 'whatwhen zsh -250'
   3827             printf $format_l 'whatwhen foo 1 99'
   3828         ;;
   3829         (\?)
   3830             printf '%s\n%s\n\n' ${usage} ${help} && return 1
   3831         ;;
   3832         (*)
   3833             # -l list results on stout rather than invoking $EDITOR.
   3834             # -i Print dates as in YYYY-MM-DD.
   3835             # -m Search for a - quoted - pattern within the history.
   3836             fc -li -m "*${first_char}${remain}*" $first $last
   3837         ;;
   3838     esac
   3839 }
   3840 
   3841 # mercurial related stuff
   3842 if check_com -c hg ; then
   3843     # gnu like diff for mercurial
   3844     # http://www.selenic.com/mercurial/wiki/index.cgi/TipsAndTricks
   3845     #f5# GNU like diff for mercurial
   3846     function hgdi () {
   3847         emulate -L zsh
   3848         local i
   3849         for i in $(hg status -marn "$@") ; diff -ubwd <(hg cat "$i") "$i"
   3850     }
   3851 
   3852     # build debian package
   3853     #a2# Alias for \kbd{hg-buildpackage}
   3854     alias hbp='hg-buildpackage'
   3855 
   3856     # execute commands on the versioned patch-queue from the current repos
   3857     [[ -n "$GRML_NO_SMALL_ALIASES" ]] || alias mq='hg -R $(readlink -f $(hg root)/.hg/patches)'
   3858 
   3859     # diffstat for specific version of a mercurial repository
   3860     #   hgstat      => display diffstat between last revision and tip
   3861     #   hgstat 1234 => display diffstat between revision 1234 and tip
   3862     #f5# Diffstat for specific version of a mercurial repos
   3863     function hgstat () {
   3864         emulate -L zsh
   3865         [[ -n "$1" ]] && hg diff -r $1 -r tip | diffstat || hg export tip | diffstat
   3866     }
   3867 
   3868 fi # end of check whether we have the 'hg'-executable
   3869 
   3870 # disable bracketed paste mode for dumb terminals
   3871 [[ "$TERM" == dumb ]] && unset zle_bracketed_paste
   3872 
   3873 # grml-small cleanups and workarounds
   3874 
   3875 # The following is used to remove zsh-config-items that do not work
   3876 # in grml-small by default.
   3877 # If you do not want these adjustments (for whatever reason), set
   3878 # $GRMLSMALL_SPECIFIC to 0 in your .zshrc.pre file (which this configuration
   3879 # sources if it is there).
   3880 
   3881 if (( GRMLSMALL_SPECIFIC > 0 )) && isgrmlsmall ; then
   3882 
   3883     # Clean up
   3884 
   3885     unset "abk[V]"
   3886     unalias    'V'      &> /dev/null
   3887     unfunction vman     &> /dev/null
   3888     unfunction viless   &> /dev/null
   3889     unfunction 2html    &> /dev/null
   3890 
   3891     # manpages are not in grmlsmall
   3892     unfunction manzsh   &> /dev/null
   3893     unfunction man2     &> /dev/null
   3894 
   3895     # Workarounds
   3896 
   3897     # See https://github.com/grml/grml/issues/56
   3898     if ! [[ -x ${commands[dig]} ]]; then
   3899         function dig_after_all () {
   3900             unfunction dig
   3901             unfunction _dig
   3902             autoload -Uz _dig
   3903             unfunction dig_after_all
   3904         }
   3905         function dig () {
   3906             if [[ -x ${commands[dig]} ]]; then
   3907                 dig_after_all
   3908                 command dig "$@"
   3909                 return "$!"
   3910             fi
   3911             printf 'This installation does not include `dig'\'' for size reasons.\n'
   3912             printf 'Try `drill'\'' as a light weight alternative.\n'
   3913             return 0
   3914         }
   3915         function _dig () {
   3916             if [[ -x ${commands[dig]} ]]; then
   3917                 dig_after_all
   3918                 zle -M 'Found `dig'\'' installed. '
   3919             else
   3920                 zle -M 'Try `drill'\'' instead of `dig'\''.'
   3921             fi
   3922         }
   3923         compdef _dig dig
   3924     fi
   3925 fi
   3926 
   3927 zrclocal
   3928 
   3929 unfunction grml_status_feature
   3930 
   3931 ## genrefcard.pl settings
   3932 
   3933 ### doc strings for external functions from files
   3934 #m# f5 grml-wallpaper() Sets a wallpaper (try completion for possible values)
   3935 
   3936 ### example: split functions-search 8,16,24,32
   3937 #@# split functions-search 8
   3938 
   3939 ## END OF FILE #################################################################
   3940 # vim:filetype=zsh foldmethod=marker autoindent expandtab shiftwidth=4
   3941 # Local variables:
   3942 # mode: sh
   3943 # End: