FileExplorer

Struct FileExplorer 

Source
pub struct FileExplorer { /* private fields */ }
Expand description

A file explorer that allows browsing and selecting files and directories.

The FileExplorer struct represents a file explorer widget that can be used to navigate through the file system. You can obtain a renderable widget from it with the widget method. It provides methods for handling user input from crossterm, termion and termwiz (depending on what feature is enabled).

§Examples

Creating a new FileExplorer widget:

use fpicker::FileExplorer;

let file_explorer = FileExplorer::new().unwrap();
let widget = file_explorer.widget();

Handling user input:

use fpicker::FileExplorer;

let mut file_explorer = FileExplorer::new().unwrap();
let event = get_event(); // Get the event from the terminal (with crossterm, termion or termwiz)
file_explorer.handle(event).unwrap();

Accessing information about the current file selected and or the current working directory:

use fpicker::FileExplorer;

let file_explorer = FileExplorer::new().unwrap();

let current_file = file_explorer.current();
let current_working_directory = file_explorer.cwd();
println!("Current Directory: {}", current_working_directory.display());
println!("Name: {}", current_file.name());

Implementations§

Source§

impl FileExplorer

Source

pub fn new() -> Result<FileExplorer>

Creates a new instance of FileExplorer.

This method initializes a FileExplorer with the current working directory.

§Examples

Suppose you have this tree file and your current working directory is /Documents:

/
├── .git
└── Documents  <- current working directory
    ├── passport.png
    └── resume.pdf

You can create a new FileExplorer like this:

use fpicker::FileExplorer;

let file_explorer = FileExplorer::new().unwrap();
assert_eq!(file_explorer.cwd().display().to_string(), "/Documents");
Source

pub fn with_theme(theme: Theme) -> Result<FileExplorer>

Creates a new instance of FileExplorer with a specific theme.

This method initializes a FileExplorer with the current working directory.

§Examples
use fpicker::{FileExplorer, Theme};

let file_explorer = FileExplorer::with_theme(Theme::default().add_default_title()).unwrap();
Examples found in repository?
examples/basic.rs (line 19)
11fn main() -> io::Result<()> {
12    enable_raw_mode()?;
13    stdout().execute(EnterAlternateScreen)?;
14
15    let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?;
16
17    // Create a new file explorer with the default theme and title.
18    let theme = Theme::default().add_default_title();
19    let mut file_explorer = FileExplorer::with_theme(theme)?;
20
21    let mut selected_paths = vec![];
22
23    loop {
24        // Render the file explorer widget.
25        terminal.draw(|f| {
26            f.render_widget(&file_explorer.widget(), f.area());
27        })?;
28
29        // Read the next event from the terminal.
30        let event = read()?;
31        if let Event::Key(key) = event {
32            if key.code == KeyCode::Char('q') {
33                // Collect selected file paths.
34                selected_paths = file_explorer
35                    .selected_files()
36                    .iter()
37                    .map(|file| file.path().display().to_string())
38                    .collect();
39                break;
40            }
41        }
42        // Handle the event in the file explorer.
43        file_explorer.handle(&event)?;
44    }
45
46    // Restore the terminal to normal mode.
47    disable_raw_mode()?;
48    stdout().execute(LeaveAlternateScreen)?;
49
50    // Print the selected file paths to stdout.
51    for path in selected_paths {
52        println!("{}", path);
53    }
54
55    // Return exit code 0 explicitly.
56    process::exit(0);
57}
More examples
Hide additional examples
examples/light_and_dark_theme.rs (line 23)
15fn main() -> io::Result<()> {
16    enable_raw_mode()?;
17    stdout().execute(EnterAlternateScreen)?;
18
19    let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?;
20
21    // Create a new file explorer with the light theme.
22    let mut dark_theme = false;
23    let mut file_explorer = FileExplorer::with_theme(get_light_theme())?;
24
25    loop {
26        // Render the file explorer widget.
27        terminal.draw(|f| {
28            f.render_widget(&file_explorer.widget(), f.area());
29        })?;
30
31        // Read the next event from the terminal.
32        let event = read()?;
33        // If the user presses `Ctrl + s`, switch the theme.
34        // If the user presses `Ctrl + q`, quit the application.
35        if let Event::Key(key) = event {
36            if key.modifiers == crossterm::event::KeyModifiers::CONTROL {
37                match key.code {
38                    KeyCode::Char('s') => {
39                        dark_theme = !dark_theme;
40                        if dark_theme {
41                            file_explorer.set_theme(get_dark_theme());
42                        } else {
43                            file_explorer.set_theme(get_light_theme());
44                        }
45                    }
46                    KeyCode::Char('q') => {
47                        break;
48                    }
49                    _ => {}
50                }
51            }
52        }
53        // Handle the event in the file explorer.
54        file_explorer.handle(&event)?;
55    }
56
57    disable_raw_mode()?;
58    stdout().execute(LeaveAlternateScreen)?;
59    Ok(())
60}
examples/file_preview.rs (line 32)
17fn main() -> io::Result<()> {
18    enable_raw_mode()?;
19    stdout().execute(EnterAlternateScreen)?;
20
21    let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?;
22    let layout = Layout::vertical([
23        Constraint::Ratio(4, 5), // Main file explorer and content area
24        Constraint::Ratio(1, 5), // Bottom window for selected file paths
25    ]);
26
27    // Inner layout for the top section
28    let top_layout = Layout::horizontal([Constraint::Ratio(1, 3), Constraint::Ratio(2, 3)]);
29
30    // Create a new file explorer with the default theme and title.
31    let theme = get_theme();
32    let mut file_explorer = FileExplorer::with_theme(theme)?;
33
34    loop {
35        // Get the content of the current selected file (if it's indeed a file).
36        let file_content = get_file_content(file_explorer.current().path())?;
37        let selected_files: String = file_explorer
38            .selected_files()
39            .iter()
40            .map(|file| file.path().display().to_string())
41            .collect::<Vec<String>>()
42            .join("\n");
43
44        // Render the file explorer widget, file content, and selected file paths.
45        terminal.draw(|f| {
46            let chunks = layout.split(f.area());
47            let top_chunks = top_layout.split(chunks[0]);
48
49            // Top section
50            f.render_widget(&file_explorer.widget(), top_chunks[0]);
51            f.render_widget(
52                Paragraph::new(file_content).block(
53                    Block::default()
54                        .borders(Borders::ALL)
55                        .border_type(BorderType::Double),
56                ),
57                top_chunks[1],
58            );
59
60            // Bottom section
61            f.render_widget(
62                Paragraph::new(selected_files.clone()).block(
63                    Block::default()
64                        .borders(Borders::ALL)
65                        .title("q:Quit, c: copy selected file contents to clipboard, p: copy paths to clipboard"),
66                ),
67                chunks[1],
68            );
69        })?;
70
71        // Read the next event from the terminal.
72        let event = read()?;
73        if let Event::Key(key) = event {
74            match key.code {
75                KeyCode::Char('q') => break, // Quit the application
76                KeyCode::Char('c') => {
77                    // Copy selected file paths to clipboard
78                    if let Ok(mut clipboard) = ClipboardContext::new() {
79                        if let Err(err) = clipboard.set_contents(get_selected_files_content(
80                            &file_explorer.selected_files(),
81                        )) {
82                            eprintln!("Failed to copy to clipboard: {}", err);
83                        }
84                    } else {
85                        eprintln!("Clipboard not available.");
86                    }
87                }
88                KeyCode::Char('p') => {
89                    // Copy selected file paths to clipboard
90                    if let Ok(mut clipboard) = ClipboardContext::new() {
91                        if let Err(err) = clipboard.set_contents(selected_files.clone()) {
92                            eprintln!("Failed to copy to clipboard: {}", err);
93                        }
94                    } else {
95                        eprintln!("Clipboard not available.");
96                    }
97                }
98                _ => {}
99            }
100        }
101        // Handle the event in the file explorer.
102        file_explorer.handle(&event)?;
103    }
104
105    disable_raw_mode()?;
106    stdout().execute(LeaveAlternateScreen)?;
107    // Print the selected file paths to stdout.
108    for file in file_explorer.selected_files() {
109        println!("{}", file.path().display());
110    }
111    Ok(())
112}
Source

pub const fn widget(&self) -> impl WidgetRef + '_

Build a ratatui widget to render the file explorer. The widget can then be rendered with Frame::render_widget.

§Examples
use ratatui::{Terminal, backend::CrosstermBackend};
use fpicker::FileExplorer;

let mut file_explorer = FileExplorer::new().unwrap();

let mut terminal = Terminal::new(CrosstermBackend::new(std::io::stdout())).unwrap();

loop {
    terminal.draw(|f| {
        let widget = file_explorer.widget(); // Get the widget to render the file explorer
        f.render_widget(&widget, f.area());
    }).unwrap();

    // ...
}
Examples found in repository?
examples/basic.rs (line 26)
11fn main() -> io::Result<()> {
12    enable_raw_mode()?;
13    stdout().execute(EnterAlternateScreen)?;
14
15    let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?;
16
17    // Create a new file explorer with the default theme and title.
18    let theme = Theme::default().add_default_title();
19    let mut file_explorer = FileExplorer::with_theme(theme)?;
20
21    let mut selected_paths = vec![];
22
23    loop {
24        // Render the file explorer widget.
25        terminal.draw(|f| {
26            f.render_widget(&file_explorer.widget(), f.area());
27        })?;
28
29        // Read the next event from the terminal.
30        let event = read()?;
31        if let Event::Key(key) = event {
32            if key.code == KeyCode::Char('q') {
33                // Collect selected file paths.
34                selected_paths = file_explorer
35                    .selected_files()
36                    .iter()
37                    .map(|file| file.path().display().to_string())
38                    .collect();
39                break;
40            }
41        }
42        // Handle the event in the file explorer.
43        file_explorer.handle(&event)?;
44    }
45
46    // Restore the terminal to normal mode.
47    disable_raw_mode()?;
48    stdout().execute(LeaveAlternateScreen)?;
49
50    // Print the selected file paths to stdout.
51    for path in selected_paths {
52        println!("{}", path);
53    }
54
55    // Return exit code 0 explicitly.
56    process::exit(0);
57}
More examples
Hide additional examples
examples/light_and_dark_theme.rs (line 28)
15fn main() -> io::Result<()> {
16    enable_raw_mode()?;
17    stdout().execute(EnterAlternateScreen)?;
18
19    let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?;
20
21    // Create a new file explorer with the light theme.
22    let mut dark_theme = false;
23    let mut file_explorer = FileExplorer::with_theme(get_light_theme())?;
24
25    loop {
26        // Render the file explorer widget.
27        terminal.draw(|f| {
28            f.render_widget(&file_explorer.widget(), f.area());
29        })?;
30
31        // Read the next event from the terminal.
32        let event = read()?;
33        // If the user presses `Ctrl + s`, switch the theme.
34        // If the user presses `Ctrl + q`, quit the application.
35        if let Event::Key(key) = event {
36            if key.modifiers == crossterm::event::KeyModifiers::CONTROL {
37                match key.code {
38                    KeyCode::Char('s') => {
39                        dark_theme = !dark_theme;
40                        if dark_theme {
41                            file_explorer.set_theme(get_dark_theme());
42                        } else {
43                            file_explorer.set_theme(get_light_theme());
44                        }
45                    }
46                    KeyCode::Char('q') => {
47                        break;
48                    }
49                    _ => {}
50                }
51            }
52        }
53        // Handle the event in the file explorer.
54        file_explorer.handle(&event)?;
55    }
56
57    disable_raw_mode()?;
58    stdout().execute(LeaveAlternateScreen)?;
59    Ok(())
60}
examples/file_preview.rs (line 50)
17fn main() -> io::Result<()> {
18    enable_raw_mode()?;
19    stdout().execute(EnterAlternateScreen)?;
20
21    let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?;
22    let layout = Layout::vertical([
23        Constraint::Ratio(4, 5), // Main file explorer and content area
24        Constraint::Ratio(1, 5), // Bottom window for selected file paths
25    ]);
26
27    // Inner layout for the top section
28    let top_layout = Layout::horizontal([Constraint::Ratio(1, 3), Constraint::Ratio(2, 3)]);
29
30    // Create a new file explorer with the default theme and title.
31    let theme = get_theme();
32    let mut file_explorer = FileExplorer::with_theme(theme)?;
33
34    loop {
35        // Get the content of the current selected file (if it's indeed a file).
36        let file_content = get_file_content(file_explorer.current().path())?;
37        let selected_files: String = file_explorer
38            .selected_files()
39            .iter()
40            .map(|file| file.path().display().to_string())
41            .collect::<Vec<String>>()
42            .join("\n");
43
44        // Render the file explorer widget, file content, and selected file paths.
45        terminal.draw(|f| {
46            let chunks = layout.split(f.area());
47            let top_chunks = top_layout.split(chunks[0]);
48
49            // Top section
50            f.render_widget(&file_explorer.widget(), top_chunks[0]);
51            f.render_widget(
52                Paragraph::new(file_content).block(
53                    Block::default()
54                        .borders(Borders::ALL)
55                        .border_type(BorderType::Double),
56                ),
57                top_chunks[1],
58            );
59
60            // Bottom section
61            f.render_widget(
62                Paragraph::new(selected_files.clone()).block(
63                    Block::default()
64                        .borders(Borders::ALL)
65                        .title("q:Quit, c: copy selected file contents to clipboard, p: copy paths to clipboard"),
66                ),
67                chunks[1],
68            );
69        })?;
70
71        // Read the next event from the terminal.
72        let event = read()?;
73        if let Event::Key(key) = event {
74            match key.code {
75                KeyCode::Char('q') => break, // Quit the application
76                KeyCode::Char('c') => {
77                    // Copy selected file paths to clipboard
78                    if let Ok(mut clipboard) = ClipboardContext::new() {
79                        if let Err(err) = clipboard.set_contents(get_selected_files_content(
80                            &file_explorer.selected_files(),
81                        )) {
82                            eprintln!("Failed to copy to clipboard: {}", err);
83                        }
84                    } else {
85                        eprintln!("Clipboard not available.");
86                    }
87                }
88                KeyCode::Char('p') => {
89                    // Copy selected file paths to clipboard
90                    if let Ok(mut clipboard) = ClipboardContext::new() {
91                        if let Err(err) = clipboard.set_contents(selected_files.clone()) {
92                            eprintln!("Failed to copy to clipboard: {}", err);
93                        }
94                    } else {
95                        eprintln!("Clipboard not available.");
96                    }
97                }
98                _ => {}
99            }
100        }
101        // Handle the event in the file explorer.
102        file_explorer.handle(&event)?;
103    }
104
105    disable_raw_mode()?;
106    stdout().execute(LeaveAlternateScreen)?;
107    // Print the selected file paths to stdout.
108    for file in file_explorer.selected_files() {
109        println!("{}", file.path().display());
110    }
111    Ok(())
112}
Source

pub fn handle<I: Into<Input>>(&mut self, input: I) -> Result<()>

Handles input from user and updates the state of the file explorer. The different inputs are interpreted as follows:

  • Up: Move the selection up.
  • Down: Move the selection down.
  • Left: Move to the parent directory.
  • Right: Move to the selected directory.
  • None: Do nothing.

Input implement From<Event> for Event of crossterm, termion and termwiz (InputEvent in this case).

§Examples

Suppose you have this tree file, with passport.png selected inside file_explorer:

/
├── .git
└── Documents
    ├── passport.png  <- selected
    └── resume.pdf

You can handle input like this:

use fpicker::{FileExplorer, Input};

let mut file_explorer = FileExplorer::new().unwrap();

/* user select `password.png` */

file_explorer.handle(Input::Down).unwrap();
assert_eq!(file_explorer.current().name(), "resume.pdf");

file_explorer.handle(Input::Up).unwrap();
file_explorer.handle(Input::Up).unwrap();
assert_eq!(file_explorer.current().name(), "Documents");

file_explorer.handle(Input::Left).unwrap();
assert_eq!(file_explorer.cwd().display().to_string(), "/");

file_explorer.handle(Input::Right).unwrap();
assert_eq!(file_explorer.cwd().display().to_string(), "/Documents");
Examples found in repository?
examples/basic.rs (line 43)
11fn main() -> io::Result<()> {
12    enable_raw_mode()?;
13    stdout().execute(EnterAlternateScreen)?;
14
15    let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?;
16
17    // Create a new file explorer with the default theme and title.
18    let theme = Theme::default().add_default_title();
19    let mut file_explorer = FileExplorer::with_theme(theme)?;
20
21    let mut selected_paths = vec![];
22
23    loop {
24        // Render the file explorer widget.
25        terminal.draw(|f| {
26            f.render_widget(&file_explorer.widget(), f.area());
27        })?;
28
29        // Read the next event from the terminal.
30        let event = read()?;
31        if let Event::Key(key) = event {
32            if key.code == KeyCode::Char('q') {
33                // Collect selected file paths.
34                selected_paths = file_explorer
35                    .selected_files()
36                    .iter()
37                    .map(|file| file.path().display().to_string())
38                    .collect();
39                break;
40            }
41        }
42        // Handle the event in the file explorer.
43        file_explorer.handle(&event)?;
44    }
45
46    // Restore the terminal to normal mode.
47    disable_raw_mode()?;
48    stdout().execute(LeaveAlternateScreen)?;
49
50    // Print the selected file paths to stdout.
51    for path in selected_paths {
52        println!("{}", path);
53    }
54
55    // Return exit code 0 explicitly.
56    process::exit(0);
57}
More examples
Hide additional examples
examples/light_and_dark_theme.rs (line 54)
15fn main() -> io::Result<()> {
16    enable_raw_mode()?;
17    stdout().execute(EnterAlternateScreen)?;
18
19    let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?;
20
21    // Create a new file explorer with the light theme.
22    let mut dark_theme = false;
23    let mut file_explorer = FileExplorer::with_theme(get_light_theme())?;
24
25    loop {
26        // Render the file explorer widget.
27        terminal.draw(|f| {
28            f.render_widget(&file_explorer.widget(), f.area());
29        })?;
30
31        // Read the next event from the terminal.
32        let event = read()?;
33        // If the user presses `Ctrl + s`, switch the theme.
34        // If the user presses `Ctrl + q`, quit the application.
35        if let Event::Key(key) = event {
36            if key.modifiers == crossterm::event::KeyModifiers::CONTROL {
37                match key.code {
38                    KeyCode::Char('s') => {
39                        dark_theme = !dark_theme;
40                        if dark_theme {
41                            file_explorer.set_theme(get_dark_theme());
42                        } else {
43                            file_explorer.set_theme(get_light_theme());
44                        }
45                    }
46                    KeyCode::Char('q') => {
47                        break;
48                    }
49                    _ => {}
50                }
51            }
52        }
53        // Handle the event in the file explorer.
54        file_explorer.handle(&event)?;
55    }
56
57    disable_raw_mode()?;
58    stdout().execute(LeaveAlternateScreen)?;
59    Ok(())
60}
examples/file_preview.rs (line 102)
17fn main() -> io::Result<()> {
18    enable_raw_mode()?;
19    stdout().execute(EnterAlternateScreen)?;
20
21    let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?;
22    let layout = Layout::vertical([
23        Constraint::Ratio(4, 5), // Main file explorer and content area
24        Constraint::Ratio(1, 5), // Bottom window for selected file paths
25    ]);
26
27    // Inner layout for the top section
28    let top_layout = Layout::horizontal([Constraint::Ratio(1, 3), Constraint::Ratio(2, 3)]);
29
30    // Create a new file explorer with the default theme and title.
31    let theme = get_theme();
32    let mut file_explorer = FileExplorer::with_theme(theme)?;
33
34    loop {
35        // Get the content of the current selected file (if it's indeed a file).
36        let file_content = get_file_content(file_explorer.current().path())?;
37        let selected_files: String = file_explorer
38            .selected_files()
39            .iter()
40            .map(|file| file.path().display().to_string())
41            .collect::<Vec<String>>()
42            .join("\n");
43
44        // Render the file explorer widget, file content, and selected file paths.
45        terminal.draw(|f| {
46            let chunks = layout.split(f.area());
47            let top_chunks = top_layout.split(chunks[0]);
48
49            // Top section
50            f.render_widget(&file_explorer.widget(), top_chunks[0]);
51            f.render_widget(
52                Paragraph::new(file_content).block(
53                    Block::default()
54                        .borders(Borders::ALL)
55                        .border_type(BorderType::Double),
56                ),
57                top_chunks[1],
58            );
59
60            // Bottom section
61            f.render_widget(
62                Paragraph::new(selected_files.clone()).block(
63                    Block::default()
64                        .borders(Borders::ALL)
65                        .title("q:Quit, c: copy selected file contents to clipboard, p: copy paths to clipboard"),
66                ),
67                chunks[1],
68            );
69        })?;
70
71        // Read the next event from the terminal.
72        let event = read()?;
73        if let Event::Key(key) = event {
74            match key.code {
75                KeyCode::Char('q') => break, // Quit the application
76                KeyCode::Char('c') => {
77                    // Copy selected file paths to clipboard
78                    if let Ok(mut clipboard) = ClipboardContext::new() {
79                        if let Err(err) = clipboard.set_contents(get_selected_files_content(
80                            &file_explorer.selected_files(),
81                        )) {
82                            eprintln!("Failed to copy to clipboard: {}", err);
83                        }
84                    } else {
85                        eprintln!("Clipboard not available.");
86                    }
87                }
88                KeyCode::Char('p') => {
89                    // Copy selected file paths to clipboard
90                    if let Ok(mut clipboard) = ClipboardContext::new() {
91                        if let Err(err) = clipboard.set_contents(selected_files.clone()) {
92                            eprintln!("Failed to copy to clipboard: {}", err);
93                        }
94                    } else {
95                        eprintln!("Clipboard not available.");
96                    }
97                }
98                _ => {}
99            }
100        }
101        // Handle the event in the file explorer.
102        file_explorer.handle(&event)?;
103    }
104
105    disable_raw_mode()?;
106    stdout().execute(LeaveAlternateScreen)?;
107    // Print the selected file paths to stdout.
108    for file in file_explorer.selected_files() {
109        println!("{}", file.path().display());
110    }
111    Ok(())
112}
Source

pub fn set_cwd<P: Into<PathBuf>>(&mut self, cwd: P) -> Result<()>

Sets the current working directory of the file explorer.

§Examples
use fpicker::FileExplorer;

let mut file_explorer = FileExplorer::new().unwrap();

file_explorer.set_cwd("/Documents").unwrap();
assert_eq!(file_explorer.cwd().display().to_string(), "/Documents");
Source

pub fn selected_files(&self) -> &Vec<File>

Examples found in repository?
examples/basic.rs (line 35)
11fn main() -> io::Result<()> {
12    enable_raw_mode()?;
13    stdout().execute(EnterAlternateScreen)?;
14
15    let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?;
16
17    // Create a new file explorer with the default theme and title.
18    let theme = Theme::default().add_default_title();
19    let mut file_explorer = FileExplorer::with_theme(theme)?;
20
21    let mut selected_paths = vec![];
22
23    loop {
24        // Render the file explorer widget.
25        terminal.draw(|f| {
26            f.render_widget(&file_explorer.widget(), f.area());
27        })?;
28
29        // Read the next event from the terminal.
30        let event = read()?;
31        if let Event::Key(key) = event {
32            if key.code == KeyCode::Char('q') {
33                // Collect selected file paths.
34                selected_paths = file_explorer
35                    .selected_files()
36                    .iter()
37                    .map(|file| file.path().display().to_string())
38                    .collect();
39                break;
40            }
41        }
42        // Handle the event in the file explorer.
43        file_explorer.handle(&event)?;
44    }
45
46    // Restore the terminal to normal mode.
47    disable_raw_mode()?;
48    stdout().execute(LeaveAlternateScreen)?;
49
50    // Print the selected file paths to stdout.
51    for path in selected_paths {
52        println!("{}", path);
53    }
54
55    // Return exit code 0 explicitly.
56    process::exit(0);
57}
More examples
Hide additional examples
examples/file_preview.rs (line 38)
17fn main() -> io::Result<()> {
18    enable_raw_mode()?;
19    stdout().execute(EnterAlternateScreen)?;
20
21    let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?;
22    let layout = Layout::vertical([
23        Constraint::Ratio(4, 5), // Main file explorer and content area
24        Constraint::Ratio(1, 5), // Bottom window for selected file paths
25    ]);
26
27    // Inner layout for the top section
28    let top_layout = Layout::horizontal([Constraint::Ratio(1, 3), Constraint::Ratio(2, 3)]);
29
30    // Create a new file explorer with the default theme and title.
31    let theme = get_theme();
32    let mut file_explorer = FileExplorer::with_theme(theme)?;
33
34    loop {
35        // Get the content of the current selected file (if it's indeed a file).
36        let file_content = get_file_content(file_explorer.current().path())?;
37        let selected_files: String = file_explorer
38            .selected_files()
39            .iter()
40            .map(|file| file.path().display().to_string())
41            .collect::<Vec<String>>()
42            .join("\n");
43
44        // Render the file explorer widget, file content, and selected file paths.
45        terminal.draw(|f| {
46            let chunks = layout.split(f.area());
47            let top_chunks = top_layout.split(chunks[0]);
48
49            // Top section
50            f.render_widget(&file_explorer.widget(), top_chunks[0]);
51            f.render_widget(
52                Paragraph::new(file_content).block(
53                    Block::default()
54                        .borders(Borders::ALL)
55                        .border_type(BorderType::Double),
56                ),
57                top_chunks[1],
58            );
59
60            // Bottom section
61            f.render_widget(
62                Paragraph::new(selected_files.clone()).block(
63                    Block::default()
64                        .borders(Borders::ALL)
65                        .title("q:Quit, c: copy selected file contents to clipboard, p: copy paths to clipboard"),
66                ),
67                chunks[1],
68            );
69        })?;
70
71        // Read the next event from the terminal.
72        let event = read()?;
73        if let Event::Key(key) = event {
74            match key.code {
75                KeyCode::Char('q') => break, // Quit the application
76                KeyCode::Char('c') => {
77                    // Copy selected file paths to clipboard
78                    if let Ok(mut clipboard) = ClipboardContext::new() {
79                        if let Err(err) = clipboard.set_contents(get_selected_files_content(
80                            &file_explorer.selected_files(),
81                        )) {
82                            eprintln!("Failed to copy to clipboard: {}", err);
83                        }
84                    } else {
85                        eprintln!("Clipboard not available.");
86                    }
87                }
88                KeyCode::Char('p') => {
89                    // Copy selected file paths to clipboard
90                    if let Ok(mut clipboard) = ClipboardContext::new() {
91                        if let Err(err) = clipboard.set_contents(selected_files.clone()) {
92                            eprintln!("Failed to copy to clipboard: {}", err);
93                        }
94                    } else {
95                        eprintln!("Clipboard not available.");
96                    }
97                }
98                _ => {}
99            }
100        }
101        // Handle the event in the file explorer.
102        file_explorer.handle(&event)?;
103    }
104
105    disable_raw_mode()?;
106    stdout().execute(LeaveAlternateScreen)?;
107    // Print the selected file paths to stdout.
108    for file in file_explorer.selected_files() {
109        println!("{}", file.path().display());
110    }
111    Ok(())
112}
Source

pub fn set_theme(&mut self, theme: Theme)

Sets the theme of the file explorer.

§Examples
use fpicker::{FileExplorer, Theme};

let mut file_explorer = FileExplorer::new().unwrap();

file_explorer.set_theme(Theme::default().add_default_title());
Examples found in repository?
examples/light_and_dark_theme.rs (line 41)
15fn main() -> io::Result<()> {
16    enable_raw_mode()?;
17    stdout().execute(EnterAlternateScreen)?;
18
19    let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?;
20
21    // Create a new file explorer with the light theme.
22    let mut dark_theme = false;
23    let mut file_explorer = FileExplorer::with_theme(get_light_theme())?;
24
25    loop {
26        // Render the file explorer widget.
27        terminal.draw(|f| {
28            f.render_widget(&file_explorer.widget(), f.area());
29        })?;
30
31        // Read the next event from the terminal.
32        let event = read()?;
33        // If the user presses `Ctrl + s`, switch the theme.
34        // If the user presses `Ctrl + q`, quit the application.
35        if let Event::Key(key) = event {
36            if key.modifiers == crossterm::event::KeyModifiers::CONTROL {
37                match key.code {
38                    KeyCode::Char('s') => {
39                        dark_theme = !dark_theme;
40                        if dark_theme {
41                            file_explorer.set_theme(get_dark_theme());
42                        } else {
43                            file_explorer.set_theme(get_light_theme());
44                        }
45                    }
46                    KeyCode::Char('q') => {
47                        break;
48                    }
49                    _ => {}
50                }
51            }
52        }
53        // Handle the event in the file explorer.
54        file_explorer.handle(&event)?;
55    }
56
57    disable_raw_mode()?;
58    stdout().execute(LeaveAlternateScreen)?;
59    Ok(())
60}
Source

pub fn set_selected_idx(&mut self, selected: usize)

Sets the selected file or directory index inside the current Vec of files and directories if the file explorer.

The file explorer add the parent directory at the beginning of the Vec of files, so setting the selected index to 0 will select the parent directory (if the current working directory not the root directory).

§Panics

Panics if selected is greater or equal to the number of files (plus the parent directory if it exist) in the current working directory.

§Examples

Suppose you have this tree file, with passport.png selected inside file_explorer:

/
├── .git
└── Documents
    ├── passport.png  <- selected (index 2)
    └── resume.pdf

You can set the selected index like this:

use fpicker::FileExplorer;

let mut file_explorer = FileExplorer::new().unwrap();

/* user select `password.png` */

// Because the file explorer add the parent directory at the beginning
// of the [`Vec`](https://doc.rust-lang.org/stable/std/vec/struct.Vec.html) of files, index 0 is indeed the parent directory.
file_explorer.set_selected_idx(0);
assert_eq!(file_explorer.current().path().display().to_string(), "/");

file_explorer.set_selected_idx(1);
assert_eq!(file_explorer.current().path().display().to_string(), "/Documents");

#[test]
#[should_panic]
fn index_out_of_bound() {
   let mut file_explorer = FileExplorer::new().unwrap();
   file_explorer.set_selected_idx(4);
}
Source

pub fn current(&self) -> &File

Returns the current file or directory selected.

§Examples

Suppose you have this tree file, with passport.png selected inside file_explorer:

/
├── .git
└── Documents
    ├── passport.png  <- selected
    └── resume.pdf

You can get the current file like this:

use fpicker::FileExplorer;

let file_explorer = FileExplorer::new().unwrap();

/* user select `password.png` */

let file = file_explorer.current();
assert_eq!(file.name(), "passport.png");
Examples found in repository?
examples/file_preview.rs (line 36)
17fn main() -> io::Result<()> {
18    enable_raw_mode()?;
19    stdout().execute(EnterAlternateScreen)?;
20
21    let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?;
22    let layout = Layout::vertical([
23        Constraint::Ratio(4, 5), // Main file explorer and content area
24        Constraint::Ratio(1, 5), // Bottom window for selected file paths
25    ]);
26
27    // Inner layout for the top section
28    let top_layout = Layout::horizontal([Constraint::Ratio(1, 3), Constraint::Ratio(2, 3)]);
29
30    // Create a new file explorer with the default theme and title.
31    let theme = get_theme();
32    let mut file_explorer = FileExplorer::with_theme(theme)?;
33
34    loop {
35        // Get the content of the current selected file (if it's indeed a file).
36        let file_content = get_file_content(file_explorer.current().path())?;
37        let selected_files: String = file_explorer
38            .selected_files()
39            .iter()
40            .map(|file| file.path().display().to_string())
41            .collect::<Vec<String>>()
42            .join("\n");
43
44        // Render the file explorer widget, file content, and selected file paths.
45        terminal.draw(|f| {
46            let chunks = layout.split(f.area());
47            let top_chunks = top_layout.split(chunks[0]);
48
49            // Top section
50            f.render_widget(&file_explorer.widget(), top_chunks[0]);
51            f.render_widget(
52                Paragraph::new(file_content).block(
53                    Block::default()
54                        .borders(Borders::ALL)
55                        .border_type(BorderType::Double),
56                ),
57                top_chunks[1],
58            );
59
60            // Bottom section
61            f.render_widget(
62                Paragraph::new(selected_files.clone()).block(
63                    Block::default()
64                        .borders(Borders::ALL)
65                        .title("q:Quit, c: copy selected file contents to clipboard, p: copy paths to clipboard"),
66                ),
67                chunks[1],
68            );
69        })?;
70
71        // Read the next event from the terminal.
72        let event = read()?;
73        if let Event::Key(key) = event {
74            match key.code {
75                KeyCode::Char('q') => break, // Quit the application
76                KeyCode::Char('c') => {
77                    // Copy selected file paths to clipboard
78                    if let Ok(mut clipboard) = ClipboardContext::new() {
79                        if let Err(err) = clipboard.set_contents(get_selected_files_content(
80                            &file_explorer.selected_files(),
81                        )) {
82                            eprintln!("Failed to copy to clipboard: {}", err);
83                        }
84                    } else {
85                        eprintln!("Clipboard not available.");
86                    }
87                }
88                KeyCode::Char('p') => {
89                    // Copy selected file paths to clipboard
90                    if let Ok(mut clipboard) = ClipboardContext::new() {
91                        if let Err(err) = clipboard.set_contents(selected_files.clone()) {
92                            eprintln!("Failed to copy to clipboard: {}", err);
93                        }
94                    } else {
95                        eprintln!("Clipboard not available.");
96                    }
97                }
98                _ => {}
99            }
100        }
101        // Handle the event in the file explorer.
102        file_explorer.handle(&event)?;
103    }
104
105    disable_raw_mode()?;
106    stdout().execute(LeaveAlternateScreen)?;
107    // Print the selected file paths to stdout.
108    for file in file_explorer.selected_files() {
109        println!("{}", file.path().display());
110    }
111    Ok(())
112}
Source

pub const fn cwd(&self) -> &PathBuf

Returns the current working directory of the file explorer.

§Examples

Suppose you have this tree file, with passport.png selected inside file_explorer:

/
├── .git
└── Documents
    ├── passport.png  <- selected
    └── resume.pdf

You can get the current working directory like this:

use fpicker::FileExplorer;

let file_explorer = FileExplorer::new().unwrap();

/* user select `password.png` */

let cwd = file_explorer.cwd();
assert_eq!(cwd.display().to_string(), "/Documents");
Source

pub const fn files(&self) -> &Vec<File>

Returns the a Vec of files and directories in the current working directory of the file explorer, plus the parent directory if it exist.

§Examples

Suppose you have this tree file, with passport.png selected inside file_explorer:

/
├── .git
└── Documents
    ├── passport.png  <- selected
    └── resume.pdf

You can get the Vec of files and directories like this:

use fpicker::FileExplorer;

let file_explorer = FileExplorer::new().unwrap();

/* user select `password.png` */

let files = file_explorer.files();
assert_eq!(files.len(), 4); // 3 files/directory and the parent directory
Source

pub const fn selected_idx(&self) -> usize

Returns the index of the selected file or directory in the current Vec of files and directories in the current working directory of the file explorer.

§Examples

Suppose you have this tree file, with passport.png selected inside file_explorer:

/
├── .git
└── Documents
    ├── passport.png  <- selected (index 2)
    └── resume.pdf

You can get the selected index like this:

use fpicker::FileExplorer;

let file_explorer = FileExplorer::new().unwrap();

/* user select `password.png` */

let selected_idx = file_explorer.selected_idx();

// Because the file explorer add the parent directory at the beginning
// of the [`Vec`](https://doc.rust-lang.org/stable/std/vec/struct.Vec.html) of files, the selected index will be 2.
assert_eq!(selected_idx, 2);
Source

pub const fn theme(&self) -> &Theme

Returns the theme of the file explorer.

§Examples
use fpicker::{FileExplorer, Theme};

let file_explorer = FileExplorer::new().unwrap();

assert_eq!(file_explorer.theme(), &Theme::default());

Trait Implementations§

Source§

impl Clone for FileExplorer

Source§

fn clone(&self) -> FileExplorer

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for FileExplorer

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Hash for FileExplorer

Source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl PartialEq for FileExplorer

Source§

fn eq(&self, other: &FileExplorer) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Eq for FileExplorer

Source§

impl StructuralPartialEq for FileExplorer

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.