Oleg Medvedyev
Oleg Medvedyev

Reputation: 1594

Zsh color inside command substitution

Coloring output of commands in zsh is kind of simple. Consider the following example in zsh prompt:

print -P "%F{cyan}$(date +'%H:%M:%S')$reset"

You get cyan HH:MM:SS as expected. It works in prompt as expected as well. Now suppose I want to color minutes and seconds in a different color. I didn't manage to achieve it using %F{color}, is it possible?

I can make it work using ANSI codes, but even then it works with print and does not work when used as prompt in ~/.zshrc:

print -P "%F{cyan}$(date +'%H:\e[38;5;82m%M:%S')" - works in zsh

RPS1="%F{cyan}$(date +'%H:\e[38;5;82m%M:%S')" as a right prompt gives 17:\e[38;5;82m14:11

What am I missing? How do I escape the color code or even better use zsh %F{color} construct?

Upvotes: 0

Views: 814

Answers (3)

Adaephon
Adaephon

Reputation: 18339

There is no need to use the external command date: Zsh has built-in prompt escapes for displaying date and time:

[…]

%D{string}

string is formatted using the strftime function. See man page strftime(3) for more details.

[…]

So the simple coloring can be achieved with

RPS1='%F{cyan}%D{%H:%M:%S}%f'

In order to have two colors, you can just use two %D{…} blocks and color them differently

RPS1="%F{cyan}%D{%H}:%F{82}%D{%M:%S}"

This can be as complex as you need (want):

RPS1='%F{154}%D{%H}%F{155}:%F{156}%D{%M}%F{157}:%F{158}%D{%S}'

Upvotes: 0

Rene Knop
Rene Knop

Reputation: 1836

Version 1 - Calling date only once:

d=$(date +'%H:%M:%S');h=${d:0:2};ms=${d:3:5};
RPS1="%F{cyan}$h:%F{green}$ms%F{default}"

Version 2 - Calling date twice:

RPS1="%F{cyan}$(date +'%H'):%F{green}$(date +'%M:%S')%F{default}"

Upvotes: 1

hchbaw
hchbaw

Reputation: 5309

It would have some quoting problems.

It could not been used double quoets; the $(date...) part would be expanded, RPS1 would not be updated for each prompts.
It could be unescaped any escape(\e)s. (especially \e[38;5;82m part for date command)

So, for PS-like strings, it would be useful to quote using $'...' forms like this:

setopt promptsubst
RPS1=$'%F{cyan}$(date +"%H:%%{\e[38;5;82m%%}%M:%S")%{\e[0m%}'

If you can find the color index for \e[38;5;82m:

RPS1=$'%F{cyan}$(date +"%H:%%{%%F{82}%%}%M:%S")%{\e[0m%}'

It could be found by some tools like https://en.wikipedia.org/wiki/ANSI_escape_code#Colors


Note: \e[38;5;82m and \e[0m are surrounded with %{...%}.

%{...%}
Include a string as a literal escape sequence. The string within the braces should not change the cursor position. Brace pairs can nest.

--- zshmisc(1), Visual Effects, Prompt Expansion

Note2: setopt promptsubst. without this option, print -P ... nor RPS1=... does not work.

PROMPT_SUBST

If set, parameter expansion, command substitution and arithmetic expansion are performed in prompts. Substitutions within prompts do not affect the command status.

--- zshoptions(1), PROMPT_SUBST, zsh options

setopt promptsubst
print -P $'%F{cyan}$(date +"%H:%%{\e[38;5;82m%%}%M:%S")%{\e[0m%}'
;# => 23:54:18

PS: %F{color} constructs would be easier for copy-pasting variables with dumping them on screen.

> print $RPS1 ;# this output could not been used for copy-pasting
%F{cyan}$(date +"%H:%%{%%}%M:%S")%{%}
> print $RPS1 | cat -v ;# this either (but close to)
%F{cyan}$(date +"%H:%%{^[[38;5;82m%%}%M:%S")%{^[[0m%}

Upvotes: 2

Related Questions