raffi 0.24.0

A simple fuzzel launcher based on YAML file
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
---
title: Addon Configuration
description: Configuration reference for built-in addons (currency, calculator, file browser, script filters, web searches, text snippets)
---

The native UI includes several built-in addons that can be configured under the `addons` section of `raffi.yaml`. All addons are enabled by default.

## Keywords

Script filters, web searches, text snippets, and the emoji picker are reached by
typing their keyword followed by a space. Typing `sn` on its own searches your
launchers as usual, while `sn ` enters the snippet source.

While you type a keyword, Raffi lists the matching keywords at the top of the
results with a short description of what each one does. Pressing Enter or Tab on
one of those rows completes your input to `sn ` and drops you into the addon, so
you never have to remember the exact keyword.

The file browser (`/`, `~/`) and the currency converter (`$`) are prefix
triggers rather than keywords, and are not affected.

Press **Ctrl+/** in the native UI to list every keyword and trigger you have
available, each with its usage syntax. The list replaces the launcher entries,
typing narrows it, Enter or Tab on a row arms that keyword, and Escape closes
it.

## Currency Converter

Converts between currencies using exchange rates from the Frankfurter API. Rates are cached for one hour.

### Configuration

**`addons.currency.enabled`** `boolean` (default: `true`)

Enable or disable the currency converter addon.

  ```yaml
  addons:
    currency:
      enabled: true

```

**`addons.currency.trigger`** `string` (default: `$`)

Character that activates currency conversion.

  Common values: `$`, `€`, `£`, `¥`

  ```yaml
  addons:
    currency:
      trigger: "€"

```

**`addons.currency.default_currency`** `string` (default: `USD`)

Source currency used when none is specified in the query.

  Must be a valid 3-letter ISO currency code (e.g., `USD`, `EUR`, `GBP`, `JPY`).

  ```yaml
  addons:
    currency:
      default_currency: EUR

```

**`addons.currency.currencies`** `array[string]`

List of available currencies for conversion.

  If omitted, all currencies supported by the Frankfurter API are available. Specify a subset to limit options.

  ```yaml
  addons:
    currency:
      currencies: ["EUR", "USD", "GBP", "JPY", "CHF"]

```

### Usage Examples

With trigger `$` and default currency `USD`:

```
$10 to eur          → Converts 10 USD to EUR
$50 gbp to usd      → Converts 50 GBP to USD
$100eur to jpy      → Converts 100 EUR to JPY
```

With trigger `€` and default currency `EUR`:

```
€10 to usd          → Converts 10 EUR to USD
€50 to gbp          → Converts 50 EUR to GBP
```

### Complete Example

```yaml
addons:
  currency:
    enabled: true
    trigger: "€"
    default_currency: EUR
    currencies: ["EUR", "USD", "GBP", "JPY"]
```

## Calculator

Evaluates mathematical expressions as you type. Results can be copied to the clipboard with Enter (requires `wl-copy`).

### Configuration

**`addons.calculator.enabled`** `boolean` (default: `true`)

Enable or disable the calculator addon.

  ```yaml
  addons:
    calculator:
      enabled: true

```

### Supported Operations

- Basic arithmetic: `+`, `-`, `*`, `/`, `%`, `^`
- Functions: `sqrt`, `sin`, `cos`, `tan`, `log`, `ln`, `exp`, `abs`, `floor`, `ceil`
- Constants: Standard mathematical constants

### Usage Examples

```
2 + 2               → 4
10 * 5              → 50
sqrt(16)            → 4
sin(0.5)            → ~0.479
2^8                 → 256
```

No trigger character is needed; simply type a valid expression.

## File Browser

Browses the filesystem with fuzzy filtering. Selecting a directory navigates into it; selecting a file opens it with `xdg-open`. Hidden files can be toggled with Ctrl+H.

### Configuration

**`addons.file_browser.enabled`** `boolean` (default: `true`)

Enable or disable the file browser addon.

  ```yaml
  addons:
    file_browser:
      enabled: true

```

**`addons.file_browser.show_hidden`** `boolean` (default: `false`)

Show hidden files by default.

  Can be toggled at runtime with Ctrl+H.

  ```yaml
  addons:
    file_browser:
      show_hidden: true

```

### Usage

- Type `/` to browse from root
- Type `~` to browse from home directory
- Text after the last `/` filters the current directory (e.g., `/home/us` filters `/home/` by "us")
- Enter: Navigate into directory or open file
- Alt+Enter: Copy file/directory path to clipboard
- Tab: Autocomplete selected entry into search bar
- Ctrl+H: Toggle hidden file visibility

Directories are listed first in accent color.

### Example

```yaml
addons:
  file_browser:
    enabled: true
    show_hidden: false
```

## Script Filters

Script filters allow external commands to provide dynamic results using the [Alfred Script Filter JSON format](https://www.alfredapp.com/help/workflows/inputs/script-filter/json/).

### Configuration

**`addons.script_filters`** `array[object]` (default: `[]`)

List of script filter configurations.

  Each entry defines a keyword-triggered dynamic source.

### Script Filter Fields

**`name`** `string` (required)

Display name shown during loading.

  ```yaml
  addons:
    script_filters:
      - name: "Timezones"

```

**`keyword`** `string` (required)

Text that activates the script filter. Type it followed by a space, so `tz `
enters the filter while `tz` keeps searching launchers.

  ```yaml
  addons:
    script_filters:
      - keyword: "tz"

```

**`command`** `string` (required)

Executable to run.

  Supports tilde and environment variable expansion.

  ```yaml
  addons:
    script_filters:
      - command: "batz"

```

**`args`** `array[string]` (default: `[]`)

Arguments passed to the command before the user's query.

  ```yaml
  addons:
    script_filters:
      - command: "my-script"
        args: ["-j", "--verbose"]

```

**`icon`** `string`

Fallback icon name for results without their own icon.

  ```yaml
  addons:
    script_filters:
      - icon: "clock"

```

**`action`** `string` (default: `copy`)

Action to perform on Enter.

  Special values:

- `copy` - Copy to clipboard via `wl-copy`/`xclip`/`xsel`
- `insert` - Type into focused app via `wtype`/`ydotool`

  Any other string is executed as a shell command via `sh -c`, with `{value}` replaced by the selected value.

  ```yaml
  addons:
    script_filters:
      - action: "copy"                    # Copy to clipboard
      - action: "xdg-open {value}"        # Open in browser
      - action: "notify-send {value}"    # Show notification

```


**`secondary_action`** `string`

Action to perform on Ctrl+Enter.

  Accepts the same values as `action`. If omitted, Ctrl+Enter behaves the same as Enter.

  ```yaml
  addons:
    script_filters:
      - action: "copy"
        secondary_action: "xdg-open {value}"

```

**`env`** `object` (default: `{}`)

Environment variables passed to the script process.

  ```yaml
  addons:
    script_filters:
      - command: "my-script"
        env:
          API_KEY: "secret"
          TZ_FORMAT: "short"

```

**`min_query_length`** `integer`

Minimum number of characters required after the keyword before the script executes.

  When the query is shorter than this value, results are cleared and the script is not run. Useful for scripts that are slow or expensive with short queries.

  ```yaml
  addons:
    script_filters:
      - command: "my-script"
        min_query_length: 2   # only execute after 2 chars typed

```

### JSON Output Format

The script must output JSON matching this structure:

```json
{
  "items": [
    {
      "title": "New York",
      "subtitle": "EST (UTC-5) — 14:30",
      "arg": "America/New_York",
      "icon": { "path": "/usr/share/icons/clock.png" }
    }
  ]
}
```

**JSON Fields:**

- `title` (required): Main text displayed for the item
- `subtitle` (optional): Secondary text shown below the title
- `arg` (optional): Value used in actions (falls back to `title` if omitted)
- `icon.path` (optional): Absolute path to a PNG or SVG icon

The `title` and `subtitle` fields support ANSI color codes for colored text rendering.

### Example: Timezone Converter

```yaml
addons:
  script_filters:
    - name: "Timezones"
      keyword: "tz"
      command: "batz"        # https://github.com/chmouel/batzconverter
      args: ["-j"]
      icon: "clock"
```

Usage: Type `tz paris` to see current time in Paris.

### Example: Bookmarks with Actions

```yaml
addons:
  script_filters:
    - name: "Bookmarks"
      keyword: "bm"
      command: "my-bookmark-script"
      args: ["-j"]
      action: "copy"                    # Enter: Copy URL
      secondary_action: "xdg-open {value}"  # Ctrl+Enter: Open in browser
      icon: "bookmark"
```

## Web Searches

Quick web searches via URL templates. Type a keyword followed by your query to open your browser with search results.

### Configuration

**`addons.web_searches`** `array[object]` (default: `[]`)

List of web search configurations.

### Web Search Fields

**`name`** `string` (required)

Display name shown in the search row (e.g., "Search Google for...").

  ```yaml
  addons:
    web_searches:
      - name: "Google"

```

**`keyword`** `string` (required)

Text that activates the web search. Type it followed by a space, so `g `
enters the search while `g` keeps searching launchers.

  ```yaml
  addons:
    web_searches:
      - keyword: "g"

```

**`url`** `string` (required)

URL template with `{query}` placeholder.

  The `{query}` placeholder is replaced with the search terms, automatically percent-encoded.

  ```yaml
  addons:
    web_searches:
      - url: "https://google.com/search?q={query}"

```

**`icon`** `string`

Icon name from your icon cache.

  ```yaml
  addons:
    web_searches:
      - icon: "google"

```

### Example: Common Search Engines

```yaml
addons:
  web_searches:
    - name: "Google"
      keyword: "g"
      url: "https://google.com/search?q={query}"
      icon: "google"

    - name: "DuckDuckGo"
      keyword: "ddg"
      url: "https://duckduckgo.com/?q={query}"
      icon: "duckduckgo"

    - name: "GitHub"
      keyword: "gh"
      url: "https://github.com/search?q={query}&type=repositories"
      icon: "github"

    - name: "Wikipedia"
      keyword: "wiki"
      url: "https://en.wikipedia.org/wiki/Special:Search?search={query}"
      icon: "wikipedia"
```

### Usage Examples

```
g rust traits       → Opens Google search for "rust traits"
ddg wayland        → Opens DuckDuckGo search for "wayland"
gh iced            → Opens GitHub search for "iced" repositories
```

## Text Snippets

Reusable text values that can be searched and copied/typed. Snippets can come from inline definitions, external files, commands, or directories.

### Configuration

**`addons.text_snippets`** `array[object]` (default: `[]`)

List of text snippet source configurations.

### Text Snippet Fields

**`name`** `string` (required)

Display name shown during loading (for command sources).

  ```yaml
  addons:
    text_snippets:
      - name: "Emails"

```

**`keyword`** `string` (required)

Text that activates this snippet source. Type it followed by a space, so `em `
enters the source while `em` keeps searching launchers.

  ```yaml
  addons:
    text_snippets:
      - keyword: "em"

```

**`icon`** `string`

Default emoji, icon name, or image path displayed next to each snippet.
A per-snippet `icon` overrides it; an unavailable icon falls back to this
default. `no_icons` hides both. Paths support tilde and environment variables.

  ```yaml
  addons:
    text_snippets:
      - icon: "mail"

```

**`snippets`** `array[object]`

Inline list of snippets.

  Each snippet has:

- `name` (string, required): Display name
- `value` (string, required): Snippet content, which may contain
  [dynamic placeholders](/features/text-snippets/#dynamic-placeholders)
  such as `{clipboard}` or `{date +1d}`
- `keyword` (string, optional): Abbreviation ranked first when typed exactly
- `icon` (string, optional): Emoji (for example `🏠`), icon name, or image path

  ```yaml
  addons:
    text_snippets:
      - snippets:
          - name: "Personal Email"
            icon: "📨"
            value: "user@example.com"
          - name: "Work Email"
            value: "user@company.com"

```


**`file`** `string`

Path to a YAML file containing snippets.

  The file must contain a list of objects with `name` and `value` fields. Supports tilde and environment variable expansion. File contents are cached per session.

  ```yaml
  addons:
    text_snippets:
      - file: "~/.config/raffi/snippets.yaml"

```

  File format:

  ```yaml
  - name: "Greeting"
    value: "Hello, world!"
  - name: "Signature"
    value: "Best regards, User"

```

**`command`** `string`

Executable that outputs Alfred Script Filter JSON.

  The `title` field maps to snippet name, `arg` to snippet value, and the optional `keyword` field to the snippet keyword. An optional `icon.path` sets the item icon. `{shell:...}` placeholders are disabled for command output. Supports tilde and environment variable expansion.

  ```yaml
  addons:
    text_snippets:
      - command: "my-snippet-gen"

```

**`directory`** `string`

Path to a directory of `.snippet` files.

  Each `.snippet` file format:

  ```
  Description (first line)
  keyword: !abbr (optional)
  icon: 🏠 (optional)
  ---
  Actual snippet content (everything after the separator)
  ```

  The optional headers can appear in either order. Supports tilde and environment variable expansion. Files are cached per session.

  ```yaml
  addons:
    text_snippets:
      - directory: "~/.local/share/snippets"

```

**`args`** `array[string]` (default: `[]`)

Arguments passed to the command.

  ```yaml
  addons:
    text_snippets:
      - command: "my-snippet-gen"
        args: ["-j", "--verbose"]

```

**`action`** `string` (default: `copy`, or `hypr_paste` on Hyprland)

Action to perform on Enter. Inside Hyprland, an unset `action` becomes
`hypr_paste` when Raffi finds a window to paste into, and `copy` otherwise.

  Special values:

- `copy` - Copy to clipboard via `wl-copy`/`xclip`/`xsel` (default outside Hyprland)
- `insert` - Type into focused app via `wtype`/`ydotool`
- `hypr_paste` - On Hyprland, copy with `wl-copy`, close Raffi, wait for the
  original window to regain focus, and send Ctrl+V to that window (Ctrl+Shift+V
  for terminals, see `general.terminal_classes`). Requires
  Hyprland's Lua API, `hyprctl`, and `wl-clipboard`. Leaves the snippet on the
  clipboard unless `restore_clipboard` is enabled; does not reposition
  `{cursor}`. Marks the snippet sensitive so CopyQ and other clipboard managers
  that honor the hint skip storing it. See
  [Hyprland paste](/features/text-snippets/#default-actions).

  Any other string is executed as a shell command via `sh -c`, with `{value}` replaced by the snippet value. The value is also exported as `$RAFFI_VALUE`; prefer `"$RAFFI_VALUE"` when the snippet may contain quotes or shell syntax, since `{value}` is substituted as raw text.

  ```yaml
  addons:
    text_snippets:
      - action: "copy"                    # Copy to clipboard
      - action: "insert"                  # Type into app
      - action: "hypr_paste"              # Paste into the original window on Hyprland
      - action: 'notify-send "$RAFFI_VALUE"'  # Custom command

```


**`secondary_action`** `string` (default: `insert`)

Action to perform on Ctrl+Enter.

  Accepts the same values as `action`. Defaults to `insert` if omitted.

  ```yaml
  addons:
    text_snippets:
      - action: "insert"          # Enter: Type
        secondary_action: "copy"  # Ctrl+Enter: Copy

```

**`restore_clipboard`** `boolean` (default: `false`)

For `action: "hypr_paste"` or `secondary_action: "hypr_paste"`, save the
previous plain-text clipboard and restore it one second after the shortcut
if Raffi's clipboard marker is still present. Requires `wl-paste`. Saving or
restoration failures do not block pasting. Snapshots are limited to 100 KiB of
UTF-8 text without NUL bytes; unavailable or non-text selections are skipped.
Rich-text formatting and images are not preserved. The delay is best effort
and may be too short for slow applications. This setting does not affect other
actions.

**`placeholders`** `boolean` (default: `true`)

Expand [dynamic placeholders](/features/text-snippets/#dynamic-placeholders) in snippet values. Set to `false` to use values exactly as written.

  ```yaml
  addons:
    text_snippets:
      - file: "~/.config/raffi/literal-snippets.yaml"
        placeholders: false

```

**Note:** Exactly one of `snippets`, `file`, `command`, or `directory` should be specified per entry.

### Example: Inline Snippets

```yaml
addons:
  text_snippets:
    - name: "Emails"
      keyword: "em"
      icon: "mail"
      action: "copy"
      snippets:
        - name: "Personal Email"
          value: "user@example.com"
        - name: "Work Email"
          value: "user@company.com"
```

### Example: File-Based Snippets

```yaml
addons:
  text_snippets:
    - name: "Templates"
      keyword: "tpl"
      icon: "document"
      file: "~/.config/raffi/snippets.yaml"
```

### Example: Command-Based Snippets

```yaml
addons:
  text_snippets:
    - name: "Dynamic"
      keyword: "dyn"
      icon: "terminal"
      command: "my-snippet-gen"
      args: ["-j"]
```

### Example: Directory-Based Snippets

```yaml
addons:
  text_snippets:
    - name: "Code Snippets"
      keyword: "sn"
      icon: "code"
      directory: "~/.local/share/snippets"
```

### Example: Custom Actions

```yaml
addons:
  text_snippets:
    - name: "URLs"
      keyword: "url"
      icon: "web-browser"
      action: "xdg-open {value}"        # Enter: Open in browser
      secondary_action: "copy"          # Ctrl+Enter: Copy URL
      snippets:
        - name: "GitHub"
          value: "https://github.com"
        - name: "Documentation"
          value: "https://docs.example.com"
```

## Complete Addon Example

```yaml
addons:
  currency:
    enabled: true
    trigger: "$"
    default_currency: USD
    currencies: ["USD", "EUR", "GBP", "JPY"]

  calculator:
    enabled: true

  file_browser:
    enabled: true
    show_hidden: false

  script_filters:
    - name: "Timezones"
      keyword: "tz"
      command: "batz"
      args: ["-j"]
      icon: "clock"
      min_query_length: 2
      env:
        TZ_FORMAT: "short"

    - name: "Bookmarks"
      keyword: "bm"
      command: "my-bookmark-script"
      args: ["-j"]
      action: "copy"
      secondary_action: "xdg-open {value}"
      icon: "bookmark"

  web_searches:
    - name: "Google"
      keyword: "g"
      url: "https://google.com/search?q={query}"
      icon: "google"

    - name: "GitHub"
      keyword: "gh"
      url: "https://github.com/search?q={query}&type=repositories"
      icon: "github"

  text_snippets:
    - name: "Emails"
      keyword: "em"
      icon: "mail"
      action: "insert"
      secondary_action: "copy"
      snippets:
        - name: "Personal Email"
          value: "user@example.com"
        - name: "Work Email"
          value: "user@company.com"

    - name: "Templates"
      keyword: "tpl"
      icon: "document"
      file: "~/.config/raffi/snippets.yaml"
```