3

I have the following in my .zshrc:

setopt PROMPT_SUBST
precmd(){
  echo""
  LEFT="$fg[cyan]$USERNAME@$HOST $fg[green]$PWD"
  RIGHT="$fg[yellow]$(date +%I:%M\ %P)"
  RIGHTWIDTH=$(($COLUMNS-${#LEFT}))
  echo $LEFT${(l:$RIGHTWIDTH:)RIGHT}
}
PROMPT="$ "

This gives me the following screenshot enter image description here

The time part on the right is always not going all the way to the edge of the terminal, even when resized. I think this is due to the $(date +%I:%M\ %P) Anyone know how to fix this?

EDIT: Zoomed in screenshot

Lord_Zane 55
  • 63
  • 10
  • 1
    Please crop your screenshot to just the terminal (it's very hard to see the problem now without enlarging), however nice your background is... – 4ae1e1 Nov 21 '15 at 04:30

1 Answers1

4

While your idea is commendable, the problem you suffer from is that your LEFT and RIGHT contains ANSI escape sequences (for colors), which should be zero-width characters, but are nevertheless counted toward the length of a string if you naively use $#name, or ${(l:expr:)name}.

Also, as a matter of style, you're better off using Zsh's builtin prompt expansion, which wraps a lot of common things people may want to see in their prompts in short percent escape sequences. In particular, there are builtin sequences for colors, so you don't need to rely on nonstandard $fg[blah].

Below is an approximate of your prompt written in my preferred coding style... Not exactly, I made everything super verbose so as to be understandable (hopefully). The lengths of left and right preprompts are calculated after stripping the escape sequences for colors and performing prompt expansion, which gives the correct display length (I can't possibly whip that up in minutes; I ripped the expression off pure).

precmd(){
    local preprompt_left="%F{cyan}%n@%m %F{green}%~"
    local preprompt_right="%F{yellow}%D{%I:%M %p}%f"
    local preprompt_left_length=${#${(S%%)preprompt_left//(\%([KF1]|)\{*\}|\%[Bbkf])}}
    local preprompt_right_length=${#${(S%%)preprompt_right//(\%([KF1]|)\{*\}|\%[Bbkf])}}
    local num_filler_spaces=$((COLUMNS - preprompt_left_length - preprompt_right_length))
    print -Pr $'\n'"$preprompt_left${(l:$num_filler_spaces:)}$preprompt_right"
}

PROMPT="$ "

Edit: In some terminal emulators, printing exactly $COLUMN characters might wrap the line. In that case, replace the appropriate line with

local num_filler_spaces=$((COLUMNS - preprompt_left_length - preprompt_right_length - 1))

End of edit.

This is very customizable, because you can put almost anything in preprompt_left and preprompt_right and still get the correct lengths — just remember to use prompt escape sequence for zero width sequences, e.g., %F{}%f for colors, %B%b for bold, etc. Again, read the docs on prompt expansion: http://zsh.sourceforge.net/Doc/Release/Prompt-Expansion.html.

Note: You might notice that %D{%I:%M %p} expands to things like 11:35 PM. That's because I would like to use %P to get pm, but not every implementation of strftime supports %P. Worst case scenario: if you really want lowercase but %P is not supported, use your original command subsitution $(date +'%I:%M %P').

Also, I'm using %~ instead of %/, so you'll get ~/Desktop instead of /c/Users/johndoe/Desktop. Some like it, some don't. However, as I said, this is easily customizable.

4ae1e1
  • 7,228
  • 8
  • 44
  • 77
  • Thanks Alot! I dont care about the pm/PM and actually like caps better (my system clock uses caps). One thing though. For some reason it is printing to many spaces, and it ends up making a new line. Any idea why? – Lord_Zane 55 Nov 21 '15 at 05:20
  • @Lord_Zane55 Hmm that's kinda weird, but I vaguely remember printing exactly `$COLUMN` spaces would wrap the line on Windows cmd and PowerShell (when I was developing some python library). Could you try to replace the `num_filler_spaces` definition by `local num_filler_spaces=$((COLUMNS - preprompt_left_length - preprompt_right_length - 1))` and see if that helps? If not, could you please link to a new screenshot, and add `print $COLUMNS $preprompt_left_length $preprompt_right_length $num_filler_spaces` to the end of the function and show me the numbers you get? – 4ae1e1 Nov 21 '15 at 05:25
  • Works perfect! Thanks alot!, also the %~ wont work due to me using cywgin (sadly the only way to get zsh on windows). The path is really /cygdrive/c/.... Trying to figure out how to replace /c/users/lord_zane with ~ is what im trying to figure out, im probably going to call a python script as the re module will make it very easy – Lord_Zane 55 Nov 21 '15 at 05:29
  • @Lord_Zane55 By the way, I believe the wrapping behavior you saw might be due to the cursor. There are ANSI escape sequences to hide and unhide the cursor, but it's more trouble, so if you don't care about one dangling space (is there?), then the current solution is fine. – 4ae1e1 Nov 21 '15 at 05:33
  • There's no extra space anymore, adding that -1 fixed it. It looks like my original screenshot but the time is all the way to the right. – Lord_Zane 55 Nov 21 '15 at 05:40
  • @Lord_Zane55 Awesome, good to know. I was worried about one extra space between time and right edge. – 4ae1e1 Nov 21 '15 at 05:41