fix(tui): Termux/Android touch-scroll via CellMotion + alternative scroll keys#503
fix(tui): Termux/Android touch-scroll via CellMotion + alternative scroll keys#503PatrickNoFilter wants to merge 8 commits into
Conversation
- mouseModeForTermEnv(): detect Termux/PRoot/Android env → use CellMotion (CellMotion is reliable through PRoot unlike AllMotion/1003 tracking) - Add Ctrl+U/D half-page scroll keys (Termux-friendly, no PgUp/PgDn needed) - Add Shift+Up/Down line scroll keys - Update keybinding help overlay with new shortcuts
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
WalkthroughAdds Termux/proot-aware mouse tracking selection, wires it into TUI rendering, and adds Shift+Up/Down plus Ctrl+U/Ctrl+D scroll handling with matching help text and tests. ChangesTermux compatibility
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant Model
participant mouseModeForTermEnv
participant View
participant KeyHandler
User->>Model: start TUI session
Model->>mouseModeForTermEnv: detect TERMUX_VERSION / PREFIX / ANDROID_ROOT
mouseModeForTermEnv-->>Model: CellMotion or AllMotion
Model->>View: render with m.mouseMode
User->>KeyHandler: press Shift+Up/Down or Ctrl+U/D
KeyHandler->>KeyHandler: route modal cursor or scroll transcript
KeyHandler-->>User: updated transcript or picker cursor
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@internal/tui/mouse.go`:
- Around line 15-23: The mouse mode detection in the function that reads
TERMUX_VERSION, PROOT_CWD, and CONTAINER is using the wrong signal for the
intended environment. Remove the uppercase CONTAINER check or replace it with
the actual environment indicator used by Termux/PRoot/container detection, and
keep the CellMotion fallback only when the real signal is present. Update the
conditional in internal/tui/mouse.go so the logic in that mouse-mode selector
matches the environments it is meant to detect.
- Line 16: In the proot detection logic in the mouse handling code, do not use
PROOT_CWD as the environment signal because it is not available in bare proot
sessions. Keep the existing Termux check, but update the detection branch to use
a guest-environment indicator that is actually present when running under proot,
and adjust the conditional in the same area of the mouse setup logic
accordingly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: f7329e98-1f70-4ba7-98f7-d6370026699f
📒 Files selected for processing (3)
internal/tui/keybinding_help.gointernal/tui/model.gointernal/tui/mouse.go
jatmn
left a comment
There was a problem hiding this comment.
I found a few issues that need to be addressed before this is ready.
Findings
-
[P2] Keep the new scroll keys out of focused modals and wizards
internal/tui/model.go:1407
The newCtrl+U/Ctrl+DandShift+↑/Shift+↓cases run before the existing focused-surface handlers for provider setup, MCP add, MCP manager, pickers, permission prompts, and ask-user prompts. That meansCtrl+Unow scrolls the transcript instead of clearing provider/MCP input when the chat composer is empty, so the existingTestProviderSearchClearRestoresFullListpath no longer reacheshandleProviderWizardKey; likewise Shift+arrow is intercepted before those surfaces can move their selection. Please gate these new transcript-scroll shortcuts behindnoBlockingModal()/the same focus checks used by the surrounding shortcuts, or move them after the focused handlers so modal and wizard keys keep working. -
[P2] Link an approved parent issue before continuing this community PR
CONTRIBUTING.md
The contribution policy says community pull requests must be tied to an existing issue that already has theissue-approvedlabel, but this PR has no linked issue or labels even though the body says it closes a scroll issue. Please link the approved issue for this Termux/Android scroll change, or get an explicit maintainer exception recorded on the PR before continuing the implementation review. -
[P2] Complete CodeRabbit's request to use real Termux/PRoot detection signals
internal/tui/mouse.go:15
CodeRabbit's two inline comments are still unresolved, and the current detection still relies onPROOT_CWDand uppercaseCONTAINERas if they identified the target Termux/PRoot environment. Those are not established guest-side signals for PRoot/Termux, so the new fallback can miss the stated PRoot case while also applying CellMotion in unrelated generic container setups. Please replace those checks with signals that are actually present in the supported environment, remove unsupported branches, and add focused tests for the default desktop path plus the Android/Termux/PRoot cases this PR claims to support.
|
Thanks for the review @jatmn! All three findings are addressed: 1. 🔒 Scroll key guards — Ctrl+U/D and Shift+↑/↓ now have the same focused-surface checks as the PgUp/Dn and mouse-wheel handlers: they break (fall through) when 2. 📋 Linked issue — Created issue #505 (#505) describing the Termux/Android scroll problem. PR body updated to reference it as "Closes #505". @maintainers: please add the 3. 🐚 Reliable Termux detection — Removed
All changes are pushed to the |
- Add focused-surface guards to Ctrl+U/D and Shift+Up/Down scroll keys (pendingPermission, pendingAskUser, providerWizard, mcpAddWizard, mcpManager, picker, suggestionsActive) - Remove unreliable PROOT_CWD and CONTAINER from Termux detection; use only TERMUX_VERSION, PREFIX, and ANDROID_ROOT
jatmn
left a comment
There was a problem hiding this comment.
Thanks for the update. I rechecked the previously discussed paths and found issues that still need to be addressed.
Findings
-
[P2] Route guarded scroll keys back to focused surfaces
internal/tui/model.go:1417
The new guards preventCtrl+U,Ctrl+D, andShift+Up/Downfrom scrolling while a wizard or modal is open, but they usebreakfrom theswitch, so the key never reaches the focused handler below. That means the priorCtrl+Uregression is still present in a different form: provider setup can no longer clear the provider/base URL/model fields viahandleProviderWizardKey, and the MCP add/managerCtrl+Uclear paths are skipped as well. Please complete the earlier review request by either moving these transcript-scroll cases after the focused-surface handlers or returning through the focused handler when one is active, and keep regression coverage for those focusedCtrl+Upaths. -
[P2] Link an approved parent issue before continuing this community PR
CONTRIBUTING.md
The PR now links issue #505, but that issue still has noissue-approvedlabel. The contribution policy requires community PRs to be tied to an existing issue that already has that label before implementation review continues. Please get the linked Termux/Android issue approved, or get an explicit maintainer exception recorded on the PR. -
[P2] Narrow
PREFIXdetection to the Termux prefix
internal/tui/mouse.go:26
The comment saysPREFIXshould identify Termux when it starts with/data/data/com.termux/files/usr, but the code treats any non-emptyPREFIXas Android/Termux and switches the whole TUI toMouseModeCellMotion. Since CellMotion intentionally disables hover reporting in the normal desktop path, a user who has an unrelatedPREFIXset loses hover highlighting even though they are not in the broken Termux/proot environment. Please check the documented Termux prefix value instead of only checking non-empty, and add focused tests for the desktop default plus the Termux/Android detection cases.
…tion - Move Ctrl+U/D and Shift+Up/Down scroll key cases to after KeyDown and KeyUp focused-surface handlers in the inner switch, using return-through-handler pattern instead of break. - Fix PREFIX detection to check for /data/data/com.termux/files/usr prefix instead of any non-empty PREFIX env var. - Add strings import to mouse.go for strings.HasPrefix.
|
Thanks @jatmn, all three findings addressed: [P2] Scroll key placement ✅ [P2] Parent issue 🔄 [P2] PREFIX detection ✅ Pushed in commit |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
internal/tui/model.go (1)
1489-1602: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsider extracting the repeated modal-forwarding chain.
The
pendingPermission/pendingAskUser/providerWizard/mcpAddWizard/mcpManager/picker/suggestionsActivedispatch chain is now duplicated 4 times in this PR (on top of the 2 pre-existing copies inKeyUp/KeyDown). A small helper parameterized by the up/down deltas would cut this to one implementation and remove the risk of exactly the kind of direction-inversion bug flagged above recurring.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/tui/model.go` around lines 1489 - 1602, The modal-forwarding logic in the key handling path is duplicated across the Ctrl+U/Ctrl+D and Shift+Up/Shift+Down cases, making direction-specific bugs easy to reintroduce. Extract the repeated pendingPermission/pendingAskUser/providerWizard/mcpAddWizard/mcpManager/picker/suggestionsActive dispatch chain into a small helper on model, and parameterize it with the scroll or cursor delta so the key cases only delegate to that shared implementation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@internal/tui/model.go`:
- Around line 1549-1602: Shift+Up/Down in the key handling switch currently
scroll the transcript even when the composer has text, unlike Ctrl+U/Ctrl+D.
Update the `keyShift(msg) && keyIs(msg, tea.KeyUp/Down)` branches in `model.go`
to apply the same `transcriptDetailed` and `m.composerValue() != ""` guard used
by the Ctrl shortcuts, so composed multiline input can keep handling the key via
`moveComposerVisualCursor`/text navigation. Keep the existing pending
modal/wizard/picker/suggestions checks intact and only fall through to
transcript scrolling when the composer is empty.
- Around line 1489-1548: The Ctrl+U/Ctrl+D handlers in model.go have the
permission and ask-user cursor directions reversed. Update the key handling in
the keyCtrl(msg, 'u') and keyCtrl(msg, 'd') branches so they follow the same
movement convention as KeyUp/KeyDown and the Shift+Up/Down cases: Ctrl+U should
move the selection upward with the negative cursor delta, and Ctrl+D should move
it downward with the positive delta. Keep the existing scrollChat behavior
unchanged and make the fix in the movePermissionCursor and moveAskUserCursor
calls within Model’s key handling logic.
---
Nitpick comments:
In `@internal/tui/model.go`:
- Around line 1489-1602: The modal-forwarding logic in the key handling path is
duplicated across the Ctrl+U/Ctrl+D and Shift+Up/Shift+Down cases, making
direction-specific bugs easy to reintroduce. Extract the repeated
pendingPermission/pendingAskUser/providerWizard/mcpAddWizard/mcpManager/picker/suggestionsActive
dispatch chain into a small helper on model, and parameterize it with the scroll
or cursor delta so the key cases only delegate to that shared implementation.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 9d8e0de2-2390-42d7-80f0-bc6a7c876b5f
📒 Files selected for processing (3)
.gitignoreinternal/tui/model.gointernal/tui/mouse.go
✅ Files skipped from review due to trivial changes (1)
- .gitignore
🚧 Files skipped from review as they are similar to previous changes (1)
- internal/tui/mouse.go
jatmn
left a comment
There was a problem hiding this comment.
Thanks for the update. I rechecked the changed paths and found issues that still need to be addressed.
Findings
-
[P2] Link an approved parent issue before continuing this community PR
CONTRIBUTING.md:19
The PR now links issue #505, but that issue still has noissue-approvedlabel. The contribution policy requires community PRs to be tied to an existing issue that has already been reviewed and approved before implementation review continues. Please get the linked Termux/Android issue approved, or get an explicit maintainer exception recorded on the PR. -
[P2] Complete CodeRabbit's request to fix the Ctrl+U/Ctrl+D prompt direction
internal/tui/model.go:1497
CodeRabbit's current review item is still valid: the newCtrl+Uhandler moves permission and ask-user cursors with+1, while the existing Up/Down convention usesKeyUp -> -1andKeyDown -> +1.Ctrl+Uis the "up" half-page shortcut and already scrolls the transcript in the upward direction, so while a permission or ask-user prompt is focused it currently moves the highlighted choice downward;Ctrl+Dhas the inverse problem at lines 1527/1530. Please complete that review request by swapping those focused-prompt deltas and adding regression coverage for the permission and ask-user prompt paths. -
[P2] Make the advertised Shift+Up/Down scroll shortcuts reachable
internal/tui/model.go:1407
The newShift+Up/Shift+Downline-scroll cases are placed after the existing plainKeyUp/KeyDowncases, butkeyIsonly checks the key code and ignores modifiers. A shifted-arrow key therefore matches the earlier plain-arrow branch first, so the new line-scroll cases at lines 1549/1576 never run for the shortcuts documented in the help overlay and PR body. Please handle the shifted-arrow shortcuts before the plain-arrow cases, and keep the composer/non-modal guards intact so text navigation and focused surfaces still receive shifted arrows when they should. -
[P3] Drop the unrelated sandbox-helper ignore entry from this PR
.gitignore:45
The newzero-linux-sandboxignore entry is unrelated to the Termux/Android TUI scroll fix and is not part of issue #505. Since the contribution policy asks community PRs to stay focused on the approved issue, please remove this entry or split it into a separate approved change if the project wants to ignore locally built sandbox helpers.
…itignore - Move Shift+Up/Shift+Down before plain KeyUp/KeyDown so shifted-arrow shortcuts are reachable (were swallowed by plain-arrow keyIs match) - Swap Ctrl+U/Ctrl+D deltas for permission and ask-user focused prompts: Ctrl+U (up) now moves cursor UP (-1), Ctrl+D (down) moves DOWN (+1) - Add TestPermissionCursorCtrlU/D and TestAskUserCursorCtrlU/D regression tests verifying the direction fix - Remove unrelated zero-linux-sandbox entry from .gitignore
|
Thanks @jatmn, all findings addressed in commit 67729ea (pushed to fork main, same base): Shift+Up/Shift+Down now reachable ✅ Ctrl+U/Ctrl+D direction fixed ✅
Regression tests added ✅
.gitignore cleanup ✅ Parent issue ❓ |
jatmn
left a comment
There was a problem hiding this comment.
Thanks for the update. I rechecked the changed paths and found issues that still need to be addressed.
Findings
-
[P2] Link an approved parent issue before continuing this community PR
CONTRIBUTING.md:19
The PR now links issue #505, but the live issue still has noissue-approvedlabel. The contribution policy requires community PRs to be tied to an existing issue that has already been reviewed and approved before implementation review continues. Please get the linked Termux/Android issue approved, or get an explicit maintainer exception recorded on the PR. -
[P2] Complete CodeRabbit's Shift+Up/Down composer guard request
internal/tui/model.go:1406
CodeRabbit's current review item is still valid: the new Shift+Up/Shift+Down cases run before the plain arrow handlers but do not include them.composerValue() != ""guard that Ctrl+U/Ctrl+D use. BecausekeyIsonly checks the key code, a shifted arrow now enters these branches and scrolls the transcript even while the composer has text, instead of falling through to the existingmoveComposerVisualCursorpath for multiline input navigation. Please complete that review request by applying the same composer-empty guard before these shortcuts scroll the transcript, and add regression coverage for Shift+Up/Down with a non-empty multiline composer. -
[P2] Complete the mouse-mode detector coverage requested earlier
internal/tui/mouse.go:23
The earlier review asked for focused tests around the default desktop path plus the Android/Termux detection cases, but the current update only added Ctrl+U/Ctrl+D prompt tests. This selector is entirely driven by process environment variables and chooses between hover-capableMouseModeAllMotionand reducedMouseModeCellMotion; the previous broadPREFIXcheck already showed how easy it is to silently regress desktop hover behavior. Please add tests for the empty/default environment,TERMUX_VERSION, the TermuxPREFIX, andANDROID_ROOTpaths, using per-test env cleanup so the cases cannot leak into each other.
|
lol he gonna cry to merge this pr @jatmn i crossed 7 seas to come here at to comment the pr |
- Add composer-empty guard to Shift+Up/Down before scrollChat so shifted arrows navigate multiline text instead of scrolling - Add TestShiftUp/DownWithComposerDoesNotScroll regression tests - Add mouseModeForTermEnv tests: default/desktop, TERMUX_VERSION, PREFIX (Termux and unrelated), ANDROID_ROOT (/system and unrelated), and all Termux signals combined — each with per-test env cleanup
|
Thanks @jatmn, three more findings addressed in commit 52dc9d2: Shift+Up/Down composer guard added ✅
Mouse-mode detector tests added ✅
Parent issue ❓ |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@internal/tui/permission_prompt_test.go`:
- Around line 332-364: The new Shift+Up/Shift+Down tests are asserting against a
non-existent transcript scroll field, so they won’t compile. Update
TestShiftUpWithComposerDoesNotScroll and TestShiftDownWithComposerDoesNotScroll
in the model test to compare the chat scroll state instead, using
chatScrollOffset (or an existing helper on model) before and after Update. Keep
the same checks on cmd and ensure the assertions reference the correct model
field.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: ebf1ec3b-f260-4622-927c-0d2f99dca485
📒 Files selected for processing (3)
internal/tui/model.gointernal/tui/mouse_test.gointernal/tui/permission_prompt_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
- internal/tui/model.go
jatmn
left a comment
There was a problem hiding this comment.
Thanks for the update. I rechecked the changed paths and found issues that still need to be addressed.
Findings
-
[P1] Complete CodeRabbit's request to fix the non-compiling Shift+arrow tests
internal/tui/permission_prompt_test.go:346
CodeRabbit's latest inline request is still valid:TestShiftUpWithComposerDoesNotScrollandTestShiftDownWithComposerDoesNotScrollcomparenext.transcriptScrollOffsetagainstm.transcriptScrollOffset, butmodelhas notranscriptScrollOffsetfield. The scroll state used elsewhere ischatScrollOffset, so the current PR head will not compile once these tests are typechecked. Please update those assertions to use the real chat scroll state and rerun the relevant TUI tests. -
[P2] Make the Shift+arrow composer regression tests exercise a scrollable transcript
internal/tui/permission_prompt_test.go:333
After the field name is fixed, these two tests still will not catch the regression they were added for. They constructnewModel(context.Background(), Options{}), leaveAltScreenfalse, and do not add enough transcript rows to make the chat scrollable;scrollChatreturns without changing any offset in that setup. A broken handler that still lets Shift+Up/Down reachscrollChatwhile the composer has text would therefore pass these tests. Please set up the tests like the existing scroll tests do, with alt-screen enabled and enough transcript content to make the offset change if the shortcut is incorrectly intercepted, then assert the chat scroll state stays unchanged. -
[P2] Link an approved parent issue before continuing this community PR
CONTRIBUTING.md:19
The PR links issue #505, but the live issue still has noissue-approvedlabel. The contribution policy requires community PRs to be tied to an existing issue that has already been reviewed and approved before implementation review continues. Please get the linked Termux/Android issue approved, or get an explicit maintainer exception recorded on the PR.
…t setup - transcriptScrollOffset -> chatScrollOffset (actual field name) - int != comparison instead of nonexistent .Equal() - AltScreen: true + width/height + transcript rows so tests actually exercise the scroll path and would catch the guard regression
|
Thanks @jatmn, finding addressed in commits 797e01b / 2e05f76 (pushed to fork main): Tests fixed + made regression-proof ✅
Parent issue ❓ |
jatmn
left a comment
There was a problem hiding this comment.
Thanks for the update. I rechecked the changed paths and found issues that still need to be addressed.
Findings
-
[P2] Get the linked parent issue approved before continuing this community PR
CONTRIBUTING.md:19
The PR now links issue #505, but the live issue still has noissue-approvedlabel. The contribution policy requires community pull requests to be tied to an existing issue that has already been reviewed and approved before implementation review continues. Please get the linked Termux/Android issue approved, or get an explicit maintainer exception recorded on the PR. -
[P3] Remove the unrelated sandbox-helper ignore entry
.gitignore:45
The latest head addszero-linux-sandboxback to.gitignore, even though this PR is scoped to Termux/Android TUI scrolling and issue #505 does not cover sandbox build artifacts. CodeRabbit also flagged this as out of scope earlier, and the contribution policy asks community PRs to stay focused on the approved issue. Please drop this line from this PR, or split it into a separately approved change if the project wants to ignore locally built sandbox helpers.
|
Building on the last comment — issue #505 still needs the label per CONTRIBUTING.md:19 before this community PR can proceed. Could a maintainer please add it? |
|
Building on the last comment — issue #505 still needs the |
jatmn
left a comment
There was a problem hiding this comment.
@PatrickNoFilter failing smoke, please fix
|
Thanks for the thorough work here — the direction fixes, the composer-guard fixes, and the detection-signal cleanup were all genuine improvements caught through real review, and we appreciate the persistence through the back-and-forth. Following up from the discussion on #505: Zero already supports Termux natively (#455) — the binary runs directly with no compatibility layer required. Running Zero inside a PRoot guest isn't a configuration we support or need to support, since none of the usual reasons for reaching for PRoot (missing packages, FHS path assumptions, glibc requirements) apply to a self-contained Go binary. That changes the calculus on this fix specifically: We tested directly on native Termux and couldn't reproduce the original issue, and this is currently a single, unconfirmed report. Given that, we're closing this rather than continuing to iterate. If the underlying PRoot-specific issue is real and someone wants to pursue it, the right fix would need to detect PRoot/ptrace specifically (e.g. checking |
Summary
Fix for Termux/Android touch-scroll support in Zero TUI.
Closes #505
Changes
mouseModeForTermEnv()— detect Termux/Android via env vars and usetea.MouseModeCellMotioninstead ofAllMotionso touch-gesture scrolling works reliably through PRoot.Ctrl+U/Ctrl+D— half-page scroll shortcuts for devices without PgUp/PgDn keys.Shift+↑/Shift+↓— single-line scroll shortcuts.?) — updated with new shortcut documentation.Environment detection
Uses
TERMUX_VERSION,PREFIX, andANDROID_ROOT(notPROOT_CWDorCONTAINERwhich are unreliable guest-side PRoot signals).Scroll key guard
Ctrl+U/D and Shift+↑/↓ are gated behind the same focused-surface checks as PgUp/PgDn and mouse-wheel: they break (fall through) when a permission prompt, ask-user prompt, provider wizard, MCP add wizard, MCP manager, picker, or suggestion overlay is active.
Testing
Summary by CodeRabbit