Skip to content

Open-Technology-Foundation/md2ansi.bash

Repository files navigation

MD2ANSI (Bash Implementation)

Version License Shell Status

A zero-dependency Bash implementation of md2ansi that converts Markdown to ANSI-colored terminal output.

Overview

This is a pure Bash implementation of the md2ansi markdown-to-ANSI formatter, designed to be compatible with the Python version while following strict Bash coding standards. The implementation is completely self-contained in a single executable file with no external dependencies beyond standard POSIX tools.

Key Features:

  • ✓ Zero installation dependencies
  • ✓ Single-file monolithic design
  • ✓ Full markdown support (headers, lists, tables, code blocks, formatting)
  • ✓ 256-color ANSI output
  • ✓ Syntax highlighting for Python, JavaScript, and Bash
  • ✓ Security features (file size limits, input sanitization, ReDoS protection)
  • ✓ Compatible with Python version's command-line interface

Quick Start

Installation

Quick Start (No Installation Required)

# Clone the repository
git clone https://github.com/Open-Technology-Foundation/md2ansi.bash.git
cd md2ansi.bash

# Make scripts executable
chmod +x md2ansi md display-ansi-palette md-link-extract

# Test it
md2ansi --version
md2ansi README.md

Method 1: Using Makefile (Recommended)

System-wide installation (requires sudo):

make install

This installs to /usr/local by default:

  • Executables → /usr/local/bin/
  • Man page → /usr/local/share/man/man1/
  • Bash completion → /usr/local/share/bash-completion/completions/

User-local installation (no sudo required):

make install-local

This installs to ~/.local:

  • Executables → ~/.local/bin/
  • Man page → ~/.local/share/man/man1/
  • Bash completion → ~/.local/share/bash-completion/completions/

Custom installation prefix:

make install PREFIX=/opt/md2ansi

Other Makefile targets:

make uninstall      # Remove installed files
make test          # Run shellcheck validation
make clean         # Remove temporary files
make help          # Show help message

Method 2: Using Interactive Install Script

The install.sh script provides an interactive installation experience:

# Interactive installation (prompts for location)
./install.sh

# System-wide installation
./install.sh --system

# User-local installation
./install.sh --user

# Custom prefix
./install.sh --prefix /opt/md2ansi

# Non-interactive mode
./install.sh --system --yes

Features:

  • ✓ Interactive prompts for installation type
  • ✓ Automatic sudo elevation when needed
  • ✓ Rollback on installation failure
  • ✓ Shellcheck validation (if available)
  • ✓ Clear post-installation instructions

Method 3: Manual Installation

For complete control over the installation:

# Install executables
sudo install -m 0755 md2ansi /usr/local/bin/
sudo install -m 0755 md /usr/local/bin/
sudo install -m 0755 display-ansi-palette /usr/local/bin/
sudo install -m 0755 md-link-extract /usr/local/bin/

# Install manpage
sudo install -m 0644 md2ansi.1 /usr/local/share/man/man1/
sudo mandb  # Update man database

# Install bash completion
sudo install -m 0644 md2ansi.bash_completion /usr/local/share/bash-completion/completions/md2ansi

# Verify installation
md2ansi --version
man md2ansi

Post-Installation

View the manual page:

man md2ansi

For user-local installation, ensure ~/.local/bin is in your PATH:

export PATH="$HOME/.local/bin:$PATH"

Add to ~/.bashrc or ~/.bash_profile to make permanent.

Enable bash completion (user-local only):

Add to ~/.bashrc:

if [ -f ~/.local/share/bash-completion/completions/md2ansi ]; then
  . ~/.local/share/bash-completion/completions/md2ansi
fi

Basic Usage

# View a markdown file
md2ansi README.md

# With pagination (recommended for long files)
md README.md

# Process from stdin
cat README.md | md2ansi
echo "# Hello **World**" | md2ansi

# Multiple files
md2ansi file1.md file2.md file3.md

# View the manual
man md2ansi

Common Use Cases

# Read documentation in color
md /usr/share/doc/bash/README

# Preview your markdown before committing
md2ansi CHANGELOG.md | less -R

# View remote markdown files
curl -s https://raw.githubusercontent.com/user/repo/main/README.md | md2ansi

# Check how your documentation will render
./md README.md

Features

Fully Implemented

Headers (H1-H6) with distinct color gradients

  • Bright yellow (H1) to dark gray (H6)
  • Inline formatting supported within headers

Inline Formatting:

  • ✓ Bold (**text**)
  • ✓ Italic (*text* or _text_)
  • ✓ Combined bold+italic (***text***)
  • ✓ Strikethrough (~~text~~)
  • ✓ Inline code (`code`)
  • ✓ Links ([text](url)) with underline formatting
  • ✓ Images (![alt](url)) displayed as placeholders

Lists:

  • ✓ Unordered lists (- or *)
  • ✓ Ordered lists (1., 2., etc.)
  • ✓ Task lists (- [ ] and - [x])
  • ✓ Nested lists with proper indentation
  • ✓ Inline formatting within list items

Tables:

  • ✓ Pipe-delimited tables with alignment support
  • ✓ Left, center, and right alignment (:---, :---:, ---:)
  • ✓ Inline formatting in cells
  • ✓ Proper borders and spacing
  • ✓ Auto-sizing columns

Code Blocks:

  • ✓ Fenced code blocks (``` and ~~~)
  • ✓ Syntax highlighting for Python, JavaScript, and Bash
  • ✓ Language detection and aliases (py, js, sh)
  • ✓ Comment and keyword highlighting

Additional Elements:

  • ✓ Blockquotes (>)
  • ✓ Horizontal Rules (---, ===, ___)
  • ✓ Footnotes ([^1] references and [^1]: text definitions)

Advanced Features:

  • ✓ ANSI-aware text wrapping
  • ✓ Terminal width auto-detection
  • ✓ Feature toggles (--no-tables, --no-syntax-highlight, etc.)
  • ✓ Plain text mode for non-ANSI terminals
  • ✓ Debug mode with detailed traces

Security:

  • ✓ File size limits (10MB maximum)
  • ✓ Per-line length limits (100KB)
  • ✓ Input sanitization (ANSI escape removal)
  • ✓ ReDoS protection with timeout
  • ✓ Proper signal handling

Utility Scripts

md - Paginated Viewer

The md script wraps md2ansi output with less for comfortable viewing of long markdown files:

md README.md              # View with pagination and color
md documentation/*.md     # Browse multiple files sequentially

Features:

  • Automatic pagination using less -FXRS
  • Auto-exit if content fits on one screen (-F)
  • No terminal initialization (-X)
  • Raw ANSI color support (-R)
  • No line wrapping (-S)

Usage:

  • SPACE - Next page
  • b - Previous page
  • q - Quit
  • /pattern - Search
  • n - Next search result

display-ansi-palette - Color Palette Viewer

View all 256 ANSI colors supported by your terminal:

display-ansi-palette      # Display color palette with codes

Output includes:

  • Standard 16 colors (0-15)
  • 6×6×6 color cube (16-231)
  • Grayscale ramp (232-255)
  • Color codes for each value

Useful for:

  • Verifying terminal color support
  • Choosing custom colors
  • Testing ANSI rendering
  • Terminal configuration debugging

md-link-extract - Link Extractor

Extract and list all URLs from markdown files:

md-link-extract README.md              # Extract all links
md-link-extract docs/*.md | sort -u    # Deduplicated links from multiple files
md-link-extract *.md | wc -l          # Count total links

Features:

  • ✓ Extracts inline links [text](url)
  • ✓ Extracts bare URLs <http://example.com>
  • ✓ Extracts reference-style links [text][ref]
  • ✓ Automatic URL deduplication
  • ✓ One URL per line for easy processing

Use cases:

  • Link validation before publishing
  • Finding broken documentation links
  • Creating link inventories
  • SEO analysis

Command-Line Options

Basic Options

# Show help
md2ansi --help
md2ansi -h

# Show version
md2ansi --version
md2ansi -V

# Enable debug mode (output to stderr)
md2ansi --debug README.md 2>debug.log
md2ansi -D file.md

# Force specific terminal width
md2ansi --width 100 README.md
md2ansi -w 80 file.md

# Plain text mode (all formatting disabled)
md2ansi --plain README.md
md2ansi -t file.md

Feature Toggles

Selectively disable specific features:

# Disable table formatting
md2ansi --no-tables doc.md

# Disable syntax highlighting
md2ansi --no-syntax-highlight code-heavy.md

# Disable footnotes
md2ansi --no-footnotes academic.md

# Disable task lists (checkboxes)
md2ansi --no-task-lists todo.md

# Disable image placeholders
md2ansi --no-images doc.md

# Disable link formatting
md2ansi --no-links plain.md

# Combine multiple toggles
md2ansi --no-tables --no-syntax-highlight --no-footnotes simple.md

Examples with Options

# Process file with custom width for narrow terminals
md2ansi -w 60 README.md

# Debug table parsing issues
md2ansi -D tables.md 2>&1 | grep -i table

# Plain mode for piping to log files
md2ansi --plain CHANGELOG.md >> release-notes.txt

# Disable heavy features for faster processing
md2ansi --no-syntax-highlight --no-tables large-file.md

Expanded Examples

Headers and Formatting

Input:

# Main Title
## Subtitle
### Section Header

This is **bold**, *italic*, and ***bold italic*** text.

This is ~~strikethrough~~ and `inline code`.

Visit [GitHub](https://github.com) for more.

Command:

echo "..." | md2ansi

Result: Colored terminal output with distinct header colors, formatted text, and underlined links.

Lists and Task Lists

Input:

Shopping List:
- Apples
- Oranges
  - Valencia oranges
  - Blood oranges
- Bananas

Todo:
- [x] Write documentation
- [ ] Add tests
- [ ] Review code

Command:

md2ansi shopping.md

Result: Nested bullets with proper indentation, checked and unchecked task boxes.

Tables with Alignment

Input:

| Feature | Status | Priority |
|:--------|:------:|---------:|
| Headers || High     |
| Tables  || Medium   |
| Code    || High     |

Command:

md2ansi features.md

Result: Bordered table with left, center, and right aligned columns.

Code Blocks with Syntax Highlighting

Input:

```python
def fibonacci(n):
    if n <= 1:
        return n
    return fibonacci(n-1) + fibonacci(n-2)
```

Command:

md2ansi code-example.md

Result: Color-highlighted Python code with keywords, functions, and comments colored appropriately.

Blockquotes

Input:

> This is a blockquote.
> It can span multiple lines.
>
> It can even have multiple paragraphs.

Command:

md2ansi quote.md

Result: Indented quoted text with distinct background color.

Footnotes

Input:

This statement needs a citation[^1].

Another fact[^2] worth noting.

[^1]: Source: Academic Journal, 2024
[^2]: See documentation for details

Command:

md2ansi academic.md

Result: Footnote references inline, definitions rendered at bottom of document.

Real-World Usage

# Preview your project README
md README.md

# Check documentation before deployment
find ./docs -name "*.md" -exec md {} \;

# View system documentation in color
md /usr/share/doc/bash/README

# Quick reference for command output
man bash | col -b > bash.txt && md bash.txt

# Compare markdown rendering
diff <(md2ansi version1.md) <(md2ansi version2.md)

Comparison Table

vs Python md2ansi

Aspect Bash Version Python Version Notes
Installation Copy one file pip install Bash: zero dependencies
Startup Time ~50ms ~30ms Bash slightly slower
Processing Speed 2-3x slower Baseline Python faster for large files
File Size 1,476 lines (45KB) ~800 lines Bash more verbose
Dependencies None (coreutils only) Python 3.7+ Bash more portable
Design Monolithic single file Single module Both self-contained
Features 100% compatible Full feature set Identical CLI
Syntax Highlighting Line-based regex Token-based parser Python more sophisticated
Error Handling set -e + trap try/except Different paradigms
ReDoS Protection timeout command multiprocessing Different approaches
Memory Usage Very low Low Both efficient
Platform Linux/Unix/macOS Cross-platform Python more portable
Security Built-in limits Built-in limits Equivalent protection

Recommendation:

  • Use Bash version: Quick installation, zero dependencies, system integration
  • Use Python version: Larger files (>5MB), complex syntax highlighting, Windows support

vs Other Markdown Renderers

Feature md2ansi.bash bat glow mdcat rich
Zero Install
Dependencies None Rust Go Rust Python
Tables
Syntax Highlight Basic ✓✓ ✓✓
Footnotes
File Size 45KB ~5MB ~10MB ~2MB varies
Startup 50ms 100ms 200ms 80ms 150ms
Portable ✓✓
Customizable ✓✓ ✓✓

md2ansi.bash advantages:

  • Truly zero dependencies (only coreutils)
  • Single file deployment
  • Full markdown spec support
  • Footnote support
  • Smallest file size
  • Fast startup

When to use alternatives:

  • bat: Need advanced syntax highlighting, line numbers, git integration
  • glow: Want TUI navigation, emoji support, glamorous styling
  • mdcat: Need image rendering in iTerm2/Kitty
  • rich: Python ecosystem integration, complex formatting

Architecture

Design Philosophy

md2ansi follows a monolithic single-file design for maximum portability and zero installation friction. All functionality is embedded in one executable file (md2ansi, 1,476 lines) with no external libraries or modules.

Design Benefits:

Benefit Description
Zero Installation Issues No broken paths, missing dependencies, or version conflicts
Single File Deployment Copy to /usr/local/bin/ and it works immediately
Faster Startup No overhead from sourcing multiple files (~50ms)
Simpler Debugging All code in one place for easy tracing and modification
Clean Architecture Well-organized internal sections with clear markers
Maximum Portability Works on any system with Bash 5.2+ and coreutils

Project Structure

md2ansi.bash/
├── md2ansi               # Main executable (1,476 lines, 45KB)
│                         # ◉ All functionality in single file
├── md                    # Pagination wrapper (15 lines)
├── display-ansi-palette  # Color palette viewer (72 lines)
├── md-link-extract       # Link extractor (54 lines)
├── test/
│   ├── run_tests         # Test suite runner (181 lines)
│   ├── test_basic.sh     # Basic features (128 lines)
│   ├── test_code.sh      # Code blocks (168 lines)
│   ├── test_tables.sh    # Tables (96 lines)
│   ├── test_footnotes.sh # Footnotes (105 lines)
│   ├── test_wrapping.sh  # Text wrapping (182 lines)
│   ├── test_edge_cases.sh # Edge cases (207 lines)
│   ├── test_options.sh   # Feature toggles (96 lines)
│   └── test_security.sh  # Security features (131 lines)
├── README.md             # This file
└── LICENSE               # GPL-3.0 license

Total Project Size:

  • Main executable: 1,476 lines
  • Utility scripts: 141 lines
  • Test suite: 1,294 lines
  • Total: 2,911 lines

Internal Code Organization

The md2ansi script is organized into clearly marked sections:

Section Lines Purpose
Script Header 1-36 Shebang, strict mode, metadata, global variables, state tracking
Utility Functions 37-226 Messaging, terminal detection, file validation, signal handling, string manipulation
ANSI Colors 227-322 Color constants, ANSI escape sequences, color detection, strip/sanitize functions
Inline Rendering 323-710 Bold, italic, strikethrough, links, inline code, text wrapping, header/list/blockquote rendering
Table Rendering 711-1015 Table parsing, alignment detection, column width calculation, table output rendering
Block Parsing 1016-1250 Main parser, code blocks, tables, headers, lists, footnotes, regular text processing
Main Functions 1251-1476 Argument parsing, file processing, main entry point, program invocation

Each section is marked with clear header comments:

# ================================================================================
# ANSI Color Definitions
# ================================================================================

State Management

Global State Variables:

# Configuration
TERM_WIDTH=0              # Auto-detected terminal width
MAX_FILE_SIZE=10485760    # 10MB file size limit
MAX_LINE_LENGTH=100000    # 100KB per-line limit

# Feature Flags
OPTIONS[footnotes]=1
OPTIONS[syntax_highlight]=1
OPTIONS[tables]=1
OPTIONS[task_lists]=1
OPTIONS[images]=1
OPTIONS[links]=1

# Parsing State
IN_CODE_BLOCK=0           # Are we inside a code fence?
CODE_FENCE_TYPE=''        # ``` or ~~~
CODE_LANG=''              # Language identifier
FOOTNOTES=()              # Associative array of footnote definitions
FOOTNOTE_REFS=()          # Array tracking footnote reference order

Key Functions

Core Processing Pipeline:

  1. main() - Entry point, argument parsing
  2. process_file() - Read file/stdin into line array
  3. parse_markdown() - Main parsing loop (block-level)
  4. colorize_line() - Inline formatting (bold, italic, links)
  5. wrap_text() - ANSI-aware text wrapping
  6. Output to stdout

Rendering Functions:

  • render_header() - H1-H6 with color gradients
  • render_list_item() - Unordered lists
  • render_ordered_item() - Numbered lists
  • render_task_item() - Checkboxes
  • render_table() - Complete table parsing and rendering
  • render_code_line() - Code with syntax highlighting
  • render_blockquote() - Quoted text
  • render_hr() - Horizontal rules
  • render_footnotes() - Footnote section at end

Testing

Test Suite

The project includes a comprehensive test suite with 8 test files covering all features:

Test File Lines Coverage
run_tests 181 Test runner with assertion framework
test_basic.sh 128 Headers, inline formatting, lists, links, images, horizontal rules
test_code.sh 168 Fenced code blocks, syntax highlighting, language detection, code fence types
test_tables.sh 96 Table parsing, alignment (left/center/right), borders, inline formatting in cells
test_footnotes.sh 105 Footnote references, definitions, ordering, missing definitions
test_wrapping.sh 182 Text wrapping, ANSI-aware wrapping, terminal width handling
test_edge_cases.sh 207 Empty files, malformed input, edge cases, error handling
test_options.sh 96 Feature toggles, --no-* options, plain mode, option combinations
test_security.sh 131 File size limits, line length limits, input sanitization, ReDoS protection

Total test coverage: 1,294 lines

Running Tests

# Run complete test suite
./test/run_tests

# Run individual test files
./test/test_basic.sh
./test/test_code.sh
./test/test_tables.sh
./test/test_footnotes.sh
./test/test_wrapping.sh
./test/test_edge_cases.sh
./test/test_options.sh
./test/test_security.sh

Test Framework

The test suite uses a simple assertion-based framework:

# Example assertions
assert_equals "expected" "actual" "test name"
assert_contains "haystack" "needle" "test name"
assert_not_empty "$value" "test name"
assert_exit_code 0 "command" "test name"

Manual Testing

# Test basic rendering
echo "# Test\n\nThis is **bold** text." | ./md2ansi

# Test with real README
./md README.md

# Test color support
./display-ansi-palette

# Test link extraction
./md-link-extract README.md

# Test with debug output
./md2ansi -D README.md 2>debug.log
cat debug.log

# Test different terminal widths
./md2ansi -w 60 README.md
./md2ansi -w 120 README.md

# Test feature toggles
./md2ansi --no-tables --no-syntax-highlight README.md
./md2ansi --plain README.md

Development

Code Standards

This implementation strictly adheres to the Bash Coding Standard:

Standard Implementation
Error Handling set -euo pipefail at start
Shell Options shopt -s inherit_errexit shift_verbose extglob nullglob
Indentation 2 spaces throughout (no tabs)
Variables Type-specific declarations (declare -i, declare -a, declare -A)
Constants readonly for immutable values
Scoping local for all function variables
Conditionals [[ ]] for tests, (( )) for arithmetic
Quoting All variable expansions quoted (except in [[ ]] or (( )))
Messaging Standard functions: error, warn, info, debug, die
Cleanup Signal handling with trap
EOF Marker All scripts end with #fin followed by blank line
Increment Use ((var+=1)) not ((var++)) (post-increment breaks set -e)

Adding New Features

Since md2ansi is monolithic, all edits are made to the single md2ansi file.

To add inline formatting:

Edit the colorize_line() function in the Inline Rendering section (lines 323-710):

# Example: Add underline support for __text__
sed -E "s/__([^_]+)__/${ANSI_UNDERLINE}\1${ANSI_RESET}/g"

To add block-level elements:

Edit the parse_markdown() function in the Block Parsing section (lines 1016-1250):

# Example: Add definition lists
if [[ $line =~ ^:\ (.*)$ ]]; then
  render_definition "${BASH_REMATCH[1]}"
  continue
fi

To add syntax highlighting for new language:

Edit the render_code_line() and add a highlighting function:

highlight_ruby() {
  local -- code="$1"
  # Add Ruby-specific patterns
  sed -E "s/\b(def|class|end|if|else)\b/${COLOR_KEYWORD}\1${COLOR_CODEBLOCK}/g" <<<"$code"
}

Debug Mode

# Enable debug output (to stderr)
./md2ansi -D file.md 2>debug.log

# View debug output
cat debug.log

# Real-time debug viewing
./md2ansi -D file.md 2>&1 | grep DEBUG

# Debug specific features
./md2ansi -D tables.md 2>&1 | grep -i table

Debug output includes:

  • ◉ Terminal width detection
  • ◉ File size validation
  • ◉ Table parsing steps (column count, alignment)
  • ◉ Regex operation timeouts
  • ◉ Feature flag states

Code Review Checklist

Before submitting changes:

  • Follows Bash Coding Standard strictly
  • All variables properly declared with types (declare -i, declare -a, etc.)
  • Functions use local for all variables
  • No shellcheck warnings (shellcheck md2ansi)
  • Proper error handling with meaningful exit codes
  • Scripts end with #fin marker
  • Comments for complex logic
  • Test coverage for new features
  • Documentation updated in README
  • No performance regressions

Performance

Benchmarks

File Size Processing Time Notes
Small (<10KB) ~100ms ◉ Fast, instant feedback
Medium (100KB) ~500ms ◉ Good, responsive
Large (1MB) ~3-5s ◉ Acceptable for terminal viewing
Very Large (5-10MB) ~15-30s ◉ Slow but within limits

Optimization target: Terminal viewing responsiveness, not batch processing speed.

Performance Characteristics

Metric Value Notes
Startup time ~50ms Library sourcing overhead
Processing speed ~2-3x slower than Python Acceptable for terminal use
Memory usage Very low Efficient line-by-line processing
File size limit 10MB Configurable via MAX_FILE_SIZE
Line length limit 100KB Safety limit for ReDoS protection
Terminal width 20-500 columns Bounds checking

Comparison to Python Version

For reference, processing a 1MB markdown file:

  • Python version: ~2 seconds
  • Bash version: ~5 seconds
  • Difference: Acceptable for interactive terminal use

Optimization notes:

  • Single sed invocation with multiple patterns in colorize_line()
  • Minimal subprocess spawning
  • Efficient regex patterns
  • ANSI-aware text wrapping without repeated strip operations

Security Features

Feature Implementation Limit/Behavior
File Size Limits Pre-processing validation with wc -c 10MB maximum (configurable)
Line Length Limits Per-line checking during processing 100KB per line
Input Sanitization ANSI escape sequence removal All input cleaned via strip_ansi()
ReDoS Protection timeout command wrapper for regex 1 second timeout on complex patterns
Injection Prevention Proper variable quoting throughout All expansions quoted
Signal Handling trap cleanup handlers Graceful Ctrl-C, proper exit
Bounds Checking Terminal width validation 20-500 column range
Directory Protection Explicit file checks Rejects directories
Permission Checks Read permission validation Clear error messages

Security Best Practices

# File size is checked before processing
validate_file_size "$filepath" "$MAX_FILE_SIZE"

# Input is sanitized
code=$(sanitize_ansi "$code")

# Complex regex uses timeout
timeout 1 sed "s/$pattern/$replacement/g" <<<"$text"

# All variables are quoted
printf '%s\n' "$variable"

# Signal handlers ensure cleanup
trap 'cleanup $?' EXIT
trap 'cleanup 130' INT

FAQ

General Usage

Q: Why use md2ansi.bash instead of the Python version?

A: The Bash version has zero installation dependencies and can be deployed as a single file. Perfect for system integration, minimal environments, or when you can't install Python packages.

Q: Will this work on macOS?

A: Yes, as long as you have Bash 5.2+ installed. macOS ships with Bash 3.2, so install via brew install bash.

Q: Can I use this in scripts and automation?

A: Absolutely. Use --plain mode for log files, or pipe to less -R for interactive viewing.

Q: How do I check if my terminal supports 256 colors?

A: Run tput colors. Should return 256 or higher. Also try ./display-ansi-palette to see all colors.

Troubleshooting

Q: Colors not showing?

A: Check terminal color support: tput colors (should be ≥256). Try setting TERM=xterm-256color.

Q: Script not found error?

A: Make sure you're in the repository directory or use the full path. Check that scripts are executable: chmod +x md2ansi md.

Q: Permission denied error?

A: Run chmod +x md2ansi md display-ansi-palette md-link-extract to make scripts executable.

Q: Output is garbled?

A: Your terminal may not support ANSI codes. Use --plain mode: md2ansi --plain file.md.

Q: Tables not rendering correctly?

A: Check that your table has proper alignment row (second row with ---, :---:, ---:). Or disable tables: --no-tables.

Q: Slow performance on large files?

A: For files >5MB, consider using the Python version. Or disable heavy features: --no-syntax-highlight --no-tables.

Features

Q: Can I customize the colors?

A: Yes, edit the ANSI color constants in the md2ansi file (lines 227-322). Look for COLOR_H1, COLOR_KEYWORD, etc.

Q: Does it support GitHub-flavored markdown?

A: Most GFM features are supported: tables, task lists, strikethrough, fenced code blocks. Some advanced features (e.g., emoji shortcodes) are not implemented.

Q: Can I add syntax highlighting for other languages?

A: Yes, add a highlight_<language>() function in the Inline Rendering section and update the language case statement in render_code_line().

Q: What about nested formatting like bold italic in tables?

A: Supported. Inline formatting works within table cells, list items, headers, and blockquotes.

Q: Can I process from a URL?

A: Yes, pipe from curl: curl -s https://example.com/file.md | md2ansi

Development

Q: How do I run the test suite?

A: Run ./test/run_tests from the project directory. Individual tests can be run directly: ./test/test_basic.sh.

Q: How do I contribute?

A: Follow the Bash Coding Standard strictly, run shellcheck, add tests, and update documentation.

Q: Why monolithic instead of modular?

A: Zero installation friction. One file to copy, no broken dependencies. The code is still well-organized with clear section markers.

Q: Can I use this as a library?

A: It's designed as a standalone executable, but you can source it and call parse_markdown directly if needed.

Known Limitations

Limitation Impact Workaround
Syntax Highlighting Simpler than Python (line-based vs token-based) Use Python version for complex code
Unicode Width Depends on terminal Unicode support Ensure UTF-8 terminal locale
Performance ~2-3x slower than Python for large files Use Python version for files >5MB
Nested Formatting Some edge cases may render differently Test with actual content
Windows Support Requires WSL or Cygwin Use Python version on native Windows
Emoji Rendering No emoji shortcode expansion Use actual emoji characters
Math Rendering No LaTeX/MathJax support Not planned for terminal renderer

Contributing

Contribution Guidelines

Requirement Tool/Process
Code Style Follow Bash Coding Standard strictly
Linting Run shellcheck md2ansi md test/*.sh with zero warnings
Testing Add tests for new features, all tests must pass
Compatibility Maintain CLI compatibility with Python version
Documentation Update README for new features, keep accurate
Performance No regressions, benchmark large files if changing parser

Development Workflow

# 1. Make changes to code
vim md2ansi

# 2. Run shellcheck (must pass with zero warnings)
shellcheck md2ansi md test/*.sh

# 3. Run test suite (all tests must pass)
./test/run_tests

# 4. Test manually with real files
./md README.md
./md2ansi -D test-file.md 2>debug.log

# 5. Commit changes
git add md2ansi test/*.sh README.md
git commit -m "Add feature: description"
git push

Code Review Requirements

All changes must:

  • ✓ Follow Bash Coding Standard
  • ✓ Pass shellcheck with zero warnings
  • ✓ Pass all existing tests
  • ✓ Include new tests for new features
  • ✓ Update README documentation
  • ✓ Use proper variable declarations and quoting
  • ✓ Include error handling with meaningful messages
  • ✓ End with #fin marker

External Tools Used

All tools are standard and available on any modern Linux/Unix system:

Tool Package Purpose
tput ncurses Terminal capability detection, color support
wc coreutils File size validation
sed coreutils Regex substitution for formatting
awk coreutils Text processing (minimal usage)
grep coreutils Pattern matching (minimal usage)
timeout coreutils ReDoS protection wrapper
less util-linux Pagination in md wrapper
stty coreutils Terminal size detection fallback

Zero additional dependencies required!

All tools are part of standard POSIX/GNU utilities installed by default on Linux, macOS (with Homebrew), and BSD systems.

License

GPL-3.0 - Same as parent Python project

See LICENSE file for full text.

Acknowledgments

  • Based on the Python md2ansi implementation
  • Designed for maximum portability and zero dependencies
  • Built with readability and maintainability in mind

Project Statistics

Metric Value
md2ansi Lines 1,476 lines (45KB)
Total Scripts 4 main + 1 test runner + 8 test files
Test Coverage 1,294 lines across 8 test files
Total Project 2,911 lines
Features 15+ markdown elements
Dependencies 0 (zero)
Installation Single file copy
Architecture Monolithic single-file design
Languages Highlighted Python, JavaScript, Bash
Security Features 7+ protections

Support & Links


Status: ✓ Core implementation complete and functional

Version: 1.0.0

#fin

About

A zero-dependency Bash implementation of md2ansi that converts Markdown to ANSI-colored terminal output.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published