Complete architectural rewrite (intentionally fails)

This commit is contained in:
Sharif Haason authored and David Peter committed 2022-11-13 22:15:41 +01:00
1 parent b36d74ed9d
commit 15e8abfc9a
2 files changed
+131 -237

No files matched your search

+6 -6
View File
@@ -4,7 +4,7 @@ extern crate clap;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::fs::File; use std::fs::File;
use std::io::{self, prelude::*, BufWriter, SeekFrom}; use std::io::{self, prelude::*, BufWriter, SeekFrom};
use std::num::{NonZeroI64, NonZeroU16}; use std::num::{NonZeroI64, NonZeroU64};
use clap::{crate_name, crate_version, AppSettings, Arg, ColorChoice, Command}; use clap::{crate_name, crate_version, AppSettings, Arg, ColorChoice, Command};
@@ -294,22 +294,22 @@ fn run() -> Result<(), AnyhowError> {
.transpose()? .transpose()?
.unwrap_or(0); .unwrap_or(0);
let max_panels_fn = |terminal_width: u16| { let max_panels_fn = |terminal_width: u64| {
let offset = if show_position_panel { 10 } else { 1 }; let offset = if show_position_panel { 10 } else { 1 };
let col_width = if show_char_panel { 35 } else { 26 }; let col_width = if show_char_panel { 35 } else { 26 };
if (terminal_width - offset) / col_width < 1 { if (terminal_width - offset) / col_width < 1 {
1 1
} else { } else {
(terminal_width - offset) / col_width ((terminal_width - offset) / col_width) as u64
} }
}; };
let panels = if matches.value_of("panels") == Some("auto") { let panels = if matches.value_of("panels") == Some("auto") {
max_panels_fn(terminal_size().ok_or_else(|| anyhow!("not a TTY"))?.0 .0) max_panels_fn(terminal_size().ok_or_else(|| anyhow!("not a TTY"))?.0 .0 as u64)
} else if let Some(panels) = matches } else if let Some(panels) = matches
.value_of("panels") .value_of("panels")
.map(|s| { .map(|s| {
s.parse::<NonZeroU16>().map(u16::from).context(anyhow!( s.parse::<NonZeroU64>().map(u64::from).context(anyhow!(
"failed to parse `--panels` arg {:?} as unsigned nonzero integer", "failed to parse `--panels` arg {:?} as unsigned nonzero integer",
s s
)) ))
@@ -320,7 +320,7 @@ fn run() -> Result<(), AnyhowError> {
} else if let Some(terminal_width) = matches } else if let Some(terminal_width) = matches
.value_of("terminal_width") .value_of("terminal_width")
.map(|s| { .map(|s| {
s.parse::<NonZeroU16>().map(u16::from).context(anyhow!( s.parse::<NonZeroU64>().map(u64::from).context(anyhow!(
"failed to parse `--terminal-width` arg {:?} as unsigned nonzero integer", "failed to parse `--terminal-width` arg {:?} as unsigned nonzero integer",
s s
)) ))
+125 -231
View File
@@ -1,15 +1,12 @@
pub(crate) mod input; pub(crate) mod input;
pub mod squeezer;
pub use input::*; pub use input::*;
use std::io::{self, BufReader, Read, Write}; use std::io::{self, BufReader, ErrorKind, Read, Write};
use ansi_term::Color; use ansi_term::Color;
use ansi_term::Color::Fixed; use ansi_term::Color::Fixed;
use crate::squeezer::{SqueezeAction, Squeezer};
const COLOR_NULL: Color = Fixed(242); // grey const COLOR_NULL: Color = Fixed(242); // grey
const COLOR_OFFSET: Color = Fixed(242); // grey const COLOR_OFFSET: Color = Fixed(242); // grey
const COLOR_ASCII_PRINTABLE: Color = Color::Cyan; const COLOR_ASCII_PRINTABLE: Color = Color::Cyan;
@@ -25,6 +22,14 @@ pub enum ByteCategory {
NonAscii, NonAscii,
} }
#[derive(PartialEq)]
enum Squeezer {
Print,
Delete,
Ignore,
Disabled,
}
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
struct Byte(u8); struct Byte(u8);
@@ -144,7 +149,7 @@ pub struct PrinterBuilder<'a, Writer: Write> {
show_position_panel: bool, show_position_panel: bool,
border_style: BorderStyle, border_style: BorderStyle,
use_squeeze: bool, use_squeeze: bool,
panels: u16, panels: u64,
} }
impl<'a, Writer: Write> PrinterBuilder<'a, Writer> { impl<'a, Writer: Write> PrinterBuilder<'a, Writer> {
@@ -185,7 +190,7 @@ impl<'a, Writer: Write> PrinterBuilder<'a, Writer> {
self self
} }
pub fn num_panels(mut self, num: u16) -> Self { pub fn num_panels(mut self, num: u64) -> Self {
self.panels = num; self.panels = num;
self self
} }
@@ -218,7 +223,7 @@ pub struct Printer<'a, Writer: Write> {
squeezer: Squeezer, squeezer: Squeezer,
display_offset: u64, display_offset: u64,
/// The number of panels to draw. /// The number of panels to draw.
panels: u16, panels: u64,
squeeze_byte: u8, squeeze_byte: u8,
} }
@@ -230,11 +235,11 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
show_position_panel: bool, show_position_panel: bool,
border_style: BorderStyle, border_style: BorderStyle,
use_squeeze: bool, use_squeeze: bool,
panels: u16, panels: u64,
) -> Printer<'a, Writer> { ) -> Printer<'a, Writer> {
Printer { Printer {
idx: 0, idx: 0,
line_buf: vec![], line_buf: vec![0x0; 8 * panels as usize],
writer, writer,
show_char_panel, show_char_panel,
show_position_panel, show_position_panel,
@@ -281,7 +286,11 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
} }
}) })
.collect(), .collect(),
squeezer: Squeezer::new(use_squeeze, 8 * panels as u64), squeezer: if use_squeeze {
Squeezer::Ignore
} else {
Squeezer::Disabled
},
display_offset: 0, display_offset: 0,
panels, panels,
squeeze_byte: 0x00, squeeze_byte: 0x00,
@@ -343,20 +352,19 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
} }
fn print_position_panel(&mut self) -> io::Result<()> { fn print_position_panel(&mut self) -> io::Result<()> {
match self.squeezer.action() { self.writer.write_all(
SqueezeAction::Print => { self.border_style
.outer_sep()
.encode_utf8(&mut [0; 4])
.as_bytes(),
)?;
match self.squeezer {
Squeezer::Print => {
self.writer self.writer
.write_all(self.byte_char_panel_g[b'*' as usize].as_bytes())?; .write_all(self.byte_char_panel_g[b'*' as usize].as_bytes())?;
self.writer.write_all(b" ")?; self.writer.write_all(b" ")?;
self.writer.write_all(
self.border_style
.outer_sep()
.encode_utf8(&mut [0; 4])
.as_bytes(),
)?;
Ok(())
} }
SqueezeAction::Ignore => { Squeezer::Ignore | Squeezer::Disabled | Squeezer::Delete => {
let byte_index: [u8; 8] = (self.idx + self.display_offset).to_be_bytes(); let byte_index: [u8; 8] = (self.idx + self.display_offset).to_be_bytes();
let mut i = 0; let mut i = 0;
while byte_index[i] == 0x0 && i < 4 { while byte_index[i] == 0x0 && i < 4 {
@@ -366,118 +374,38 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
self.writer self.writer
.write_all(self.byte_hex_panel_g[byte as usize].as_bytes())?; .write_all(self.byte_hex_panel_g[byte as usize].as_bytes())?;
} }
self.writer.write_all(
self.border_style
.outer_sep()
.encode_utf8(&mut [0; 4])
.as_bytes(),
)?;
Ok(())
} }
_ => unreachable!(),
}
}
pub fn print_char_panel(&mut self) -> io::Result<()> {
match self.squeezer.action() {
SqueezeAction::Print => {
for i in 0..self.panels {
self.writer.write_all(b" ")?;
if i == self.panels - 1 {
self.writer.write_all(
self.border_style
.outer_sep()
.encode_utf8(&mut [0; 4])
.as_bytes(),
)?;
self.writer.write_all(b"\n")?;
} else {
self.writer.write_all(
self.border_style
.inner_sep()
.encode_utf8(&mut [0; 4])
.as_bytes(),
)?;
}
}
}
SqueezeAction::Ignore => {
let mut idx = 0;
for &b in self.line_buf.iter() {
self.writer
.write_all(self.byte_char_panel[b as usize].as_bytes())?;
if idx == 8 * self.panels - 1 {
self.writer.write_all(
self.border_style
.outer_sep()
.encode_utf8(&mut [0; 4])
.as_bytes(),
)?;
self.writer.write_all(b"\n")?;
} else if idx % 8 == 7 {
self.writer.write_all(
self.border_style
.inner_sep()
.encode_utf8(&mut [0; 4])
.as_bytes(),
)?;
}
idx += 1;
}
// there is space left over at the end
if idx < 8 * self.panels - 1 {
for i in idx..8 * self.panels {
self.writer.write_all(b" ")?;
if i == 8 * self.panels - 1 {
self.writer.write_all(
self.border_style
.outer_sep()
.encode_utf8(&mut [0; 4])
.as_bytes(),
)?;
self.writer.write_all(b"\n")?;
} else if i % 8 == 7 {
self.writer.write_all(
self.border_style
.inner_sep()
.encode_utf8(&mut [0; 4])
.as_bytes(),
)?;
}
}
}
}
_ => unreachable!(),
} }
self.writer.write_all(
self.border_style
.outer_sep()
.encode_utf8(&mut [0; 4])
.as_bytes(),
)?;
Ok(()) Ok(())
} }
pub fn print_byte(&mut self, b: u8) -> io::Result<()> { pub fn print_char_panel(&mut self) -> io::Result<()> {
match self.squeezer.action() { for i in 0..8 * self.panels {
SqueezeAction::Print => { match self.squeezer {
self.writer.write_all(b" ")?; Squeezer::Print | Squeezer::Delete => self.writer.write_all(b" ")?,
Squeezer::Ignore | Squeezer::Disabled => {
if let Some(&b) = self.line_buf.get(i as usize) {
self.writer.write_all(self.byte_char_panel[b as usize].as_bytes())?;
} else {
self.squeezer = Squeezer::Print;
}
},
} }
SqueezeAction::Ignore => { if i == 8 * self.panels - 1 {
// print the byte
self.writer
.write_all(self.byte_hex_panel[b as usize].as_bytes())?;
}
_ => unreachable!(),
}
// byte is last in panel
if self.idx % 8 == 7 {
// byte is last in last panel
if self.idx % (8 * self.panels as u64) == 8 * self.panels as u64 - 1 {
self.writer.write_all(b" ")?;
self.writer.write_all( self.writer.write_all(
self.border_style self.border_style
.outer_sep() .outer_sep()
.encode_utf8(&mut [0; 4]) .encode_utf8(&mut [0; 4])
.as_bytes(), .as_bytes(),
)?; )?;
} else { self.writer.write_all(b"\n")?;
self.writer.write_all(b" ")?; } else if i % 8 == 7 {
self.writer.write_all( self.writer.write_all(
self.border_style self.border_style
.inner_sep() .inner_sep()
@@ -486,78 +414,39 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
)?; )?;
} }
} }
Ok(()) Ok(())
} }
pub fn print_line(&mut self, b: u8) -> io::Result<()> { pub fn print_bytes(&mut self) -> io::Result<()> {
let mut is_flushed = false; for (i, &b) in self.line_buf.iter().enumerate() {
let old_active = self.squeezer.active(); match self.squeezer {
self.squeezer.process(b, self.idx); Squeezer::Print | Squeezer::Delete => self.writer.write_all(b" ")?,
let new_active = self.squeezer.active(); Squeezer::Ignore | Squeezer::Disabled => self
.writer
if new_active { .write_all(self.byte_hex_panel[b as usize].as_bytes())?,
self.squeeze_byte = b;
}
// the header should be the first thing printed
if self.idx == 0 {
self.print_header()?;
}
// flush the rest of the line buffer before continuing to write
if old_active && !new_active {
self.writer.write_all(
self.border_style
.outer_sep()
.encode_utf8(&mut [0; 4])
.as_bytes(),
)?;
let old_idx = self.idx;
self.idx -= self.idx % (8 * self.panels as u64);
if self.show_position_panel {
self.print_position_panel()?;
} }
while self.idx < old_idx { // byte is last in panel
self.print_byte(self.squeeze_byte)?; if i as u64 % 8 == 7 {
self.idx += 1; // byte is last in last panel
} if i as u64 % (8 * self.panels) == 8 * self.panels - 1 {
is_flushed = true; self.writer.write_all(b" ")?;
} self.writer.write_all(
self.border_style
if !new_active || self.squeezer.action() == SqueezeAction::Print { .outer_sep()
// print the left border and position panel if there's a new line .encode_utf8(&mut [0; 4])
self.line_buf.push(b); .as_bytes(),
if self.idx % (8 * self.panels as u64) == 0 && !is_flushed { )?;
self.writer.write_all(
self.border_style
.outer_sep()
.encode_utf8(&mut [0; 4])
.as_bytes(),
)?;
if self.show_position_panel {
self.print_position_panel()?;
}
}
self.print_byte(b)?;
if self.idx % (8 * self.panels as u64) == 8 * self.panels as u64 - 1 {
if self.show_char_panel {
self.print_char_panel()?;
} else { } else {
self.writer.write_all(b"\n")?; self.writer.write_all(b" ")?;
self.writer.write_all(
self.border_style
.inner_sep()
.encode_utf8(&mut [0; 4])
.as_bytes(),
)?;
} }
self.line_buf.clear();
} }
} }
self.idx += 1;
if self.idx % (8 * self.panels as u64) == 0 {
self.line_buf.clear();
self.squeezer.advance();
}
Ok(()) Ok(())
} }
@@ -565,22 +454,60 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
/// is exhausted. /// is exhausted.
pub fn print_all<Reader: Read>(&mut self, reader: Reader) -> io::Result<()> { pub fn print_all<Reader: Read>(&mut self, reader: Reader) -> io::Result<()> {
let mut is_empty = true; let mut is_empty = true;
let mut will_delete = false;
let buf = BufReader::new(reader); let mut buf = BufReader::new(reader);
for b in buf.bytes() { self.print_header()?;
if is_empty { loop {
is_empty = false; if let Err(e) = buf.read_exact(&mut self.line_buf) {
// self.print_position_panel()?;
// self.print_bytes()?;
// self.print_char_panel()?;
// self.writer.write_all(b"UENXPEC")?;
if e.kind() == ErrorKind::UnexpectedEof {
break;
}
} }
if self.print_line(b?).is_err() { is_empty = false;
break;
if matches!(self.squeezer, Squeezer::Print | Squeezer::Delete) {
if self.line_buf[0] == self.squeeze_byte && self.line_buf.windows(2).all(|w| w[0] == w[1]) {
if self.squeezer == Squeezer::Print {
will_delete = true;
} else {
self.idx += 8 * self.panels;
continue;
}
} else {
self.squeezer = Squeezer::Ignore;
}
} }
if self.show_position_panel {
self.print_position_panel()?;
}
self.print_bytes()?;
if self.show_char_panel {
self.print_char_panel()?;
}
self.idx += 8 * self.panels;
if will_delete {
self.squeezer = Squeezer::Delete;
will_delete = false;
}
if !matches!(self.squeezer, Squeezer::Disabled | Squeezer::Delete)
&& self.line_buf.windows(2).all(|w| w[0] == w[1])
{
self.squeezer = Squeezer::Print;
self.squeeze_byte = self.line_buf[0];
};
} }
// special ending // special ending
if is_empty { if is_empty {
self.print_header()?;
if self.show_position_panel { if self.show_position_panel {
write!(self.writer, "{0:9}", "│")?; write!(self.writer, "{0:9}", "│")?;
} }
@@ -588,58 +515,25 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
self.writer, self.writer,
"{0:2}{1:24}{0}{0:>26}", "{0:2}{1:24}{0}{0:>26}",
"│", "No content to print" "│", "No content to print"
) )?;
.ok();
if self.show_char_panel { if self.show_char_panel {
write!(self.writer, "{0:>9}{0:>9}", "│")?; write!(self.writer, "{0:>9}{0:>9}", "│")?;
} }
writeln!(self.writer)?; writeln!(self.writer)?;
} else if self.squeezer.active() { } else if matches!(self.squeezer, Squeezer::Print | Squeezer::Delete) {
// input was squeezed at the end // input was squeezed at the end
write!(self.writer, "{}", self.border_style.outer_sep())?; self.squeezer = Squeezer::Ignore;
if self.show_position_panel { if self.show_position_panel {
self.print_position_panel()?; self.print_position_panel()?;
} }
self.squeezer = Squeezer::Print;
// print empty bytes // print empty bytes
for i in 0..8 * self.panels { self.print_bytes()?;
write!(self.writer, " ")?;
if i % 8 == 7 {
if i % (8 * self.panels) == 8 * self.panels - 1 {
write!(self.writer, " {}", self.border_style.outer_sep())?;
} else {
write!(self.writer, " {}", self.border_style.inner_sep())?;
}
}
}
if self.show_char_panel { if self.show_char_panel {
// print empty char panel // print empty char panel
for i in 0..self.panels { self.print_char_panel()?;
write!(self.writer, " ")?;
if i == self.panels - 1 {
writeln!(self.writer, "{}", self.border_style.outer_sep())?;
} else {
write!(self.writer, "{}", self.border_style.inner_sep())?;
}
}
}
} else {
// finish unfinished last line
if self.idx % (8 * self.panels as u64) != 0 {
for i in self.idx % (8 * self.panels as u64)..8 * self.panels as u64 {
// print empty byte space
write!(self.writer, " ")?;
if i == (8 * self.panels - 1) as u64 {
write!(self.writer, " {}", self.border_style.outer_sep())?;
} else if i % 8 == 7 {
write!(self.writer, " {}", self.border_style.inner_sep())?;
}
}
if self.show_char_panel {
self.print_char_panel()?;
} else {
writeln!(self.writer)?;
}
} }
} }