raffi 0.25.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
---
title: File Browser
description: Navigate your filesystem with keyboard shortcuts
---

import { Aside, Tabs, TabItem, Steps } from '@astrojs/starlight/components';
import { Image } from 'astro:assets';
import fileBrowserScreenshot from '../../../assets/screenshots/file-browser.png';
import codePreviewScreenshot from '../../../assets/screenshots/file-browser-code-preview.png';
import imagePreviewScreenshot from '../../../assets/screenshots/file-browser-image-preview.png';
import imageDetailsScreenshot from '../../../assets/screenshots/file-browser-image-scrolled.png';
import hiddenFilesScreenshot from '../../../assets/screenshots/file-browser-hidden.png';
import richPreviewScreenshot from '../../../assets/screenshots/file-browser-rich-preview.png';
import pdfPreviewScreenshot from '../../../assets/screenshots/file-browser-pdf.png';
import filterScreenshot from '../../../assets/screenshots/file-browser-filter.png';

The native interface includes a built-in file browser for quick filesystem navigation using keyboard shortcuts.

<Aside type="note">
The file browser is only available in **native mode**. It is not available when using Fuzzel mode.
</Aside>

## Overview

Navigate your filesystem directly from the launcher with fuzzy filtering, hidden file support, keyboard-driven actions, drag-and-drop to other applications, and a right-hand preview pane. Image previews scale to the largest size that fits the preview pane while keeping their aspect ratio and rescale when the window is resized; file details appear below the image and can be reached by scrolling the pane with Ctrl+J / Ctrl+K.

<Image src={fileBrowserScreenshot} alt="File browser example" width={800} />

## Activation

Start the file browser by typing one of these prefixes:

- Type `/` to browse from the root filesystem
- Type `~` to browse from your home directory

### Examples

```text
/                  # Browse root directory
~                  # Browse home directory
/home/user/        # Browse specific directory
~/Documents/       # Browse Documents folder
```

## Navigation

### Directory Structure

- **Directories** are listed first in accent color
- **Files** are listed after directories
- Current path shows in the input field

### Keyboard Shortcuts

| Key | Action |
|-----|--------|
| **Enter** | Navigate into directory OR run `action` on a file (`xdg-open` by default) |
| **Ctrl+Enter** | Run `secondary_action` on a file or directory (copy path by default) |
| **Tab** | Autocomplete selected entry into search bar |
| **Backspace** | On a trailing `/`, go up to the parent directory |
| **`~/`** or **`/`** after a `/` | Start over from your home directory or the root |
| **Ctrl+H** | Toggle hidden file visibility |
| **Ctrl+O** | Open the selected file or directory with `xdg-open` |
| **Ctrl+B** | Open the current directory in a file manager |
| **Ctrl+Y** | Copy the selected path to the clipboard, regardless of configured actions |
| **Ctrl+Alt+Y** | Copy a supported image file to the clipboard |
| **Ctrl+S** | Cycle the sort order: name, modified date, created date |
| **Ctrl+.** | Cycle the listing: all entries, files only, directories only |
| **Ctrl+J** / **Ctrl+K** | Scroll the right-hand preview pane down / up |
| **Ctrl+P** | Toggle right-hand file/directory/image preview pane |
| **Esc** | Exit file browser |
| **↑/↓** | Navigate through results |

Image clipboard copying requires `wl-copy` or `xclip`.

### File and Image Previews

<Image src={codePreviewScreenshot} alt="File browser showing a text file and its contents in the preview pane" width={800} />

<Image src={imagePreviewScreenshot} alt="Image scaled into the right-hand preview pane" width={800} />

<Image src={imageDetailsScreenshot} alt="Image preview scrolled down to file details" width={800} />

### Rich Previews

The built-in preview shows plain text, common image formats and directory listings. When `python3` is installed, raffi also runs the previewer it bundles from [`scripts/file-preview`](https://github.com/chmouel/raffi/tree/main/scripts/file-preview), which adds PDF pages, video frames, ebook and album covers, archive listings, syntax-highlighted source, Markdown, JSON and CSV tables. Nothing needs to be installed or configured.

The previewer only needs Python 3. It uses tools such as `bat`, `pdftoppm`, `ffmpegthumbnailer` or `ebook-meta` when they are installed and falls back to plainer output without them; see its README for the full list. Without `python3` on your `PATH`, raffi keeps its plain preview.

<Image src={richPreviewScreenshot} alt="Bundled file previewer showing syntax-highlighted Python from a demo document" width={800} />

<Image src={pdfPreviewScreenshot} alt="A demo PDF's first page rendered in the file browser preview pane" width={800} />

<Image src={filterScreenshot} alt="File browser restricted to files and sorted by modification time, with the current modes in the footer" width={800} />

When you select an entry, raffi shows its plain preview at once and swaps in the previewer's output when it arrives. Results are kept for the session and reused until the file changes.

The previewer follows the raffi theme: it picks the matching `bat` theme (Catppuccin, Nord, Dracula or Gruvbox) or bat's `ansi` theme, which is drawn with the raffi palette, and it ignores your terminal's `BAT_THEME`, `LS_COLORS` and `EZA_COLORS`. To keep a bat theme of your own, set `FILE_PREVIEW_BAT_THEME` in your environment.

Each new selection starts a short `python3` process once you stop moving through the list. To turn rich previews off, for example on a slow machine:

```yaml raffi.yaml
addons:
  file_browser:
    preview_command: none
```

#### Customising the previewer

The bundled script is a single Python file. To change it, fetch it from the repository, edit your copy and point `preview_command` at it:

```bash
mkdir -p ~/.config/raffi/scripts
curl -fsSL -o ~/.config/raffi/scripts/file-preview.py \
  https://raw.githubusercontent.com/chmouel/raffi/main/scripts/file-preview/file-preview.py
chmod +x ~/.config/raffi/scripts/file-preview.py
```

```yaml raffi.yaml
addons:
  file_browser:
    preview_command: "~/.config/raffi/scripts/file-preview.py"
```

Your copy no longer follows raffi upgrades.

#### Writing your own previewer

Any executable works. Raffi runs the command with `sh -c`, adds the selected path as the last argument, and sets these environment variables:

| Variable | Value |
|---|---|
| `RAFFI_PREVIEW` | `1` |
| `RAFFI_VALUE` | Absolute path of the selected file or directory |
| `RAFFI_PREVIEW_WIDTH`, `RAFFI_PREVIEW_HEIGHT` | Preview pane size in pixels |
| `RAFFI_PREVIEW_COLUMNS`, `RAFFI_PREVIEW_LINES` | Preview pane size in text cells, for tools such as `bat --terminal-width` |
| `RAFFI_THEME`, `RAFFI_THEME_MODE`, `RAFFI_THEME_FG`, ... | The current theme, see [Terminal Colours](../themes/#terminal-colours) |

The path is never pasted into the shell line, so file names containing quotes, spaces or `$(...)` are safe.

The command can print one of two things:

- Text, with ANSI colours and bold, dim, italic or underline styles. The 16 basic colours are drawn with the theme's palette, so output from `bat --theme=ansi`, `eza` or `jq -C` matches the theme. It replaces the built-in preview body. Output is cut after 1000 lines.
- A JSON preview object, in the same format as a [Script Filter preview](../script-filters/#preview-object). Use it to show an image with metadata rows, or several sections. Any `metadata` rows go above raffi's own Path, Size and Modified rows.

```json
{
  "badge": "PDF",
  "image": {"path": "/home/me/.cache/thumbs/report.png"},
  "metadata": [["Pages", "12"], ["Author", "Jane Doe"]]
}
```

JSON is only treated as a preview object when every top-level key is a preview object field (`title`, `subtitle`, `badge`, `icon`, `text`, `image`, `sections`, `metadata`; `refresh` and `dynamic` are accepted and ignored). Anything else, such as a `package.json` printed with `cat`, is shown as text.

If the command prints nothing or exits with a non-zero status, raffi keeps its built-in preview, so a previewer only needs to handle the types it knows. A command that runs longer than 3 seconds is stopped, and raffi shows the error in a `Preview` row.

<Aside type="note">
Terminal image protocols (kitty, sixel, iTerm2) do not work in the preview pane. To show an image, write it to a file and return its path in a JSON preview object.
</Aside>

## Fuzzy Filtering

Text after the last `/` fuzzy-filters the current directory listing:

<Tabs>
<TabItem label="Basic Filter">
```text
/home/us
# Filters /home/ by "us"
# Matches: user, username, usr, etc.
```
</TabItem>
<TabItem label="Deep Filter">
```text
~/Documents/proj
# Filters ~/Documents/ by "proj"
# Matches: projects, my-project, old_projects, etc.
```
</TabItem>
<TabItem label="Extension Filter">
```text
~/Downloads/.pdf
# Filters ~/Downloads/ by ".pdf"
# Shows all PDF files
```
</TabItem>
</Tabs>

## Hidden Files

Control visibility of hidden files (dotfiles):

<Tabs>
  <TabItem label="Toggle at Runtime">
    Press **Ctrl+H** to toggle hidden file visibility while browsing
  </TabItem>

  <TabItem label="Default Hidden">
    ```yaml raffi.yaml
    addons:
      file_browser:
        enabled: true
        show_hidden: false
    ```
  </TabItem>

  <TabItem label="Default Visible">
    ```yaml raffi.yaml
    addons:
      file_browser:
        enabled: true
        show_hidden: true
    ```
  </TabItem>
</Tabs>

<Aside type="note">
Hidden files start with a dot (`.`), like `.bashrc`, `.config`, etc.
</Aside>

<Image src={hiddenFilesScreenshot} alt="File browser showing hidden project files" width={800} />

## Actions

### Open File

1. Navigate to file
2. Press **Enter**
3. File opens with `xdg-open` (system default application)

```text Example
~/Documents/report.pdf
[Enter] → Opens PDF in default viewer
```

### Navigate Directory

1. Navigate to directory
2. Press **Enter**
3. Directory contents are displayed

```text Example
~/Documents/
[Enter] → Shows contents of Documents/
```

### Go Up a Directory

With the input ending in `/`, press **Backspace** to jump to the parent directory. The directory you came from stays selected, so **Enter** takes you straight back.

```text Example
~/Projects/myapp/src/
[Backspace] → Input becomes: ~/Projects/myapp/  (src/ selected)
```

### Jump Home or to the Root

After a `/`, type `~/` to start over from your home directory, or a second `/` to start over from the root, as in Emacs.

```text Example
~/Projects/myapp/src/~/   → Input becomes: ~/
~/Projects/myapp/src//    → Input becomes: /
```

Both shortcuts come from the [`fido_style`](#configuration-options) option, which is on by default.

### Copy Path

1. Navigate to file or directory
2. Press **Ctrl+Enter** (or Ctrl+click the row)
3. Full path copied to clipboard

```text Example
~/Documents/report.pdf
[Ctrl+Enter] → Copies: /home/user/Documents/report.pdf
```

This is the default `secondary_action`; see [Configuration](#configuration) to change it.

### Drag and Drop

Files and directories can be dragged **out of raffi** into any application that accepts drops (file managers, editors, terminals, browsers, email clients...):

1. Press and hold the left mouse button on a file browser row
2. Move the pointer — the drag starts once the pointer moves a few pixels (~8 logical px, typically while still inside the row)
3. Release over the target application to drop

```text Example
~/Documents/report.pdf
[press, move to a file manager] → Drops the file there
```

A quick press and release on a row still activates it like **Enter** would.

The drag offers the file as `text/uri-list` (what file managers expect) and as plain UTF-8 text of the full path (what terminals and most editors take), so text targets that are not drop-aware may still receive the path if they accept text drops.

<Aside type="note">
Dragging out of raffi requires the native Wayland interface (the default). It does not work under XWayland, X11, or in Fuzzel mode.
</Aside>

<Aside type="note">
raffi is a drag source only: it does not accept files dropped **into** it.
</Aside>

### Open in File Manager

Press **Ctrl+B** to open the directory you are browsing in a graphical file manager. With Nautilus, Dolphin, Nemo and Caja the entry selected in raffi is also selected in the file manager; other file managers just open the directory. Raffi picks your desktop's own file manager when it is installed (Dolphin on KDE, Nautilus on GNOME, Thunar on XFCE, Nemo on Cinnamon, Caja on MATE, PCManFM on LXQt/LXDE, and so on). On other sessions such as Hyprland or Sway it uses the first one it finds, and falls back to `xdg-open`. Set [`file_manager`](#configuration) to choose one yourself.

```text Example
~/Projects/myapp/src/
Selected: main.rs
[Ctrl+B] → Opens ~/Projects/myapp/src/ in your file manager with main.rs selected
```

### Autocomplete

1. Navigate to file or directory
2. Press **Tab**
3. Entry is autocompleted into search bar

```text Example
Current: /home/us
Selected: user/
[Tab] → Input becomes: /home/user/
```

## Configuration

Configure the file browser in `raffi.yaml`:

```yaml raffi.yaml
addons:
  file_browser:
    enabled: true
    show_hidden: false
    sort: name
    sort_reverse: false
    show: all
    fido_style: true
    action: open
    secondary_action: copy
    file_manager: thunar
```

### Configuration Options

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

Enable or disable the file browser addon


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

Show hidden files (dotfiles) by default. Can be toggled at runtime with Ctrl+H.


**`sort`** `string` (default: `name`)

Initial order of the listing. Directories always come before files. Press Ctrl+S to cycle through the modes while browsing; the hint bar shows the current one.

- `name`: alphabetical, ignoring case
- `modified` (or `date`): last modification time, newest first
- `created`: creation time, newest first. Entries on filesystems that do not record it go last.


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

Reverse the order of whichever `sort` mode is active: Z to A for `name`, oldest first for `modified` and `created`. Directories still come first. Ctrl+S does not change this setting.


**`show`** `string` (default: `all`)

Which entries the listing starts with. Press Ctrl+. to cycle through the modes while browsing; the hint bar shows the current one, and Raffi keeps it until it closes.

- `all`: directories and files
- `files`: files only
- `directories` (or `dirs`): directories only

When directories are hidden you can still type a path such as `~/src/` to enter one, and Tab completes the best hidden match when no visible row matches what you typed. Symlinks count as files, so `directories` hides a link to a directory.


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

Edit paths the way Emacs fido-mode (and ido or vertico) does, so you rarely delete a path one character at a time:

- Backspace on a trailing `/` goes up to the parent directory and selects the one you left (see [Go Up a Directory](#go-up-a-directory)). On `~/` it goes to the parent of your home directory; on `/` it deletes the slash.
- Typing `~/` right after a `/` starts over from your home directory, and a second `/` starts over from the root (see [Jump Home or to the Root](#jump-home-or-to-the-root)).

Set to `false` to edit the path as plain text: Backspace deletes one character and slashes stay as typed.


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

What Enter (or a click) does on a file. Enter on a directory always navigates into it. **Ctrl+O** always opens the selected file or directory with `xdg-open`, whatever this is set to. Accepted values:

- `open`: open the file with `xdg-open`
- `copy`: copy the full path to the clipboard
- `insert`: type the full path into the focused app (needs `wtype` or `ydotool`)
- any other string: run it as a shell command, with `{value}` replaced by the full path (also exported as `$RAFFI_VALUE`)


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

What Ctrl+Enter (or Ctrl+click) does on a file or directory. Takes the same values as `action`.

```yaml raffi.yaml
addons:
  file_browser:
    action: "code {value}"
    secondary_action: insert
```

**`file_manager`** `string` (default: autodetected)

Command used by **Ctrl+B** to open the current directory. The directory is appended as the last argument, or replaces `{value}` if present (it is also exported as `$RAFFI_VALUE`). When the value is just `nautilus`, `dolphin`, `nemo` or `caja` (or a path to one), raffi passes `--select` with the selected entry instead. When unset, raffi detects a file manager as described in [Open in File Manager](#open-in-file-manager).

```yaml raffi.yaml
addons:
  file_browser:
    file_manager: dolphin
    # or a terminal file manager:
    # file_manager: kitty yazi
```

**`preview_command`** `string` (default: the bundled previewer when `python3` is installed)

Command that previews the selected entry in the preview pane, replacing the plain preview when it prints something. `none` turns rich previews off. See [Rich Previews](#rich-previews) and [Writing your own previewer](#writing-your-own-previewer) for what it receives and may print. `~` and environment variables are expanded.

```yaml raffi.yaml
addons:
  file_browser:
    preview_command: "~/.config/raffi/scripts/file-preview.py"
```


### Disable File Browser

```yaml raffi.yaml
addons:
  file_browser:
    enabled: false
```

## Use Cases


  <details>
<summary>Quick File Access</summary>

    ```text
    ~/Downloads/
    # Type: latest
    # Find: latest-report.pdf
    # [Enter] to open
    ```
  </details>

  <details>
<summary>Copy File Paths</summary>

    ```text
    ~/Projects/myapp/src/
    # Navigate to: main.rs
    # [Ctrl+Enter] to copy path
    # Paste into terminal or IDE
    ```
  </details>

  <details>
<summary>Browse Config Files</summary>

    ```text
    ~/.config/
    # [Ctrl+H] to show hidden files
    # Navigate to: .bashrc, .vimrc, etc.
    # [Enter] to edit
    ```
  </details>

  <details>
<summary>Project Navigation</summary>

    ```text
    ~/Projects/
    # Filter: myapp
    # [Enter] to navigate
    # Filter: src
    # [Tab] to autocomplete
    ```
  </details>


## Visual Indicators

- **Directories** — Listed first in accent color
- **Files** — Listed after directories in normal text

## Requirements

<Aside type="caution">
The file browser requires `xdg-open` to open files (standard on most Linux distributions)
</Aside>

<Aside type="note">
Clipboard operations need `wl-copy` (wl-clipboard), `xclip` or `xsel`
</Aside>

## Examples

### Navigate to Documents

<Steps>
1. **Type Prefix**

   Type `~` to start browsing home directory

2. **Filter**

   Type `Doc` to filter for Documents

3. **Navigate**

   Press **Enter** on Documents folder

4. **Browse Files**

   See all files in ~/Documents/

</Steps>

### Open Configuration File

<Steps>
1. **Go to Config**

   Type `~/.config/`

2. **Show Hidden**

   Press **Ctrl+H** if needed

3. **Filter**

   Type filename to filter (e.g., `raf` for raffi)

4. **Open**

   Press **Enter** to open with default editor

</Steps>

### Copy Script Path

<Steps>
1. **Navigate**

   Type `~/bin/` or `/usr/local/bin/`

2. **Find Script**

   Filter by name (e.g., `my-script`)

3. **Copy Path**

   Press **Ctrl+Enter** to copy full path

4. **Use Path**

   Paste into terminal, config, or documentation

</Steps>

## Tips

<Aside type="tip">
Directories are always listed first and highlighted in the accent color, making it easy to distinguish them from files.
</Aside>

<Aside type="tip">
Use fuzzy filtering after the last `/` to quickly find files: `/home/user/doc` matches `/home/user/Documents/`
</Aside>

<Aside type="tip">
Toggle hidden files with **Ctrl+H** without leaving the file browser.
</Aside>

<Aside type="tip">
Drag files straight out of raffi into another application instead of copying their path first.
</Aside>