Skip to content

Quick Switcher revamp: floating panel, fuzzy engine, frecency ranking#1644

Open
datlechin wants to merge 6 commits into
mainfrom
feat/quick-switcher-fuzzy-engine
Open

Quick Switcher revamp: floating panel, fuzzy engine, frecency ranking#1644
datlechin wants to merge 6 commits into
mainfrom
feat/quick-switcher-fuzzy-engine

Conversation

@datlechin

@datlechin datlechin commented Jun 10, 2026

Copy link
Copy Markdown
Member

What

Full revamp of the Quick Switcher (Cmd+Shift+O), in 5 commits that each build and test on their own.

Matching engine

  • FuzzyMatcher rewritten as an fzy-style dynamic program with affine gap penalties. It finds the best alignment instead of the first one, returns matched character indices, and treats _ . - / $ and camelCase transitions as word boundaries. Candidates over 1024 chars fall back to the old greedy pass.
  • New QuickSwitcherFrecencyStore: Firefox-style recency buckets (4/14/31/90 days), 10 samples per item, 100 items per connection. Migrates the old MRU list and removes it.
  • Ranking is matchScore x typeWeight x frecency, scored off the main actor behind the existing 40ms debounce.

Surface

  • The switcher is now a floating borderless NSPanel anchored 20% from the top of the window, not a modal sheet. It dismisses on Escape and on losing key focus. ActiveSheet.quickSwitcher is gone.
  • The panel UI follows a measured Spotlight spec (pixel measurements from 2x screenshots of Sequoia and Tahoe Spotlight, cross-checked against DSFQuickActionBar): 640pt wide, 52pt input row with a borderless 22pt text field and a detached magnifier icon, 30pt rows, 11pt semibold sentence-case section headers, corner radius 13pt (28pt on macOS 26).
  • Selection is a rounded unemphasizedSelectedContentBackgroundColor wash, like real Spotlight; text does not invert and there is no accent fill. Matched characters render semibold.
  • Scopes render as Tahoe-style capsule chips under the input instead of a segmented control. No footer, matching Spotlight and Xcode Open Quickly. No loading spinner block: the panel opens as a bare search bar and grows when results arrive, snapping height like Spotlight.
  • NSGlassEffectView on macOS 26, NSVisualEffectView (.popover) on macOS 14/15.

Corpus and freshness

  • Awaits SQLSchemaProvider.loadSchema when the table cache is empty, so the panel no longer opens with zero tables before autocomplete has warmed up. Concurrent callers coalesce on the provider's in-flight task.
  • Saved queries (SQLFavorite) join the corpus. History items carry the full query in a new payload field, so opening one loads the real query instead of the 100-char preview.

Actions

  • Option+Return opens the table in a new window tab (forceNewWindowTab on openTableTab).
  • Tables already open in a tab get an Open badge, a 1.2x rank boost, and Return focuses the existing tab.
  • Cmd+1..4 switch scope: All, Tables, Databases, Queries.
  • Right-click a row for Open Structure, Copy Name, Copy Query.

Consolidation

  • The sidebar filter (both tree views), database switcher, and connection switcher now use the same fuzzy matcher, so upv finds user_profile_view everywhere. The database switcher also ranks by score.

Out of scope, deliberate

Testing

  • New/updated suites, all green: FuzzyMatcherTests (22), QuickSwitcherFrecencyStoreTests (11), QuickSwitcherViewModelTests (26), QuickSwitcherPanelControllerTests (6), DatabaseSwitcherFilterTests (4), ConnectionSwitcherFilterTests, SidebarViewModelTests.
  • swiftlint lint --strict clean on every touched file (SidebarViewModelTests has pre-existing strict violations, untouched).
  • No UI automation for the panel: the full UI test suite does not run deterministically locally (CI quarantine list). Panel present/dismiss/key handling is covered by the controller unit tests instead.
  • Manual QA still needed on a live session: panel focus, glass on macOS 26, Escape two-stage, Option+Return.

@mintlify

mintlify Bot commented Jun 10, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
TablePro 🟢 Ready View Preview Jun 10, 2026, 7:55 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1871f30b4c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


init(contentView: NSView) {
super.init(
contentRect: NSRect(origin: .zero, size: contentView.fittingSize),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Resize the panel after async content loads

When the quick switcher is opened before its items finish loading, the panel frame is fixed from the initial loading view's fittingSize; after QuickSwitcherPanelView switches to the taller results list there is no code that updates the NSPanel frame, and the borderless panel is not user-resizable. In that common uncached/async-load path, the list/footer can be clipped to the loading-height window until the panel is recreated, so the panel should observe the hosting view's size/preferredContentSize and call setFrame/re-anchor when it changes.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7f20daefd1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +17 to +21
let openTableNames = Set(
tabManager.tabs
.filter { $0.tabType == .table }
.compactMap(\.tableContext.tableName)
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Key open-tab markers by database/schema

In contexts where tabs from another database or schema can remain open, this collects only bare table names even though tab activation later compares databaseName and schemaName. QuickSwitcherViewModel.loadItems then uses openTableNames.contains(table.name), so a closed users table in the current database/schema is shown and boosted as already “Open” whenever any other users tab exists. Please key this by the same database/schema/table identity used for tab matching.

Useful? React with 👍 / 👎.

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