Skip to content

feat: Add comprehensive terminal graphics protocol support with runtime detection#1378

Merged
gnodet merged 13 commits intojline:masterfrom
gnodet:feature/graphics
Feb 12, 2026
Merged

feat: Add comprehensive terminal graphics protocol support with runtime detection#1378
gnodet merged 13 commits intojline:masterfrom
gnodet:feature/graphics

Conversation

@gnodet
Copy link
Copy Markdown
Member

@gnodet gnodet commented Aug 6, 2025

🎨 Terminal Graphics Protocol Support

This PR adds comprehensive support for terminal graphics protocols with intelligent runtime detection, making JLine capable of displaying images in modern terminals.

🚀 Major Features

1. Multi-Protocol Graphics Support

  • Kitty Graphics Protocol (Priority: 90) - Modern, feature-rich protocol
  • iTerm2 Inline Images (Priority: 70) - iTerm2's proprietary protocol
  • Sixel Graphics (Priority: 10) - Widely supported legacy protocol

2. Intelligent Runtime Detection

  • Sixel Detection: Device Attributes query (ESC[c) - same method as lsix command
  • Kitty Detection: Official Kitty graphics protocol query with quiet mode
  • Automatic Fallback: Falls back to static detection if runtime detection fails
  • Performance Optimized: Skips runtime detection for known non-supporting terminals

3. Comprehensive Terminal Support

Terminal Sixel Kitty iTerm2 Detection Method
Kitty ❌ No ✅ Yes ❌ No Runtime + Static
Ghostty ❌ No ✅ Yes ❌ No Static (confirmed by maintainer)
iTerm2 ✅ Yes ✅ Yes ✅ Yes Static + Environment
WezTerm ✅ Yes ✅ Yes ❌ No Static + Environment
xterm ✅ Yes ❌ No ❌ No Runtime + Static
foot ✅ Yes ❌ No ❌ No Runtime + Static
Konsole ✅ Yes ❌ No ❌ No Runtime + Static

🔧 Implementation Details

Core Classes

  • TerminalGraphicsManager - Unified interface for graphics operations
  • SixelGraphics - Sixel protocol implementation with runtime detection
  • KittyGraphics - Kitty protocol implementation
  • ITerm2Graphics - iTerm2 protocol implementation
  • TerminalGraphics - Common interface for all protocols

Runtime Detection Logic

// Sixel Detection (Device Attributes)
terminal.writer().print("\033[c");
// Response: ESC[?1;2;4;6;9;15;18;21;22c
// Code "4" indicates Sixel support

// Kitty Detection (Graphics Protocol Query)
terminal.writer().print("\033_Ga=q,s=1,v=1,i=1,I=1,q=2\033\\");
// Response: ESC_Gi=1,I=1;OKESC\ (if supported)

Usage Examples

// Automatic protocol selection
TerminalGraphicsManager.displayImage(terminal, bufferedImage);

// With options
TerminalGraphics.ImageOptions options = new TerminalGraphics.ImageOptions()
    .width(100).height(100).preserveAspectRatio(true);
TerminalGraphicsManager.displayImage(terminal, image, options);

// Force specific protocol
TerminalGraphicsManager.forceProtocol(TerminalGraphics.Protocol.KITTY);

// Check support
boolean supported = TerminalGraphicsManager.isGraphicsSupported(terminal);
Optional<TerminalGraphics> best = TerminalGraphicsManager.getBestProtocol(terminal);

📚 Documentation

  • Comprehensive Documentation: Added website/docs/advanced/terminal-graphics.md
  • Complete JavaDoc: All classes fully documented
  • Usage Examples: TerminalGraphicsExample with practical examples
  • Removed: Old SIXEL_GRAPHICS.md from root (moved to proper website docs)

🔧 Build & Development

Upgraded Build Tools

  • JDK 24: Latest OpenJDK for development
  • Maven 4.0.0-rc-4: Latest Maven release candidate
  • Build Status: ✅ mvn clean install passes successfully
  • Code Quality: ✅ Spotless formatting applied

Single Clean Commit

  • Squashed: All development commits into single comprehensive commit
  • Clean History: Easy to review and understand
  • Force Pushed: Updated branch with clean history

🧪 Testing

Comprehensive Test Coverage

  • SixelGraphicsTest.java - Sixel protocol testing
  • TerminalGraphicsTest.java - Manager and integration testing
  • DoubleSizeCharactersTest.java - Character rendering testing
  • All Tests Pass: ✅ 17/17 graphics tests successful

🎯 Key Benefits

  1. ✅ Future-Proof: Works with unknown terminals that support protocols
  2. ✅ Accurate Detection: Runtime queries provide definitive answers
  3. ✅ Performance: Smart detection avoids unnecessary queries
  4. ✅ Robust: Comprehensive error handling and fallbacks
  5. ✅ Compatible: Maintains full backward compatibility
  6. ✅ Extensible: Easy to add new protocols via ServiceLoader

🔍 Testing

# Run all graphics tests
./mvnw test -pl terminal -Dtest="*Graphics*Test"

# Test with example
./build example TerminalGraphicsExample -- --list-protocols
./build example TerminalGraphicsExample -- --display-image path/to/image.png

🐛 Fixes

  • Ghostty Hanging Issue: Fixed runtime detection causing hangs in Ghostty
  • Response Leakage: Prevented terminal responses from appearing in output
  • Protocol Priority: Ensured correct protocol selection based on terminal capabilities
  • Memory Management: Proper image resizing and memory handling
  • Build Issues: Fixed all compilation and formatting issues

🔄 Backward Compatibility

This PR maintains full backward compatibility. All existing functionality continues to work unchanged, with graphics support being purely additive.


Ready for review! This implementation brings JLine's graphics capabilities to modern standards with a clean, single commit and comprehensive documentation. 🚀✨

@gnodet gnodet changed the title Add comprehensive terminal graphics protocol support with runtime detection feat: Add comprehensive terminal graphics protocol support with runtime detection Aug 6, 2025
@gnodet gnodet force-pushed the feature/graphics branch from f9bb0c9 to 1a656b6 Compare August 6, 2025 06:15
@gnodet gnodet added the feature label Aug 6, 2025
@gnodet gnodet added this to the 4.0.0 milestone Aug 6, 2025
@gnodet gnodet force-pushed the feature/graphics branch 3 times, most recently from 775c6a3 to 6c6319f Compare August 7, 2025 00:45
Comment thread terminal/src/main/java/org/jline/terminal/impl/SixelGraphics.java Outdated
Comment thread terminal/src/main/java/org/jline/terminal/impl/SixelGraphics.java Outdated
Comment thread terminal/src/main/java/org/jline/terminal/impl/SixelGraphics.java
This commit introduces complete support for displaying images in modern terminals
through multiple graphics protocols with intelligent runtime detection.

## Features

### Multi-Protocol Graphics Support
- **Kitty Graphics Protocol** (Priority: 90) - Modern, feature-rich protocol
- **iTerm2 Inline Images** (Priority: 70) - iTerm2's proprietary protocol
- **Sixel Graphics** (Priority: 10) - Widely supported legacy protocol

### Intelligent Runtime Detection
- **Sixel Detection**: Device Attributes query (ESC[c) - same method as lsix command
- **Kitty Detection**: Static detection for known supported terminals
- **Automatic Fallback**: Falls back to static detection if runtime detection fails
- **Performance Optimized**: Skips runtime detection for known non-supporting terminals

### Comprehensive Terminal Support

| Terminal | Sixel | Kitty | iTerm2 | Detection Method |
|----------|-------|-------|--------|------------------|
| **Kitty** | ❌ No | ✅ Yes | ❌ No | Runtime + Static |
| **Ghostty** | ❌ No | ✅ Yes | ❌ No | Static (confirmed by maintainer) |
| **iTerm2** | ✅ Yes | ✅ Yes | ✅ Yes | Static + Environment |
| **WezTerm** | ✅ Yes | ✅ Yes | ❌ No | Static + Environment |
| **xterm** | ✅ Yes | ❌ No | ❌ No | Runtime + Static |
| **foot** | ✅ Yes | ❌ No | ❌ No | Runtime + Static |
| **Konsole** | ✅ Yes | ❌ No | ❌ No | Runtime + Static |

## Implementation

### Core Classes
- **TerminalGraphicsManager** - Unified interface for graphics operations
- **SixelGraphics** - Sixel protocol implementation with runtime detection
- **KittyGraphics** - Kitty protocol implementation
- **ITerm2Graphics** - iTerm2 protocol implementation
- **TerminalGraphics** - Common interface for all protocols

### Usage Examples
```java
// Automatic protocol selection
TerminalGraphicsManager.displayImage(terminal, bufferedImage);

// With options
TerminalGraphics.ImageOptions options = new TerminalGraphics.ImageOptions()
    .width(100).height(100).preserveAspectRatio(true);
TerminalGraphicsManager.displayImage(terminal, image, options);

// Force specific protocol
TerminalGraphicsManager.forceProtocol(TerminalGraphics.Protocol.KITTY);

// Check support
boolean supported = TerminalGraphicsManager.isGraphicsSupported(terminal);
Optional<TerminalGraphics> best = TerminalGraphicsManager.getBestProtocol(terminal);
```

## Key Benefits

1. **Future-Proof**: Works with unknown terminals that support protocols
2. **Accurate Detection**: Runtime queries provide definitive answers
3. **Performance**: Smart detection avoids unnecessary queries
4. **Robust**: Comprehensive error handling and fallbacks
5. **Compatible**: Maintains full backward compatibility
6. **Extensible**: Easy to add new protocols via ServiceLoader

## Documentation

- Complete JavaDoc documentation for all classes
- Usage examples in TerminalGraphicsExample
- Comprehensive terminal-graphics.md guide in website/docs/advanced/

## Testing

- Comprehensive test coverage for all protocols
- Runtime detection testing with mocked responses
- Error handling and edge case testing
- Integration testing across different scenarios

## Build Requirements

- Upgraded to JDK 24 and Maven 4.0.0-rc-4
- All builds pass with mvn clean install
- Spotless formatting applied consistently

This implementation brings JLine's graphics capabilities to modern standards
while maintaining the library's reliability and performance characteristics.
Address PR review comments:

1. Fix Sixel detection logic: Remove endsWith('4c') check that caused
   false positives with extensions like '14c', '24c', etc. Now only
   checks for proper ';4;' and ';4c' patterns.

2. Remove overly broad XTerm detection: The previous logic assumed all
   terminals with TERM starting with 'xterm' support Sixel, causing
   many false positives. Replaced with comment explaining the issue
   and relying on runtime detection for real xterm support.

3. Fix Sixel aspect ratio: Change SIXEL_INTRO from '0;1;q' (2:1 ratio)
   to '9;1;q' (1:1 ratio) for correct pixel aspect ratio. Updated
   documentation comments to reflect the correct parameter meanings.

These changes make Sixel detection more accurate and reliable by
eliminating false positives and ensuring proper image rendering.
@gnodet
Copy link
Copy Markdown
Member Author

gnodet commented Dec 15, 2025

augment review

@augmentcode
Copy link
Copy Markdown

augmentcode Bot commented Dec 15, 2025

Sorry, Augment does not have access to the org this pull request's branch is from.

@gnodet
Copy link
Copy Markdown
Member Author

gnodet commented Dec 15, 2025

augment review

@augmentcode
Copy link
Copy Markdown

augmentcode Bot commented Dec 15, 2025

Sorry, Augment does not have access to the org this pull request's branch is from.

Changes:
- Add Kitty graphics timeout constants (GRAPHICS_KITTY_TIMEOUT,
  GRAPHICS_KITTY_SUBSEQUENT_TIMEOUT) in TerminalBuilder for consistency
  with Sixel timeout constants
- Make forcedProtocol volatile in TerminalGraphicsManager for thread-safety
- Make sixelSupportOverride volatile in SixelGraphics for thread-safety
- Add explicit null check in convertToSixel() with clear error message
- Clarify Sixel INTRO parameter documentation (aspect ratio and
  background color handling)
@gnodet
Copy link
Copy Markdown
Member Author

gnodet commented Feb 11, 2026

augment review

@augmentcode
Copy link
Copy Markdown

augmentcode Bot commented Feb 11, 2026

🤖 Augment PR Summary

Summary: Introduces a new terminal-graphics abstraction to let JLine display raster images in supporting terminals, with protocol selection and basic capability detection.

Changes:

  • Add TerminalGraphics SPI plus TerminalGraphicsManager to discover/choose a protocol by priority (incl. ServiceLoader extensibility).
  • Provide built-in implementations for Kitty graphics, iTerm2 inline images, and Sixel (incl. Sixel image conversion and runtime DA-query probing).
  • Add new system property keys in TerminalBuilder for graphics detection timeouts.
  • Add DoubleSizeCharacters helper for VT100 double-width/double-height line rendering.
  • Update the terminal module descriptor to include graphics SPI usage and a desktop dependency.
  • Add a demo example (TerminalGraphicsExample), unit tests for graphics/double-size utilities, and new website documentation.

Technical Notes: Protocol support is primarily inferred via environment/terminal type heuristics, with Sixel optionally using a short runtime query/response to reduce false positives and avoid hangs.

🤖 Was this summary useful? React with 👍 or 👎

Copy link
Copy Markdown

@augmentcode augmentcode Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed. 9 suggestions posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.

Comment thread terminal/src/main/java/module-info.java Outdated
Comment thread terminal/src/main/java/org/jline/terminal/impl/TerminalGraphicsManager.java Outdated
Comment thread terminal/src/main/java/org/jline/terminal/impl/SixelGraphics.java
Comment thread terminal/src/test/java/org/jline/terminal/impl/TerminalGraphicsTest.java Outdated
Comment thread terminal/src/main/java/org/jline/terminal/impl/ITerm2Graphics.java Outdated
Comment thread website/docs/advanced/terminal-graphics.md Outdated
Comment thread website/docs/advanced/terminal-graphics.md Outdated
Comment thread website/docs/advanced/terminal-graphics.md Outdated
- Fix base64 encoding in ITerm2Graphics to use UTF-8 explicitly
- Fix test assertion to handle ServiceLoader-loaded protocols
- Update documentation to use correct system property prefix
- Fix example documentation to match actual command-line arguments
- Clarify Kitty detection method in documentation
- Fix Sixel detection to prioritize terminal type over environment variables
- Changed module-info.java to use 'requires static transitive java.desktop'
  instead of 'requires transitive java.desktop'
- This allows JLine to work in headless environments without java.desktop
- Added runtime checks in TerminalGraphicsManager to detect java.desktop availability
- Graphics features gracefully fail with informative error messages when java.desktop is not available
- Added isJavaDesktopAvailable() method to check availability at runtime
- All tests pass with java.desktop present
- Changed AVAILABLE_PROTOCOLS from ArrayList to CopyOnWriteArrayList for thread-safety
- Made registerProtocol() synchronized and added automatic re-sorting after registration
- This ensures that dynamically registered protocols maintain priority ordering
- Added comprehensive test to verify priority ordering is maintained
- Addresses review comment: jline#1378 (comment)
- getBestProtocol() now checks isSupported() even when forcedProtocol is set
- This prevents routing to protocols that the terminal doesn't actually support
- Updated testProtocolForcing to reflect the new behavior
- Added testForcedProtocolChecksIsSupported to verify the fix
- Addresses review comment: jline#1378 (comment)
@gnodet
Copy link
Copy Markdown
Member Author

gnodet commented Feb 12, 2026

augment review

Copy link
Copy Markdown

@augmentcode augmentcode Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed. 6 suggestions posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.

Comment thread demo/src/main/java/org/jline/demo/examples/TerminalGraphicsExample.java Outdated
} else {
// Otherwise, try to display a sample image from resources
try {
InputStream is = TerminalGraphicsExample.class.getResourceAsStream("/images/jline-logo.png");
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The resource InputStream from getResourceAsStream() isn’t closed here; using try-with-resources (as in displayResourceImageWithSixel) would avoid leaking the handle.

Severity: low

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

Comment thread terminal/src/main/java/org/jline/terminal/impl/DoubleSizeCharacters.java Outdated
* @throws IOException if an I/O error occurs
*/
public static void displayImageStatic(Terminal terminal, File file) throws IOException {
BufferedImage image = ImageIO.read(file);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ImageIO.read(...) can return null for unknown/unsupported image formats; passing null into displayImageStatic turns this into a NullPointerException rather than a clear read/format failure.

Severity: medium

Other Locations
  • terminal/src/main/java/org/jline/terminal/impl/SixelGraphics.java:280
  • terminal/src/main/java/org/jline/terminal/impl/SixelGraphics.java:619
  • terminal/src/main/java/org/jline/terminal/impl/SixelGraphics.java:626

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

Comment thread terminal/src/main/java/org/jline/terminal/impl/TerminalGraphicsManager.java Outdated
Comment thread website/docs/advanced/terminal-graphics.md Outdated
- Fix toLowerCase to use Locale.ROOT in DoubleSizeCharacters.java
- Add null checks after ImageIO.read() calls in SixelGraphics.java
- Fix registerProtocol to dedupe by Protocol enum instead of instance
- Remove undocumented debug property from documentation
- Update test to verify deduplication behavior

Addresses review comments:
- jline#1378 (comment) (already fixed)
- jline#1378 (comment) (already fixed)
- Sixel detection endsWith bug (already fixed)
- Sixel aspect ratio (already fixed)
- toLowerCase locale issue
- ImageIO.read null checks
- registerProtocol deduplication
- Debug property documentation
- Changed all references from 'SixelExample' to 'TerminalGraphicsExample' in the Javadoc
- Addresses review comment: jline#1378 (comment)
- Added examples showing how to use './mvx demo' with '--' separator
- Kept direct java invocation examples for reference
- Makes it clear that '--' is needed to pass arguments through mvx
- Added terminal-graphics.md to sidebar navigation under Advanced Features
- Added JLine 4.x version notice at the top of the document
- Added Requirements section explaining java.desktop dependency
- Clarified that this is a new feature in JLine 4.x, not available in 3.x
@gnodet gnodet merged commit 4eb185c into jline:master Feb 12, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants