1

I already changed my bash output format to something like this:

enter image description here

which I am very happy with. I achieved this by adding this code to the .bashrc:

set_PS1()
{
    local RESET=$(tput sgr0 )
    local BOLD=$(tput bold )
    local RED=$(tput setaf 1 )
    local GREEN=$(tput setaf 2 )
    local YELLOW=$(tput setaf 3 )
    local BLUE=$(tput setaf 4 )
    local CYAN=$(tput setaf 6 )
local WHOAMI='\u'
local WHERE='\w'
local HOSTNAME='\h'
local TIME='\D{%H:%M:%S}'


 exit_code_prompt() {
    local EXIT_CODE=$?
    local RED=$(tput setaf 1 )
    local GREEN=$(tput setaf 2 )
    if [ $EXIT_CODE -ne 0 ]; then
        echo -e "$RED$BOLD\xE2\x9C\x98 $EXIT_CODE \xE2\x86\x92"  # Red cross mark symbol
    else
        echo -e "$GREEN$BOLD\xE2\x9C\x93 \xE2\x86\x92"  # Green checkmark symbol
    fi
}

local LINE_1="$BOLD$YELLOW$TIME $CYAN$WHOAMI$BLUE@$CYAN$HOSTNAME$RESET$BOLD":" $BLUE$WHERE$RESET"
local LINE_2="$BOLD\$(exit_code_prompt) "$RESET$BOLD' \$: '$RESET


PS1="$LINE_1\n$LINE_2"

unset -f set_PS1

}

set_PS1

My problem was that if I had a comand that is longer than one line it didn't do a linebreak but instead it overwrote the content from the same line (only in visual representation ofc):

enter image description here

Now when I delete the complete command, it deletes a part of the bash prompt as well:

enter image description here

This could be solved by adding \[ and \]:

    local LINE_1="\[$BOLD$YELLOW$TIME $CYAN$WHOAMI$BLUE@$CYAN$HOSTNAME$RESET$BOLD":" $BLUE$WHERE$RESET\]"
    local LINE_2="\[$BOLD\$(exit_code_prompt) "$RESET$BOLD' \$: \]'$RESET

Another problem persists though. When I cycle through the last used commands it deletes the prompt sign $:

enter image description here

how do I solve this issue?

I already looked into using zsh but I didn't want to loose the bash functionality like keyboard shortcuts that I already got used to...

UPDATE: below is my updated code, that still doesn't work:

set_PS1()
{
    local Reset="\\[$(tput sgr0 )\\]"
    local Bold="\\[$(tput bold )\\]"
    local Red="\\[$(tput setaf 1 )\\]"
    local Green="\\[$(tput setaf 2 )\\]"
    local Yellow="\\[$(tput setaf 3 )\\]"
    local Blue="\\[$(tput setaf 4 )\\]"
    local MagentaBG="\\[$(tput setab 5 )\\]"
    local Cyan="\\[$(tput setaf 6 )\\]"
local Whoami='\u'
local Where='\w'
local Hostname='\h'
local Time='\D{%H:%M:%S}'
local Exit_Code="$?"

exit_code_prompt() {
    local Exit_Code="$?"
    local Red="$(tput setaf 1 )"
    local Green="$(tput setaf 2 )"
    if [ $Exit_Code -ne 0 ]; then
        printf "$Red\xE2\x9C\x98 $Exit_Code \xE2\x86\x92 " # Red cross mark symbol
    else
        printf "$Green\xE2\x9C\x93 \xE2\x86\x92 " # Green checkmark symbol
    fi
}

local Line_1="$Bold$Yellow$Time $Cyan$Whoami$Blue@$Cyan$Hostname$Reset$Bold":" $Blue$Where$Reset"
local Line_2="$Bold\$(exit_code_prompt)$Reset$Bold \$: $Reset"

PS1="$Line_1\n$Line_2"

unset -f set_PS1

}

set_PS1

I will have the same problem as before. Text that is longer than one line will appear on the start of the same line and overwrite. Cycling through commands results in either the deletion of a part of the prompt or in an visual bug that shows part of a previous command that is not accessible.

UPDATE 2: The problem definitely lies in the exit_code_prompt function. when i delete it from $Line_2 everything works as expected.

reneas
  • 365

1 Answers1

4

Following @Daniel's advice, use

    local RESET="\\[$(tput sgr0 )\\]"

And similar with all the other colour codes.

From 6.9 Controlling the Prompt in the manual:

\[
    Begin a sequence of non-printing characters. This could be used to
    embed a terminal control sequence into the prompt.

] End a sequence of non-printing characters.


Looping back to your question:

When I cycle through the last used commands it deletes the prompt sign

That's because without the \[ and \] to wrap the control sequences, bash cannot correctly calculate the length of your prompt.

glenn jackman
  • 18,218