I'm attempting to add my Buildkite (ci build server) project status to the zsh prompt! I've written a ruby script that pulls the status and puts it into a colon separated file in the following format:
# .buildkite_status
project1: √
project2: x
The √ and x are ansi colour coded.
And I have a prompt that works fine until I add my $ci_build variable/function to the RPROMPT!
At the moment my prompt looks like;
~/.dotfiles » ± master*:3cce1cb
and after the change I want
~/.dotfiles » ± master*:3cce1cb √
The problem I'm facing is the introduction of the ci_build is now wrapping my prompt. after a week of reading docs and tweaking, I'm out of suggestions. I really would love this to work, but would prefer it working correctly.
Here is an image of the problem: https://www.dropbox.com/s/ufj82ipd7bm0o30/Screenshot%202015-06-11%2016.52.11.png?dl=0
build_status() {
current_directory=$(basename $PWD)
var=$(cat ~/.buildkite_status | grep \^$current_directory: | awk -F':' '{print $2}')
echo -n $var | tr '\n' ' '
}
local git_formats="%{${fg_bold[yellow]}%}± %b%c%u:%.7i%{${reset_color}%}"
zstyle ':vcs_info:git*' enable git
zstyle ':vcs_info:git*' check-for-changes true
zstyle ':vcs_info:git*' get-revision true
zstyle ':vcs_info:git*' stagedstr "+"
zstyle ':vcs_info:git*' unstagedstr "*"
zstyle ':vcs_info:git*' formats "$git_formats"
zstyle ':vcs_info:git*' actionformats "%a $git_formats"
precmd() {
vcs_info
build_status
}
zle-keymap-select() { zle reset-prompt; }
zle -N zle-keymap-select
VI_MODE_INDICATOR="%{$fg_bold[red]%}<%{$fg[red]%}<<%{$reset_color%}"
vi_mode_prompt_info() {
echo "${${KEYMAP/vicmd/$VI_MODE_INDICATOR}/(main|viins)/}"
}
local cwd='%{${fg_bold[green]}%}$(prompt_pwd)%{${reset_color}%}'
local usr='%{${fg[yellow]}%}$(user_hostname)%{${reset_color}%} '
local char='%(?,%F{cyan}»,%F{red}»)%f '
local git='${vcs_info_msg_0_}$(git_stash) '
local git_author='$(git author > /dev/null || echo "$(git author) ")'
local vi_mode='$(which vi_mode_prompt_info &> /dev/null && vi_mode_prompt_info) '
local bg_job='%{${fg_bold[black]}%}$(prompt_bg_job)%{${reset_color}%} '
local ci_build='%{$(build_status)%} '
PROMPT=$cwd$usr$char
RPROMPT=$vi_mode$bg_job$git_author$git$ci_build
The issue is caused by the way you include the output of build_status
:
local ci_build='%{$(build_status)%} '
According to the zsh manual
%{...%}
Include a string as a literal escape sequence. The string within the braces should not change the cursor position
zsh assumes that $ci_build
contains only escape sequences and prints out to a length of 0 characters, while it also contains the character showing the status and a space, thus being actually 2 characters longer.
As there is no actual right-alignment in the terminal zsh calculates the position of the right prompt from its perceived length. As it is 2 characters longer then calculated the right prompt wraps over the end of line, placing the cursor on the next line.
The quick fix for this problem is to use %G
inside %{...%}
to tell zsh that there are characters that will be output. %G
stands for one character, for more characters you can either use the appropriate amount of %G
or put the matching number between %
and G
:
local ci_build='%{$(build_status)%2G} '
The cleaner fix would be to keep the ANSI codes (and possibly the special characters you are using) out of the status file and just use zsh features for that.