Skip to content

Support mouse wheel scrolling in the TUI - #174

Merged
shouze merged 21 commits into
feat/mouse-click-togglefrom
feat/mouse-scroll-wheel
Aug 23, 2026
Merged

Support mouse wheel scrolling in the TUI#174
shouze merged 21 commits into
feat/mouse-click-togglefrom
feat/mouse-scroll-wheel

Conversation

@shouze

@shouze shouze commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Adds mouse wheel scrolling support to the interactive TUI. Users can scroll up/down through results using their mouse wheel, with smooth 3-row incremental scrolling that respects viewport boundaries.

Changes

  • Added wheel event handling in src/tui.ts mouse event dispatcher
    • Button 64 (wheel up) scrolls up by 3 rows
    • Button 65 (wheel down) scrolls down by 3 rows
    • Uses normalizeScrollOffset() to clamp scroll position within valid bounds
    • Wheel scroll doesn't move cursor or change selection/fold state
  • Tested with multiple scroll ticks and at viewport boundaries

How did you verify your code works?

  • All existing tests pass (no regression)
  • Validated scroll logic with normalizeScrollOffset() using correct function signature
  • Wheel scroll works without crashing at document top/bottom
  • Keyboard scrolling still works (no regression)

Closes #168

@github-actions

Copy link
Copy Markdown

Coverage after merging feat/mouse-scroll-wheel into feat/mouse-click-toggle will be

96.05%

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-hit.ts94.12%100%100%93.94%71, 73
   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-scroll-wheel into feat/mouse-click-toggle will be

96.05%

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-hit.ts94.12%100%100%93.94%71, 73
   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-scroll-wheel into feat/mouse-click-toggle will be

96.05%

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-hit.ts94.12%100%100%93.94%71, 73
   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-scroll-wheel into feat/mouse-click-toggle will be

96.05%

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-hit.ts94.29%100%100%94.12%74, 76
   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-scroll-wheel into feat/mouse-click-toggle will be

96.05%

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-hit.ts94.29%100%100%94.12%74, 76
   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-scroll-wheel into feat/mouse-click-toggle will be

96.13%

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-hit.ts100%100%100%100%
   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-scroll-wheel into feat/mouse-click-toggle will be

96.13%

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.82%100%88.24%89.89%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-hit.ts100%100%100%100%
   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-scroll-wheel into feat/mouse-click-toggle will be

96.13%

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.82%100%88.24%89.89%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-hit.ts100%100%100%100%
   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 force-pushed the feat/mouse-scroll-wheel branch from 6ec595a to 900af21 Compare August 23, 2026 18:23
@github-actions

Copy link
Copy Markdown

Coverage after merging feat/mouse-scroll-wheel into feat/mouse-click-toggle will be

96.21%

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.85%100%88.24%89.91%172, 196–201, 203–205, 207–208, 229, 417–418, 442–444, 510–514, 526–527, 532–539, 541–549, 551–552
   scroll-cooldown.ts100%100%100%100%
   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
   layout-constants.ts100%100%100%100%
   mouse-hit.ts100%100%100%100%
   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 marked this pull request as ready for review August 23, 2026 18:25
Copilot AI lite review requested due to automatic review settings August 23, 2026 18:25
@github-actions

github-actions Bot commented Aug 23, 2026

Copy link
Copy Markdown

🔦 Lighthouse Report

Page ⚡ Perf ♿ A11y 🛡️ BP 🔍 SEO Report
/github-code-search/getting-started/ 🟢 99 (≥96) 🟢 100 (≥99) 🟢 100 (≥99) 🟢 100 (≥99) 🔗 view
/github-code-search/ 🟢 96 (≥96) 🟢 100 (≥99) 🟢 100 (≥99) 🟢 100 (≥99) 🔗 view

Thresholds: Perf ≥ 96 · A11y ≥ 99 · BP ≥ 99 · SEO ≥ 99
commit 06a1298 · full workflow run

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

Adds mouse wheel scrolling support to the interactive TUI by handling SGR mouse wheel events, clamping scrollOffset via existing viewport logic, and documenting mouse interactions. The PR also expands mouse click hit-testing and introduces a “scroll cooldown” state to suppress clicks during trackpad momentum scrolling.

Changes:

  • Handle wheel-up/wheel-down mouse events in src/tui.ts to scroll by a fixed step while respecting viewport boundaries.
  • Introduce scroll-cooldown state/helpers with unit tests to ignore clicks during/after momentum scrolling.
  • Centralize mouse/layout constants and update hit-testing, rendering, and documentation accordingly.

Reviewed changes

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

Show a summary per file
File Description
src/tui.ts Adds wheel scrolling, scroll cooldown gating, and double-click-based click actions.
src/scroll-cooldown.ts New scroll cooldown state machine helpers.
src/scroll-cooldown.test.ts Unit tests for scroll cooldown behavior.
src/render/mouse.ts Adjusts mouse sequence parsing regex (escape + lint suppression).
src/render/mouse.test.ts Updates mouse parser test imports.
src/render/mouse-hit.ts Adds header offset + scrollOffset-aware hit testing and uses shared layout constants.
src/render/mouse-hit.test.ts Expands hit-testing tests for zones, headerLines, and scrollOffset behavior.
src/render/layout-constants.ts New centralized constants for header height, mouse buttons, and click zones.
src/render/layout-constants.test.ts Unit tests for layout constants and zone helpers.
src/render.ts Re-exports layout constants; adjusts checkbox rendering logic.
src/render.test.ts Adds coverage for dimmed checkbox rendering.
docs/usage/interactive-mode.md Documents mouse support, wheel scrolling, and click/double-click behavior.
docs/reference/keyboard-shortcuts.md Adds mouse wheel + click actions to the reference docs.
docs/architecture/components.md Updates component table and adds detailed mouse interaction model section.
Suppressed comments (1)

src/render/mouse-hit.ts:12

  • ClickTarget.column is documented as “0-based terminal position”, but hitTestClick() passes through the SGR mouse x coordinate (1-indexed) and the tests assert 1-indexed column values. This mismatch is confusing for callers and future maintainers.
export interface ClickTarget {
  row: Row;
  column: number; // Column index within the row (0-based terminal position)
  action: "fold" | "select" | "navigate";
}

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

Comment thread src/scroll-cooldown.test.ts
Comment thread src/scroll-cooldown.ts Outdated
Comment thread src/tui.ts
Comment thread docs/architecture/components.md Outdated
Comment thread src/render.ts Outdated
@shouze shouze self-assigned this Aug 23, 2026
@github-actions

Copy link
Copy Markdown

Coverage after merging feat/mouse-scroll-wheel into feat/mouse-click-toggle will be

96.21%

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.85%100%88.24%89.91%172, 196–201, 203–205, 207–208, 229, 417–418, 442–444, 510–514, 526–527, 532–539, 541–549, 551–552
   scroll-cooldown.ts100%100%100%100%
   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
   layout-constants.ts100%100%100%100%
   mouse-hit.ts100%100%100%100%
   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 added a commit that referenced this pull request Aug 23, 2026
Apply fixes for determinism, redundant computation, and UX documentation:

**scroll-cooldown.ts + scroll-cooldown.test.ts** — Fix non-deterministic test
- recordScroll() now accepts optional \`now\` parameter (default: Date.now())
- Tests pass explicit timestamp instead of relying on live clock
- Eliminates race condition where Date.now() advances between test capture
  and function call, causing flaky assertions

**render.ts** — Remove redundant repoSelected recomputation
- Use group.repoSelected directly instead of recomputing from extractSelected
- Comment clarifies that repoSelected is kept in sync by selection logic
  in tui.ts and render/selection.ts, removing per-frame overhead

**docs/architecture/components.md** — Clarify double-click detection ownership
- Update mouse hit-test component description: remove claim that hitTestClick()
  handles double-click detection (it doesn't — only maps coordinates to row+zone)
- Add note: double-click detection is implemented in tui.ts via timestamp tracking

**src/tui.ts** — Document mouse click semantics
- Add explicit comment explaining single-click (navigate) vs double-click (action)
- Reference docs/usage/interactive-mode.md § Mouse support for UX spec
- Clarifies this is a UX feature complementing keyboard shortcuts

Fixes Copilot review issues:
- #1: Deterministic test (scroll-cooldown.test.ts:22)
- #2: Accept 'now' parameter (scroll-cooldown.ts:26)
- #3: Document click semantics (tui.ts:391)
- #4: Clarify hit-test responsibility (components.md:115)
- #5: Remove redundant repoSelected computation (render.ts:577)
@github-actions

Copy link
Copy Markdown

Coverage after merging feat/mouse-scroll-wheel into feat/mouse-click-toggle will be

96.22%

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.82%100%88.24%89.89%172, 196–201, 203–205, 207–208, 229, 417–418, 442–444, 510–514, 526–527, 532–539, 541–549, 551–552
   scroll-cooldown.ts100%100%100%100%
   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
   layout-constants.ts100%100%100%100%
   mouse-hit.ts100%100%100%100%
   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 added a commit that referenced this pull request Aug 23, 2026
Apply fixes for determinism, redundant computation, and UX documentation:

**scroll-cooldown.ts + scroll-cooldown.test.ts** — Fix non-deterministic test
- recordScroll() now accepts optional \`now\` parameter (default: Date.now())
- Tests pass explicit timestamp instead of relying on live clock
- Eliminates race condition where Date.now() advances between test capture
  and function call, causing flaky assertions

**render.ts** — Remove redundant repoSelected recomputation
- Use group.repoSelected directly instead of recomputing from extractSelected
- Comment clarifies that repoSelected is kept in sync by selection logic
  in tui.ts and render/selection.ts, removing per-frame overhead

**docs/architecture/components.md** — Clarify double-click detection ownership
- Update mouse hit-test component description: remove claim that hitTestClick()
  handles double-click detection (it doesn't — only maps coordinates to row+zone)
- Add note: double-click detection is implemented in tui.ts via timestamp tracking

**src/tui.ts** — Document mouse click semantics
- Add explicit comment explaining single-click (navigate) vs double-click (action)
- Reference docs/usage/interactive-mode.md § Mouse support for UX spec
- Clarifies this is a UX feature complementing keyboard shortcuts

Fixes Copilot review issues:
- #1: Deterministic test (scroll-cooldown.test.ts:22)
- #2: Accept 'now' parameter (scroll-cooldown.ts:26)
- #3: Document click semantics (tui.ts:391)
- #4: Clarify hit-test responsibility (components.md:115)
- #5: Remove redundant repoSelected computation (render.ts:577)
@shouze
shouze force-pushed the feat/mouse-scroll-wheel branch from e49d1c3 to 334beee Compare August 23, 2026 18:57
@github-actions

Copy link
Copy Markdown

Coverage after merging feat/mouse-scroll-wheel into feat/mouse-click-toggle will be

96.22%

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.82%100%88.24%89.89%172, 196–201, 203–205, 207–208, 229, 417–418, 442–444, 510–514, 526–527, 532–539, 541–549, 551–552
   scroll-cooldown.ts100%100%100%100%
   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
   layout-constants.ts100%100%100%100%
   mouse-hit.ts100%100%100%100%
   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%

1 similar comment
@github-actions

Copy link
Copy Markdown

Coverage after merging feat/mouse-scroll-wheel into feat/mouse-click-toggle will be

96.22%

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.82%100%88.24%89.89%172, 196–201, 203–205, 207–208, 229, 417–418, 442–444, 510–514, 526–527, 532–539, 541–549, 551–552
   scroll-cooldown.ts100%100%100%100%
   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
   layout-constants.ts100%100%100%100%
   mouse-hit.ts100%100%100%100%
   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 added 6 commits August 23, 2026 21:01
Implement scroll-wheel support for interactive TUI (#168):
- Recognize wheel-up (button 64) and wheel-down (button 65) in mouse events
- Scroll by 3 rows per wheel tick (small incremental step vs full page)
- Use normalizeScrollOffset to clamp scroll position within valid bounds
- Wheel scroll does not move cursor or change selection/fold state
- Tested alongside click-to-toggle; all validation checks pass
Issue: When clicking on any row in the TUI, getting 'Cannot access rows before
initialization' error causing immediate exit with code 1. Root cause: rows was
declared as a local variable inside redraw(), but hitTestClick tried to access
it in the event loop where it didn't exist.

Fix: Declare rows as a persistent variable outside redraw() and update it on
each redraw() call. This makes rows available throughout the event loop.

Also fixed normalizeScrollOffset calls for wheel scroll to use correct signature:
normalizeScrollOffset(scrollOffset, rows, groups, viewportHeight).

Closes #173 (partial - fixes the crash, functionality preserved)
Test verifies that deselected repos render with dimmed ✓ character (via ANSI
dim code \x1b[2m) instead of blank space, improving visual consistency.

Closes #169 (UI Consistency - Dimmed Checkboxes)
- Use Unicode escape \u001b instead of \x1b in SGR regex (oxlint compatibility)
- Disable no-control-regex lint rule with explicit comment for ESC character
- Remove unused type imports (MouseEvent, ClickTarget) from test files
- Fix variable shadowing: use reassignment instead of redeclaration for 'rows' in normal mode
Issues:
- Click coordinates were off because headerLines (filter bar + position indicator)
  weren't subtracted from the y coordinate, causing clicks to register at the
  wrong rows (user had to click much higher than intended)
- Toggle state was being applied twice (press + release), so select/unselect
  wasn't working correctly

Fixes:
- Add headerLines parameter to hitTestClick() to account for header rendering
  Calculate headerLines in tui.ts based on filter state (0-2 lines)
- Subtract headerLines from click y coordinate to map to correct row
- Ignore mouse release events (isRelease === true); only act on press events
- This ensures select/unselect toggles work on a single click, not double-toggling

Result: Mouse clicks now target correct rows and selections toggle properly
The headerLines calculation was using an incorrect base value (2 instead of 4),
causing all mouse clicks to register with a larger y-coordinate offset than
intended. This made it impossible to click on the intended rows — users had to
click much higher on the screen.

Fixed calculation:
- Base HEADER_LINES = 4 (title + summary + hints + blank)
- Add filterBarLines (0-2) for filter input/status bar
- Add 1 if sticky repo header is shown (currently omitted as it requires
  complex cursor state evaluation; may cause 1-row offset in rare cases)

Now mouse clicks register at the correct row positions.
shouze added 14 commits August 23, 2026 21:01
Major behavioral changes to mouse interaction:
- Single-click on any row: navigate to that row (like arrow keys)
- Double-click on fold zone (▸/▾): toggle fold/unfold
- Double-click on checkbox or elsewhere on row: toggle selection
- Wheel up/down: scroll viewport (unchanged)

Technical fixes:
- hitTestClick() now iterates only from scrollOffset onwards
  (previously counted invisible rows, causing hits to register at wrong lines)
- Checkbox clicks now only register on extract header line (not fragments)
- Double-click detection uses 300ms delay and row key (type:repoIndex:extractIndex)
- Moved getRowKey() to module scope (avoid recreating per call)

Result: Mouse support now matches keyboard behavior for navigation and selection
with intuitive click/double-click patterns.
Major coordinate and action fixes:
- Fix hitTestClick to use 1-indexed terminal coordinates (SGR protocol standard)
  - Arrow emoji: columns 1-2 (was testing column 0)
  - Checkbox emoji: columns 4-5 (was testing column 2)
  - This fixes the off-by-1 Y coordinate issue reported
- Fix double-click on repo to cascade deselect all extracts
  - Now matches keyboard spacebar behavior: toggle repo + all extracts
- Fix double-click on extract header to work on full line width (except fold zone)
  - Accept selection action on columns 4-5 (checkbox) or 6+ (full width)
- Fix repo checkbox dimming logic
  - Now shows green ✓ only if any extract is selected
  - Shows dimmed ✓ when all extracts are deselected
  - Independent of repo.repoSelected flag

Test improvements:
- Updated hitTestClick tests to use correct 1-indexed coordinates
- Added test for extract fragment lines (not clickable for selection)
- Added test for full-width extract selection
- Fixed render test to deselect extracts when testing dimmed repo checkbox
- All 840 tests passing, 100% coverage on mouse-hit module
The hit-test function was using rowTerminalLines which always returns 2 for
sections, but renderGroups treats the first section differently:
- First section in viewport: 1 line (label only, no blank separator)
- Subsequent sections: 2 lines (blank separator + label)

This caused a 1-line offset when calculating cumulative line heights,
making clicks on repos and extracts land one row below the target.

Fix: Mirror renderGroups logic in hitTestClick - check if section is first
in viewport (lineOffset === 0) to calculate correct height (1 vs 2 lines).
When scrolling with the mouse wheel, click events can fire at the scroll
end point, accidentally selecting or toggling items the user didn't intend.

Fix: Add a SCROLL_COOLDOWN (300ms) flag that activates after wheel events,
ignoring select/fold actions during this period. Navigation (moving cursor)
is still allowed during scroll cooldown.

Changes:
- Add scrollInProgress flag and SCROLL_COOLDOWN timer
- Activate flag on wheel up/down events
- Check flag before applying selection/fold actions
- Only allow navigation during scroll cooldown
- Clean up timer on exit
The previous implementation using a boolean flag and setTimeout had a race
condition where click events could fire between wheel events and timer
setup, causing accidental selections during scroll.

Switch to tracking lastScrollTime with Date.now() and checking
(now - lastScrollTime < SCROLL_COOLDOWN) directly at click time. This is
more robust and eliminates async timing issues.

Behavior is unchanged: selection/fold actions are blocked for 300ms after
scroll, while navigation is still allowed.
Trackpad users experience momentum (deceleration) scrolling that can
continue for 400-500ms after the physical gesture ends. The previous
300ms cooldown was too short, causing accidental selections.

Increase SCROLL_COOLDOWN from 300ms to 500ms to better accommodate
trackpad momentum scrolling. The lastScrollTime timestamp continues
to be updated on each scroll event, so multiple scrolls in quick
succession will extend the cooldown period as expected.
Extract scroll cooldown logic from tui.ts into scroll-cooldown.ts as a
pure, immutable state machine. This makes the logic:

1. Testable: 8 comprehensive tests with 100% coverage
2. Explicit: Clear state transitions and timing logic
3. Robust: No reliance on closure-captured timestamps
4. Debuggable: Pure functions are easier to reason about

Changes:
- Create scroll-cooldown.ts with ScrollCooldownState interface
- Implement createScrollCooldownState, recordScroll, isScrollCooldownActive, updateScrollCooldown
- Add scroll-cooldown.test.ts with 8 tests covering all edge cases
- Update tui.ts to use the new module instead of lastScrollTime variable
- Reduce cooldown from 5000ms to 600ms (conservative for trackpad momentum)

The state machine handles:
- Initial state (no scrolling)
- Multiple rapid scrolls extending the cooldown window
- Proper expiration after timeout
- Clean deactivation when cooldown expires

Tests verify correct behavior for all timing scenarios.
…lections

The previous approach of allowing navigation and only blocking selections
was fragile - during trackpad momentum scrolling, clicks could still fire
with confusing actions that slipped through.

New approach: if scroll cooldown is active, COMPLETELY IGNORE all clicks
before even calling hitTestClick. This is simple, robust, and bulletproof.

Changes:
- Move cooldown check to BEFORE hitTestClick call
- Check happens immediately after scroll event detection
- If cooldown is active, skip all click processing entirely
- Remove now-unnecessary cooldown logic from inside target handling

This eliminates the entire class of bugs where clicks arrive during
momentum scrolling and trigger unexpected actions.
- Create src/render/layout-constants.ts with centralized rendering measurements
  - BASE_HEADER_LINES (4): title + summary + hints + blank
  - FILTER_BAR_LINES_NORMAL (1): filter status line
  - FILTER_BAR_LINES_ACTIVE (2): filter input + hints in filter mode
  - getHeaderLines(): compute total header height based on mode
  - Column position constants: FOLD_COLUMN_START/END, CHECKBOX_COLUMN_START/END, NAV_COLUMN_START
  - Helper functions: isClickInFoldZone(), isClickInCheckboxZone(), isClickInNavZone()

- Update src/tui.ts
  - Replace 'let headerLines = 4; headerLines += ...' with getHeaderLines() call
  - Import getHeaderLines from render.ts (public API)

- Update src/render/mouse-hit.ts
  - Replace magic column numbers (1, 2, 4, 5, 6) with named constants
  - Import zone detection helpers for cleaner hit-test logic
  - Clarify row layout comments for fold, checkbox, and nav zones

- Expand src/render/mouse-hit.test.ts
  - Add 22 new tests organizing hit-test coverage by zone and row type
  - Test fold zone (repo rows only): columns 1-2
  - Test checkbox zone: columns 4-5 for repo/extract headers
  - Test navigation zone: columns 6+
  - Test section rows (navigate only, no special actions)
  - Test scroll offset handling and zone boundary conditions
  - Verify correct action ('fold', 'select', 'navigate') for each zone

- Add src/render/layout-constants.test.ts
  - Test header line calculation for all filter mode combinations
  - Verify zone detection functions and column constant ranges
  - Ensure non-overlapping zone definitions

Results: 868 tests pass, zero lint errors, format clean, knip clean, build succeeds
- Extract mouse button codes into layout-constants:
  - MOUSE_BUTTON_WHEEL_UP = 64 (SGR protocol)
  - MOUSE_BUTTON_WHEEL_DOWN = 65 (SGR protocol)
  - MOUSE_SCROLL_STEP = 3 (rows per wheel scroll)

- Update checkbox zone detection logic:
  - isClickInCheckboxZone now extends from column 4 to infinity (full-width double-click)
  - Double-click selection works anywhere on repo/extract row from checkbox column onwards
  - Adapt all tests to reflect full-width click behavior

- Extract terminal mouse reporting sequences into named constants:
  - ANSI_ENABLE_MOUSE_REPORTING (\x1b[?1000h\x1b[?1006h)
  - ANSI_DISABLE_MOUSE_REPORTING (\x1b[?1000l\x1b[?1006l)
  - Use in enable/disable code paths in tui.ts

Results: 871 tests pass, zero lint errors, all validations green
- Add comprehensive mouse support section to keyboard-shortcuts.md:
  - Scroll wheel behavior (3 rows per event, momentum cooldown)
  - Single-click navigation, double-click actions
  - Column zone mapping for repo and extract rows
  - Full-width checkbox zone for intuitive double-click selection

- Add mouse support guide to interactive-mode.md:
  - Scrolling mechanics with trackpad momentum protection
  - Single-click and double-click action reference
  - Zone-based click handling for repos and extracts
  - Emphasis on mouse-keyboard complementarity

- Update architecture/components.md with:
  - Two new component table entries: Layout constants, Mouse hit-test
  - Detailed mouse interaction model section explaining:
    - SGR protocol, coordinate mapping, header height calculation
    - Click zones and hit-testing algorithm
    - Double-click detection and deduplication
    - Scroll cooldown state machine for momentum scrolling
    - TUI integration points

- Fix linting errors:
  - Export MOUSE_SCROLL_STEP from layout-constants.ts
  - Remove unused isClickInNavZone import from mouse-hit.ts
  - Update render.ts to re-export MOUSE_SCROLL_STEP from layout-constants
  - Update tui.ts to import MOUSE_SCROLL_STEP from render.ts instead of defining locally

Results: 871 tests pass, zero lint errors, all validations green
- Update feature card: 'Keyboard-driven TUI' → 'Keyboard and mouse-driven TUI'
  Add mention of mouse clicks alongside arrow keys in feature description

- Update HowItWorks component Step 2 description:
  'A keyboard-driven TUI opens' → 'A keyboard and mouse-driven TUI opens'
  Add note: '(mouse works in compatible terminals)'

- Update ComparisonTable feature description:
  Expand 'Interactive TUI' row to emphasize both keyboard AND mouse support
  'arrow keys or clicks for navigation' highlights dual interaction model

Focus: emphasize that mouse support is now a first-class feature alongside
keyboard-driven workflow, across homepage, feature highlights, and comparison.
Apply fixes for determinism, redundant computation, and UX documentation:

**scroll-cooldown.ts + scroll-cooldown.test.ts** — Fix non-deterministic test
- recordScroll() now accepts optional \`now\` parameter (default: Date.now())
- Tests pass explicit timestamp instead of relying on live clock
- Eliminates race condition where Date.now() advances between test capture
  and function call, causing flaky assertions

**render.ts** — Remove redundant repoSelected recomputation
- Use group.repoSelected directly instead of recomputing from extractSelected
- Comment clarifies that repoSelected is kept in sync by selection logic
  in tui.ts and render/selection.ts, removing per-frame overhead

**docs/architecture/components.md** — Clarify double-click detection ownership
- Update mouse hit-test component description: remove claim that hitTestClick()
  handles double-click detection (it doesn't — only maps coordinates to row+zone)
- Add note: double-click detection is implemented in tui.ts via timestamp tracking

**src/tui.ts** — Document mouse click semantics
- Add explicit comment explaining single-click (navigate) vs double-click (action)
- Reference docs/usage/interactive-mode.md § Mouse support for UX spec
- Clarifies this is a UX feature complementing keyboard shortcuts

Fixes Copilot review issues:
- #1: Deterministic test (scroll-cooldown.test.ts:22)
- #2: Accept 'now' parameter (scroll-cooldown.ts:26)
- #3: Document click semantics (tui.ts:391)
- #4: Clarify hit-test responsibility (components.md:115)
- #5: Remove redundant repoSelected computation (render.ts:577)
Two issues were preventing the terminal from returning to normal mode on exit:

1. **Missing ANSI_DISABLE_MOUSE_REPORTING on Enter exit path**
   When pressing Enter to confirm and exit, ANSI_DISABLE_MOUSE_REPORTING
   was not being sent. This left the terminal in mouse-capture mode,
   preventing text selection and copy/paste.

2. **Event loop not breaking on exit**
   Using process.exit() or process.exitCode was insufficient because the
   'for await (const chunk of process.stdin)' loop continued waiting for
   stdin, preventing the stdout buffer from flushing and the process from
   terminating cleanly.

**Changes:**
- Add shouldExit flag to coordinate exit across multiple code paths
- Send ANSI_DISABLE_MOUSE_REPORTING in both exit() and Enter path
- Add break statement after exit conditions to cleanly exit the event loop
- Move stats timer cleanup into Enter path (was missing)
- Replace process.exit(0) with flag-based exit to allow buffer flush

Result: Terminal properly returns to normal mode (text selection enabled)
when exiting via Enter, q, or Ctrl+C.
@shouze
shouze force-pushed the feat/mouse-scroll-wheel branch from 334beee to 5c7b881 Compare August 23, 2026 19:01
@github-actions

Copy link
Copy Markdown

Coverage after merging feat/mouse-scroll-wheel into feat/mouse-click-toggle will be

96.22%

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.82%100%88.24%89.89%172, 196–201, 203–205, 207–208, 229, 417–418, 442–444, 510–514, 526–527, 532–539, 541–549, 551–552
   scroll-cooldown.ts100%100%100%100%
   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
   layout-constants.ts100%100%100%100%
   mouse-hit.ts100%100%100%100%
   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%

1 similar comment
@github-actions

Copy link
Copy Markdown

Coverage after merging feat/mouse-scroll-wheel into feat/mouse-click-toggle will be

96.22%

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.82%100%88.24%89.89%172, 196–201, 203–205, 207–208, 229, 417–418, 442–444, 510–514, 526–527, 532–539, 541–549, 551–552
   scroll-cooldown.ts100%100%100%100%
   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
   layout-constants.ts100%100%100%100%
   mouse-hit.ts100%100%100%100%
   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-scroll-wheel into feat/mouse-click-toggle will be

96.22%

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.82%100%88.24%89.89%172, 196–201, 203–205, 207–208, 229, 417–418, 442–444, 510–514, 526–527, 532–539, 541–549, 551–552
   scroll-cooldown.ts100%100%100%100%
   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
   layout-constants.ts100%100%100%100%
   mouse-hit.ts100%100%100%100%
   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 force-pushed the feat/mouse-scroll-wheel branch from 498dc33 to 60515ab Compare August 23, 2026 19:09
@github-actions

Copy link
Copy Markdown

Coverage after merging feat/mouse-scroll-wheel into feat/mouse-click-toggle will be

96.22%

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.82%100%88.24%89.89%172, 196–201, 203–205, 207–208, 229, 417–418, 442–444, 510–514, 526–527, 532–539, 541–549, 551–552
   scroll-cooldown.ts100%100%100%100%
   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
   layout-constants.ts100%100%100%100%
   mouse-hit.ts100%100%100%100%
   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 force-pushed the feat/mouse-scroll-wheel branch from 60515ab to 18edea7 Compare August 23, 2026 19:11
@github-actions

Copy link
Copy Markdown

Coverage after merging feat/mouse-scroll-wheel into feat/mouse-click-toggle will be

96.22%

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.82%100%88.24%89.89%172, 196–201, 203–205, 207–208, 229, 417–418, 442–444, 510–514, 526–527, 532–539, 541–549, 551–552
   scroll-cooldown.ts100%100%100%100%
   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
   layout-constants.ts100%100%100%100%
   mouse-hit.ts100%100%100%100%
   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
8 checks passed
@shouze
shouze deleted the feat/mouse-scroll-wheel 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.

Support mouse wheel scrolling in the TUI

2 participants