Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds --columns for Print using custom width #13 #164

Merged
merged 16 commits into from
Sep 11, 2022
Merged
2 changes: 2 additions & 0 deletions examples/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ fn main() {
let show_position_panel = true;
let use_squeezing = false;
let border_style = BorderStyle::Unicode;
let columns = 2;

let mut printer = Printer::new(
&mut handle,
Expand All @@ -24,6 +25,7 @@ fn main() {
show_position_panel,
border_style,
use_squeezing,
columns,
);
printer.print_all(&input[..]).unwrap();
}
25 changes: 24 additions & 1 deletion src/bin/hexyl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ extern crate clap;
use std::convert::TryFrom;
use std::fs::File;
use std::io::{self, prelude::*, SeekFrom};
use std::num::NonZeroI64;
use std::num::{NonZeroI64, NonZeroU8};

use clap::{crate_name, crate_version, AppSettings, Arg, ColorChoice, Command};

Expand Down Expand Up @@ -149,6 +149,17 @@ fn run() -> Result<(), AnyhowError> {
A negative value is valid and calculates an offset relative to the \
end of the file.",
),
)
.arg(
Arg::new("columns")
.short('w')
.long("columns")
.takes_value(true)
.value_name("N")
.help(
"Sets the number of hex data columns to be displayed. \
Cannot be used with other width-setting options.",
sharifhsn marked this conversation as resolved.
Show resolved Hide resolved
),
);

let matches = command.get_matches();
Expand Down Expand Up @@ -267,6 +278,17 @@ fn run() -> Result<(), AnyhowError> {
.transpose()?
.unwrap_or(0);

let columns = matches
.value_of("columns")
.map(|s| {
s.parse::<NonZeroU8>().map(u8::from).context(anyhow!(
"failed to parse `--columns` arg {:?} as unsigned nonzero integer",
s
))
})
.transpose()?
.unwrap_or(2);

let stdout = io::stdout();
let mut stdout_lock = stdout.lock();

Expand All @@ -277,6 +299,7 @@ fn run() -> Result<(), AnyhowError> {
show_position_panel,
border_style,
squeeze,
columns,
);
printer.display_offset(skip_offset + display_offset);
printer.print_all(&mut reader).map_err(|e| anyhow!(e))?;
Expand Down
185 changes: 116 additions & 69 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ pub struct Printer<'a, Writer: Write> {
byte_char_panel: Vec<String>,
squeezer: Squeezer,
display_offset: u64,
/// The number of panels to draw.
columns: u8,
}

impl<'a, Writer: Write> Printer<'a, Writer> {
Expand All @@ -164,6 +166,7 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
show_position_panel: bool,
border_style: BorderStyle,
use_squeeze: bool,
columns: u8,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a breaking change for hexyl-as-a-library. This whole new method is really unfortunate. There are too many arguments even before this PR. We should really use a builder-pattern instead.

But that's not really the problem of your PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would be willing to work on implementing a builder pattern if you're committed to pushing a breaking change anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a commit ready for a builder pattern. It uses a new PrinterBuilder struct, so it can technically be implemented in a non-breaking way, although that's probably undesirable. It's quite out of scope for this pull request, so I'll submit a new one once this one is approved.

) -> Printer<'a, Writer> {
Printer {
idx: 1,
Expand All @@ -175,7 +178,7 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
show_position_panel,
border_style,
header_was_printed: false,
byte_hex_panel: (0u8..=u8::max_value())
byte_hex_panel: (0u8..=u8::MAX)
.map(|i| {
let byte_hex = format!("{:02x} ", i);
if show_color {
Expand All @@ -187,7 +190,7 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
.collect(),
byte_char_panel: show_char_panel
.then(|| {
(0u8..=u8::max_value())
(0u8..=u8::MAX)
.map(|i| {
let byte_char = format!("{}", Byte(i).as_char());
if show_color {
Expand All @@ -199,8 +202,9 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
.collect()
})
.unwrap_or_default(),
squeezer: Squeezer::new(use_squeeze),
squeezer: Squeezer::new(use_squeeze, 8 * columns as u64),
display_offset: 0,
columns,
}
}

Expand All @@ -223,10 +227,20 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
write!(self.writer, "{}", l).ok();
}

write!(self.writer, "{h25}{c}{h25}", c = c, h25 = h25).ok();
for _ in 0..self.columns - 1 {
write!(self.writer, "{h25}{c}", h25 = h25, c = c).ok();
}
if self.show_char_panel {
write!(self.writer, "{h25}{c}", h25 = h25, c = c).ok();
} else {
write!(self.writer, "{h25}", h25 = h25).ok();
}

if self.show_char_panel {
writeln!(self.writer, "{c}{h8}{c}{h8}{r}", c = c, h8 = h8, r = r).ok();
for _ in 0..self.columns - 1 {
write!(self.writer, "{h8}{c}", h8 = h8, c = c).ok();
}
writeln!(self.writer, "{h8}{r}", h8 = h8, r = r).ok();
} else {
writeln!(self.writer, "{r}", r = r).ok();
}
Expand Down Expand Up @@ -287,36 +301,30 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
self.byte_char_panel[b as usize]
);

if idx == 8 {
if idx % 8 == 0 && idx % (u64::from(self.columns * 8)) != 0 {
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()
);
if len < usize::from(8 * self.columns) {
let _ = write!(&mut self.buffer_line, "{0:1$}", "", 8 - len % 8);
for _ in 0..(usize::from(8 * self.columns) - (len + (8 - len % 8))) / 8 {
let _ = write!(
&mut self.buffer_line,
"{2}{0:1$}",
"",
8,
self.border_style.inner_sep()
);
}
}
let _ = writeln!(&mut self.buffer_line, "{}", self.border_style.outer_sep());
}

pub fn print_byte(&mut self, b: u8) -> io::Result<()> {
if self.idx % 16 == 1 {
if self.idx % u64::from(self.columns * 8) == 1 {
self.print_header();
self.print_position_panel();
}
Expand All @@ -326,14 +334,10 @@ impl<'a, Writer: Write> Printer<'a, Writer> {

self.squeezer.process(b, self.idx);

match self.idx % 16 {
8 => {
let _ = write!(&mut self.buffer_line, "{} ", self.border_style.inner_sep());
}
0 => {
self.print_textline()?;
}
_ => {}
if self.idx % u64::from(self.columns * 8) == 0 {
self.print_textline()?;
} else if self.idx % 8 == 0 {
let _ = write!(&mut self.buffer_line, "{} ", self.border_style.inner_sep());
}

self.idx += 1;
Expand All @@ -347,45 +351,57 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
if len == 0 {
if self.squeezer.active() {
self.print_position_panel();
let _ = writeln!(
write!(&mut self.buffer_line, "{0:1$}", "", 24)?;
for _ in 0..self.columns - 1 {
write!(
&mut self.buffer_line,
"{2}{0:1$}",
"",
25,
self.border_style.inner_sep()
)?;
}
write!(
&mut self.buffer_line,
"{0:1$}{4}{0:2$}{5}{0:3$}{4}{0:3$}{5}",
"{2}{0:1$}",
"",
24,
25,
8,
self.border_style.inner_sep(),
self.border_style.outer_sep(),
);
self.border_style.outer_sep()
)?;
for _ in 0..self.columns - 1 {
write!(
&mut self.buffer_line,
"{2}{0:1$}",
"",
8,
self.border_style.inner_sep()
)?;
}
writeln!(&mut self.buffer_line, "{}", self.border_style.outer_sep())?;
self.writer.write_all(&self.buffer_line)?;
}
return Ok(());
}

let squeeze_action = self.squeezer.action();

// print empty space on last line
if squeeze_action != SqueezeAction::Delete {
if len < 8 {
let _ = write!(
&mut self.buffer_line,
"{0:1$}{3}{0:2$}{4}",
"",
3 * (8 - len),
1 + 3 * 8,
self.border_style.inner_sep(),
self.border_style.outer_sep(),
);
} else {
let _ = write!(
&mut self.buffer_line,
"{0:1$}{2}",
"",
3 * (16 - len),
self.border_style.outer_sep()
);
if len < usize::from(8 * self.columns) {
write!(&mut self.buffer_line, "{0:1$}", "", 3 * (8 - len % 8))?;
// dbg!(usize::from(8 * self.columns) - (len + (8 - len % 8)));
sharifhsn marked this conversation as resolved.
Show resolved Hide resolved
for _ in 0..(usize::from(8 * self.columns) - (len + (8 - len % 8))) / 8 {
write!(
&mut self.buffer_line,
"{2}{0:1$}",
"",
1 + 3 * 8,
self.border_style.inner_sep()
)?;
}
}
write!(&mut self.buffer_line, "{}", self.border_style.outer_sep())?;
}

self.print_char_panel();

match squeeze_action {
Expand All @@ -397,17 +413,33 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
} else {
String::from("*")
};
let _ = writeln!(

write!(
&mut self.buffer_line,
"{5}{0}{1:2$}{5}{1:3$}{6}{1:3$}{5}{1:4$}{6}{1:4$}{5}",
"{3}{0}{1:2$}{3}",
asterisk,
"",
7,
25,
8,
self.border_style.outer_sep(),
self.border_style.inner_sep(),
);
self.border_style.outer_sep()
)?;

for i in 0..self.columns {
write!(&mut self.buffer_line, "{0:1$}", "", 25)?;
if i != self.columns - 1 {
write!(&mut self.buffer_line, "{}", self.border_style.inner_sep())?;
} else {
write!(&mut self.buffer_line, "{}", self.border_style.outer_sep())?;
}
}

for i in 0..self.columns {
write!(&mut self.buffer_line, "{0:1$}", "", 8)?;
if i != self.columns - 1 {
write!(&mut self.buffer_line, "{}", self.border_style.inner_sep())?;
} else {
writeln!(&mut self.buffer_line, "{}", self.border_style.outer_sep())?;
}
}
}
SqueezeAction::Delete => self.buffer_line.clear(),
SqueezeAction::Ignore => (),
Expand Down Expand Up @@ -484,7 +516,15 @@ mod tests {

fn assert_print_all_output<Reader: Read>(input: Reader, expected_string: String) {
let mut output = vec![];
let mut printer = Printer::new(&mut output, false, true, true, BorderStyle::Unicode, true);
let mut printer = Printer::new(
&mut output,
false,
true,
true,
BorderStyle::Unicode,
true,
2,
);

printer.print_all(input).unwrap();

Expand Down Expand Up @@ -528,8 +568,15 @@ mod tests {
.to_owned();

let mut output = vec![];
let mut printer: Printer<Vec<u8>> =
Printer::new(&mut output, false, true, true, BorderStyle::Unicode, true);
let mut printer: Printer<Vec<u8>> = Printer::new(
&mut output,
false,
true,
true,
BorderStyle::Unicode,
true,
2,
);
printer.display_offset(0xdeadbeef);

printer.print_all(input).unwrap();
Expand Down