zshrc: Give check_com a -g option to test for global aliases, too.
[grml-etc-core.git] / etc / zsh / zshrc
index 3dffc29..06523f6 100644 (file)
 # Global Order: zshenv, zprofile, zshrc, zlogin
 ################################################################################
 
+# Contributing:
+# If you want to help to improve grml's zsh setup, clone the grml-etc-core
+# repository from git.grml.org:
+#   git clone git://git.grml.org/grml-etc-core.git
+#
+# Make your changes, commit them; use 'git format-patch' to create a series
+# of patches and send those to the following address via 'git send-email':
+#   grml-etc-core@grml.org
+#
+# Doing so makes sure the right people get your patches for review and
+# possibly inclusion.
+
 # zsh-refcard-tag documentation: {{{
 #   You may notice strange looking comments in this file.
 #   These are there for a purpose. grml's zsh-refcard can now be
@@ -121,6 +133,11 @@ is43(){
     return 1
 }
 
+is433(){
+    [[ $ZSH_VERSION == 4.3.<3->* || $ZSH_VERSION == <5->* ]] && return 0
+    return 1
+}
+
 #f1# Checks whether or not you're running grml
 isgrml(){
     [[ -f /etc/grml_version ]] && return 0
@@ -230,6 +247,8 @@ zrcautoload is-at-least || is-at-least() { return 1 }
 NOCOR=${NOCOR:-0}
 NOMENU=${NOMENU:-0}
 NOPRECMD=${NOPRECMD:-0}
+COMMAND_NOT_FOUND=${COMMAND_NOT_FOUND:-0}
+GRML_ZSH_CNF_HANDLER=${GRML_ZSH_CNF_HANDLER:-/usr/share/command-not-found/command-not-found}
 BATTERY=${BATTERY:-0}
 GRMLSMALL_SPECIFIC=${GRMLSMALL_SPECIFIC:-1}
 GRML_ALWAYS_LOAD_ALL=${GRML_ALWAYS_LOAD_ALL:-0}
@@ -313,14 +332,20 @@ fi # GRML_WARN_SKEL
 # this function checks if a command exists and returns either true
 # or false. This avoids using 'which' and 'whence', which will
 # avoid problems with aliases for which on certain weird systems. :-)
+# Usage: check_com [-c|-g] word
+#   -c  only checks for external commands
+#   -g  does the usual tests and also checks for global aliases
 check_com() {
-    local -i comonly
+    local -i comonly gatoo
 
     if [[ ${1} == '-c' ]] ; then
         (( comonly = 1 ))
         shift
+    elif [[ ${1} == '-g' ]] ; then
+        (( gatoo = 1 ))
     else
         (( comonly = 0 ))
+        (( gatoo = 0 ))
     fi
 
     if (( ${#argv} != 1 )) ; then
@@ -341,6 +366,10 @@ check_com() {
         return 0
     fi
 
+    if (( gatoo > 0 )) && [[ -n ${galiases[$1]} ]] ; then
+        return 0
+    fi
+
     return 1
 }
 
@@ -446,6 +475,7 @@ xunfunction() {
 # this allows us to stay in sync with grml's zshrc and put own
 # modifications in ~/.zshrc.local
 zrclocal() {
+    xsource "/etc/zsh/zshrc.local"
     xsource "${HOME}/.zshrc.local"
     return 0
 }
@@ -453,12 +483,9 @@ zrclocal() {
 #}}}
 
 # locale setup {{{
-if [[ -z "$LANG" ]] ; then
-   xsource "/etc/default/locale"
-fi
+xsource "/etc/default/locale"
 
-export LANG=${LANG:-en_US.iso885915}
-for var in LC_ALL LC_MESSAGES ; do
+for var in LANG LC_ALL LC_MESSAGES ; do
     [[ -n ${(P)var} ]] && export $var
 done
 
@@ -542,6 +569,15 @@ else
     fi
 fi
 
+# support colors in less
+export LESS_TERMCAP_mb=$'\E[01;31m'
+export LESS_TERMCAP_md=$'\E[01;31m'
+export LESS_TERMCAP_me=$'\E[0m'
+export LESS_TERMCAP_se=$'\E[0m'
+export LESS_TERMCAP_so=$'\E[01;44;33m'
+export LESS_TERMCAP_ue=$'\E[0m'
+export LESS_TERMCAP_us=$'\E[01;32m'
+
 # automatically remove duplicates from these arrays
 typeset -U path cdpath fpath manpath
 # }}}
@@ -630,6 +666,14 @@ grml_toggle_abbrev() {
 zle -N grml_toggle_abbrev
 bindkey '^xA' grml_toggle_abbrev
 
+# add a command line to the shells history without executing it
+commit-to-history() {
+    print -s ${(z)BUFFER}
+    zle send-break
+}
+zle -N commit-to-history
+bindkey "^x^h" commit-to-history
+
 # }}}
 
 # a generic accept-line wrapper {{{
@@ -783,26 +827,26 @@ declare -A abk
 setopt extendedglob
 setopt interactivecomments
 abk=(
-# key  # value                (#d additional doc string)
+#   key   # value                  (#d additional doc string)
 #A# start
-    '...' '../..'
+    '...'  '../..'
     '....' '../../..'
-    'BG' '& exit'
-    'C' '| wc -l'
-    'G' '|& grep --color=auto'
-    'H' '| head'
-    'Hl' ' --help |& less -r'      #d (Display help in pager)
-    'L' '| less'
-    'LL' '|& less -r'
-    'M' '| most'
-    'N' '&>/dev/null'              #d (No Output)
-    'R' '| tr A-z N-za-m'          #d (ROT13)
-    'SL' '| sort | less'
-    'S' '| sort -u'
-    'T' '| tail'
-    'V' '|& vim -'
+    'BG'   '& exit'
+    'C'    '| wc -l'
+    'G'    '|& grep --color=auto '
+    'H'    '| head'
+    'Hl'   ' --help |& less -r'    #d (Display help in pager)
+    'L'    '| less'
+    'LL'   '|& less -r'
+    'M'    '| most'
+    'N'    '&>/dev/null'           #d (No Output)
+    'R'    '| tr A-z N-za-m'       #d (ROT13)
+    'SL'   '| sort | less'
+    'S'    '| sort -u'
+    'T'    '| tail'
+    'V'    '|& vim -'
 #A# end
-    'co' "./configure && make && sudo make install"
+    'co'   './configure && make && sudo make install'
 )
 
 globalias() {
@@ -840,8 +884,8 @@ alias run-help >&/dev/null && unalias run-help
 zrcautoload run-help # use via 'esc-h'
 
 # completion system
-if zrcautoload compinit && compinit 2>/dev/null ; then
-    compinit 2>/dev/null || print 'Notice: no compinit available :('
+if zrcautoload compinit ; then
+    compinit || print 'Notice: no compinit available :('
 else
     print 'Notice: no compinit available :('
     function zstyle { }
@@ -1023,6 +1067,95 @@ chpwd() {
 
 # }}}
 
+# directory based profiles {{{
+
+if is433 ; then
+
+CHPWD_PROFILE='default'
+function chpwd_profiles() {
+    # Say you want certain settings to be active in certain directories.
+    # This is what you want.
+    #
+    # zstyle ':chpwd:profiles:/usr/src/grml(|/|/*)'   profile grml
+    # zstyle ':chpwd:profiles:/usr/src/debian(|/|/*)' profile debian
+    #
+    # When that's done and you enter a directory that matches the pattern
+    # in the third part of the context, a function called chpwd_profile_grml,
+    # for example, is called (if it exists).
+    #
+    # If no pattern matches (read: no profile is detected) the profile is
+    # set to 'default', which means chpwd_profile_default is attempted to
+    # be called.
+    #
+    # A word about the context (the ':chpwd:profiles:*' stuff in the zstyle
+    # command) which is used: The third part in the context is matched against
+    # ${PWD}. That's why using a pattern such as /foo/bar(|/|/*) makes sense.
+    # Because that way the profile is detected for all these values of ${PWD}:
+    #   /foo/bar
+    #   /foo/bar/
+    #   /foo/bar/baz
+    # So, if you want to make double damn sure a profile works in /foo/bar
+    # and everywhere deeper in that tree, just use (|/|/*) and be happy.
+    #
+    # The name of the detected profile will be available in a variable called
+    # 'profile' in your functions. You don't need to do anything, it'll just
+    # be there.
+    #
+    # Then there is the parameter $CHPWD_PROFILE is set to the profile, that
+    # was is currently active. That way you can avoid running code for a
+    # profile that is already active, by running code such as the following
+    # at the start of your function:
+    #
+    # function chpwd_profile_grml() {
+    #     [[ ${profile} == ${CHPWD_PROFILE} ]] && return 1
+    #   ...
+    # }
+    #
+    # The initial value for $CHPWD_PROFILE is 'default'.
+    #
+    # Version requirement:
+    #   This feature requires zsh 4.3.3 or newer.
+    #   If you use this feature and need to know whether it is active in your
+    #   current shell, there are several ways to do that. Here are two simple
+    #   ways:
+    #
+    #   a) If knowing if the profiles feature is active when zsh starts is
+    #      good enough for you, you can put the following snippet into your
+    #      .zshrc.local:
+    #
+    #   (( ${+functions[chpwd_profiles]} )) && print "directory profiles active"
+    #
+    #   b) If that is not good enough, and you would prefer to be notified
+    #      whenever a profile changes, you can solve that by making sure you
+    #      start *every* profile function you create like this:
+    #
+    #   function chpwd_profile_myprofilename() {
+    #       [[ ${profile} == ${CHPWD_PROFILE} ]] && return 1
+    #       print "chpwd(): Switching to profile: $profile"
+    #     ...
+    #   }
+    #
+    #      That makes sure you only get notified if a profile is *changed*,
+    #      not everytime you change directory, which would probably piss
+    #      you off fairly quickly. :-)
+    #
+    # There you go. Now have fun with that.
+    local -x profile
+
+    zstyle -s ":chpwd:profiles:${PWD}" profile profile || profile='default'
+    if (( ${+functions[chpwd_profile_$profile]} )) ; then
+        chpwd_profile_${profile}
+    fi
+
+    CHPWD_PROFILE="${profile}"
+    return 0
+}
+chpwd_functions=( ${chpwd_functions} chpwd_profiles )
+
+fi # is433
+
+# }}}
+
 # {{{ display battery status on right side of prompt via running 'BATTERY=1 zsh'
 if [[ $BATTERY -gt 0 ]] ; then
     if ! check_com -c acpi ; then
@@ -1032,7 +1165,7 @@ fi
 
 battery() {
 if [[ $BATTERY -gt 0 ]] ; then
-    PERCENT="${${"$(acpi 2>/dev/null)"}/(#b)[[:space:]]##Battery <->: [^0-9]##, (<->)%*/${match[1]}}"
+    PERCENT="${${"$(acpi 2>/dev/null)"}/(#b)[[:space:]]#Battery <->: [^0-9]##, (<->)%*/${match[1]}}"
     if [[ -z "$PERCENT" ]] ; then
         PERCENT='acpi not present'
     else
@@ -1619,10 +1752,17 @@ VCS_INFO_git_get_data () { # {{{
 }
 # }}}
 VCS_INFO_hg_get_data () { # {{{
-    local hgbranch hgbase
+    local hgbranch hgbase file
 
     hgbase=${vcs_comm[basedir]}
-    hgbranch=$(< ${hgbase}/.hg/branch)
+
+    file="${hgbase}/.hg/branch"
+    if [[ -r ${file} ]] ; then
+        hgbranch=$(< ${file})
+    else
+        hgbranch='default'
+    fi
+
     VCS_INFO_formats '' "${hgbranch}" "${hgbase}"
     return 0
 }
@@ -1683,7 +1823,7 @@ VCS_INFO_detect_by_dir() { #{{{
     while [[ ${realbasedir} != '/' ]]; do
         if [[ -n ${vcs_comm[detect_need_file]} ]] ; then
             [[ -d ${basedir}/${dirname} ]] && \
-            [[ -f ${basedir}/${dirname}/${vcs_comm[detect_need_file]} ]] && \
+            [[ -e ${basedir}/${dirname}/${vcs_comm[detect_need_file]} ]] && \
                 break
         else
             [[ -d ${basedir}/${dirname} ]] && break
@@ -1737,7 +1877,7 @@ VCS_INFO_git_detect() { #{{{
 # }}}
 VCS_INFO_hg_detect() { #{{{
     VCS_INFO_check_com hg || return 1
-    vcs_comm[detect_need_file]=branch
+    vcs_comm[detect_need_file]=store
     VCS_INFO_detect_by_dir '.hg'
     return $?
 }
@@ -1907,6 +2047,19 @@ fi
 
 # }}}
 
+# command not found handling {{{
+
+(( ${COMMAND_NOT_FOUND} == 1 )) &&
+function command_not_found_handler() {
+    setopt localoptions no_sh_wordsplit
+    if [[ -x ${GRML_ZSH_CNF_HANDLER} ]] ; then
+        ${GRML_ZSH_CNF_HANDLER} $1
+    fi
+    return 1
+}
+
+# }}}
+
 # {{{ set prompt
 if zrcautoload promptinit && promptinit 2>/dev/null ; then
     promptinit # people should be able to use their favourite prompt
@@ -1971,7 +2124,7 @@ preexec () {
 # adjust title of xterm
     [[ ${NOTITLE} -gt 0 ]] && return 0
     case $TERM in
-        (xterm*|rxvt)
+        (xterm*|rxvt*)
             print -Pn "\e]0;%n@%m: $1\a"
             ;;
     esac
@@ -2195,6 +2348,11 @@ the zsh yet. :)
   "NOTITLE=1  zsh" => disable setting the title of xterms without disabling
                       preexec() and precmd() completely
   "BATTERY=1  zsh" => activate battery status (via acpi) on right side of prompt
+  "COMMAND_NOT_FOUND=1 zsh"
+                   => Enable a handler if an external command was not found
+                      The command called in the handler can be altered by setting
+                      the GRML_ZSH_CNF_HANDLER variable, the default is:
+                      "/usr/share/command-not-found/command-not-found"
 
 A value greater than 0 is enables a feature; a value equal to zero
 disables it. If you like one or the other of these settings, you can
@@ -2257,9 +2415,9 @@ if [[ -r /etc/debian_version ]] ; then
      fi
 
     #a1# Take a look at the syslog: \kbd{\$PAGER /var/log/syslog}
-    alias llog="$PAGER /var/log/syslog"     # take a look at the syslog
+    salias llog="$PAGER /var/log/syslog"     # take a look at the syslog
     #a1# Take a look at the syslog: \kbd{tail -f /var/log/syslog}
-    alias tlog="tail -f /var/log/syslog"    # follow the syslog
+    salias tlog="tail -f /var/log/syslog"    # follow the syslog
 fi
 
 # sort installed Debian-packages by size
@@ -2465,7 +2623,10 @@ grmlcomp() {
 
     # use generic completion system for programs not yet defined; (_gnu_generic works
     # with commands that provide a --help option with "standard" gnu-like output.)
-    compdef _gnu_generic tail head feh cp mv df stow uname ipacsum fetchipac
+    for compcom in cp deborphan df feh fetchipac head hnb ipacsum mv \
+                   pal stow tail uname ; do
+        [[ -z ${_comps[$compcom]} ]] && compdef _gnu_generic ${compcom}
+    done; unset compcom
 
     # see upgrade function in this file
     compdef _hosts upgrade
@@ -2846,6 +3007,17 @@ minimal-shell() {
     exec env -i ENV="/etc/minimal-shellrc" HOME="$HOME" TERM="$TERM" ksh
 }
 
+# a wrapper for vim, that deals with title setting
+#   VIM_OPTIONS
+#       set this array to a set of options to vim you always want
+#       to have set when calling vim (in .zshrc.local), like:
+#           VIM_OPTIONS=( -p )
+#       This will cause vim to send every file given on the
+#       commandline to be send to it's own tab (needs vim7).
+vim() {
+    VIM_PLEASE_SET_TITLE='yes' command vim ${VIM_OPTIONS} "$@"
+}
+
 # make a backup of a file
 bk() {
     cp -a "$1" "${1}_$(date --iso-8601=seconds)"
@@ -2914,10 +3086,6 @@ exit 0;
 for color in BLUE RED GREEN CYAN YELLOW MAGENTA WHITE ; unset $color
 # }}}
 
-# source another config file if present {{{
-xsource "/etc/zsh/zshrc.local"
-# }}}
-
 # "persistent history" {{{
 # just write important commands you always need to ~/.important_commands
 if [[ -r ~/.important_commands ]] ; then
@@ -2986,11 +3154,6 @@ alias CO="./configure"
 #a2# Execute \kbd{./configure --help}
 alias CH="./configure --help"
 
-# http://conkeror.mozdev.org/
-# TODO: I think this should be removed, as conkeror is not a simple extension anymore
-#a2# Run a keyboard driven firefox
-alias conkeror='firefox -chrome chrome://conkeror/content'
-
 # arch/tla stuff
 if check_com -c tla ; then
     #a2# Execute \kbd{tla what-changed --diffs | less}
@@ -3067,11 +3230,6 @@ check_com -c python && alias http="python -m SimpleHTTPServer"
 # Use 'g' instead of 'git':
 check_com g || alias g='git'
 
-# use colors when browsing man pages, but only if not using LESS_TERMCAP_* from /etc/zsh/zshenv:
-if [[ -z "$LESS_TERMCAP_md" ]] ; then
-    [[ -d ~/.terminfo/ ]] && alias man='TERMINFO=~/.terminfo/ LESS=C TERM=mostlike PAGER=less man'
-fi
-
 # check whether Debian's package management (dpkg) is running
 if check_com salias ; then
     #a2# Check whether a dpkg instance is currently running
@@ -3271,11 +3429,8 @@ greph() { history 0 | grep $1 }
 #a2# Execute \kbd{grep -i -{}-color=auto}
 alias GREP='grep -i --color=auto'
 
-# one blank line between each line
-if [[ -r ~/.terminfo/m/mostlike ]] ; then
-    #f5# Watch manpages in a stretched style
-    man2() { PAGER='dash -c "sed G | /usr/bin/less"' TERM=mostlike /usr/bin/man "$@" ; }
-fi
+#f5# Watch manpages in a stretched style
+man2() { PAGER='dash -c "sed G | /usr/bin/less"' command man "$@" ; }
 
 # d():Copyright 2005 Nikolai Weibull <nikolai@bitwi.se>
 # note: option AUTO_PUSHD has to be set