feat(tabs): keep a preview tab by double-clicking it - #2441
Merged
Conversation
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Signed-off-by: Ngô Quốc Đạt <datlechin@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #2436.
A table already open in a preview tab could only be kept by closing it and double-clicking it again in the sidebar. Double-clicking the tab itself did nothing.
Root cause
EditorTabStripItem's only pointer wiring isButton(action: onSelect). Nothing in the strip reads a click count, so a double-click never reachedpromotePreviewTab(), which already existed and was already bound to the sidebar double-click, FK navigation and the edit-promotes-preview path. A missing input route to an existing action, not missing state.The reported "no visual indication" half was already shipped for sighted users: the strip has drawn a preview tab's title in italic since well before this issue. What was missing there is the accessibility channel, since
accessibilityValuecarried only the position, and the tooltip, which said nothing about preview state at all.The fix
Reading
NSApp.currentEvent's click count inside the tab's own button action, which is whatNSTableViewdoes withactionanddoubleAction. Every SwiftUI multi-click gesture is disqualified, measured rather than assumed: driven withCGEvents posted to.cghidEventTapso the window server assigned the click count itself, against a button carrying the strip's own shape,NSEvent.doubleClickIntervalat its 0.5s default.Buttonalone (what shipped)+ .onTapGesture(count: 2)+ .simultaneousGesture(TapGesture(count: 2))+ NSApp.currentEvent.clickCountSo a
count: 2tap gesture holds every tab selection back 371ms and drops it entirely on the double, and a simultaneous one selects twice. Neither is visible to any other test: the tab still selects and still promotes, just late, or twice.EditorTabStripGestureConventionTestsfails on either spelling reappearing in this file, and carries the table.A selection made by clicking a tab no longer recentres the strip. The track scrolls once the tabs stop fitting, and the existing
scrollTo(_:anchor: .center)on a selection change would slide the clicked tab to the middle in a 0.15s animation, taking it out from under the second click that was already on its way. The recentre still runs for every selection that comes from outside the strip, which is what it exists for.The second click has to land on the tab the first one activated. Two clicks close enough in time and space arrive as one click of count two whichever view each hit, and tabs sit flush against each other, so a pair straddling a boundary would otherwise keep a tab the user only meant to select.
NSTableViewhas the same exposure and lives with it, because its double-click opens the row the second click hit and a single click would have led there anyway; here it would change a tab's state without being asked. Any count above one keeps the tab rather than two exactly, since that same coalescing carries the count past two and a strict== 2would refuse a genuine double-click that followed a nearby click.isPreview's single mutator moves toQueryTabManager.promotePreviewTab(id:), besidemoveTab(id:by:), because the context menu can fire on a tab that is not selected and the coordinator's version only ever acted on the selected one.MainContentCoordinator.promotePreviewTab()delegates to it, so its four existing callers are unchanged. The strip calls it directly, as it already does forselectedTabIdandmoveTab.Alongside the gesture:
Promotion does not reorder the tab (that is pinning, a different feature in the editors that offer both) and is one way, matching TablePlus, VS Code, DataGrip and Xcode.
Not done, deliberately
No File-menu item or keyboard shortcut: Xcode puts this on the tab's contextual menu only. No pinning, no demotion, and no change to preview-tab persistence, which deliberately restores every tab permanent.
One consequence of that worth naming: the strip is drawn only once a window holds more than one tab (
ConnectionWindowPaneResolver.showsTabStrip), so neither new affordance exists while a lone preview tab is open. Double-clicking the table in the sidebar, or selecting it and pressingReturn, already keeps it there, anddocs/features/tabs.mdxnow says when the strip appears rather than implying it is always available. A File-menu command bound to the selected tab would close the gap if it turns out to matter.Tests
EditorTabActivationTests: the activation resolver over single, double, triple, modified, caps-lock, cross-tab, first-click and no-event cases, plus reading a click off anNSEventand rejecting a right-click, sinceNSEvent.clickCountraises for anything that is not a mouse-down or mouse-up.PreviewTabTests:promotePreviewTab(id:)on an unselected tab, on an already-permanent tab and on an unknown id; that it does not reorder the strip; andcanPromotePreviewTab(id:)for each case.OpenTableTabTests: a kept tab is not reused by the next table opened from the sidebar, which is the behaviour the issue asks for.EditorTabStripGestureConventionTests: the source guard described above.EditorTabKeepOpenUITests: double-clicking a preview tab keeps it so a third table gets its own tab, and a single click on it does not.Verification
generate,build,testover the 15 suites owning the changed types,lintover all three targets (0 violations), anddocs.Reviewed by
/code-reviewrather than Codex, which failed withYour workspace is out of creditsand never read the diff. Five findings, all acted on: the auto-scroll race above,>= 2over== 2, two UI tests that sampled their baseline tab count before waiting for the strip (a false green in one and a flake in the other), the docs overclaim, and a "Keep Open" accessibility action offered on tabs where it does nothing.Screenshots
Not captured. The two visible states are the new Keep Open item on a tab's contextual menu, and a tab title losing its italic once it is kept, which needs two tables open and a double-click between the frames. Driving a Debug build for it did not get far enough: the object browser published no
AXOutlineto click, so the sidebar rows could not be reached.EditorTabKeepOpenUITestscovers both states as behaviour instead.https://claude.ai/code/session_01KGirjf9LTGgxJBs1vJsFYh