5

I've recently been getting really excited about zsh, and making myself an extravagant prompt, but I'm stuck trying to align my RPROMPT. I have an output like this:

    | [14:59:44] git:(master)                           |
    | /home/zoey/.oh-my-zsh                             |
    | yes, zoey? :                           2016-05-26 |

where | represent the terminal edges. What I want is for the date to be vertically aligned with the time; as where it is, it is prone to be overwritten by a long command, whereas the git info is unlikely to get very long.

Is there any way to the vertical displacement of RPROMPT? Preferably something that is beginner-level zsh, as I'm used to bash, but I can copy-paste stuff if needed.

Here's the relevant bit of my .zshrc:

# show all but the last dir in the current path
function trim_pwd
{
    echo $(pwd | sed -e "s:/$::;s:[^/]*$::")
} 
setopt PROMPT_SUBST
# red for error, green for ok
ERRCOL='%(?:%F{green}:%F{red})'
PROMPT='${ERRCOL}[%f%B%F%D{%H:%M:%S}%f%b${ERRCOL}]%f %B$(git_prompt_info)%b
%F{green}%n%f@%F{yellow}%m%f:%F{blue}$(trim_pwd)%B%1/%b%f
%F{magenta}yes, %Bzoey%b?%f : '
RPROMPT='%F%D{%Y-%m-%d}%f'
# update clock per second
TRAPALRM() {
    zle reset-prompt
}
TMOUT=1

If I remove all of the formatting stuff, and just show the plain prompt:

setopt PROMPT_SUBST
PROMPT='[%D{%H:%M:%S}] $(git_prompt_info)
%n@%m:%/
yes, zoey? : '
RPROMPT='%D{%Y-%m-%d}'

Edit: I am now able to handle variable-length plain text and fixed-width colored text with:

ERRCOL="%(?:%F{green}:%F{red})"
() {
    left="${ERRCOL}[%F%B%D{%H:%M:%S}%b${ERRCOL}]%f "
    right="%F%D{%Y-%m-%d}%f"
    local bare_left='[00:00:00] '
    local bare_right='0000-00-00'
    local middle_width=$((${COLUMNS}-1-${#bare_left}-${#bare_right}))
    git_prompt_info=$(git_prompt_info)
    middle=${(r:$middle_width:: :)git_prompt_info}
    PROMPT='${left}${middle}${right}'
    PROMPT+=$'\n : '
}

But the variable-length colored text in git_prompt_info is still counted. I have tried using the invisible substitution from this answer, but it doesn't seem to work, or I'm using it wrong:

right="%F%D{%Y-%m-%d}%f"
local invisible='%([BSUbfksu]|([FBK]|){*})'
local bare_right=${(S)right//$~invisible}
echo ${(%)bare_right}
echo ${(%)right}

prints the same colored line twice, i.e the substitution does nothing.

  • Would you be able to include the configuration you have so far into your question? – forquare May 26 '16 at 7:45
1

The point of RPROMPT is to be on the same line as the command you type. I'm not even sure if you can have a multiline RPROMPT (except by including some cursor motion commands in it). If you want a multiline prompt with something on the right of the first lines, include that in the left prompt. The variable COLUMNS contains the terminal width. Here's one way to do it, which uses a function to rebuild the prompt each time to get more control (I don't see offhand how to pad to the terminal width with only % escapes; it can be done with embedded substitutions but it gets hard to read or extend):

setopt prompt_subst
precmd_prompt () {
  git_prompt_info=${(r:$((COLUMNS-22)):: :)$(git_prompt_info)}
  PROMPT="[%D{%H:%M:%S}] %>>$git_prompt_info %D{%Y-%m-%d}"
  PROMPT+=$'\n%n@%m:%/\nyes, zoey? : '
}
precmd_functions+=(precmd_prompt)

If you want even more control over how the prompt is composed, build it from more pieces. For example, I hard-coded the length of the time and date above. Here's a variant that calculates the widths and pads or truncates the middle part containing the git information accordingly. This time I do the truncation manually to illustrate how it can be done. ${(%):-STUFF} expands prompt sequences in STUFF.

precmd_prompt () {
  PS1_1_left=${(%):-'[%D{%H:%M:%S}] '}
  PS1_1_right=${(%):-' %D{%Y-%m-%d'}
  local middle_width=$((COLUMNS-#PS1_1_left-#PS1_1_right}))
  local git_prompt_info=$(git_prompt_info)
  if ((#git_prompt_info < middle_width)); then
    PS1_1_middle=${(r:$middle_width:: :)git_prompt_info}
  else
    PS1_1_middle=${git_prompt_info:0:$middle_width}
  fi
  PROMPT='${PS1_1_left}${PS1_1_middle}${PS1_1_right}'
  PROMPT+=$'\n%n@%m:%/\nyes, zoey? : '
}
  • While that doesn't work with variable-length text in the prompt, I can use wc to fix that, and use some additional variables. – Zoey Hewll May 27 '16 at 0:14
  • What is the %>> before calling git_prompt_info? – Zoey Hewll May 27 '16 at 0:14
  • @ZoeyHewll This answer on another question showcases how to handle variable text lengths without the need for external tools like wc. – Adaephon May 27 '16 at 9:34
  • @ZoeyHewll See my edit. Don't use wc, just use $#variable to get the length of $variable. – Gilles May 27 '16 at 15:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.