Skip to content

Insert mode (CSI 4 h) is dropped, so an ncurses insch eats the rest of the line #261

Description

@vyncint

Today — insert mode (IRM, CSI 4 h / CSI 4 l) is parsed and ignored, so text inserted into a line overwrites what was there instead of pushing it right. Measured against 0.9.0 on a 20x2 terminal:

$ inspect --size 20x2 sh -c "printf 'abcd\033[1GZZ'"          # no insert mode
ZZcd                                                           # correct

$ inspect --size 20x2 sh -c "printf 'abcd\033[1G\033[4hZZ'"   # IRM on, then ZZ
ZZcd                                                           # xterm shows ZZabcd

$ inspect --size 20x2 sh -c "printf 'abcd\033[1G\033[2@ZZ'"   # ICH, the other spelling
ZZabcd                                                         # correct

The last line is the shape of it: CSI @ (insert blank cells) works, because the backend dispatches @; CSI 4 h does not, because the backend dispatches no ANSI-mode set or reset at all. Its CSI table covers @ A B C D E F G H J K L M P S T X d m r t and the DEC-private ?h / ?l, and nothing else — so every non-private mode reaches an unhandled path and disappears.

Why it is worth fixing — this is not an exotic sequence. Insert mode is smir/rmir in terminfo and both are present in xterm-256color, which is the TERM termlens hands every child by default:

$ infocmp -1 xterm-256color | grep -E '^\s+(smir|rmir)='
	rmir=\E[4l,
	smir=\E[4h,

An ncurses application calling insch, insstr or winsertln on a terminal that advertises smir uses insert mode rather than CSI @, and which one it picks is ncurses's decision, not the application author's. So a line-editor, a form field, or any widget that inserts a character mid-line renders wrong on the grid — the tail of the line is eaten instead of shifted — and the test asserting on that line fails against an application that is correct, or worse, a snapshot blesses the eaten tail and keeps passing.

It is the same failure class as ESC ( 0 line drawing before #204: a sequence real terminfo entries emit, acknowledged by the parser, dropped before the grid.

Fix — the backend does not implement it, so termlens does, in the layer built for exactly this. emu/seq.rs already tracks state vt100 does not model (the character sets, focus reporting, the cursor shape) and emu/vt100.rs already rewrites the byte stream on the way to the grid — that is how DEC Special Graphics became box drawing.

The mechanism here is different from a glyph substitution: IRM changes what a printable byte does. The cheapest correct shape is to track the flag in the tracker (CSI 4 h sets, CSI 4 l clears, RIS and DECSTR clear it — DECSTR's list already lives in soft_reset), and, while it is set, precede each run of printable bytes handed to the grid with the CSI n @ that reserves room for it. ICH is dispatched by the backend and has the same effect, which is what makes this a rewrite rather than a new grid operation.

Two details worth getting right, both cheap: a run that reaches the right margin must not reserve past it, and the run length is in columns, so a wide character counts twice — emu/vt100.rs already knows how to reason about that from the wide-continuation work in #218.

Out of scope, deliberately: the other ANSI modes vt100 drops (LNM, mode 20, and the rest). This issue is the one with a terminfo capability behind it. Say in the PR whether the tracker's flag is worth exposing on Screen, and decide it either way — "the application put the terminal in insert mode and left it there" is the same shape of assertion as alternate_screen().

Done whenprintf 'abcd\033[1G\033[4hZZ' renders ZZabcd; CSI 4 l returns to overwrite; RIS and DECSTR clear the mode; a test in the emulation suite covers all four, including an insert at the right margin and one over a wide character; and the README's Known limitations no longer implies insert mode is unmodelled.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinggood first issueGood for newcomershelp wantedExtra attention is needed

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions