ClipDiff is a tiny macOS menu bar utility for comparing the last two copied text values or text files.
scripts/create-local-release.shThe app is copied to releases/ClipDiff.app and opened.
- Copy the older text or file.
- Copy the newer text or file.
- Press
Control-Option-C, or choose Show Diff from the menu bar item. Choose Change Keyboard Shortcut… in that menu to record a different global shortcut. - View the diff in the selected viewer. The built-in native window remains the default.
You can also copy exactly two files together in Finder. ClipDiff immediately treats the first file as Previous and the second as Current.
The shortcut recorder checks enabled macOS system shortcuts and ClipDiff’s own menu commands. It explains known conflicts and registration failures, and keeps the current shortcut active if a replacement fails. These checks cannot identify every shortcut used inside other apps.
The app includes a Finder Sync extension. Choose Enable Finder menu… in the ClipDiff menu and enable ClipDiff Finder Integration in macOS System Settings. With exactly one regular file selected, Finder shows Compare with current ClipDiff capture. It reads the selected file only after invocation, moves the current in-memory capture to Previous, makes the selected file Current, and opens the configured viewer without changing the clipboard. This works while monitoring is paused if a capture remains. If there is no capture (including after a cold start), ClipDiff activates and explains that text or a file must first be copied while monitoring.
With exactly two regular files selected, Finder shows Compare two selected files with ClipDiff. Choosing it opens ClipDiff if necessary, reads and classifies the pair, replaces the in-memory comparison pair, and immediately shows the diff; the first Finder selection is Previous and the second is Current. Binary and otherwise unusable files use the documented filename-and-reason fallback. Zero, more than two, or any folder/non-regular selection shows neither command.
Finder file URLs take precedence over incidental path text on the pasteboard. A single copied file becomes one capture; exactly two copied files atomically replace the comparison pair; copies containing more than two files are ignored.
For a usable text file, ClipDiff reads and retains the complete decoded contents in memory. It supports UTF-8, BOM-marked UTF-16 and UTF-32, common BOM-less UTF-16, and Windows-1252. Files larger than 16 MiB are not read.
An unusable file contributes its filename followed by a reason:
(binary file)(directory)(empty file)(file not found)(file unreadable)(file too large)
The source filename is shown in side-by-side headings and unified diff headers. When both files have the same basename, ClipDiff adds only enough parent directories to distinguish them, such as branch-a/Sources/settings.json and branch-b/Sources/settings.json.
The full standardized file path is retained only with the corresponding in-memory history entry. A generated diff keeps its resolved display label but drops the full path. File contents and paths are never logged, uploaded, indexed, or persisted.
- The app monitors
NSPasteboard.changeCountand captures only future changes. - The optional Finder extension inspects selection metadata only to choose the one-file or two-file command. File contents are read only after that command is chosen; the app rechecks selection requests and asynchronous capture identity before committing.
- Plain text and one or two copied file URLs are supported.
- Separate copy events are captured even when their text is identical.
- Unsupported non-text changes are ignored without clearing history.
- A copied value immediately followed by an explicit clipboard clear within 60 seconds is removed as a best-effort privacy measure.
- Captured content is kept in memory only and lost when the app exits.
- Slow file reads are superseded if a newer pasteboard change arrives.
- Clipboard items marked
org.nspasteboard.ConcealedTypeororg.nspasteboard.TransientTypeare ignored before ClipDiff reads either their text or file URLs. These advisory markers are commonly used by password managers and other privacy-conscious clipboard producers. - The built-in diff is native SwiftUI and never writes captured text to disk.
The menu's Diff viewer submenu lists supported applications found on the Mac, provides Choose Application… for another app or executable, and lets you return to the built-in viewer. The selection is remembered.
ClipDiff recognizes these viewer profiles:
- FileMerge
- Kaleidoscope
- Beyond Compare
- Araxis Merge
- Visual Studio Code
- Cursor
- BBEdit
- KDiff3
- Meld
- P4Merge
- SourceGear DiffMerge
The app checks Launch Services, /Applications, ~/Applications, common Homebrew command locations, and its process PATH. A manually selected unknown executable receives the previous and current file paths as two separate positional arguments. If a selected viewer is missing or cannot be launched, Show Diff falls back to the built-in viewer without discarding either capture.
Known profiles use their supported wait, read-only, diff, and side-label options. File-backed captures preserve their basenames in separate Previous and Current directories, while viewers with title support receive the same disambiguated labels as the built-in diff.
ClipDiff supplies those labels to Beyond Compare, Araxis Merge, KDiff3, Meld, and SourceGear DiffMerge. For example, two files named README.md can appear as Previous clipboard — old/README.md and Current clipboard — new/README.md. These viewers still read temporary copies of the captured text; the labels describe the original sources. VS Code and Cursor's command-line diff integration does not accept custom side titles, so they may display the temporary paths. Other viewer profiles preserve the source basenames where available and let the viewer choose how to display them.
The local build is not App Sandbox-restricted because it must start the explicitly selected external executable. The app remains dependency-free and does not add network access or broaden its clipboard and copied-file workflow.
The default view is side-by-side:
- previous text on the left
- current text on the right
- changed and removed lines tinted red
- changed and added lines tinted green
There is also a unified view for copying or scanning a compact diff. Diff rows are rendered lazily so larger text files do not eagerly construct every visible row.
The recent-clear behavior is only a heuristic. An unmarked secret is otherwise indistinguishable from ordinary text, and Swift strings cannot be guaranteed to be securely zeroed. Operating-system paging, process dumps, other clipboard monitors, and macOS clipboard behavior are outside ClipDiff's control.
Concealed and transient pasteboard markers are advisory and depend on the source application providing them. ClipDiff does not guess whether unmarked text is sensitive from its contents, length, or source application.
The built-in viewer keeps the memory-only privacy model. Selecting an external viewer creates an explicit exception because another application cannot compare the captured strings directly. Before the first external comparison, ClipDiff warns that clipboard text may contain secrets and asks for confirmation. Cancelling opens the built-in viewer and creates no files.
After confirmation, each comparison writes two read-only UTF-8 plaintext files to a unique directory below the system temporary directory. ClipDiff attempts to delete that directory after the launched comparison process exits, when ClipDiff exits, and on its next launch. Cleanup is best effort: a crash, power loss, open file handle, or external application may leave or retain a copy. Do not select an external viewer when that disk exposure is unacceptable.
Only the selected executable path, the one-time warning acknowledgement, and the chosen global shortcut are stored in app preferences. Clipboard text, previews, diffs, and source paths are never stored there.
The SwiftPM XCTest suite covers clipboard history, privacy-marker payload exclusion, recent clears, copied-file decoding and fallback behavior, filename disambiguation, version formatting, and line-based diff behavior:
swift testFor Finder changes, also build the app and extension on macOS with scripts/create-local-release.sh, then smoke-test one-file captured-text/captured-file comparisons, the visible no-capture message, paused monitoring, unchanged clipboard, same-basename labels, unsupported selections, two-file cold start, and external-viewer warning/fallback.
For external-viewer labels, compare two files with the same basename in different folders in Beyond Compare or Meld. Confirm the panes show the shortest distinguishing source labels, including names containing spaces or Unicode. Also check plain-text captures still show Previous clipboard and Current clipboard.