Grapheme Cluster Mode (Mode 2027)
JLine supports terminal mode 2027 ("Unicode Core"), which tells the terminal to use UAX #29 grapheme cluster segmentation instead of per-codepoint wcwidth() for cursor positioning.
Why It Mattersโ
Without mode 2027, terminals determine cursor movement on a per-codepoint basis. This causes incorrect positioning for characters composed of multiple Unicode code points, such as:
- ZWJ emoji sequences:
๐จโ๐พ(farmer) is made of๐จ+ ZWJ +๐พ, but should occupy a single display cell - Flag sequences:
๐ซ๐ทis made of two regional indicator symbols - Combined characters: Characters with combining marks like
เคเฅเคทเคฟ
When mode 2027 is enabled, the terminal treats these multi-codepoint sequences as single grapheme clusters and positions the cursor accordingly.
Checking Supportโ
JLine probes the terminal at runtime using DECRQM (DEC Request Mode) to determine whether mode 2027 is supported. This avoids false positives from terminals that report xterm-256color as their type but don't actually support the mode.
Terminal terminal = TerminalBuilder.terminal();
if (terminal.supportsGraphemeClusterMode()) {
System.out.println("Terminal supports grapheme cluster mode");
} else {
System.out.println("Terminal does not support grapheme cluster mode");
}
The result of the probe is cached, so subsequent calls to supportsGraphemeClusterMode() do not send additional escape sequences.
Enabling and Disablingโ
Terminal terminal = TerminalBuilder.terminal();
// Enable grapheme cluster mode
if (terminal.setGraphemeClusterMode(true)) {
// Mode 2027 is now active
// The terminal will use grapheme cluster segmentation
// ... application logic ...
// Disable when done
terminal.setGraphemeClusterMode(false);
}
setGraphemeClusterMode() returns true if the terminal supports mode 2027 and the escape sequence was sent, or false if the terminal does not support it.
Escape Sequencesโ
JLine uses the following escape sequences internally:
| Operation | Sequence |
|---|---|
| Enable | CSI ? 2027 h |
| Disable | CSI ? 2027 l |
| Query (DECRQM) | CSI ? 2027 $ p |
| Response (DECRPM) | CSI ? 2027 ; Ps $ y |
The query response Ps indicates the mode status:
| Ps | Meaning |
|---|---|
| 0 | Not recognized |
| 1 | Set (enabled) |
| 2 | Reset (disabled, but recognized) |
| 3 | Permanently set |
| 4 | Permanently reset |
JLine considers the mode supported when Ps is 1, 2, or 3.
Terminal Compatibilityโ
Mode 2027 support varies across terminal emulators:
| Terminal Emulator | Mode 2027 Support |
|---|---|
| Contour | Yes |
| foot | Yes |
| WezTerm | Yes |
| Ghostty | Yes |
| iTerm2 | No |
| macOS Terminal.app | No |
| GNOME Terminal | No |
| Windows Terminal | No |
| Konsole | No |
| xterm | No |
Since JLine probes for support at runtime via DECRQM, it correctly detects whether the terminal actually supports mode 2027 regardless of the reported terminal type.
Best Practicesโ
-
Always disable before exiting: If you enable grapheme cluster mode, disable it before your application exits to leave the terminal in a clean state.
-
Don't assume support from terminal type: Many terminals report
xterm-256colorbut don't support mode 2027. Always usesupportsGraphemeClusterMode()which probes the terminal. -
Graceful fallback: Applications should work correctly without mode 2027. Use it as an enhancement for better emoji and complex script rendering when available.