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:This comes from this
.zshrc.This is a rough explanation of why it works, liberally quoting from
man zshexpn, sectionPARAMETER EXPANSION. I’m not 100% sure of the details, so, if you’re using this to develop your own equivalent, read the relevantman zshallsections.Working from the line
FOOLENGTH=${#${(S%%)FOO//$~zero/}}, we’ve got a number of bits. Going from the inside out:$~zero: The~ensures thatzero, 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}:Note that we don’t have a
repl; we replace the longest possible match ofpatternwith nothing, thereby removing it.(S%%)FOOconducts an expansion onFOOwith several flags set. I don’t quite follow it.${#${(S%%)FOO//$~zero/}}:${#spec}will substitute the length in characters of the result of the substitutionspec, ifspecis a substitution. In our case,specis the result of the substitution${(S%%)FOO//$~zero/}; so this basically returns the length of characters in the result of the regular expressions/zero//onFOO, wherezerois the pattern above.