Skip to content
Advertisement

Prompt Expansion ZSH Remove Hostname if entire PROMPT is too long

Currently, my zshrc looks like this

setopt prompt_subst # real time reevaluation of prompt
zmodload zsh/mathfunc # int function
function widthHelper() { echo $(( int(${COLUMNS:-80}) * ${1}/100)) } # calc $1% of prompt
outWidth='$(widthHelper 40)'
inWidth='$(widthHelper 90)'
export PROMPT="%F{cyan}%${outWidth}<◀︎<%f" # truncation based on terminal width
PROMPT+="%(l." # inner truncation group
PROMPT+="%F{cyan}%8>‣>%n%>>%f" # username truncated
PROMPT+="%-${inWidth}(l. %F{blue}%5>‣>%m%>>%f.) " # hostname truncated
PROMPT+=".)" # end truncation
PROMPT+="%F{magenta}%1~%f%<< " # pwd 1 depth
PROMPT+="%# " # privilege group

influenced by this question and my other question

what is currently working as expected

  1. it truncates the hostname and the username to constant values
  2. it dynamically truncates the entire PROMPT based on widthHelper() which allows me to resize my terminal and dynamically truncate the PROMPT

Currently, I have this line working but not in the desired way

PROMPT+="%-${inWidth}(l. %F{blue}%5>‣>%m%>>%f.) " # hostname truncated

what I want

I want to have the displaying of the hostname depend on the length of the entire PROMPT and not just rely on the width of the current terminal COLUMNS.

i.e. I want the hostname to dissapear if I enter a directory with a very long name before I begin to truncate the entire prompt. But I do want both to happen in this order

  1. the hostname would dissapear (this happens but is not dependent on the PROMPT length but on the width of the entire terminal, COLUMNS)
  2. the entire prompt would begin to truncate on the left (this currently works)

example

If I am in a directory ~ then move into a directory with a long name ~/abcdefghijklmnopqrstuvwxyzabcd I want the hostname to dissapear, but what is happening is that my prompt is being truncated first.

william‣ wmbp‣ ~ %                                                                          
william‣ wmbp‣ ~ % cd abcdefghijklmnopqrstuvwxyzabcd                                        
◀︎m‣ wmbp‣ abcdefghijklmnopqrstuvwxyzabcd %                                                  

what I want

william‣ wmbp‣ ~ %                                                                          
william‣ wmbp‣ ~ % cd abcdefghijklmnopqrstuvwxyzabcd                                        
william‣ abcdefghijklmnopqrstuvwxyzabcd %                                                  

If I could make the # hostname truncated line depend on the PROMPT length then I could solve this issue.

tldr

How can I remove part of my PROMPT based on how long my current PROMPT is.

Advertisement

Answer

Ok so I solved my own problem but first I have to say the question was flawed because I am holding the length of the prompt to a solid percentage of the terminal window. So, I can not expect the prompt to do this

william‣ wmbp‣ ~ %                                                                          
william‣ wmbp‣ ~ % cd abcdefghijklmnopqrstuvwxyzabcd                                        
william‣ abcdefghijklmnopqrstuvwxyzabcd %

but what I can do is expect the terminal to do this

william‣ wmbp‣ Desktop %
william‣ wmbp‣ Desktop % cd abcdefghijk
william‣ abcdefghijk %

because the % is aligned from one line to the next.

The way I got to this solution was to use this in my zshrc

LENGTH_OF_USERNAME=8
LENGTH_OF_HOSTNAME=5
# calc $1% of prompt
function termWidthPercentHelper() { echo $(( int(${COLUMNS:-80}) * ${1}/100)) }
function hostNameInPromptHelper() {
    # if you are in the home directory or if you are in a directory with a name
    # that has a length which is less than $1% of the terminal's width
    if [[ ${PWD##*/} == ${HOME##*/} ]] || [[ ${#PWD##*/} -lt $(termWidthPercentHelper $1) ]] then
        echo "%F{blue}%${LENGTH_OF_HOSTNAME}>‣>%m%>>%f "
    fi
}
PROMPT_PERCENTAGE='$(termWidthPercentHelper 30)'
HOST_NAME_IN_PROMPT='$(hostNameInPromptHelper 9)'
# left prompt
export PROMPT="%F{cyan}%${PROMPT_PERCENTAGE}<◀︎<%f" # truncation based on terminal width
PROMPT+='%(l.' # inner truncation group
PROMPT+="%F{cyan}%${LENGTH_OF_USERNAME}>‣>%n%>>%f " # username truncated
PROMPT+="${HOST_NAME_IN_PROMPT}"
PROMPT+='.)' # end truncation
PROMPT+='%F{magenta}%1~%f%<< ' # pwd 1 depth
PROMPT+='%# ' # privilege group

I replaced the old line PROMPT+="%-${inWidth}(l. %F{blue}%5>‣>%m%>>%f.) " # hostname truncated with a function call PROMPT+="${HOST_NAME_IN_PROMPT}". This is so that I can check the length of the current directory, and then either display the hostname or if the current directory is too long then not display the hostname.

things which helped me come to this solution

  1. [[ ${PWD##*/} == ${HOME##*/} ]] returns true if you are in your home directory
  2. ${#PWD##*/} gives the length of the present working directory without calling a subprocess

conclusion

What I wanted to do was not possible if I wanted to keep the entire prompt to a certain percentage of my terminal screen as seen in the previously named widthHelper function call.

I was able to get to a point where my terminal would not display a portion of my PROMPT if I entered a directory with a long name (See definition for hostNameInPromptHelper above). I also tweaked the values for the percentage of my screen that is the prompt (i.e. PROMPT_PERCENTAGE='$(termWidthPercentHelper 30)') and the value set for the percentage of my screen that the length of the directory name can take up before I don’t display the hostname (i.e. HOST_NAME_IN_PROMPT='$(hostNameInPromptHelper 9)'). These values work for me but if you might want to tweak these until you like your prompt.

sources

Advertisement