zsh подсказывает перенос на новую строку после добавления buildstatus

Я пытаюсь добавить статус проекта Buildkite (сервер сборки ci) в приглашение zsh! Я написал ruby-скрипт, который извлекает статус и помещает его в файл, разделенный двоеточием, в следующем формате:

# .buildkite_status
project1: √
project2: x

Символы √ и x имеют цветовую кодировку ansi.

И у меня есть подсказка, которая работает нормально, пока я не добавлю переменную/функцию $ci_build в RPROMPT!

На данный момент моя подсказка выглядит так;

~/.dotfiles »                                         ± master*:3cce1cb

и после изменения я хочу

~/.dotfiles »                                         ± master*:3cce1cb √

Проблема, с которой я столкнулся, заключается в том, что введение ci_build теперь упаковывает мою подсказку. после недели чтения документов и настройки у меня закончились предложения. Я действительно хотел бы, чтобы это работало, но предпочел бы, чтобы оно работало правильно.

Вот изображение проблемы: 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

person mark    schedule 10.06.2015    source источник
comment
Зачем использовать тройную трубу антипаттерна с cat file | grep regex | awk blah, если один awk -F: "/^$current_directory:/ {print \$2}" ~/.buildkite_status позволит избежать двух дорогих форков?   -  person Jens    schedule 10.06.2015
comment
Не уверен, что вы имеете в виду под проблемой, с которой я столкнулся, это введение ci_build, которое теперь обертывает мое приглашение. Пожалуйста, опубликуйте скриншоты.   -  person 4ae1e1    schedule 10.06.2015


Ответы (1)


Проблема вызвана тем, как вы включаете вывод build_status:

local ci_build='%{$(build_status)%} '

Согласно руководству zsh

%{...%}

Включите строку в качестве буквальной управляющей последовательности. Строка в фигурных скобках не должна изменять положение курсора.

zsh предполагает, что $ci_build содержит только escape-последовательности и выводит длину 0 символов, а также содержит символ, показывающий статус, и пробел, поэтому на самом деле он на 2 символа длиннее.

Поскольку в терминале нет фактического выравнивания по правому краю, zsh вычисляет положение правой подсказки на основе ее воспринимаемой длины. Поскольку это на 2 символа длиннее, чем рассчитано, правая подсказка переносится на конец строки, помещая курсор на следующую строку.

Быстрое решение этой проблемы состоит в том, чтобы использовать %G внутри %{...%}, чтобы сообщить zsh, что есть символы, которые будут выведены. %G обозначает один символ, для большего количества символов вы можете либо использовать соответствующее количество %G, либо поместить соответствующее число между % и G:

local ci_build='%{$(build_status)%2G} '

Более чистое исправление состояло бы в том, чтобы убрать коды ANSI (и, возможно, используемые вами специальные символы) из файла состояния и просто использовать для этого функции zsh.

person Adaephon    schedule 19.06.2015