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.
Best Answer
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 multilineRPROMPT
(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 variableCOLUMNS
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):precmd_functions
is an array of functions that are executed before displaying a prompt.r
pads the string on the right.%>>
truncates the git information if it's too long to fit on the line.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 inSTUFF
.