Two-panel GNU C23 file manager with two build profiles.
| Profile | Display | Memory and features |
|---|---|---|
embedded |
Fixed 80x30 DOS framebuffer | 32 KiB contract, fixed panel stores, streaming viewer, no editor, optional ZIP, no shell by default |
desktop |
Full terminal window | Dynamic panels and screen grids, 4 KiB paths, streaming viewer, in-memory editor, ZIP and shell on by default |
The embedded framebuffer is 4,800 bytes (CP437 byte plus color byte) and is outside the 32 KiB contract.
- Two panels, FAR-like double frames and status footer
- Navigation and FAR Default Highlighting by type
- ZIP folders and host shell support (off by default in embedded, on in desktop)
- F3 streaming viewer (any size; wrap with F2). Keeps a small window over the open file, not the whole file in RAM
- F4 line editor, desktop only. It reads the whole file into RAM, so it does not fit the embedded RAM contract. Changes stay in memory until F2 saves them through a temp file, which needs free disk for a second copy of the file
- FAR-like text search in the viewer and editor: F7 finds without case matching, Shift+F7 finds the next match
- Stateful F4 syntax color for C/C++, Python, shell, JSON, HTML/XML, and INI, with small generic code rules for other text files. It scans each physical line as it is drawn and keeps 16 recent line states without a full-file color map
- F5 copy / F6 move between panels, Shift+F6 rename, F7 make folder, F8 delete
- Folders are copied and moved whole, one file at a time
- Mark entries with
Insert; mark all with grey+, clear with grey-(desktop) - Copy, move, and delete act on all marked files when any are marked (desktop)
- Overwrite dialog (
Yyes,Nno,Aall) when a destination already exists - Fast Find (
Alt+char), panel sort (Ctrl+F3…F7) - Alt+F1 / Alt+F2 change drive (Windows), hidden-file toggle (
Hembedded,Alt+Hdesktop), Ctrl+R refresh, Ctrl+O user screen
- Total RAM is 32,768 bytes: 26,560-byte dynamic app block + 6,144-byte stack reserve + 64-byte allocator reserve.
- App state and scratch share the one dynamic block. A compile-time check keeps at least 9,600 scratch bytes free.
tinyfm_run()gets allocator callbacks and the external framebuffer. Shutdown uses one cleanup path and returns the full app block.- Each embedded panel has at most 64 entries and a 2 KiB name store. Embedded paths have a 192-byte limit. Longer listings show
Listing truncated. - Folder copy, move, and delete walk the tree one file at a time, reusing one path buffer per side. A level costs about 240 stack bytes and the walk stops at 12 levels, so its stack use stays bounded. The 256-byte copy buffer sits in a leaf that is kept out of line, so it is paid once whatever the depth.
- Folder-size scans are not present because their stack use is not bounded.
The 64-byte allocator reserve is a platform contract. Set TINYFM_ALLOCATOR_OVERHEAD_BYTES to the real target allocator cost. Stack reports are made with -fstack-usage; check them with the target compiler.
Desktop mode is not under the 32 KiB contract. Its panels, viewer, current screen, prior screen, and native output grid use dynamic memory. They are all released at shutdown.
Include src/tinyfm.h, provide TinyfmAllocator, and pass a writable TINYFM_FRAMEBUFFER_BYTES buffer to tinyfm_run(). The call returns after the manager closes and releases its app block. The framebuffer remains owned by the host.
The present terminal and filesystem backends are for Windows and Linux. An RP2040 build still needs target input, display-present, and filesystem adapters; these APIs depend on the selected SDK and filesystem library.
Needs CMake ≥ 3.20, Ninja (or Make), and either:
- CLion / MinGW GCC — open the project and build (host compiler), or
- Zig on
PATH— usecmake/zig.cmake(see below /CMakePresets.json)
Use the default MinGW toolchain profile (cmake-build-minsizerel) for desktop mode. Set TINYFM_PROFILE=embedded when the 32 KiB build is needed. No Zig is required.
For Zig profiles: Settings → Build → CMake and enable preset zig-windows or zig-linux (from CMakePresets.json). Zig must be on PATH.
cmake -S . -B build/desktop-minsizerel -G Ninja -DCMAKE_BUILD_TYPE=MinSizeRel
cmake --build build/desktop-minsizerelBuild the embedded profile explicitly:
cmake -S . -B build/embedded-minsizerel -G Ninja `
-DCMAKE_BUILD_TYPE=MinSizeRel -DTINYFM_PROFILE=embedded
cmake --build build/embedded-minsizerelBuild the desktop Zig preset:
cmake --preset desktop-windows
cmake --build --preset desktop-windowsBuild the embedded Windows host check with zig-windows. ZIP and shell may still be changed with TINYFM_ZIP_SUPPORT and TINYFM_SHELL_SUPPORT; their defaults are off for embedded and on for desktop.
ZIP uses a small random-read interface; the parser does not open files itself. Embedded ZIP data is bounded by the scratch arena and omits dates. Desktop ZIP lists and names are dynamic and keep dates. Shell processes are outside the embedded RAM contract.
For the lifecycle and ZIP checks:
cmake -S . -B build/tests -G Ninja -DTINYFM_BUILD_TESTS=ON -DTINYFM_ZIP_SUPPORT=ON
cmake --build build/tests
ctest --test-dir build/tests --output-on-failurecmake -S . -B build/x86_64-windows-gnu-minsizerel -G Ninja `
--toolchain cmake/zig.cmake `
-DTINYFM_ZIG_TARGET=x86_64-windows-gnu `
-DCMAKE_BUILD_TYPE=MinSizeRel
cmake --build build/x86_64-windows-gnu-minsizerelCross-compile a Linux ELF from Windows:
cmake -S . -B build/x86_64-linux-gnu-minsizerel -G Ninja `
--toolchain cmake/zig.cmake `
-DTINYFM_ZIG_TARGET=x86_64-linux-gnu `
-DCMAKE_BUILD_TYPE=MinSizeRel
cmake --build build/x86_64-linux-gnu-minsizerelchmod +x cmake/zig-cc cmake/zig-ar cmake/zig-ranlib
cmake -S . -B build/x86_64-linux-gnu-minsizerel -G Ninja \
--toolchain cmake/zig.cmake \
-DTINYFM_ZIG_TARGET=x86_64-linux-gnu \
-DCMAKE_BUILD_TYPE=MinSizeRel
cmake --build build/x86_64-linux-gnu-minsizerelEvery push to master starts a GCC desktop build for Linux x86_64 and Windows x86_64. After both builds pass, GitHub Actions makes a build-<run-number> release with tinyfm-linux-x86_64.tar.gz and tinyfm-windows-x86_64.zip. The Linux file is statically linked with musl and does not need glibc.
Without Ninja, use -G "Unix Makefiles" and omit CMAKE_MAKE_PROGRAM.
./build/desktop-minsizerel/tinyfm [left-directory] [right-directory]
# Windows: build\desktop-minsizerel\tinyfm.exe| Key | Action |
|---|---|
| Arrows / Home / End / PgUp / PgDn | Move selection |
| Tab | Switch panel |
| Enter | Open folder; enter ZIP or launch file when enabled |
| Text + Enter | Desktop: run a shell command in the active folder |
| Backspace | Parent directory |
| Esc | Close a dialog |
| F3 | View file (any size; streams from disk) |
| F4 | Desktop: edit file. Also switches the open viewer into the editor |
| F2 | Viewer: wrap on/off; Editor: save the file |
| F7 / Shift+F7 | Viewer and editor: search / find next; search wraps at the file end |
| Del | Panel: delete, same as F8. Editor: delete the character under the cursor |
| Ins | Editor: switch between Ins and Ovr |
| Ctrl+Home / Ctrl+End | Start / end of the file in the viewer and editor |
| F5 / F6 | Copy / move to the other panel (desktop can edit the target) |
| Shift+F6 | Rename the entry in place |
| Insert | Desktop: mark / unmark the entry, then step down |
grey + / grey - |
Desktop: mark / unmark all entries |
| F7 / F8 | Panel: make folder / delete |
| F10 / Q / Ctrl+C | Quit |
| Ctrl+F3…F7 | Sort (name, ext, time, size, unsorted) |
| Ctrl+F8 / Ctrl+F9 | Desktop: sort by creation / access time |
| Alt+char | Fast Find (Alt+H is the desktop hidden-file key) |
| Alt+F1 / Alt+F2 | Change drive (left / right panel) |
| Ctrl+R | Refresh |
| Ctrl+O | User screen |
| H / Alt+H | Toggle hidden files in embedded / desktop profile |