summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--development.md3
-rw-r--r--readme.md10
-rw-r--r--src/args.rs18
-rw-r--r--src/shell_menu.rs17
-rw-r--r--src/status.rs70
-rw-r--r--src/tab.rs26
6 files changed, 94 insertions, 50 deletions
diff --git a/development.md b/development.md
index 06033fd..8ef539a 100644
--- a/development.md
+++ b/development.md
@@ -577,6 +577,9 @@ New view: Tree ! Toggle with 't', fold with 'z'. Navigate normally.
- [x] refresh every 10 seconds. If no file in current dir has changed, nothing happens.
- [x] scroll in preview second screen
- [x] FIX sending `Event::User(())` events from refresher hangs skim. Use `Event(Key::AltPageUp)` which is now reserved.
+- [x] allow file selection from args : -f filename selects a file
+- [x] more args : dual pane, preview second, display full, show hidden
+- [ ] document filepicking (from my config etc.).
- [ ] avoid multiple refreshs if we edit files ourself
## TODO
diff --git a/readme.md b/readme.md
index 8fa797a..974e060 100644
--- a/readme.md
+++ b/readme.md
@@ -11,16 +11,16 @@ Written in rust.
[docrs]: https://docs.rs/fm-tui/0.1.0
```
-FM : dired like file manager
-
+A TUI file manager inspired by dired and ranger
Usage: fm [OPTIONS]
Options:
-p, --path <PATH> Starting path [default: .]
-s, --server <SERVER> Nvim server [default: ]
- -h, --help Print help information
- -V, --version Print version information
+ -f, --file <FILE> Selected file [default: .]
+ -h, --help Print help
+ -V, --version Print version
```
## Platform
@@ -100,7 +100,7 @@ Many ways to jump somewhere :
- Toggle the tree view with t. Fold selected folder with z. Unfold every folder with Z, fold every folder with Alt+z.
- Enter preview mode with Alt+P. Every file is previewed in the second pane.
- Filter the view (by extension, name, directory only, all files) with F
-- Find files with / (with completion: Tab, enter to search),
+- Find files with / (with completion: Tab, enter to search),
- flag files matching a regex with w
### Fuzzy finder
diff --git a/src/args.rs b/src/args.rs
index 4034d44..f49a697 100644
--- a/src/args.rs
+++ b/src/args.rs
@@ -4,11 +4,27 @@ use clap::Parser;
#[clap(author, version, about)]
/// FM : dired like file manager{n}
pub struct Args {
- /// Starting path
+ /// Starting path. directory or file
#[arg(short, long, default_value_t = String::from("."))]
pub path: String,
/// Nvim server
#[arg(short, long, default_value_t = String::from(""))]
pub server: String,
+
+ /// Dual pane ? default to true
+ #[arg(short, long, default_value_t = false)]
+ pub dual: bool,
+
+ /// Display file metadata ? default to true
+ #[arg(short, long, default_value_t = false)]
+ pub metadata: bool,
+
+ /// Use second pane as preview ? default to false
+ #[arg(short = 'P', long, default_value_t = false)]
+ pub preview: bool,
+
+ /// Display all files (hidden)
+ #[arg(short, long, default_value_t = false)]
+ pub all: bool,
}
diff --git a/src/shell_menu.rs b/src/shell_menu.rs
index fb54abd..05fed46 100644
--- a/src/shell_menu.rs
+++ b/src/shell_menu.rs
@@ -21,6 +21,15 @@ impl Default for ShellMenu {
}
impl ShellMenu {
+ pub fn new(path: &str) -> Result<Self> {
+ let mut shell_menu = Self::default();
+ let file =
+ std::fs::File::open(std::path::Path::new(&shellexpand::tilde(path).to_string()))?;
+ let yaml = serde_yaml::from_reader(file)?;
+ shell_menu.update_from_file(&yaml)?;
+ Ok(shell_menu)
+ }
+
fn update_from_file(&mut self, yaml: &serde_yaml::mapping::Mapping) -> Result<()> {
for (key, mapping) in yaml.into_iter() {
let Some(command) = key.as_str() else {
@@ -86,11 +95,3 @@ impl ShellMenu {
type SBool = (String, bool);
impl_selectable_content!(SBool, ShellMenu);
-
-pub fn load_shell_menu(path: &str) -> Result<ShellMenu> {
- let mut shell_menu = ShellMenu::default();
- let file = std::fs::File::open(std::path::Path::new(&shellexpand::tilde(path).to_string()))?;
- let yaml = serde_yaml::from_reader(file)?;
- shell_menu.update_from_file(&yaml)?;
- Ok(shell_menu)
-}
diff --git a/src/status.rs b/src/status.rs
index d2cf265..4ae9f5a 100644
--- a/src/status.rs
+++ b/src/status.rs
@@ -35,7 +35,7 @@ use crate::password::{
};
use crate::preview::{Directory, Preview};
use crate::selectable_content::SelectableContent;
-use crate::shell_menu::{load_shell_menu, ShellMenu};
+use crate::shell_menu::ShellMenu;
use crate::shell_parser::ShellCommandParser;
use crate::skim::Skimer;
use crate::tab::Tab;
@@ -109,50 +109,52 @@ impl Status {
settings: &Settings,
) -> Result<Self> {
let args = Args::parse();
- let Ok(shell_menu) = load_shell_menu(TUIS_PATH) else {
- eprintln!("Couldn't load the TUIs config file at {TUIS_PATH}. See https://raw.githubusercontent.com/qkzk/fm/master/config_files/fm/tuis.yaml for an example");
- info!("Couldn't read tuis file at {TUIS_PATH}. Exiting");
- std::process::exit(1);
+ let preview_second = args.preview;
+ let start_folder = std::fs::canonicalize(std::path::PathBuf::from(&args.path))?;
+ let nvim_server = args.server.clone();
+ let display_full = args.metadata || settings.full;
+ let dual_pane = (args.dual || settings.dual) && Self::display_wide_enough(&term)?;
+
+ let Ok(shell_menu) = ShellMenu::new(TUIS_PATH) else {
+ Self::quit()
};
let cli_info = CliInfo::default();
-
let sys = System::new_with_specifics(RefreshKind::new().with_disks());
- let nvim_server = args.server.clone();
let encrypted_devices = CryptoDeviceOpener::default();
let trash = Trash::new()?;
let compression = Compresser::default();
let force_clear = false;
let bulk = Bulk::default();
- let start_folder = std::fs::canonicalize(std::path::PathBuf::from(&args.path))?;
- let dual_pane = settings.dual && term.term_size()?.0 >= MIN_WIDTH_FOR_DUAL_PANE;
+ let iso_device = None;
+ let password_holder = PasswordHolder::default();
+ let sudo_command = None;
+ let flagged = Flagged::default();
+ let marks = Marks::read_from_config_file();
+ let skimer = Skimer::new(term.clone());
+ let index = 0;
+
// unsafe because of UsersCache::with_all_users
let users_cache = unsafe { UsersCache::with_all_users() };
- let mut right_tab = Tab::new(args.clone(), height, users_cache)?;
- right_tab
- .shortcut
- .extend_with_mount_points(&Self::disks_mounts(sys.disks()));
-
// unsafe because of UsersCache::with_all_users
let users_cache2 = unsafe { UsersCache::with_all_users() };
- let mut left_tab = Tab::new(args, height, users_cache2)?;
- left_tab
- .shortcut
- .extend_with_mount_points(&Self::disks_mounts(sys.disks()));
- let iso_mounter = None;
- let password_holder = PasswordHolder::default();
- let sudo_command = None;
+ let mount_points = Self::disks_mounts(sys.disks());
+
+ let tabs = [
+ Tab::new(&args, height, users_cache, &mount_points)?,
+ Tab::new(&args, height, users_cache2, &mount_points)?,
+ ];
Ok(Self {
- tabs: [left_tab, right_tab],
- index: 0,
- flagged: Flagged::default(),
- marks: Marks::read_from_config_file(),
- skimer: Skimer::new(term.clone()),
+ tabs,
+ index,
+ flagged,
+ marks,
+ skimer,
term,
dual_pane,
- preview_second: false,
+ preview_second,
system_info: sys,
- display_full: settings.full,
+ display_full,
opener,
help,
trash,
@@ -162,7 +164,7 @@ impl Status {
force_clear,
bulk,
shell_menu,
- iso_device: iso_mounter,
+ iso_device,
cli_info,
start_folder,
password_holder,
@@ -170,6 +172,16 @@ impl Status {
})
}
+ fn display_wide_enough(term: &Arc<Term>) -> Result<bool> {
+ Ok(term.term_size()?.0 >= MIN_WIDTH_FOR_DUAL_PANE)
+ }
+
+ fn quit() -> ! {
+ eprintln!("Couldn't load the TUIs config file at {TUIS_PATH}. See https://raw.githubusercontent.com/qkzk/fm/master/config_files/fm/tuis.yaml for an example");
+ info!("Couldn't read tuis file at {TUIS_PATH}. Exiting");
+ std::process::exit(1);
+ }
+
/// Select the other tab if two are displayed. Does nother otherwise.
pub fn next(&mut self) {
if !self.dual_pane {
diff --git a/src/tab.rs b/src/tab.rs
index a0ec2f3..d0c6caf 100644
--- a/src/tab.rs
+++ b/src/tab.rs
@@ -58,24 +58,36 @@ pub struct Tab {
impl Tab {
/// Creates a new tab from args and height.
- pub fn new(args: Args, height: usize, users_cache: UsersCache) -> Result<Self> {
+ pub fn new(
+ args: &Args,
+ height: usize,
+ users_cache: UsersCache,
+ mount_points: &[&path::Path],
+ ) -> Result<Self> {
let path = std::fs::canonicalize(path::Path::new(&args.path))?;
- let directory = Directory::empty(&path, &users_cache)?;
+ let start_dir = if path.is_dir() {
+ &path
+ } else {
+ path.parent().context("")?
+ };
+ let directory = Directory::empty(start_dir, &users_cache)?;
let filter = FilterKind::All;
- let show_hidden = false;
- let path_content = PathContent::new(&path, users_cache, &filter, show_hidden)?;
- let show_hidden = false;
+ let show_hidden = args.all;
+ let mut path_content = PathContent::new(start_dir, users_cache, &filter, show_hidden)?;
let mode = Mode::Normal;
let previous_mode = Mode::Normal;
- let window = ContentWindow::new(path_content.content.len(), height);
+ let mut window = ContentWindow::new(path_content.content.len(), height);
let input = Input::default();
let completion = Completion::default();
let must_quit = false;
let preview = Preview::Empty;
let mut history = History::default();
history.push(&path);
- let shortcut = Shortcut::new(&path);
+ let mut shortcut = Shortcut::new(&path);
+ shortcut.extend_with_mount_points(mount_points);
let searched = None;
+ let index = path_content.select_file(&path);
+ window.scroll_to(index);
Ok(Self {
mode,
previous_mode,