CLI OUTPUT LIBRARY - nself-org/cli GitHub Wiki
Standardized output formatting for nself CLI commands.
The cli-output.sh library provides consistent, cross-platform CLI output formatting with:
- Bash 3.2+ compatibility - Works on macOS, Linux, WSL
- NO_COLOR support - Respects user preferences
- CI/TTY detection - Adapts to terminal vs. non-interactive environments
- Comprehensive API - 40+ functions for all output needs
- Zero dependencies - Pure Bash, no external tools required
# Source the library
source "src/lib/utils/cli-output.sh"
# Basic usage
cli_success "Operation completed successfully"
cli_error "Failed to connect to database"
cli_warning "Port 8080 is already in use"
cli_info "Loading configuration..."The library is automatically available in all nself CLI commands:
# In any CLI command file
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/../lib/utils/cli-output.sh"Print a success message with checkmark icon.
cli_success "Database connection established"
# Output: β Database connection established (in green)Print an error message with cross icon. Outputs to stderr.
cli_error "Failed to read configuration file"
# Output: β Failed to read configuration file (in red, to stderr)Print a warning message with warning icon. Outputs to stderr.
cli_warning "Configuration file not found, using defaults"
# Output: β Configuration file not found, using defaults (in yellow, to stderr)Print an informational message with info icon.
cli_info "Scanning for services..."
# Output: βΉ Scanning for services... (in blue)Print a debug message (only when DEBUG=true).
DEBUG=true cli_debug "Variable value: $var"
# Output: [DEBUG] Variable value: example (in magenta)Print a plain message without icons or colors.
cli_message "Hello, world"
# Output: Hello, worldPrint a bold message.
cli_bold "Important Notice"
# Output: Important Notice (bold)Print a dimmed/subtle message.
cli_dim "Additional context information"
# Output: Additional context information (dimmed)Print a section header with arrow.
cli_section "Database Configuration"
# Output:
# β Database Configuration (bold, with spacing)Print a major section header with double-line box.
cli_header "Build Process"
# Output:
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# Build Process
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββPrint a step indicator for multi-step processes.
cli_step 1 5 "Installing dependencies"
cli_step 2 5 "Running tests"
# Output:
# β Step 1/5 β Installing dependencies
# β Step 2/5 β Running testsDraw a simple box around text.
Types: info (default), success, error, warning
cli_box "Build completed successfully" "success"
# Output:
# ββββββββββββββββββββββββββββββββββββ
# β Build completed successfully β
# ββββββββββββββββββββββββββββββββββββDraw an enhanced box with title and word-wrapped content.
cli_box_detailed "Important Notice" "This is a longer message that will be wrapped properly within the box boundaries to fit the standard 60-character width."
# Output:
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# β Important Notice β
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ’
# β This is a longer message that will be wrapped properly β
# β within the box boundaries to fit the standard β
# β 60-character width. β
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββTables automatically calculate column widths based on headers.
Print table header with column names.
Print table row with values.
Print table footer (closes the table).
Example:
cli_table_header "Service" "Status" "Port"
cli_table_row "postgres" "running" "5432"
cli_table_row "hasura" "running" "8080"
cli_table_row "auth" "stopped" "4000"
cli_table_footer "Service" "Status" "Port"
# Output:
# βββββββββββ¬ββββββββββ¬βββββββ
# β Service β Status β Port β
# βββββββββββΌββββββββββΌβββββββ€
# β postgresβ running β 5432 β
# β hasura β running β 8080 β
# β auth β stopped β 4000 β
# βββββββββββ΄ββββββββββ΄βββββββPrint a bullet list item.
cli_list_item "First item"
cli_list_item "Second item"
# Output:
# β’ First item
# β’ Second itemPrint a numbered list item.
cli_list_numbered 1 "First task"
cli_list_numbered 2 "Second task"
# Output:
# 1. First task
# 2. Second taskPrint a checked checklist item.
cli_list_checked "Completed task"
# Output:
# [β] Completed task (in green)Print an unchecked checklist item.
cli_list_unchecked "Pending task"
# Output:
# [ ] Pending task (dimmed)Show a progress bar for a task.
cli_progress "Building project" 45 100
# Output:
# β Building project [ββββββββββββββββββββββββββββββββββββββ] 45%
cli_progress "Building project" 100 100
# Output:
# β Building project [ββββββββββββββββββββββββββββββββββββββββ] 100% βStart an animated spinner (returns PID).
spinner_pid=$(cli_spinner_start "Loading configuration")
# Do work...
cli_spinner_stop "$spinner_pid" "Configuration loaded"
# Output (animated):
# β Loading configuration...
# (becomes)
# β Configuration loadedNote: Spinners only work in interactive terminals. In CI/non-TTY, a simple message is printed instead.
Print a summary box with multiple items.
cli_summary "Build Complete" \
"5 services started" \
"Database initialized" \
"Nginx configured"
# Output:
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# β β
Build Complete β
β
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ’
# β β’ 5 services started β
# β β’ Database initialized β
# β β’ Nginx configured β
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββPrint a banner for major events.
cli_banner "nself v1.0.0" "Modern Full-Stack Platform"
# Output:
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# β β
# β nself v1.0.0 β
# β Modern Full-Stack Platform β
# β β
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββPrint a horizontal separator line.
cli_separator # 60 characters (default)
cli_separator 40 # 40 characters
# Output:
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββRemove ANSI color codes from text (useful for logging).
colored_output=$(cli_success "Done")
plain_output=$(echo "$colored_output" | cli_strip_colors)
echo "$plain_output" >> logfile.txtPrint blank line(s).
cli_blank # 1 blank line
cli_blank 3 # 3 blank linesCenter text within a given width.
cli_center "Centered Text" 60
# Output (centered within 60 characters):
# Centered TextPrint an indented message.
cli_indent "Level 1 indent" 1
cli_indent "Level 2 indent" 2
cli_indent "Level 3 indent" 3
# Output:
# Level 1 indent
# Level 2 indent
# Level 3 indentThe library respects the NO_COLOR environment variable (no-color.org):
# Disable all colors
export NO_COLOR=1
nself build
# Colors will be disabled for all outputEnable debug messages:
# Show debug messages
DEBUG=true nself build
# Debug messages will be shownThe library is fully compatible with Bash 3.2 (default on macOS):
- β
Uses
printf(notecho -e) - β No Bash 4+ features (associative arrays, lowercase expansion)
- β No external dependencies
- β Tested on macOS, Linux, WSL
The library automatically detects terminal capabilities:
# Interactive terminal
if [[ -t 1 ]]; then
# Colors enabled, animations work
fi
# CI/non-TTY
if [[ ! -t 1 ]]; then
# Colors may be disabled, spinners become simple messages
fiStandard pattern for nself CLI commands:
#!/usr/bin/env bash
# command.sh - Description
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "${SCRIPT_DIR}/../lib/utils/cli-output.sh"
main() {
cli_header "Command Name"
cli_section "Phase 1"
cli_info "Starting phase 1..."
# Do work
cli_success "Phase 1 complete"
cli_section "Phase 2"
cli_info "Starting phase 2..."
# Do work
cli_success "Phase 2 complete"
cli_summary "Operation Complete" \
"Phase 1: Done" \
"Phase 2: Done"
}
main "$@"perform_operation() {
cli_info "Starting operation..."
if ! some_command; then
cli_error "Operation failed: some_command returned error"
cli_warning "Check logs for more details"
return 1
fi
cli_success "Operation completed successfully"
return 0
}build_project() {
local steps=5
cli_header "Build Process"
cli_step 1 $steps "Installing dependencies"
npm install || { cli_error "npm install failed"; return 1; }
cli_step 2 $steps "Running linter"
npm run lint || { cli_warning "Linting found issues"; }
cli_step 3 $steps "Running tests"
npm test || { cli_error "Tests failed"; return 1; }
cli_step 4 $steps "Building application"
npm run build || { cli_error "Build failed"; return 1; }
cli_step 5 $steps "Cleanup"
npm run clean
cli_summary "Build Complete" \
"Dependencies: Installed" \
"Tests: Passed" \
"Build: Successful"
}process_files() {
local files=("file1.txt" "file2.txt" "file3.txt")
local total=${#files[@]}
local current=0
for file in "${files[@]}"; do
((current++))
cli_progress "Processing files" $current $total
# Process file
process_file "$file"
done
}load_configuration() {
local spinner_pid
spinner_pid=$(cli_spinner_start "Loading configuration")
# Simulate long operation
sleep 3
cli_spinner_stop "$spinner_pid" "Configuration loaded successfully"
}show_status() {
cli_header "Service Status"
cli_table_header "Service" "Status" "Port" "Health"
cli_table_row "postgres" "running" "5432" "healthy"
cli_table_row "hasura" "running" "8080" "healthy"
cli_table_row "auth" "stopped" "4000" "n/a"
cli_table_row "nginx" "running" "443" "healthy"
cli_table_footer "Service" "Status" "Port" "Health"
}Run the test suite:
bash src/tests/unit/test-cli-output.shTests include:
- β All message types
- β Sections and headers
- β Boxes and borders
- β Lists (bullet, numbered, checkbox)
- β Tables
- β Progress bars
- β Spinners
- β Summaries and banners
- β NO_COLOR support
- β Non-TTY output
- β Bash 3.2 compatibility
# Old
log_info "message"
log_success "message"
log_error "message"
log_warning "message"
# New
cli_info "message"
cli_success "message"
cli_error "message"
cli_warning "message"# Old
format_success "message"
format_error "message"
format_warning "message"
format_info "message"
# New
cli_success "message"
cli_error "message"
cli_warning "message"
cli_info "message"# Old
echo -e "\033[32mβ\033[0m Success"
printf "\033[31mβ\033[0m Error\n"
# New
cli_success "Success"
cli_error "Error"All colors are exported as constants:
CLI_RESET # Reset all formatting
CLI_BOLD # Bold text
CLI_DIM # Dimmed text
CLI_UNDERLINE # Underlined text
# Standard colors
CLI_RED CLI_GREEN CLI_YELLOW
CLI_BLUE CLI_MAGENTA CLI_CYAN
CLI_WHITE CLI_BLACK
# Bright colors
CLI_BRIGHT_RED CLI_BRIGHT_GREEN
CLI_BRIGHT_YELLOW CLI_BRIGHT_BLUE
CLI_BRIGHT_MAGENTA CLI_BRIGHT_CYAN
CLI_BRIGHT_WHITE# Manual color usage
printf "%b%s%b\n" "${CLI_GREEN}" "Custom green text" "${CLI_RESET}"
# Combined formatting
printf "%b%b%s%b\n" "${CLI_BOLD}" "${CLI_RED}" "Bold red text" "${CLI_RESET}"CLI_ICON_SUCCESS # β
CLI_ICON_ERROR # β
CLI_ICON_WARNING # β
CLI_ICON_INFO # βΉ
CLI_ICON_ARROW # β
CLI_ICON_BULLET # β’
CLI_ICON_CHECK # β
CLI_ICON_CROSS # β
CLI_ICON_STAR # β
CLI_ICON_GEAR # β
CLI_ICON_ROCKET # π
CLI_ICON_PACKAGE # π¦
CLI_ICON_FIRE # π₯
CLI_ICON_SPARKLES # β¨printf "%b%s%b %s\n" \
"${CLI_BLUE}" "${CLI_ICON_ROCKET}" "${CLI_RESET}" \
"Launching application"cli_header "Top-level operation" # Major sections
cli_section "Sub-operation" # Sub-sections
cli_info "Detailed step" # Individual actions- Use
cli_successfor completed operations - Use
cli_errorfor failures that stop execution - Use
cli_warningfor issues that don't stop execution - Use
cli_infofor informational messages
Always provide feedback for long operations:
# Bad
perform_long_operation # User sees nothing
# Good
cli_info "Starting long operation..."
perform_long_operation
cli_success "Operation completed"
# Better
spinner_pid=$(cli_spinner_start "Performing operation")
perform_long_operation
cli_spinner_stop "$spinner_pid" "Operation completed"Provide actionable information with errors:
# Bad
cli_error "Failed"
# Good
cli_error "Failed to connect to database"
cli_info "Check that PostgreSQL is running: nself status"End complex operations with summaries:
cli_summary "Build Complete" \
"Duration: 2m 34s" \
"Warnings: 0" \
"Errors: 0" \
"Services started: 5"- Check
NO_COLORenvironment variable:echo $NO_COLOR - Verify terminal supports colors:
echo -e "\033[31mRed\033[0m" - Test with:
cli_success "Test"(should be green)
Spinners only work in interactive terminals. In CI or when piped, they become simple messages (by design).
Ensure terminal supports UTF-8:
echo $LANG # Should contain UTF-8The library uses 60-character width by default. For narrower terminals:
# Most functions respect this width
cli_box "Text" # 60 chars
cli_separator 40 # 40 chars (custom)The library is optimized for performance:
-
No external commands - Pure Bash, no
sed/awk/etc - Minimal string operations - Direct printf usage
- Lazy evaluation - Colors only loaded when needed
- TTY detection - Skips animations in non-interactive mode
Typical overhead: <1ms per function call
When adding new functions:
- Use
printf(neverecho -e) - Support NO_COLOR
- Test in Bash 3.2
- Add to test suite
- Document in this file
- Export the function
Part of nself - MIT License