WIP: add numbered quick paste

This commit is contained in:
Akshay Kolli
2026-06-30 02:38:48 -07:00
parent 158086fdc9
commit 1b1ca3936c
8 changed files with 175 additions and 16 deletions

View File

@@ -52,6 +52,17 @@ final class ClipboardPanelController: NSObject, NSWindowDelegate, QLPreviewPanel
private var isAnimating = false
private var quickLookURL: URL?
private var screenParametersObserver: NSObjectProtocol?
private static let quickPasteKeyCodes: [UInt16: Int] = [
18: 0,
19: 1,
20: 2,
21: 3,
23: 4,
22: 5,
26: 6,
28: 7,
25: 8
]
private static let collectionShortcuts: [UInt16: ClipboardSortMode] = [
18: .mostRecent,
19: .mostUsed,
@@ -326,6 +337,16 @@ final class ClipboardPanelController: NSObject, NSWindowDelegate, QLPreviewPanel
removeKeyMonitor()
keyMonitor = NSEvent.addLocalMonitorForEvents(matching: .keyDown) { [weak self] event in
guard let self else { return event }
if self.shouldHandlePanelKeyEvent(event, allowSearchFieldEditing: true),
let index = Self.quickPasteIndex(forKeyCode: event.keyCode, modifiers: event.modifierFlags) {
self.viewModel.pasteItem(at: index)
return nil
}
if self.shouldHandlePanelKeyEvent(event, allowSearchFieldEditing: true),
let index = Self.quickPastePlainTextIndex(forKeyCode: event.keyCode, modifiers: event.modifierFlags) {
self.viewModel.pasteItemPlainText(at: index)
return nil
}
if self.shouldHandlePanelKeyEvent(event, allowSearchFieldEditing: true),
let mode = Self.collectionShortcutMode(forKeyCode: event.keyCode, modifiers: event.modifierFlags) {
self.viewModel.sortMode = mode
@@ -424,9 +445,21 @@ final class ClipboardPanelController: NSObject, NSWindowDelegate, QLPreviewPanel
|| NSApp.window(withWindowNumber: event.windowNumber) === panel
}
static func collectionShortcutMode(forKeyCode keyCode: UInt16, modifiers: NSEvent.ModifierFlags) -> ClipboardSortMode? {
static func quickPasteIndex(forKeyCode keyCode: UInt16, modifiers: NSEvent.ModifierFlags) -> Int? {
let relevantModifiers = modifiers.intersection(.deviceIndependentFlagsMask)
guard relevantModifiers == .command else { return nil }
return quickPasteKeyCodes[keyCode]
}
static func quickPastePlainTextIndex(forKeyCode keyCode: UInt16, modifiers: NSEvent.ModifierFlags) -> Int? {
let relevantModifiers = modifiers.intersection(.deviceIndependentFlagsMask)
guard relevantModifiers == [.command, .shift] else { return nil }
return quickPasteKeyCodes[keyCode]
}
static func collectionShortcutMode(forKeyCode keyCode: UInt16, modifiers: NSEvent.ModifierFlags) -> ClipboardSortMode? {
let relevantModifiers = modifiers.intersection(.deviceIndependentFlagsMask)
guard relevantModifiers == [.command, .option] else { return nil }
return collectionShortcuts[keyCode]
}

View File

@@ -990,6 +990,10 @@ final class ClipboardPanelView: NSVisualEffectView, NSSearchFieldDelegate {
cardViews.map(\.debugHeaderBadgeSymbol)
}
var debugQuickPasteBadgeTexts: [String] {
cardViews.compactMap(\.debugQuickPasteBadgeText)
}
var debugSelectedCardFrameInDocument: NSRect {
guard viewModel.selectedIndex >= 0, viewModel.selectedIndex < cardViews.count else {
return .zero
@@ -1399,6 +1403,7 @@ private final class ClipboardItemCardView: NSView, NSDraggingSource {
private var actionRailButtons: [NSButton] = []
private weak var headerBadgeView: NSView?
private weak var headerPinView: NSView?
private weak var quickPasteBadgeLabel: NSTextField?
private var isSelected = false
private var isHovered = false
private var mouseDownLocation: NSPoint?
@@ -1564,6 +1569,10 @@ private final class ClipboardItemCardView: NSView, NSDraggingSource {
var debugHeaderBadgeIsHidden: Bool {
headerBadgeView?.isHidden ?? false
}
var debugQuickPasteBadgeText: String? {
quickPasteBadgeLabel?.stringValue
}
#endif
private func contextMenu() -> NSMenu {
@@ -1959,11 +1968,16 @@ private final class ClipboardItemCardView: NSView, NSDraggingSource {
titleAndSource.spacing = 2
titleAndSource.translatesAutoresizingMaskIntoConstraints = false
let labelStack = NSStackView(views: [titleAndSource])
var labelViews: [NSView] = []
if let quickPasteBadge = quickPasteBadge() {
labelViews.append(quickPasteBadge)
}
labelViews.append(titleAndSource)
let labelStack = NSStackView(views: labelViews)
labelStack.orientation = .horizontal
labelStack.alignment = .centerY
labelStack.distribution = .fill
labelStack.spacing = 1
labelStack.spacing = labelViews.count > 1 ? 9 : 1
labelStack.translatesAutoresizingMaskIntoConstraints = false
let badge = iconBadge(for: item)
@@ -2011,6 +2025,27 @@ private final class ClipboardItemCardView: NSView, NSDraggingSource {
return header
}
private func quickPasteBadge() -> NSTextField? {
guard index < 9 else { return nil }
let label = NSTextField(labelWithString: "\(index + 1)")
label.font = .monospacedDigitSystemFont(ofSize: 11, weight: .bold)
label.textColor = NSColor.white.withAlphaComponent(0.92)
label.alignment = .center
label.lineBreakMode = .byClipping
label.wantsLayer = true
label.layer?.cornerRadius = 9
label.layer?.backgroundColor = NSColor.white.withAlphaComponent(0.18).cgColor
label.layer?.borderWidth = 0.5
label.layer?.borderColor = NSColor.white.withAlphaComponent(0.24).cgColor
label.toolTip = "Press Command-\(index + 1) to paste"
label.setAccessibilityLabel("Quick paste \(index + 1)")
label.translatesAutoresizingMaskIntoConstraints = false
label.widthAnchor.constraint(equalToConstant: 19).isActive = true
label.heightAnchor.constraint(equalToConstant: 19).isActive = true
quickPasteBadgeLabel = label
return label
}
private func bodyView(for item: ClipboardItem, thumbnail: NSImage?) -> NSView {
let body = NSView()
body.wantsLayer = true

View File

@@ -218,6 +218,18 @@ final class ClipboardPanelViewModel {
settings.setPasteStatus(message: result.message)
}
func pasteItem(at index: Int) {
guard index >= 0 && index < visibleItems.count else { return }
selectItem(at: index)
pasteSelected()
}
func pasteItemPlainText(at index: Int) {
guard index >= 0 && index < visibleItems.count else { return }
selectItem(at: index)
pasteSelectedPlainText()
}
func copySelected() {
guard let item = selectedItem else { return }
let result = pasteService.copy(item)