7

Does anyone know how to draw lines in between the commands in zsh?

Here is an example with MobaXterm:

enter image description here

14

In order to extend your current PS1 prompt by a preceding horizontal line, you can use one of the following methods. The basic principle is the same but which one works best depends on your terminal emulator, locale setting and font settings.

Print a bunch of minus (-) or underscore (_) characters

setopt promptsubst
PS1=$'${(r:$COLUMNS::_:)}'$PS1

Explanation

  • The option promptsubst enables the substitution of parameters inside the prompt each time the prompt is drawn, in this case COLUMNS.
  • The parameter expansion flag r:$COLUMNS::_: pads the right side of the parameter with underscores (given between the last two : :) until a width of $COLUMNS is reached. As in this case no parameter is given, only the padding is printed.
  • The padding takes up the whole width of the terminal, the original PS1 is automatically wrapped to the next line. So there is no need to add an extra newline. This is also important as explicit newlines may in some cases lead to the prompt overwriting the last line(s) of the output. (In my case this happened when the prompt text before the explicit newline was exactly as long as the terminal was wide.)

This works on every terminal emulator (or console), every locale and every font. But it may not look that good: At least with minuses as there will be gaps between them (----), with undercores it depends on the font. The other methods use different ways to build on that.


Underline with zsh Prompt Escapes for visual effects

setopt promptsubst
PS1=$'%U${(r:$COLUMNS:: :)}%u'$PS1

Explanation:

  • Everything between %U and %u is underlined.
  • print spaces (which will be underlined) instead of underscores

This should work with most terminal emulators, locales and fonts as it just uses underlining. A possible drawback is, that the horizontal line will not be centered but very low on the output line, just above the next line of the prompt.


Line-drawing (aka Box-drawing) using alternate character set

setopt promptsubst
PS1=$'%{\e(0%}${(r:$COLUMNS::q:)}%{\e(B%}'$PS1

Explanation:

  • %{...%} tells zsh to expect only escape codes that do not actually move the cursor
  • \e(0 switches to the alternate character set
  • q maps to a horizontal line in the alternate character set
  • \e(B switches back to the regular character set

This also should work with most terminal emulators (but probably not console), locales and fonts. The thickness of the line seems to vary between fonts and even terminal emulators using the same font (on my Machine with the Terminus font urxvt prints a thin line, while roxterm prints a very thick line).


Box-drawing using Unicode characters

setopt promptsubst
PS1=$'${(r:$COLUMNS::\u2500:)}'$PS1

Explanation

  • use the Unicode character U+2500 ("Box Drawing Light Horizontal", ) for padding.

This obviously requires the terminal emulator to support Unicode characters, a font that has the required character and an UTF-8 locale. But it also provides a few styles of line to chose from, like thick () or double lines (). (see the Official Unicode Consortium code chart for more)

  • Wow... when I was writing my answer I thought, that look too much complicated for zsh... but I haven't looked into the prompt escapes. +1 from me. – mpy Nov 28 '14 at 19:24
  • indeed this works too is much cleaner. Thanks – user52441 Nov 28 '14 at 23:35
  • I am having an issue with this proposal, the line is perfectly displayed but when I press tab for autocompletion the cursor is moving up in the line drawn above, any idea why ? – user52441 Nov 8 '18 at 10:35
  • @user52441 It might be, that the automatic line break due to overlong lines is messing with zsh's ability to know where in the terminal it is supposed to write. It might also be that your TERM variable does not really match your terminal. You can try to add explicit newlines while making the line slightly shorter than the full widt. For example PS1=$'${(r:$COLUMNS - 1::_:)}\n'$PS1 – Adaephon Nov 19 '18 at 10:41
  • @adaephon, thanks for trying to help me but that does not fixes it. I still have the cursor going up on the line drawn before the prompt. – user52441 Nov 20 '18 at 9:36
1

I think the line is coded into the prompt and realized via the underline prompt escape %U:

PS1="%U                         %u
%~ "

where %~ is your usual prompt (check with print $PS1):

enter image description here

More tricky is to make the line as wide as your terminal. The number of characters is stored in $COLUMNS, so we construct a string of an appropriate number of blanks, surrounded by %U/%u:

drawline=""
for i in {1..$COLUMNS}; drawline=" $drawline"
drawline="%U${drawline}%u"

As we want to update the length if the size is altered, we redefine the prompt every time before it is redrawn, which can be accomplished by putting the code in the precmd() function:

precmd() {
   drawline=""
   for i in {1..$COLUMNS}; drawline=" $drawline"
   drawline="%U${drawline}%u"
   PS1="${drawline}
%~ "
}

Et voilà:

enter image description here

  • Thanks a lot this is exactly what I was looking for and it work fine. I just have to find how to change the line color now. – user52441 Nov 28 '14 at 8:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.