summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/action_map.rs6
-rw-r--r--src/config.rs5
-rw-r--r--src/event_dispatch.rs6
-rw-r--r--src/event_exec.rs85
-rw-r--r--src/fileinfo.rs18
-rw-r--r--src/filter.rs7
-rw-r--r--src/fm_error.rs13
-rw-r--r--src/git.rs2
-rw-r--r--src/help.rs5
-rw-r--r--src/input.rs2
-rw-r--r--src/keybindings.rs8
-rw-r--r--src/log.rs3
-rw-r--r--src/main.rs13
-rw-r--r--src/marks.rs9
-rw-r--r--src/mode.rs6
-rw-r--r--src/opener.rs61
-rw-r--r--src/preview.rs87
-rw-r--r--src/shortcut.rs16
-rw-r--r--src/status.rs109
-rw-r--r--src/tab.rs36
-rw-r--r--src/term_manager.rs11
-rw-r--r--src/utils.rs20
-rw-r--r--src/visited.rs16
23 files changed, 412 insertions, 132 deletions
diff --git a/src/action_map.rs b/src/action_map.rs
index f3614c8..f6abb02 100644
--- a/src/action_map.rs
+++ b/src/action_map.rs
@@ -95,7 +95,7 @@ impl ActionMap {
ActionMap::FlagAll => EventExec::event_flag_all(status),
ActionMap::FuzzyFind => EventExec::event_fuzzyfind(status),
ActionMap::Goto => EventExec::event_goto(current_tab),
- ActionMap::Help => EventExec::event_help(current_tab),
+ ActionMap::Help => EventExec::event_help(status),
ActionMap::History => EventExec::event_history(current_tab),
ActionMap::Home => EventExec::event_home(current_tab),
ActionMap::Jump => EventExec::event_jump(status),
@@ -110,7 +110,7 @@ impl ActionMap {
ActionMap::NewDir => EventExec::event_new_dir(current_tab),
ActionMap::NewFile => EventExec::event_new_file(current_tab),
ActionMap::NvimFilepicker => EventExec::event_nvim_filepicker(current_tab),
- ActionMap::OpenFile => EventExec::event_open_file(current_tab),
+ ActionMap::OpenFile => EventExec::event_open_file(status),
ActionMap::PageDown => EventExec::page_down(status),
ActionMap::PageUp => EventExec::page_up(status),
ActionMap::Preview => EventExec::event_preview(current_tab),
@@ -120,7 +120,7 @@ impl ActionMap {
ActionMap::Rename => EventExec::event_rename(current_tab),
ActionMap::ReverseFlags => EventExec::event_reverse_flags(status),
ActionMap::Search => EventExec::event_search(current_tab),
- ActionMap::Shell => EventExec::event_shell(current_tab),
+ ActionMap::Shell => EventExec::event_shell(status),
ActionMap::Shortcut => EventExec::event_shortcut(current_tab),
ActionMap::Sort => EventExec::event_sort(current_tab),
ActionMap::Symlink => EventExec::event_symlink(status),
diff --git a/src/config.rs b/src/config.rs
index 95c71af..a477ea2 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -30,6 +30,11 @@ impl Config {
}
}
+ /// The terminal name
+ pub fn terminal(&self) -> &str {
+ &self.terminal
+ }
+
/// Updates the config from a configuration content.
fn update_from_config(&mut self, yaml: &serde_yaml::value::Value) -> FmResult<()> {
self.colors.update_from_config(&yaml["colors"]);
diff --git a/src/event_dispatch.rs b/src/event_dispatch.rs
index d725451..2c2d9d8 100644
--- a/src/event_dispatch.rs
+++ b/src/event_dispatch.rs
@@ -20,8 +20,12 @@ impl EventDispatcher {
pub fn new(binds: Bindings) -> Self {
Self { binds }
}
+
/// Reaction to received events.
- pub fn read_event(&self, status: &mut Status, ev: Event) -> FmResult<()> {
+ /// Only non keyboard events are dealt here directly.
+ /// Keyboard events are configurable and are sent to specific functions
+ /// which needs to know those keybindings.
+ pub fn dispatch(&self, status: &mut Status, ev: Event) -> FmResult<()> {
match ev {
Event::Key(Key::WheelUp(_, _, _)) => EventExec::event_move_up(status),
Event::Key(Key::WheelDown(_, _, _)) => EventExec::event_move_down(status),
diff --git a/src/event_exec.rs b/src/event_exec.rs
index 1bda454..53d92e4 100644
--- a/src/event_exec.rs
+++ b/src/event_exec.rs
@@ -62,7 +62,7 @@ impl EventExec {
.for_each(|file| {
status.flagged.insert(file.path.clone());
});
- status.reset_statuses()
+ status.reset_tabs_view()
}
/// Reverse every flag in _current_ directory. Flagged files in other
@@ -79,7 +79,7 @@ impl EventExec {
status.flagged.insert(file.path.clone());
}
});
- status.reset_statuses()
+ status.reset_tabs_view()
}
/// Toggle a single flag and move down one row.
@@ -128,7 +128,7 @@ impl EventExec {
.clone(),
);
};
- status.reset_statuses()
+ status.reset_tabs_view()
}
/// Enter JUMP mode, allowing to jump to any flagged file.
@@ -191,8 +191,7 @@ impl EventExec {
/// can edit the selected filenames.
/// Once the temp file is saved, those file names are changed.
pub fn event_bulkrename(status: &mut Status) -> FmResult<()> {
- Bulkrename::new(status.filtered_flagged_files())?
- .rename(&status.selected_non_mut().opener)?;
+ Bulkrename::new(status.filtered_flagged_files())?.rename(&status.opener)?;
status.selected().refresh_view()
}
@@ -238,7 +237,7 @@ impl EventExec {
status.flagged.clear()
}
status.selected().refresh_view()?;
- status.reset_statuses()
+ status.reset_tabs_view()
}
fn _exec_last_edition(status: &mut Status) -> FmResult<()> {
@@ -462,14 +461,15 @@ impl EventExec {
}
/// Open the file with configured opener or enter the directory.
- pub fn exec_file(tab: &mut Tab) -> FmResult<()> {
+ pub fn exec_file(status: &mut Status) -> FmResult<()> {
+ let tab = status.selected();
if tab.path_content.is_empty() {
return Ok(());
}
if tab.path_content.is_selected_dir()? {
tab.go_to_child()
} else {
- Self::event_open_file(tab)
+ Self::event_open_file(status)
}
}
@@ -557,9 +557,11 @@ impl EventExec {
/// Display the help which can be navigated and displays the configrable
/// binds.
- pub fn event_help(tab: &mut Tab) -> FmResult<()> {
+ pub fn event_help(status: &mut Status) -> FmResult<()> {
+ let help = status.help.clone();
+ let tab = status.selected();
tab.mode = Mode::Help;
- tab.preview = Preview::help(tab.help.clone());
+ tab.preview = Preview::help(help);
tab.window.reset(tab.preview.len());
Ok(())
}
@@ -649,9 +651,11 @@ impl EventExec {
}
/// Open a file with custom opener.
- pub fn event_open_file(tab: &mut Tab) -> FmResult<()> {
- match tab.opener.open(
- tab.path_content
+ pub fn event_open_file(status: &mut Status) -> FmResult<()> {
+ match status.opener.open(
+ status
+ .selected_non_mut()
+ .path_content
.selected_file()
.ok_or_else(|| {
FmError::new(
@@ -665,7 +669,7 @@ impl EventExec {
Ok(_) => (),
Err(e) => info!(
"Error opening {:?}: {:?}",
- tab.path_content.selected_file(),
+ status.selected_non_mut().path_content.selected_file(),
e
),
}
@@ -688,9 +692,10 @@ impl EventExec {
/// Open a new terminal in current directory.
/// The shell is a fork of current process and will exit if the application
/// is terminated first.
- pub fn event_shell(tab: &mut Tab) -> FmResult<()> {
+ pub fn event_shell(status: &mut Status) -> FmResult<()> {
+ let tab = status.selected_non_mut();
execute_in_child(
- &tab.terminal,
+ &status.opener.terminal.clone(),
&vec![
"-d",
tab.path_content.path.to_str().ok_or_else(|| {
@@ -744,9 +749,9 @@ impl EventExec {
})?
.file_kind
{
- Self::exec_file(tab)
+ Self::exec_file(status)
} else {
- Self::event_open_file(tab)
+ Self::event_open_file(status)
}
} else {
Ok(())
@@ -977,6 +982,8 @@ impl EventExec {
Ok(())
}
+ /// Move to the selected shortcut.
+ /// It may fail if the user has no permission to visit the path.
pub fn exec_shortcut(tab: &mut Tab) -> FmResult<()> {
tab.input.reset();
let path = tab.shortcut.selected();
@@ -985,6 +992,8 @@ impl EventExec {
Self::event_normal(tab)
}
+ /// Move back to a previously visited path.
+ /// It may fail if the user has no permission to visit the path
pub fn exec_history(tab: &mut Tab) -> FmResult<()> {
tab.input.reset();
tab.path_content = PathContent::new(
@@ -1000,6 +1009,8 @@ impl EventExec {
Self::event_normal(tab)
}
+ /// Apply a filter to the displayed files.
+ /// See `crate::filter` for more details.
pub fn exec_filter(tab: &mut Tab) -> FmResult<()> {
let filter = FilterKind::from_input(&tab.input.string);
tab.path_content.set_filter(filter);
@@ -1008,6 +1019,8 @@ impl EventExec {
Self::event_normal(tab)
}
+ /// Move up one row in modes allowing movement.
+ /// Does nothing if the selected item is already the first in list.
pub fn event_move_up(status: &mut Status) -> FmResult<()> {
match status.selected().mode {
Mode::Normal | Mode::Preview | Mode::Help => {
@@ -1024,6 +1037,8 @@ impl EventExec {
Ok(())
}
+ /// Move down one row in modes allowing movements.
+ /// Does nothing if the user is already at the bottom.
pub fn event_move_down(status: &mut Status) -> FmResult<()> {
match status.selected().mode {
Mode::Normal | Mode::Preview | Mode::Help => {
@@ -1040,6 +1055,8 @@ impl EventExec {
Ok(())
}
+ /// Move to parent in normal mode,
+ /// move left one char in mode requiring text input.
pub fn event_move_left(status: &mut Status) -> FmResult<()> {
match status.selected().mode {
Mode::Normal => EventExec::event_move_to_parent(status.selected()),
@@ -1060,9 +1077,11 @@ impl EventExec {
}
}
+ /// Move to child if any or open a regular file in normal mode.
+ /// Move the cursor one char to right in mode requiring text input.
pub fn event_move_right(status: &mut Status) -> FmResult<()> {
match status.selected().mode {
- Mode::Normal => EventExec::exec_file(status.selected()),
+ Mode::Normal => EventExec::exec_file(status),
Mode::Rename
| Mode::Chmod
| Mode::Newdir
@@ -1079,6 +1098,7 @@ impl EventExec {
}
}
+ /// Delete a char to the left in modes allowing edition.
pub fn event_backspace(status: &mut Status) -> FmResult<()> {
match status.selected().mode {
Mode::Rename
@@ -1098,6 +1118,7 @@ impl EventExec {
}
}
+ /// Delete all chars to the right in mode allowing edition.
pub fn event_delete(status: &mut Status) -> FmResult<()> {
match status.selected().mode {
Mode::Rename
@@ -1116,6 +1137,7 @@ impl EventExec {
}
}
+ /// Move to leftmost char in mode allowing edition.
pub fn event_key_home(status: &mut Status) -> FmResult<()> {
match status.selected().mode {
Mode::Normal | Mode::Preview | Mode::Help => EventExec::event_go_top(status.selected()),
@@ -1124,6 +1146,7 @@ impl EventExec {
Ok(())
}
+ /// Move to the bottom in any mode.
pub fn event_end(status: &mut Status) -> FmResult<()> {
match status.selected().mode {
Mode::Normal | Mode::Preview | Mode::Help => {
@@ -1134,6 +1157,7 @@ impl EventExec {
Ok(())
}
+ /// Move up 10 lines in normal mode and preview.
pub fn page_up(status: &mut Status) -> FmResult<()> {
match status.selected().mode {
Mode::Normal | Mode::Preview | Mode::Help => {
@@ -1144,6 +1168,7 @@ impl EventExec {
Ok(())
}
+ /// Move down 10 lines in normal & preview mode.
pub fn page_down(status: &mut Status) -> FmResult<()> {
match status.selected().mode {
Mode::Normal | Mode::Preview | Mode::Help => {
@@ -1154,6 +1179,11 @@ impl EventExec {
Ok(())
}
+ /// Execute the mode.
+ /// In modes requiring confirmation or text input, it will execute the
+ /// related action.
+ /// In normal mode, it will open the file.
+ /// Reset to normal mode afterwards.
pub fn enter(status: &mut Status) -> FmResult<()> {
match status.selected().mode {
Mode::Rename => EventExec::exec_rename(status.selected())?,
@@ -1168,7 +1198,7 @@ impl EventExec {
Mode::History => EventExec::exec_history(status.selected())?,
Mode::Shortcut => EventExec::exec_shortcut(status.selected())?,
Mode::Filter => EventExec::exec_filter(status.selected())?,
- Mode::Normal => EventExec::exec_file(status.selected())?,
+ Mode::Normal => EventExec::exec_file(status)?,
Mode::NeedConfirmation | Mode::Help | Mode::Sort | Mode::Preview | Mode::Marks(_) => (),
};
@@ -1177,6 +1207,8 @@ impl EventExec {
Ok(())
}
+ /// Change tab in normal mode with dual pane displayed,
+ /// insert a completion in modes allowing completion.
pub fn tab(status: &mut Status) -> FmResult<()> {
match status.selected().mode {
Mode::Goto | Mode::Exec | Mode::Search => {
@@ -1188,6 +1220,7 @@ impl EventExec {
Ok(())
}
+ /// Change tab in normal mode.
pub fn backtab(status: &mut Status) -> FmResult<()> {
if let Mode::Normal = status.selected().mode {
status.prev()
@@ -1195,10 +1228,13 @@ impl EventExec {
Ok(())
}
+ /// Start a fuzzy find with skim.
+ /// ATM idk how to avoid using the whole screen.
pub fn event_fuzzyfind(status: &mut Status) -> FmResult<()> {
status.fill_tabs_with_skim()
}
+ /// Copy the filename of the selected file in normal mode.
pub fn event_copy_filename(status: &mut Status) -> FmResult<()> {
if let Mode::Normal = status.selected_non_mut().mode {
return EventExec::event_filename_to_clipboard(status.selected());
@@ -1206,6 +1242,7 @@ impl EventExec {
Ok(())
}
+ /// Copy the filepath of the selected file in normal mode.
pub fn event_copy_filepath(status: &mut Status) -> FmResult<()> {
if let Mode::Normal = status.selected_non_mut().mode {
return EventExec::event_filepath_to_clipboard(status.selected());
@@ -1213,10 +1250,12 @@ impl EventExec {
Ok(())
}
+ /// Refresh the current view, reloading the files. Move the selection to top.
pub fn event_refreshview(status: &mut Status) -> FmResult<()> {
Self::refresh_selected_view(status)
}
+ /// Open a thumbnail of an image, scaled up to the whole window.
pub fn event_thumbnail(tab: &mut Tab) -> FmResult<()> {
if let Mode::Normal = tab.mode {
tab.mode = Mode::Preview;
@@ -1228,11 +1267,15 @@ impl EventExec {
Ok(())
}
+ /// Toggle between a full display (aka ls -lah) or a simple mode (only the
+ /// filenames).
pub fn event_toggle_display_full(status: &mut Status) -> FmResult<()> {
status.display_full = !status.display_full;
Ok(())
}
+ /// Toggle between dualpane and single pane. Does nothing if the width
+ /// is too low to display both panes.
pub fn event_toggle_dualpane(status: &mut Status) -> FmResult<()> {
status.dual_pane = !status.dual_pane;
status.select_tab(0)?;
@@ -1247,5 +1290,5 @@ impl EventExec {
fn string_to_path(path_string: String) -> FmResult<path::PathBuf> {
let expanded_cow_path = shellexpand::tilde(&path_string);
let expanded_target: &str = expanded_cow_path.borrow();
- Ok(std::fs::canonicalize(expanded_target)?.to_path_buf())
+ Ok(std::fs::canonicalize(expanded_target)?)
}
diff --git a/src/fileinfo.rs b/src/fileinfo.rs
index d31c739..2ff7335 100644
--- a/src/fileinfo.rs
+++ b/src/fileinfo.rs
@@ -234,11 +234,17 @@ impl FileInfo {
/// the "display all files including hidden" flag and the key to sort files.
#[derive(Clone)]
pub struct PathContent {
+ /// The current path
pub path: path::PathBuf,
+ /// A vector of FileInfo with every file in current path
pub files: Vec<FileInfo>,
+ /// The index of the selected file.
pub selected: usize,
+ /// Do we display the hidden files ?
pub show_hidden: bool,
+ /// The kind of sort used to display the files.
pub sort_by: SortBy,
+ /// Is it reversed ?
pub reverse: bool,
filter: FilterKind,
used_space: u64,
@@ -272,6 +278,7 @@ impl PathContent {
})
}
+ /// Apply the filter.
pub fn set_filter(&mut self, filter: FilterKind) {
self.filter = filter
}
@@ -304,6 +311,8 @@ impl PathContent {
}
}
+ /// Convert a path to a &str.
+ /// It may fails if the path contains non valid utf-8 chars.
pub fn path_to_str(&self) -> FmResult<&str> {
self.path.to_str().ok_or_else(|| {
FmError::new(
@@ -400,14 +409,18 @@ impl PathContent {
}
}
+ /// Path of the currently selected file.
pub fn selected_path_str(&self) -> Option<String> {
Some(self.selected_file()?.path.to_str()?.to_owned())
}
+ /// True if the path starts with a subpath.
pub fn contains(&self, path: &path::Path) -> bool {
path.starts_with(&self.path)
}
+ /// Is the selected file a directory ?
+ /// It may fails if the current path is empty, aka if nothing is selected.
pub fn is_selected_dir(&self) -> FmResult<bool> {
match self
.selected_file()
@@ -437,14 +450,19 @@ impl PathContent {
}
}
+ /// True if the path is empty.
pub fn is_empty(&self) -> bool {
self.files.is_empty()
}
+ /// Human readable string representation of the space used by _files_
+ /// in current path.
+ /// No recursive exploration of directory.
pub fn used_space(&self) -> String {
human_size(self.used_space)
}
+ /// A string representation of the git status of the path.
pub fn git_string(&self) -> FmResult<String> {
Ok(git(&self.path)?)
}
diff --git a/src/filter.rs b/src/filter.rs
index d1c23eb..6e06d80 100644
--- a/src/filter.rs
+++ b/src/filter.rs
@@ -2,6 +2,8 @@ use regex::Regex;
use crate::fileinfo::{FileInfo, FileKind};
+/// Different kinds of filters.
+/// By extension, by name, only the directory or all files.
#[derive(Clone)]
pub enum FilterKind {
Extension(String),
@@ -11,6 +13,8 @@ pub enum FilterKind {
}
impl FilterKind {
+ /// Parse the input string into a filter.
+ /// It shouldn't fail but use a `Filter::All` if the string isn't parsable;
pub fn from_input(input: &str) -> Self {
let words = input.split_whitespace().collect::<Vec<&str>>();
if words.len() < 2 {
@@ -24,6 +28,9 @@ impl FilterKind {
}
}
+ /// Apply the selected filter to the file list.
+ /// It's a "key" used by the Filter method to hold the files matching this
+ /// filter.
pub fn filter_by(&self, fileinfo: &FileInfo) -> bool {
match self {
Self::Extension(ext) => Self::filter_by_ext(fileinfo, ext.clone()),
diff --git a/src/fm_error.rs b/src/fm_error.rs
index 59d2ab2..a7bc39e 100644
--- a/src/fm_error.rs
+++ b/src/fm_error.rs
@@ -8,6 +8,8 @@ use notify_rust::error::Error as NotifyError;
use strfmt::FmtError;
use tuikit::error::TuikitError;
+/// Different variant of errors, depending on what caused the error.
+/// If the error is custom made, a string depicts the problem more precisely.
#[derive(Debug)]
pub enum ErrorVariant {
IO,
@@ -25,9 +27,11 @@ pub enum ErrorVariant {
STRUM,
COMPRESSTOOLS,
IMAGEERROR,
+ SERDEYAML,
CUSTOM(String),
}
+/// Default error used in whole application.
#[derive(Debug)]
pub struct FmError {
variant: ErrorVariant,
@@ -35,6 +39,7 @@ pub struct FmError {
}
impl FmError {
+ /// Creates a new `FmError` with a variant and a message.
pub fn new(variant: ErrorVariant, msg: &str) -> Self {
info!("FmError. Variant: {:?} - msg: {}", variant, msg);
Self {
@@ -150,4 +155,12 @@ impl From<image::error::ImageError> for FmError {
Self::new(ErrorVariant::IMAGEERROR, &error.to_string())
}
}
+
+impl From<serde_yaml::Error> for FmError {
+ fn from(error: serde_yaml::Error) -> Self {
+ Self::new(ErrorVariant::SERDEYAML, &error.to_string())
+ }
+}
+
+/// A Result with type `T` and `FmError`.
pub type FmResult<T> = Result<T, FmError>;
diff --git a/src/git.rs b/src/git.rs
index ab6cf1f..af63936 100644
--- a/src/git.rs
+++ b/src/git.rs
@@ -75,6 +75,8 @@ fn parse_porcelain2(data: String) -> Option<GitStatus> {
Some(status)
}
+/// Returns a string representation of the git status of this path.
+/// Will return an empty string if we're not in a git repository.
pub fn git(path: &Path) -> Result<String, Box<dyn Error>> {
if std::env::set_current_dir(path).is_err() {
// The path may not exist. It should never happen.
diff --git a/src/help.rs b/src/help.rs
index 87283bc..8a63edc 100644
--- a/src/help.rs
+++ b/src/help.rs
@@ -70,11 +70,16 @@ static HELP_TO_FORMAT: &str = "
{ModeNormal}: NORMAL
";
+/// Holds the help string, formated with current keybindings.
pub struct Help {
+ /// The help string, formated with current keybindings.
pub help: String,
}
impl Help {
+ /// Creates an Help instance from keybindings.
+ /// If multiple keybindings are bound to the same action, the last one
+ /// is displayed.
pub fn from_keybindings(binds: &Bindings) -> FmResult<Self> {
let help = strfmt(HELP_TO_FORMAT, &binds.keybind_reversed())?;
Ok(Self { help })
diff --git a/src/input.rs b/src/input.rs
index d99e7cb..e4da28b 100644
--- a/src/input.rs
+++ b/src/input.rs
@@ -2,7 +2,9 @@
/// Methods allow mutation of this string and movement of the cursor.
#[derive(Clone)]
pub struct Input {
+ /// The input string typed by the user
pub string: String,
+ /// The index of the cursor in that string
pub cursor_index: usize,
}
diff --git a/src/keybindings.rs b/src/keybindings.rs
index 88c7bed..24c187d 100644
--- a/src/keybindings.rs
+++ b/src/keybindings.rs
@@ -7,8 +7,11 @@ use tuikit::prelude::{from_keyname, Key};
use crate::action_map::ActionMap;
use crate::fm_error::FmResult;
+/// Holds an hashmap between keys and actions.
#[derive(Clone, Debug)]
pub struct Bindings {
+ /// An HashMap of key & Actions.
+ /// Every binded key is linked to its corresponding action
pub binds: HashMap<Key, ActionMap>,
}
@@ -81,10 +84,13 @@ impl Bindings {
Self { binds }
}
+ /// Returns an Option of action. None if the key isn't binded.
pub fn get(&self, key: &Key) -> Option<&ActionMap> {
self.binds.get(key)
}
+ /// Reverse the hashmap of keys.
+ /// Used to format the help string.
pub fn keybind_reversed(&self) -> HashMap<String, String> {
self.binds
.clone()
@@ -93,6 +99,8 @@ impl Bindings {
.collect()
}
+ /// Update the binds from a config file.
+ /// It may fail (and leave keybinding intact) if the file isn't formated properly.
pub fn update_from_config(&mut self, yaml: &serde_yaml::value::Value) -> FmResult<()> {
for yaml_key in yaml.as_mapping().unwrap().keys() {
if let Some(key_string) = yaml_key.as_str() {
diff --git a/src/log.rs b/src/log.rs
index ea03310..c49110b 100644
--- a/src/log.rs
+++ b/src/log.rs
@@ -32,6 +32,9 @@ fn create_log_folder(log_path: &str) -> FmResult<String> {
Ok(parent.to_string_lossy().to_string())
}
+/// Creates a default logger with rotating file logs.
+/// 3 files à 5KB each are maintened.
+/// The log files are located in $HOME/username/.config/fm
pub fn set_logger() -> FmResult<Handle> {
let log_path = shellexpand::tilde(LOG_PATH).to_string();
eprintln!("log path: {}", log_path);
diff --git a/src/main.rs b/src/main.rs
index 74c5799..51710d4 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -11,13 +11,14 @@ use fm::help::Help;
use fm::log::set_logger;
use fm::status::Status;
use fm::term_manager::{Display, EventReader};
-use fm::utils::{init_term, print_on_quit};
+use fm::utils::{drop_everything, init_term, print_on_quit};
static CONFIG_PATH: &str = "~/.config/fm/config.yaml";
/// Main function
-/// Init the status and display and listen to events from keyboard and mouse.
+/// Init the status and display and listen to events (keyboard, mouse, resize, custom...).
/// The application is redrawn after every event.
+/// When the user issues a quit event, the main loop is broken and we reset the cursor.
fn main() -> FmResult<()> {
set_logger()?;
info!("fm is starting");
@@ -32,17 +33,19 @@ fn main() -> FmResult<()> {
let mut status = Status::new(Args::parse(), config, display.height()?, term.clone(), help)?;
while let Ok(event) = event_reader.poll_event() {
- event_dispatcher.read_event(&mut status, event)?;
+ event_dispatcher.dispatch(&mut status, event)?;
status.refresh_disks();
-
display.display_all(&status)?;
if status.selected_non_mut().must_quit() {
break;
};
}
+
display.show_cursor()?;
- print_on_quit(term, event_dispatcher, event_reader, status, display);
+ let final_path = status.selected_path_str();
+ drop_everything(term, event_dispatcher, event_reader, status, display);
+ print_on_quit(final_path);
info!("fm is shutting down");
Ok(())
}
diff --git a/src/marks.rs b/src/marks.rs
index 5963b58..ef6b811 100644
--- a/src/marks.rs
+++ b/src/marks.rs
@@ -7,12 +7,17 @@ use crate::fm_error::{ErrorVariant, FmError, FmResult};
static MARKS_FILEPATH: &str = "~/.config/fm/marks.cfg";
+/// Holds the marks created by the user.
+/// It's a map between any char (except :) and a PathBuf.
pub struct Marks {
save_path: PathBuf,
marks: HashMap<char, PathBuf>,
}
impl Marks {
+ /// Reads the marks stored in the config file (~/.config/fm/marks.cfg).
+ /// If an invalid marks is read, only the valid ones are kept
+ /// and the file is saved again.
pub fn read_from_config_file() -> Self {
let path = PathBuf::from(shellexpand::tilde(&MARKS_FILEPATH).to_string());
Self::read_from_file(path)
@@ -38,6 +43,7 @@ impl Marks {
marks
}
+ /// Returns an optional marks associated to a char bind.
pub fn get(&self, ch: char) -> Option<&PathBuf> {
self.marks.get(&ch)
}
@@ -62,6 +68,8 @@ impl Marks {
}
}
+ /// Store a new mark in the config file.
+ /// All the marks are saved again.
pub fn new_mark(&mut self, ch: char, path: PathBuf) -> FmResult<()> {
if ch == ':' {
return Err(FmError::new(
@@ -94,6 +102,7 @@ impl Marks {
.to_owned())
}
+ /// Returns a vector of strings like "d: /dev" for every mark.
pub fn as_strin