You are not logged in.

#1 2014-03-16 18:13:58

karkhaz
Member
Registered: 2014-01-25
Posts: 79

[SOLVED] Fixed-width string in bash/zsh prompt

Hi, I'm trying to create a zsh prompt. Best to show what I would like with an example:

~                            user@hostname
> cd documents

~/documents                  user@hostname
> cd secret_project

~/documents/secret_project   user@hostname
>

Notice that the current directory takes up a fixed width, and if the string is shorter than that width then it is padded with spaces.

I have not been able to achieve fixed width with padding. I have tried the following:

P_CURDIR=$(printf "%-30s" "%~")
PROMPT=$P_CURDIR
PROMPT+=%M

(note that %~ and %M are expanded by zsh into the working directory and hostname, respectively).

But this pads the working directory with 30 spaces always, rather than padding it with the correct number of spaces to ensure constant width. Like this:

~                            user@hostname
> cd documents

~/documents                            user@hostname
> cd secret_project

~/documents/secret_project                            user@hostname
>

Does anybody have any idea on how to achieve a prompt like the first example, as opposed to the second one?

Last edited by karkhaz (2014-03-16 19:50:19)

Offline

#2 2014-03-16 19:21:29

VanillaFunk
Member
From: MA. USA
Registered: 2013-06-10
Posts: 396
Website

Re: [SOLVED] Fixed-width string in bash/zsh prompt

may be way off but have you tried replacing "%-30s" with "%-(30-%)s"  I dont use zsh so I am not sure if it would read that as I would want it to.


archx86_64 : awesomewm
https://github.com/dreemsoul

Remeber to feed the squirrels

Offline

#3 2014-03-16 19:50:03

karkhaz
Member
Registered: 2014-01-25
Posts: 79

Re: [SOLVED] Fixed-width string in bash/zsh prompt

VanillaFunk wrote:

may be way off but have you tried replacing "%-30s" with "%-(30-%)s"

'fraid not, that gives me .zshrc:printf:56: %-(: invalid directive. If it works on bash then it should work on zsh, as the printf command is a bash thing.

I'm going to mark this as solved, as I've found a hacky solution. If somebody has something more elegant, please do share. Else, I hope this is useful to somebody.

PROMPT=%~
DIR_WIDTH=40
for i in {0..$DIR_WIDTH}
do
  PROMPT+=%$DIR_WIDTH(l.. )
done
PROMPT+=%M

Explanation: the construct %n(l.x.y) prints out x if at least n characters have already been printed on the current line; else, it prints y. Thus, in the true case I print nothing, and in the false case I print out a space. Repeating this 40 times after I have already printed out the working directory gives the correct result. More explanation in section 13.3 on this page.

Edit: Just to be clear, the character to the right of the left paren in %$DIR_WIDTH(l.. ) is a lower-case leter 'el', not a number one.

Last edited by karkhaz (2014-03-16 19:52:19)

Offline

#4 2014-03-16 20:50:26

Trent
Member
From: Baltimore, MD (US)
Registered: 2009-04-16
Posts: 990

Re: [SOLVED] Fixed-width string in bash/zsh prompt

printf is not a bash built-in, but it is a zsh built-in. Try referring to the printf binary, /usr/bin/printf.

Offline

#5 2014-03-17 01:41:49

rockin turtle
Member
From: Montana, USA
Registered: 2009-10-22
Posts: 227

Re: [SOLVED] Fixed-width string in bash/zsh prompt

I don't use zsh, so I'm only speculating, but I believe that the "%~" doesn't get expanded during

P_CURDIR=$(printf "%-30s" "%~")

Thus P_CURDIR contains the literal string "%~                            " after that line is executed.  The expansion is performed when you assign P_CURDIR to PROMPT.

Also, printf won't truncate the string to 30 characters.  If %~ expands to more than 30 chars, you will get them all - which may not be what you want.

I believe you can use the 'print' zsh builtin to do what you want. Try this:

P_CURDIR=$(print -P -f "%-30s %s" %~ %M) 
PROMPT=$P_CURDIR

If you want the directory name to be a maximum of 30 characters, you could truncate yourself.  It all depends on which end you want to cut off. To have only the trailing 30 characters, do

P_CURDIR=$(print -P -f "%-30s" %~)
P_CURDIR=${P_CURDIR: -30}
PROMPT="$P_CURDIR %M"

Note that you need the space between the : and the - in 'P_CURDIR=${P_CURDIR: -30}'.

If you want the leading 30 characters, try

P_CURDIR=$(print -P -f "%-30s" %~)
P_CURDIR=${P_CURDIR:0:30}
PROMPT="$P_CURDIR %M"

Offline

Board footer

Powered by FluxBB