| Crates.io | rainbowterm |
| lib.rs | rainbowterm |
| version | 0.2.23 |
| created_at | 2025-12-11 22:30:36.908159+00 |
| updated_at | 2026-01-19 19:47:46.90002+00 |
| description | Context-aware terminal colorizer with magnitude spectrum visualization for network device output |
| homepage | https://github.com/Legendberg/rainbowterm |
| repository | https://github.com/Legendberg/rainbowterm |
| max_upload_size | |
| id | 1980679 |
| size | 1,698,985 |
Context-aware terminal colorizer with magnitude spectrum visualization for network device output.
๐ธ View Screenshots: Visit the GitHub repository to see the dual spectrum coloring system in action!
Juniper interface output showing dual spectrum: neutral colors for traffic stats, warm colors for errors
JunOS configuration diff with syntax highlighting
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.
RainbowTerm uses context-aware coloring with two distinct spectrum systems:
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)
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!)
Same number, different meaning, different color - The philosophy behind context-aware coloring.
RainbowTerm automatically detects the correct profile based on:
user@hostname>, hostname#)ge-0/0/0, vni-0/2, GigabitEthernet0/1)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
Multi-line state machine tracks context across output:
Choose your platform:
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.
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 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
ssh <remote-host> | rtExample:
ssh admin@192.168.1.1 | rt
# Clone the repository
git clone https://github.com/Legendberg/rainbowterm.git
cd rainbowterm
# Build and install
cargo install --path .
Setup automatic SSH colorization - no | rt needed:
rt init # Preview what will be installed
rt init --install # Install to your shell config
This adds a shell function that automatically pipes SSH through RainbowTerm:
ssh router # Automatically colorized!
# 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
# Preserve ANSI codes from input (default: stripped for cleaner matching)
cat pre-colored.txt | rt --preserve-ansi
# List available profiles
rt --list-profiles
For interactive SSH sessions on Windows, use Git Bash (see Windows installation above). Non-interactive commands work in PowerShell:
ssh router "show version" | rt
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.
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!
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
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)
regex crateHigher priority = applied first:
Contributions are welcome! Please feel free to submit issues or pull requests on GitHub.
rt init) for automatic SSH colorizationrt completions <shell>)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:
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.
Tab completion broken - The PTY layer intercepts terminal control sequences, preventing tab completion from working on the remote device.
Space pagination broken - Similar issue: pressing space for "more" pagination doesn't work properly through the PTY wrapper.
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:
Direct passthrough - Process data immediately as it arrives. Result: Highly inconsistent colorization because serial data splits unpredictably.
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.
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.
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:
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.
Dual licensed under MIT OR Apache-2.0
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.