Skip to content

Add mobile double-tap Tab shortcut - #10239

Open
himomohi wants to merge 7 commits into
stablyai:mainfrom
himomohi:agent/mobile-double-tap-tab
Open

himomohi wants to merge 7 commits into
stablyai:mainfrom
himomohi:agent/mobile-double-tap-tab

Conversation

@himomohi

@himomohi himomohi commented Jul 23, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • add an opt-in, default-off Double-tap sends Tab setting for the mobile terminal
  • treat only two plain finger taps on the same active terminal within 300 ms as the shortcut
  • send raw \t through the existing accessory-key path, preserving IME flush and active/connected terminal guards
  • cancel a pending tap sequence when the intervening action is a URL, OSC link, file path, mouse-tracking TUI tap, scroll, pinch, long press, selection action, external mouse click, or wheel/trackpad gesture
  • reset tap state on blur, active-terminal changes, route/worktree changes, and reconnects
  • reconcile the Settings switch with persisted storage after failed or overlapping writes

There is no host-OS branch: the connected shell receives the standard Tab byte on macOS, Linux, and Windows and keeps ownership of completion behavior.

Screenshots

Not included. The UI change is one switch in Terminal Settings.

Testing

  • focused preference, resolver, WebView routing, and lifecycle tests: 146/146
  • cd mobile && node_modules/.bin/tsc.cmd --noEmit
  • cd mobile && node_modules/.bin/oxlint.cmd .
  • changed files pass oxfmt --check
  • git diff --check origin/main
  • full mobile suite is not completely green in this Windows checkout
    • 3,442 passed, 3 pending, 6 failed
    • the 6 failures are pre-existing CRLF-sensitive source-text assertions in 5 files that are unchanged from origin/main
  • iOS/Android physical-device smoke test was not available on this Windows host
  • app build/export was not completed

AI Review Report

The final fixed diff was reviewed for gesture routing, terminal identity/lifecycle resets, preference ordering, IME handling, accessory-key transport, and cross-platform host behavior. No remaining P0-P3 actionable findings were found.

Review findings incorporated in this revision:

  • separated focus taps from gesture-eligible plain finger taps so TUI mouse clicks cannot become Tab
  • added an explicit cancellation event so scroll, pinch, selection, links/files, wheel input, and external mouse actions break an in-progress double-tap sequence
  • classified unsupported OSC 8 targets such as mailto: as links rather than plain terminal space
  • added runtime regressions for plain tap → excluded gesture → plain tap and unsupported OSC-link double taps
  • retained the existing focus behavior after excluded touch taps

Security Audit

  • no new command construction or execution
  • no path, auth, secret, dependency, or IPC changes
  • only a fixed Tab byte can be emitted
  • the feature defaults to off and is stored as a local boolean preference
  • the active terminal handle and connection state are rechecked by the existing send path

Notes

This shortcut is intended for terminal autocomplete from the mobile client. Host-side behavior still follows the connected shell's Tab binding.

ELI5

When enabled, two quick taps on otherwise plain terminal content act like pressing Tab. Taps and gestures that already do something else keep their existing behavior.

@himomohi
himomohi marked this pull request as ready for review July 24, 2026 00:59
@coderabbitai

coderabbitai Bot commented Jul 24, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a persisted “Double-tap sends Tab” terminal setting with asynchronous loading, immediate saving, and settings UI state. Introduces double-tap resolution with timing and terminal-handle checks, plus tests for disabled, valid, expired, switched, and reversed-clock taps. A focus-aware hook loads the preference and tracks taps. The session screen uses the hook to send Tab through the accessory-key pathway when the active terminal is tapped twice.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely describes the main user-visible change: a mobile double-tap Tab shortcut.
Description check ✅ Passed The description covers the user-visible change, testing, review, security, platform behavior, and known limitations.

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.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: fad7d8b4-6e22-453c-a4bf-b72d306b3d6e

📥 Commits

Reviewing files that changed from the base of the PR and between ef985ed and 0df5064381ea35b98304c96f0d96a83795e0e8a1.

📒 Files selected for processing (7)
  • mobile/app/h/[hostId]/session/[worktreeId].tsx
  • mobile/app/terminal-settings.tsx
  • mobile/src/storage/preferences.test.ts
  • mobile/src/storage/preferences.ts
  • mobile/src/terminal/terminal-double-tap-tab.test.ts
  • mobile/src/terminal/terminal-double-tap-tab.ts
  • mobile/src/terminal/use-terminal-double-tap-tab.ts

Comment thread mobile/src/terminal/use-terminal-double-tap-tab.ts
@AmethystLiang
AmethystLiang requested a review from OrcaWin July 24, 2026 16:50
@nwparker nwparker added the enhancement New feature or request label Jul 27, 2026
@himomohi
himomohi force-pushed the agent/mobile-double-tap-tab branch from 6618a37 to 110e55a Compare July 30, 2026 02:38

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 92995f71-802a-4b78-a19a-e224bc6d116d

📥 Commits

Reviewing files that changed from the base of the PR and between 6618a378a295e4f08869d0cd35b3616c8bf5ff50 and 110e55a.

📒 Files selected for processing (2)
  • mobile/app/h/[hostId]/session/[worktreeId].tsx
  • mobile/app/terminal-settings.tsx

Comment thread mobile/app/h/[hostId]/session/[worktreeId].tsx Outdated
Comment thread mobile/app/terminal-settings.tsx Outdated
Comment thread mobile/app/h/[hostId]/session/[worktreeId].tsx Outdated
Comment thread mobile/src/terminal/use-terminal-double-tap-tab.ts Outdated
@greptile-apps

greptile-apps Bot commented Jul 30, 2026 •

Copy link
Copy Markdown

Greptile Summary

This PR adds an opt-in "Double-tap sends Tab" mobile terminal setting. Two taps on empty terminal space within 300 ms route a raw \t byte through the existing accessory-key send path, while link, file-path, and mouse-protocol taps continue on their separate handlers.

  • terminal-double-tap-tab.ts is a pure, side-effect-free resolver function that determines whether a tap should send Tab based on elapsed time and terminal handle identity; it is fully unit-tested including clock-reversal and cross-terminal edge cases.
  • use-terminal-double-tap-tab.ts manages the focus-lifecycle guard (reloads preference on screen focus, resets tap state on blur), and a useEffect on activeHandle clears stale tap state across terminal switches.
  • [worktreeId].tsx moves handleAccessoryKeyRef earlier to serve both the double-tap path and the existing hold-to-repeat path, then threads shouldSendTabForTap into handleTerminalTap; the underlying sendLiveTerminalInput guard still validates the active handle and connection state before bytes reach the transport.

Confidence Score: 5/5

Safe to merge — the feature is opt-in (defaults off), isolated to a fixed Tab byte, and every send path is guarded by the existing handle/connection checks in sendLiveTerminalInput.

The pure resolver, the hook lifecycle, the preference persistence layer, and the session-screen integration are all covered by focused tests. The handleAccessoryKeyRef relocation is a clean refactor; the original send guards remain intact. No data-loss, auth, or cross-component correctness concerns were found.

Files Needing Attention: No files require special attention.

Important Files Changed

Filename Overview
mobile/src/terminal/terminal-double-tap-tab.ts Pure resolver with correct elapsed-time logic, clock-reversal guard (elapsed >= 0), cross-terminal guard, and disabled-state guard; well-tested.
mobile/src/terminal/use-terminal-double-tap-tab.ts Hook wires focus-lifecycle preference reload and activeHandle-change tap reset correctly; useFocusEffect cleanup synchronously clears state before any inflight load can apply.
mobile/src/terminal/use-terminal-double-tap-tab-preference.ts Optimistic-update preference hook with revision-keyed stale-write protection and async recovery; edge cases tested (fast toggle, write failure, interleaved writes).
mobile/app/h/[hostId]/session/[worktreeId].tsx Moves handleAccessoryKeyRef earlier to serve both double-tap and repeat paths; handleTerminalTap restructured cleanly; underlying send guard still validates handle and connection state.
mobile/app/terminal-settings.tsx Adds "Double-tap sends Tab" switch following the existing settings UI pattern; integrates useTerminalDoubleTapTabPreference correctly.
mobile/src/storage/preferences.ts Adds loadTerminalDoubleTapTabEnabled (with try/catch defaulting to false) and saveTerminalDoubleTapTabEnabled following the existing pattern.
mobile/src/terminal/terminal-double-tap-tab.test.ts Covers disabled state, within-window, expired-window, cross-terminal, and clock-reversal cases for the pure resolver.
mobile/src/terminal/use-terminal-double-tap-tab.test.ts Tests the full hook lifecycle: two-tap sequence, terminal-switch reset, blur/refocus with disabled preference reload, and stale-load-after-blur guard.
mobile/src/terminal/use-terminal-double-tap-tab-preference.test.ts Tests fast-toggle precedence over initial load, write-failure recovery, and interleaved-write ordering for the preference hook.
mobile/src/storage/preferences.test.ts Adds regression tests for the new storage key: default-false on null/error and round-trip load/save verification.

Sequence Diagram

sequenceDiagram
    participant User
    participant TerminalView
    participant handleTerminalTap
    participant shouldSendTabForTap
    participant resolveTerminalDoubleTapTab
    participant lastTapRef
    participant handleAccessoryKey
    participant sendLiveTerminalInput

    User->>TerminalView: First tap on empty space
    TerminalView->>handleTerminalTap: "handle="term-1""
    handleTerminalTap->>handleTerminalTap: "check handle === activeHandleRef"
    handleTerminalTap->>shouldSendTabForTap: call(handle)
    shouldSendTabForTap->>resolveTerminalDoubleTapTab: "{enabled, handle, lastTap=null, now}"
    resolveTerminalDoubleTapTab-->>shouldSendTabForTap: "{sendTab:false, nextTap:{handle, at:t1}}"
    shouldSendTabForTap->>lastTapRef: "store {handle, at:t1}"
    shouldSendTabForTap-->>handleTerminalTap: false
    Note over handleTerminalTap: focusLiveInput() called, no Tab sent

    User->>TerminalView: Second tap within 300ms
    TerminalView->>handleTerminalTap: "handle="term-1""
    handleTerminalTap->>shouldSendTabForTap: call(handle)
    shouldSendTabForTap->>resolveTerminalDoubleTapTab: "{enabled, handle, lastTap:{handle,at:t1}, now=t2}"
    resolveTerminalDoubleTapTab-->>shouldSendTabForTap: "{sendTab:true, nextTap:null}"
    shouldSendTabForTap->>lastTapRef: clear (null)
    shouldSendTabForTap-->>handleTerminalTap: true
    handleTerminalTap->>handleAccessoryKey: "{bytes: '\t'}"
    handleAccessoryKey->>sendLiveTerminalInput: handle, '\t'
    sendLiveTerminalInput->>sendLiveTerminalInput: "guard (rpc, connected, handle===active)"
    sendLiveTerminalInput-->>handleAccessoryKey: RPC terminal.send
Loading

Reviews (2): Last reviewed commit: "Address mobile double-tap review feedbac..." | Re-trigger Greptile

@himomohi
himomohi force-pushed the agent/mobile-double-tap-tab branch from c1ff0d1 to 85b0188 Compare August 11, 2026 03:05
@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 440d29fd-2fb8-4e62-af40-52b5b2dd1a34

📥 Commits

Reviewing files that changed from the base of the PR and between 3e3f48f and 85b0188.

📒 Files selected for processing (24)
  • mobile/app/h/[hostId]/session/[worktreeId].tsx
  • mobile/app/terminal-settings.tsx
  • mobile/src/session/TerminalPaneView.tsx
  • mobile/src/storage/preferences.test.ts
  • mobile/src/storage/preferences.ts
  • mobile/src/terminal/TerminalWebView.tsx
  • mobile/src/terminal/terminal-double-tap-tab.test.ts
  • mobile/src/terminal/terminal-double-tap-tab.ts
  • mobile/src/terminal/terminal-webview-contract.ts
  • mobile/src/terminal/terminal-webview-mouse-click-drag-injected.ts
  • mobile/src/terminal/terminal-webview-mouse-click.test.ts
  • mobile/src/terminal/terminal-webview-notification-dispatch.test.ts
  • mobile/src/terminal/terminal-webview-notification-dispatch.ts
  • mobile/src/terminal/terminal-webview-scroll-routing.test.ts
  • mobile/src/terminal/terminal-webview-tap-dispatch-injected.ts
  • mobile/src/terminal/terminal-webview-tap-routing.test.ts
  • mobile/src/terminal/terminal-webview-url-tap.test.ts
  • mobile/src/terminal/terminal-webview-url-tap.ts
  • mobile/src/terminal/terminal-webview-wheel-scroll-injected.ts
  • mobile/src/terminal/terminal-webview-wheel-scroll.test.ts
  • mobile/src/terminal/use-terminal-double-tap-tab-preference.test.ts
  • mobile/src/terminal/use-terminal-double-tap-tab-preference.ts
  • mobile/src/terminal/use-terminal-double-tap-tab.test.ts
  • mobile/src/terminal/use-terminal-double-tap-tab.ts
🚧 Files skipped from review as they are similar to previous changes (8)
  • mobile/src/terminal/terminal-double-tap-tab.test.ts
  • mobile/src/terminal/use-terminal-double-tap-tab-preference.ts
  • mobile/src/terminal/terminal-double-tap-tab.ts
  • mobile/app/terminal-settings.tsx
  • mobile/src/terminal/use-terminal-double-tap-tab-preference.test.ts
  • mobile/src/storage/preferences.test.ts
  • mobile/src/storage/preferences.ts
  • mobile/app/h/[hostId]/session/[worktreeId].tsx

Comment thread mobile/src/terminal/terminal-webview-url-tap.ts

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants