← Back to projects

fman-rs

A Rust and Slint rewrite of the fman dual-pane file manager for Windows, built to remove its performance limits.

fman-rs: two panes, folders first, sizes and modified dates

fman-rs with a 90,000-file folder on the left (status bar: 20 folders, 90000 files) and a small project folder sorted by size on the right. The files are generated demo files; the app is the real build.

Why rebuild it

fman is a Python/Qt app. I first patched its Python code, which cut a 90,000-file folder from 19.7 s to 5.6 s. The rest of its cost is structural: interpreter and Qt start-up, one plugin object per file, and the GUI thread doing the work. So I built a spike in Rust, measured it, set acceptance targets, and then wrote the real app.

Measurements: three versions, same machine

The original is the public fman 1.7.6, built unmodified. All three ran maximized on the same folder, timed from inside the apps. Median of 3 runs. The tinted cell is the best in its row.

Start-up: launch to rows on screen / idle memoryOriginal fmanMy patched fmanfman-rs
5,000 files1.75 s / 157 MB1.39 s / 156 MB0.06 s / 65 MB
90,000 files19.7 s / 438 MB5.6 s / 429 MB0.13 s / 94 MB
File operations, 1,000 small files, same driveOriginal fmanMy patched fmanfman-rs
Copy36.7 s2.5 s0.28 s
Move67.8 s2.7 s0.18 s
Delete (permanent)31.3 s0.6 s0.10 s

What this shows: against the original, fman-rs is about 150x faster to show a 90,000-file folder, uses a fifth of the memory, and does small-file copy, move and delete over 100x faster. My earlier Python patches already took the original from 36.7 s to 2.5 s on copy; the Rust rewrite adds a further 6–14x. Not measured: Recycle Bin delete, larger trees, the GPU renderer, other machines.

A measurement that changed the design

My first version handed every copy, move and delete to Windows Explorer's file engine. Benchmarking showed that was no faster than my patched Python version (and slower for delete), at 2–3 ms per file. I timed plain Windows file calls to find the floor, found moves must not be parallelised (8 threads was 60x slower than one), and wrote a fast path for the clean cases: nothing at the destination, under 256 MB, no links or read-only files. Anything else still goes to Explorer for its conflict dialog and progress window. I wrote 9 safety tests for it first, which caught one real issue in my first draft: it deleted read-only files outright, a case where I wasn't sure Explorer behaves the same, so those now stay with Explorer.

Method: one machine (4K display, SSD, warm cache). The timing hooks live in a plugin for fman and a built-in switch in fman-rs, and each answers its own confirmation prompts. fman-rs's start-up figure is the later of "data ready" and "window shown", so its first paint lands a frame or two after.

How it works

  • Directory listing runs on a worker thread and streams rows into the list. Stale results are dropped using a per-pane generation counter.
  • A ReadDirectoryChangesW watcher patches the list in place, debounced to 50 ms. It falls back to a full relist for large bursts.
  • Small, conflict-free copy, move and delete run in a purpose-built fast path. Name conflicts, large transfers, the Recycle Bin and any error go to Windows' own file engine, so its conflict dialog, progress window and permissions behave normally.

A bug I found by testing

A burst of 1,000+ file creations triggered a relist, and the watcher patches applied during it were overwritten by the older snapshot. 12 of 1,040 files were missing. The fix: patches now wait while a listing is in flight.

Honest limits

  • Windows only. Known gaps include rubber-band selection and edge auto-scroll while dragging.
  • Built with Claude Code from my written spec. I set the targets and checked the measurements.
  • The in-app permanent-delete prompt and Explorer fallback dialogs have not yet been checked by hand.