mirror of
https://github.com/sharkdp/hexyl.git
synced 2026-10-28 08:05:52 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ad15413b9 | ||
|
|
710c86f6a1 | ||
|
|
a2ea80e960 | ||
|
|
3390bedee9 | ||
|
|
6978f7a277 | ||
|
|
2c7c857ccc | ||
|
|
55adb2db2c | ||
|
|
3a62809c8c | ||
|
|
7cc0b51537 | ||
|
|
8363e3f37e | ||
|
|
07c222947d | ||
|
|
2566d7b9f9 | ||
|
|
8bd7677c9b | ||
|
|
6a848b14f8 | ||
|
|
c6c4dd416e | ||
|
|
f918bfb911 | ||
|
|
10e3535999 | ||
|
|
8725f8cd25 | ||
|
|
c8e65d7528 | ||
|
|
170573fad0 | ||
|
|
880807619f |
No files matched your search
+1
-1
@@ -18,7 +18,7 @@ matrix:
|
||||
|
||||
# Minimum Rust supported channel.
|
||||
- os: linux
|
||||
rust: 1.29.0
|
||||
rust: 1.31.0
|
||||
env: TARGET=x86_64-unknown-linux-gnu
|
||||
|
||||
|
||||
|
||||
Generated
+33
-31
@@ -1,9 +1,11 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -11,9 +13,9 @@ name = "atty"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -23,25 +25,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.28"
|
||||
version = "1.0.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.6"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.32.0"
|
||||
version = "2.33.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"term_size 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
@@ -52,16 +54,16 @@ version = "3.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"nix 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hexyl"
|
||||
version = "0.4.0"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ctrlc 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -76,7 +78,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.46"
|
||||
version = "0.2.51"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
@@ -85,15 +87,15 @@ version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.1.50"
|
||||
version = "0.1.54"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
@@ -101,12 +103,12 @@ name = "redox_termios"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"redox_syscall 0.1.50 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.7.0"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
@@ -115,7 +117,7 @@ version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
@@ -124,14 +126,14 @@ name = "termion"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.50 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.10.0"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"term_size 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -160,7 +162,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.6"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -186,24 +188,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
|
||||
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
||||
"checksum cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749"
|
||||
"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
|
||||
"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
|
||||
"checksum cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)" = "5e5f3fee5eeb60324c2781f1e41286bdee933850fff9b3c672587fed5ec58c83"
|
||||
"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4"
|
||||
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
|
||||
"checksum ctrlc 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "630391922b1b893692c6334369ff528dcc3a9d8061ccf4c803aa8f83cb13db5e"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)" = "023a4cd09b2ff695f9734c1934145a315594b7986398496841c7031a5a1bbdbd"
|
||||
"checksum libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "bedcc7a809076656486ffe045abeeac163da1b558e963a31e29fbfbeba916917"
|
||||
"checksum nix 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d37e713a259ff641624b6cb20e3b12b2952313ba36b6823c0f16e6cfd9e5de17"
|
||||
"checksum redox_syscall 0.1.50 (registry+https://github.com/rust-lang/crates.io-index)" = "52ee9a534dc1301776eff45b4fa92d2c39b1d8c3d3357e6eb593e0d795506fc2"
|
||||
"checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252"
|
||||
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
|
||||
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
|
||||
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
"checksum term_size 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9e5b9a66db815dcfd2da92db471106457082577c3c278d4138ab3e3b4e189327"
|
||||
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
|
||||
"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
|
||||
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
|
||||
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
|
||||
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
|
||||
"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"
|
||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
+2
-1
@@ -7,7 +7,8 @@ license = "MIT/Apache-2.0"
|
||||
name = "hexyl"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/sharkdp/hexyl"
|
||||
version = "0.4.0"
|
||||
version = "0.5.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
ansi_term = "0.11"
|
||||
|
||||
@@ -22,16 +22,16 @@ of bytes (NULL bytes, printable ASCII characters, ASCII whitespace characters, o
|
||||
### On Debian-based systems
|
||||
|
||||
``` bash
|
||||
wget "https://github.com/sharkdp/hexyl/releases/download/v0.4.0/hexyl_0.4.0_amd64.deb"
|
||||
sudo dpkg -i hexyl_0.4.0_amd64.deb
|
||||
wget "https://github.com/sharkdp/hexyl/releases/download/v0.5.0/hexyl_0.5.0_amd64.deb"
|
||||
sudo dpkg -i hexyl_0.5.0_amd64.deb
|
||||
```
|
||||
|
||||
### On Arch Linux
|
||||
|
||||
You can install `hexyl` from [this AUR package](https://aur.archlinux.org/packages/hexyl/):
|
||||
You can install `hexyl` from [the official package repository](https://www.archlinux.org/packages/community/x86_64/hexyl/):
|
||||
|
||||
```
|
||||
yay -S hexyl
|
||||
pacman -S hexyl
|
||||
```
|
||||
|
||||
### On macOS
|
||||
@@ -46,6 +46,12 @@ brew install hexyl
|
||||
pkg install hexyl
|
||||
```
|
||||
|
||||
### Via Nix
|
||||
|
||||
```
|
||||
nix-env -i hexyl
|
||||
```
|
||||
|
||||
### On other distributions
|
||||
|
||||
Check out the [release page](https://github.com/sharkdp/hexyl/releases) for binary builds.
|
||||
@@ -57,7 +63,7 @@ you use a terminal that supports ANSI escape sequences (like PowerShell on Windo
|
||||
|
||||
### Via cargo
|
||||
|
||||
If you have Rust 1.29 or higher, you can install `hexyl` from source via `cargo`:
|
||||
If you have Rust 1.31 or higher, you can install `hexyl` from source via `cargo`:
|
||||
```
|
||||
cargo install hexyl
|
||||
```
|
||||
|
||||
+259
-41
@@ -1,8 +1,10 @@
|
||||
#[macro_use]
|
||||
extern crate clap;
|
||||
extern crate ansi_term;
|
||||
extern crate atty;
|
||||
extern crate ctrlc;
|
||||
|
||||
use atty;
|
||||
use ctrlc;
|
||||
|
||||
mod squeezer;
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::{self, prelude::*, StdoutLock};
|
||||
@@ -15,6 +17,7 @@ use ansi_term::Color;
|
||||
use ansi_term::Color::Fixed;
|
||||
|
||||
use atty::Stream;
|
||||
use crate::squeezer::{SqueezeAction, Squeezer};
|
||||
|
||||
const BUFFER_SIZE: usize = 256;
|
||||
|
||||
@@ -55,7 +58,7 @@ impl Byte {
|
||||
}
|
||||
|
||||
fn color(self) -> &'static Color {
|
||||
use ByteCategory::*;
|
||||
use crate::ByteCategory::*;
|
||||
|
||||
match self.category() {
|
||||
Null => &COLOR_NULL,
|
||||
@@ -67,7 +70,7 @@ impl Byte {
|
||||
}
|
||||
|
||||
fn as_char(self) -> char {
|
||||
use ByteCategory::*;
|
||||
use crate::ByteCategory::*;
|
||||
|
||||
match self.category() {
|
||||
Null => '0',
|
||||
@@ -80,6 +83,73 @@ impl Byte {
|
||||
}
|
||||
}
|
||||
|
||||
struct BorderElements {
|
||||
left_corner: char,
|
||||
horizontal_line: char,
|
||||
column_separator: char,
|
||||
right_corner: char,
|
||||
}
|
||||
|
||||
enum BorderStyle {
|
||||
Unicode,
|
||||
Ascii,
|
||||
None,
|
||||
}
|
||||
|
||||
impl BorderStyle {
|
||||
fn header_elems(&self) -> Option<BorderElements> {
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
fn footer_elems(&self) -> Option<BorderElements> {
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
fn outer_sep(&self) -> char {
|
||||
match self {
|
||||
BorderStyle::Unicode => '│',
|
||||
BorderStyle::Ascii => '|',
|
||||
BorderStyle::None => ' ',
|
||||
}
|
||||
}
|
||||
|
||||
fn inner_sep(&self) -> char {
|
||||
match self {
|
||||
BorderStyle::Unicode => '┊',
|
||||
BorderStyle::Ascii => '|',
|
||||
BorderStyle::None => ' ',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Printer<'a> {
|
||||
idx: usize,
|
||||
/// The raw bytes used as input for the current line.
|
||||
@@ -88,18 +158,28 @@ struct Printer<'a> {
|
||||
buffer_line: Vec<u8>,
|
||||
stdout: StdoutLock<'a>,
|
||||
show_color: bool,
|
||||
border_style: BorderStyle,
|
||||
header_was_printed: bool,
|
||||
byte_hex_table: Vec<String>,
|
||||
byte_char_table: Vec<String>,
|
||||
squeezer: Squeezer,
|
||||
}
|
||||
|
||||
impl<'a> Printer<'a> {
|
||||
fn new(stdout: StdoutLock, show_color: bool) -> Printer {
|
||||
fn new(
|
||||
stdout: StdoutLock<'_>,
|
||||
show_color: bool,
|
||||
border_style: BorderStyle,
|
||||
use_squeeze: bool,
|
||||
) -> Printer<'_> {
|
||||
Printer {
|
||||
idx: 1,
|
||||
raw_line: vec![],
|
||||
buffer_line: vec![],
|
||||
stdout,
|
||||
show_color,
|
||||
border_style,
|
||||
header_was_printed: false,
|
||||
byte_hex_table: (0u8..=u8::max_value())
|
||||
.map(|i| {
|
||||
let byte_hex = format!("{:02x} ", i);
|
||||
@@ -120,47 +200,87 @@ impl<'a> Printer<'a> {
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
squeezer: Squeezer::new(use_squeeze),
|
||||
}
|
||||
}
|
||||
|
||||
fn header(&mut self) {
|
||||
writeln!(
|
||||
self.stdout,
|
||||
"┌{0:─<8}┬{0:─<25}┬{0:─<25}┬{0:─<8}┬{0:─<8}┐",
|
||||
""
|
||||
)
|
||||
.ok();
|
||||
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);
|
||||
|
||||
writeln!(
|
||||
self.stdout,
|
||||
"{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();
|
||||
}
|
||||
}
|
||||
|
||||
fn footer(&mut self) {
|
||||
writeln!(
|
||||
self.stdout,
|
||||
"└{0:─<8}┴{0:─<25}┴{0:─<25}┴{0:─<8}┴{0:─<8}┘",
|
||||
""
|
||||
)
|
||||
.ok();
|
||||
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);
|
||||
|
||||
writeln!(
|
||||
self.stdout,
|
||||
"{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();
|
||||
}
|
||||
}
|
||||
|
||||
fn print_position_indicator(&mut self) {
|
||||
if !self.header_was_printed {
|
||||
self.header();
|
||||
self.header_was_printed = true;
|
||||
}
|
||||
|
||||
let style = COLOR_OFFSET.normal();
|
||||
let byte_index = format!("{:08x}", self.idx - 1);
|
||||
let formatted_string = if self.show_color {
|
||||
format!("{}", style.paint(byte_index))
|
||||
} else {
|
||||
byte_index
|
||||
};
|
||||
let _ = write!(
|
||||
&mut self.buffer_line,
|
||||
"{}{}{} ",
|
||||
self.border_style.outer_sep(),
|
||||
formatted_string,
|
||||
self.border_style.outer_sep()
|
||||
);
|
||||
}
|
||||
|
||||
fn print_byte(&mut self, b: u8) -> io::Result<()> {
|
||||
if self.idx % 16 == 1 {
|
||||
let style = COLOR_OFFSET.normal();
|
||||
let byte_index = format!("{:08x}", self.idx - 1);
|
||||
let formatted_string = if self.show_color {
|
||||
format!("{}", style.paint(byte_index))
|
||||
} else {
|
||||
byte_index
|
||||
};
|
||||
let _ = write!(&mut self.buffer_line, "│{}│ ", formatted_string);
|
||||
self.print_position_indicator();
|
||||
}
|
||||
|
||||
write!(&mut self.buffer_line, "{}", self.byte_hex_table[b as usize])?;
|
||||
self.raw_line.push(b);
|
||||
|
||||
self.squeezer.process(b, self.idx);
|
||||
|
||||
match self.idx % 16 {
|
||||
8 => {
|
||||
let _ = write!(&mut self.buffer_line, "┊ ");
|
||||
let _ = write!(&mut self.buffer_line, "{} ", self.border_style.inner_sep());
|
||||
}
|
||||
0 => {
|
||||
self.print_textline()?;
|
||||
}
|
||||
0 => self.print_textline()?,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
@@ -173,19 +293,41 @@ impl<'a> Printer<'a> {
|
||||
let len = self.raw_line.len();
|
||||
|
||||
if len == 0 {
|
||||
if self.squeezer.active() {
|
||||
self.print_position_indicator();
|
||||
let _ = writeln!(
|
||||
&mut self.buffer_line,
|
||||
"{0:1$}{4}{0:2$}{5}{0:3$}{4}{0:3$}{5}",
|
||||
"",
|
||||
24,
|
||||
25,
|
||||
8,
|
||||
self.border_style.inner_sep(),
|
||||
self.border_style.outer_sep(),
|
||||
);
|
||||
self.stdout.write_all(&self.buffer_line)?;
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if len < 8 {
|
||||
let _ = write!(
|
||||
&mut self.buffer_line,
|
||||
"{0:1$}┊{0:2$}│",
|
||||
"{0:1$}{3}{0:2$}{4}",
|
||||
"",
|
||||
3 * (8 - len),
|
||||
1 + 3 * 8
|
||||
1 + 3 * 8,
|
||||
self.border_style.inner_sep(),
|
||||
self.border_style.outer_sep(),
|
||||
);
|
||||
} else {
|
||||
let _ = write!(&mut self.buffer_line, "{0:1$}│", "", 3 * (16 - len));
|
||||
let _ = write!(
|
||||
&mut self.buffer_line,
|
||||
"{0:1$}{2}",
|
||||
"",
|
||||
3 * (16 - len),
|
||||
self.border_style.outer_sep()
|
||||
);
|
||||
}
|
||||
|
||||
let mut idx = 1;
|
||||
@@ -197,17 +339,52 @@ impl<'a> Printer<'a> {
|
||||
);
|
||||
|
||||
if idx == 8 {
|
||||
let _ = write!(&mut self.buffer_line, "┊");
|
||||
let _ = write!(&mut self.buffer_line, "{}", self.border_style.inner_sep());
|
||||
}
|
||||
|
||||
idx += 1;
|
||||
}
|
||||
|
||||
if len < 8 {
|
||||
let _ = writeln!(&mut self.buffer_line, "{0:1$}┊{0:2$}│ ", "", 8 - 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$}│", "", 16 - len);
|
||||
let _ = writeln!(
|
||||
&mut self.buffer_line,
|
||||
"{0:1$}{2}",
|
||||
"",
|
||||
16 - len,
|
||||
self.border_style.outer_sep()
|
||||
);
|
||||
}
|
||||
|
||||
match self.squeezer.action() {
|
||||
SqueezeAction::Print => {
|
||||
self.buffer_line.clear();
|
||||
let style = COLOR_OFFSET.normal();
|
||||
let _ = writeln!(
|
||||
&mut self.buffer_line,
|
||||
"{5}{0}{1:2$}{5}{1:3$}{6}{1:3$}{5}{1:4$}{6}{1:4$}{5}",
|
||||
style.paint("*"),
|
||||
"",
|
||||
7,
|
||||
25,
|
||||
8,
|
||||
self.border_style.outer_sep(),
|
||||
self.border_style.inner_sep(),
|
||||
);
|
||||
}
|
||||
SqueezeAction::Delete => self.buffer_line.clear(),
|
||||
SqueezeAction::Ignore => (),
|
||||
}
|
||||
|
||||
self.stdout.write_all(&self.buffer_line)?;
|
||||
|
||||
self.raw_line.clear();
|
||||
@@ -217,7 +394,7 @@ impl<'a> Printer<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn run() -> Result<(), Box<::std::error::Error>> {
|
||||
fn run() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let app = App::new(crate_name!())
|
||||
.setting(AppSettings::ColorAuto)
|
||||
.setting(AppSettings::ColoredHelp)
|
||||
@@ -234,6 +411,24 @@ fn run() -> Result<(), Box<::std::error::Error>> {
|
||||
.value_name("N")
|
||||
.help("Read only N bytes from the input"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("bytes")
|
||||
.short("c")
|
||||
.long("bytes")
|
||||
.takes_value(true)
|
||||
.value_name("N")
|
||||
.help("An alias for -n/--length"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("nosqueezing")
|
||||
.short("v")
|
||||
.long("no-squeezing")
|
||||
.help(
|
||||
"Displays all input data. Otherwise any number of groups of output \
|
||||
lines which would be identical to the preceding group of lines, are \
|
||||
replaced with a line comprised of a single asterisk.",
|
||||
),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("color")
|
||||
.long("color")
|
||||
@@ -245,6 +440,14 @@ fn run() -> Result<(), Box<::std::error::Error>> {
|
||||
"When to use colors. The auto-mode only displays colors if the output \
|
||||
goes to an interactive terminal",
|
||||
),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("border")
|
||||
.long("border")
|
||||
.takes_value(true)
|
||||
.possible_values(&["unicode", "ascii", "none"])
|
||||
.default_value("unicode")
|
||||
.help("Whether to draw a border with unicode or ASCII characters, or none at all"),
|
||||
);
|
||||
|
||||
let matches = app.get_matches_safe()?;
|
||||
@@ -256,10 +459,15 @@ fn run() -> Result<(), Box<::std::error::Error>> {
|
||||
None => Box::new(stdin.lock()),
|
||||
};
|
||||
|
||||
if let Some(length) = matches
|
||||
.value_of("length")
|
||||
.and_then(|n| n.parse::<u64>().ok())
|
||||
{
|
||||
let length_arg = matches.value_of("length").or(matches.value_of("bytes"));
|
||||
|
||||
if let Some(length) = length_arg.and_then(|n| {
|
||||
if n.starts_with("0x") {
|
||||
u64::from_str_radix(n.trim_start_matches("0x"), 16).ok()
|
||||
} else {
|
||||
n.parse::<u64>().ok()
|
||||
}
|
||||
}) {
|
||||
reader = Box::new(reader.take(length));
|
||||
}
|
||||
|
||||
@@ -269,6 +477,14 @@ fn run() -> Result<(), Box<::std::error::Error>> {
|
||||
_ => true,
|
||||
};
|
||||
|
||||
let border_style = match matches.value_of("border") {
|
||||
Some("unicode") => BorderStyle::Unicode,
|
||||
Some("ascii") => BorderStyle::Ascii,
|
||||
_ => BorderStyle::None,
|
||||
};
|
||||
|
||||
let squeeze = !matches.is_present("nosqueezing");
|
||||
|
||||
// Set up Ctrl-C handler
|
||||
let cancelled = Arc::new(AtomicBool::new(false));
|
||||
let c = cancelled.clone();
|
||||
@@ -279,8 +495,7 @@ fn run() -> Result<(), Box<::std::error::Error>> {
|
||||
.expect("Error setting Ctrl-C handler");
|
||||
|
||||
let stdout = io::stdout();
|
||||
let mut printer = Printer::new(stdout.lock(), show_color);
|
||||
printer.header();
|
||||
let mut printer = Printer::new(stdout.lock(), show_color, border_style, squeeze);
|
||||
|
||||
let mut buffer = [0; BUFFER_SIZE];
|
||||
'mainloop: loop {
|
||||
@@ -306,6 +521,9 @@ fn run() -> Result<(), Box<::std::error::Error>> {
|
||||
|
||||
// Finish last line
|
||||
printer.print_textline().ok();
|
||||
if !printer.header_was_printed {
|
||||
printer.header();
|
||||
}
|
||||
printer.footer();
|
||||
|
||||
Ok(())
|
||||
|
||||
+260
@@ -0,0 +1,260 @@
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum SqueezeState {
|
||||
/// not enabled
|
||||
Disabled,
|
||||
/// Will be set from all states if equal condition can't be hold up.
|
||||
/// Set if previous byte is not equal the current processed byte.
|
||||
NoSqueeze,
|
||||
/// Valid for a whole line to identify if it is candidate for squeezing
|
||||
Probe,
|
||||
/// Squeeze line parsing is active, but EOL is not reached yet
|
||||
SqueezeActive,
|
||||
/// Squeeze line, EOL is reached, will influence the action
|
||||
Squeeze,
|
||||
/// same as Squeeze, however this is only for the first line after
|
||||
/// the squeeze candidate has been set.
|
||||
SqueezeFirstLine,
|
||||
/// same as SqueezeActive, however this is only for the first line after
|
||||
/// the squeeze candidate has been set.
|
||||
SqueezeActiveFirstLine,
|
||||
}
|
||||
|
||||
pub struct Squeezer {
|
||||
state: SqueezeState,
|
||||
byte: u8,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum SqueezeAction {
|
||||
Ignore,
|
||||
Print,
|
||||
Delete,
|
||||
}
|
||||
|
||||
/// line size
|
||||
const LSIZE: usize = 16;
|
||||
|
||||
impl Squeezer {
|
||||
pub fn new(enabled: bool) -> Squeezer {
|
||||
Squeezer {
|
||||
state: if enabled {
|
||||
SqueezeState::Probe
|
||||
} else {
|
||||
SqueezeState::Disabled
|
||||
},
|
||||
byte: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process(&mut self, b: u8, i: usize) {
|
||||
use self::SqueezeState::*;
|
||||
if self.state == Disabled {
|
||||
return;
|
||||
}
|
||||
let eq = b == self.byte;
|
||||
|
||||
if i % LSIZE == 0 {
|
||||
self.state = match self.state {
|
||||
NoSqueeze => Probe,
|
||||
Probe => SqueezeActiveFirstLine,
|
||||
SqueezeActiveFirstLine => SqueezeFirstLine,
|
||||
SqueezeFirstLine => SqueezeActive,
|
||||
SqueezeActive => Squeeze,
|
||||
Squeeze => SqueezeActive,
|
||||
Disabled => Disabled,
|
||||
};
|
||||
} else if !eq {
|
||||
if (i % LSIZE == 1 && self.state != Probe) || i % LSIZE != 1 {
|
||||
self.state = NoSqueeze;
|
||||
}
|
||||
}
|
||||
|
||||
self.byte = b;
|
||||
}
|
||||
|
||||
pub fn active(&self) -> bool {
|
||||
use self::SqueezeState::*;
|
||||
match self.state {
|
||||
Squeeze | SqueezeActive | SqueezeFirstLine | SqueezeActiveFirstLine => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn action(&mut self) -> SqueezeAction {
|
||||
match self.state {
|
||||
SqueezeState::SqueezeFirstLine => {
|
||||
self.state = SqueezeState::SqueezeActive;
|
||||
SqueezeAction::Print
|
||||
}
|
||||
SqueezeState::Squeeze => {
|
||||
self.state = SqueezeState::SqueezeActive;
|
||||
SqueezeAction::Delete
|
||||
}
|
||||
_ => SqueezeAction::Ignore,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn three_same_lines() {
|
||||
const LINES: usize = 3;
|
||||
let v = vec![0u8; LINES * LSIZE];
|
||||
let mut s = Squeezer::new(true);
|
||||
// just initialized
|
||||
assert_eq!(s.action(), SqueezeAction::Ignore);
|
||||
|
||||
let exp = vec![
|
||||
SqueezeAction::Ignore, // first line, print as is
|
||||
SqueezeAction::Print, // print squeeze symbol
|
||||
SqueezeAction::Delete, // delete reoccurring line
|
||||
];
|
||||
|
||||
for z in 0..LINES {
|
||||
for i in z * LSIZE..(z + 1) * LSIZE {
|
||||
s.process(v[i], i + 1);
|
||||
}
|
||||
assert_eq!(s.action(), exp[z]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn incomplete_while_squeeze() {
|
||||
const LINES: usize = 3;
|
||||
// third line only has 12 bytes and should be printed
|
||||
let v = vec![0u8; LINES * LSIZE + 12];
|
||||
let mut s = Squeezer::new(true);
|
||||
// just initialized
|
||||
assert_eq!(s.action(), SqueezeAction::Ignore);
|
||||
|
||||
let exp = vec![
|
||||
SqueezeAction::Ignore, // first line, print as is
|
||||
SqueezeAction::Print, // print squeeze symbol
|
||||
SqueezeAction::Delete, // delete reoccurring line
|
||||
SqueezeAction::Ignore, // last line only 12 bytes, print it
|
||||
];
|
||||
|
||||
for z in 0..LINES {
|
||||
for i in z * LSIZE..(z + 1) * LSIZE {
|
||||
s.process(v[i], i + 1);
|
||||
}
|
||||
assert_eq!(s.action(), exp[z]);
|
||||
}
|
||||
|
||||
for i in LSIZE * LINES..LINES * LSIZE + 12 {
|
||||
s.process(v[i], i + 1);
|
||||
}
|
||||
assert_eq!(s.action(), exp[3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// all three lines are different, print all
|
||||
fn three_different_lines() {
|
||||
const LINES: usize = 3;
|
||||
let mut v: Vec<u8> = vec![];
|
||||
v.extend(vec![0u8; 16]);
|
||||
v.extend(vec![1u8; 16]);
|
||||
v.extend(vec![2u8; 16]);
|
||||
|
||||
let mut s = Squeezer::new(true);
|
||||
// just initialized
|
||||
assert_eq!(s.action(), SqueezeAction::Ignore);
|
||||
|
||||
let exp = vec![
|
||||
SqueezeAction::Ignore, // first line, print as is
|
||||
SqueezeAction::Ignore, // different
|
||||
SqueezeAction::Ignore, // different
|
||||
];
|
||||
|
||||
for z in 0..LINES {
|
||||
for i in z * LSIZE..(z + 1) * LSIZE {
|
||||
s.process(v[i], i + 1);
|
||||
}
|
||||
assert_eq!(s.action(), exp[z]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// first two lines same, hence squeeze symbol, third line diff, hence
|
||||
/// print
|
||||
fn one_squeeze_no_delete() {
|
||||
const LINES: usize = 3;
|
||||
let mut v = vec![0u8; (LINES - 1) * LSIZE];
|
||||
v.extend(vec![1u8; 16]);
|
||||
|
||||
let mut s = Squeezer::new(true);
|
||||
// just initialized
|
||||
assert_eq!(s.action(), SqueezeAction::Ignore);
|
||||
|
||||
let exp = vec![
|
||||
SqueezeAction::Ignore, // first line, print as is
|
||||
SqueezeAction::Print, // print squeeze symbol
|
||||
SqueezeAction::Ignore, // different lines, print again
|
||||
];
|
||||
|
||||
for z in 0..LINES {
|
||||
for i in z * LSIZE..(z + 1) * LSIZE {
|
||||
s.process(v[i], i + 1);
|
||||
}
|
||||
assert_eq!(s.action(), exp[z]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// First line all eq, 2nd half eq with first line, then change
|
||||
fn second_line_different() {
|
||||
const LINES: usize = 2;
|
||||
let mut v = vec![0u8; (LINES - 1) * LSIZE];
|
||||
v.extend(vec![0u8; 8]);
|
||||
v.extend(vec![1u8; 8]);
|
||||
|
||||
let mut s = Squeezer::new(true);
|
||||
// just initialized
|
||||
assert_eq!(s.action(), SqueezeAction::Ignore);
|
||||
|
||||
let exp = vec![
|
||||
SqueezeAction::Ignore, // first line, print as is
|
||||
SqueezeAction::Ignore, // print squeeze symbol
|
||||
];
|
||||
|
||||
for z in 0..LINES {
|
||||
for i in z * LSIZE..(z + 1) * LSIZE {
|
||||
s.process(v[i], i + 1);
|
||||
}
|
||||
assert_eq!(s.action(), exp[z]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// all three lines never become squeeze candidate (diff within line)
|
||||
fn never_squeeze_candidate() {
|
||||
const LINES: usize = 3;
|
||||
let mut v = vec![];
|
||||
v.extend(vec![0u8; 8]);
|
||||
v.extend(vec![1u8; 8]);
|
||||
v.extend(vec![0u8; 8]);
|
||||
v.extend(vec![1u8; 8]);
|
||||
v.extend(vec![0u8; 8]);
|
||||
v.extend(vec![1u8; 8]);
|
||||
|
||||
let mut s = Squeezer::new(true);
|
||||
// just initialized
|
||||
assert_eq!(s.action(), SqueezeAction::Ignore);
|
||||
|
||||
let exp = vec![
|
||||
SqueezeAction::Ignore, // first line, print as is
|
||||
SqueezeAction::Ignore, // print squeeze symbol
|
||||
SqueezeAction::Ignore, // print squeeze symbol
|
||||
];
|
||||
|
||||
for z in 0..LINES {
|
||||
for i in z * LSIZE..(z + 1) * LSIZE {
|
||||
s.process(v[i], i + 1);
|
||||
}
|
||||
assert_eq!(s.action(), exp[z]);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user