Skip to content

feat!: replace containerd/console with x/term and harden Listen - #17

Draft
MarvinJWendt wants to merge 2 commits into
mainfrom
feat/new-pterm
Draft

MarvinJWendt wants to merge 2 commits into
mainfrom
feat/new-pterm

Conversation

@MarvinJWendt

Copy link
Copy Markdown
Member

Requested by Marvin · project thread

Before: The tests used testza, which pulled an old pterm, gookit/color and xo/terminfo into the module graph. Raw mode went through containerd/console. If the callback returned an error, Listen returned without restoring the terminal, and a panic left it in raw mode. Read errors were turned into empty keys, which could make Listen spin. SimulateKeyPress only sent its first argument.

After: The module only depends on golang.org/x/sys and golang.org/x/term (go 1.27.0). Listen always restores the terminal, including on callback errors and panics. It can be called any number of times in a row, and Ctrl+C still arrives as keys.CtrlC. The new ListenReader(r io.Reader, cb) reads key presses from any reader, for tests and non-tty input. go test -race ./... and golangci-lint (Linux, Windows, macOS) pass. pterm's test suite also passes against this branch.

How: Raw mode uses term.MakeRaw/term.Restore. On Unix, reads wait in select(2) on the tty and a wake-up pipe, so Listen can cancel the reader and join it before returning. select is used because poll does not support ttys on macOS. On Windows the reader opens CONIN$ and is canceled with CancelIoEx. A new parser splits escape sequences and control keys that arrive in one read. Typed or pasted printable text is still grouped into one RuneKey. The tests use only the standard library. They use a fake terminal, plus a Linux pty test that checks raw mode, Ctrl+C delivery, cancellation and restore.

Breaking changes:

  • Requires Go 1.27.
  • Listen returns the new ErrAlreadyListening when it is called while another Listen is still running (for example, from inside the callback).
  • SimulateKeyPress now sends every argument instead of only the first one, and returns an error for unsupported input types.
  • Terminal read errors (EOF, hangup) are now returned from Listen instead of being delivered as empty keys. Invalid UTF-8 input is skipped instead of ending Listen with an error.
  • When escape sequences or control characters arrive together with text in one read (for example, a paste that contains newlines), they are now delivered as separate keys.

🤖 Generated with Claude Code

https://claude.ai/code/session_011Dno7CsMx2fSzNx5ZTm7RL


Generated by Claude Code

Switch raw mode handling to golang.org/x/term and golang.org/x/sys on
Unix and Windows, and drop the testza test dependency. The module graph
now only contains golang.org/x/sys and golang.org/x/term.

Listen now always restores the terminal, also when the callback returns
an error or panics, can be called repeatedly, and returns
ErrAlreadyListening for overlapping calls. Terminal reads can be
canceled, so no reader goroutine outlives Listen. Escape sequences and
control keys that arrive in one read are split into separate keys.

ListenReader reads key presses from any io.Reader, for tests and
non-interactive input. SimulateKeyPress now sends every argument
instead of only the first one.

BREAKING CHANGE: requires Go 1.27. Listen returns ErrAlreadyListening
when called while another Listen is running. SimulateKeyPress returns
an error for unsupported input types.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011Dno7CsMx2fSzNx5ZTm7RL
@MarvinJWendt MarvinJWendt self-assigned this Oct 10, 2026
@codecov

codecov Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 86.06965% with 28 lines in your changes missing coverage. Please review.
✅ Project coverage is 81.56%. Comparing base (fae8463) to head (9523c30).

Files with missing lines Patch % Lines
terminal_unix.go 60.71% 22 Missing ⚠️
keyboard.go 93.90% 5 Missing ⚠️
input.go 98.41% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##             main      #17       +/-   ##
===========================================
+ Coverage   42.10%   81.56%   +39.46%     
===========================================
  Files           5        4        -1     
  Lines         171      217       +46     
===========================================
+ Hits           72      177      +105     
+ Misses         92       40       -52     
+ Partials        7        0        -7     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

The v2.11.4 release binary is built with Go 1.26 and refuses to lint a
module that targets Go 1.27.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011Dno7CsMx2fSzNx5ZTm7RL
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.

2 participants