Local text-expander app for macOS with a Raycast-style snippet list/editor and global snippet insertion.
- Create, edit, delete, duplicate, enable/disable, and pin snippets.
- Global expansion in other apps by typing
\+ keyword. - Suggestion panel near the caret with fuzzy matching on snippet name and keyword.
- Dynamic placeholders in snippet content:
{clipboard}{date}{time}{datetime}{date:<DateFormatter pattern>}(for example{date:yyyy-MM-dd})
- Import/export JSON snippets.
- Share a single snippet via a
snippets://share?...deep link. - Menu bar item with quick open/quit.
- Optional Launch at Login toggle.
- Configurable extra Chromium bundle IDs in a dedicated
Snippets > Settings…window (applies immediately, no relaunch).
- macOS 15.5+ (project deployment target).
- Xcode with Swift 5 support.
- Open
Snippets.xcodeprojin Xcode. - Select the
Snippetsscheme. - Build and run.
The global expander uses Accessibility APIs. If expansion does not start:
- Click
Request Permissionin the app banner. - Open
Accessibilityfrom the same banner and enable Snippets. - Click
Refresh.
Depending on macOS version/settings, Input Monitoring may also be needed for global keystroke capture.
- Type
\in a text input field to open suggestions. - Keep typing to filter snippets (fuzzy match by name/keyword).
- Use
↑/↓orCtrl+N/Ctrl+Pto navigate suggestions. - Press
TaborReturnto insert the selected snippet. - If your query exactly matches one keyword (and no longer keyword shares that prefix), it auto-expands.
- If focused text-field detection fails in some apps, fallback auto-expansion still tries to trigger from typed text.
Keyword notes:
- In the editor, the visible
\is a prefix label. Store keywords without the leading slash. - Spaces in keywords are converted to
-. - Overlapping keywords (prefix collisions) show a warning and prevent auto-expand disambiguation.
The app is organized around three main pieces:
SnippetStore: owns snippet state in memory, debounces writes, persists JSON, and handles import/export merge rules.ViewController: builds the app UI, binds controls to the store, and routes keyboard actions.SnippetExpansionEngine: runs global key listening, suggestion mode, and text replacement in other apps.
Detailed deep dive:
docs/text-input-detection.mdexplains cross-app text-input detection, Chromium/Electron workarounds, monitor quirks, and troubleshooting.
Global expansion pipeline:
- The expansion engine starts a session-level
CGEventtap plus a localNSEventmonitor. - Typed characters are appended to an internal rolling buffer.
- On
\, suggestion mode activates andSuggestionPanelControllershows ranked matches. - Ranking uses fuzzy scoring (
FuzzyMatch) against snippet name and keyword. - Selecting a snippet (or unambiguous exact-match auto-expand) triggers expansion.
- The engine resolves placeholders with
PlaceholderResolverand injects final text.
Text replacement strategy:
- The engine deletes trigger characters with synthetic backspaces.
- It writes expansion text to the pasteboard.
- It sends synthetic
Cmd+Vto paste into the frontmost app. - It restores previous clipboard contents shortly after paste, unless the clipboard changed in the meantime.
Suggestion panel positioning:
- The panel attempts to read caret bounds from Accessibility (
AXBoundsForRange). - If that fails, it falls back to focused-element geometry.
- Extra normalization avoids awkward placement in some apps (for example Safari/Chromium-style controls).
Persistence and sync behavior:
- Snippet updates write through
SnippetStoreand are saved with a short debounce. - Immediate writes are used for operations like add/delete/import/export.
- Pending writes are flushed on app termination.
The in-app shortcuts panel shows essential shortcuts by default. Hold Option while it is open to reveal the full list.
Return: copy selected snippet to clipboard.Cmd+Return: paste selected snippet into frontmost app.Cmd+K: open/close shortcuts panel.Cmd+F: focus search.Cmd+N: create snippet.Cmd+E: edit selected snippet.Cmd+D: duplicate selected snippet.Cmd+/: enable/disable selected snippet.Cmd+.: pin/unpin selected snippet.Cmd+Delete: delete selected snippet.Cmd+Shift+C: copy a deep link for the selected snippet.Cmd+Shift+I: import JSON.Cmd+Shift+E: export JSON.Esc: close action panel (or return focus to list).Ctrl+N/Ctrl+P: move selection down/up in list context.
- Import accepts:
- A raw array of snippets:
[...] - Wrapped payload:
{ "snippets": [...] }
- A raw array of snippets:
- Export writes wrapped payload format:
{ "snippets": [...] } - Import merge behavior:
- Match by
idfirst (replace existing). - Else match by
keywordcase-insensitively (replace existing, preserve existingidandcreatedAt). - Else insert as new.
- Match by
Cmd+Shift+Ccopies a shareable deep link for the selected snippet.- Deep links use the custom scheme
snippets://share?data=.... - Opening one of these links shows an import confirmation and then imports that single snippet using the same merge rules as JSON import.
- Snippets are persisted locally at:
~/Library/Application Support/SnippetsClone/snippets.json
- On first launch (or load failure), a starter snippet is created:
- Name:
Temporary Password - Keyword:
tp - Content:
TP-{date:yyyyMMdd}-{clipboard}
- Name:
- App Sandbox is disabled so global key monitoring and synthetic paste can work.
Cmd+Qsupports a one-time choice:- Hide to menu bar (keep running), or
- Quit completely.
- If you choose "Remember choice", you can reset it later from Settings, the menu bar menu, or the main window's More menu.