diff --git a/examples/simple.rs b/examples/simple.rs index 7470d879..18a1bbe6 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -1,6 +1,6 @@ use std::io; -use hexyl::{BorderStyle, Printer}; +use hexyl::{BorderType, InnerSeparatorStyle, OuterBorderStyle, Printer}; fn main() { let input = vec![ @@ -13,8 +13,11 @@ fn main() { let show_color = true; let use_squeezing = false; - let border_style = BorderStyle::Unicode; + let border_type = BorderType::Unicode; + let hex_inner_separator_style = InnerSeparatorStyle::Visible; + let text_inner_separator_style = InnerSeparatorStyle::Visible; + let outer_border_style = OuterBorderStyle::Visible; - let mut printer = Printer::new(&mut handle, show_color, border_style, use_squeezing); + let mut printer = Printer::new(&mut handle, show_color, border_type, hex_inner_separator_style, text_inner_separator_style, outer_border_style, use_squeezing); printer.print_all(&input[..]).unwrap(); } diff --git a/src/bin/hexyl.rs b/src/bin/hexyl.rs index 367cc4e7..a7946136 100644 --- a/src/bin/hexyl.rs +++ b/src/bin/hexyl.rs @@ -16,7 +16,7 @@ use const_format::formatcp; use thiserror::Error as ThisError; -use hexyl::{BorderStyle, Input, Printer}; +use hexyl::{BorderType, InnerSeparatorStyle, Input, OuterBorderStyle, Printer}; const DEFAULT_BLOCK_SIZE: i64 = 512; @@ -110,6 +110,7 @@ fn run() -> Result<(), AnyhowError> { goes to an interactive terminal", ), ) + // TODO: Revisit name, value_name of border, {hex,text}_inner_separator .arg( Arg::with_name("border") .long("border") @@ -122,6 +123,39 @@ fn run() -> Result<(), AnyhowError> { or none at all", ), ) + .arg( + Arg::with_name("hex_inner_separator") + .long("hex-inner-separator") + .takes_value(true) + .value_name("STYLE") + .possible_values(&["visible", "none"]) + .default_value("visible") + .help( + "Whether or not to draw the inner separator for the hex display", // TODO: Rephrase this + ), + ) + .arg( + Arg::with_name("text_inner_separator") + .long("text-inner-separator") + .takes_value(true) + .value_name("STYLE") + .possible_values(&["visible", "none"]) + .default_value("visible") + .help( + "Whether or not to draw the inner separator for the text display", // TODO: Rephrase this + ), + ) + .arg( + Arg::with_name("outer_border") + .long("outer-border") + .takes_value(true) + .value_name("STYLE") + .possible_values(&["visible", "none"]) + .default_value("visible") + .help( + "Whether or not to draw the outer border", // TODO: Rephrase this + ), + ) .arg( Arg::with_name("display_offset") .short("o") @@ -228,11 +262,28 @@ fn run() -> Result<(), AnyhowError> { Some("auto") => atty::is(Stream::Stdout), _ => true, }; + + // TODO: Revisit name of border_type, {hex,text}_inner_separator_style - let border_style = match matches.value_of("border") { - Some("unicode") => BorderStyle::Unicode, - Some("ascii") => BorderStyle::Ascii, - _ => BorderStyle::None, + let border_type = match matches.value_of("border") { + Some("unicode") => BorderType::Unicode, + Some("ascii") => BorderType::Ascii, + _ => BorderType::None, + }; + + let hex_inner_separator_style = match matches.value_of("hex_inner_separator") { + Some("visible") => InnerSeparatorStyle::Visible, + _ => InnerSeparatorStyle::None + }; + + let text_inner_separator_style = match matches.value_of("text_inner_separator") { + Some("visible") => InnerSeparatorStyle::Visible, + _ => InnerSeparatorStyle::None + }; + + let outer_border_style = match matches.value_of("outer_border") { + Some("visible") => OuterBorderStyle::Visible, + _ => OuterBorderStyle::None }; let squeeze = !matches.is_present("nosqueezing"); @@ -251,7 +302,7 @@ fn run() -> Result<(), AnyhowError> { let stdout = io::stdout(); let mut stdout_lock = stdout.lock(); - let mut printer = Printer::new(&mut stdout_lock, show_color, border_style, squeeze); + let mut printer = Printer::new(&mut stdout_lock, show_color, border_type, hex_inner_separator_style, text_inner_separator_style, outer_border_style, squeeze); printer.display_offset(skip_offset + display_offset); printer.print_all(&mut reader).map_err(|e| anyhow!(e))?; diff --git a/src/lib.rs b/src/lib.rs index 41859da8..b93e0c8f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -71,69 +71,161 @@ impl Byte { } } -struct BorderElements { - left_corner: char, - horizontal_line: char, - column_separator: char, - right_corner: char, +struct BorderElements<'a> { + left_corner: &'a str, + horizontal_line: &'a str, + outer_separator: &'a str, + hex_inner_separator: &'a str, + text_inner_separator: &'a str, + right_corner: &'a str, } -pub enum BorderStyle { +// TODO: Revisit name of BorderType and InnerSeparatorStyle + +pub enum BorderType { Unicode, Ascii, None, } +pub enum InnerSeparatorStyle { + Visible, + None, +} + +pub enum OuterBorderStyle { + Visible, + None, +} + +struct BorderStyle { + border_type: BorderType, + hex_inner_separator_style: InnerSeparatorStyle, + text_inner_separator_style: InnerSeparatorStyle, + outer_border_style: OuterBorderStyle, +} + impl BorderStyle { fn header_elems(&self) -> Option { - match self { - BorderStyle::Unicode => Some(BorderElements { - left_corner: '┌', - horizontal_line: '─', - column_separator: '┬', - right_corner: '┐', - }), - BorderStyle::Ascii => Some(BorderElements { - left_corner: '+', - horizontal_line: '-', - column_separator: '+', - right_corner: '+', - }), - BorderStyle::None => None, + match self.outer_border_style { + OuterBorderStyle::Visible => match self.border_type { + BorderType::Unicode => Some(BorderElements { + left_corner: "┌", + horizontal_line: "─", + outer_separator: "┬", + hex_inner_separator: match self.hex_inner_separator_style { + InnerSeparatorStyle::Visible => "┬", + InnerSeparatorStyle::None => "", + }, + text_inner_separator: match self.text_inner_separator_style { + InnerSeparatorStyle::Visible => "┬", + InnerSeparatorStyle::None => "", + }, + right_corner: "┐", + }), + BorderType::Ascii => Some(BorderElements { + left_corner: "+", + horizontal_line: "-", + outer_separator: "+", + hex_inner_separator: match self.hex_inner_separator_style { + InnerSeparatorStyle::Visible => "+", + InnerSeparatorStyle::None => "", + }, + text_inner_separator: match self.text_inner_separator_style { + InnerSeparatorStyle::Visible => "+", + InnerSeparatorStyle::None => "", + }, + right_corner: "+", + }), + BorderType::None => None, + }, + OuterBorderStyle::None => None, } } fn footer_elems(&self) -> Option { - match self { - BorderStyle::Unicode => Some(BorderElements { - left_corner: '└', - horizontal_line: '─', - column_separator: '┴', - right_corner: '┘', - }), - BorderStyle::Ascii => Some(BorderElements { - left_corner: '+', - horizontal_line: '-', - column_separator: '+', - right_corner: '+', - }), - BorderStyle::None => None, + match self.outer_border_style { + OuterBorderStyle::Visible => match self.border_type { + BorderType::Unicode => Some(BorderElements { + left_corner: "└", + horizontal_line: "─", + outer_separator: "┴", + hex_inner_separator: match self.hex_inner_separator_style { + InnerSeparatorStyle::Visible => "┴", + InnerSeparatorStyle::None => "", + }, + text_inner_separator: match self.text_inner_separator_style { + InnerSeparatorStyle::Visible => "┴", + InnerSeparatorStyle::None => "", + }, + right_corner: "┘", + }), + BorderType::Ascii => Some(BorderElements { + left_corner: "+", + horizontal_line: "-", + outer_separator: "+", + hex_inner_separator: match self.hex_inner_separator_style { + InnerSeparatorStyle::Visible => "+", + InnerSeparatorStyle::None => "", + }, + text_inner_separator: match self.text_inner_separator_style { + InnerSeparatorStyle::Visible => "+", + InnerSeparatorStyle::None => "", + }, + right_corner: "+", + }), + BorderType::None => None, + }, + OuterBorderStyle::None => None, } } - - fn outer_sep(&self) -> char { - match self { - BorderStyle::Unicode => '│', - BorderStyle::Ascii => '|', - BorderStyle::None => ' ', + + fn hex_inner_separator(&self) -> &str { + match self.hex_inner_separator_style { + InnerSeparatorStyle::Visible => match self.border_type { + BorderType::Unicode => "┊", + BorderType::Ascii => "|", + BorderType::None => " ", + }, + InnerSeparatorStyle::None => "", } } - - fn inner_sep(&self) -> char { - match self { - BorderStyle::Unicode => '┊', - BorderStyle::Ascii => '|', - BorderStyle::None => ' ', + + fn text_inner_separator(&self) -> &str { + match self.text_inner_separator_style { + InnerSeparatorStyle::Visible => match self.border_type { + BorderType::Unicode => "┊", + BorderType::Ascii => "|", + BorderType::None => " ", + }, + InnerSeparatorStyle::None => "", + } + } + + fn outer_separator(&self) -> &str { + match self.border_type { + BorderType::Unicode => "│", + BorderType::Ascii => "|", + BorderType::None => " ", + } + } + + fn left_edge_separator(&self) -> &str { + match self.outer_border_style { + OuterBorderStyle::Visible => match self.border_type { + BorderType::Unicode => "│", + BorderType::Ascii => "|", + BorderType::None => "", + }, + OuterBorderStyle::None => "", + } + } + + fn right_edge_separator(&self) -> &str { + match self.border_type { + BorderType::Unicode => "│", + BorderType::Ascii => "|", + BorderType::None => "", } } } @@ -158,7 +250,11 @@ impl<'a, Writer: Write> Printer<'a, Writer> { pub fn new( writer: &'a mut Writer, show_color: bool, - border_style: BorderStyle, + // TODO: Revisit name of border_type, {hex,text}_inner_separator_style + border_type: BorderType, + hex_inner_separator_style: InnerSeparatorStyle, + text_inner_separator_style: InnerSeparatorStyle, + outer_border_style: OuterBorderStyle, use_squeeze: bool, ) -> Printer<'a, Writer> { Printer { @@ -167,7 +263,13 @@ impl<'a, Writer: Write> Printer<'a, Writer> { buffer_line: vec![], writer, show_color, - border_style, + // TODO: Revisit name of border_type, {hex,text}_inner_separator_style + border_style: BorderStyle { + border_type, + hex_inner_separator_style, + text_inner_separator_style, + outer_border_style, + }, header_was_printed: false, byte_hex_table: (0u8..=u8::max_value()) .map(|i| { @@ -207,9 +309,11 @@ impl<'a, Writer: Write> Printer<'a, Writer> { writeln!( self.writer, - "{l}{h8}{c}{h25}{c}{h25}{c}{h8}{c}{h8}{r}", + "{l}{h8}{o}{h25}{x}{h25}{o}{h8}{t}{h8}{r}", l = border_elements.left_corner, - c = border_elements.column_separator, + o = border_elements.outer_separator, + x = border_elements.hex_inner_separator, + t = border_elements.text_inner_separator, r = border_elements.right_corner, h8 = h8, h25 = h25 @@ -226,9 +330,11 @@ impl<'a, Writer: Write> Printer<'a, Writer> { writeln!( self.writer, - "{l}{h8}{c}{h25}{c}{h25}{c}{h8}{c}{h8}{r}", + "{l}{h8}{o}{h25}{x}{h25}{o}{h8}{t}{h8}{r}", l = border_elements.left_corner, - c = border_elements.column_separator, + o = border_elements.outer_separator, + x = border_elements.hex_inner_separator, + t = border_elements.text_inner_separator, r = border_elements.right_corner, h8 = h8, h25 = h25 @@ -253,9 +359,9 @@ impl<'a, Writer: Write> Printer<'a, Writer> { let _ = write!( &mut self.buffer_line, "{}{}{} ", - self.border_style.outer_sep(), + self.border_style.left_edge_separator(), formatted_string, - self.border_style.outer_sep() + self.border_style.outer_separator() ); } @@ -271,7 +377,7 @@ impl<'a, Writer: Write> Printer<'a, Writer> { match self.idx % 16 { 8 => { - let _ = write!(&mut self.buffer_line, "{} ", self.border_style.inner_sep()); + let _ = write!(&mut self.buffer_line, "{} ", self.border_style.hex_inner_separator()); } 0 => { self.print_textline()?; @@ -292,13 +398,15 @@ impl<'a, Writer: Write> Printer<'a, Writer> { self.print_position_indicator(); let _ = writeln!( &mut self.buffer_line, - "{0:1$}{4}{0:2$}{5}{0:3$}{4}{0:3$}{5}", + "{0:1$}{4}{0:2$}{6}{0:3$}{5}{0:3$}{7}", "", 24, 25, 8, - self.border_style.inner_sep(), - self.border_style.outer_sep(), + self.border_style.hex_inner_separator(), + self.border_style.text_inner_separator(), + self.border_style.outer_separator(), + self.border_style.right_edge_separator(), ); self.writer.write_all(&self.buffer_line)?; } @@ -315,8 +423,8 @@ impl<'a, Writer: Write> Printer<'a, Writer> { "", 3 * (8 - len), 1 + 3 * 8, - self.border_style.inner_sep(), - self.border_style.outer_sep(), + self.border_style.hex_inner_separator(), + self.border_style.outer_separator(), ); } else { let _ = write!( @@ -324,7 +432,7 @@ impl<'a, Writer: Write> Printer<'a, Writer> { "{0:1$}{2}", "", 3 * (16 - len), - self.border_style.outer_sep() + self.border_style.outer_separator() ); } @@ -337,7 +445,7 @@ impl<'a, Writer: Write> Printer<'a, Writer> { ); if idx == 8 { - let _ = write!(&mut self.buffer_line, "{}", self.border_style.inner_sep()); + let _ = write!(&mut self.buffer_line, "{}", self.border_style.text_inner_separator()); } idx += 1; @@ -350,8 +458,8 @@ impl<'a, Writer: Write> Printer<'a, Writer> { "", 8 - len, 8, - self.border_style.inner_sep(), - self.border_style.outer_sep(), + self.border_style.text_inner_separator(), + self.border_style.right_edge_separator(), ); } else { let _ = writeln!( @@ -359,7 +467,7 @@ impl<'a, Writer: Write> Printer<'a, Writer> { "{0:1$}{2}", "", 16 - len, - self.border_style.outer_sep() + self.border_style.right_edge_separator() ); } } @@ -375,14 +483,17 @@ impl<'a, Writer: Write> Printer<'a, Writer> { }; let _ = writeln!( &mut self.buffer_line, - "{5}{0}{1:2$}{5}{1:3$}{6}{1:3$}{5}{1:4$}{6}{1:4$}{5}", + "{8}{0}{1:2$}{7}{1:3$}{5}{1:3$}{7}{1:4$}{6}{1:4$}{9}", asterisk, "", 7, 25, 8, - self.border_style.outer_sep(), - self.border_style.inner_sep(), + self.border_style.hex_inner_separator(), + self.border_style.text_inner_separator(), + self.border_style.outer_separator(), + self.border_style.left_edge_separator(), + self.border_style.right_edge_separator(), ); } SqueezeAction::Delete => self.buffer_line.clear(), @@ -452,7 +563,7 @@ mod tests { fn assert_print_all_output(input: Reader, expected_string: String) -> () { let mut output = vec![]; - let mut printer = Printer::new(&mut output, false, BorderStyle::Unicode, true); + let mut printer = Printer::new(&mut output, false, BorderType::Unicode, InnerSeparatorStyle::Visible, InnerSeparatorStyle::Visible, OuterBorderStyle::Visible, true); printer.print_all(input).unwrap(); @@ -497,7 +608,7 @@ mod tests { let mut output = vec![]; let mut printer: Printer> = - Printer::new(&mut output, false, BorderStyle::Unicode, true); + Printer::new(&mut output, false, BorderType::Unicode, InnerSeparatorStyle::Visible, InnerSeparatorStyle::Visible, OuterBorderStyle::Visible, true); printer.display_offset(0xdeadbeef); printer.print_all(input).unwrap();