diff options
author | Canop <cano.petrole@gmail.com> | 2020-07-14 21:58:12 +0200 |
---|---|---|
committer | Canop <cano.petrole@gmail.com> | 2020-07-14 21:58:12 +0200 |
commit | d198f840c44118bc7e9af0bd03c2db9bcb1d699f (patch) | |
tree | 46f6b2c2b08f550963018a8f18bfc8e1836c35d3 | |
parent | cc83313ef6d6ef076699207e3e92b64390f70afd (diff) |
chars in binary preview
-rw-r--r-- | src/app/app.rs | 11 | ||||
-rw-r--r-- | src/browser/browser_state.rs | 3 | ||||
-rw-r--r-- | src/display/areas.rs | 19 | ||||
-rw-r--r-- | src/display/displayable_tree.rs | 118 | ||||
-rw-r--r-- | src/display/mod.rs | 12 | ||||
-rw-r--r-- | src/display/permissions.rs | 147 | ||||
-rw-r--r-- | src/hex/hex_view.rs | 55 | ||||
-rw-r--r-- | src/preview/preview_state.rs | 10 | ||||
-rw-r--r-- | src/skin/style_map.rs | 2 |
9 files changed, 237 insertions, 140 deletions
diff --git a/src/app/app.rs b/src/app/app.rs index 768dc6f..1792165 100644 --- a/src/app/app.rs +++ b/src/app/app.rs @@ -51,7 +51,7 @@ impl App { )? .expect("Failed to create BrowserState"), ), - Areas::create(&mut Vec::new(), 0, screen)?, + Areas::create(&mut Vec::new(), 0, screen, false)?, con, ); Ok(App { @@ -90,14 +90,14 @@ impl App { fn close_panel(&mut self, panel_idx: usize, screen: &Screen) -> bool { let active_panel_id = self.panels[self.active_panel_idx].id; if let Ok(removed_panel) = self.panels.remove(panel_idx) { - Areas::resize_all(self.panels.as_mut_slice(), screen) - .expect("removing a panel should be easy"); if self.preview == Some(removed_panel.id) { self.preview = None; } else if self.panels.has_len(1) && self.preview.is_some() { info!("closing because only the preview panel is left"); return false; } + Areas::resize_all(self.panels.as_mut_slice(), screen, self.preview.is_some()) + .expect("removing a panel should be easy"); self.active_panel_idx = self.panels.iter() .position(|p| p.id == active_panel_id) .unwrap_or(self.panels.len().get()-1); @@ -220,7 +220,8 @@ impl App { } else { self.active_panel_idx }; - match Areas::create(self.panels.as_mut_slice(), insertion_idx, screen) { + let with_preview = purpose.is_preview() || self.preview.is_some(); + match Areas::create(self.panels.as_mut_slice(), insertion_idx, screen, with_preview) { Ok(areas) => { let panel_id = self.created_panels_count.into(); let mut panel = Panel::new(panel_id, state, areas, con); @@ -419,7 +420,7 @@ impl App { } Event::Resize(w, h) => { screen.set_terminal_size(w, h, con); - Areas::resize_all(self.panels.as_mut_slice(), screen)?; + Areas::resize_all(self.panels.as_mut_slice(), screen, self.preview.is_some())?; for panel in &mut self.panels { panel.mut_state().refresh(screen, con); } diff --git a/src/browser/browser_state.rs b/src/browser/browser_state.rs index 579eadf..0dcfc16 100644 --- a/src/browser/browser_state.rs +++ b/src/browser/browser_state.rs @@ -460,7 +460,8 @@ impl AppState for BrowserState { } Internal::panel_left => { if cc.areas.is_first() { - if cc.preview.is_some() && cc.areas.nb_pos == 2 { + //if cc.preview.is_some() && cc.areas.nb_pos == 2 { + if cc.preview.is_some() && self.selected_path().is_file() { AppStateCmdResult::ClosePanel { validate_purpose: false, id: cc.preview, diff --git a/src/display/areas.rs b/src/display/areas.rs index 01685d4..888e25f 100644 --- a/src/display/areas.rs +++ b/src/display/areas.rs @@ -38,6 +38,7 @@ impl Areas { present_panels: &mut [Panel], mut insertion_idx: usize, screen: &Screen, + with_preview: bool, // slightly larger last panel ) -> Result<Self, ProgramError> { if insertion_idx > present_panels.len() { insertion_idx = present_panels.len(); @@ -58,27 +59,37 @@ impl Areas { for i in insertion_idx..present_panels.len() { slots.push(Slot::Panel(i)); } - Self::compute_areas(present_panels, &mut slots, screen)?; + Self::compute_areas(present_panels, &mut slots, screen, with_preview)?; Ok(areas) } - pub fn resize_all(panels: &mut [Panel], screen: &Screen) -> Result<(), ProgramError> { + pub fn resize_all( + panels: &mut [Panel], + screen: &Screen, + with_preview: bool, // slightly larger last panel + ) -> Result<(), ProgramError> { let mut slots = Vec::new(); for i in 0..panels.len() { slots.push(Slot::Panel(i)); } - Self::compute_areas(panels, &mut slots, screen) + Self::compute_areas(panels, &mut slots, screen, with_preview) } fn compute_areas( panels: &mut [Panel], slots: &mut Vec<Slot>, screen: &Screen, + with_preview: bool, // slightly larger last panel ) -> Result<(), ProgramError> { if screen.height < MINIMAL_PANEL_HEIGHT { return Err(ProgramError::TerminalTooSmallError); } - let mut panel_width = screen.width / slots.len() as u16; + let n = slots.len() as u16; + let mut panel_width = if with_preview { + 4 * screen.width / (4 * n + 1) + } else { + screen.width / n + }; if panel_width < MINIMAL_PANEL_WIDTH { return Err(ProgramError::TerminalTooSmallError); } diff --git a/src/display/displayable_tree.rs b/src/display/displayable_tree.rs index fa65243..15b2898 100644 --- a/src/display/displayable_tree.rs +++ b/src/display/displayable_tree.rs @@ -7,6 +7,7 @@ use { GitStatusDisplay, LONG_SPACE, LONG_BRANCH, MatchedString, + PermWriter, }, crate::{ content_search::ContentMatch, @@ -28,9 +29,6 @@ use { termimad::{CompoundStyle, ProgressBar}, }; -#[cfg(unix)] -use {crate::permissions, std::os::unix::fs::MetadataExt, umask::*}; - /// A tree wrapper which can be used either /// - to write on the screen in the application, /// - or to write in a file or an exported string. @@ -184,97 +182,6 @@ impl<'s, 't> DisplayableTree<'s, 't> { Ok(1) } - #[cfg(unix)] - fn write_mode<'w, W: Write>( - &self, - cw: &mut CropWriter<'w, W>, - mode: Mode, - selected: bool, - ) -> Result<(), termimad::Error> { - cond_bg!(n_style, self, selected, self.skin.perm__); - cond_bg!(r_style, self, selected, self.skin.perm_r); - cond_bg!(w_style, self, selected, self.skin.perm_w); - cond_bg!(x_style, self, selected, self.skin.perm_x); - - if mode.has(USER_READ) { - cw.queue_char(r_style, 'r')?; - } else { - cw.queue_char(n_style, '_')?; - } - if mode.has(USER_WRITE) { - cw.queue_char(w_style, 'w')?; - } else { - cw.queue_char(n_style, '_')?; - } - if mode.has(USER_EXEC) { - cw.queue_char(x_style, 'x')?; - } else { - cw.queue_char(n_style, '_')?; - } - - if mode.has(GROUP_READ) { - cw.queue_char(r_style, 'r')?; - } else { - cw.queue_char(n_style, '_')?; - } - if mode.has(GROUP_WRITE) { - cw.queue_char(w_style, 'w')?; - } else { - cw.queue_char(n_style, '_')?; - } - if mode.has(GROUP_EXEC) { - cw.queue_char(x_style, 'x')?; - } else { - cw.queue_char(n_style, '_')?; - } - - if mode.has(OTHERS_READ) { - cw.queue_char(r_style, 'r')?; - } else { - cw.queue_char(n_style, '_')?; - } - if mode.has(OTHERS_WRITE) { - cw.queue_char(w_style, 'w')?; - } else { - cw.queue_char(n_style, '_')?; - } - if mode.has(OTHERS_EXEC) { - cw.queue_char(x_style, 'x')?; - } else { - cw.queue_char(n_style, '_')?; - } - - Ok(()) - } - - #[cfg(unix)] - fn write_permissions<'w, W: Write>( - &self, - cw: &mut CropWriter<'w, W>, - line: &TreeLine, - user_group_max_lengths: (usize, usize), - selected: bool, - ) -> Result<usize, ProgramError> { - Ok(if line.is_selectable() { - self.write_mode(cw, line.mode(), selected)?; - let owner = permissions::user_name(line.metadata.uid()); - cond_bg!(owner_style, self, selected, self.skin.owner); - cw.queue_string( - &owner_style, - format!(" {:w$}", &owner, w = user_group_max_lengths.0), - )?; - let group = permissions::group_name(line.metadata.gid()); - cond_bg!(group_style, self, selected, self.skin.group); - cw.queue_string( - &group_style, - format!(" {:w$}", &group, w = user_group_max_lengths.1), - )?; - 1 - } else { - 9 + 1 + user_group_max_lengths.0 + 1 + user_group_max_lengths.1 + 1 - }) - } - fn write_branch<'w, W: Write>( &self, cw: &mut CropWriter<'w, W>, @@ -329,7 +236,6 @@ impl<'s, 't> DisplayableTree<'s, 't> { }; let mut cloned_style; if let Some(ext_color) = line.extension().and_then(|ext| self.ext_colors.get(ext)) { - debug!("extension: {:?}", ext_color); cloned_style = style.clone(); cloned_style.set_fg(ext_color); style = &cloned_style; @@ -437,9 +343,10 @@ impl<'s, 't> DisplayableTree<'s, 't> { /// write the whole tree on the given `W` pub fn write_on<W: Write>(&self, f: &mut W) -> Result<(), ProgramError> { - let tree = self.tree; #[cfg(unix)] - let user_group_max_lengths = user_group_max_lengths(&tree); + let perm_writer = PermWriter::for_tree(&self.skin, &self.tree); + + let tree = self.tree; let total_size = tree.total_sum(); let scrollbar = if self.in_app { self.area.scrollbar(tree.scroll, tree.lines.len() as i32 - 1) @@ -499,7 +406,7 @@ impl<'s, 't> DisplayableTree<'s, 't> { #[cfg(unix)] Col::Permission if tree.options.show_permissions => { - self.write_permissions(cw, line, user_group_max_lengths, selected)? + perm_writer.write_permissions(cw, line, selected)? } Col::Date if tree.options.show_dates => { @@ -570,18 +477,3 @@ impl<'s, 't> DisplayableTree<'s, 't> { } } -#[cfg(unix)] -fn user_group_max_lengths(tree: &Tree) -> (usize, usize) { - let mut max_user_len = 0; - let mut max_group_len = 0; - if tree.options.show_permissions { - for i in 1..tree.lines.len() { - let line = &tree.lines[i]; - let user = permissions::user_name(line.metadata.uid()); - max_user_len = max_user_len.max(user.len()); - let group = permissions::group_name(line.metadata.gid()); - max_group_len = max_group_len.max(group.len()); - } - } - (max_user_len, max_group_len) -} diff --git a/src/display/mod.rs b/src/display/mod.rs index c2ed980..46bdbbb 100644 --- a/src/display/mod.rs +++ b/src/display/mod.rs @@ -31,7 +31,8 @@ pub mod status_line; mod matched_string; mod screen; -use std::io::BufWriter; +#[cfg(unix)] +mod permissions; pub use { areas::Areas, @@ -43,6 +44,11 @@ pub use { screen::Screen, }; +#[cfg(unix)] +pub use { + permissions::PermWriter, +}; + pub static LONG_SPACE: &str = " "; pub static LONG_BRANCH: &str = "───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────"; @@ -52,10 +58,10 @@ pub static LONG_BRANCH: &str = "──────────────── pub const WIDE_STATUS: bool = true; /// the type used by all GUI writing functions -pub type W = BufWriter<std::io::Stderr>; +pub type W = std::io::BufWriter<std::io::Stderr>; /// return the writer used by the application pub fn writer() -> W { - BufWriter::new(std::io::stderr()) + std::io::BufWriter::new(std::io::stderr()) } diff --git a/src/display/permissions.rs b/src/display/permissions.rs new file mode 100644 index 0000000..2b797c5 --- /dev/null +++ b/src/display/permissions.rs @@ -0,0 +1,147 @@ +use { + super::{ + CropWriter, + }, + crate::{ + errors::ProgramError, + permissions, + skin::StyleMap, + tree::{Tree, TreeLine}, + }, + std::{ + io::Write, + os::unix::fs::MetadataExt, + }, + umask::*, +}; + +/// an object which writes file permissions (mode, owner, group) +pub struct PermWriter<'s> { + pub skin: &'s StyleMap, + max_user_len: usize, + max_group_len: usize, +} + +impl<'s> PermWriter<'s> { + + pub fn new( + skin: &'s StyleMap, + max_user_len: usize, + max_group_len: usize, + ) -> Self { + Self { skin, max_user_len, max_group_len } + } + + pub fn for_tree( + skin: &'s StyleMap, + tree: &Tree, + ) -> Self { + let (max_user_len, max_group_len) = user_group_max_lengths(tree); + Self::new(skin, max_user_len, max_group_len) + } + + fn write_mode<'w, W: Write>( + &self, + cw: &mut CropWriter<'w, W>, + mode: Mode, + selected: bool, + ) -> Result<(), termimad::Error> { + cond_bg!(n_style, self, selected, self.skin.perm__); + cond_bg!(r_style, self, selected, self.skin.perm_r); + cond_bg!(w_style, self, selected, self.skin.perm_w); + cond_bg!(x_style, self, selected, self.skin.perm_x); + + if mode.has(USER_READ) { + cw.queue_char(r_style, 'r')?; + } else { + cw.queue_char(n_style, '_')?; + } + if mode.has(USER_WRITE) { + cw.queue_char(w_style, 'w')?; + } else { + cw.queue_char(n_style, '_')?; + } + if mode.has(USER_EXEC) { + cw.queue_char(x_style, 'x')?; + } else { + cw.queue_char(n_style, '_')?; + } + + if mode.has(GROUP_READ) { + cw.queue_char(r_style, 'r')?; + } else { + cw.queue_char(n_style, '_')?; + } + if mode.has(GROUP_WRITE) { + cw.queue_char(w_style, 'w')?; + } else { + cw.queue_char(n_style, '_')?; + } + if mode.has(GROUP_EXEC) { + cw.queue_char(x_style, 'x')?; + } else { + cw.queue_char(n_style, '_')?; + } + + if mode.has(OTHERS_READ) { + cw.queue_char(r_style, 'r')?; + } else { + cw.queue_char(n_style, '_')?; + } + if mode.has(OTHERS_WRITE) { + cw.queue_char(w_style, 'w')?; + } else { + cw.queue_char(n_style, '_')?; + } + if mode.has(OTHERS_EXEC) { + cw.queue_char(x_style, 'x')?; + } else { + cw.queue_char(n_style, '_')?; + } + + Ok(()) + } + + #[cfg(unix)] + pub fn write_permissions<'w, W: Write>( + &self, + cw: &mut CropWriter<'w, W>, + line: &TreeLine, + selected: bool, + ) -> Result<usize, ProgramError> { + Ok(if line.is_selectable() { + self.write_mode(cw, line.mode(), selected)?; + let owner = permissions::user_name(line.metadata.uid()); + cond_bg!(owner_style, self, selected, self.skin.owner); + cw.queue_string( + &owner_style, + format!(" {:w$}", &owner, w = self.max_user_len), + )?; + let group = permissions::group_name(line.metadata.gid()); + cond_bg!(group_style, self, selected, self.skin.group); + cw.queue_string( + &group_style, + format!(" {:w$}", &group, w = self.max_group_len), + )?; + 1 + } else { + 9 + 1 + self.max_user_len + 1 + self.max_group_len + 1 + }) + } + +} + +fn user_group_max_lengths(tree: &Tree) -> (usize, usize) { + let mut max_user_len = 0; + let mut max_group_len = 0; + if tree.options.show_permissions { + for i in 1..tree.lines.len() { + let line = &tree.lines[i]; + let user = permissions::user_name(line.metadata.uid()); + max_user_len = max_user_len.max(user.len()); + let group = permissions::group_name(line.metadata.gid()); + max_group_len = max_group_len.max(group.len()); + } + } + (max_user_len, max_group_len) +} diff --git a/src/hex/hex_view.rs b/src/hex/hex_view.rs index e2b7672..c4c8525 100644 --- a/src/hex/hex_view.rs +++ b/src/hex/hex_view.rs @@ -11,7 +11,7 @@ use { }, crossterm::{ cursor, - style::{Color, Print, ResetColor, SetBackgroundColor, SetForegroundColor}, + style::{Color, Print, SetForegroundColor}, QueueableCommand, }, memmap::Mmap, @@ -92,9 +92,31 @@ impl HexView { self.page_height = area.height as i32; let page = self.get_page(self.scroll as usize, line_count)?; let styles = &panel_skin.styles; - let mut show_middle_space = false; - if area.width > 50 { - show_middle_space = true; + let mut left_margin = false; + let mut hex_middle_space = false; + let mut chars_middle_space = false; + let mut inter_hex = false; + let mut chars = false; + let mut rem = area.width as i32 - 32; // 32: minimum, tight + if rem > 17 { + chars = true; + rem -= 17; + } + if rem > 16 { + inter_hex = true; + rem -= 16; + } + if rem > 1 { + hex_middle_space = true; + rem -= 1; + } + if rem > 1 { + left_margin = true; + rem -= 1; + } + if rem > 1 { + chars_middle_space = true; + //rem -= 1; } let scrollbar = area.scrollbar(self.scroll, self.line_count() as i32); let scrollbar_fg = styles.scrollbar_thumb.get_fg() @@ -105,16 +127,35 @@ impl HexView { let mut cw = CropWriter::new(w, area.width as usize - 1); // -1 for scrollbar let cw = &mut cw; if y < page.len() { + if left_margin { + cw.queue_char(&styles.default, ' ')?; + } let line = &page[y]; for x in 0..16 { - if x==8 && show_middle_space { + if x==8 && hex_middle_space { cw.queue_char(&styles.default, ' ')?; } if let Some(b) = line.bytes.get(x) { let byte = Byte::from(*b); - cw.queue_string(byte.style(styles), format!(" {:02x}", b))?; + if inter_hex { + cw.queue_string(byte.style(styles), format!("{:02x} ", b))?; + } else { + cw.queue_string(byte.style(styles), format!("{:02x}", b))?; + } } else { - cw.queue_str(&styles.default, " ")?; + cw.queue_str(&styles.default, if inter_hex { " " } else { " " })?; + } + } + if chars { + cw.queue_char(&styles.default, ' ')?; + for x in 0..16 { + if x==8 && chars_middle_space { + cw.queue_char(&styles.default, ' ')?; + } + if let Some(b) = line.bytes.get(x) { + let byte = Byte::from(*b); + cw.queue_char(byte.style(styles), byte.as_char())?; + } } } cw.fill(&styles.default, LONG_SPACE)?; diff --git a/src/preview/preview_state.rs b/src/preview/preview_state.rs index ebc88f3..ace6b87 100644 --- a/src/preview/preview_state.rs +++ b/src/preview/preview_state.rs @@ -90,17 +90,15 @@ impl AppState for PreviewState { panel_skin.styles.default.queue_bg(w)?; screen.clear_area_to_right(w, &state_area)?; self.preview_area = state_area.clone(); - self.preview_area.height -= 2; - self.preview_area.top += 2; + self.preview_area.height -= 1; + self.preview_area.top += 1; self.dirty = false; } let styles = &panel_skin.styles; w.queue(cursor::MoveTo(state_area.left, 0))?; let mut cw = CropWriter::new(w, state_area.width as usize); - cw.queue_str(&styles.file, &self.file_name)?; - cw.fill(&styles.file, LONG_SPACE)?; - - debug!("display preview on {:?}", &self.path); + cw.queue_str(&styles.default, &self.file_name)?; + cw.fill(&styles.default, LONG_SPACE)?; self.preview.display(w, screen, panel_skin, &self.preview_area) } diff --git a/src/skin/style_map.rs b/src/skin/style_map.rs index c7f6ffa..1ac2f55 100644 --- a/src/skin/style_map.rs +++ b/src/skin/style_map.rs @@ -140,7 +140,7 @@ StyleMap! { git_status_ignored: gray(17), None, [] git_status_conflicted: ansi(88), None, [] git_status_other: ansi(88), None, [] - selected_line: None, gray(5), [] / None, gray(4), [] + selected_line: None, gray(6), [] / None, gray(4), [] char_match: Some(Green), None, [] file_error: Some(Red), None, [] flag_label: gray(15), gray(2), [] |