---
title: Text Snippets
description: Reusable text values from inline, file, command, or directory sources
---
import { Aside, Tabs, TabItem, Card, CardGrid, Steps, Code } from '@astrojs/starlight/components';
import { Image } from 'astro:assets';
import snippetsScreenshot from '../../../assets/screenshots/text-snippets.png';
import placeholdersScreenshot from '../../../assets/screenshots/text-snippets-placeholders.png';
import bugReport from '../../../../../examples/snippets/bug-report.snippet?raw';
import reviewRequest from '../../../../../examples/snippets/review-request.snippet?raw';
import meetingNotes from '../../../../../examples/snippets/meeting-notes.snippet?raw';
import incidentHandover from '../../../../../examples/snippets/incident-handover.snippet?raw';
import followUp from '../../../../../examples/snippets/follow-up.snippet?raw';
import signOff from '../../../../../examples/snippets/sign-off.snippet?raw';
The native interface supports text snippets, which let you define reusable text values that can be searched and copied to the clipboard or typed into applications.
<Aside type="note">
Text snippets are only available in **native mode**. They are not available when using Fuzzel mode.
</Aside>
## Overview
Snippets can come from four different sources:
<div class="nav-cards">
<CardGrid>
<a href="#inline-snippets">
<Card title="Inline" icon="pencil">
Defined directly in the config file
</Card>
</a>
<a href="#file-source">
<Card title="File" icon="document">
Loaded from an external YAML file
</Card>
</a>
<a href="#command-source">
<Card title="Command" icon="laptop">
Generated by running a command (Alfred JSON format)
</Card>
</a>
<a href="#directory-source">
<Card title="Directory" icon="puzzle">
Loaded from `.snippet` files in a directory
</Card>
</a>
</CardGrid>
</div>
<Image src={snippetsScreenshot} alt="Text snippets list with a selected snippet and expanded preview" width={800} />
<style>
{`
.nav-cards a {
text-decoration: none !important;
color: inherit;
display: flex;
height: 100%;
}
.nav-cards a article {
flex: 1;
transition: all 0.2s ease-in-out;
cursor: pointer;
display: flex;
flex-direction: column;
gap: 1rem;
border: 1px solid var(--sl-color-gray-5);
background-color: var(--sl-color-black);
}
.nav-cards a article .title {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 1rem;
font-size: 1.2rem;
}
.nav-cards a article .title .icon {
font-size: 2.5rem !important; /* Huge icons */
color: var(--sl-color-purple);
background: var(--sl-color-purple-low);
padding: 0.5rem;
border-radius: 0.5rem;
border: 1px solid var(--sl-color-purple);
}
.nav-cards a:hover article {
border-color: var(--sl-color-text-accent);
background-color: var(--sl-color-gray-6);
}
`}
</style>
## Usage
<Steps>
1. **Type Keyword**
Type the configured keyword followed by a space (e.g., `em ` for emails).
While you are still typing the keyword, Raffi shows a row describing what it
does; press Enter or Tab on that row to jump straight into the source.
2. **Filter Results**
Continue typing to filter snippets. Exact [keyword](#snippet-keywords-and-search)
matches come first, then keyword prefixes, then fuzzy matches on the name,
then fuzzy matches on the snippet content. Snippets you used recently come
first when nothing is typed and win ties between equal matches
3. **Select Snippet**
Use arrow keys to select the desired snippet
4. **Execute Action**
- **Enter**: Default action (copy or insert)
- **Ctrl+Enter**: Secondary action (if configured)
</Steps>
## Configuration Sources
### Inline Snippets
Define snippets directly in `raffi.yaml`:
```yaml raffi.yaml
addons:
text_snippets:
- name: "Emails"
keyword: "em"
icon: "mail"
snippets:
- name: "Personal Email"
icon: "📨"
value: "user@example.com"
- name: "Work Email"
value: "user@company.com"
- name: "Support Email"
value: "support@company.com"
```
Usage:
```text
em personal
# Filters to "Personal Email"
# Press Enter to copy user@example.com
```
### File Source
Load snippets from an external YAML file:
```yaml raffi.yaml
addons:
text_snippets:
- name: "Templates"
keyword: "tpl"
icon: "document"
file: "~/.config/raffi/snippets.yaml"
```
The snippet file (`~/.config/raffi/snippets.yaml`):
```yaml snippets.yaml
- name: "Greeting"
value: "Hello, world!"
- name: "Signature"
value: "Best regards, User"
- name: "Meeting Template"
value: |
Meeting Notes
Date: {date}
Attendees: [NAMES]
Topics:
-
Action Items:
-
```
<Aside type="note">
File-based snippets are cached per session for performance.
</Aside>
### Command Source
Generate snippets dynamically from a command:
```yaml raffi.yaml
addons:
text_snippets:
- name: "Dynamic"
keyword: "dyn"
icon: "terminal"
command: "my-snippet-gen"
args: ["-j"]
```
The command must output JSON in Alfred Script Filter format:
```json
{
"items": [
{
"title": "Current Date",
"arg": "2024-03-15"
},
{
"title": "Current Time",
"arg": "14:30:00"
}
]
}
```
<Aside type="tip">
The `title` field becomes the snippet name, and `arg` becomes the snippet value.
An optional `keyword` field sets the [snippet keyword](#snippet-keywords-and-search).
An optional `icon` object, such as `"icon": {"path": "mail-client"}`, sets the item icon.
</Aside>
### Directory Source
Load snippets from a directory of `.snippet` files:
```yaml raffi.yaml
addons:
text_snippets:
- name: "Snippets"
keyword: "sn"
icon: "snippets"
directory: "~/.local/share/desktop-config/snippets"
```
Each `.snippet` file has this format:
```text greeting.snippet
Friendly Greeting
---
Hello! How are you doing today?
```
```text email-signature.snippet
Professional Signature
---
Best regards,
John Doe
Software Engineer
john@example.com
```
Format:
- **First line**: Snippet name (description)
- **Optional `keyword: ...` header**: [Snippet keyword](#snippet-keywords-and-search)
- **Optional `icon: ...` header**: Emoji, icon name, or image path
- **`---`**: Separator
- **After separator**: Snippet content (value)
```text signature.snippet
Professional Signature
keyword: !sig
icon: ✍️
---
Best regards,
John Doe
```
<Aside type="note">
The `keyword:` and `icon:` headers can appear in either order. Keep the name
on the first line and the content after `---`. Directory-based snippets are
read in alphabetical order, then ordered by use like any other source, and
cached per session.
</Aside>
## Dynamic Placeholders
Snippet values can contain placeholders that are filled in when you pick the
snippet. The subtitle under each snippet shows a preview of the result.
```yaml raffi.yaml
snippets:
- name: "Quote clipboard"
value: "> {clipboard}"
- name: "Meeting header"
value: "## Meeting {date:%A %d %B}, follow-up on {date +1w}"
- name: "Branch"
value: "{shell:git -C ~/src/project branch --show-current}"
- name: "Function"
value: "fn {cursor}() {}"
```
| Placeholder | Result |
|---|---|
| `{clipboard}` | Current clipboard text |
| `{clipboard:1}` | An earlier clipboard entry, up to `{clipboard:100}`. See [Clipboard history](#clipboard-history) |
| `{date}` `{time}` `{datetime}` | Now, formatted as `%Y-%m-%d`, `%H:%M` and `%Y-%m-%d %H:%M` |
| `{date:%A %d %B}` | Custom [strftime](https://docs.rs/chrono/latest/chrono/format/strftime/index.html) format, also for `time` and `datetime` |
| `{date +1d}` `{datetime -2h +30m:%H:%M}` | Date arithmetic. Units: `s` `m` `h` `d` `w` `M` (months) `y` |
| `{random:uuid}` | A random UUID (v4) |
| `{random:1-100}` | A random whole number between both values, inclusive |
| `{env:USER}` | An environment variable, empty when unset |
| `{snippet:NAME}` | Another snippet from the same source, by name or keyword |
| `{shell:COMMAND}` | Output of `sh -c COMMAND` |
| `{cursor}` | Where the caret ends up after `insert` |
<Image src={placeholdersScreenshot} alt="Snippet preview showing an expanded dynamic value and its raw template" width={800} />
Add transforms after a `|`, chained left to right: `uppercase`, `lowercase`,
`capitals` (first letter of each word) and `trim`. For example
`{clipboard|trim|lowercase}` or `{env:USER|capitals}`. Transforms work on every
placeholder except `shell` and `cursor`.
Some details worth knowing:
- Only the names above are placeholders. Other braces, such as code or a
`{value}` in an action, are left alone. Write `\{date}` to get a literal
`{date}`. YAML double-quoted strings reject `\{` and `\}` as invalid
escapes, so put values containing them in single quotes or a block scalar,
for example `value: '\{date} is {date}'`.
- A placeholder with a mistake in it (unknown transform, bad date format,
reversed range, missing snippet) shows an error row and leaves Raffi open
instead of copying the wrong text.
- Month and year offsets clamp to the end of the month: January 31 `+1M` is the
last day of February.
- Text that comes from the clipboard, environment, shell or another snippet's
placeholders is inserted as is and not scanned for more placeholders.
`{snippet:...}` references can nest up to 5 levels and expand at most 1000
times in total.
- `{shell:...}` ends at the first `}`. Write `\}` for a literal `}` inside the
command. It times out after 5 seconds and terminates the command and its
child processes. It never runs for the preview, only
when you select the snippet, and it is disabled for `command:` sources.
- Previews leave `{shell:...}` and `{random:...}` untouched. The clipboard
preview is read once when the source opens, the final value reads it again.
- Only the first `{cursor}` counts, and it only moves the caret with `insert`.
The caret moves one Left key per character, which can be off by a few for
emoji sequences or combining accents.
- Expanded values are limited to 100 KiB. With `insert`, `{cursor}` can be at
most 1000 characters from the end of the value.
### Clipboard History
`{clipboard:1}` is the entry copied before the current one, `{clipboard:2}` the
one before that, and so on. `{clipboard:0}` is the same as `{clipboard}`. Raffi
keeps no history of its own, so these read from the clipboard manager you
already run: [cliphist](https://github.com/sentriz/cliphist),
[CopyQ](https://hluk.github.io/CopyQ/) or
[clipman](https://github.com/yory8/clipman).
```yaml raffi.yaml
snippets:
- name: "Previous copy"
value: "{clipboard:1|trim}"
- name: "Name and email"
value: "{clipboard:1} <{clipboard}>"
```
Raffi picks the manager that is running under your user. It looks for
`cliphist store` or `clipman store` (usually run from `wl-paste --watch`) and
for the CopyQ server, and prefers them in that order when several run. A custom
`-db-path` for cliphist or `--histpath` for clipman on that command line is
used too, including paths containing spaces. Quote those paths when launching
the watcher through a shell. To pick one yourself or turn history off, set
[`clipboard_history`](../../configuration/general-settings/) in
`general:`.
With CopyQ, Raffi reads the tab CopyQ saves the clipboard to (its
`clipboard_tab` setting), even when that is not the first tab.
Numbering assumes the newest entry in the manager is the current clipboard, as
Alfred does. If the manager skipped what you just copied (an image, a password
it ignores, text below its minimum length), the numbers are off by one. Entries
that are not text, such as images, show an error instead of being inserted.
<Aside type="caution">
Placeholders are on by default, so existing snippets containing `{date}` or
`{clipboard}` now expand. Escape them with `\{` inside single-quoted or block
scalar YAML values, such as `value: '\{date} is {date}'`, or set
`placeholders: false` on the source to keep every value exactly as written.
</Aside>
## Snippet Keywords and Search
Each snippet can have its own `keyword`, a short abbreviation you type to find
it straight away, like Alfred's snippet keywords:
```yaml raffi.yaml
snippets:
- name: "Email signature"
keyword: "!sig"
value: "Best regards, John"
```
Typing `sn !sig` puts that snippet first. Results are ranked as exact keyword,
then keyword prefix, then fuzzy match on the name, then fuzzy match on the raw
snippet value (before placeholders are filled in). The keyword is shown next to
the snippet name.
Raffi also remembers which snippets you pick, scored with the same
[`sort_mode`](../../configuration/general-settings/) as launchers (`hybrid` by
default). With nothing typed after the source keyword, the snippets you use
most come first; while typing, usage only decides between equally good
matches. A query starting with `!` is a keyword lookup, so usage is ignored
there and ties keep the source order. Usage is stored in
`~/.cache/raffi/snippets.cache`, per source keyword and snippet name.
To search a source without its keyword, add it to
[`general.main_view`](../../configuration/general-settings/#main-view) as
`text_snippets."<name>"`. Its best matches then show in the main list. A
command source runs once when Raffi starts there, rather than for each
search.
## Actions
Configure how snippets are used when selected:
### Default Actions
<Tabs>
<TabItem label="Copy (Default)">
```yaml
action: "copy"
```
Copies snippet to clipboard using `wl-copy`, `xclip`, or `xsel`
</TabItem>
<TabItem label="Insert/Type">
```yaml
action: "insert"
```
Types snippet into focused app using `wtype` or `ydotool`
</TabItem>
<TabItem label="Hyprland Paste (Default on Hyprland)">
```yaml
action: "hypr_paste"
secondary_action: "copy"
restore_clipboard: true
```
Copies the expanded snippet with `wl-copy`, closes Raffi, waits for the
original window to regain focus, and sends the paste shortcut directly to
that window through Hyprland: Ctrl+V, or Ctrl+Shift+V in terminals. This avoids typing long snippets character by character.
</TabItem>
</Tabs>
When Raffi runs inside Hyprland and a source has no `action`, Enter uses
`hypr_paste`. If Raffi finds no window to paste into when it opens, or
Hyprland is older than 0.55, Enter keeps the `copy` default. Set `action: "copy"` to keep copying on Hyprland.
`hypr_paste` requires Hyprland's Lua API (0.55 or later), `hyprctl`, and
`wl-clipboard`. Run Raffi inside the Hyprland session so it inherits
`HYPRLAND_INSTANCE_SIGNATURE` and `XDG_RUNTIME_DIR`. It works with either
`action` or `secondary_action` on a text snippet source. The receiving app
must accept Ctrl+V, or Ctrl+Shift+V for terminals. Raffi recognises common
terminals by their window class; add others with
[`general.terminal_classes`](../../configuration/general-settings/).
Snippet copies are marked sensitive so clipboard managers that honor this
hint, including CopyQ with its default settings, keep them out of history.
The hint needs wl-clipboard 2.3 or later; older versions paste without it.
This applies whether clipboard restoration is enabled or not. Ordinary `copy`
actions and restored clipboard text are not marked sensitive. Existing history
entries are not removed.
By default, the snippet stays on the clipboard. Set `restore_clipboard: true`
on the source to restore the previous plain text one second after sending the
paste shortcut, provided the clipboard still has Raffi's paste marker. A newer
copy skips restoration, even if it contains identical text. Saving an empty,
unavailable, non-text, invalid UTF-8, or larger-than-100-KiB selection skips
restoration and still allows pasting. Rich text is restored as plain text;
images and other formats are not preserved. Restoration is best effort: a
slow application may not finish reading the snippet before the delay expires.
`{cursor}` is removed during expansion but does not move the caret with this
action. Clipboard preparation errors keep Raffi open. If the original window
does not regain focus within two seconds, or Hyprland rejects the shortcut,
Raffi reports an error and does not paste elsewhere. Successful dispatch means
the shortcut was sent, not that the receiving app confirmed insertion.
### Custom Actions
Use a shell command as the action. The value is exported as the `RAFFI_VALUE`
environment variable:
```yaml raffi.yaml
text_snippets:
- name: "Commands"
keyword: "cmd"
action: 'kitty sh -c "$RAFFI_VALUE"'
snippets:
- name: "System Update"
value: "sudo pacman -Syu"
```
The command can also use a `{value}` placeholder, but `{value}` is pasted into
the command as raw text, so quotes or `$(...)` in the snippet are interpreted
by the shell. For snippets that pull in the clipboard, shell output or anything
else you do not control, quote the variable instead:
```yaml
action: 'notify-send "Snippet" "$RAFFI_VALUE"'
```
### Primary and Secondary Actions
Configure different actions for Enter and Ctrl+Enter:
```yaml raffi.yaml
text_snippets:
- name: "Emails"
keyword: "em"
icon: "mail"
action: "insert" # Enter: Type into app
secondary_action: "copy" # Ctrl+Enter: Copy to clipboard
snippets:
- name: "Personal Email"
value: "user@example.com"
- name: "Work Email"
value: "user@company.com"
```
## Configuration Fields
**`name`** `string` (required)
Display name shown during loading (for command sources)
**`keyword`** `string` (required)
Text that activates the snippet source
**`icon`** `string`
Default icon for the source: an emoji, a name from your icon cache, or an image
path. A snippet’s `icon` overrides it. Missing icons fall back to the source
icon. `no_icons` hides both. Image paths support `~` and environment variables.
**`snippets`** `array`
Inline list of snippets (each with `name`, `value`, and optional `keyword` and `icon` fields)
**`file`** `string`
Path to a YAML file containing snippets (cached per session)
**`command`** `string`
Executable that outputs Alfred Script Filter JSON
**`directory`** `string`
Path to a directory of `.snippet` files (cached per session)
**`args`** `array`
Arguments passed to the command
**`action`** `string` (default: `copy`, or `hypr_paste` on Hyprland)
Action on Enter:
- `"copy"`: Copy to clipboard
- `"insert"`: Type into focused app
- `"hypr_paste"`: Paste into the original window on Hyprland
- Command template with `{value}` placeholder
**`secondary_action`** `string` (default: `insert`)
Action on Ctrl+Enter. Accepts same values as `action`.
**`placeholders`** `boolean` (default: `true`)
Expand [dynamic placeholders](#dynamic-placeholders) in snippet values. Set to
`false` to use values exactly as written.
<Aside type="caution">
Exactly one of `snippets`, `file`, `command`, or `directory` should be specified per entry.
</Aside>
## Examples
### Work Templates
These templates turn copied context into bug reports, review requests, notes,
and emails. Browse the [snippet files on GitHub](https://github.com/chmouel/raffi/tree/main/examples/snippets),
or download all six with `curl`. This command skips files you already have:
```sh
snippet_dir="$HOME/.local/share/raffi/snippets"
base_url="https://raw.githubusercontent.com/chmouel/raffi/main/examples/snippets"
mkdir -p "$snippet_dir"
for name in bug-report review-request meeting-notes incident-handover follow-up sign-off; do
[ -e "$snippet_dir/$name.snippet" ] && continue
curl --fail --location --remove-on-error \
"$base_url/$name.snippet" \
--output "$snippet_dir/$name.snippet" || break
done
```
Keep all six files together: the review request and follow-up email reuse the
sign-off by its `!signoff` keyword. Edit that file to use your preferred name;
by default it uses your login name with an initial capital.
Add a directory source to your existing `addons.text_snippets` list:
```yaml raffi.yaml
addons:
text_snippets:
- name: "Work templates"
keyword: "sn"
directory: "~/.local/share/raffi/snippets"
action: "hypr_paste"
secondary_action: "copy"
restore_clipboard: true
```
Use `action: "copy"` on other compositors. Placeholders are enabled by default.
Copy the context described below, focus a browser text field, open Raffi, and
search for the template's keyword. Dates use local time; `+2d` means two
calendar days. Replace the bracketed prompts after pasting.
| Search | Copy before opening Raffi | Result |
|---|---|---|
| `sn !bug` | Error output or a failing test log | Markdown bug report with the error and report date |
| `sn !review` | A pull request URL | Review request with testing prompts, a deadline, and your sign-off |
| `sn !meeting` | A meeting topic on one line | Notes with decisions, action owners, and next week's date |
| `sn !handover` | The latest incident summary | Handover with impact, next actions, and an update time in 30 minutes |
| `sn !followup` | A ticket, link, or earlier message | Follow-up email with a reply date and your sign-off |
| `sn !signoff` | Nothing | The shared sign-off used by the email templates |
<Tabs>
<TabItem label="Bug report">
<Code code={bugReport} lang="text" title="bug-report.snippet" />
</TabItem>
<TabItem label="PR review">
<Code code={reviewRequest} lang="text" title="review-request.snippet" />
</TabItem>
<TabItem label="Meeting notes">
<Code code={meetingNotes} lang="text" title="meeting-notes.snippet" />
</TabItem>
<TabItem label="Incident handover">
<Code code={incidentHandover} lang="text" title="incident-handover.snippet" />
</TabItem>
<TabItem label="Follow-up email">
<Code code={followUp} lang="text" title="follow-up.snippet" />
</TabItem>
<TabItem label="Sign-off">
<Code code={signOff} lang="text" title="sign-off.snippet" />
</TabItem>
</Tabs>
To check clipboard restoration, copy a recognizable piece of text, paste a
template with Enter, wait a second, then paste manually again. The second
paste should contain the original text. With CopyQ's default settings, the
generated template should stay out of history. Ctrl+Enter uses the ordinary
copy action, so you can keep a generated template on the clipboard and in
history when you want to reuse it.
### Email Addresses
```yaml raffi.yaml
text_snippets:
- name: "Emails"
keyword: "em"
icon: "mail"
snippets:
- name: "Personal"
value: "john@personal.com"
- name: "Work"
value: "john@company.com"
- name: "GitHub"
value: "john@users.noreply.github.com"
```
### Code Snippets
```yaml raffi.yaml
text_snippets:
- name: "Code Templates"
keyword: "code"
icon: "code"
action: "insert"
snippets:
- name: "Rust Main"
value: |
fn main() {
println!("Hello, world!");
}
- name: "Python Main"
value: |
if __name__ == "__main__":
pass
```
### Git Commands
```yaml raffi.yaml
text_snippets:
- name: "Git Commands"
keyword: "git"
file: "~/.config/raffi/git-snippets.yaml"
```
```yaml git-snippets.yaml
- name: "Amend Commit"
value: "git commit --amend --no-edit"
- name: "Push Force"
value: "git push --force-with-lease"
- name: "Interactive Rebase"
value: "git rebase -i HEAD~"
```
### Dynamic Dates
```yaml raffi.yaml
text_snippets:
- name: "Dates"
keyword: "date"
icon: "calendar"
snippets:
- name: "Today"
keyword: "td"
value: "{date}"
- name: "Yesterday"
value: "{date -1d}"
- name: "Tomorrow"
value: "{date +1d}"
- name: "ISO Timestamp"
value: "{datetime:%Y-%m-%dT%H:%M:%S%:z}"
```
## Use Cases
<details>
<summary>Contact Information</summary>
```yaml
- name: "Contact"
keyword: "contact"
snippets:
- name: "Email"
value: "user@example.com"
- name: "Phone"
value: "+1-555-0123"
- name: "Address"
value: "123 Main St, City, State 12345"
```
</details>
<details>
<summary>Frequently Used Commands</summary>
```yaml
- name: "Shell Commands"
keyword: "sh"
action: "insert"
snippets:
- name: "Docker Cleanup"
value: "docker system prune -af"
- name: "Find Large Files"
value: "du -sh * | sort -h"
```
</details>
<details>
<summary>Text Templates</summary>
```yaml
- name: "Templates"
keyword: "tpl"
directory: "~/.config/raffi/templates"
```
With files like:
- `meeting-notes.snippet`
- `bug-report.snippet`
- `email-signature.snippet`
</details>
<details>
<summary>Programming Snippets</summary>
```yaml
- name: "Code"
keyword: "snippet"
file: "~/.config/raffi/code-snippets.yaml"
action: "insert"
```
</details>
## Keyboard Shortcuts
- **Enter**: Execute primary action (default: copy, or paste on Hyprland)
- **Ctrl+Enter**: Execute secondary action (default: insert)
- **Esc**: Cancel and return to normal mode
- **↑/↓**: Navigate through snippets
## Requirements
<Aside type="note">
**For copying**: `wl-copy` (wl-clipboard), `xclip`, or `xsel`
</Aside>
<Aside type="note">
**For typing/inserting**: `wtype` or `ydotool`
</Aside>
<Aside type="note">
**For `{clipboard:N}`**: cliphist, CopyQ or clipman running
</Aside>
## Tips
<Aside type="tip">
Use file sources for large snippet collections to keep your main config clean
</Aside>
<Aside type="tip">
Use placeholders for dates, the clipboard or a quick shell command, and command sources when the list of snippets itself is dynamic, such as API responses
</Aside>
<Aside type="tip">
Directory sources work well for organizing snippets by category (each category in its own directory)
</Aside>
<Aside type="tip">
Set `action: "insert"` and `secondary_action: "copy"` for maximum flexibility
</Aside>
## Complete Example
Here's a full configuration with multiple snippet sources:
```yaml raffi.yaml
addons:
text_snippets:
# Inline emails
- name: "Emails"
keyword: "em"
icon: "mail"
action: "copy"
snippets:
- name: "Personal"
value: "user@example.com"
- name: "Work"
value: "user@company.com"
# Templates from file
- name: "Templates"
keyword: "tpl"
icon: "document"
file: "~/.config/raffi/templates.yaml"
action: "insert"
# Snippets generated by a command
- name: "Projects"
keyword: "proj"
command: "project-snippets"
icon: "folder"
# Code snippets from directory
- name: "Code Snippets"
keyword: "code"
directory: "~/.config/raffi/snippets"
action: "insert"
secondary_action: "copy"
```