Skip to content

Repository files navigation

sourcedialog

SourceDialog is a pure Bash TUI dialog library you can source from your own scripts to create interactive terminal forms — no external dependencies (dialog, whiptail, ncurses, etc.).

sourcedialog screenshot

Features

  • Pure Bash — single file, no dependencies, just source it
  • No ncurses, no dialog, no whiptail — uses only Bash builtins and raw ANSI/DEC escape sequences (clears the screen via \e[H\e[2J\e[3J, not /usr/bin/clear)
  • All standard widgets — canvas, frame, textbox, pushbutton, inputbox, passwordbox, menubox, checklist, radiolist
  • Unicode rendering — rounded box-drawing characters, modern markers, scroll indicators (auto-detected, falls back to legacy ACS)
  • 256-color support — auto-detected, smoother shadows and custom themes
  • Robust terminal handling — traps every fatal signal (INT, TERM, HUP, QUIT, PIPE) plus EXIT, so the terminal is always restored even when a callback throws or the process is killed mid-dialog
  • TTY-aware — refuses to enter raw mode if stdin isn't a terminal (returns 127), so piping into a script never wedges the shell
  • Customizable — override any _SD_* color/style variable before calling sd_start
  • Full API compatibility — drop-in upgrade for the original SourceDialog
  • Bash 4.3+

Quick Start

Install by sourcing — either clone the repo or fetch directly via jsDelivr (follows the latest release, HTTPS-served, CDN-backed):

# Latest release (auto-updates):
source <(curl -sSL https://cdn.jsdelivr.net/gh/robindubreuil/sourcedialog@latest/sourcedialog)

# Or pin a specific version for reproducibility:
source <(curl -sSL https://cdn.jsdelivr.net/gh/robindubreuil/sourcedialog@1.1.1/sourcedialog)

Or clone and source locally:

source /path/to/sourcedialog

Then:

myvar=""

sd_load_canvas     name=cv1 x=10 y=2 width=40 height=8 caption=" MY FORM "
sd_load_textbox    name=tb1 x=13 y=4 width=34 text="Enter your name:"
sd_load_inputbox   name=ib1 x=13 y=6 width=34 varname=myvar
sd_load_pushbutton name=ok  x=20 y=8 caption="  OK  "
sd_load_pushbutton name=cc  x=30 y=8 caption=" Cancel "

sd_ok_push()  { return 0; }
sd_cc_push()  { return 1; }

sd_start

API

Widget Registration

Function Description
sd_load_canvas Frame/decoration
sd_load_frame Concave frame (no shadow)
sd_load_textbox Static text
sd_load_pushbutton Button
sd_load_inputbox Text input
sd_load_passwordbox Password input
sd_load_menubox Selection list
sd_load_checklist Multi-select list
sd_load_radiolist Single-select list

Lifecycle

Function Description
sd_start Init, draw, read, reset (main entry point)
sd_init Set up terminal (hide cursor, raw mode)
sd_draw Render all registered widgets
sd_read Interactive input loop
sd_reset Restore terminal
sd_clear Unregister all widgets (for multi-page dialogs)
sd_version Print the loaded library version (e.g. 1.1.1)

The current version is also available as the readonly variable SD_VERSION immediately after sourcing — useful for feature-detection:

source ./sourcedialog
if [[ ${SD_VERSION:-0} < 1.1 ]]; then
    echo "sourcedialog >= 1.1 required (have ${SD_VERSION:-unknown})" >&2
    exit 1
fi

Return Codes

Code Meaning
0 OK / confirm
1 Cancel
27 Escape
127 Not interactive
254 Move backward
255 Move forward

Customizable Variables

Set any of these before sd_start to customize appearance:

Colors (values: 0–7 for 8-color, 0–255 for 256-color terminals):

_SD_BG, _SD_FG, _SD_FRAME_BG, _SD_FRAME_HI, _SD_FRAME_LO, _SD_TEXT_FG, _SD_TEXT_BG, _SD_BTN_FG, _SD_BTN_BG, _SD_BTN_KEY, _SD_BTN_SEL_FG, _SD_BTN_SEL_BG, _SD_INPUT_FG, _SD_INPUT_BG, _SD_INPUT_SEL_FG, _SD_INPUT_SEL_BG, _SD_LIST_FG, _SD_LIST_BG, _SD_LIST_KEY, _SD_LIST_SEL_FG, _SD_LIST_SEL_BG, _SD_SHADOW_BG

Style:

Variable Default Values
_SD_STYLE auto auto, unicode, legacy
_SD_CORNER rounded rounded, square (unicode only)
_SD_256COLOR auto auto, yes, no

Keybindings

Key Action
Arrow keys Navigate items (list)
Space Toggle selection (list)
Tab / Enter Move forward
Shift+Tab Move backward
Home / End First / last item
Page Up / Down Scroll page
Escape Cancel
Backspace Delete character (input)
Any letter Jump to matching item (list)

Environment

Variable Default Meaning
SD_FORCE_TTY 0 Treat stdin as a TTY even when it isn't (useful for tests, snapshots, and piping pre-recorded input). When unset/0, sd_init returns 127 for non-TTY stdin.
SD_DEBUG unset When non-empty, widget read-loops emit their stderr instead of suppressing it.
TERM (inherited) Selects xterm vs linux-console capability tables.
LANG, LC_CTYPE, LC_ALL (inherited) Locale, in standard precedence (LC_ALL wins). A UTF-8 locale selects the Unicode renderer; otherwise the legacy ACS renderer is used.

Robustness guarantees

  • Terminal is always restored. sd_start installs traps on INT, TERM, HUP, QUIT, PIPE, and EXIT, captures any prior handlers you had installed, and restores them on return. If a callback calls exit, the cursor/echo/stty state is still cleaned up before the process terminates.
  • No busy-loop on EOF. If stdin closes mid-dialog, every widget read-loop returns 1 instead of spinning on read.
  • No glob expansion on quick-jump. Letters typed into a listbox are matched literally — typing * no longer jumps to "anything".
  • Renderer falls back gracefully. Pre-populated values longer than their inputbox are scrolled to their tail instead of overrunning neighbouring widgets.

Customizing defaults

The widget loaders distinguish forced identity props from soft defaults:

  • Forced (type=, and password=yes on sd_load_passwordbox) — cannot be overridden by the caller. A canvas stays a canvas.
  • Soft (shadow=, frame=, mark=, multi=) — applied only when the caller did not pass the same prop. So sd_load_frame name=fr1 shadow=yes honours your shadow=yes.

Examples

bash examples/demo        # multi-page dialog with all widgets
bash examples/example1    # OS chooser
bash examples/example2    # address form
bash examples/example3    # account creation

Development

make test           # run the unit suite (419 assertions, no TTY needed)
make lint           # shellcheck the library, tests, examples, tutorials
make pty-smoke      # real-PTY byte-level smoke test (civis/cnorm/smkx/SGR)
make examples-smoke # run every example/tutorial under SD_FORCE_TTY=1
make check          # test + lint (the CI contract)
make all            # check + pty-smoke + examples-smoke

CI runs the unit suite against Bash 4.3 / 4.4 / 5.0 / 5.1 / 5.2 in Docker, plus a macOS job that verifies the version guard rejects Bash 3.2. See CHANGELOG.md for release history.

License

Copyright (c) 2025 Robin Dubreuil 63008968+robindubreuil@users.noreply.github.com Licensed under the GNU General Public License v3. See LICENSE.

Credits

Inspired by SourceDialog by Antonio Macchi (2008), originally posted to comp.os.linux.development.apps on 2008-11-07. This is a complete rewrite aiming to be a drop-in upgrade with full API compatibility.

About

Pure Bash TUI dialog library — create interactive terminal forms with no dependencies

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages