![Как исправить цветную обертку приглашений Bash?](https://rvso.com/image/1259391/%D0%9A%D0%B0%D0%BA%20%D0%B8%D1%81%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D1%82%D1%8C%20%D1%86%D0%B2%D0%B5%D1%82%D0%BD%D1%83%D1%8E%20%D0%BE%D0%B1%D0%B5%D1%80%D1%82%D0%BA%D1%83%20%D0%BF%D1%80%D0%B8%D0%B3%D0%BB%D0%B0%D1%88%D0%B5%D0%BD%D0%B8%D0%B9%20Bash%3F.png)
Я определил приглашение bash (используя PROMPT_FUNCTION) следующим образом:
function get_hg_prompt_prefix() {
local APPLIED_COLOR=$1; shift
local UNAPPLIED_COLOR=$1; shift
local ALERT_COLOUR=$1; shift
local TEXTCOLOR=$1; shift
local mercurial_prompt_line="{{patches|join(:)|pre_applied(${APPLIED_COLOR})|post_applied(${TEXTCOLOR})|pre_unapplied(${UNAPPLIED_COLOR})|post_unapplied(${TEXTCOLOR})}\n\r}"
local mercurial_status_prompt="{ ${ALERT_COLOUR}{status}${TEXTCOLOR}}"
echo "$(hg prompt "${mercurial_prompt_line}" 2>/dev/null)$(hg prompt "${mercurial_status_prompt}" 2>/dev/null)"
}
function set_prompt() {
bright='\[[01m\]'
colors_reset='\[[00m\]'
HOSTCOLOR=${colors_reset}='\[[34m\]'
USERCOLOR=${colors_reset}='\[[01m\]'
TEXTCOLOR=${colors_reset}='\[[32m\]'
APPLIED_COLOR=${colors_reset}='\[[32m\]'
UNAPPLIED_COLOR=${colors_reset}='\[[37m\]'
ALERT_COLOUR=${colors_reset}='\[[31m\]'
hg_status="$(get_hg_prompt_prefix $APPLIED_COLOR $UNAPPLIED_COLOR $ALERT_COLOUR $TEXTCOLOR)"
ps1_prefix="${hg_status}$colors_reset($bright$(basename $VIRTUAL_ENV)$colors_reset) "
PROMPTEND='$'
PS1="${ps1_prefix}${USERCOLOR}\u${colors_reset}${TEXTCOLOR}@${colors_reset}${HOSTCOLOR}\h${colors_reset}${TEXTCOLOR} (\W) ${PROMPTEND}${colors_reset} "
}
PROMPT_COMMAND=set_prompt
В общем, это дает мне многострочное приглашение, которое отображает некоторую информацию о состоянии hg, а также мое текущее virtualenv, выглядящее (без цвета) следующим образом:
buggy-wins.patch
! (saas) user@computer (~) $
Проблема в том, что это портит расчет длины приглашения (я думаю!) и вызывает странные проблемы с переносом терминала и размещением курсора. Например, в 80-символьном терминале я вижу вот приглашение (символ, окруженный **, — это местоположение курсора):
~) $ **a**nis) crose@chris-rose (~
В терминалах, достаточно широких для отображения приглашения, перенос строк происходит гораздо раньше, чем следовало бы; вот максимальный текст, который я смог поместить напервыйстрока приглашения в окне терминала шириной 108 символов (снова ** отмечает местоположение моего курсора):
**(**advanis) crose@chris-rose (~) $ sdkfjlskdjflksdjff
Когда строка переносится, она перезаписывает приглашение. Однако вторая строка ввода доходит до края терминала, а затем переносится правильно.
Итак, очевидно, что-то не так с шириной приглашения. Как заставить bash определять длину строки PS1 не по escape-кодам ANSI, а по фактической отображаемой длине приглашения?
решение1
bash
используется \[
\]
для определения «отображаемой длины»: текст между этими двумя экранированными символами считается непечатаемым и не учитывается в общей длине; все остальное учитывается.
Кажется, проблема с вашими переменными: bright='\[[01m\]'
на самом деле не включает символ ESC, поэтому [01m
печатается как обычный текст, но не учитывается в длине. Должно быть '\[\e[01m\]'
. То же самое для всех остальных переменных.
Связанный:
- В Bash вы можете поместить
\$(hg_status)
его$PS1
напрямую, без необходимости в отдельномPROMPT_COMMAND
.