fast-fs
High-speed async file system traversal and navigation library for Rust.
Overview
fast-fs provides two main capabilities:
- Directory Reading Functions - Simple async functions for traversing directories
- Navigation Module (
nav) - A batteries-included file browser state machine for building file pickers, save dialogs, and project explorers
The library is framework-agnostic: you handle rendering and input capture, fast-fs manages all browser state, navigation logic, and file operations.
Features
- Async Directory Reading - Non-blocking traversal using tokio
- Streaming API - Memory-efficient traversal with backpressure support
- Gitignore Support - Built-in .gitignore and .ignore pattern matching
- Advanced Filtering - Depth limits, extensions, glob patterns, hidden files
- File Browser Component - Complete state machine with vim-style keybindings
- Multi-Selection - Range selection with Shift+Arrow, toggle with Space
- Clipboard Model - Cut/copy intent tracking with conflict detection
- Navigation History - Back/forward with H/L keys
- Parent Directory Entry - Optional ".." entry at top of file list
- File Categorization - Classify files as Code, Image, Video, Document, etc.
- UI Integration Helpers -
scroll_offset(),visible_range()for viewport management
Installation
[]
= "0.2"
= { = "1.48", = ["rt", "fs"] }
Quick Start
Directory Reading
use ;
async
File Browser (nav module)
use ;
async
API Reference
Directory Reading Functions
use ;
// Async single directory
let files = read_dir.await?;
// Non-hidden files only
let visible = read_dir_visible.await?;
// Recursive with options
let options = default.with_max_depth;
let all = read_dir_recursive.await?;
// Streaming (memory-efficient)
let stream = read_dir_stream;
TraversalOptions
use TraversalOptions;
let options = default
.with_gitignore // Respect .gitignore (default: true)
.with_max_depth // Limit recursion depth
.with_extensions // Filter by extension
.with_patterns // Custom ignore patterns
.include_hidden; // Include hidden files
Navigation Module
The nav module provides a complete file browser component:
| Type | Description |
|---|---|
Browser |
Core state machine (owns all browser state) |
BrowserConfig |
Configuration with presets |
KeyInput |
Framework-agnostic key events |
KeyMap |
Configurable key bindings |
Action |
User actions (move, select, delete, etc.) |
ActionResult |
Action outcomes |
Selection |
Multi-selection with range support |
ClipboardState |
Cut/copy intent tracking |
History |
Back/forward navigation |
FileCategory |
File type categorization |
Configuration Presets:
use BrowserConfig;
// Read-only file picker (shows ".." parent entry)
let config = open_dialog;
// Writable, no confirmations
let config = save_dialog;
// Full-featured explorer
let config = project_explorer;
// Customize: disable parent entry
let config = open_dialog
.with_show_parent_entry;
Default Key Bindings (vim-style):
| Key | Action |
|---|---|
j/k or arrows |
Move up/down |
Shift+Up/Down |
Range selection (extend) |
Enter/l |
Open/select |
h/Backspace |
Parent directory |
H/L |
History back/forward |
Space |
Toggle selection |
Ctrl+A |
Select all |
Ctrl+X |
Cut |
Ctrl+C |
Copy |
d |
Delete |
r |
Rename |
/ |
Filter |
. |
Toggle hidden |
s |
Cycle sort (includes extension) |
PageUp/PageDown |
Page navigation (caller handles) |
| Any letter | Typeahead jump (caller handles) |
Typeahead & Page Navigation:
// Page navigation (caller provides viewport height)
browser.page_up;
browser.page_down;
// Windows-style typeahead: press 'a' repeatedly to cycle through 'a' files
browser.jump_to_char;
// Substring search: jump to files containing "doc"
browser.jump_to_substring;
UI Integration Helpers:
The browser provides state accessors for building your render loop:
// Get viewport boundaries for rendering
let start = browser.scroll_offset;
let range = browser.visible_range;
// Render only visible files
for i in range
// Check if parent ".." entry is shown
if browser.has_parent_entry
Clipboard Model:
The library tracks cut/copy intent; the caller handles actual clipboard and paste operations:
use ;
// Store clipboard state when user cuts/copies
let mut app_clipboard: = None;
match browser.handle_key.await
// Later, check for conflicts before pasting
if let Some = app_clipboard
Custom Key Bindings:
use ;
// Start with defaults and customize
let mut keymap = default;
keymap.unbind; // Free for terminal interrupt
keymap.bind; // Use 'y' instead
let config = default.with_keymap;
FileEntry
// Lazy methods (syscalls on demand)
entry.is_executable // Check execute permission
entry.resolve_symlink // Get symlink target
entry.is_symlink_broken // Check if target exists
entry.category // Get FileCategory
FileCategory
use FileCategory;
// Categorize by extension
let cat = from_extension; // Code
let cat = from_extension; // Image
// From FileEntry (checks symlink, dir, executable first)
let cat = entry.category;
Categories: Directory, Text, Code, Image, Video, Audio, Archive, Document, Executable, Symlink, Unknown
FileList
Versioned file list with deferred sorting:
let mut list = new;
list.push_batch;
list.set_sort; // Deferred
list.set_show_hidden; // Deferred
list.catchup; // Sort happens here
SortBy
| Variant | Description |
|---|---|
Name / NameDesc |
Alphabetical |
Size / SizeDesc |
By file size |
Modified / ModifiedDesc |
By modification time |
Extension |
By file extension |
DirsFirst |
Directories before files |
GitignoreMatcher
use GitignoreMatcher;
let matcher = from_path?;
if matcher.is_ignored
// Add patterns at runtime
matcher.add_pattern?;
Thread Safety
Browser is Send but not Sync. For shared access:
use ;
let browser = new;
Documentation
- API Documentation - Complete API reference on docs.rs
- Quick Start Guide - Get started in 5 minutes
- Navigation API Reference - Detailed nav module reference
Testing
199 tests total: 76 unit tests + 113 integration tests + 10 doc tests covering directory reading, filtering, navigation, selection, clipboard, and file operations.
License
MIT
Author
Made with care in Madeira, Portugal
GitHub: 5ocworkshop
Note on source file versions: This crate uses OFPF (One Function Per File) methodology. Version numbers in source file headers (e.g.,
VERSION: 0.5.0) track individual file edit history, not the crate release version. The crate release version is defined inCargo.toml.