问题
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
zsh.rc
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
回答1:
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.
来源:https://stackoverflow.com/questions/30749223/zsh-prompt-wrapping-to-a-newline-after-adding-buildstatus