Skip to content

Add a configurable "Re-detect Focus" reload action#4

Open
t-h-tech wants to merge 1 commit into
mainfrom
feat/reload-focus-detection
Open

Add a configurable "Re-detect Focus" reload action#4
t-h-tech wants to merge 1 commit into
mainfrom
feat/reload-focus-detection

Conversation

@t-h-tech

Copy link
Copy Markdown
Owner

Summary

Cotabby sometimes latches onto the wrong focus source — it keeps a plain AX text field (e.g. an editor pane) instead of the terminal shell prompt or the Claude Code TUI, because the editor-protection guards key off a focus snapshot that can go stale. This adds a manual escape hatch (a configurable "Re-detect Focus" reload action, available as both a global hotkey and a menu-bar item) plus a low-risk automatic mitigation (re-read focus on app activation).

What the reload does, in order: prune dead shell sessions → cancel in-flight TUI OCR and release a TUI-owned injection → stop AX suppression and republish the real focused element → drop stale prompt anchors → force an immediate fresh AX read → re-evaluate suggestion availability. After that, the next shell report / TUI heartbeat / keystroke re-injects the correct source because the stale snapshot that was blocking it is gone.

Validation

xcodebuild test -project Cotabby.xcodeproj -scheme Cotabby \
  -destination 'platform=macOS' CODE_SIGNING_ALLOWED=NO
# ** TEST SUCCEEDED **  793 tests, 4 skipped, 0 failures
#   incl. ReloadFocusKeybindTests (3) and the new .reloadFocus ShortcutConflictTests

swiftlint lint --quiet
# exit 0 — no violations

xcodegen generate && git diff --exit-code -- Cotabby.xcodeproj
# clean — committed project matches project.yml (new test file wired in)

Manual: built + ran from Xcode; bound the hotkey in Settings → Shortcuts, confirmed it fires the reload, and confirmed the menu-bar "Re-detect Focus" item triggers the same path. App-activation auto-refresh re-resolves the focused source when switching back into a terminal/editor pane without pressing reload.

Linked issues

None.

Risk / rollout notes

  • Opt-in by default. The hotkey ships unbound (shows "None"); users with no binding pay no per-keystroke tap cost and see no behavior change. The menu-bar item and app-switch auto-refresh are the only always-on surfaces.
  • Settings migration is additive. Three new UserDefaults keys (cotabbyReloadFocusKeyCode / Modifiers / Label), all defaulting to the disabled sentinel. No existing keys touched.
  • App-activation observer does a focus re-read on every app switch; FocusTracker debounces by focused-element identity, so this is cheap. The observer is owned by AppDelegate (app-lifetime), not the transient environment.
  • Project file: Cotabby.xcodeproj/project.pbxproj was regenerated with xcodegen generate to wire in the new test (the only change is the four standard entries for ReloadFocusKeybindTests.swift; no signing/team or other drift).

Cotabby sometimes latches onto the wrong focus source — keeping a plain AX
text field (e.g. an editor pane) instead of the terminal shell prompt or the
Claude Code TUI — because the editor-protection guards key off a cached focus
snapshot that can go stale. This adds a manual escape hatch plus a low-risk
automatic mitigation.

- Reload action: discards stale terminal/TUI injections and cached AX state,
  prunes dead shell sessions, drops stale prompt anchors, re-reads the focused
  element, and re-evaluates suggestion availability.
- Configurable global hotkey, opt-in / unbound by default, set in
  Settings -> Shortcuts, plus a "Re-detect Focus" menu-bar item.
- Auto-refresh focus on app activation so switching into a terminal/editor
  dissolves a stale snapshot without a manual reload.

Adds keybind storage + conflict-detection test coverage.
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.

1 participant