Cowsay UTF Borders

Nice borders for cowsay. Also features a small lolcat implementation.

A simple cowsay patch replaces the hardcoded baloon borders with more appealing UTF-8 equivalents.

Cowsay UTF-8 Border Balloon

The different ASCII art “cowfiles” are left unchanged.

--- /usr/games/cowsay
+++ cowsay
@@ -146,16 +146,18 @@ sub construct_balloon {
        @border = qw[ / \ \ / | | ];    
    }
     }
+    @border = ("\x{2502}", "\x{2502}", "\x{2502}", "\x{2502}", "\x{2502}", "\x{2502}");
+    $thoughts = "\x{2572}";
 ## no trailing spaces (#276144)
     push(@balloon_lines, 
-   " " . ("_" x $max2) . "\n" ,
+   "\x{256D}" . ("\x{2500}" x $max2) . "\x{256E}\n" ,
         sprintf($format, $border[0], colstr($message[0], $max), $border[1]),
    (@message < 2 ? "" :  
             map { sprintf($format, $border[4], colstr($_, $max), $border[5]) } 
        @message[1 .. $#message - 1]),
    (@message < 2 ? "" : 
             sprintf($format, $border[2], colstr($message[$#message], $max), $border[3])),
-        " " . ("-" x $max2) . "\n"
+        "\x{2570}" . ("\x{2500}" x $max2) . "\x{256F}\n"
     );
 }

lolcat

The simplified lolcat implementation from above uses the main 256 color wheel in pure Python:

#!/usr/bin/env python3

import sys

COLOR_WHEEL = [196, 202, 208, 214, 220, 226, 190, 154, 118, 82, 46, 47, 48, 49, 50,
               51, 45, 39, 33, 27, 21, 57, 93, 129, 165, 201, 200, 199, 198, 197]

def colorize(line: str, idx: int) -> str:
    return "".join("\x1b[38;5;{}m{}".format(COLOR_WHEEL[(idx + i) % len(COLOR_WHEEL)], c)
                   if not c.isspace() else c
                   for i, c in enumerate(line)) + "\x1b[0m"

def main() -> int:
    idx: int = 0
    while line := sys.stdin.readline():
        sys.stdout.write(colorize(line, idx))
        idx += 1
    return 0

if __name__ == "__main__":
    sys.exit(main())