Skip to content

Terminal: UTF-8-safe shared line editor, paste-leak containment, mid-line editing - #497

Open
SkrawlCO wants to merge 2 commits into
awehttam:claudesbbsfrom
SkrawlCO:upstream/up-023-utf8-line-editor
Open

SkrawlCO wants to merge 2 commits into
awehttam:claudesbbsfrom
SkrawlCO:upstream/up-023-utf8-line-editor

Conversation

@SkrawlCO

@SkrawlCO SkrawlCO commented Oct 5, 2026

Copy link
Copy Markdown

TITLE: Terminal: UTF-8-safe shared line editor, paste-leak containment, mid-line editing

Depends on #485 (#485, "Terminal: decode parametrised/SS3 cursor keys, bracketed paste and lone ESC"). This branch is stacked on #485's commit; review or merge #485 first.

Problem

The terminal server has three separate line readers: BbsSession::readTelnetLine(), TelnetUtils::showInputDialog() and LineShell::readPromptLine(). Each implements editing differently:

  • TelnetUtils::readRawChar() returns single bytes, so a UTF-8 character is split. In showInputDialog() its lead byte cancels the dialog; readPromptLine() silently drops it.
  • Every reader returns at the first CR/LF and leaves the rest of a multi-line paste queued. Those lines then run as keystrokes against the next menu, prompt or password field.
  • LineShell treats CR and LF as separate submits, so CRLF submits twice.
  • Left/Right/Home/End are ignored in the boxed dialog, and the cursor is always drawn at end of text.

Impact

Non-ASCII input cancels dialogs or disappears, pasted text leaks into later prompts (including password fields), and CRLF clients double-submit.

Repair

  • New telnet/src/TerminalLineEditor (codepoint-safe insert/delete, cursor motion, max length, submit/cancel) and TerminalLineHistory (per-prompt recall), shared by showInputDialog() and LineShell::readPromptLine().
  • TelnetUtils::readRawChar() reassembles a UTF-8 lead byte and its continuation bytes into one character; truncated sequences don't hang.
  • After a line is submitted or cancelled, BbsSession::drainPendingInput() discards input already queued from the same paste burst, so it cannot leak into the next prompt.
  • CRLF is one submit, and bursts are coalesced so a paste redraws once.
  • The boxed dialog honors cursor keys and draws the cursor at the insertion point, scrolling horizontally when needed.
  • Both daemon include lists load the new classes, keeping the telnet and SSH include lists in sync.

Proof

  • tests/Unit/TerminalLineEditorTest.php and tests/Unit/TerminalLineHistoryTest.php (pure unit tests).
  • tests/Unit/TerminalLineInputPipelineTest.php: real BbsSession, TelnetUtils and LineShell readers over a socket pair. It covers:
    • UTF-8 preservation and codepoint-safe backspace;
    • multi-line paste containment;
    • CRLF;
    • Ctrl-C drain;
    • bracketed paste in every reader;
    • mid-line cursor editing and cursor placement;
    • password prompts masked with no history.
  • 51 tests pass together with Terminal: decode parametrised/SS3 cursor keys, bracketed paste and lone ESC #485's TerminalKeyDecodingTest. Without this change the new classes are absent, so the tests cannot run. The rest of tests/Unit is unchanged.

SkrawlCO and others added 2 commits October 5, 2026 15:37
…ne ESC

readRawChar() discarded parametrised cursor keys such as ESC[1D as
device reports, leaked SS3 arrows (ESC O A) as typed characters, and
surfaced bracketed-paste markers as unknown tokens; readKeyWithTimeout()
returned '' for a lone ESC and treated chatter as activity.

Normalise CSI/SS3 cursor keys to the bare arrow form, treat paste
markers as chatter, return chatter as a soft timeout, and report a lone
ESC as 'ESC'.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…line editing

The three terminal line readers split UTF-8 characters (cancelling the
input dialog or dropping the character), left the rest of a multi-line
paste queued to run against later prompts, double-submitted on CRLF in
LineShell, and ignored cursor keys in the boxed dialog.

Add a shared codepoint-safe TerminalLineEditor and TerminalLineHistory,
reassemble UTF-8 in readRawChar(), drain a paste burst after submit or
cancel, treat CRLF as one submit, and honor mid-line cursor editing.

Depends on awehttam#485.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant