Thanks to visit codestin.com
Credit goes to Github.com

Skip to content

Conversation

@gdamore
Copy link
Owner

@gdamore gdamore commented Dec 22, 2025

This adds testing of the cursor movement primitives, and better synchronization for the drain operation, as well as support for DECALN and a supporting test case.

Summary by CodeRabbit

  • New Features

    • Richer terminal cells and visible display attributes; I/O now accepts mixed message types for bytes and control signals.
    • Extended escape-sequence support (including DECALN) that updates displayed cells and styling.
  • Bug Fixes

    • Improved escape-state routing and OSC-like handling for stability.
    • Synchronized drain/checkpoint behavior for more reliable I/O.
    • Idempotent terminal size initialization.
  • Tests

    • Added tests for DECALN and cursor movement.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 22, 2025

Warning

Rate limit exceeded

@gdamore has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 3 minutes and 19 seconds before requesting another review.

βŒ› How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 727dc44 and 4835297.

πŸ“’ Files selected for processing (1)
  • mock/mock.go

Walkthrough

Mock TTY channels switched to mixed-type messages (chan any); terminal Reset made idempotent; added Cell type and expanded MockTty public fields; input state machine extended with ESC-# (3Fp) handling including DECALN; drain/checkpoint synchronization introduced; new tests for DECALN and cursor movement added.

Changes

Cohort / File(s) Change Summary
Mock I/O, state & types
mock/mock.go
Replaced ReadQ/WriteQ from chan byte to chan any (128 cap); added exported Cell type and expanded MockTty public fields (Cols, X, Fg, Bg, Attr); added state3Fp and handle3Fp(final byte); extended input state machine to handle ESC-# (3Fp) sequences (e.g., DECALN); updated Run/Read/Write to process mixed message types and drain/checkpoint signaling; adjusted OSC/PM/SOS/APC/DCS transitions; Reset now sets default 24x80 only when rows/cols are zero.
Tests
mock/mock_test.go
Added TestMockDECALN and TestMockCursorMovement; imported vt types; tests validate DECALN-populated cells, attributes (Fg/Bg/Attr), and cursor movement across escape sequences.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • attention points:
    • type assertions and safety when receiving chan any messages in Run/Read/Write
    • correctness and integration of state3Fp and ESC-# handling with existing escape-state transitions
    • drain/checkpoint signaling correctness and potential deadlock/race conditions
    • public API additions (Cell, new MockTty fields) and corresponding test coverage

Possibly related PRs

Poem

🐰 I hop through queues where bytes once lay,
Now mixed voices chatter, checkpointed on the way.
DECALN lays tiles where blank screens slept,
Cursors dance and tests have leapt.
A happy hare nibbles code and calls it day. πŸ₯•

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title uses the vague term 'improvements' without specifying the main changes, which are cursor movement testing, drain synchronization, and DECALN support. Consider using a more specific title like 'Add cursor movement tests and DECALN support to mock' to better convey the primary changes.
βœ… Passed checks (1 passed)
Check name Status Explanation
Description Check βœ… Passed Check skipped - CodeRabbit’s high-level summary is enabled.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❀️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link

codecov bot commented Dec 22, 2025

Codecov Report

❌ Patch coverage is 66.66667% with 25 lines in your changes missing coverage. Please review.
βœ… Project coverage is 30.76%. Comparing base (86fb56b) to head (4835297).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
mock/mock.go 66.66% 22 Missing and 3 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #919      +/-   ##
==========================================
+ Coverage   29.40%   30.76%   +1.36%     
==========================================
  Files          41       41              
  Lines        3731     3787      +56     
==========================================
+ Hits         1097     1165      +68     
+ Misses       2535     2521      -14     
- Partials       99      101       +2     

β˜” View full report in Codecov by Sentry.
πŸ“’ 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.
  • πŸ“¦ JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
mock/mock.go (1)

606-622: Consider potential blocking on channel send.

The WriteQ <- wcq send on line 611 could block if the channel buffer (128) is full and run() is not consuming. While the current test patterns call Drain() before Stop(), consider wrapping this send in a select with the timeout or stopQ to prevent indefinite blocking if called in unexpected scenarios.

πŸ”Ž Optional defensive improvement
 func (mt *MockTty) Drain() error {
 	wcq := make(chan struct{})
-	mt.WriteQ <- wcq
+	select {
+	case mt.WriteQ <- wcq:
+	case <-mt.stopQ:
+		return nil
+	case <-time.After(time.Millisecond * 200):
+		return nil
+	}
 	select {
 	case <-wcq:
 	case <-time.After(time.Millisecond * 200):
 	}
πŸ“œ Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 86fb56b and cef66e8.

πŸ“’ Files selected for processing (2)
  • mock/mock.go
  • mock/mock_test.go
🧰 Additional context used
🧠 Learnings (1)
πŸ“š Learning: 2025-12-18T02:50:37.669Z
Learnt from: gdamore
Repo: gdamore/tcell PR: 908
File: stdin_unix.go:128-155
Timestamp: 2025-12-18T02:50:37.669Z
Learning: In the tcell Tty interface implementations (stdin_unix.go, tty_unix.go, tty_win.go, tty_plan9.go), the caller is responsible for providing synchronization/mutual exclusion guarantees for method calls like NotifyResize. The Tty implementations themselves do not need internal locking for these methods, as documented in tty.go. The tscreen.go layer handles the synchronization.

Applied to files:

  • mock/mock_test.go
🧬 Code graph analysis (2)
mock/mock.go (2)
color.go (2)
  • ColorWhite (73-73)
  • ColorBlack (58-58)
attr.go (1)
  • AttrNone (35-35)
mock/mock_test.go (4)
mock/mock.go (1)
  • MockTty (42-72)
color.go (3)
  • ColorWhite (73-73)
  • ColorBlack (58-58)
  • ColorRed (67-67)
attr.go (2)
  • AttrNone (35-35)
  • AttrBold (28-28)
vt/coord.go (2)
  • Col (25-25)
  • Row (22-22)
πŸ”‡ Additional comments (8)
mock/mock_test.go (3)

24-26: LGTM!

Import addition for vt package is appropriate for using vt.Col and vt.Row types in the cursor movement test.


48-100: LGTM!

Well-structured test for DECALN functionality. The test correctly:

  • Validates all 15 cells are filled with 'E'
  • Checks default attributes in the first phase
  • Verifies custom attributes (Red foreground, Bold) are applied in the second phase
  • Tests the Start/Stop/Restart cycle

102-148: LGTM!

Comprehensive test coverage for cursor movement primitives:

  • CUP (H) for absolute positioning
  • CUU/CUD (A/B) for vertical movement with boundary clamping
  • CUF/CUB (C/D) for horizontal movement with boundary clamping
  • CNL/CPL (E/F) for next/previous line with column reset

The checkPos helper keeps assertions concise and readable.

mock/mock.go (5)

53-54: LGTM!

Changing channel types from chan byte to chan any enables mixed-type messaging for control signals (checkpoints, drain notifications) alongside byte data. This is a reasonable approach for the mock's internal synchronization needs.


327-334: LGTM!

The type switch correctly handles both byte data and checkpoint channels. Closing the checkpoint channel signals drain completion to the waiting caller.


554-591: LGTM!

The Read function correctly handles the mixed-type channel:

  • Byte data is processed normally
  • Checkpoint channels are closed to signal completion
  • Boolean drain signals return immediately to unblock callers

636-650: LGTM!

Good improvement to make default size initialization idempotent. This allows tests to pre-configure custom dimensions (e.g., Rows: 3, Cols: 5) before calling Reset() without those values being overwritten.


503-511: LGTM!

Clean consolidation of unimplemented escape sequence states (PM, SOS, APC, DCS). They share termination logic (ST byte or ESC+backslash) and safely reset to stateInit.

This adds testing of the cursor movement primitives, and better
synchronization for the drain operation, as well as support for DECALN
and a supporting test case.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
mock/mock.go (1)

352-352: Consider setting Width field consistently across all Cell assignments.

While this PR correctly sets Width: 1 for new Cell assignments (DECALN at line 308, eraseCell at line 145), existing Cell assignments at lines 352 and 420 don't set the Width field, leaving it at zero. For consistency and to ensure display width calculations work correctly throughout the mock, consider setting Width explicitly for all Cell assignments:

  • Line 352: ASCII characters should have Width: 1
  • Line 420: UTF-8 characters should have Width calculated from uniseg.StringWidth(string(r))

Note: This is existing code not changed by this PR, so addressing it is optional and can be deferred to a future cleanup.

Example approach for UTF-8 width handling
// At line 420, calculate and set width
w := uniseg.StringWidth(string(r))
mt.Cells[ix] = Cell{C: []rune{r}, Fg: mt.Fg, Bg: mt.Bg, Attr: mt.Attr, Width: w}
if w > 1 && mt.X < mt.Cols {
    // ... existing continuation cell logic ...
}

Also applies to: 420-420

πŸ“œ Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between be32775 and 727dc44.

πŸ“’ Files selected for processing (1)
  • mock/mock.go
🧰 Additional context used
🧠 Learnings (2)
πŸ““ Common learnings
Learnt from: gdamore
Repo: gdamore/tcell PR: 908
File: stdin_unix.go:128-155
Timestamp: 2025-12-18T02:50:37.669Z
Learning: In the tcell Tty interface implementations (stdin_unix.go, tty_unix.go, tty_win.go, tty_plan9.go), the caller is responsible for providing synchronization/mutual exclusion guarantees for method calls like NotifyResize. The Tty implementations themselves do not need internal locking for these methods, as documented in tty.go. The tscreen.go layer handles the synchronization.
πŸ“š Learning: 2025-12-18T02:50:37.669Z
Learnt from: gdamore
Repo: gdamore/tcell PR: 908
File: stdin_unix.go:128-155
Timestamp: 2025-12-18T02:50:37.669Z
Learning: In the tcell Tty interface implementations (stdin_unix.go, tty_unix.go, tty_win.go, tty_plan9.go), the caller is responsible for providing synchronization/mutual exclusion guarantees for method calls like NotifyResize. The Tty implementations themselves do not need internal locking for these methods, as documented in tty.go. The tscreen.go layer handles the synchronization.

Applied to files:

  • mock/mock.go
🧬 Code graph analysis (1)
mock/mock.go (2)
color.go (2)
  • ColorWhite (73-73)
  • ColorBlack (58-58)
attr.go (1)
  • AttrNone (35-35)
πŸ”‡ Additional comments (9)
mock/mock.go (9)

34-41: Well-structured Cell type.

The new Cell type properly captures all necessary display cell information including the Width field for handling multi-width characters. The struct is cleanly defined and well-documented.


55-56: Channel type change enables synchronization primitives.

The change from chan byte to chan any for ReadQ and WriteQ is well-motivated, enabling the checkpoint mechanism in Drain() to send control messages alongside data bytes. The type change is consistently applied throughout all I/O handling code.


296-313: DECALN implementation correctly addresses previous feedback.

The handle3Fp method properly implements DECALN support:

  • State is reset to stateInit at line 298 (previous review issue resolved).
  • Width: 1 is explicitly set at line 308 (previous review issue resolved).
  • The implementation correctly fills all screen cells with 'E' when no intermediate bytes are present.

332-339: Clean handling of mixed message types in run().

The type switch correctly processes both data bytes and checkpoint control messages from WriteQ. Closing the checkpoint channel signals completion to the waiting Drain() call, enabling proper write synchronization.


483-485: State machine properly integrates ESC-# handling.

The state machine correctly integrates the new state3Fp:

  • Transition occurs on '#' in escape state (lines 483-485).
  • Intermediate bytes (0x20-0x2F) are buffered, final bytes (0x30-0x3F) trigger handle3Fp.
  • State reset is handled within handle3Fp (line 298), ensuring the state machine returns to stateInit after processing.
  • Unexpected bytes trigger proper fallback to stateInit.

Also applies to: 517-525


559-577: Read() correctly handles mixed message types for blocking and non-blocking phases.

The implementation properly distinguishes between blocking (first byte) and non-blocking (subsequent bytes) read phases:

  • First byte (blocking): Checkpoint and bool signals interrupt the read by returning 0, nil, which is correct for drain synchronization.
  • Subsequent bytes (non-blocking): Checkpoints are closed but don't interrupt the read, allowing more data to be collected if available.

This design correctly supports both data transfer and control signaling through the same channel.

Also applies to: 583-590


611-631: Robust checkpoint mechanism for drain synchronization.

The Drain() implementation uses a well-designed checkpoint mechanism:

  1. Checkpoint sent to WriteQ ensures all prior writes are processed.
  2. Waiting with a 200ms timeout prevents indefinite blocking.
  3. Bool signal to ReadQ interrupts any pending blocking read.

The non-blocking send pattern (select with stopQ) ensures Drain() won't deadlock if channels are full or not being actively read.


645-650: Reset() idempotence improves flexibility.

The conditional dimension initialization (only setting 24Γ—80 defaults when zero) makes Reset() idempotent and allows test code to specify custom terminal dimensions before initialization. This is a sensible design for test infrastructure.


658-659: Channel initialization consistent with type changes.

The initialization of WriteQ and ReadQ as chan any with 128-element buffers is consistent with the type declarations and provides appropriate buffering for mock I/O operations.

@gdamore gdamore merged commit 8de88c1 into main Dec 22, 2025
15 checks passed
@gdamore gdamore deleted the more-mock branch December 22, 2025 03:34
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