File: iecoli.sh
   1 #!/bin/sh
   2 
   3 # The MIT License (MIT)
   4 #
   5 # Copyright © 2020-2025 pacman64
   6 #
   7 # Permission is hereby granted, free of charge, to any person obtaining a copy
   8 # of this software and associated documentation files (the “Software”), to deal
   9 # in the Software without restriction, including without limitation the rights
  10 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11 # copies of the Software, and to permit persons to whom the Software is
  12 # furnished to do so, subject to the following conditions:
  13 #
  14 # The above copyright notice and this permission notice shall be included in
  15 # all copies or substantial portions of the Software.
  16 #
  17 # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  23 # SOFTWARE.
  24 
  25 
  26 # iecoli [regex/style pairs...]
  27 #
  28 # Insensitive Expressions COloring LInes tries to case-insensitively match
  29 # each line to the regexes given, coloring/styling with the named-style
  30 # associated to the first match, if any.
  31 #
  32 # Lines not matching any regex stay verbatim.
  33 #
  34 # The colors/styles available are:
  35 #     blue
  36 #     bold
  37 #     gray
  38 #     green
  39 #     inverse
  40 #     magenta
  41 #     orange
  42 #     purple
  43 #     red
  44 #     underline
  45 #
  46 # Some style aliases are:
  47 #     b       blue
  48 #     g       green
  49 #     m       magenta
  50 #     o       orange
  51 #     p       purple
  52 #     r       red
  53 #     u       underline
  54 #     hi      inverse (highlight)
  55 
  56 
  57 case "$1" in
  58     -h|--h|-help|--help)
  59         awk '/^# +iecoli /, /^$/ { gsub(/^# ?/, ""); print }' "$0"
  60         exit 0
  61     ;;
  62 esac
  63 
  64 [ "$1" = "--" ] && shift
  65 
  66 command="awk"
  67 if [ -p 1 ] || [ -t 1 ]; then
  68     command="stdbuf -oL awk"
  69 fi
  70 
  71 ${command} '
  72     BEGIN {
  73         # enable case-insensitive regex-matching, or complain if unavailable
  74         if (IGNORECASE == "") {
  75             msg = "this variant of AWK lacks case-insensitive regex-matching"
  76             printf("\x1b[31m%s\x1b[0m\n", msg) > "/dev/stderr"
  77             exit 125
  78         }
  79         IGNORECASE = 1
  80 
  81         # alias-lookup table
  82         a["r"] = "red"
  83         a["g"] = "green"
  84         a["b"] = "blue"
  85         a["o"] = "orange"
  86         a["p"] = "purple"
  87         a["m"] = "magenta"
  88         a["h"] = "invert"
  89         a["i"] = "invert"
  90         a["u"] = "underline"
  91         a["or"] = "orange"
  92         a["ma"] = "magenta"
  93         a["hi"] = "invert"
  94         a["in"] = "invert"
  95         a["un"] = "underline"
  96         a["inv"] = "invert"
  97         a["mag"] = "magenta"
  98         a["grey"] = "gray"
  99         a["inverse"] = "invert"
 100         a["inverted"] = "invert"
 101         a["hilite"] = "invert"
 102         a["hilited"] = "invert"
 103         a["highlight"] = "invert"
 104         a["highlighted"] = "invert"
 105         a["underlined"] = "underline"
 106         a["bb"] = "blueback"
 107         a["gb"] = "greenback"
 108         a["mb"] = "magentaback"
 109         a["ob"] = "orangeback"
 110         a["pb"] = "purpleback"
 111         a["rb"] = "redback"
 112         a["bg"] = "greenback"
 113         a["bm"] = "magentaback"
 114         a["bo"] = "orangeback"
 115         a["bp"] = "purpleback"
 116         a["br"] = "redback"
 117         a["bluebg"] = "blueback"
 118         a["graybg"] = "grayback"
 119         a["greenbg"] = "greenback"
 120         a["greyback"] = "grayback"
 121         a["greybg"] = "grayback"
 122         a["magentabg"] = "magentaback"
 123         a["orangebg"] = "orangeback"
 124         a["purplebg"] = "purpleback"
 125         a["redbg"] = "redback"
 126         a["magback"] = "magentaback"
 127         a["magbg"] = "magentaback"
 128         a["orback"] = "orangeback"
 129         a["orbg"] = "orangeback"
 130         a["purback"] = "purpleback"
 131         a["purbg"] = "purpleback"
 132 
 133         # style-lookup table
 134         s["red"] = "\x1b[38;2;204;0;0m"
 135         s["green"] = "\x1b[38;2;0;135;95m"
 136         s["blue"] = "\x1b[38;2;0;95;215m"
 137         s["orange"] = "\x1b[38;2;215;95;0m"
 138         s["purple"] = "\x1b[38;2;135;95;255m"
 139         s["magenta"] = "\x1b[38;2;215;0;255m"
 140         s["gray"] = "\x1b[38;2;168;168;168m"
 141         s["bold"] = "\x1b[1m"
 142         s["invert"] = "\x1b[7m"
 143         s["italic"] = "\x1b[3m"
 144         s["strike"] = "\x1b[9m"
 145         s["underline"] = "\x1b[4m"
 146         s["blueback"] = "\x1b[48;2;0;95;215m\x1b[38;2;238;238;238m"
 147         s["grayback"] = "\x1b[48;2;168;168;168m\x1b[38;2;238;238;238m"
 148         s["greenback"] = "\x1b[48;2;0;135;95m\x1b[38;2;238;238;238m"
 149         s["magentaback"] = "\x1b[48;2;215;0;255m\x1b[38;2;238;238;238m"
 150         s["orangeback"] = "\x1b[48;2;215;95;0m\x1b[38;2;238;238;238m"
 151         s["purpleback"] = "\x1b[48;2;135;95;255m\x1b[38;2;238;238;238m"
 152         s["redback"] = "\x1b[48;2;204;0;0m\x1b[38;2;238;238;238m"
 153 
 154         if (ARGC % 2 != 1) {
 155             printf "\x1b[31mmissing final style name\x1b[0m\n" > "/dev/stderr"
 156             exit 1
 157         }
 158 
 159         for (i = 1; i < ARGC; i++) {
 160             arg = ARGV[i]
 161             delete ARGV[i]
 162 
 163             if (i % 2 != 0) {
 164                 exprs[++n] = arg
 165                 continue
 166             }
 167 
 168             name = arg
 169             # resolve aliases
 170             if (a[name] != "") {
 171                 name = a[name]
 172             }
 173 
 174             if (s[name] == "") {
 175                 fmt = "\x1b[31mstyle/color %s not supported\x1b[0m\n"
 176                 printf(fmt, name) > "/dev/stderr"
 177                 exit 1
 178             }
 179 
 180             styles[n] = s[name]
 181             resetstyles[n] = "\x1b[0m" styles[n]
 182         }
 183     }
 184 
 185     {
 186         for (i = 1; i <= n; i++) {
 187             if ($0 ~ exprs[i]) {
 188                 gsub(/\x1b\[0m/, resetstyles[i])
 189                 printf "%s%s\x1b[0m\n", styles[i], $0
 190                 next
 191             }
 192         }
 193 
 194         print
 195     }
 196 ' "$@"