Подтвердить что ты не робот

Подсчитайте длину видимой пользователем строки для приглашения zsh

Я хочу разместить текущую ветвь git в моей многострочной строке ZSH. Тем не менее, это испортит две линии - я бы хотел, чтобы они выстроились хорошо.


┌─([email protected]:s000)─[master *]────────────────
───(~  )─┐  
└─(127:15:44)──                       ──(Sat,May12)─┘

должен быть:


┌─([email protected]:s000)─[master *]─────────(~  )─┐  
└─(127:15:44)──                       ──(Sat,May12)─┘

Отвод git захватывается из функции oh-my-zsh, git_prompt_info(), которая дает мне ветку, грязный статус и кучу подсказок, чтобы красиво краситься.

Как подсчитать символы, которые будут видимо вставлены в приглашение ZSH, а не escape-последовательности подсказок?

4b9b3361

Ответ 1

Предполагая, что строка с экранированной подсказкой хранится в переменной FOO, это будет считать только видимые пользователем символы:

                                                                                                                                
FOO=$(git_prompt_info)                                                                                                                     
local zero='%([BSUbfksu]|([FK]|){*})'
FOOLENGTH=${#${(S%%)FOO//$~zero/}} 

Это происходит от this .zshrc.

Это грубое объяснение того, почему оно работает, свободно цитируя man zshexpn, раздел PARAMETER EXPANSION. Я не уверен на 100% деталей, поэтому, если вы используете это для разработки своего собственного эквивалента, прочитайте соответствующие разделы man zshall.

Работая с линией FOOLENGTH=${#${(S%%)FOO//$~zero/}}, у нас есть несколько бит. Идти изнутри:

  • $~zero: ~ гарантирует, что zero, который мы определили как '%([BSUbfksu]|([FB]|){*})', рассматривается как шаблон, а не как простая строка.

  • ${(S%%)FOO//$~zero/}: Это соответствует ${name//pattern/repl}:

    Замените максимально возможное совпадение шаблона при расширении имени параметра с помощью строкового repl

    Заметим, что мы не имеем repl; мы заменяем самое длинное совпадение pattern ничем, тем самым удаляя его.
     (S%%)FOO выполняет разложение на FOO с несколькими установленными флагами. Я не совсем понимаю это.

  • ${#${(S%%)FOO//$~zero/}}: ${#spec} будет заменять длину в символах результата подстановки spec, если spec является заменой. В нашем случае spec является результатом подстановки ${(S%%)FOO//$~zero/}; так что это в основном возвращает длину символов в результате регулярного выражения s/zero// на FOO, где zero - это шаблон выше.

Ответ 2

Не знаю, как это сделать со встроенными командами zsh, но информация о цвете может быть удалена с помощью sed (как описано здесь):

sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g"

например.

plain_str=$(git_prompt_info | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g")

Что бы удалить все escape-последовательности из строки. Длина теперь просто:

echo $#plain_str