BASH prompts: Box-drawing characters

xterm_shot2

An xterm session with BASH prompts containing box-drawing characters. The rest of the screen is the output of repeated fortune commands.

I used to be a big user of xterm’s box drawing characters. I hadn’t been aware that they could be used in prompts.

But I recently heard a (probably dated) discussion on how box drawing characters could be used in a command prompt.

I think that’s a great idea, however, the big problem I found was to do it in a way that correctly turn off the drawing so that you could display text again. Otherwise a lot of text ends up looking garbled.

First, let me say that I used a “twtty” example code at Giles Orr’s BASH prompt website which I modified to allow actual box prompts. A clue was provided in the HOWTO here, where they showed, in a very brief way, the entire “catalogue” of “high-bit” ANSI characters, which I pasted into an xterm:

echo -e "�33(0abcdefghijklmnopqrstuvwxyz�33(B"

The high-bit characters are whatever you type in lowercase after you output the ANSI escape sequence “�33(0“, I needed the echo command (echo -e) to get that to work. The output of echo -e can be stored in a string like this:

local box1=`echo -e "�33(0qqqqqqqqqqqqqqqq�33(B"

�33(0 turns on ANSI escapes, while �33(B turns it off. The string “qqqq”… are the characters used to draw a horizontal line. There were some other tweaks I did to his code to become more complete in box characters for a two-line prompt, but it had the side effect of not going all the way across the screen like the original. Adding six characters fixed it, albeit in a kludgy kind of way:

ESC_IN=`echo -e "�33(0"`  # turn on box-drawing
ESC_OUT=`echo -e "�33(B"` # turn off box-drawing

function prompt_command {
    #   Find the width of the prompt:
    TERMWIDTH=${COLUMNS}

    #   Add all the accessories below ...
    local l="${ESC_IN}l${ESC_OUT}"
    local m="${ESC_IN}m${ESC_OUT}"
    local temp="${l}-(${usernam}@${hostnam}:${cur_tty})---(${PWD})--"

    let fillsize=${TERMWIDTH}-${#temp}+6

What I mean by “kludgy” is that I simply added a “6” on the last line above which controls the number of characters required for the first line of the prompt to go across the screen. It’s unlikely that the terminal width will ever need to be less than 6.

I added two variables which are occasionally useful: $ESC_IN for turning on the ANSI feature, and $ESC_OUT for turning it off. Inside the function prompt_command, I added variables $l and $m since his code uses dashes and I wanted the ANSI horizontal lines instead. $l is for the ANSI output for the letter “l”; while $m is for the letter “m” in ANSI. These generate two corners of the box which occur on the far left of the prompt. And they do join up. The $l is used in the next statement below in the form of ${l} to begin making the string $temp. I could have done something with the dashes in this string such as use “${ESC_IN}qqq${ESC_OUT}” in place of “—“, but there were problems if I was too overzealous, so some dashes were left as is.

The main problem was to get a horizontal line in place of the string “——————————————————” which went on indefinitely. Those were replaced by lowercase “q” letters without the ANSI escapes. These were better placed in a statement nearby:

if [ "$fillsize" -gt "0" ]
then
    fill="qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"
    #   It's theoretically possible someone could need more 
    #   dashes than above, but very unlikely!  HOWTO users, 
    #   the above should be ONE LINE, it may not cut and
    #   paste properly
    fill="$ESC_IN${fill:0:${fillsize}}$ESC_OUT"
    newPWD="${PWD}"
fi

where $ESC_IN and $ESC_OUT were used in the next statement below the comments. You can’t put them inside the first $fill assignment, because the second assignment cuts off the end including $ESC_OUT should you attempt to do it that way.