Clipboard enhancements: pin items, performance overhaul, UX improvements#248
Clipboard enhancements: pin items, performance overhaul, UX improvements#248MrLionware wants to merge 3 commits intoospfranco:mainfrom
Conversation
Major clipboard system rework with pin support, performance optimizations, and multiple UX improvements across the app. Clipboard pin feature: - Add pinnable clipboard items that always stay at the top of the list - Cmd+K opens an actions menu above the bottom bar, Cmd+P toggles pin - Pin state persists across app restarts via secure storage - Pinned items are never evicted when the clipboard reaches the 1000-item limit - Selection follows the item to its new position after pinning/unpinning - Opening clipboard defaults selection to the first unpinned (most recent) item Clipboard performance overhaul: - O(1) duplicate detection via hash map instead of O(n) linear scan - MiniSearch indexes only first 500 chars instead of full text - Search results map back to full items by ID, avoiding storing full text in index - In-place array mutations (splice/unshift) instead of array spread copies - Debounced persistence (2s) instead of persisting on every change - Text preview truncated at 5000 chars with total length indicator Clipboard UX improvements: - Reduce clipboard detection delay from 1s to 200ms (native polling interval) - Fix empty state showing "[]" instead of "No items" - Fix clipboard list not updating when copying text from the preview panel - Fix down arrow navigation going past visible items during search - Detail panel is now scrollable with selectable text and proper padding - Delete item now correctly resolves display index to raw index Other app improvements: - File search hotkey now shows the window (added to itemsThatShouldShowWindow) - Hotkeys toggle: second press hides window if same view is already showing - ESC always closes the window instantly instead of navigating backwards - Process manager shows app icons next to process names - Fix Xcode 16.3 sandbox settings blocking app functionality - Fix systemPreferences crash when accessing ~/Library/PreferencePanes Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR delivers a major clipboard manager rework (pinning + faster search/dedup + persistence improvements) alongside several UX/hotkey tweaks, file search improvements, and macOS native/project updates to support these features and improve responsiveness.
Changes:
- Add pinned clipboard items (top-sticky), a clipboard actions menu (⌘K), and pin toggle (⌘P) with persistence.
- Rework clipboard performance: hashed duplicate detection, reduced search indexing payload, and debounced persistence.
- Improve file search behavior and native search limits; update macOS project/build settings and dependencies.
Reviewed changes
Copilot reviewed 13 out of 14 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| src/stores/clipboard.store.tsx | Pin state, dedup/search performance changes, debounced persistence, display-index-aware operations |
| src/widgets/clipboard.widget.tsx | Pinned indicator, scrollable/selectable preview, truncation, empty-state fix, actions menu UI |
| src/stores/keystroke.store.ts | ⌘K menu toggle, ⌘P pin hotkey, ESC close behavior, clipboard nav fix |
| src/stores/ui.store.tsx | File search window display + debounce, hotkey toggle behavior, clipboard default selection logic |
| src/widgets/processes.widget.tsx | Render process icons via FileIcon |
| src/stores/systemPreferences.tsx | Guard sandboxed PreferencePanes access with try/catch |
| macos/sol-macOS/lib/FileSearch.h | Add depth/result limits to native file search API |
| macos/sol-macOS/lib/FileSearch.mm | Apply directory skipping + depth/result limiting to improve performance |
| macos/sol-macOS/lib/JSIBindings.mm | Thread result limit state through JSI searchFiles binding |
| macos/sol-macOS/lib/ClipboardHelper.swift | Reduce pasteboard polling interval (1.0s → 0.2s) |
| macos/sol.xcodeproj/project.pbxproj | Update build settings (sandbox/signing/Sentry script defaults/etc.) |
| macos/sol.xcodeproj/xcshareddata/xcschemes/debug.xcscheme | Update Xcode scheme upgrade version |
| macos/sol.xcodeproj/xcshareddata/xcschemes/release.xcscheme | Update Xcode scheme upgrade version |
| macos/Podfile.lock | Bump Sparkle dependency version |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
macos/sol-macOS/lib/FileSearch.mm
Outdated
| static NSSet *skippedDirectories = nil; | ||
|
|
||
| static NSSet *getSkippedDirectories() { | ||
| if (!skippedDirectories) { | ||
| skippedDirectories = [NSSet setWithObjects: | ||
| @"node_modules", @".git", @"Library", @".cache", | ||
| @".Trash", @"__pycache__", @".npm", @".yarn", | ||
| @"Pods", @"build", @"DerivedData", nil]; | ||
| } | ||
| return skippedDirectories; | ||
| } |
| import MiniSearch from "minisearch"; | ||
| import { storage } from "./storage"; | ||
| import { captureException } from "@sentry/react-native"; | ||
|
|
||
| const MAX_ITEMS = 1000; | ||
| const MAX_TEXT_INDEX_LENGTH = 500; // Only index first N chars for search | ||
| const PERSIST_DEBOUNCE_MS = 2000; |
| while (store.items.length > MAX_ITEMS) { | ||
| const last = store.items[store.items.length - 1]; | ||
| if (last?.pinned) break; | ||
| const removed = store.items.pop(); | ||
| if (removed) { | ||
| removeFromIndex(removed); | ||
| } | ||
|
|
||
| store.items = store.items.slice(0, MAX_ITEMS); | ||
| } |
| function removeFromIndex(item: PasteItem) { | ||
| try { | ||
| minisearch.remove({ id: item.id, indexText: "", datetime: 0 }); | ||
| } catch { | ||
| // ignore missing id errors | ||
| } | ||
| } |
| const [item] = store.items.splice(index, 1); | ||
| item.datetime = Date.now(); | ||
| store.items.unshift(item); |
src/stores/ui.store.tsx
Outdated
| if (firstUnpinned > 0) { | ||
| store.selectedIndex = firstUnpinned; |
…view issues Image clipboard: - Detect images (TIFF/PNG) on pasteboard and save as temp PNGs - Native FileImageView component (NSImageView) for displaying local images - Show image thumbnails in clipboard list and full preview in detail panel - Paste images back to apps via pasteFileToFrontmostApp Hotkey optimization: - Eliminate native→JS→native round-trip for app-opening hotkeys - Apps with URLs now open directly in native via NSWorkspace - Pass urlMap alongside shortcuts to updateHotkeys - syncHotkeys() rebuilds URL map when apps change PR review fixes: - Thread-safe static local in getSkippedDirectories (FileSearch.mm) - Remove unused captureException import (clipboard.store.tsx) - Use minisearch.discard(id) instead of remove with synthetic doc - Fix removeLastItemIfNeeded to evict oldest unpinned item from end - Fix popToTop to update MiniSearch datetime and trigger persist - Fix showClipboardManager selectedIndex edge case (>= 0 vs > 0) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use NSImage(pasteboard:) for automatic format handling and check for JPEG, HEIC, GIF, and BMP in addition to TIFF and PNG. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Before you start adding support for images you should take a look into the comments here: It's not something AI can one shot and this PR is way too large now. I appreciate the effort to improve but cannot really merge so many changes at once |
Summary
Major clipboard system rework with pin support, performance optimizations, and multiple UX improvements across the app.
Clipboard Pin Feature
Clipboard Performance Overhaul
splice/unshift) instead of full array spread copiesClipboard UX Improvements
NSPasteboardpolling interval)[]instead of"No items"deleteItemnow correctly resolves display index to raw index (required after pin reordering)Other App Improvements
file_searchadded toitemsThatShouldShowWindow)ENABLE_APP_SANDBOX,ENABLE_USER_SCRIPT_SANDBOXING) blocking app functionalitysystemPreferencescrash when accessing~/Library/PreferencePanesin sandboxed buildsFiles Changed
src/stores/clipboard.store.tsxsrc/stores/keystroke.store.tssrc/stores/ui.store.tsxsrc/widgets/clipboard.widget.tsxsrc/widgets/processes.widget.tsxsrc/stores/systemPreferences.tsxmacos/sol-macOS/lib/ClipboardHelper.swiftmacos/sol.xcodeproj/project.pbxprojTest Plan