summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCanop <cano.petrole@gmail.com>2020-07-14 21:58:12 +0200
committerCanop <cano.petrole@gmail.com>2020-07-14 21:58:12 +0200
commitd198f840c44118bc7e9af0bd03c2db9bcb1d699f (patch)
tree46f6b2c2b08f550963018a8f18bfc8e1836c35d3
parentcc83313ef6d6ef076699207e3e92b64390f70afd (diff)
chars in binary preview
-rw-r--r--src/app/app.rs11
-rw-r--r--src/browser/browser_state.rs3
-rw-r--r--src/display/areas.rs19
-rw-r--r--src/display/displayable_tree.rs118
-rw-r--r--src/display/mod.rs12
-rw-r--r--src/display/permissions.rs147
-rw-r--r--src/hex/hex_view.rs55
-rw-r--r--src/preview/preview_state.rs10
-rw-r--r--src/skin/style_map.rs2
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), []