Skip to content

Add letter-prefix tile labels mode#16

Closed
peterp wants to merge 3 commits intofresh-showfrom
letter-picks
Closed

Add letter-prefix tile labels mode#16
peterp wants to merge 3 commits intofresh-showfrom
letter-picks

Conversation

@peterp
Copy link
Copy Markdown
Owner

@peterp peterp commented May 6, 2026

Stacked on top of #15 — review/merge that first; this branch will retarget to main automatically once it lands.

Summary

Adds a new Tile labels setting that lets the user pick between the existing 1-9 numeric picks and a new letters mode where every tile is labelled with a 2-char prefix derived from its app name (gc Google Chrome, wa WhatsApp, cu Cursor, cc Claude Code). Type the prefix to pick + activate the window.

Behavior

  • Prefix algorithm: tokenize the app name on whitespace and camelCase boundaries (WhatsApp[Whats, App], VSCodium[VS, Codium]). 2+ tokens → first letter of first two; 1 token → first two letters.
  • Same-app duplicates: keep the first letter, pick the second from a home-row pool (j k l f d s a g h) — second Chrome window gets gj, third gk, etc.
  • Cross-app collisions: extend to 3 chars from the app name (Calendar vs Camera → ca vs cam).
  • Sticky assignments: prefixes persist for the lifetime of the process. Closing the original gc Chrome window does not reshuffle the second window's gj prefix.

Input

  • A typeahead buffer matches the prefix as you type. The matched portion on each tile's chip renders in yellow; tiles whose prefix does not match the buffer dim to 30%. A unique full match auto-picks.
  • delete (backspace) pops the last char.
  • esc clears the buffer; pressing it again with an empty buffer dismisses.
  • wasd movement, 1-9 picks, and ⌃+letter app-jump are suppressed in letters mode. Arrows still move; ⌘+arrow still swaps; search and tag bindings are unaffected.

Files

  • LabelAssigner.swift (new) — tokenizer + sticky assignment.
  • Tile.swiftsetLabel(_:matchPrefix:) replaces setNumber; chip widens for multi-char strings; matched portion rendered via NSAttributedString on the existing CATextLayer.
  • Config.swift, SettingsWindow.swift — new tilePicks enum + segmented picker in Settings.
  • Overlay.swift, OverlayView.swift — typeahead buffer, mode-aware label render, keymap bypass for letters/digits/backspace when letters mode is active.

Test plan

  • Settings → Tile labels → Letters. Reopen overlay; tiles show 2-char chips.
  • Type a letter — matching tiles' prefix highlights yellow on the matched chars; non-matching tiles dim. Type the next char to narrow down. Unique match auto-picks + activates.
  • Open two Chrome windows — first is gc, second is gj. Close the first; the second stays gj.
  • Calendar + Camera both want ca → one gets ca, the other cam.
  • Backspace pops a char; esc clears buffer; second esc dismisses.
  • In letters mode, wasd, 1-9, and ⌃+letter are no-ops; arrows still move; ⌘+arrow still swaps.
  • Switch back to Numbers mode → tiles show 1-9; wasd, digit picks, and ⌃+letter work again.

peterp added 3 commits May 6, 2026 07:23
New "Tile labels" setting picks between numbers (1-9) and letters
(app initials). In letters mode, every tile gets a sticky 2-char
prefix derived from its app name — "gc" for Google Chrome, "wa" for
WhatsApp, "cu" for Cursor, "cc" for Claude Code — and the user types
the prefix to pick + activate.

Algorithm:
- Tokenize the app name on whitespace and camelCase boundaries.
  "WhatsApp" -> ["Whats", "App"], "VSCodium" -> ["VS", "Codium"].
- 2+ tokens: first letter of first two tokens. 1 token: first two
  letters.
- Same-app dups keep the first letter and pick the second from a
  home-row pool (j k l f d s a g h) — second Chrome window becomes
  "gj".
- Cross-app collisions extend to 3 chars from the app name (Calendar
  vs Camera -> "ca" vs "cam").
- Assignments are sticky for the lifetime of the process: closing or
  opening other windows never reshuffles existing prefixes.

Input:
- A typeahead buffer matches the prefix as you type. The matched
  portion of each tile's chip renders in yellow; tiles whose prefix
  does not match the buffer dim to 30%.
- delete (backspace) pops the last char, esc clears the buffer (and
  dismisses on a second press).
- letters mode suppresses 1-9 picks, ctrl+letter app jump, and the
  wasd movement keys; arrows still move and cmd+arrow still swaps.
Flips the unset-config default from numbers to letters and updates
the README accordingly. Numbers (and wasd / ctrl+letter app jump)
remain available via "tilePicks": "numbers" in the config or the
Settings picker.
@peterp peterp deleted the branch fresh-show May 6, 2026 14:54
@peterp peterp closed this May 6, 2026
@peterp peterp mentioned this pull request May 6, 2026
6 tasks
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