Skip to content

Rank results by usage (frecency) - #87

Merged
oNaiPs merged 3 commits into
mainfrom
feature/frecency
Oct 17, 2026
Merged

oNaiPs merged 3 commits into
mainfrom
feature/frecency

Conversation

@oNaiPs

@oNaiPs oNaiPs commented Oct 17, 2026

Copy link
Copy Markdown
Owner

Items you open often and recently now rank higher.

Behaviour

  • Each selection of an app, System Settings pane or $PATH program is recorded in UserDefaults (`usageHistory`), keyed by file path or `cmd:`. The score is decayed: +1 per use, halving every 14 days. Entries that have faded below 0.05 are pruned when the history is saved.
  • With an empty query, used items come first (most used first), then everything else alphabetically.
  • While typing, the fuzzy score still decides the order. Usage only lowers it by a capped amount (0.04 * log2(1 + uses), at most 0.15), so a much better match still wins and usage settles near-ties like Calculator vs Calendar for cal.
  • Piped stdin menus are never recorded, because their items have no stable identity (data == nil). Typed free-text commands aren't recorded either.

Implementation

  • New src/UsageStore.swift: UsageStore (takes the UserDefaults instance, half-life and clock, so it can be injected) and a UsageIdentifiable protocol (URL, Command, and the composite provider's tagged wrapper).
  • SearchService takes an optional usage: store (defaults to nil, so existing callers and tests behave as before) and has recordSelection(_:).
  • SearchViewController: a two-line change, which passes UsageStore.shared and records the selected item in submit.

Testing

  • New UsageStoreTests (13 tests) use a throwaway UserDefaults suite and a fake clock. They cover accumulation, decay, persistence, pruning, the pipe/no-identity skip, composite/command identity, empty-query ordering, tie-breaking, the boost cap, and recording through submit.
  • Full xcodebuild ... test: 225 tests pass. swiftlint --strict: 0 violations.

🤖 Generated with Claude Code

@oNaiPs
oNaiPs merged commit d421ff0 into main Oct 17, 2026
3 checks passed
@oNaiPs
oNaiPs deleted the feature/frecency branch October 17, 2026 13:25
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