Summary
When the kernel's terminal height is smaller than the real terminal, the prompt moves up one screen row on every keystroke, leaving blank rows below it. It stops once the anchor reaches the row reedline believes is the bottom, so it looks intermittent.
When it happens
The kernel winsize is shorter than the window actually attached:
| situation |
winsize |
serial console / IPMI SOL / console server (agetty) |
0x0 → reedline assumes 80x24 |
expect / pexpect wrappers |
pty default 24x80 |
window resized where SIGWINCH never reached the pty |
stale, too short |
Repro
stty rows 10 # lie to the kernel; the real window is 50+ rows
seq 1 40 # push the cursor below row 10
<your reedline app>
Type characters slowly. The prompt climbs one row per character until it reaches row 10.
stty rows 0 cols 0 reproduces the serial-console shape (climbs until row 24).
Evidence
Stub app, reedline =0.49.0 / crossterm =0.29.0, driven under a pty whose winsize is set with TIOCSWINSZ and whose CPR query is answered with a chosen row. Recording the MoveTo(0, row) emitted before each paint while typing s,h,o,w,Enter:
| kernel rows |
CPR cursor row |
MoveTo(0, row) per repaint |
result |
| 10 |
36 |
10, 35, 10, 34, 10, 33, 10, 32, 10, 31, 10, 30 |
climbs 1 row/keystroke |
| 10 |
5 |
5, 5, 5, 5, 5, 5 |
stable (control) |
| 0 (assumed 24) |
40 |
24, 39, 24, 38, 24, 37, 24, 36, 24, 35, 24, 34 |
climbs |
| 0 (assumed 24) |
20 |
20, 20, 20, 20, 20, 20 |
stable (control) |
The interleaved 10 / 24 is MoveTo(0, believed_height - 1) from queue_universal_scroll.
Cause
All in src/painting/painter.rs (0.49.0):
- L468 — a
(0, 0) size becomes (80, 24).
- L482 —
initialize_prompt_position guards only equality:
if new_row == self.screen_height() {
A new_row greater than screen_height takes the else branch and is stored as the anchor unchanged.
- L342 —
remaining_lines() is screen_height - prompt_start_row, saturating, so an anchor at or below the believed height gives 0.
- L598-602 — with
required_lines (1) >= remaining_lines (0), extra = 1, so it scrolls and decrements the anchor. Next keystroke the anchor is still past the believed height, so it repeats.
Suggested fix
Either, in initialize_prompt_position:
- Clamp the anchor:
new_row.min(self.screen_height().saturating_sub(1)), or
- Grow
screen_height — the CPR row is direct evidence the terminal is at least that tall.
Changing L482's == to >= alone is not enough: the anchor also needs to be brought inside the believed screen, or remaining_lines() stays 0.
Version
reedline 0.49.0, crossterm 0.29.0, Linux.
Summary
When the kernel's terminal height is smaller than the real terminal, the prompt moves up one screen row on every keystroke, leaving blank rows below it. It stops once the anchor reaches the row reedline believes is the bottom, so it looks intermittent.
When it happens
The kernel winsize is shorter than the window actually attached:
agetty)0x0→ reedline assumes 80x24expect/pexpectwrappersSIGWINCHnever reached the ptyRepro
Type characters slowly. The prompt climbs one row per character until it reaches row 10.
stty rows 0 cols 0reproduces the serial-console shape (climbs until row 24).Evidence
Stub app, reedline
=0.49.0/ crossterm=0.29.0, driven under a pty whose winsize is set withTIOCSWINSZand whose CPR query is answered with a chosen row. Recording theMoveTo(0, row)emitted before each paint while typings,h,o,w,Enter:MoveTo(0, row)per repaint10, 35, 10, 34, 10, 33, 10, 32, 10, 31, 10, 305, 5, 5, 5, 5, 524, 39, 24, 38, 24, 37, 24, 36, 24, 35, 24, 3420, 20, 20, 20, 20, 20The interleaved
10/24isMoveTo(0, believed_height - 1)fromqueue_universal_scroll.Cause
All in
src/painting/painter.rs(0.49.0):(0, 0)size becomes(80, 24).initialize_prompt_positionguards only equality:new_rowgreater thanscreen_heighttakes theelsebranch and is stored as the anchor unchanged.remaining_lines()isscreen_height - prompt_start_row, saturating, so an anchor at or below the believed height gives0.required_lines (1) >= remaining_lines (0),extra = 1, so it scrolls and decrements the anchor. Next keystroke the anchor is still past the believed height, so it repeats.Suggested fix
Either, in
initialize_prompt_position:new_row.min(self.screen_height().saturating_sub(1)), orscreen_height— the CPR row is direct evidence the terminal is at least that tall.Changing L482's
==to>=alone is not enough: the anchor also needs to be brought inside the believed screen, orremaining_lines()stays0.Version
reedline 0.49.0, crossterm 0.29.0, Linux.