Skip to content

Switch tcell to our fork of the upstream v3 baseline with escape sequence support - #4174

Draft
JoeKar wants to merge 9 commits into
masterfrom
tcell/v3
Draft

Switch tcell to our fork of the upstream v3 baseline with escape sequence support#4174
JoeKar wants to merge 9 commits into
masterfrom
tcell/v3

Conversation

@JoeKar

@JoeKar JoeKar commented Aug 14, 2026

Copy link
Copy Markdown
Member

This work was initially done by @Tubbles and Claude. 😉
Many thanks for this preparation!

With this we are finally able to have proper pastes in the Windows Terminal App.

TODOs:

  • It looks like it causes a redraw bug in case the bracketed paste is done over a selection.
  • Actually it will additionally display PASTE in the left status bar section as a result of the forced paste in the Windows Terminal App.
  • Add full underline style support (styles and colors)

Related to micro-editor/tcell#5.
Fixes #3571
Fixes #4173

JoeKar and others added 9 commits August 14, 2026 21:11
…ro-editor`

With the fork we can still use raw escape sequences until something similar is
present upstream.

Adapt to the style and clipboard interface changes:
- replace Decompose() with dedicated getters
- replace attributes with dedicated getters
- replace underline attribute with new interface

We have to update our required go toolchain version to 1.25 due to the fact
that tcell updated its toolchain dependency to 1.25.
Several small API adaptations in the screen wrapper:

  - Screen.SetPaste(bool) is replaced by Screen.EnablePaste() and
    Screen.DisablePaste().
  - Screen.CanDisplay is no longer exposed; drop the pass-through.
  - Screen.RegisterRawSeq / UnregisterRawSeq are gone. The v3 input
    processor handles the CSI-u keyboard protocol natively, covering
    the cases raw-seq registration was used for.
  - Add InitMockScreen helper for tests that migrated from the
    removed SimulationScreen to vt.MockTerm.

Assisted-by: Claude:claude-opus-4-7
  - EventKey.Rune() is replaced by Str(). Call sites take the first
    rune where a scalar is still required. Multi-rune grapheme
    clusters get truncated to their first rune on the keystroke path;
    the paste path handles wide input via accumulation (below).
  - NewEventKey takes a string instead of a rune.
  - EventPaste no longer carries payload text. Between Start and End
    the v3 input processor streams EventKey events, so bufpane
    accumulates them into a buffer and replays the whole block
    through paste() on End. This preserves single-undo and
    smartpaste behaviour for bracketed pastes and prevents
    plugin-driven autoclose etc. from firing per-character.
  - command.go: SetPaste(bool) call is split into EnablePaste /
    DisablePaste.
  - events.go: drop the *EventRaw branch from ConstructEvent and
    eventEscSeq. CSI-u covers the original use case natively.
  - rawpane: the EscSeq accessor is no longer a method on the event
    type; use the internal eventEscSeq helper.
  - bindings.go: tcell v3 dropped the KeyCtrlSpace / KeyCtrlLeftSq /
    KeyCtrlBackslash / KeyCtrlRightSq / KeyCtrlCarat /
    KeyCtrlUnderscore constants, and its CSI-u disambiguate path
    delivers Ctrl+Shift+letter, Ctrl+Alt+letter, and Ctrl+non-letter
    as KeyRune+str+mod rather than the KeyCtrlX form. Add
    ctrlNameAliases for the long-form names, gate the KeyCtrlX
    return on mod == ModCtrl exactly to mirror tcell's NewEventKey
    fold (key.go:282-291), and lowercase the rune in the
    single-character emission so the unshifted base kitty sends
    matches bindings written as CtrlShiftP etc. Plain Ctrl+letter
    keeps the legacy KeyCtrlX path. CtrlLeftSq parses but does not
    fire because tcell consumes 0x1B as the start of an escape
    sequence, matching v2 behaviour.
  - tcell v3 drops KeyBackspace2 and only populates KeyBackspace

Assisted-by: Claude:claude-opus-4-7

action tcell
  - tcell v3 exposes an EventQ() channel directly. The PollEvent
    goroutine micro used to plumb events into its own channel is no
    longer needed; select on Screen.EventQ() alongside the existing
    timer / redraw channels.
  - EventError.Err() is gone. Use errors.Is(e, io.EOF) to distinguish
    clean EOF from real errors.

Assisted-by: Claude:claude-opus-4-7
  - Mirror the bracketed-paste accumulator on the termpane side.
    Between EventPaste{Start} and EventPaste{End} the intervening
    EventKeys are buffered together with \x1b[200~ / \x1b[201~
    framing and the whole frame is written to the child pty in one
    go. This preserves bracketed-paste semantics for programs
    running inside termpane (so e.g. bash skips alias expansion on
    the pasted text).
  - When forwarding keystrokes to the pty, translate CSI-u
    Ctrl+letter events (KeyRune + ModCtrl + single-letter Str) back
    to the legacy single-byte C0 control. Child shells and readline
    speak the legacy byte protocol regardless of the outer
    terminal's keyboard encoding.
  - Use the eventEscSeq() helper for raw key forwarding now that
    EscSeq is not a method on the event type.

Assisted-by: Claude:claude-opus-4-7
tcell v3 drops SimulationScreen. The package's vt.MockTerm is the
closest replacement: it satisfies tcell.Screen with an in-memory cell
grid and event queue, so the existing test harness adapts with
minimal changes.

PostEvent(NewEventResize(...)) replaces the old InjectResize helper.

Assisted-by: Claude:claude-opus-4-7
tcell v3 removes the legacy KeyCtrlSpace / KeyCtrlLeftSq /
KeyCtrlBackslash / KeyCtrlRightSq / KeyCtrlCarat / KeyCtrlUnderscore
constants. Micro's bindings parser previously accepted the matching
string names ("CtrlSpace", "CtrlLeftSq", ...) as aliases; those are
now invalid and the parser emits a TermMessage warning when it sees
one.

Update the shipped comment plugin and the keybindings help page to
use the supported forms.

Assisted-by: Claude:claude-opus-4-7
@JoeKar
JoeKar requested a review from dmaluka August 14, 2026 19:32
@JoeKar
JoeKar marked this pull request as draft August 14, 2026 19:32
@JoeKar

JoeKar commented Aug 14, 2026

Copy link
Copy Markdown
Member Author

Currently I'm unsure if this should be added within micro's v2.x.y releases, because it might cause compatibility issues with some key mappings. Maybe its worth a minor instead of a patch release.

@Andriamanitra:
Did you discover some incompatibilities while testing?

@Andriamanitra

Copy link
Copy Markdown
Contributor

I just tested all the bindings in my bindings.json (and some random ones) in micro versions before and after this PR. Most notable change is that bunch of key combinations that didn't get parsed correctly before just started working (for example Ctrli, Ctrlm, modifiers with non-ascii letters).

There were however a few key combinations that were emitting valid events before that now show up as a different event in the raw event viewer:

keys pressed event before this PR event now
Backspace Backspace2 (??) Backspace
CtrlBackspace Backspace Ctrl-Backspace
AltShift7 Alt-/ 1 Shift-Alt-7
CtrlSpacebar Ctrl-Space Ctrl- (??)
CtrlShift- Ctrl-_ 2 Shift-Ctrl--

I assume the results will vary a bit depending on OS/terminal emulator/keyboard layout, but on my setup (Linux/Ghostty/Nordic kbd layout) the breakage doesn't seem to be too bad.

Footnotes

  1. Shift7 is / on my keyboard layout

  2. Shift- is _ on my keyboard layout

@JoeKar

JoeKar commented Aug 15, 2026

Copy link
Copy Markdown
Member Author
keys pressed event before this PR event now
Backspace Backspace2 (??) Backspace
CtrlBackspace Backspace Ctrl-Backspace
AltShift7 Alt-/ Shift-Alt-7
CtrlSpacebar Ctrl-Space Ctrl- (??)
CtrlShift- Ctrl-_ Shift-Ctrl--

According to tcell's CHANGESv3.md#key-event-changes:

Additionally the following special keys are removed, as they are delivered instead as KeyRune with the relevant rune, and the ModCtrl modifier: KeyCtrlSpace, KeyCtrlLeftSq, KeyCtrlRightSq, KeyCtrlBackslash, and KeyCtrlUnderscore.
[...]
The KeyBackspace2 key is no longer delivered, but is converted to KeyBackspace. (This resolves some inconsistency around e.g. CTRL-H vs DELETE.)

In general it is now more consistent to receive all modifiers instead of special key combinations.
But yes, this might cause problems like here:

config.TryBindKey("Alt-/", "lua:comment.comment", false)
config.TryBindKey("CtrlUnderscore", "lua:comment.comment", false)

to
config.TryBindKey("Alt-/", "lua:comment.comment", false)
config.TryBindKey("Ctrl-_", "lua:comment.comment", false)

via f5e19bb

A 100% downward compatibility is quite hard here. 🤔

| AltShift7 | Alt-/| Shift-Alt-7 |
[...]
| CtrlShift- | Ctrl-_| Shift-Ctrl-- |

This case seems to be terminal dependent, because I still receive Alt-/ and Ctrl-_.

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.

[BUG] Del key not working and inserting P at the beggining Paste into Window micro misformats the pasted values

3 participants