Add zsh to ignored commands for the prompt bell
[zsh.git] / .zsh / functions / prompt_ganneff_setup
index 907a1ce..e9f18bf 100644 (file)
@@ -6,7 +6,7 @@
 #   - The "design" is taken from Phil!'s ZSH prompt, as found on
 #     http://aperiodic.net/phil/prompt/
 #
-#   - The technic using zstyle is inspired by the prompt as used by
+#   - The tech using zstyle is inspired by the prompt as used by
 #     the grml-live system <http://grml.org>, see
 #     http://git.grml.org/?p=grml-etc-core.git;a=summary for details
 #     on theirs.
@@ -53,7 +53,9 @@ prompt_ganneff_help () {
     The available items are: at, battery, change-root, date, history,
     host, jobs, newline, path, percent, rc, rc-always, shell-level,
     time, user, vcs, ulcorner, llcorner, urcorner, lrcorner, line, pts,
-    openbracket, closebracket, pipe, space, flexline
+    privileges, openparentheses, closeparentheses, openbracket,
+    closebracket, openbraces, closebraces, openanglebracket,
+    closeanglebracket, colon, pipe, space, flexline
 
     Most of those should be self-explanatory, some may need more:
      line     - Draws a single line character
@@ -64,22 +66,47 @@ prompt_ganneff_help () {
                 Only works in a two-line prompt in the upper line, that
                 is, a newline MUST appear in the setup!
 
-    The actual configuration is done via zsh's \`zstyle' mechanism. The
-    context, that is used while looking up styles is:
+    Should they not fit your need, there is an easy way to have the
+    prompt include basically anything you want. Just define your own
+    items. For that you simply define them inside the
+    ':prompt:ganneff:extra:' namespace.
+
+    Example: To have the prompt include the value of the variable
+    \$FOOBAR, in red and have the variable updated by the function
+    jj_foobar, use the following:
+
+       zstyle ':prompt:ganneff:extra:foobar' pre '${PR_RED}'
+       zstyle ':prompt:ganneff:extra:foobar' post '${PR_NO_COLOR}'
+       zstyle ':prompt:ganneff:extra:foobar' token '$FOOBAR'
+       zstyle ':prompt:ganneff:extra:foobar' precmd jj_foobar
+
+    Now you can add the token \`foobar' to the list of items and voila,
+    your own stuff appears.
+
+    Note that the function part only works in zsh 4.3.5 or later (I've
+    been to lazy to replace add-zsh-hook with something for the older
+    versions).
+
+
+    The configuration of the predefined items can also be changed using
+    zsh's \`zstyle' mechanism. The context, that is used while looking
+    up styles is:
 
         ':prompt:ganneff:<left-or-right>:<full-or-small>:<subcontext>'
 
-    Here <left-or-right> is either \`left' or \`right', signifying whether the
-    style should affect the left or the right prompt. <full-or-small> is
-    either \`full' or \`small' and only valid in the item selection,
-    signifying wether the item list should affect the full length or
-    the "small terminal" prompt. As "small terminal" prompt does not
-    display the right side prompt, <full-or-small> has no effect on the
-    right side prompt.
+    Here <left-or-right> is either \`left' or \`right', signifying
+    whether the style should affect the left or the right prompt.
+
+    <full-or-small> is either \`full' or \`small' and only valid in the
+    item selection, signifying wether the item list should affect the
+    full length or the "small terminal" prompt. As "small terminal"
+    prompt does not display the right side prompt, <full-or-small> has
+    no effect on the right side prompt.
+
     <subcontext> is either \`setup' or 'items:<item>', where \`<item>'
     is one of the available items.
 
-    The styles available under ':prompt:ganneff:':
+    The styles/settings available under ':prompt:ganneff:':
 
         - vcs_info (boolean): If \`true' (the default), use \`vcs_info'.
 
@@ -107,6 +134,8 @@ prompt_ganneff_help () {
         - nicelines (boolean): If \`true' (the default), use special
           magic to draw nice lines and corners. Might not work on every
           terminal. If false, draws using plain ascii characters.
+          Linux console also seems to identify itself as if it could,
+          but then doesn't do drawing right (not in our way at least).
 
         - battery (string): If \`none' then no battery function at all.
           If either \`ibam' or \`acpi' then use those tools to gather
@@ -120,23 +149,37 @@ prompt_ganneff_help () {
           accordingly. Default (left): rc change-root user at host path vcs
           percent; Default (right): sad-smiley
 
-    Available styles in 'items:<item>' are: pre, post. These are strings that
-    are inserted before (pre) and after (post) the item in question. Thus, the
-    following would cause the user name to be printed in red instead of the
-    default blue:
+    Note that both, nicelines and colors are forced to false in case the
+    TERM variable is set to dumb.
+
+    Available styles in 'items:<item>' are: pre, post, token and precmd.
+    Pre and Post are strings that are inserted before (pre) and after
+    (post) the item in question. Token is the token itself that gets
+    inserted into PS1. Thus, the following would cause the
+    user name to be printed in red instead of the default blue:
 
         zstyle ':prompt:ganneff:*:items:user' pre '\${PR_RED}'
 
-    Note, that the \`post' style may remain at its default value, because its
-    default value is '\${PR_NO_COLOR}', which turns the foreground text
-    attribute off (which is exactly, what is still required with the new
-    \`pre' value).
+    and
+
+        zstyle ':prompt:ganneff:*:items:date' token '%D{%Y-%m-%d [d:%j/w:%V]}'
+
+    will output a very different date token compared with the default
+    definition of '%D{%Y-%m-%d}'.
+
+    Note, that in the above example the \`post' style may remain at its
+    default value, because its default value is '\${PR_NO_COLOR}', which
+    turns the foreground text attribute off (which is exactly, what is
+    still required with the new \`pre' value).
 
     Possible values for the colors: \${PR_XXX} and \${PR_BOLD_XXX} with
-    XXX replaced with one of: RED GREEN YELLOW BLUE MAGENTA CYAN WHITE
+    XXX replaced with one of: RED GREEN YELLOW BLUE MAGENTA CYAN WHITE BLACK.
     \${PR_NO_COLOR} resets color.
     Using the \${PR_XXX} values instead of zsh's internal \%F{xxx} allows
-    the style to turn off colors to work.
+    the usage of the colors style to turn of prompt colors easily.
+
+    Last note: You really want to have "setopt promptsubst", otherwise you
+    won't like this prompt.
 __EOF0__
 }
 
@@ -144,20 +187,37 @@ prompt_ganneff_setup () {
     emulate -L zsh
     setopt nolocaltraps
 
+    # We forcefully overwrite colors and nicelines setting for a dumb
+    # terminal.
+    if [[ "$TERM" == "dumb" ]]; then
+        zstyle ':prompt:ganneff' colors false
+        zstyle ':prompt:ganneff' nicelines false
+    fi
+
     # See if we can and should use extended characters to look nicer.
-    if zstyle -t ':prompt:ganneff' nicelines && [[ "$TERM" != dumb ]] \
-        && [[ "$TERM" != "linux" ]]; then
-        typeset -A altchar
-        set -A altchar ${(s..)terminfo[acsc]}
-        # Some stuff to help us draw nice lines
-        PR_SET_CHARSET="%{$terminfo[enacs]%}"
-        PR_SHIFT_IN="%{$terminfo[smacs]%}"
-        PR_SHIFT_OUT="%{$terminfo[rmacs]%}"
-        PR_HBAR=${altchar[q]:--}
-        PR_ULCORNER=${altchar[l]:--}
-        PR_LLCORNER=${altchar[m]:--}
-        PR_LRCORNER=${altchar[j]:--}
-        PR_URCORNER=${altchar[k]:--}
+    if zstyle -t ':prompt:ganneff' nicelines; then
+        if [[ $(locale charmap) == "UTF-8" ]]; then
+            PR_SET_CHARSET=""
+            PR_SHIFT_IN=""
+            PR_SHIFT_OUT=""
+            PR_HBAR="─"
+            PR_ULCORNER="┌"
+            PR_LLCORNER="└"
+            PR_LRCORNER="┘"
+            PR_URCORNER="┐"
+        else
+            typeset -A altchar
+            set -A altchar ${(s..)terminfo[acsc]}
+            # Some stuff to help us draw nice lines
+            PR_SET_CHARSET="%{$terminfo[enacs]%}"
+            PR_SHIFT_IN="%{$terminfo[smacs]%}"
+            PR_SHIFT_OUT="%{$terminfo[rmacs]%}"
+            PR_HBAR=${altchar[q]:--}
+            PR_ULCORNER=${altchar[l]:--}
+            PR_LLCORNER=${altchar[m]:--}
+            PR_LRCORNER=${altchar[j]:--}
+            PR_URCORNER=${altchar[k]:--}
+        fi
     else
         PR_SET_CHARSET=""
         PR_SHIFT_IN=""
@@ -169,18 +229,35 @@ prompt_ganneff_setup () {
         PR_URCORNER=""
     fi
 
-    if zstyle -t ':prompt:ganneff' colors && [[ "$TERM" != dumb ]]; then
+    if zstyle -t ':prompt:ganneff' colors; then
         if [[ -n "${BLUE}" ]] && [[ -n "${YELLOW}" ]]; then
             # Two defined, so we assume someone already defined themself
             # the colors. We just use them and not setup our own.
-            for color in RED GREEN YELLOW BLUE MAGENTA CYAN WHITE; do
-                eval PR_$color="%{${(P)color}%}"
-                eval PR_BOLD_$color="%{$terminfo[bold]${(LP)color}%}"
+            for color in RED GREEN YELLOW BLUE MAGENTA CYAN WHITE BLACK GREY; do
+                eval PR_$color='%{${(P)color}%}'
+                eval PR_BOLD_$color='%{$terminfo[bold]${(LP)color}%}'
             done
             PR_NO_COLOR="%{${reset_color}%}"
         else
             # Seems like colors are not defined, so set them up
-            docolors
+            # This duplicates docolors from 01_Terminfo.zsh, but is here to have
+            # prompt_ganneff_setup not require anything else from my dotfiles
+            if autoload -Uz colors && colors 2>/dev/null ; then
+                for COLOR in RED GREEN YELLOW BLUE MAGENTA CYAN WHITE BLACK GREY; do
+                    eval PR_$COLOR='%{$fg_no_bold[${(L)COLOR}]%}'
+                    eval PR_BOLD_$COLOR='%{$fg_bold[${(L)COLOR}]%}'
+                done
+                eval PR_NO_COLOR='%{$reset_color%}'
+            else
+                PR_BLUE=$'%{\e[1;34m%}'
+                PR_RED=$'%{\e[1;31m%}'
+                PR_GREEN=$'%{\e[1;32m%}'
+                PR_CYAN=$'%{\e[1;36m%}'
+                PR_WHITE=$'%{\e[1;37m%}'
+                PR_MAGENTA=$'%{\e[1;35m%}'
+                PR_YELLOW=$'%{\e[1;33m%}'
+                PR_NO_COLOR=$'%{\e[0m%}'
+            fi
         fi
     else
         PR_BLUE=''
@@ -197,7 +274,7 @@ prompt_ganneff_setup () {
     # The secondary prompt, printed when the shell needs more
     # information to complete a command. %_ displays any shell constructs
     # or quotation marks which are currently being processed.
-    if zstyle -t ':prompt:ganneff' colors && [[ "$TERM" != dumb ]]; then
+    if zstyle -t ':prompt:ganneff' nicelines; then
         PS2='${PR_CYAN}${PR_SHIFT_IN}${PR_HBAR}${PR_BLUE}${PR_HBAR}${PR_SHIFT_OUT}\
 (${PR_GREEN}%_${PR_BLUE})\
 ${PR_SHIFT_IN}${PR_HBAR}${PR_CYAN}${PR_HBAR}${PR_SHIFT_OUT}${PR_NO_COLOR} '
@@ -207,7 +284,11 @@ ${PR_SHIFT_IN}${PR_HBAR}${PR_CYAN}${PR_HBAR}${PR_SHIFT_OUT}${PR_NO_COLOR} '
     # selection prompt used within a select loop.
     PS3='?# '
     # the execution trace prompt (setopt xtrace). default: '+%N:%i>'
-    PS4='+%N:%i:%_> '
+    # Not changed if the option xtrace is on, assuming that a trace prompt is then
+    # already defined.
+    if [[ ${options[xtrace]} == off ]]; then
+        PS4='+%N:%i:%_> '
+    fi
 
     if zstyle -t ':prompt:ganneff' vcs_info && \
         is439 && autoload -Uz vcs_info && vcs_info; then
@@ -236,35 +317,44 @@ ${PR_SHIFT_IN}${PR_HBAR}${PR_CYAN}${PR_HBAR}${PR_SHIFT_OUT}${PR_NO_COLOR} '
         ganneff_prompt_token_default
 
     ganneff_prompt_pre_default=(
-        at                ''
-        battery           ' '
-        change-root       ''
-        date              '${PR_BLUE}'
-        history           '${PR_GREEN}'
-        host              '${PR_RED}'
-        jobs              '${PR_CYAN}'
-        newline           ''
-        path              '${PR_MAGENTA}'
-        percent           ''
-        rc                '${PR_RED}'
-        rc-always         ''
-        shell-level       '${PR_RED}'
-        time              '${PR_BLUE}'
-        user              '${PR_BLUE}'
-        vcs               ''
-        ulcorner          '${PR_SHIFT_IN}'
-        llcorner          '${PR_SHIFT_IN}'
-        urcorner          '${PR_SHIFT_IN}'
-        lrcorner          '${PR_SHIFT_IN}'
-        line              '${PR_SHIFT_IN}'
-        pts               ''
-        openbracket       ''
-        closebracket      ''
-        pipe              ''
-        space             ''
-        flexline          '${PR_SHIFT_IN}'
+        at                 ''
+        battery            ' '
+        change-root        ''
+        date               '${PR_BLUE}'
+        history            '${PR_GREEN}'
+        host               '${PR_RED}'
+        jobs               '${PR_CYAN}'
+        newline            ''
+        path               '${PR_MAGENTA}'
+        percent            ''
+        rc                 '${PR_RED}'
+        rc-always          ''
+        shell-level        '${PR_RED}'
+        time               '${PR_BLUE}'
+        user               '${PR_BLUE}'
+        vcs                ''
+        ulcorner           '${PR_SHIFT_IN}'
+        llcorner           '${PR_SHIFT_IN}'
+        urcorner           '${PR_SHIFT_IN}'
+        lrcorner           '${PR_SHIFT_IN}'
+        line               '${PR_SHIFT_IN}'
+        pts                ''
+        privileges         ''
+        openparentheses    ''
+        closeparentheses   ''
+        openbracket        ''
+        closebracket       ''
+        openbraces         ''
+        closebraces        ''
+        openanglebracket   ''
+        closeanglebracket  ''
+        pipe               ''
+        space              ''
+        colon              ''
+        flexline           '${PR_SHIFT_IN}'
     )
 
+
     ganneff_prompt_post_default=(
         at                ''
         battery           ''
@@ -288,10 +378,18 @@ ${PR_SHIFT_IN}${PR_HBAR}${PR_CYAN}${PR_HBAR}${PR_SHIFT_OUT}${PR_NO_COLOR} '
         lrcorner          '${PR_SHIFT_OUT}'
         line              '${PR_SHIFT_OUT}'
         pts               ''
+        privileges        ''
+        openparentheses   ''
+        closeparentheses  ''
         openbracket       ''
         closebracket      ''
+        openbraces        ''
+        closebraces       ''
+        openanglebracket  ''
+        closeanglebracket ''
         pipe              ''
         space             ''
+        colon             ''
         flexline          '${PR_SHIFT_OUT}'
     )
 
@@ -305,7 +403,7 @@ ${PR_SHIFT_IN}${PR_HBAR}${PR_CYAN}${PR_HBAR}${PR_SHIFT_OUT}${PR_NO_COLOR} '
         jobs              '[%j running job(s)] '
         newline           $'\n'
         path              '%40<..<%~%<<'
-        percent           '% # '
+        percent           '%# '
         rc                '%(?..%? )'
         rc-always         '%?'
         shell-level       '%(2L.%L.)'
@@ -317,11 +415,19 @@ ${PR_SHIFT_IN}${PR_HBAR}${PR_CYAN}${PR_HBAR}${PR_SHIFT_OUT}${PR_NO_COLOR} '
         urcorner          '${PR_URCORNER}'
         lrcorner          '${PR_LRCORNER}'
         line              '${PR_HBAR}'
-        pts               ':%y'
-        openbracket       '('
-        closebracket      ')'
+        pts               '%y'
+        privileges        '%#'
+        openparentheses   '('
+        closeparentheses  ')'
+        openbracket       '['
+        closebracket      ']'
+        openbraces        '{'
+        closebraces       '}'
+        openanglebracket  '<'
+        closeanglebracket '>'
         pipe              '|'
         space             ' '
+        colon             ':'
         flexline          'PR_FLEXLINE'
     )
 
@@ -339,6 +445,31 @@ ${PR_SHIFT_IN}${PR_HBAR}${PR_CYAN}${PR_HBAR}${PR_SHIFT_OUT}${PR_NO_COLOR} '
 
     functions[TRAPWINCH]="${functions[TRAPWINCH]//prompt_ganneff_winch}
         prompt_ganneff_winch"
+
+    # Should we "ring the bell" when a command finishes?
+    zstyle -s ':prompt:ganneff' longbell _prompt_ganneff_belltime || \
+        _prompt_ganneff_belltime=600
+    if [[ ${_prompt_ganneff_belltime} -gt 0 ]]; then
+        # New shell, initialize the timestamp once
+        _prompt_ganneff_timestamp=${EPOCHSECONDS}
+        typeset -ga _prompt_ganneff_ignore
+        zstyle -a ':prompt:ganneff' bell_ignore _prompt_ganneff_ignore || \
+            _prompt_ganneff_ignore=( '$EDITOR' '$PAGER' sleep man ssh zsh )
+        # In case the commands to ignore include variables (say $EDITOR), we want to
+        # store them once as variable - and once the variable expanded.
+        for (( i = 1; i <= ${#_prompt_ganneff_ignore}; i++ )) do
+            if (( ${${_prompt_ganneff_ignore[$i]}[(i)$]} <= ${#_prompt_ganneff_ignore[$i]} )); then
+                _prompt_ganneff_ignore+=(${(e)${_prompt_ganneff_ignore[$i]}})
+            fi
+        done
+        add-zsh-hook preexec prompt_ganneff_preexec
+    fi
+}
+
+# right before we begin to execute something, store the time it started at
+prompt_ganneff_preexec() {
+       _prompt_ganneff_timestamp=${EPOCHSECONDS}
+       _prompt_ganneff_lastcmd=${2}
 }
 
 prompt_ganneff_precmd () {
@@ -346,36 +477,54 @@ prompt_ganneff_precmd () {
     setopt nolocaltraps
 
     zstyle -t ':prompt:ganneff' vcs_info && vcs_info
-    local -a left_items right_items
-    left_items=(ulcorner line openbracket user at host pts closebracket line history flexline
-                         openbracket path closebracket line urcorner newline
-                llcorner line rc openbracket time closebracket line vcs line change-root pipe space)
+    local -a left_items right_items drop_words
+
+    left_items=(ulcorner line openparantheses user at host colon pts closeparantheses line history
+        line shell-level line flexline openparentheses path closeparentheses line urcorner newline
+        llcorner line rc openparentheses time closeparentheses line vcs line change-root pipe space)
     PR_PS1=""; nomore=0
     ganneff_prompt_addto PS1 full "${left_items[@]}"
     if zstyle -T ":prompt:ganneff:right:setup" use-rprompt; then
-        right_items=(space pipe line openbracket date closebracket line lrcorner)
+        right_items=(pipe line openparentheses date closeparentheses line lrcorner)
         ganneff_prompt_addto RPS1 full "${right_items[@]}"
     fi
 
     # Now a kind-of-hack to reduce the prompt when we run out of space.
     promptsize=${#PR_PS1}
     if [[ ${promptsize} -lt ${TERMWIDTH} ]]; then
-        # the q here should be ${PR_HBAR}, but for some reason zsh didn't like me,
-        # so meh
-        if zstyle -t ':prompt:ganneff' nicelines && [[ "$TERM" != dumb ]] \
-            && [[ "$TERM" != "linux" ]]; then
-            PR_FLEXLINE="${(l.(($TERMWIDTH - $promptsize ))..q.)}"
-        else
-            PR_FLEXLINE="${(l.(($TERMWIDTH - $promptsize ))..-.)}"
-        fi
+        PR_FLEXLINE=${${(el.(($TERMWIDTH - $promptsize ))..X.)}//X/$PR_HBAR}
     else
         # Small size prompt is needed
-        left_items=(ulcorner line openbracket user at host closebracket line openbracket path closebracket newline
-            llcorner line rc openbracket time closebracket line vcs line pipe space)
+        left_items=(ulcorner line openparentheses user at host closeparentheses line openparentheses
+            path closeparentheses newline
+            llcorner line rc openparentheses time closeparentheses line vcs line pipe space)
         ganneff_prompt_addto PS1 small "${left_items[@]}"
         # And with a small prompt, we don't show the right size at all.
         RPS1=""
     fi
+
+    # Should we "ring the bell" when a command finishes?
+    if (( _prompt_ganneff_timestamp )); then
+        ran_long=$(( ${EPOCHSECONDS} - ${_prompt_ganneff_timestamp} >= ${_prompt_ganneff_belltime} ))
+        if (( ran_long )); then
+            has_ignored_cmd=0
+            drop_words=(builtin command nocorrect noglob)
+            for cmd in ${(s:;:)_prompt_ganneff_lastcmd//|/;}; do
+                words=(${(z)cmd})
+                util=${words[1]}
+                if (( ${drop_words[(i)$util]} <= ${#drop_words} )); then
+                    util=${words[2]}
+                fi
+                if (( ${_prompt_ganneff_ignore[(i)$util]} <= ${#_prompt_ganneff_ignore} )); then
+                    has_ignored_cmd=1
+                    break
+                fi
+            done
+            if (( ! ${has_ignored_cmd} )); then
+                print -n "\a"
+            fi
+        fi
+    fi
 }
 
 prompt_ganneff_length () {
@@ -407,7 +556,7 @@ ganneff_prompt_addto () {
     emulate -L zsh
     local target="$1"
     local size="$2"
-    local lr it apre apost new v
+    local lr it apre apost new v prefunc
     local -a items
     shift
     shift
@@ -417,11 +566,22 @@ ganneff_prompt_addto () {
     typeset -g "${target}="
     for it in "${items[@]}"; do
         zstyle -s ":prompt:ganneff:${lr}:items:$it" pre apre \
+            || zstyle -s ":prompt:ganneff:extra:$it" pre apre \
             || apre=${ganneff_prompt_pre_default[$it]}
         zstyle -s ":prompt:ganneff:${lr}:items:$it" post apost \
+            || zstyle -s ":prompt:ganneff:extra:$it" post apost \
             || apost=${ganneff_prompt_post_default[$it]}
         zstyle -s ":prompt:ganneff:${lr}:items:$it" token new \
+            || zstyle -s ":prompt:ganneff:extra:$it" token new \
             || new=${ganneff_prompt_token_default[$it]}
+
+        # Now check if there is the wish for a precmd function and if so,
+        # run it
+        zstyle -s ":prompt:ganneff:extra:$it" precmd prefunc
+        if [[ -n "${prefunc}" ]]; then
+            ${prefunc} || true
+        fi
+
         typeset -g "${target}=${(P)target}${apre}"
         # Store the expanded value in PR_PS1, as we use that for length calculations
         [[ $it == "newline" ]] && nomore=1
@@ -456,8 +616,8 @@ ganneff_prompt_addto () {
 prompt_ganneff_battery() {
     zstyle -s ':prompt:ganneff' battery pr_battery
     case $pr_battery in
-           ibam)
-                   local ACPIDATA=$(ibam --percentbattery 2>/dev/null || echo "")
+        ibam)
+            local ACPIDATA=$(ibam --percentbattery 2>/dev/null || echo "")
             PERCENT=${${ACPIDATA[(f)1]}[(w)-2]}
             ;;
         acpi)
@@ -479,4 +639,10 @@ prompt_ganneff_battery() {
     fi
 }
 
+is439(){
+    [[ $ZSH_VERSION == 4.3.<9->* || $ZSH_VERSION == 4.<4->* \
+                                 || $ZSH_VERSION == <5->* ]] && return 0
+    return 1
+}
+
 prompt_ganneff_setup "$@"