Skip to main content

Crate tui_file_explorer

Crate tui_file_explorer 

Source
Expand description

§tui-file-explorer

A self-contained, keyboard-driven file-browser widget for Ratatui.

§Design goals

  • Zero application-specific dependencies — only ratatui, crossterm, and the standard library are required.
  • Narrow public surface — the public API is intentionally small so the crate can evolve without breaking changes.
  • Extension filtering — pass a list of allowed extensions so that only relevant files are selectable (e.g. ["iso", "img"]); directories are always navigable.
  • Keyboard-driven/// scroll the list, Enter / l to descend or confirm, Backspace / h to ascend, / to search, s to cycle sort, n to create a new folder, N to create a new file, Esc / q to dismiss.
  • Searchable — press / to enter incremental search; entries are filtered live as you type. Esc clears the query; a second Esc dismisses the explorer.
  • Sortable — press s to cycle through Name, Size ↓, and Extension sort modes, or set one programmatically via FileExplorer::set_sort_mode.
  • Themeable — every colour is overridable via Theme and render_themed.
  • Dual-paneDualPane owns two independent FileExplorers, manages focus switching (Tab), and supports a single-pane toggle (w).

§Quick start

use tui_file_explorer::{FileExplorer, ExplorerOutcome, SortMode, render};
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};

// 1. Create once (e.g. in your App::new).
let mut explorer = FileExplorer::builder(std::env::current_dir().unwrap())
    .allow_extension("iso")
    .allow_extension("img")
    .sort_mode(SortMode::SizeDesc)
    .build();

// 2. In your Terminal::draw closure:
//    render(&mut explorer, frame, frame.area());

// 3. In your key-handler:
match explorer.handle_key(key) {
    ExplorerOutcome::Selected(path) => println!("chosen: {}", path.display()),
    ExplorerOutcome::Dismissed      => { /* close the overlay */ }
    _                               => {}
}

§Builder / configuration

Use FileExplorer::builder for a more ergonomic construction API:

use tui_file_explorer::{FileExplorer, SortMode};

let explorer = FileExplorer::builder(std::env::current_dir().unwrap())
    .allow_extension("rs")
    .allow_extension("toml")
    .show_hidden(true)
    .sort_mode(SortMode::Extension)
    .build();

Press / to activate search mode. Subsequent keystrokes append to the query and the entry list is filtered live (case-insensitive substring match on the file name). Backspace removes the last character; an extra Backspace on an empty query deactivates search. Esc clears the query and deactivates search without dismissing the explorer; a second Esc (when search is already inactive) dismisses it.

Search state is also accessible programmatically:

use tui_file_explorer::FileExplorer;

let explorer = FileExplorer::new(std::env::current_dir().unwrap(), vec![]);
println!("searching: {}", explorer.is_searching());
println!("query    : {}", explorer.search_query());

§Sort modes

Press s to cycle through the three sort modes, or set one directly:

use tui_file_explorer::{FileExplorer, SortMode};

let mut explorer = FileExplorer::new(std::env::current_dir().unwrap(), vec![]);
explorer.set_sort_mode(SortMode::SizeDesc); // largest files first

println!("{}", explorer.sort_mode().label()); // "size ↓"

§Theming

Every colour is customisable via Theme and render_themed:

use tui_file_explorer::{FileExplorer, Theme, render_themed};
use ratatui::style::Color;

let theme = Theme::default()
    .brand(Color::Magenta)
    .accent(Color::Cyan)
    .dir(Color::LightYellow);

// terminal.draw(|frame| {
//     render_themed(&mut explorer, frame, frame.area(), &theme);
// });

§Named presets

Twenty well-known editor / terminal colour schemes are available as associated constructors on Theme, mirroring the catalogue found in Iced:

use tui_file_explorer::Theme;

let t = Theme::dracula();
let t = Theme::nord();
let t = Theme::catppuccin_mocha();
let t = Theme::tokyo_night();
let t = Theme::gruvbox_dark();
let t = Theme::kanagawa_wave();
let t = Theme::oxocarbon();

// Iterate the full catalogue (name, description, theme):
for (name, desc, _theme) in Theme::all_presets() {
    println!("{name} — {desc}");
}

The complete list: Default, Dracula, Nord, Solarized Dark, Solarized Light, Gruvbox Dark, Gruvbox Light, Catppuccin Latte, Catppuccin Frappé, Catppuccin Macchiato, Catppuccin Mocha, Tokyo Night, Tokyo Night Storm, Tokyo Night Light, Kanagawa Wave, Kanagawa Dragon, Kanagawa Lotus, Moonfly, Nightfly, Oxocarbon.

§Key bindings reference

KeyAction
/ kMove cursor up
/ jMove cursor down
PgUp / PgDnJump 10 entries
Home / gJump to top
End / GJump to bottom
/ l / EnterDescend into directory; on a file moves cursor down, l/Enter confirm
/ h / BackspaceAscend to parent directory
SpaceToggle space-mark on current entry and advance cursor
/Activate incremental search
sCycle sort mode (NameSize ↓Extension)
.Toggle hidden (dot-file) entries
nCreate a new folder (type name → Enter confirm, Esc cancel)
NCreate a new file (type name → Enter confirm, Esc cancel)
rRename current entry (pre-filled with current name → Enter confirm, Esc cancel)
EscClear search / cancel mkdir / cancel touch / cancel rename (if active), then dismiss
qDismiss (when search / mkdir / touch / rename is not active)

§Dual-pane quick start

use tui_file_explorer::{DualPane, DualPaneOutcome, render_dual_pane_themed, Theme};
use crossterm::event::{Event, KeyCode, KeyModifiers, self};

// 1. Create once — left pane defaults to cwd; right pane mirrors it.
let mut dual = DualPane::builder(std::env::current_dir().unwrap())
    .right_dir(std::path::PathBuf::from("/tmp"))
    .build();

let theme = Theme::default();

// 2. In your Terminal::draw closure:
// terminal.draw(|frame| {
//     render_dual_pane_themed(&mut dual, frame, frame.area(), &theme);
// }).unwrap();

// 3. In your event loop:
match dual.handle_key(key) {
    DualPaneOutcome::Selected(path) => println!("chosen: {}", path.display()),
    DualPaneOutcome::Dismissed      => { /* close the overlay */ }
    _                               => {}
}

§Extra key bindings provided by DualPane

KeyAction
TabSwitch focus between left and right pane
wToggle single-pane / dual-pane mode
SpaceMark current entry (forwarded to active pane)

All standard FileExplorer bindings continue to work on whichever pane is currently active.

§Folder and file creation

§New folder — n

Press n to enter mkdir mode. Type the new folder name, then press Enter to create it (using fs::create_dir_all, so nested paths like a/b/c work) or Esc to cancel without creating anything. On success ExplorerOutcome::MkdirCreated is returned and the cursor moves to the new directory.

§New file — N

Press N (Shift+N) to enter touch mode. Type the new file name (including extension), then press Enter to create it or Esc to cancel. Parent directories are created automatically when the name contains /. An existing file at the target path is left untouched (no truncation). On success ExplorerOutcome::TouchCreated is returned and the cursor moves to the new file.

Both modes are also accessible programmatically:

use tui_file_explorer::FileExplorer;

let explorer = FileExplorer::new(std::env::current_dir().unwrap(), vec![]);
println!("mkdir active : {}", explorer.is_mkdir_active());
println!("mkdir input  : {}", explorer.mkdir_input());
println!("touch active : {}", explorer.is_touch_active());
println!("touch input  : {}", explorer.touch_input());

§Module layout

ModuleContents
typesFsEntry, ExplorerOutcome, SortMode
palettePalette constants (all pub) + Theme builder + 27 named presets
explorerFileExplorer, FileExplorerBuilder, entry_icon, fmt_size, load_entries
dual_paneDualPane, DualPaneBuilder, DualPaneActive, DualPaneOutcome
render[render], render_themed, render_dual_pane, render_dual_pane_themed — pure rendering, no I/O

Re-exports§

pub use dual_pane::DualPane;
pub use dual_pane::DualPaneActive;
pub use dual_pane::DualPaneBuilder;
pub use dual_pane::DualPaneOutcome;
pub use explorer::entry_icon;
pub use explorer::fmt_size;
pub use explorer::FileExplorer;
pub use explorer::FileExplorerBuilder;
pub use palette::Theme;
pub use render::render;
pub use render::render_dual_pane;
pub use render::render_dual_pane_themed;
pub use render::render_themed;
pub use types::ExplorerOutcome;
pub use types::FsEntry;
pub use types::SortMode;
pub use app::App;
pub use app::AppOptions;
pub use app::ClipOp;
pub use app::ClipboardItem;
pub use app::CopyProgress;
pub use app::Editor;
pub use app::Modal;
pub use app::Pane;
pub use app::Snackbar;
pub use fs::copy_dir_all;
pub use fs::resolve_output_path;
pub use persistence::load_state;
pub use persistence::resolve_theme_idx;
pub use persistence::save_state;
pub use persistence::AppState;
pub use ui::draw;
pub use ui::render_action_bar;
pub use ui::render_copy_progress;
pub use ui::render_editor_panel;
pub use ui::render_modal;
pub use ui::render_nav_hints;
pub use ui::render_options_panel;
pub use ui::render_snackbar;
pub use ui::render_theme_panel;

Modules§

app
Application state for the tfe binary.
dual_pane
Dual-pane file-explorer widget.
explorer
FileExplorer state machine, FileExplorerBuilder, and filesystem helpers.
fs
Filesystem helpers for the tfe binary.
palette
Default colour palette used by the file-explorer widget.
persistence
Persist application state between sessions.
render
Ratatui rendering functions for the file-explorer widget.
types
Public data types exposed by the tui-file-explorer crate.
ui
Terminal UI drawing functions for the tfe binary.