Count length of user-visible string for zsh prompt

zsh

Solution

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 substitute 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.

Problem

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?

Original source