Run lolcat after each command

aliasbashterminal

I'm trying to add an alias for lolcat that will invoke after each command put into the terminal.

I only know how to add it to select items, anyone know how to just make it a standard output?

enter image description here

Best Answer

UPDATE

I put my implementation here with install instructions:

https://github.com/dosentmatter/rainbow-bash-prompt

It uses the C implementation of lolcat but I modified it a little to make it psuedo-random.

OLD ANSWER

Here is how I did it. Add this to your .bashrc:

PS1_colorless=${PS1:-'\h:\W \u\$ '}

ESC=$(echo -e '\033')
SOH=$(echo -e '\001')
STX=$(echo -e '\002')
PS1_color_wrap='s/'$ESC'\\[[[:digit:];]*m/'$SOH'&'$STX'/g'

PS1="\$(lolcat -f <<< \"$PS1_colorless\" | sed '$PS1_color_wrap')"

It works by running lolcat dynamically on $PS1_colorless and doing a sed to add in control characters so line wrapping works correctly.

It takes a little less than 200 milliseconds to run. So it might be too slow for you. Here is an example I timed:

ruby lolcat time

I chose to use PS1 and not PROMPT_COMMAND because I wanted to be able to use the bash prompt escape sequences such as \h, \W, etc. which wouldn't be possible with PROMPT_COMMAND since I need to pass it to PS1 for expansion before running lolcat. You can use alternatives like ${HOSTNAME%%.*} to imitate the behavior of \h but I don't think you can do it for something like

\#     the command number of this command

It uses -f to force lolcat to run even though the output is being piped to sed. lolcat defaults to not output anything if the output is not to a tty.

After doing the lolcat, it does a sed to surround the ansi color syntax such as ESC[38;5;184m (ESC is the control character \033) with the control characters SOH and STX so it becomes SOHESC[38;5;184mSTX. SOH and STX are just \[ and \] respectively in the bash prompt control characters. I have to use SOH and STX control characters instead of \[ and \] because I am generating colors dynamically. \[ and \] would not work because they are translated to control characters when PS1 is first parsed. \[ and \] would work if you used PROMPT_COMMAND to generate output for PS1 but then I wouldn't be able to use \u and \W because lolcat would have been run before passing \u to PS1 for expansion.

For reference: https://stackoverflow.com/questions/24839271/bash-ps1-line-wrap-issue-with-non-printing-characters-from-an-external-command

Characters surrounded by SOH and STX are treated as non printing characters. This is required so line-wrapping works correctly and doesn't treat the ansi color as actual visible characters.

If you want to use literal non-printable control characters, you can replace

this

ESC=$(echo -e '\033')
SOH=$(echo -e '\001')
STX=$(echo -e '\002')
PS1_color_wrap='s/'$ESC'\\[[[:digit:];]*m/'$SOH'&'$STX'/g'

with this

PS1_color_wrap='s/^[\\[[[:digit:];]*m/^A&^B/g'

Note the ^[, ^A, and ^B are the literal control characters so you can't just copy and paste. You would have to use something like vim to enter them

In vim:

^[ == Ctrl+vEsc or Ctrl+vo033

^A == Ctrl+vCtrl+a or Ctrl+vo001

^B == Ctrl+vCtrl+b or Ctrl+vo002

EDIT (a little faster in python): The python one seem to run a little bit faster:

python lolcat time

Change these variables in your .bash_profile:

PS1_colorless=${PS1:-'\h:\W \u\$'}
PS1_newline="tr -d '\n'"
PS1_spacing=' '
PS1="\$(lolcat -F 6 -p 25 -f <<< \"$PS1_colorless\" | $PS1_newline | sed '$PS1_color_wrap')"
PS1+=$PS1_spacing

The python version has extra newlines in the output so I remove them with the tr. It also removes trailing spaces so I removed the trailing spaces from PS1_colorless and add them back with PS1_spacing.

You can get it here: https://github.com/tehmaze/lolcat

I will update if I ever get the C port working: https://github.com/jaseg/lolcat

I can't get it to build on mac os. If anyone can get it working on linux or mac os, please let me know.