I'd like to put my current git branch into my multi-line ZSH prompt. However, this messes up the two lines - I'd like them to line up nicely.
┌─(simont@charmander:s000)─[master *]────────────────
───(~ )─┐
└─(127:15:44)── ──(Sat,May12)─┘
should be:
┌─(simont@charmander:s000)─[master *]─────────(~ )─┐
└─(127:15:44)── ──(Sat,May12)─┘
The git branch is grabbed from an oh-my-zsh function, git_prompt_info(), which gives me the branch, dirty status, and a bunch of prompt-escapes to color things nicely.
How do I count the characters that will be visibly inserted into the ZSH prompt - not the prompt escape sequences?
Assuming that the prompt-escaped string is stored in a variable FOO, this will count only user-visible characters:
FOO=$(git_prompt_info)
local zero='%([BSUbfksu]|([FK]|){*})'
FOOLENGTH=${#${(S%%)FOO//$~zero/}}
This comes from this .zshrc.
This is a rough explanation of why it works, liberally quoting from man zshexpn, section PARAMETER EXPANSION. I'm not 100% sure of the details, so, if you're using this to develop your own equivalent, read the relevant man zshall sections.
Working from the line FOOLENGTH=${#${(S%%)FOO//$~zero/}}, we've got a number of bits. Going from the inside out:
$~zero: The ~ ensures that zero, which we've defined as '%([BSUbfksu]|([FB]|){*})', is treated as a pattern rather than as a plain string.
${(S%%)FOO//$~zero/}: This matches ${name//pattern/repl}:
Replace the longest possible match of pattern in the expansion of parameter name by string repl
Note that we don't have a repl; we replace the longest possible match of pattern with nothing, thereby removing it.(S%%)FOO conducts an expansion on FOO with several flags set. I don't quite follow it.
${#${(S%%)FOO//$~zero/}}: ${#spec} will substitue the length in characters of the result of the substitution spec, if spec is a substitution. In our case, spec is the result of the substitution ${(S%%)FOO//$~zero/}; so this basically returns the length of characters in the result of the regular expression s/zero// on FOO, where zero is the pattern above.
Not sure how to do this with builtin zsh commands, but color information can be stripped with sed (as documented here):
sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g"
e.g.
plain_str=$(git_prompt_info | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g")
Which would strip all escape sequences from the string. The length is now simply:
echo $#plain_str
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With