boop

Object-oriented programming for bash 4.3+ — real classes, objects, inheritance, and a standard library, in pure bash.


Project maintained by ydbxmhc Hosted on GitHub Pages

Terminal (mixin)

ANSI escape sequences, raw keyboard input, terminal sizing, and a named symbol table. Mix into any class that needs terminal output capabilities.

Dependencies

. boop Terminal

Mixing In

boopClass MyRenderer mixin:Terminal public:new,...

All Terminal methods become available on every instance of MyRenderer.


Screen Control

$r.clear          # erase entire screen, move cursor to top-left
$r.home           # move cursor to top-left without clearing
$r.move 5 10      # move cursor to row 5, column 10 (1-based)
$r.hideCursor     # hide the blinking cursor (restore on exit)
$r.showCursor     # show the cursor again

Typical TUI loop:

trap "$r.showCursor; $r.restore" EXIT

$r.hideCursor
$r.raw              # enter raw input mode

while true; do
  $r.clear
  draw_screen       # your rendering function
  into=k $r.readKey
  [[ "$k" == "q" ]] && break
  handle_key "$k"
done

Text Styles

Write escape sequences directly to stdout. Combine freely with printf.

$r.bold;       printf "This is bold\n";       $r.reset
$r.italic;     printf "This is italic\n";     $r.reset
$r.underline;  printf "This is underlined\n"; $r.reset
$r.dim;        printf "This is dim\n";        $r.reset
$r.reverse;    printf "Reversed fg/bg\n";     $r.reset

# Combine styles
$r.bold; $r.underline; printf "Bold and underlined"; $r.reset; printf "\n"

Always call $r.reset to clear active styles.


Colors

Set foreground and background color by name:

$r.fg red;    printf "red text";    $r.reset; printf "\n"
$r.bg blue;   printf "blue bg";    $r.reset; printf "\n"

# Combine fg + bg + style
$r.bold; $r.fg bright_white; $r.bg red
printf " ALERT "; $r.reset; printf "\n"

Available color names

Standard Bright variant
black bright_black (dark grey)
red bright_red
green bright_green
yellow bright_yellow
blue bright_blue
magenta bright_magenta
cyan bright_cyan
white bright_white

Both fg and bg accept all 16 names. Unknown names return non-zero with an error.


Terminal Size

into=w $r.width     # terminal width in columns (falls back to 80)
into=h $r.height    # terminal height in rows (falls back to 24)

width uses $COLUMNS if set, then tput cols, then 80. height uses $LINES if set, then tput lines, then 24.

Center a string:

into=w $r.width
text="Hello"
pad=$(( (w - ${#text}) / 2 ))
printf "%*s%s\n" "$pad" "" "$text"

Raw Input

Raw mode disables echo and line buffering so each keypress is delivered immediately without waiting for Enter.

$r.raw                    # enter raw mode
into=k $r.readKey         # read exactly one keypress
$r.restore                # return to normal mode

Always restore terminal mode on exit:

trap "$r.restore; $r.showCursor" EXIT
$r.raw

readKey returns a single character. Arrow keys and function keys produce multi-character sequences (e.g. $'\033[A' for up-arrow). Read with a timeout if you need to distinguish Escape from an escape sequence:

$r.raw
IFS= read -rn1 k
if [[ "$k" == $'\033' ]]; then
  IFS= read -rn2 -t 0.05 rest
  k="${k}${rest}"
fi
$r.restore

Named Characters

Access Unicode box-drawing, suits, arrows, and symbols by name. Two lookup styles — use whichever fits the context:

Via method (any object)

into=tl $r.char topLeft     # tl='┌'
into=sp $r.char spade       # sp='♠'

Via global array (tight rendering loops)

# Direct array access — no method call overhead
printf '%s' "${__Terminal_chars[topLeft]}"
printf '%s' "${__Terminal_chars[dHoriz]}"

Single-line box drawing

Name Char   Name Char
topLeft   topRight
bottomLeft   bottomRight
horiz   vert
cross      
teeDown   teeUp
teeRight   teeLeft

Double-line box drawing

Name Char   Name Char
dTopLeft   dTopRight
dBottomLeft   dBottomRight
dHoriz   dVert
dCross      
dTeeDown   dTeeUp
dTeeRight   dTeeLeft

Card suits

Name Char   Name Char
spade   club
heart   diamond

Block / shade gradient

Name Char
block
darkShade
medShade
shade

Arrows

Name Char   Name Char
arrowLeft   arrowRight
arrowUp   arrowDown

Misc

Name Char   Name Char
bullet   ellipsis
check   ballotX
star   circle
square      

Drawing a Box

tl="${__Terminal_chars[topLeft]}"
tr="${__Terminal_chars[topRight]}"
bl="${__Terminal_chars[bottomLeft]}"
br="${__Terminal_chars[bottomRight]}"
h="${__Terminal_chars[horiz]}"
v="${__Terminal_chars[vert]}"

printf '%s%s%s\n' "$tl" "${h}${h}${h}${h}${h}${h}" "$tr"
printf '%s %s %s\n' "$v" "Hello!" "$v"
printf '%s%s%s\n' "$bl" "${h}${h}${h}${h}${h}${h}" "$br"

Output:

┌──────┐
│ Hello! │
└──────┘

Visual Tests

The visual test suite lets you grade each Terminal capability interactively:

./tests/visual/test_terminal_visual

Grade each item y (pass) or n (fail). Results feed into TestSuite reporting. Run manually — not part of test_all.


Design Notes

Global arrays for direct access. __Terminal_chars, __Terminal_fg, and __Terminal_bg are populated at load time and accessible without a method call. In a tight rendering loop that draws hundreds of box characters, direct array access avoids per-character dispatch overhead.

Methods write to stdout. fg, bg, bold, etc. print escape sequences directly. Use them inline with printf:

printf '%s%sERROR%s: %s\n' "$($r.bold)" "$($r.fg red)" "$($r.reset)" "$message"

Or for even tighter output, combine printf calls so the sequences are adjacent.

Error on unknown names. char, fg, and bg call _Error and return non-zero for unknown names. This catches typos at test time rather than silently producing broken output.


↑ Site map