sgrtab (6953B)
1 #!/bin/sh 2 # sgrtab - Display standard/custom table of SGR combinations (terminal colors) 3 # Copyright 2017, Avi Halachmi https://github.com/avih/sgrtab License: MIT. 4 5 if [ "$1" = '-h' ] || [ "$1" = '--help' ]; then 6 echo "Usage: $(basename "$0") [[-g] G1..] [-m MODE] [-t TXT [-w W]] [-[xXyYzZ] S1..] ..." 7 echo "Display terminal colors (SGR sequences) in various modes." 8 echo " MODE : table(default)/256/true/info" 9 echo " G1.. : Global individual SGR modifiers added to all table cells." 10 echo 11 echo "-m MODE or --MODE:" 12 echo " 256 : 256 colors indexed palette (accepts -g, ignores others)." 13 echo " true : true-colors surface (accepts -[gt], ignores others)." 14 echo " info : attributes and their SGR codes (accepts -[gty], ignores others)." 15 echo " table: (default) display standard/custom table of terminal colors:" 16 echo " - The Z axis repeats each row with the different z values." 17 echo " - Default: X: 40-47 (bg colors), Y: 30-37 (fg), Z: -/1 (normal/bold)." 18 echo 19 echo "TXT : Sample text. The default is ' gYw ', or ' ' with mode 'true'." 20 echo "W : On-screen width of txt (work around locale/alignment issues)." 21 echo "S1.. : Axis SGR sequences. Use '-' as an empty sequence." 22 echo "-[xyz]: S1 S2 ... are added to the axis. -[XYZ]: replace axis values." 23 echo "Each cell uses an SGR sequence of: [x-seq][y-seq][z-seq][G1;G2...] ." 24 echo "Example: $(basename "$0") -g 3 -y 7 '33;7' -X '- 2 4 48;5;40'" 25 echo " > global italic (3), two extra rows (-y), four columns (-X)."; 26 exit 27 fi 28 29 T=" gYw " 30 X="- 40 41 42 43 44 45 46 47" 31 Y="- 30 31 32 33 34 35 36 37" 32 Z="- 1" 33 G= # global modifiers ("g1;g2...") 34 W= # on-screen text width. set if different than ${#T} e.g. maybe for UTF8 35 ylen=2 # the widest y sequence, for row-headers alignment. considers ${#G} too 36 zlen=2 # widest non-empty z +1, or 0 if empty (empty z headers are suppressed) 37 mode=table # table/256/true/info 38 39 # for SGR. ignore empty or -* args, combine the rest with semicolon delimiter. 40 # hot function. sets seq_out rather than printing from a (slow) subshell. 41 seq_set() { 42 seq_out= 43 for c; do 44 [ "${c##-*}" ] && seq_out="$seq_out;$c" 45 done 46 seq_out="${seq_out#;}" # strip leading ';' from first concat 47 } 48 49 # from (CLI) args: possibly update T/W/G/X/Y/Z/ylen/zlen with minimal validation 50 process_args() { 51 ylen=0 zlen=0 state=g 52 for a; do 53 case $a in 54 -[twgxyzm]) 55 state=${a#-}; continue;; 56 -[XYZ]) 57 state=${a#-}; eval $state=; continue;; 58 --table|--256|--true|--info) 59 state=m; a=${a#??};; # fall to the next case..esac 60 esac 61 case $state in 62 t) T="$a";; 63 w) W="$a";; 64 g) G="$G $a";; 65 x|X) X="$X $a";; 66 y|Y) Y="$Y $a";; 67 z|Z) Z="$Z $a";; 68 m) mode=$a 69 [ "$mode" = true ] && T=" " 70 [ "$mode" = info ] && Y= ;; 71 esac 72 case $state in t|w|m) state=g; esac # one arg, back to -g 73 done 74 case "$W$G$X$Y$Z" in *[!0-9\ \;-]*) echo Invalid arguments; exit 1; esac 75 seq_set $G; G="$seq_out" 76 has $X || X=-; has $Y || [ $mode = info ] || Y=-; has $Z || Z=-; # be nice. 77 for a in $Y; do [ ${#a} -gt $ylen ] && ylen=${#a}; done 78 for a in $Z; do 79 [ "${a##-*}" ] && [ ${#a} -ge $zlen ] && zlen=$((1 + ${#a})) 80 done 81 [ "$G" ] && [ ${#G} -gt $(($ylen + $zlen - 1)) ] && ylen=$((${#G} + 1 - $zlen)) 82 } 83 84 # args: field width, text width, fmt, args... . pad pre/post spaces if shorter 85 print_center() { 86 [ $1 -le $2 ] && shift 2 && printf "$@" && return 87 88 post=$(( ($1 - $2) / 2 )) # post is smaller if non-even 89 pre=$(( $1 - $post - $2 )) 90 fmt="$3"; shift 3 91 printf "%${pre}s$fmt%${post}s" "" "$@" "" 92 } 93 94 has() { [ $# -gt 0 ]; } 95 print_row_header() { printf " %${ylen}s%${zlen}s" "$1" "${2##-*}"; } 96 97 # -- main -- 98 has "$@" && process_args "$@" 99 [ "$W" ] || W=${#T} 100 echo() { printf %s\\n ${1+"$*"}; } 101 102 case $mode in 103 256) ESC=$(printf \\033) 104 # $1: from, $2: len, $3: FG color sequence 105 print_256_line() { 106 i=$1 out= 107 while [ $i -lt $(($1+$2)) ]; do 108 case ${#i} in 1) pad=" ";; 2) pad=" ";; 3) pad=; esac 109 out=$out"$ESC[$3m$ESC[48;5;${i}m${G:+$ESC[${G}m} $pad$i$ESC[m" 110 i=$((i+1)) 111 done; echo "$out" 112 } 113 114 black="38;5;16" 115 white="38;5;231" 116 117 print_256_line 0 8 $black 118 print_256_line 8 8 $black 119 for from in 16 52 88 124 160 196 34 70 106 142 178 214; do 120 case $from in 16|52|88|124|160|196) fg=$white;; *) fg=$black; esac 121 print_256_line $from 18 $fg 122 done 123 print_256_line 232 12 $white 124 print_256_line 244 12 $black 125 ;; 126 127 true) ESC=$(printf \\033) 128 y=1 129 while [ $y -le 16 ]; do 130 x=1 out= 131 while [ $x -le 64 ]; do 132 top=$((256-y*16)); left=$((256-x*4)); bottomright=$((x*2+y*8-1)) 133 out=$out"$ESC[48;2;${top};${left};${bottomright}m${G:+$ESC[${G}m}$T$ESC[m" 134 x=$((x+1)) 135 done; echo "$out" 136 y=$((y+1)) 137 done 138 ;; 139 140 info) ESC=$(printf \\033) 141 # $1: title, $2...: SGR code[s] to append 142 print_var_line() { 143 printf "%${ylen}s " "$1"; shift 144 out= 145 for x in - 30 31 32 33 34 35 36 37; do 146 seq_set $* $x $G 147 out=$out"$ESC[${seq_out}m$T$ESC[m" 148 done; echo "$out" 149 } 150 151 # blink(5) and bright fg/bg (90-97,100-107) should be be used, so we don't 152 ylen=28 153 print_var_line "Normal" 154 print_var_line "Bold (1)" 1 155 print_var_line "Inverse (7)" 7 156 print_var_line "Bold + Inverse (1;7)" "1;7" 157 print_var_line "Italic (3)" 3 158 print_var_line "Underline (4)" 4 159 print_var_line "Crossed-out (9)" 9 160 print_var_line "Dim (2)" 2 161 print_var_line "Conceal (8)" 8 162 163 v2q() { q=$(($1<48 ? 0 : $1<115 ? 1 : ($1-35)/40 )); } # 0-255 -> 0-5 164 printf "%${ylen}s " "256 colors (38/48;5;N)" 165 i=0 out= 166 while [ $i -lt 45 ]; do 167 v2q $((255-i*5)); r=$q 168 v2q $((20+i*5)); b=$q 169 out=$out"$ESC[48;5;$((16 + 36*r + 6*0 + b))${G:+;$G}m $ESC[m" 170 i=$((i+1)) 171 done; echo "$out" 172 173 printf "%${ylen}s " "True colors (38/48;2;R;G;B)" 174 i=0 out= 175 while [ $i -lt 45 ]; do 176 out=$out"$ESC[48;2;$((255-i*5));0;$((20+i*5))${G:+;$G}m $ESC[m" 177 i=$((i+1)) 178 done; echo "$out" 179 180 for y in $Y; do 181 print_var_line "($y)" "$y" 182 done 183 ;; 184 185 table) 186 [ "$G" ] && printf " %$(($ylen + $zlen))s" "+$G" || print_row_header "" "" 187 for x in $X; do 188 print_center $W ${#x} " %s" $x # headers line. center narrow headers 189 done; echo 190 191 for y in $Y; do 192 for z in $Z; do 193 print_row_header $y $z 194 for x in $X; do 195 seq_set $x $y $z $G 196 print_center ${#x} $W " \033[%sm%s\033[m" "$seq_out" "$T" 197 done; echo 198 done 199 done 200 ;; 201 202 *) >&2 printf "Invalid mode '%s'\n" "$mode"; exit 1 203 esac