From f7f744799427fd520e01ce4ecc567e5cc4631ceb Mon Sep 17 00:00:00 2001 From: Mikhail Katychev Date: Fri, 22 Apr 2022 15:33:26 -0500 Subject: [PATCH] added --plain functionality --- examples/simple.rs | 11 ++- src/bin/hexyl.rs | 38 +++++++- src/lib.rs | 191 +++++++++++++++++++++---------------- tests/integration_tests.rs | 61 ++++++++++++ 4 files changed, 219 insertions(+), 82 deletions(-) diff --git a/examples/simple.rs b/examples/simple.rs index 7470d87..1d56498 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -12,9 +12,18 @@ fn main() { let mut handle = stdout.lock(); let show_color = true; + let show_char_table = true; + let show_position_indicator = true; let use_squeezing = false; let border_style = BorderStyle::Unicode; - let mut printer = Printer::new(&mut handle, show_color, border_style, use_squeezing); + let mut printer = Printer::new( + &mut handle, + show_color, + show_char_table, + show_position_indicator, + border_style, + use_squeezing, + ); printer.print_all(&input[..]).unwrap(); } diff --git a/src/bin/hexyl.rs b/src/bin/hexyl.rs index c5b616b..9866ae6 100644 --- a/src/bin/hexyl.rs +++ b/src/bin/hexyl.rs @@ -104,24 +104,46 @@ fn run() -> Result<(), AnyhowError> { .takes_value(true) .value_name("WHEN") .possible_values(&["always", "auto", "never"]) + .default_value_if("plain", None, "never") .default_value("always") .help( "When to use colors. The auto-mode only displays colors if the output \ goes to an interactive terminal", ), ) + .arg( + Arg::with_name("plain") + .short("p") + .long("plain") + .help("Display output with --no-chars, --no-position, and --border=none."), + ) .arg( Arg::with_name("border") .long("border") .takes_value(true) .value_name("STYLE") .possible_values(&["unicode", "ascii", "none"]) + .default_value_if("plain", None, "none") .default_value("unicode") .help( "Whether to draw a border with Unicode characters, ASCII characters, \ or none at all", ), ) + .arg( + Arg::with_name("no_chars") + .short("C") + .long("no-chars") + .conflicts_with("plain") + .help("Whether to display the character table on the right."), + ) + .arg( + Arg::with_name("no_position") + .short("P") + .long("no-position") + .conflicts_with("plain") + .help("Whether to display the position indicator on the left."), + ) .arg( Arg::with_name("display_offset") .short("o") @@ -237,6 +259,13 @@ fn run() -> Result<(), AnyhowError> { let squeeze = !matches.is_present("nosqueezing"); + // -nc true && false + // -plain true && false + let show_char_table = !matches.is_present("no_chars") && !matches.is_present("plain"); + + let show_position_indicator = + !matches.is_present("no_position") && !matches.is_present("plain"); + let display_offset: u64 = matches .value_of("display_offset") .map(|s| { @@ -251,7 +280,14 @@ 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, + show_char_table, + show_position_indicator, + 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 41859da..cb23bb6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -146,6 +146,8 @@ pub struct Printer<'a, Writer: Write> { buffer_line: Vec, writer: &'a mut Writer, show_color: bool, + show_char_table: bool, + show_position_indicator: bool, border_style: BorderStyle, header_was_printed: bool, byte_hex_table: Vec, @@ -158,6 +160,8 @@ impl<'a, Writer: Write> Printer<'a, Writer> { pub fn new( writer: &'a mut Writer, show_color: bool, + show_char_table: bool, + show_position_indicator: bool, border_style: BorderStyle, use_squeeze: bool, ) -> Printer<'a, Writer> { @@ -167,6 +171,8 @@ impl<'a, Writer: Write> Printer<'a, Writer> { buffer_line: vec![], writer, show_color, + show_char_table, + show_position_indicator, border_style, header_was_printed: false, byte_hex_table: (0u8..=u8::max_value()) @@ -179,16 +185,20 @@ impl<'a, Writer: Write> Printer<'a, Writer> { } }) .collect(), - byte_char_table: (0u8..=u8::max_value()) - .map(|i| { - let byte_char = format!("{}", Byte(i).as_char()); - if show_color { - Byte(i).color().paint(byte_char).to_string() - } else { - byte_char - } + byte_char_table: show_char_table + .then(|| { + (0u8..=u8::max_value()) + .map(|i| { + let byte_char = format!("{}", Byte(i).as_char()); + if show_color { + Byte(i).color().paint(byte_char).to_string() + } else { + byte_char + } + }) + .collect() }) - .collect(), + .unwrap_or_default(), squeezer: Squeezer::new(use_squeeze), display_offset: 0, } @@ -199,42 +209,39 @@ impl<'a, Writer: Write> Printer<'a, Writer> { self } - pub fn header(&mut self) { - if let Some(border_elements) = self.border_style.header_elems() { - let h = border_elements.horizontal_line; - let h8 = h.to_string().repeat(8); - let h25 = h.to_string().repeat(25); + fn write_border(&mut self, border_elements: BorderElements) { + let h = border_elements.horizontal_line; + let c = border_elements.column_separator; + let l = border_elements.left_corner; + let r = border_elements.right_corner; + let h8 = h.to_string().repeat(8); + let h25 = h.to_string().repeat(25); - writeln!( - self.writer, - "{l}{h8}{c}{h25}{c}{h25}{c}{h8}{c}{h8}{r}", - l = border_elements.left_corner, - c = border_elements.column_separator, - r = border_elements.right_corner, - h8 = h8, - h25 = h25 - ) - .ok(); + if self.show_position_indicator { + write!(self.writer, "{l}{h8}{c}", l = l, c = c, h8 = h8).ok(); + } else { + write!(self.writer, "{}", l).ok(); + } + + write!(self.writer, "{h25}{c}{h25}", c = c, h25 = h25).ok(); + + if self.show_char_table { + writeln!(self.writer, "{c}{h8}{c}{h8}{r}", c = c, h8 = h8, r = r).ok(); + } else { + writeln!(self.writer, "{r}", r = r).ok(); } } - pub fn footer(&mut self) { - if let Some(border_elements) = self.border_style.footer_elems() { - let h = border_elements.horizontal_line; - let h8 = h.to_string().repeat(8); - let h25 = h.to_string().repeat(25); + pub fn header(&mut self) { + self.border_style + .header_elems() + .map(|e| self.write_border(e)); + } - writeln!( - self.writer, - "{l}{h8}{c}{h25}{c}{h25}{c}{h8}{c}{h8}{r}", - l = border_elements.left_corner, - c = border_elements.column_separator, - r = border_elements.right_corner, - h8 = h8, - h25 = h25 - ) - .ok(); - } + pub fn footer(&mut self) { + self.border_style + .footer_elems() + .map(|e| self.write_border(e)); } fn print_position_indicator(&mut self) { @@ -242,6 +249,10 @@ impl<'a, Writer: Write> Printer<'a, Writer> { self.header(); self.header_was_printed = true; } + if !self.show_position_indicator { + write!(&mut self.buffer_line, "{} ", self.border_style.outer_sep()).ok(); + return; + } let style = COLOR_OFFSET.normal(); let byte_index = format!("{:08x}", self.idx - 1 + self.display_offset); @@ -259,6 +270,51 @@ impl<'a, Writer: Write> Printer<'a, Writer> { ); } + pub fn print_char_table(&mut self) { + let len = self.raw_line.len(); + + if !self.show_char_table { + // just write newline if character table is hidden + writeln!(&mut self.buffer_line, "").ok(); + return; + } + + let mut idx = 1; + for &b in self.raw_line.iter() { + let _ = write!( + &mut self.buffer_line, + "{}", + self.byte_char_table[b as usize] + ); + + if idx == 8 { + let _ = write!(&mut self.buffer_line, "{}", self.border_style.inner_sep()); + } + + idx += 1; + } + + if len < 8 { + let _ = writeln!( + &mut self.buffer_line, + "{0:1$}{3}{0:2$}{4}", + "", + 8 - len, + 8, + self.border_style.inner_sep(), + self.border_style.outer_sep(), + ); + } else { + let _ = writeln!( + &mut self.buffer_line, + "{0:1$}{2}", + "", + 16 - len, + self.border_style.outer_sep() + ); + } + } + pub fn print_byte(&mut self, b: u8) -> io::Result<()> { if self.idx % 16 == 1 { self.print_position_indicator(); @@ -327,43 +383,10 @@ impl<'a, Writer: Write> Printer<'a, Writer> { self.border_style.outer_sep() ); } - - let mut idx = 1; - for &b in self.raw_line.iter() { - let _ = write!( - &mut self.buffer_line, - "{}", - self.byte_char_table[b as usize] - ); - - if idx == 8 { - let _ = write!(&mut self.buffer_line, "{}", self.border_style.inner_sep()); - } - - idx += 1; - } - - if len < 8 { - let _ = writeln!( - &mut self.buffer_line, - "{0:1$}{3}{0:2$}{4}", - "", - 8 - len, - 8, - self.border_style.inner_sep(), - self.border_style.outer_sep(), - ); - } else { - let _ = writeln!( - &mut self.buffer_line, - "{0:1$}{2}", - "", - 16 - len, - self.border_style.outer_sep() - ); - } } + self.print_char_table(); + match squeeze_action { SqueezeAction::Print => { self.buffer_line.clear(); @@ -431,11 +454,19 @@ impl<'a, Writer: Write> Printer<'a, Writer> { if !self.header_was_printed() { self.header(); - writeln!( + if self.show_position_indicator { + write!(self.writer, "{0:9}", "│").ok(); + } + write!( self.writer, - "│ │ No content to print │ │ │ │" + "{0:2}{1:24}{0}{0:>26}", + "│", "No content to print" ) .ok(); + if self.show_char_table { + write!(self.writer, "{0:>9}{0:>9}", "│").ok(); + } + writeln!(self.writer, "").ok(); } self.footer(); @@ -452,12 +483,12 @@ 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, true, true, BorderStyle::Unicode, true); printer.print_all(input).unwrap(); let actual_string: &str = str::from_utf8(&output).unwrap(); - assert_eq!(actual_string, expected_string) + assert_eq!(actual_string, expected_string,) } #[test] @@ -497,7 +528,7 @@ mod tests { let mut output = vec![]; let mut printer: Printer> = - Printer::new(&mut output, false, BorderStyle::Unicode, true); + Printer::new(&mut output, false, true, true, BorderStyle::Unicode, true); printer.display_offset(0xdeadbeef); printer.print_all(input).unwrap(); diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index bc718ad..b4a1bff 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -227,3 +227,64 @@ mod blocksize { .failure(); } } + +mod display_settings { + use super::hexyl; + + #[test] + fn plain() { + hexyl() + .arg("ascii") + .arg("--plain") + .assert() + .success() + .stdout(" 30 31 32 33 34 35 36 37 38 39 61 62 63 64 65 0a \n"); + } + + #[test] + fn no_chars() { + hexyl() + .arg("ascii") + .arg("--no-chars") + .arg("--color=never") + .assert() + .success() + .stdout( + "┌────────┬─────────────────────────┬─────────────────────────┐\n\ + │00000000│ 30 31 32 33 34 35 36 37 ┊ 38 39 61 62 63 64 65 0a │\n\ + └────────┴─────────────────────────┴─────────────────────────┘\n", + ); + } + + #[test] + fn no_position() { + hexyl() + .arg("ascii") + .arg("--no-position") + .arg("--color=never") + .assert() + .success() + .stdout( + "┌─────────────────────────┬─────────────────────────┬────────┬────────┐\n\ + │ 30 31 32 33 34 35 36 37 ┊ 38 39 61 62 63 64 65 0a │01234567┊89abcde_│\n\ + └─────────────────────────┴─────────────────────────┴────────┴────────┘\n", + ); + } + + // #[test] + // fn display_offset_and_skip() { + // hexyl() + // .arg("hello_world_elf64") + // .arg("--color=never") + // .arg("--display-offset=0x20") + // .arg("--skip=0x10") + // .arg("--length=0x10") + // .assert() + // .success() + // .stdout( + // "┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐\n\ + // │00000030│ 02 00 3e 00 01 00 00 00 ┊ 00 10 40 00 00 00 00 00 │•0>0•000┊0•@00000│\n\ + // └────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘\n", + // ); + // } +}