#syntax-highlighting #colorizer #networking #terminal #cli

bin+lib rainbowterm

Context-aware terminal colorizer with magnitude spectrum visualization for network device output

20 releases

new 0.2.19 Dec 29, 2025
0.2.18 Dec 29, 2025
0.1.0 Dec 11, 2025

#105 in Visualization

MIT/Apache

405KB
1.5K SLoC

RainbowTerm

Context-aware terminal colorizer with magnitude spectrum visualization for network device output.

Rust Crates.io License

๐Ÿ“ธ View Screenshots: Visit the GitHub repository to see the dual spectrum coloring system in action!

Screenshots

Dual Spectrum Coloring in Action

Interface Statistics Juniper interface output showing dual spectrum: neutral colors for traffic stats, warm colors for errors

Configuration Diff Highlighting

Configuration Compare JunOS configuration diff with syntax highlighting

Overview

RainbowTerm is a high-performance Rust-based terminal colorizer designed for network engineers. It provides intelligent syntax highlighting for network device output with advanced features like dual magnitude spectrum visualization (neutral vs. error-based) and context-aware coloring.

โœจ Key Features

๐ŸŒˆ Dual Spectrum Coloring System

RainbowTerm uses context-aware coloring with two distinct spectrum systems:

Neutral Spectrum (Cool Colors) - Informational Magnitude

For traffic counters, packet counts, and other metrics where bigger isn't bad:

Input bytes: 1298458             # Green โ†’ Blue โ†’ Purple (millions)
Output packets: 1234567890       # Orange โ†’ Yellow โ†’ Green โ†’ Blue โ†’ Purple (billions)
Input bytes: 2342779625172       # Orange โ†’ Yellow โ†’ Green โ†’ Blue โ†’ Purple (trillions)
Input bytes: 0                   # Gray (idle)
  • Rightmost 3 digits: Purple (base color)
  • Next group (thousands): Blue โ†’ Purple
  • Millions: Green โ†’ Blue โ†’ Purple
  • Billions: Yellow โ†’ Green โ†’ Blue โ†’ Purple
  • Trillions+: Orange โ†’ Yellow โ†’ Green โ†’ Blue โ†’ Purple
  • Zero: Gray (idle/no traffic)

Error Spectrum (Warm Colors) - Severity-Based Problems

For errors, drops, and problems where bigger IS bad:

Errors: 724                      # Yellow (minor - hundreds)
Drops: 1750520                   # Orange โ†’ Yellow (moderate - millions)
Errors: 1234567890               # Magenta โ†’ Dark Red โ†’ Crimson โ†’ Yellow (billions)
Errors: 0                        # Green (healthy - no errors!)
  • Rightmost 3 digits: Yellow (base color)
  • Thousands: Orange โ†’ Yellow
  • Ten thousands: Red โ†’ Orange โ†’ Yellow
  • Hundred thousands: Dark Red โ†’ Red โ†’ Orange โ†’ Yellow
  • Millions: Crimson โ†’ Dark Red โ†’ Red โ†’ Orange โ†’ Yellow
  • Billions+: Magenta/Violet โ†’ Crimson โ†’ Dark Red โ†’ Red โ†’ Orange โ†’ Yellow
  • Zero errors: Green (healthy state!)

Same number, different meaning, different color - The philosophy behind context-aware coloring.

๐Ÿ” Automatic Profile Detection

RainbowTerm automatically detects the correct profile based on:

  • Banner/MOTD content (e.g., "Versa FlexVNF", "JUNOS", "Cisco IOS")
  • CLI prompts (e.g., user@hostname>, hostname#)
  • Interface naming patterns (e.g., ge-0/0/0, vni-0/2, GigabitEthernet0/1)
  • Configurable hostname prefixes (e.g., jr, vr, cs)

No flags needed - just pipe and go:

ssh router | rt          # Auto-detects from banner/prompt
cat output.txt | rt      # Auto-detects from content

๐Ÿ”ง Network Protocol Support

Juniper JunOS

  • โœ… Interface names by speed (ge, xe, et, mge, vcp, ae)
  • โœ… BGP states (Established/Idle)
  • โœ… OSPF states (Full/Down)
  • โœ… STP states (FWD/BLK) and roles (DESG/DIS)
  • โœ… STP port costs with quality indicators
  • โœ… Physical link status (Up/Down)
  • โœ… Duplex modes (Full-duplex/Half-duplex)
  • โœ… Log severity levels (Critical/Warning/Info)
  • โœ… Active alarms and defects
  • โœ… Routing table markers (* and >)
  • โœ… Configuration diff output (+/-/!)

Versa SD-WAN

  • โœ… Interface types (eth, vni, tvi, ptvi, dtvi)
  • โœ… VRF coloring (Control-VR, LAN-VR, Transport-VR)
  • โœ… WAN link identifiers (WAN1, WAN2, WAN3)
  • โœ… SD-WAN session details (natted, sdwan, offload)
  • โœ… SLA metrics (delay, jitter, loss)
  • โœ… LLDP neighbor information
  • โœ… Operational/configuration mode prompts
  • โœ… Branch/site naming patterns

Cisco IOS/IOS-XE/NX-OS

  • โœ… Interface names (GigabitEthernet, TenGigabitEthernet, etc.)
  • โœ… BGP/OSPF states
  • โœ… STP states and roles
  • โœ… VTP/VLAN information

Generic Patterns

  • โœ… IPv4 addresses
  • โœ… MAC addresses (colon and dot formats)
  • โœ… Serial numbers and model numbers
  • โœ… Status keywords (up/down, error/warning)
  • โœ… Packet/byte counters with magnitude spectrum

๐ŸŽฏ Context-Aware Coloring

Multi-line state machine tracks context across output:

  • Interface state (up/down) affects duplex coloring
  • Half-duplex on UP link = red warning
  • Half-duplex on DOWN link = gray (irrelevant)

โš™๏ธ Advanced Features

  • Group-based coloring: Different colors for each regex capture group
  • Priority system: Fine-grained control over pattern precedence
  • Profile inheritance: Extend base patterns with vendor-specific rules
  • TOML configuration: Human-readable, version-controllable config
  • ChromaTerm converter: Migrate existing YAML configs to TOML

๐Ÿš€ Installation

Choose your platform:


macOS / Linux

Step 1: Install Rust

Using rustup (recommended):

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

After installation, restart your terminal or run source ~/.cargo/env.

Alternative: Homebrew (macOS) or system package manager (Linux)

Homebrew (macOS):

brew install rust

Important: Homebrew doesn't add Cargo to your PATH automatically. Run:

# For zsh (default on macOS)
echo 'export PATH="$HOME/.cargo/bin:$PATH"' >> ~/.zshrc && source ~/.zshrc

# For bash
echo 'export PATH="$HOME/.cargo/bin:$PATH"' >> ~/.bashrc && source ~/.bashrc

Linux package managers:

# Debian/Ubuntu
sudo apt install cargo

# Fedora
sudo dnf install cargo

# Arch
sudo pacman -S rust

Note: System packages may be older versions. If you encounter build issues, use rustup instead.

Step 2: Install RainbowTerm

cargo install rainbowterm

Step 3: Verify installation

rt --version

You're done! Config is created automatically on first run.


Windows

Windows requires additional setup for compiling Rust programs and for interactive SSH sessions.

Step 1: Install Git for Windows

Required for Git Bash, which supports interactive SSH sessions (PowerShell does not).

winget install Git.Git

Or download from git-scm.com.

Step 2: Install Visual Studio Build Tools

Required for compiling Rust programs.

winget install Microsoft.VisualStudio.2022.BuildTools --override "--wait --passive --add Microsoft.VisualStudio.Workload.VCTools --includeRecommended"

Or download from Visual Studio Build Tools and select "Desktop development with C++".

Step 3: Install Rust

winget install Rustlang.Rustup

Or download from rustup.rs.

Step 4: Restart your terminal, then verify Rust is installed:

cargo --version

Step 5: Install RainbowTerm

cargo install rainbowterm

Step 6: Add Cargo to your PATH (if rt command is not found):

# Check if rt is installed
ls $env:USERPROFILE\.cargo\bin\rt.exe

# Add to PATH permanently
[Environment]::SetEnvironmentVariable("Path", $env:Path + ";$env:USERPROFILE\.cargo\bin", "User")

Restart your terminal after updating the PATH.

Step 7: Add Git Bash to Windows Terminal

Note: If you installed Git via the GUI installer (not winget), Git Bash may already appear in Windows Terminal. Skip to step 8 if it's there.

Run these commands in PowerShell to add Git Bash as a profile:

$settingsPath = "$env:LOCALAPPDATA\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\settings.json"
$settings = Get-Content $settingsPath | ConvertFrom-Json

$gitBashProfile = @{
    name = "Git Bash"
    commandline = "C:\\Program Files\\Git\\bin\\bash.exe"
    icon = "C:\\Program Files\\Git\\mingw64\\share\\git\\git-for-windows.ico"
    startingDirectory = "%USERPROFILE%"
    guid = "{" + [guid]::NewGuid().ToString() + "}"
}

$settings.profiles.list = @($settings.profiles.list) + $gitBashProfile
$settings | ConvertTo-Json -Depth 100 | Set-Content $settingsPath

Step 8: Use Git Bash for interactive SSH

  1. Open Windows Terminal
  2. Click the dropdown (โ–ผ) next to the tab and select Git Bash
  3. Run: ssh <remote-host> | rt

Example:

ssh admin@192.168.1.1 | rt

From Source

# Clone the repository
git clone https://github.com/Legendberg/rainbowterm.git
cd rainbowterm

# Build and install
cargo install --path .

Requirements

  • Rust 1.70+ (for building)
  • macOS, Linux, WSL2, or Windows (with Git Bash for interactive SSH)

๐Ÿ“– Usage

Basic Usage

# Pipe any command through RainbowTerm (auto-detects profile)
ssh router | rt

# Use with specific profile (skip auto-detection)
cat output.txt | rt --profile juniper

# Disable auto-detection, use default profile from config
cat output.txt | rt --no-auto-detect

# Disable context awareness
tail -f /var/log/messages | rt --no-context

# List available profiles
rt --list-profiles

Windows Note

For interactive SSH sessions on Windows, use Git Bash (see Windows installation above). Non-interactive commands work in PowerShell:

ssh router "show version" | rt

Testing Profiles

Comprehensive test files are included for each vendor:

# Test Juniper profile
cat tests/networking/juniper/common/sample.txt | rt --profile juniper

# Test Cisco profile
cat tests/networking/cisco/ios/sample.txt | rt --profile cisco

# Run integration tests
cargo test --test integration_tests

# Run all tests (unit + integration)
cargo test

Test files include realistic output from various commands: interfaces, BGP, OSPF, STP, logging, and more.

Real-World Example: Context-Aware Dual Spectrum

Same output, different colors based on context:

Physical interface: ge-0/0/0, Enabled, Physical link is Up
  
  Traffic statistics (NEUTRAL SPECTRUM - cool colors):
   Input  bytes  :              1298458                    0 bps
   Output bytes  :            909181029                32112 bps
  
  Input errors (ERROR SPECTRUM - warm colors, same magnitudes!):
    Errors: 1298458, Drops: 909181029, Framing errors: 0
    
  Queue counters:       Queued packets  Transmitted packets      Dropped packets
    0                          1644910              1644910                  724
    1                         14362000             14362000              1750520
    ^^^                       ^^^^^^^^             ^^^^^^^^             ^^^^^^^^^
                            neutral/cool         neutral/cool          error/warm

Notice how 1298458 appears twice with different colors - once as traffic (neutral spectrum) and once as errors (error spectrum). Context determines meaning!

Configuration

On first run, RainbowTerm creates a default config file at the OS-standard location:

OS Config Path
Linux ~/.config/rainbowterm/config.toml
macOS ~/Library/Application Support/rainbowterm/config.toml
Windows C:\Users\<user>\AppData\Roaming\rainbowterm\config.toml

Use -c <path> to specify a custom config file.

Tip: The config file includes a version comment at line 3. Check it to verify you're using the latest patterns:

head -3 ~/.config/rainbowterm/config.toml  # Linux
head -3 ~/Library/Application\ Support/rainbowterm/config.toml  # macOS
# Set default profile (used when auto-detection fails)
default_profile = "juniper"

# Customize hostname prefixes for your organization
# These help auto-detection identify devices by hostname
[hostname_prefixes]
juniper = ["jr", "js", "mx", "ex"]    # Your Juniper naming convention
versa = ["vr", "sdwan"]               # Your Versa naming convention
cisco = ["cs", "sw", "rtr", "cat"]    # Your Cisco naming convention

# Add custom colors to palette
[palette]
my-blue = "#0080ff"

# Create custom patterns
[[profiles.juniper.patterns]]
description = "Custom pattern"
regex = '''my-regex-here'''
color = "my-blue"
priority = 100

Profile System

  • base: Universal patterns (IPs, MACs, dates, status)
  • juniper: JunOS-specific patterns (inherits from base)
  • versa: Versa SD-WAN patterns (inherits from base)
  • cisco: Cisco IOS/NX-OS patterns (inherits from base)

๐ŸŽจ Color Schemes

Status Colors

  • ๐ŸŸข Green: Good/Active (FWD, Established, Up)
  • ๐ŸŸก Orange: Warning (BLK, threshold)
  • ๐Ÿ”ด Red: Critical (Down, Error, Idle)
  • โšช Gray: Inactive (DIS, zero counters)
  • ๐Ÿ”ต Cyan: Info (DESG, configuration)
  • ๐ŸŸฃ Purple: Virtual interfaces (ae, irb, lo)

Interface Speed Colors

  • ๐Ÿ’š Bright green: 100G+ (et, fte)
  • ๐ŸŒฟ Green-lime: 10G (xe)
  • ๐Ÿ’™ Cyan: 2.5G (mge)
  • ๐Ÿงก Orange: 1G (ge)
  • ๐ŸŸ  Amber: <1G (fe)

๐Ÿ”ฌ Technical Details

Architecture

src/
โ”œโ”€โ”€ main.rs      # CLI interface, stdin processing, output rendering
โ”œโ”€โ”€ config.rs    # TOML parsing, profile management, shared types
โ”œโ”€โ”€ matching.rs  # Pattern compilation and application
โ”œโ”€โ”€ context.rs   # State machine for context-aware rules
โ””โ”€โ”€ convert.rs   # ChromaTerm YAML converter (optional feature)

Performance

  • Patterns compiled at startup with regex crate
  • O(n) processing with efficient overlap detection
  • Chunk-based reading (8192 bytes) for SSH compatibility
  • ANSI escape sequence preservation
  • No performance degradation on large outputs

Pattern Priority System

Higher priority = applied first:

  • 200+: Critical keywords (error, warning, failure)
  • 168: Error counter zeros (green = healthy)
  • 166-160: Error spectrum (trillions down to hundreds)
  • 155-150: Dropped packets column (error spectrum)
  • 155-145: Neutral spectrum (trillions down to hundreds) and queue counters
  • 100: Interface names and service patterns
  • 90: Protocol states (BGP, OSPF, STP)
  • 85: Routing markers and roles
  • 80: Speed indicators
  • 10: Generic up/down keywords

๐Ÿค Contributing

Contributions are welcome! Please feel free to submit issues or pull requests on GitHub.

๐Ÿ—บ๏ธ Roadmap

  • Add Cisco IOS/IOS-XE/NX-OS profile
  • Comprehensive test files for Juniper, Cisco, Arista
  • Dual spectrum system (neutral vs. error-based coloring)
  • Context-aware coloring philosophy
  • Auto-create config on first run
  • Public release to crates.io (v0.1.0)
  • v0.2.0 release with dual spectrum and screenshots
  • v0.2.3 improved documentation for both platforms
  • Unit test suite (15 tests for config and matching)
  • Integration test suite (Juniper, Cisco profiles)
  • Versa SD-WAN profile (v0.2.12)
  • Automatic profile detection from content/banners
  • User-configurable hostname prefixes
  • Complete Arista EOS profile implementation
  • Shell completions (bash, zsh, fish)
  • Performance benchmarks
  • Additional vendor profiles (Palo Alto, F5, etc.)
  • PTY wrap mode for serial console access (see Future Development)

๐Ÿ”ฎ Future Development

PTY Wrap Mode (Paused)

A PTY (pseudo-terminal) wrap mode was prototyped to support serial console access (e.g., rt screen /dev/ttyUSB0). This would allow colorizing output from direct console connections where pipe mode isn't possible.

Why it was paused:

The implementation revealed fundamental limitations with the PTY approach for serial/console access:

  1. Inconsistent colorization - Serial data arrives in unpredictable chunks due to baud rate timing. Pattern matching requires complete lines, but data often splits mid-line, causing the same command to colorize differently on each run.

  2. Tab completion broken - The PTY layer intercepts terminal control sequences, preventing tab completion from working on the remote device.

  3. Space pagination broken - Similar issue: pressing space for "more" pagination doesn't work properly through the PTY wrapper.

  4. Password visibility - Unlike SSH pipe mode (where the SSH client handles password prompts directly), PTY wrap mode would display typed passwords on screen, creating security concerns for screen sharing, terminal logging, and shoulder surfing scenarios.

Current recommendation: Use pipe mode (ssh router | rt) for the best experience. For serial console access, colorization is not currently supported.

What we tried:

The prototype used portable-pty to spawn commands in a pseudo-terminal with two threads: one passing stdin to the PTY, another reading PTY output, colorizing it, and writing to stdout. Several buffering strategies were attempted:

  1. Direct passthrough - Process data immediately as it arrives. Result: Highly inconsistent colorization because serial data splits unpredictably.

  2. Line buffering - Only process complete lines (wait for newline). Result: Prompts (which don't end with newlines) would get stuck and not display until the next line arrived.

  3. Accumulation delay - Add 5-20ms delay after each read to let more data accumulate before processing. Result: Improved consistency but still unreliable; also added noticeable latency.

  4. Hybrid approach - Buffer complete lines, flush incomplete data (like prompts) after accumulation. Result: Still inconsistent due to the fundamental timing unpredictability of serial data.

The core issue is that serial/console data doesn't arrive in logical units - it arrives based on baud rate timing, which means a single line like x1oz@BuffLab> might arrive as x1o, then z@Buff, then Lab> in separate reads. No amount of buffering can reliably reassemble this without either blocking indefinitely or accepting inconsistent results.

Future possibility: This could be revisited if:

  • A reliable line-buffering solution is found for serial timing issues
  • Terminal control sequence passthrough can be implemented
  • A secure password handling mechanism is developed

The prototype code demonstrated that colorization does work when timing aligns, so the core concept is sound - it's the edge cases and user experience that need solving.

๐Ÿ“ License

Dual licensed under MIT OR Apache-2.0

๐Ÿ™ Acknowledgments


Note: RainbowTerm is designed for network engineers working with CLI output from routers, switches, and firewalls. It significantly improves readability and reduces eye strain during troubleshooting sessions.

Dependencies

~6โ€“11MB
~212K SLoC