2

In my .zshrc file I have the following lines that parse my current git branch and display it in the terminal, the .zshrc file looks like this:

# Load version control information
autoload -Uz vcs_info
precmd() { vcs_info }

# Set up the prompt (with git branch name)
setopt PROMPT_SUBST
PROMPT='%n in ${PWD/#$HOME/~} ${vcs_info_msg_0_} > '


# Format the vcs_info_msg_0_ variable
zstyle ':vcs_info:git:*' formats '(%b)'

So my terminal ends up looking like this:

me in ~/repos/myrepo (feat/MYISSUE-123/fix-the-broken-stuff) >

I would like to modify the script above so MYISSUE-123 has a different colour to the rest of the branch name.
How can I do that?

mal
  • 3,022
  • 5
  • 32
  • 62
  • 2
    So why vote to close this question? – mal Sep 28 '21 at 07:28
  • I unfortunately don't know zsh but I would try to extract the branch name with `git branch --show-current` then pass it through `sed` to inject the color around the issue. But I'm not sure it's as simple as that. I think that in bash the PROMPT_COMMAND can be set to any script so that you can prepare the variables that PS1 can then use. – Patrick Janser Sep 28 '21 at 08:27
  • 1
    @PatrickJanser The code already does that, the branch name is stored in `$vcs_info_msg_0_`. However, OP wants to colour only *parts* of the branch name. And since this is part of the prompt, a solution should ideally not invoke any external commands to avoid forking a process which slows down the display of the prompt. – Konrad Rudolph Sep 28 '21 at 08:31
  • @mal : As you can see, the votes to close the question were because the question lacks _details and clarity_. For instance, you demonstrate that you know how to get the branch name, but we don't see any code which would attempt to colorize it. We don't know whether you are stuck with the problem of extracting the substring _MYISSUE-123_, or with the problem of colouring it. – user1934428 Sep 29 '21 at 10:18
  • 2
    No offence, but this is ridiculous. I'm stuck with both those things. – mal Sep 29 '21 at 13:16
  • 2
    @user1934428 That’s really reaching. The question is perfectly fine as is. – Konrad Rudolph Sep 29 '21 at 13:36

1 Answers1

1

Try this ... change precmd to:

precmd() {
  vcs_info
  psvar=(${(s:/:)vcs_info_msg_0_})
  # in case there are more than three components:
  psvar[3]=${(j:/:)psvar[3,-1]}  
}

Make sure precmd() is being called prior to each prompt display by adding it to the hook:

autoload -Uz add-zsh-hook
add-zsh-hook precmd precmd

And change PROMPT to:

PROMPT='%n in ${PWD/#$HOME/~} %1v/%F{red}%2v%f/%3v > '

There are some notes about psvar in this answer: https://stackoverflow.com/a/64094551/9307265.
The (s) and (j) parameter expansion flags are documented in the zshexpn man page.

Please let me know if there are any issues.

Gairfowl
  • 2,226
  • 6
  • 9
  • Thank you! It doesn't seem to work right now. so looking at the man page for `zshexpn` the `s` splits the string at the delimiter, the `/` in this case, and the `j` appends everything in the array into a single value. However, in the man page where you have `(s:/:)` it has `(s./.)` changing it doesn't make any difference though. In `PROMPT` this - `%1v` is saying "take variable one from the array"? and so on... and the `%F` and `%f` are encapsulating the formatting? right now the final output looks like this: `me in ~/repos/myrepo /} >` which looks like there is a formatting error somewhere – mal Sep 29 '21 at 14:02
  • OK looks like it should be zero indexed too, like `%0v` .... I'll tweak some things – mal Sep 29 '21 at 14:10
  • 1
    @mal - Thanks for trying it! The items you've noted are in the parts that should have worked :). `(s:/:)` and `(s./.)` are equivalent - the delimiter can be anything as long as it's consistent. That's how it supports splitting on any character, e.g. `s(.:.)`. `%1v` is indeed saying to substitute `psvar[1]`, `%2v` is for `psvar[2]`, etc. - `zsh` is usually 1-indexed thanks to its `csh` roots. And here, `%F` and `%f` are essentially 'start color' and 'stop color'. – Gairfowl Sep 30 '21 at 01:36
  • 1
    After setting up a git repository to test this end-to-end, I found that on my system, `precmd()` was not being invoked. But, `vcs_info_msg_0_` was still being updated - I'm not sure how. I updated the answer to make sure `precmd` is called prior to displaying every prompt. – Gairfowl Sep 30 '21 at 01:38
  • Awesome! Thank you my friend! can I ask why `precmd` is in the `add-zsh-hook` command twice? – mal Sep 30 '21 at 05:21
  • 1
    The first one is the hook name, the second one is the function name. On my system, I named the function `my_precmd()` just to avoid that confusion, so it has `add-zsh-hook precmd my_precmd`. Good luck! – Gairfowl Sep 30 '21 at 05:59