#!/usr/bin/env bash # # ANSI code generator # # © Copyright 2015 Tyler Akins # Licensed under the MIT license with an additional non-advertising clause # See http://github.com/fidian/ansi ANSI_ESC=$'\033' ANSI_CSI="${ANSI_ESC}[" ANSI_OSC="${ANSI_ESC}]" ANSI_ST="${ANSI_ESC}\\" ANSI_REPORT="" # The return value from ansi::report ansi::backward() { printf '%s%sD' "$ANSI_CSI" "${1-}" } ansi::bell() { printf "%s" $'\007' } ansi::black() { printf '%s30m' "$ANSI_CSI" } ansi::blackIntense() { printf '%s90m' "$ANSI_CSI" } ansi::blink() { printf '%s5m' "$ANSI_CSI" } ansi::blue() { printf '%s34m' "$ANSI_CSI" } ansi::blueIntense() { printf '%s94m' "$ANSI_CSI" } ansi::bgBlack() { printf '%s40m' "$ANSI_CSI" } ansi::bgBlackIntense() { printf '%s100m' "$ANSI_CSI" } ansi::bgBlue() { printf '%s44m' "$ANSI_CSI" } ansi::bgBlueIntense() { printf '%s104m' "$ANSI_CSI" } ansi::bgColor() { printf '%s48;5;%sm' "$ANSI_CSI" "$1" } ansi::bgCyan() { printf '%s46m' "$ANSI_CSI" } ansi::bgCyanIntense() { printf '%s106m' "$ANSI_CSI" } ansi::bgGreen() { printf '%s42m' "$ANSI_CSI" } ansi::bgGreenIntense() { printf '%s102m' "$ANSI_CSI" } ansi::bgMagenta() { printf '%s45m' "$ANSI_CSI" } ansi::bgMagentaIntense() { printf '%s105m' "$ANSI_CSI" } ansi::bgRed() { printf '%s41m' "$ANSI_CSI" } ansi::bgRgb() { printf '%s48;2;%s;%s;%sm' "$ANSI_CSI" "$1" "$2" "$3" } ansi::bgRedIntense() { printf '%s101m' "$ANSI_CSI" } ansi::bgWhite() { printf '%s47m' "$ANSI_CSI" } ansi::bgWhiteIntense() { printf '%s107m' "$ANSI_CSI" } ansi::bgYellow() { printf '%s43m' "$ANSI_CSI" } ansi::bgYellowIntense() { printf '%s103m' "$ANSI_CSI" } ansi::bold() { printf '%s1m' "$ANSI_CSI" } ansi::color() { printf '%s38;5;%sm' "$ANSI_CSI" "$1" } ansi::colorCodes() { local code i j printf 'Standard: ' ansi::bold ansi::white for code in 0 1 2 3 4 5 6 7; do if [[ "$code" == 7 ]]; then ansi::black fi ansi::colorCodePatch "$code" done ansi::resetForeground ansi::normal printf '\nIntense: ' ansi::white for code in 8 9 10 11 12 13 14 15; do if [[ "$code" == 9 ]]; then ansi::black fi ansi::colorCodePatch "$code" done ansi::resetForeground printf '\n\n' # for i in 16 22 28 34 40 46; do for i in 16 22 28; do for j in $i $((i+36)) $((i+72)) $((i+108)) $((i+144)) $((i+180)); do ansi::white ansi::bold for code in $j $((j+1)) $((j+2)) $((j+3)) $((j+4)) $((j+5)); do ansi::colorCodePatch "$code" done ansi::normal ansi::resetForeground printf ' ' ansi::black for code in $((j+18)) $((j+19)) $((j+20)) $((j+21)) $((j+22)) $((j+23)); do ansi::colorCodePatch "$code" done ansi::resetForeground printf '\n' done printf '\n' done printf 'Grays: ' ansi::bold ansi::white for code in 232 233 234 235 236 237 238 239 240 241 242 243; do ansi::colorCodePatch "$code" done ansi::resetForeground ansi::normal printf '\n ' ansi::black for code in 244 245 246 247 248 249 250 251 252 253 254 255; do ansi::colorCodePatch "$code" done ansi::resetForeground printf '\n' } ansi::colorCodePatch() { ansi::bgColor "$1" printf ' %3s ' "$1" ansi::resetBackground } ansi::colorTable() { local colorLabel counter fnbLower fnbUpper functionName IFS resetFunction fnbLower="$( ansi::faint printf f ansi::normal printf n ansi::bold printf b ansi::normal )" fnbUpper="$( ansi::faint printf F ansi::normal printf N ansi::bold printf B ansi::normal )" IFS=$' \n' counter= while read -r colorLabel functionName resetFunction; do printf -- '--%s ' "$colorLabel" $functionName printf 'Sample' $resetFunction if [[ "$counter" == "x" ]]; then counter= printf '\n' else counter=x ansi::column 40 fi done <" to enable the override. if [[ -n "${ANSI_FORCE_SUPPORT-}" ]]; then return 0 fi if hash tput &> /dev/null; then if [[ "$(tput colors)" -lt 8 ]]; then return 1 fi return 0 fi # Query the console and see if we get ANSI codes back. # CSI 0 c == CSI c == Primary Device Attributes. # Idea: CSI c # Response = CSI ? 6 [234] ; 2 2 c # The "22" means ANSI color, but terminals don't need to send that back. # If we get anything back, let's assume it works. ansi::report c "$ANSI_CSI?" c || return 1 [[ -n "$ANSI_REPORT" ]] } ansi::italic() { printf '%s3m' "$ANSI_CSI" } ansi::line() { printf '%s%sd' "$ANSI_CSI" "${1-}" } ansi::lineRelative() { printf '%s%se' "$ANSI_CSI" "${1-}" } ansi::magenta() { printf '%s35m' "$ANSI_CSI" } ansi::magentaIntense() { printf '%s95m' "$ANSI_CSI" } ansi::nextLine() { printf '%s%sE' "$ANSI_CSI" "${1-}" } ansi::noBlink() { printf '%s25m' "$ANSI_CSI" } ansi::noBorder() { printf '%s54m' "$ANSI_CSI" } ansi::noInverse() { printf '%s27m' "$ANSI_CSI" } ansi::normal() { printf '%s22m' "$ANSI_CSI" } ansi::noOverline() { printf '%s55m' "$ANSI_CSI" } ansi::noStrike() { printf '%s29m' "$ANSI_CSI" } ansi::noUnderline() { printf '%s24m' "$ANSI_CSI" } ansi::overline() { printf '%s53m' "$ANSI_CSI" } ansi::plain() { printf '%s23m' "$ANSI_CSI" } ansi::position() { local position="${1-}" printf '%s%sH' "$ANSI_CSI" "${position/,/;}" } ansi::previousLine() { printf '%s%sF' "$ANSI_CSI" "${1-}" } ansi::rapidBlink() { printf '%s6m' "$ANSI_CSI" } ansi::red() { printf '%s31m' "$ANSI_CSI" } ansi::redIntense() { printf '%s91m' "$ANSI_CSI" } ansi::repeat() { printf '%s%sb' "$ANSI_CSI" "${1-}" } ansi::report() { local buff c report report="" # Note: read bypass piping, which lets this work: # ansi --report-window-chars | cut -d , -f 1 read -p "$ANSI_CSI$1" -r -N "${#2}" -s -t 1 buff if [ "$buff" != "$2" ]; then return 1 fi read -r -N "${#3}" -s -t 1 buff while [[ "$buff" != "$3" ]]; do report="$report${buff:0:1}" read -r -N 1 -s -t 1 c || exit 1 buff="${buff:1}$c" done ANSI_REPORT=$report } ansi::reportPosition() { ansi::report 6n "$ANSI_CSI" R || return 1 printf '%s\n' "${ANSI_REPORT//;/,}" } ansi::reportIcon() { ansi::report 20t "${ANSI_OSC}L" "$ANSI_ST" || return 1 printf '%s\n' "${ANSI_REPORT//;/,}" } ansi::reportScreenChars() { ansi::report 19t "${ANSI_CSI}9;" t || return 1 printf '%s\n' "${ANSI_REPORT//;/,}" } ansi::reportTitle() { ansi::report 21t "${ANSI_OSC}l" "$ANSI_ST" || return 1 printf '%s\n' "${ANSI_REPORT//;/,}" } ansi::reportWindowChars() { ansi::report 18t "${ANSI_CSI}8;" t || return 1 printf '%s\n' "${ANSI_REPORT//;/,}" } ansi::reportWindowPixels() { ansi::report 14t "${ANSI_CSI}4;" t || return 1 printf '%s\n' "${ANSI_REPORT//;/,}" } ansi::reportWindowPosition() { ansi::report 13t "${ANSI_CSI}3;" t || return 1 printf '%s\n' "${ANSI_REPORT//;/,}" } ansi::reportWindowState() { ansi::report 11t "$ANSI_CSI" t || return 1 case "$ANSI_REPORT" in 1) printf 'open\n' ;; 2) printf 'iconified\n' ;; *) printf 'unknown (%s)\n' "$ANSI_REPORT" ;; esac } ansi::reset() { ansi::resetColor ansi::resetFont ansi::eraseDisplay 2 ansi::position "1;1" ansi::showCursor } ansi::resetAttributes() { printf '%s22;23;24;25;27;28;29;54;55m' "$ANSI_CSI" } ansi::resetBackground() { printf '%s49m' "$ANSI_CSI" } ansi::resetColor() { printf '%s0m' "$ANSI_CSI" } ansi::resetFont() { printf '%s10m' "$ANSI_CSI" } ansi::resetForeground() { printf '%s39m' "$ANSI_CSI" } ansi::resetIdeogram() { printf '%s65m' "$ANSI_CSI" } ansi::restoreCursor() { printf '%su' "$ANSI_CSI" } ansi::rgb() { printf '%s38;2;%s;%s;%sm' "$ANSI_CSI" "$1" "$2" "$3" } ansi::saveCursor() { printf '%ss' "$ANSI_CSI" } ansi::scrollDown() { printf '%s%sT' "$ANSI_CSI" "${1-}" } ansi::scrollUp() { printf '%s%sS' "$ANSI_CSI" "${1-}" } ansi::icon() { printf '%s1;%s%s' "$ANSI_OSC" "${1-}" "$ANSI_ST" } ansi::title() { printf '%s2;%s%s' "$ANSI_OSC" "${1-}" "$ANSI_ST" } ansi::showCursor() { printf '%s?25h' "$ANSI_CSI" } ansi::showHelp() { cat <