-
Notifications
You must be signed in to change notification settings - Fork 268
Description
Bug Summary
When Terminal.getTerminalSize() is called, it corrupts the cursor position as a side effect, causing subsequent output to appear at incorrect positions on the terminal.
Affected Terminal Types
- UnixTerminal (and likely other ANSI-based terminals) - ✗ Affected
- ScrollingSwingTerminal - ✓ Not affected
Root Cause
The getTerminalSize() implementation uses a hack where it moves the cursor to position 5000x5000 to detect terminal boundaries, then reads back the actual cursor position. However, the cursor position is not restored after this operation, leaving the cursor in an incorrect location.
Steps to Reproduce
Terminal terminal = new DefaultTerminalFactory()
.setPreferTerminalEmulator(false)
.createTerminal();
// Output some text
terminal.putString("Line 1");
terminal.putCharacter('\n');
terminal.putString("Line 2: ");
terminal.flush();
// Query terminal size (this corrupts cursor position)
TerminalSize size = terminal.getTerminalSize();
// Further output will now appear at incorrect position
terminal.putString("more text");
terminal.flush();Expected Behavior
getTerminalSize() should be a read-only query operation that doesn't affect terminal state, particularly cursor position. Text output after the call should continue from where it left off.
Actual Behavior
After calling getTerminalSize(), the cursor position is corrupted, causing subsequent output to:
- Appear at an incorrect column/row position
- Have unexpected spacing or padding
- Not align with previously rendered content
The exact manifestation depends on when getTerminalSize() is called and what the application does with cursor positioning.
Workaround
Save and restore cursor position around getTerminalSize() calls:
TerminalPosition savedPosition = terminal.getCursorPosition();
try {
return terminal.getTerminalSize();
} finally {
if (savedPosition != null) {
terminal.setCursorPosition(savedPosition.getColumn(), savedPosition.getRow());
}
}We've implemented a transparent wrapper class that applies this fix by intercepting getTerminalSize() calls to preserve cursor position while delegating all other Terminal methods normally.
Environment
- Lanterna version: 3.1.3
- OS: macOS (Darwin 25.0.0)
- Terminal: Unix terminal (via
DefaultTerminalFactory) - Java: 21
Impact
This affects any application that needs to query terminal size during active rendering, such as:
- Responsive layouts that adapt to terminal width
- Word wrapping implementations
- Table rendering with dynamic column sizing
- Any code that queries size between text output operations
Suggested Fix
The getTerminalSize() implementation should save and restore cursor position internally, making the cursor movement hack transparent to callers.