Skip to content

Enable SGR mouse tracking and parse mouse escape sequences - #172

Merged
shouze merged 2 commits into
feat/mouse-ui-checkboxfrom
feat/mouse-tracking-foundation
Aug 23, 2026
Merged

Enable SGR mouse tracking and parse mouse escape sequences#172
shouze merged 2 commits into
feat/mouse-ui-checkboxfrom
feat/mouse-tracking-foundation

Conversation

@shouze

@shouze shouze commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Establishes the foundation for mouse support in the interactive TUI by enabling SGR (Select Graphic Rendition) terminal mouse reporting. This allows the terminal to send mouse events (clicks, wheel scrolling) to the application in a structured format.

Changes

  • Created src/render/mouse.ts with SGR mouse event parser
    • Recognizes the SGR escape sequence format: \x1b[<button;x;yM (press) or m (release)
    • Button codes: 0/1/2 = left/middle/right click, 64/65 = wheel up/down
    • Coordinates are 1-indexed (1,1 is top-left corner)
    • Gracefully handles malformed sequences by returning null (no crash)
  • Created src/render/mouse.test.ts with 15 unit tests (100% coverage)
  • Modified src/tui.ts to enable SGR on startup and disable on exit
  • Added stdin loop to parse mouse events and pass them through the action pipeline

How did you verify your code works?

  • All 15 SGR parser unit tests pass with 100% coverage
  • Tested malformed sequences, edge coordinates (0,0), (999,999), and valid click/release pairs
  • Verified that mouse events don't crash the application (graceful null handling)
  • Existing keyboard tests still pass (no regression)
  • Terminal mouse reporting properly enabled on startup and disabled on exit

Closes #167

@shouze
shouze marked this pull request as ready for review August 23, 2026 18:24
Copilot AI lite review requested due to automatic review settings August 23, 2026 18:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR lays groundwork for future mouse support in the interactive TUI by enabling SGR mouse reporting and introducing a small parser + test suite for SGR mouse escape sequences.

Changes:

  • Enable SGR mouse reporting in runInteractive() and add a hook in the stdin loop to detect mouse sequences.
  • Add src/render/mouse.ts with an SGR mouse escape sequence parser returning structured mouse events (or null on non-matches).
  • Add unit tests for the parser in src/render/mouse.test.ts.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
src/tui.ts Enables/disables SGR mouse reporting and attempts to parse incoming stdin chunks as mouse events before keyboard handling.
src/render/mouse.ts Implements parseMouseEvent() for SGR \x1b[<b;x;yM/m sequences.
src/render/mouse.test.ts Adds unit tests for valid and malformed SGR mouse sequences.
Suppressed comments (1)

src/tui.ts:272

  • Mouse reporting is disabled in exit(), but runInteractive() has other termination paths that call process.exit(0) after doing partial cleanup (e.g. the Enter/confirm-selection branch later in the loop) and will now skip the mouse-disable sequence. To avoid leaving the user’s terminal with mouse reporting still enabled, consider centralizing all exits through this exit() helper (or ensuring every process.exit path disables ?1000/?1006).
  // ─── Exit handler for cleanup ────────────────────────────────────────────
  const exit = () => {
    // Disable SGR mouse reporting and clear terminal
    process.stdout.write("\x1b[?1000l\x1b[?1006l");
    process.stdout.write(ANSI_CLEAR);
    process.stdin.setRawMode(false);
    process.off("SIGWINCH", onResize);
    process.exit(0);

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/tui.ts
Comment thread src/render/mouse.test.ts Outdated
Comment thread src/tui.ts
@shouze shouze self-assigned this Aug 23, 2026
Implement mouse tracking foundation for interactive TUI (#167):
- Add src/render/mouse.ts with SGR parser for mouse events
- Parser recognizes button codes, coordinates, press/release
- Enable mouse tracking (\x1b[?1000h\x1b[?1006h) on TUI start
- Disable tracking (\x1b[?1000l\x1b[?1006l) on exit
- Wire parser into stdin loop in tui.ts; silently ignore unrecognized sequences
- 15 unit tests with 100% coverage for parseMouseEvent
- All validation checks pass (test, lint, format, knip, build)
@shouze
shouze force-pushed the feat/mouse-tracking-foundation branch from 78e051c to 19872c3 Compare August 23, 2026 18:53
@github-actions

Copy link
Copy Markdown

Coverage after merging feat/mouse-tracking-foundation into feat/mouse-ui-checkbox will be

96.08%

Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
src
   aggregate.ts100%100%100%100%
   api-utils.ts93.20%100%93.75%93.13%101–103, 65, 73, 86–87, 91–92
   api.ts94.74%100%100%94.07%340–344, 405, 422, 63–69
   cache.ts94.67%100%100%94.29%139–141, 39
   completions.ts99.42%100%100%99.37%270
   group.ts99.50%100%97.44%100%
   output.ts99.29%100%95.65%99.61%80
   regex.ts99.39%100%100%99.34%329
   render.ts89.80%100%88.24%89.86%166, 190–195, 197–199, 201–202, 223, 411–412, 436–438, 504–508, 520–521, 526–533, 535–543, 545–546
   upgrade.ts88.38%100%94.44%87.89%128, 131, 133, 153, 167–168, 188–195, 198–204, 209, 214, 250–253
src/render
   filter-match.ts97.44%100%92.31%100%
   filter.ts100%100%100%100%
   highlight.ts96.63%100%90.40%99.31%284–285
   mouse.ts100%100%100%100%
   rows.ts97.58%100%100%97.44%168, 54–55
   selection.ts100%100%100%100%
   summary.ts100%100%100%100%
   team-pick.ts100%100%100%100%
   terminal.ts100%100%100%100%

@github-actions

Copy link
Copy Markdown

Coverage after merging feat/mouse-tracking-foundation into feat/mouse-ui-checkbox will be

96.08%

Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
src
   aggregate.ts100%100%100%100%
   api-utils.ts93.20%100%93.75%93.13%101–103, 65, 73, 86–87, 91–92
   api.ts94.74%100%100%94.07%340–344, 405, 422, 63–69
   cache.ts94.67%100%100%94.29%139–141, 39
   completions.ts99.42%100%100%99.37%270
   group.ts99.50%100%97.44%100%
   output.ts99.29%100%95.65%99.61%80
   regex.ts99.39%100%100%99.34%329
   render.ts89.80%100%88.24%89.86%166, 190–195, 197–199, 201–202, 223, 411–412, 436–438, 504–508, 520–521, 526–533, 535–543, 545–546
   upgrade.ts88.38%100%94.44%87.89%128, 131, 133, 153, 167–168, 188–195, 198–204, 209, 214, 250–253
src/render
   filter-match.ts97.44%100%92.31%100%
   filter.ts100%100%100%100%
   highlight.ts96.63%100%90.40%99.31%284–285
   mouse.ts100%100%100%100%
   rows.ts97.58%100%100%97.44%168, 54–55
   selection.ts100%100%100%100%
   summary.ts100%100%100%100%
   team-pick.ts100%100%100%100%
   terminal.ts100%100%100%100%

@shouze
shouze merged commit 69a4122 into main Aug 23, 2026
5 checks passed
@shouze
shouze deleted the feat/mouse-tracking-foundation branch August 23, 2026 19:19
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.

Render a dimmed ✓ instead of blank space for deselected checkboxes

2 participants