diff options
author | qkzk <qu3nt1n@gmail.com> | 2022-10-04 22:24:00 +0200 |
---|---|---|
committer | qkzk <qu3nt1n@gmail.com> | 2022-10-04 22:24:00 +0200 |
commit | c4130dd55c5fd781b4fbe0054afa298d1c417e1f (patch) | |
tree | 659fa28b0a53de1d1dd3de1b6f7663d18fab4d2f | |
parent | 8bf51e2f9efdc5cd417d942d4e50fa8046f602dc (diff) |
preview a file with Ppreview
-rw-r--r-- | config.yaml | 1 | ||||
-rw-r--r-- | readme.md | 1 | ||||
-rw-r--r-- | src/actioner.rs | 5 | ||||
-rw-r--r-- | src/config.rs | 9 | ||||
-rw-r--r-- | src/display.rs | 33 | ||||
-rw-r--r-- | src/event_char.rs | 2 | ||||
-rw-r--r-- | src/fileinfo.rs | 10 | ||||
-rw-r--r-- | src/help.rs | 2 | ||||
-rw-r--r-- | src/mode.rs | 3 | ||||
-rw-r--r-- | src/status.rs | 64 |
10 files changed, 109 insertions, 21 deletions
diff --git a/config.yaml b/config.yaml index bc9c61e..a39d053 100644 --- a/config.yaml +++ b/config.yaml @@ -40,3 +40,4 @@ keybindings: nvim: i sort_by: O symlink: S + preview: P @@ -78,6 +78,7 @@ - https://github.com/KillTheMule/nvim-rs/blob/master/examples/basic.rs - https://neovim.io/doc/user/api.html - [ ] display / event separation. use async and message passing between coroutines +- [ ] less or cat/bat a file content, window with preview ## BUGS diff --git a/src/actioner.rs b/src/actioner.rs index 490c07f..fd09ca4 100644 --- a/src/actioner.rs +++ b/src/actioner.rs @@ -43,6 +43,7 @@ impl Actioner { (keybindings.nvim, EventChar::NvimFilepicker), (keybindings.sort_by, EventChar::Sort), (keybindings.symlink, EventChar::Symlink), + (keybindings.preview, EventChar::Preview), ]); Self { binds } } @@ -207,7 +208,7 @@ impl Actioner { Mode::Goto => status.exec_goto(), Mode::RegexMatch => status.exec_regex(), Mode::Jump => status.exec_jump(), - Mode::Normal | Mode::NeedConfirmation | Mode::Help | Mode::Sort => (), + Mode::Normal | Mode::NeedConfirmation | Mode::Help | Mode::Sort | Mode::Preview => (), } status.input.reset(); @@ -248,7 +249,7 @@ impl Actioner { Some(event_char) => event_char.match_char(status), None => (), }, - Mode::Help => status.event_normal(), + Mode::Help | Mode::Preview => status.event_normal(), Mode::Jump => (), Mode::NeedConfirmation => { if c == 'y' { diff --git a/src/config.rs b/src/config.rs index 9bc9ff8..e0fa5bb 100644 --- a/src/config.rs +++ b/src/config.rs @@ -50,6 +50,7 @@ use tuikit::attr::Color; /// jump: j /// nvim: i /// sort_by: O +/// preview: S #[derive(Debug, Clone)] pub struct Config { /// Color of every kind of file @@ -200,6 +201,8 @@ pub struct Keybindings { pub sort_by: char, /// Creates asymlink pub symlink: char, + /// Preview with bat + pub preview: char, } impl Keybindings { @@ -275,9 +278,12 @@ impl Keybindings { if let Some(sort_by) = yaml["sort_by"].as_str().map(|s| s.to_string()) { self.sort_by = sort_by.chars().next().unwrap_or('O'); } - if let Some(symlink) = yaml["symblink"].as_str().map(|s| s.to_string()) { + if let Some(symlink) = yaml["symlink"].as_str().map(|s| s.to_string()) { self.symlink = symlink.chars().next().unwrap_or('S'); } + if let Some(preview) = yaml["preview"].as_str().map(|s| s.to_string()) { + self.preview = preview.chars().next().unwrap_or('P'); + } } /// Returns a new `Keybindings` instance with hardcoded values. @@ -307,6 +313,7 @@ impl Keybindings { nvim: 'i', sort_by: 'O', symlink: 'S', + preview: 'P', } } } diff --git a/src/display.rs b/src/display.rs index e38adff..38167d0 100644 --- a/src/display.rs +++ b/src/display.rs @@ -1,5 +1,7 @@ use std::cmp::min; +use std::io::BufRead; +use bat::PrettyPrinter; use tuikit::attr::*; use tuikit::term::Term; @@ -46,6 +48,7 @@ impl Display { self.help(status); self.jump_list(status); self.completion(status); + self.preview(status); } /// Reads and returns the `tuikit::term::Term` height. @@ -71,6 +74,10 @@ impl Display { Mode::NeedConfirmation => { format!("Confirm {} (y/n) : ", status.last_edition) } + Mode::Preview => match status.path_content.selected_file() { + Some(fileinfo) => format!("{:?} {}", status.mode.clone(), fileinfo.filename), + None => "".to_owned(), + }, _ => { format!("{:?} {}", status.mode.clone(), status.input.string.clone()) } @@ -151,7 +158,7 @@ impl Display { /// Display the possible completion items. The currently selected one is /// reversed. - pub fn completion(&mut self, status: &Status) { + fn completion(&mut self, status: &Status) { match status.mode { Mode::Goto | Mode::Exec | Mode::Search => { let _ = self.term.clear(); @@ -170,4 +177,28 @@ impl Display { _ => (), } } + + /// Display a preview of a file with bat + fn preview(&mut self, status: &Status) { + if let Mode::Preview = status.mode { + match status.path_content.selected_file() { + Some(file) => { + let _ = self.term.clear(); + self.first_line(status); + let attr = Attr::default(); + let reader = + std::io::BufReader::new(std::fs::File::open(file.path.clone()).unwrap()); + for (row, line) in reader.lines().enumerate() { + let _ = self.term.print_with_attr( + row + 1, + 3, + &line.unwrap_or("".to_owned()), + attr, + ); + } + } + None => (), + } + } + } } diff --git a/src/event_char.rs b/src/event_char.rs index 7f48d5c..9b3e4fc 100644 --- a/src/event_char.rs +++ b/src/event_char.rs @@ -25,6 +25,7 @@ pub enum EventChar { NvimFilepicker, Sort, Symlink, + Preview, } impl EventChar { @@ -54,6 +55,7 @@ impl EventChar { EventChar::NvimFilepicker => status.event_nvim_filepicker(), EventChar::Sort => status.event_sort(), EventChar::Symlink => status.event_symlink(), + EventChar::Preview => status.event_preview(), } } } diff --git a/src/fileinfo.rs b/src/fileinfo.rs index a56ffc6..ee91f03 100644 --- a/src/fileinfo.rs +++ b/src/fileinfo.rs @@ -306,6 +306,16 @@ impl PathContent { self.files[0].select(); } } + + /// Return the Optional FileInfo + /// Since the FileInfo is borrowed it won't be mutable. + pub fn selected_file(&self) -> Option<&FileInfo> { + if self.files.is_empty() { + None + } else { + Some(&self.files[self.selected]) + } + } } /// Associates a filetype to `tuikit::prelude::Attr` : fg color, bg color and diff --git a/src/help.rs b/src/help.rs index c03b086..1424201 100644 --- a/src/help.rs +++ b/src/help.rs @@ -19,6 +19,8 @@ PgDown: 10 lines down a: toggle hidden s: shell in current directory o: xdg-open this file +i: open in current nvim session +P: preview this file - Action on flagged files - space: toggle flag on a file diff --git a/src/mode.rs b/src/mode.rs index 07ca789..be13bcf 100644 --- a/src/mode.rs +++ b/src/mode.rs @@ -31,6 +31,8 @@ pub enum Mode { NeedConfirmation, /// Change the type of sort Sort, + /// Preview a content with bat + Preview, } impl fmt::Debug for Mode { @@ -49,6 +51,7 @@ impl fmt::Debug for Mode { Mode::Jump => write!(f, "Jump : "), Mode::NeedConfirmation => write!(f, "Y/N :"), Mode::Sort => write!(f, "(N)ame (D)ate (S)ize (E)xt (R)ev :"), + Mode::Preview => write!(f, "Preview : "), } } } diff --git a/src/status.rs b/src/status.rs index c46409b..31c577a 100644 --- a/src/status.rs +++ b/src/status.rs @@ -188,11 +188,12 @@ impl Status { } pub fn event_go_to_child(&mut self) { - if let FileKind::Directory = self.path_content.files[self.path_content.selected].file_kind { + if self.path_content.files.is_empty() { + return; + } + if let FileKind::Directory = self.path_content.selected_file().unwrap().file_kind { self.path_content = PathContent::new( - self.path_content.files[self.path_content.selected] - .path - .clone(), + self.path_content.selected_file().unwrap().path.clone(), self.show_hidden, ); self.window.reset(self.path_content.files.len()); @@ -240,6 +241,12 @@ impl Status { self.mode = Mode::Exec } + pub fn event_preview(&mut self) { + if !self.path_content.files.is_empty() { + self.mode = Mode::Preview + } + } + pub fn event_clear_flags(&mut self) { self.flagged.clear() } @@ -302,7 +309,10 @@ impl Status { } pub fn event_toggle_flag(&mut self) { - self.toggle_flag_on_path(self.path_content.files[self.file_index].path.clone()); + if self.path_content.files.is_empty() { + return; + } + self.toggle_flag_on_path(self.path_content.selected_file().unwrap().path.clone()); if self.file_index < self.path_content.files.len() - WINDOW_MARGIN_TOP { self.file_index += 1 } @@ -336,9 +346,15 @@ impl Status { } pub fn event_open_file(&mut self) { + if self.path_content.files.is_empty() { + return; + } execute_in_child( &self.opener, - &vec![self.path_content.files[self.path_content.selected] + &vec![self + .path_content + .selected_file() + .unwrap() .path .to_str() .unwrap()], @@ -350,13 +366,13 @@ impl Status { } pub fn event_chmod(&mut self) { + if self.path_content.files.is_empty() { + return; + } self.mode = Mode::Chmod; if self.flagged.is_empty() { - self.flagged.insert( - self.path_content.files[self.path_content.selected] - .path - .clone(), - ); + self.flagged + .insert(self.path_content.selected_file().unwrap().path.clone()); } } @@ -380,10 +396,13 @@ impl Status { } pub fn event_right_click(&mut self, row: u16) { + if self.path_content.files.is_empty() || row as usize > self.path_content.files.len() { + return; + } self.file_index = (row - 1).into(); self.path_content.select_index(self.file_index); self.window.scroll_to(self.file_index); - if let FileKind::Directory = self.path_content.files[self.file_index].file_kind { + if let FileKind::Directory = self.path_content.selected_file().unwrap().file_kind { self.event_go_to_child() } else { self.event_open_file() @@ -410,6 +429,9 @@ impl Status { } pub fn event_nvim_filepicker(&mut self) { + if self.path_content.files.is_empty() { + return; + } // "nvim-send --remote-send '<esc>:e readme.md<cr>' --servername 127.0.0.1:8888" let server = std::env::var("NVIM_LISTEN_ADDRESS").unwrap_or_else(|_| "".to_owned()); if server.is_empty() { @@ -421,7 +443,9 @@ impl Status { "--remote-send", &format!( "<esc>:e {}<cr><esc>:close<cr>", - self.path_content.files[self.file_index] + self.path_content + .selected_file() + .unwrap() .path .clone() .to_str() @@ -473,10 +497,11 @@ impl Status { } pub fn exec_rename(&mut self) { + if self.path_content.files.is_empty() { + return; + } fs::rename( - self.path_content.files[self.path_content.selected] - .clone() - .path, + self.path_content.selected_file().unwrap().clone().path, self.path_content .path .to_path_buf() @@ -525,11 +550,16 @@ impl Status { } pub fn exec_exec(&mut self) { + if self.path_content.files.is_empty() { + return; + } let exec_command = self.input.string.clone(); let mut args: Vec<&str> = exec_command.split(' ').collect(); let command = args.remove(0); args.push( - self.path_content.files[self.path_content.selected] + self.path_content + .selected_file() + .unwrap() .path .to_str() .unwrap(), |