diff --git a/zsh/prompt.zsh b/zsh/prompt.zsh index 39d3716..67a0479 100644 --- a/zsh/prompt.zsh +++ b/zsh/prompt.zsh @@ -1,70 +1,131 @@ -function precmd { +# ===== setopts and misc +# only show RPROMPT on the current prompt +setopt transient_rprompt # only show the rprompt on the current prompt - local TERMWIDTH - (( TERMWIDTH = ${COLUMNS} - 1 )) +# set RPROMPT_INDENT to zero in order to remove the useless space on the bottom +# right of the prompt. +ZLE_RPROMPT_INDENT=0 - ### - # Truncate the path if it's too long. - - PR_FILLBAR="" - PR_PWDLEN="" - - local promptsize=${#${(%):---(%n@%m)---()--}} - local pwdsize=${#${(%):-%~}} - - if [[ "$promptsize + $pwdsize" -gt $TERMWIDTH ]]; then - ((PR_PWDLEN=$TERMWIDTH - $promptsize)) - else - PR_FILLBAR="\${(l.(($TERMWIDTH - ($promptsize + $pwdsize)))..${PR_HBAR}.)}" - fi -} +# ===== set the prompt +zshrc_prompt_precmd() { -function show_battery { - if [[ $HAS_PMSET -eq 1 ]]; then - ~/.zsh/scripts/battery_osx.sh + # regex to remove all zerospace elements. Used to calculate the width of + # the top prompt. + local zero='%([BSUBfksu]|([FB]|){*})' + + # linedrawing characters + local top_left_corner="╭" + local top_right_corner="╮" + local bottom_left_corner="╰" + local bottom_right_corner="╯" + local dash="─" + + # check $TERM and use non unicode symbols if necessary + if [[ $TERM == "linux" ]]; then + top_left_corner="+" + top_right_corner="+" + bottom_left_corner="+" + bottom_right_corner="+" + dash="-" fi -} -function setprompt { - PR_HBAR="─" - - if [[ "$TERM" != "xterm" ]]; then - PR_ULCORNER="╭" - PR_LLCORNER="╰" - PR_LRCORNER="╯" - PR_URCORNER="╮" + # commonly used design elements + local bracket_open="%F{blue}${dash}(%f" + local bracket_close="%F{blue}%)${dash}%f" + local separator="%F{cyan}${dash}%f" + + # current directory, truncated if necessary (WIDTH is replaced later) + local directory="%F{magenta}%WIDTH<..<%~%<<%f" + + # current time (HH:MM) + local time="%F{yellow}%D{%H:%M}%f" + + # username, green for normal users, red for root + local user="%(!.%F{red}.%F{green})%n%f" + + # hostname, underlined if running on a remote system through SSH + local host="%F{green}%m%f" + if [[ -n $SSH_CONNECTION ]]; then + host="%U${host}%u" + fi + + # exitcode in parentheses if not zero + local exitcode="%(?..[%F{red}%?%f])" + + # prompt symbol, $ in cyan for normal users, # in red for root + local symbol="%(!.%F{red}#%f.%F{cyan}>%f)" + + # battery percentage, if acpi is available + local battery_pct= + if type acpi &> /dev/null ; then + battery_pct="$(acpi -b | cut -d, -f2 | sed -e 's/[^0-9]//g')" + fi + + # colorize battery percentage or display status + if [[ $(acpi -a | cut -d':' -f2) == " on-line" ]]; then + battery_pct="charging" + elif [[ $battery_pct -le 20 ]]; then + battery_pct="%F{red}${battery_pct}%%%f" + elif [[ $battery_pct -le 65 ]]; then + battery_pct="%F{yellow}${battery_pct}%%%f" else - PR_ULCORNER="+" - PR_LLCORNER="+" - PR_LRCORNER="+" - PR_URCORNER="+" + battery_pct="%F{green}${battery_pct}%%%f" fi - PR_RESET="%{$terminfo[sgr0]%}" + # prefix characters in first and second line + local top_prefix="%F{cyan}${top_left_corner}%f" + local bottom_prefix="%F{cyan}${bottom_left_corner}%f" - ### - # Finally, the prompt. + # suffix characters in first and second line + local top_suffix="%F{cyan}${top_right_corner}%f" + local bottom_suffix="%F{cyan}${bottom_right_corner}%f" - PROMPT='%F{cyan}$PR_ULCORNER%F{blue}$PR_HBAR(\ -%F{magenta}%$PR_PWDLEN<...<%~%<<\ -%F{blue})$PR_HBAR%F{cyan}$PR_HBAR${(e)PR_FILLBAR}%F{blue}$PR_HBAR(\ -%F{green}%n@%m%F{blue}\ -%F{blue})$PR_HBAR%F{cyan}$PR_URCORNER\ + # combine them to create the prompt + local top_left="" + local top_right="${bracket_open}${time}${bracket_close}" + local bottom_left="${bracket_open}${user}%F{green}@%f${host}${bracket_close}${exitcode}${separator}${symbol}" + local bottom_right= -%F{cyan}$PR_LLCORNER%F{blue}$PR_HBAR(\ -%F{yellow}%D{%H:%M}\ -%F{blue})$PR_HBAR%F{cyan}$PR_HBAR\ -%f ' + # if $battery_pct is empty, just add a vertical line + if [[ -n $battery_pct ]]; then + bottom_right="${separator}${bracket_open}${battery_pct}${bracket_close}" + else + bottom_right="%F{blue}${dash}%f" + fi - RPROMPT='%F{cyan}$PR_HBAR%F{blue}$PR_HBAR(\ -%F{yellow}$(show_battery)\ -%F{blue})$PR_HBAR%F{cyan}$PR_LRCORNER\ -%f' + # calculate width of prompt components + local width_top_prefix=${#${(S%%%)top_prefix//$~zero/}} + local width_top_suffix=${#${(S%%%)top_suffix//$~zero/}} + local width_top_left=${#${(S%%%)top_left//$~zero/}} + local width_top_right=${#${(S%%%)top_right//$~zero/}} - PS2='%F{cyan}$PR_HBAR%F{blue}$PR_HBAR(\ -%F{green}%_ -%F{blue})$PR_HBAR%F{cyan}$PR_HBAR\ -%f ' + # calculate the maximum width of ${top_left}: + # (-4 for brackets, -1 as spacing between top_left and top_right) + local top_left_width_max=$(( + COLUMNS - $width_top_prefix + - $width_top_left - 4 + - 1 + - $width_top_right + - $width_top_suffix + )) + + # truncated directory if necessary + top_left="${bracket_open}${directory/WIDTH/${top_left_width_max}}${bracket_close}${top_left}" + width_top_left=${#${(S%%)top_left//$~zero/}} + + # calculate the width of the top prompt to fill the middle with separators + local width=$(( + COLUMNS - width_top_prefix + - width_top_left + - width_top_right + - width_top_suffix + )) + local top_separator="%F{cyan}${(pl:${width}::$dash:)}%f" + + PROMPT="${top_prefix}${top_left}${top_separator}${top_right}${top_suffix} +${bottom_prefix}${bottom_left} " + + RPROMPT="${bottom_right}${bottom_suffix}" } -setprompt +precmd_functions+=(zshrc_prompt_precmd) diff --git a/zsh/setopt.zsh b/zsh/setopt.zsh index 517e577..f2b4a4c 100644 --- a/zsh/setopt.zsh +++ b/zsh/setopt.zsh @@ -34,9 +34,5 @@ unsetopt menu_complete # do not autoselect the first completion entry # setopt correct # spelling correction for commands # setopt correctall # spelling correction for arguments -# ===== Prompt -setopt prompt_subst # Enable parameter expansion, command substitution, and arithmetic expansion in the prompt -setopt transient_rprompt # only show the rprompt on the current prompt - # ===== Scripts and Functions setopt multios # perform implicit tees or cats when multiple redirections are attempted