Retain the picker, and one comment (#1195)

Apple documents no retention for show(relativeTo:of:preferredEdge:), so
the sheet is held here rather than left to an unstated behaviour -- my
own test showed it surviving, but a comment is not a contract. The share
doc comment is one line now.
This commit is contained in:
Ali
2026-09-28 23:36:04 +06:00
committed by GitHub
parent 0f526ad0cc
commit 2115b8f241
5 changed files with 33 additions and 0 deletions
@@ -8,6 +8,7 @@ final class FileSearchCoordinator {
private let palette: PaletteState
private let paletteCoordinator: PaletteCoordinator
private let windowController: PaletteWindowController
private var sharePicker: NSSharingServicePicker?
private unowned let core: AppCore
init(
@@ -62,6 +63,19 @@ final class FileSearchCoordinator {
AppLauncher.showInFinder(result.url)
}
/// macOS's own share sheet, anchored to the palette's trailing edge so the row stays beside it.
func share(_ result: FileSearchResult) {
guard let provider = NSItemProvider(contentsOf: result.url),
let anchor = paletteCoordinator.anchorView
else { return }
let picker = NSSharingServicePicker(items: [provider])
sharePicker = picker
picker.show(
relativeTo: CGRect(
x: anchor.bounds.maxX, y: anchor.bounds.midY, width: 0, height: 0),
of: anchor, preferredEdge: .maxX)
}
func copyPath(_ result: FileSearchResult) {
Paster.copyPlainText(result.id)
core.showMessage("Copied path")
@@ -159,6 +159,9 @@ enum FileSearchActionsMenu {
PopoverMenuItem(title: "Quick Look", systemImage: "eye", shortcut: "⌘Y") {
vm.fileSearchQuickLook = true
},
PopoverMenuItem(title: "Share…", systemImage: "square.and.arrow.up") {
coordinator.share(result)
},
PopoverMenuItem(
title: "Copy File", systemImage: "doc.on.clipboard", startsSection: true,
shortcut: "⇧⌘C"
@@ -39,6 +39,9 @@ final class PaletteCoordinator {
var panelFrame: CGRect? { windowController.visibleFrame }
/// The palette's own view, for AppKit UI anchored to it — a sharing picker, say.
var anchorView: NSView? { windowController.anchorView }
/// The app an action acts on: the one displaced, else what a hotkey found frontmost.
var targetApp: NSRunningApplication? {
windowController.isVisible
@@ -50,6 +50,9 @@ final class PaletteWindowController: NSObject, NSWindowDelegate {
/// Where the panel sits in screen coordinates, so an overlay drawn under it can avoid it.
var visibleFrame: CGRect? { panel.flatMap { $0.isVisible ? $0.frame : nil } }
/// The palette's own view, for AppKit UI that must be anchored to it rather than drawn.
var anchorView: NSView? { panel?.isVisible == true ? panel?.contentView : nil }
/// What the palette covered when it was summoned, for anything it expands into on dismissal.
var previousTarget: InjectionTarget? {
InjectionTarget.behindPalette(ownWindow: previousOwnWindow, app: previousApp)
+10
View File
@@ -41,6 +41,15 @@ feature is enabled in Settings.
after the synchronous Spotlight call, so a late result cannot replace the newer query's rows. Editing
the scopes or the patterns cancels the session for the same reason: a result found under the old
rules must not land under the new ones.
- **Share is the one system popover, and the palette stays up under it.** `AGENTS.md` keeps Tinycast's
own dialogs because a question or a report is Tinycast's to word. A share sheet is neither: it is
AirDrop, Mail and Messages, and re-drawing it would mean re-implementing the transports and losing
whatever the system adds. So this row hands off, and the two rules it does keep are that the palette
is never hidden and that the row stays visible beside the sheet — which is what anchoring to
`PaletteWindowController.anchorView` buys. The picker is retained on the coordinator, because it
dies with its last reference, and `NSItemProvider(contentsOf:)` failing (a file that vanished between
the query and the keystroke) leaves the palette exactly as it was, which is the only failure this row
can have.
## Query path
@@ -215,6 +224,7 @@ not outlive the window.
| Open File / Open Folder | ↵ | `NSWorkspace`'s asynchronous configuration API; hides the palette without restoring focus, and reports a failure through the dialog controller |
| Show in Finder | ⌘↵ | reveals and dismisses |
| Quick Look | ⌘Y | the in-panel overlay above |
| Share… | — | `NSSharingServicePicker`, anchored to the palette's trailing edge so the row it was opened from stays visible beside it. Escape or a click elsewhere dismisses it, and the palette is never hidden, so the flow returns to the same row. There is no chord: the destinations are the system's, and it is the only place a system popover is right |
| Copy File | ⇧⌘C | the file itself on the pasteboard through `PasteboardFiles.write`, which declares `.fileURL` and the path as `.string` |
| Copy Name | ⌥⌘C | through `Paster`, palette stays open |
| Copy Path | ⌃⌘C | the standardized path, palette stays open |