54 Commits
Author SHA1 Message Date
David Peter becc75caf1 Fix #254 2026-02-14 13:42:51 +01:00
Sharif Haason cc9476d665 Return a proper error if terminal size fails 2022-07-17 15:53:56 -04:00
Sharif Haason ab381e88f8 Change columns type to u16 2022-07-17 15:53:23 -04:00
Sharif Haason 361ded43fd Remove debugging line 2022-07-17 15:48:05 -04:00
Sharif Haason 20056fb4d9 Bump MSRV 2022-07-17 15:26:43 -04:00
Sharif Haason 34c55b5e55 Implement -a and -t for terminal width setting 2022-07-17 15:20:00 -04:00
Sharif Haason f4c4b22c57 Added test for multiple columns 2022-07-17 13:37:25 -04:00
Sharif Haason 98c65d94e7 Prevent overflow when columns >= 32 2022-07-17 11:31:46 -04:00
sharifandDavid Peter d74520fbab Update src/squeezer.rs
Co-authored-by: David Peter <sharkdp@users.noreply.github.com>
2022-07-17 08:54:24 -04:00
Sharif Haason c8b05ff96f cargo fmt 2022-07-12 11:49:50 -04:00
Sharif Haason 734365723b Adds --columns for Print using custom width #13 2022-07-12 11:39:24 -04:00
Giovanni Tirloni 55cf7b034c Add Fedora install instructions 2022-06-23 21:56:49 +02:00
Vadym-Valdis Yudaiev c622c8217f doc: Add example usage with terminal pager 2022-05-24 18:57:21 +02:00
David Peter 49484fa0f0 Bump MSRV 2022-05-22 22:26:59 +02:00
David Peter 3661b06b60 Update CHANGELOG 2022-05-22 22:24:47 +02:00
David Peter f5814d4442 Update version 2022-05-22 22:23:25 +02:00
David Peter 49ebf4771f Update to clap 3 2022-05-22 22:21:49 +02:00
David Peter 4904a7e26f Relax constraints 2022-05-22 21:53:26 +02:00
David Peter becc1b80f1 Update dependencies 2022-05-22 21:52:44 +02:00
David Peter 1fb5263c3b Fix clippy suggestions 2022-05-22 21:48:40 +02:00
David Peter 0ae89168ad Update CHANGELOG 2022-05-22 21:39:42 +02:00
Mikhail Katychev 6873867658 table -> panel 2022-05-22 21:34:26 +02:00
Mikhail Katychev f15e049bf5 added proposed table suffix to no_chars and no_position 2022-05-22 21:34:26 +02:00
Mikhail Katychev 1d04cdf119 bump min version 2022-05-22 21:34:26 +02:00
Mikhail Katychev 5d92f07e21 cargo clippy warning 2022-05-22 21:34:26 +02:00
Mikhail Katychev a4ed50e1f0 clippy feedback 2022-05-22 21:34:26 +02:00
Mikhail Katychev f7f7447994 added --plain functionality 2022-05-22 21:34:26 +02:00
cuishuang e4f0e8a092 fix some typos
Signed-off-by: cuishuang <imcusg@gmail.com>
2022-05-18 20:10:29 +02:00
Shun Sakai a23645ddfd Add man page 2022-03-27 10:22:14 +02:00
Shun Sakai 7da04c6bff Change -l to conflict with -n and -c 2022-03-25 22:00:40 +01:00
Shun Sakai c497c1fac9 Fix Clippy warnings 2022-03-25 22:00:40 +01:00
Shun Sakai 653cf02954 Add rustfmt and clippy to the CI 2022-03-25 22:00:40 +01:00
David Peter 18cdbe02c5 Fix Debian package description 2021-11-14 09:36:35 +01:00
merkrafter d1ae68585f Make code compatible with rust 1.46 2021-11-14 09:26:21 +01:00
merkrafter 7a225fe732 Apply clippy suggestions 2021-11-14 09:26:21 +01:00
merkrafter 1b33e516d9 Move hex number processing into own function 2021-11-14 09:26:21 +01:00
merkrafter 55d02c933a Move sign (+/-) processing into own function 2021-11-14 09:26:21 +01:00
merkrafter b8ed8d5df9 Raise minimum Rust version for executable to 1.46 2021-11-14 09:26:21 +01:00
merkrafter 641c32e395 Mention new feature in CHANGELOG 2021-11-14 09:26:21 +01:00
merkrafter 51b28ed0b0 Allow hex numbers for --block-size 2021-11-14 09:26:21 +01:00
merkrafter 825100c6d6 Deny 'block' as unit for --block-size 2021-11-14 09:26:21 +01:00
merkrafter 1b1fc4b053 Allow units for --block-size 2021-11-14 09:26:21 +01:00
merkrafter c3dd4e871e Use extraction function for length arg parsing 2021-11-14 09:26:21 +01:00
merkrafter 923bceffaa Add function to extract num and unit from string
Having this as an own function allows special handling of the
'block' unit in --block-size argument.
2021-11-14 09:26:21 +01:00
merkrafter 2942d2419f Introduce enum for byte size units 2021-11-14 09:26:21 +01:00
merkrafter 37d4180f9a Refactor default block size into constant 2021-11-14 09:26:21 +01:00
Mark Umnus 99435cd215 Mention ability to specify length in hex 2021-10-20 22:52:01 +02:00
Issac Lin 27f039d72a README: Add scoop instruction (on Windows) 2021-09-20 08:41:25 +02:00
a1346054 e72422ecfb Trim trailing whitespace 2021-08-28 09:56:56 +02:00
a1346054 3c56ed2b0e Fix typos 2021-08-28 09:56:56 +02:00
a1346054 a09ea8ee27 Use HTTPS links 2021-08-28 09:56:56 +02:00
David Peter d6bdfe9897 Update package links 2021-08-25 22:17:21 +02:00
HRXN 7c9f7e1bd0 README.md does not mention availability of binary builds for Windows
Could not check this, but release page lists Windows binaries, apparently.
2021-07-12 07:15:41 +02:00
David Peter b1d2a47590 Remove old ci/ directory 2021-07-11 22:03:19 +02:00
15 changed files with 1274 additions and 550 deletions

No files matched your search

+29 -2
View File
@@ -1,7 +1,7 @@
name: CICD
env:
MIN_SUPPORTED_RUST_VERSION: "1.40.0"
MIN_SUPPORTED_RUST_VERSION: "1.56.1"
CICD_INTERMEDIATES_DIR: "_cicd-intermediates"
on:
@@ -27,11 +27,25 @@ jobs:
toolchain: ${{ env.MIN_SUPPORTED_RUST_VERSION }}
default: true
profile: minimal # minimal component installation (ie, no documentation)
components: clippy, rustfmt
- name: Ensure `cargo fmt` has been run
uses: actions-rs/cargo@v1
with:
command: fmt
args: -- --check
- name: Run clippy (on minimum supported rust version to prevent warnings we can't fix)
uses: actions-rs/cargo@v1
with:
command: clippy
args: --locked --all-targets
- name: Run tests
uses: actions-rs/cargo@v1
with:
command: test
args: --locked
build:
name: ${{ matrix.job.os }} (${{ matrix.job.target }})
@@ -155,6 +169,12 @@ jobs:
command: test
args: --target=${{ matrix.job.target }} ${{ steps.test-options.outputs.CARGO_TEST_OPTIONS}}
- name: Setup Pandoc
uses: r-lib/actions/setup-pandoc@v2
- name: Generate man page
run: pandoc -s -f markdown -t man -o "doc/${{ env.PROJECT_NAME }}.1" "doc/${{ env.PROJECT_NAME }}.1.md"
- name: Create tarball
id: package
shell: bash
@@ -171,6 +191,9 @@ jobs:
# Binary
cp "${{ steps.strip.outputs.BIN_PATH }}" "$ARCHIVE_DIR"
# Man page
cp "doc/${{ env.PROJECT_NAME }}.1" "$ARCHIVE_DIR"
# README, LICENSE and CHANGELOG files
cp "README.md" "LICENSE-MIT" "LICENSE-APACHE" "CHANGELOG.md" "$ARCHIVE_DIR"
@@ -215,6 +238,10 @@ jobs:
# Binary
install -Dm755 "${{ steps.strip.outputs.BIN_PATH }}" "${DPKG_DIR}/usr/bin/${{ steps.strip.outputs.BIN_NAME }}"
# Man page
install -Dm644 "doc/${{ env.PROJECT_NAME }}.1" "${DPKG_DIR}/usr/share/man/man1/${{ env.PROJECT_NAME }}.1"
gzip -n --best "${DPKG_DIR}/usr/share/man/man1/${{ env.PROJECT_NAME }}.1"
# README and LICENSE
install -Dm644 "README.md" "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/README.md"
install -Dm644 "LICENSE-MIT" "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/LICENSE-MIT"
@@ -275,7 +302,7 @@ jobs:
Architecture: ${DPKG_ARCH}
Provides: ${{ env.PROJECT_NAME }}
Conflicts: ${DPKG_CONFLICTS}
Description: command-line tool to generate, analyze, convert and manipulate colors
Description: colorized hex viewer for the terminal.
EOF
DPKG_PATH="${DPKG_STAGING}/${DPKG_NAME}"
+3
View File
@@ -1,2 +1,5 @@
/target
**/*.rs.bk
# Generated files
hexyl.1
+23 -2
View File
@@ -16,6 +16,19 @@
# v0.10.0
## Features
- Added new `--plain`, `--no-characters`, and `--no-position` flags, see #154 (@mkatychev)
- Allow hex numbers and units for `--block-size` argument, see #111 and #144 (@merkrafter)
## Other
- Added a man page, see #151 (@sorairolake)
- Mention ability to specify length in hex, see #143 (@merkrafter)
- `--length` and `--bytes` are now marked as conflicting command-line options, see #152 (@sorairolake)
# v0.9.0
@@ -43,6 +56,7 @@
- `hexyl` is now available on snapstore, see #116 (@purveshpatel511)
# v0.8.0
## Features
@@ -69,17 +83,19 @@
- `hexyl` is now available on Void Linux, see #91 (@notramo)
# v0.7.0
## Bugfixes
- hexyl can now be closed with `Ctrl-C` when reading input from STDIN, see #84
- hexyl can now be closed with `Ctrl-C` when reading input from STDIN, see #84
## Changes
- Breaking change (library): [`Printer::print_all`](https://docs.rs/hexyl/latest/hexyl/struct.Printer.html#method.print_all) does not take a second argument anymore.
- Added an example on how to use `hexyl` as a library: https://github.com/sharkdp/hexyl/blob/v0.7.0/examples/simple.rs
# v0.6.0
## Features
@@ -97,6 +113,7 @@
- Performance improvements, see #73 and #66
# v0.5.1
## Bugfixes
@@ -105,11 +122,12 @@
- Some colors are printed even if they're disabled, see #64 (@awidegreen)
- Fixed build failure on OpenBSD 6.5, see #61
# v0.5.0
## Features
- Added support for squeezing where reoccuring lines are squashed together and visualized with an asterisk. A new `-v`/`--no-squeezing` option can be used to disable the feature. For details, see #59 (@awidegreen)
- Added support for squeezing where reoccurring lines are squashed together and visualized with an asterisk. A new `-v`/`--no-squeezing` option can be used to disable the feature. For details, see #59 (@awidegreen)
- Added a new `--border` option with support for various styles (Unicode, ASCII, None), see #54 (@dmke)
- The `--length`/`-n` argument can be passed as a hexadecimal number (`hexyl -n 0xff /dev/urandom`), see #45 (@Qyriad)
- Added `--bytes`/`-c` as an alias for `--length`/`-n`, see #48 (@selfup)
@@ -136,16 +154,19 @@
- Proper Ctrl-C handling, see #35
- Proper handling of broken pipes (`hexyl … | head`)
# v0.3.1
- Various (huge) performance improvements, see #23 and #24 (@kballard)
- Replaced 24-bit truecolor ANSI codes by 8-bit codes to support
more terminal emulators, fixes #9
# v0.3.0
Windows support
# v0.2.0
Initial release
+1 -1
View File
@@ -8,7 +8,7 @@ Thank you for considering to contribute to `hexyl`!
If your contribution changes the behavior of `hexyl` (as opposed to a typo-fix
in the documentation), please update the [`CHANGELOG.md`](CHANGELOG.md) file
and describe your changes. This makes the release proess much easier and
and describe your changes. This makes the release process much easier and
therefore helps to get your changes into a new `hexyl` release faster.
The top of the `CHANGELOG` contains a *"unreleased"* section with a few
Generated
+298 -109
View File
@@ -1,5 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "aho-corasick"
version = "0.7.18"
@@ -9,15 +11,6 @@ dependencies = [
"memchr",
]
[[package]]
name = "ansi_term"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
dependencies = [
"winapi",
]
[[package]]
name = "ansi_term"
version = "0.12.1"
@@ -28,20 +21,27 @@ dependencies = [
]
[[package]]
name = "anyhow"
version = "1.0.42"
name = "anstyle"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "595d3cfa7a60d4555cb5067b99f07142a08ea778de5cf993f7b75c7d8fabc486"
checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
[[package]]
name = "anyhow"
version = "1.0.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc"
[[package]]
name = "assert_cmd"
version = "1.0.7"
version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d20831bd004dda4c7c372c19cdabff369f794a95e955b3f13fe460e3e1ae95f"
checksum = "9c5bcfa8749ac45dd12cb11055aeeb6b27a3895560d60d71e3c23bf979e60514"
dependencies = [
"anstyle",
"bstr",
"doc-comment",
"predicates",
"libc",
"predicates 3.1.4",
"predicates-core",
"predicates-tree",
"wait-timeout",
@@ -60,40 +60,77 @@ dependencies = [
[[package]]
name = "autocfg"
version = "1.0.1"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bitflags"
version = "1.2.1"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bstr"
version = "0.2.16"
version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90682c8d613ad3373e66de8c6411e0ae2ab2571e879d2efbf73558cc66f21279"
checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab"
dependencies = [
"lazy_static",
"memchr",
"regex-automata",
"serde",
]
[[package]]
name = "clap"
version = "2.33.3"
name = "cc"
version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
[[package]]
name = "clap"
version = "3.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d646c7ade5eb07c4aa20e907a922750df0c448892513714fd3e4acbc7130829f"
dependencies = [
"ansi_term 0.11.0",
"atty",
"bitflags",
"clap_lex",
"indexmap",
"once_cell",
"strsim",
"term_size",
"termcolor",
"terminal_size 0.1.17",
"textwrap",
"unicode-width",
]
[[package]]
name = "clap_lex"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
dependencies = [
"os_str_bytes",
]
[[package]]
name = "const_format"
version = "0.2.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0936ffe6d0c8d6a51b3b0a73b2acbe925d786f346cf45bfddc8341d79fb7dc8a"
dependencies = [
"const_format_proc_macros",
]
[[package]]
name = "const_format_proc_macros"
version = "0.2.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef196d5d972878a48da7decb7686eded338b4858fbabeed513d63a7c98b2b82d"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
@@ -102,12 +139,6 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
[[package]]
name = "doc-comment"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
[[package]]
name = "either"
version = "1.6.1"
@@ -115,14 +146,41 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "float-cmp"
version = "0.8.0"
name = "errno"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1267f4ac4f343772758f7b1bdcbe767c218bbab93bb432acbf5162bbf85a6c4"
checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
dependencies = [
"errno-dragonfly",
"libc",
"winapi",
]
[[package]]
name = "errno-dragonfly"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
dependencies = [
"cc",
"libc",
]
[[package]]
name = "float-cmp"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4"
dependencies = [
"num-traits",
]
[[package]]
name = "hashbrown"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
[[package]]
name = "hermit-abi"
version = "0.1.19"
@@ -134,44 +192,62 @@ dependencies = [
[[package]]
name = "hexyl"
version = "0.9.0"
version = "0.10.0"
dependencies = [
"ansi_term 0.12.1",
"ansi_term",
"anyhow",
"assert_cmd",
"atty",
"clap",
"const_format",
"libc",
"predicates",
"predicates 2.1.1",
"terminal_size 0.2.1",
"thiserror",
]
[[package]]
name = "itertools"
version = "0.10.1"
name = "indexmap"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf"
checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
name = "io-lifetimes"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24c3f4eff5495aee4c0399d7b6a0dc2b6e81be84242ffbfcf253ebacccc1d0cb"
[[package]]
name = "itertools"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
dependencies = [
"either",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
name = "libc"
version = "0.2.182"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112"
[[package]]
name = "libc"
version = "0.2.98"
name = "linux-raw-sys"
version = "0.0.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790"
checksum = "d4d2456c373231a208ad294c33dc5bff30051eafd954cd4caae83a712b12854d"
[[package]]
name = "memchr"
version = "2.4.0"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
[[package]]
name = "normalize-line-endings"
@@ -181,18 +257,30 @@ checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be"
[[package]]
name = "num-traits"
version = "0.2.14"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
dependencies = [
"autocfg",
]
[[package]]
name = "predicates"
version = "2.0.0"
name = "once_cell"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6e46ca79eb4e21e2ec14430340c71250ab69332abf85521c95d3a8bc336aa76"
checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
[[package]]
name = "os_str_bytes"
version = "6.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "029d8d0b2f198229de29dca79676f2738ff952edf3fde542eb8bf94d8c21b435"
[[package]]
name = "predicates"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5aab5be6e4732b473071984b3164dbbfb7a3674d30ea5ff44410b6bcd960c3c"
dependencies = [
"difflib",
"float-cmp",
@@ -203,44 +291,55 @@ dependencies = [
]
[[package]]
name = "predicates-core"
version = "1.0.2"
name = "predicates"
version = "3.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57e35a3326b75e49aa85f5dc6ec15b41108cf5aee58eabb1f274dd18b73c2451"
checksum = "ada8f2932f28a27ee7b70dd6c1c39ea0675c55a36879ab92f3a715eaa1e63cfe"
dependencies = [
"anstyle",
"difflib",
"predicates-core",
]
[[package]]
name = "predicates-core"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cad38746f3166b4031b1a0d39ad9f954dd291e7854fcc0eed52ee41a0b50d144"
[[package]]
name = "predicates-tree"
version = "1.0.2"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15f553275e5721409451eb85e15fd9a860a6e5ab4496eb215987502b5f5391f2"
checksum = "4d86de6de25020a36c6d3643a86d9a6a9f552107c0559c60ea03551b5e16c032"
dependencies = [
"predicates-core",
"treeline",
"termtree",
]
[[package]]
name = "proc-macro2"
version = "1.0.27"
version = "1.0.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038"
checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f"
dependencies = [
"unicode-xid",
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.9"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.5.4"
version = "1.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1"
dependencies = [
"aho-corasick",
"memchr",
@@ -249,67 +348,111 @@ dependencies = [
[[package]]
name = "regex-automata"
version = "0.1.10"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
[[package]]
name = "regex-syntax"
version = "0.6.25"
version = "0.6.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64"
[[package]]
name = "strsim"
version = "0.8.0"
name = "rustix"
version = "0.35.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
name = "syn"
version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7"
checksum = "d51cc38aa10f6bbb377ed28197aa052aa4e2b762c22be9d3153d01822587e787"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
"bitflags",
"errno",
"io-lifetimes",
"libc",
"linux-raw-sys",
"windows-sys",
]
[[package]]
name = "term_size"
version = "0.3.2"
name = "serde"
version = "1.0.185"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e4129646ca0ed8f45d09b929036bafad5377103edd06e50bf574b353d2b08d9"
checksum = "be9b6f69f1dfd54c3b568ffa45c310d6973a5e5148fd40cf515acaf38cf5bc31"
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "termcolor"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
dependencies = [
"winapi-util",
]
[[package]]
name = "terminal_size"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "textwrap"
version = "0.11.0"
name = "terminal_size"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
checksum = "8440c860cf79def6164e4a0a983bcc2305d82419177a0e0c71930d049e3ac5a1"
dependencies = [
"term_size",
"unicode-width",
"rustix",
"windows-sys",
]
[[package]]
name = "termtree"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "507e9898683b6c43a9aa55b64259b721b52ba226e0f3779137e50ad114a4c90b"
[[package]]
name = "textwrap"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
dependencies = [
"terminal_size 0.1.17",
]
[[package]]
name = "thiserror"
version = "1.0.26"
version = "1.0.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2"
checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.26"
version = "1.0.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745"
checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a"
dependencies = [
"proc-macro2",
"quote",
@@ -317,22 +460,16 @@ dependencies = [
]
[[package]]
name = "treeline"
version = "0.1.0"
name = "unicode-ident"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41"
[[package]]
name = "unicode-width"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee"
[[package]]
name = "unicode-xid"
version = "0.2.2"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04"
[[package]]
name = "wait-timeout"
@@ -359,8 +496,60 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
dependencies = [
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_msvc"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
[[package]]
name = "windows_i686_gnu"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
[[package]]
name = "windows_i686_msvc"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
[[package]]
name = "windows_x86_64_gnu"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
[[package]]
name = "windows_x86_64_msvc"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
+9 -7
View File
@@ -7,23 +7,25 @@ license = "MIT/Apache-2.0"
name = "hexyl"
readme = "README.md"
repository = "https://github.com/sharkdp/hexyl"
version = "0.9.0"
edition = "2018"
version = "0.10.0"
edition = "2021"
[dependencies]
ansi_term = "0.12"
anyhow = "1.0.31"
anyhow = "1.0"
atty = "0.2"
const_format = "0.2"
libc = "0.2"
thiserror = "1.0.19"
thiserror = "1.0"
terminal_size = "0.2"
[dependencies.clap]
version = "2"
version = "3"
default-features = false
features = ["suggestions", "color", "wrap_help"]
features = ["std", "suggestions", "color", "wrap_help", "cargo"]
[dev-dependencies]
assert_cmd = "1.0"
assert_cmd = "2.1"
predicates = "2.0"
[profile.release]
+39 -10
View File
@@ -23,7 +23,7 @@ of bytes (NULL bytes, printable ASCII characters, ASCII whitespace characters, o
*... and other Debian-based Linux distributions.*
If you run Ubuntu 19.10 (Eoan Ermine) or newer, you can install the [officially maintained package](https://packages.ubuntu.com/eoan/hexyl):
If you run Ubuntu 19.10 (Eoan Ermine) or newer, you can install the [officially maintained package](https://packages.ubuntu.com/search?keywords=hexyl):
```bash
sudo apt install hexyl
```
@@ -31,12 +31,12 @@ If you use an older version of Ubuntu, you can download
the latest `.deb` package from the release page and install it via:
``` bash
sudo dpkg -i hexyl_0.9.0_amd64.deb # adapt version number and architecture
sudo dpkg -i hexyl_0.10.0_amd64.deb # adapt version number and architecture
```
### On Debian
If you run Debian Buster or newer, you can install the [officially maintained Debian package](https://packages.debian.org/buster/hexyl):
If you run Debian Buster or newer, you can install the [officially maintained Debian package](https://packages.debian.org/search?searchon=names&keywords=hexyl):
```bash
sudo apt-get install hexyl
```
@@ -44,6 +44,14 @@ sudo apt-get install hexyl
If you run an older version of Debian, see above for instructions on how to
manually install `hexyl`.
### On Fedora
If you run Fedora 35 or newer, you can install the [officially maintained Fedora package](https://packages.fedoraproject.org/pkgs/rust-hexyl/hexyl):
```bash
sudo dnf install hexyl
```
### On Arch Linux
You can install `hexyl` from [the official package repository](https://www.archlinux.org/packages/community/x86_64/hexyl/):
@@ -53,6 +61,7 @@ pacman -S hexyl
```
### On Void Linux
```
xbps-install hexyl
```
@@ -91,7 +100,7 @@ pkg install hexyl
```
pkg install hexyl
```
or
or
```
apt install hexyl
```
@@ -116,30 +125,50 @@ Check out the [release page](https://github.com/sharkdp/hexyl/releases) for bina
### On Windows
For now, you will have to install from source via `cargo` (see below). Make sure that you
use a terminal that supports ANSI escape sequences (like ConHost v2 since Windows 10 1703
Check out the [release page](https://github.com/sharkdp/hexyl/releases) for binary builds.
Alternatively, install from source via `cargo`, `snap` or `scoop` (see below).
Make sure that you use a terminal that supports ANSI escape sequences (like ConHost v2 since Windows 10 1703
or Windows Terminal since Windows 10 1903).
### Via cargo
If you have Rust 1.40 or higher, you can install `hexyl` from source via `cargo`:
If you have Rust 1.56 or higher, you can install `hexyl` from source via `cargo`:
```
cargo install hexyl
```
Alternatively, you can install `hexyl` directly from the repository by using:
```
git clone https://github.com/sharkdp/hexyl
cargo install --path ./hexyl
```
Note: To convert the man page, you will need [Pandoc](https://pandoc.org/).
You can convert from Markdown by using (in the project root):
```
pandoc -s -f markdown -t man -o ./doc/hexyl.1 ./doc/hexyl.1.md
```
### Via snap package
```
sudo snap install hexyl
```
[Get it from the Snap Store](https://snapcraft.io/hexyl)
### Via [Scoop](https://scoop.sh)
```
scoop install hexyl
```
## License
Licensed under either of
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or https://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or https://opensource.org/licenses/MIT)
at your option.
-1
View File
@@ -1 +0,0 @@
*.bash linguist-vendored
-103
View File
@@ -1,103 +0,0 @@
#!/usr/bin/env bash
# Building and packaging for release
set -ex
build() {
cargo build --target "$TARGET" --release --verbose
}
pack() {
local tempdir
local out_dir
local package_name
tempdir=$(mktemp -d 2>/dev/null || mktemp -d -t tmp)
out_dir=$(pwd)
package_name="$PROJECT_NAME-$TRAVIS_TAG-$TARGET"
# create a "staging" directory
mkdir "$tempdir/$package_name"
# copying the main binary
cp "target/$TARGET/release/$PROJECT_NAME" "$tempdir/$package_name/"
strip "$tempdir/$package_name/$PROJECT_NAME"
# readme and license
cp README.md "$tempdir/$package_name"
cp LICENSE-MIT "$tempdir/$package_name"
cp LICENSE-APACHE "$tempdir/$package_name"
# archiving
pushd "$tempdir"
tar czf "$out_dir/$package_name.tar.gz" "$package_name"/*
popd
rm -r "$tempdir"
}
make_deb() {
local tempdir
local architecture
local version
local dpkgname
local conflictname
case $TARGET in
x86_64*)
architecture=amd64
;;
i686*)
architecture=i386
;;
*)
echo "ERROR: unknown target" >&2
return 1
;;
esac
version=${TRAVIS_TAG#v}
if [[ $TARGET = *musl* ]]; then
dpkgname=$PROJECT_NAME-musl
conflictname=$PROJECT_NAME
else
dpkgname=$PROJECT_NAME
conflictname=$PROJECT_NAME-musl
fi
tempdir=$(mktemp -d 2>/dev/null || mktemp -d -t tmp)
# copy the main binary
install -Dm755 "target/$TARGET/release/$PROJECT_NAME" "$tempdir/usr/bin/$PROJECT_NAME"
strip "$tempdir/usr/bin/$PROJECT_NAME"
# readme and license
install -Dm644 README.md "$tempdir/usr/share/doc/$PROJECT_NAME/README.md"
install -Dm644 LICENSE-MIT "$tempdir/usr/share/doc/$PROJECT_NAME/LICENSE-MIT"
install -Dm644 LICENSE-APACHE "$tempdir/usr/share/doc/$PROJECT_NAME/LICENSE-APACHE"
# Control file
mkdir "$tempdir/DEBIAN"
cat > "$tempdir/DEBIAN/control" <<EOF
Package: $dpkgname
Version: $version
Section: utils
Priority: optional
Maintainer: David Peter <mail@david-peter.de>
Architecture: $architecture
Provides: $PROJECT_NAME
Conflicts: $conflictname
Description: A command-line hex viewer.
EOF
fakeroot dpkg-deb --build "$tempdir" "${dpkgname}_${version}_${architecture}.deb"
}
main() {
build
pack
if [[ $TARGET = *linux* ]]; then
make_deb
fi
}
main
+148
View File
@@ -0,0 +1,148 @@
% HEXYL(1) hexyl 0.10.0 | General Commands Manual
%
% 2022-03-23
<!--
This man page is written in Pandoc's Markdown.
See: https://pandoc.org/MANUAL.html#pandocs-markdown
-->
# NAME
hexyl - a command-line hex viewer
# SYNOPSIS
**hexyl** [_OPTIONS_] [_FILE_]
# DESCRIPTION
**hexyl** is a simple hex viewer for the terminal.
It uses a colored output to distinguish different categories of bytes (NULL
bytes, printable ASCII characters, ASCII whitespace characters, other ASCII
characters and non-ASCII).
# POSITIONAL ARGUMENTS
_FILE_
: The file to display.
If no _FILE_ argument is given, read from STDIN.
# OPTIONS
**-n**, **\--length** _N_
: Only read _N_ bytes from the input.
The _N_ argument can also include a unit with a decimal prefix (kB, MB, ..)
or binary prefix (kiB, MiB, ..), or can be specified using a hex number.
Examples:
:
Read the first 64 bytes:
: $ **hexyl \--length=64**
Read the first 4 kibibytes:
: $ **hexyl \--length=4KiB**
Read the first 255 bytes (specified using a hex number):
: $ **hexyl \--length=0xff**
**-c**, **\--bytes** _N_
: An alias for **-n**/**\--length**.
**-l** _N_
: Yet another alias for **-n**/**\--length**.
**-s**, **\--skip** _N_
: Skip the first _N_ bytes of the input.
The _N_ argument can also include a unit (see **\--length** for details).
A negative value is valid and will seek from the end of the file.
**\--block-size** _SIZE_
: Sets the size of the block unit to _SIZE_ (default is 512).
Examples:
:
Sets the block size to 1024 bytes:
: $ **hexyl \--block-size=1024 \--length=5block**
Sets the block size to 4 kilobytes:
: $ **hexyl \--block-size=4kB \--length=2block**
**-v**, **\--no-squeezing**
: 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.
**\--color** _WHEN_
: When to use colors.
The auto-mode only displays colors if the output goes to an interactive
terminal.
Possible values:
: - **always** (default)
- **auto**
- **never**
**\--border** _STYLE_
: Whether to draw a border with Unicode characters, ASCII characters, or none
at all.
Possible values:
: - **unicode** (default)
- **ascii**
- **none**
**-o**, **\--display-offset** _N_
: Add _N_ bytes to the displayed file position.
The _N_ argument can also include a unit (see **\--length** for details).
A negative value is valid and calculates an offset relative to the end of
the file.
**-h**, **\--help**
: Prints help information.
**-V**, **\--version**
: Prints version information.
# NOTES
Source repository:
: <https://github.com/sharkdp/hexyl>
# EXAMPLES
Print a given file:
: $ **hexyl small.png**
Print and view a given file in the terminal pager:
: $ **hexyl big.png | less -r**
Print the first 256 bytes of a given special file:
: $ **hexyl -n 256 /dev/urandom**
# AUTHORS
**hexyl** was written by David Peter <mail@david-peter.de>.
# REPORTING BUGS
Bugs can be reported on GitHub at:
: <https://github.com/sharkdp/hexyl/issues>
# COPYRIGHT
**hexyl** is dual-licensed under:
: - Apache License 2.0 (<https://www.apache.org/licenses/LICENSE-2.0>)
- MIT License (<https://opensource.org/licenses/MIT>)
# SEE ALSO
**hexdump**(1), **xxd**(1)
+12 -1
View File
@@ -12,9 +12,20 @@ fn main() {
let mut handle = stdout.lock();
let show_color = true;
let show_char_panel = true;
let show_position_panel = true;
let use_squeezing = false;
let border_style = BorderStyle::Unicode;
let columns = 2;
let mut printer = Printer::new(&mut handle, show_color, border_style, use_squeezing);
let mut printer = Printer::new(
&mut handle,
show_color,
show_char_panel,
show_position_panel,
border_style,
use_squeezing,
columns,
);
printer.print_all(&input[..]).unwrap();
}
+371 -131
View File
@@ -4,46 +4,52 @@ extern crate clap;
use std::convert::TryFrom;
use std::fs::File;
use std::io::{self, prelude::*, SeekFrom};
use std::num::{NonZeroI64, NonZeroU16};
use clap::{App, AppSettings, Arg};
use clap::{crate_name, crate_version, AppSettings, Arg, ColorChoice, Command};
use atty::Stream;
use anyhow::{anyhow, Context, Error as AnyhowError};
use const_format::formatcp;
use thiserror::Error as ThisError;
use terminal_size::terminal_size;
use hexyl::{BorderStyle, Input, Printer};
const DEFAULT_BLOCK_SIZE: i64 = 512;
fn run() -> Result<(), AnyhowError> {
let app = App::new(crate_name!())
.setting(AppSettings::ColorAuto)
.setting(AppSettings::ColoredHelp)
let command = Command::new(crate_name!())
.setting(AppSettings::DeriveDisplayOrder)
.setting(AppSettings::UnifiedHelpMessage)
.color(ColorChoice::Auto)
.max_term_width(90)
.version(crate_version!())
.about(crate_description!())
.arg(
Arg::with_name("FILE")
Arg::new("FILE")
.help("The file to display. If no FILE argument is given, read from STDIN."),
)
.arg(
Arg::with_name("length")
.short("n")
Arg::new("length")
.short('n')
.long("length")
.takes_value(true)
.value_name("N")
.help(
"Only read N bytes from the input. The N argument can also include a \
unit with a decimal prefix (kB, MB, ..) or binary prefix (kiB, MiB, ..). \
unit with a decimal prefix (kB, MB, ..) or binary prefix (kiB, MiB, ..), \
or can be specified using a hex number. \
The short option '-l' can be used as an alias.\n\
Examples: --length=64, --length=4KiB",
Examples: --length=64, --length=4KiB, --length=0xff",
),
)
.arg(
Arg::with_name("bytes")
.short("c")
Arg::new("bytes")
.short('c')
.long("bytes")
.takes_value(true)
.value_name("N")
@@ -51,16 +57,17 @@ fn run() -> Result<(), AnyhowError> {
.help("An alias for -n/--length"),
)
.arg(
Arg::with_name("count")
.short("l")
Arg::new("count")
.short('l')
.takes_value(true)
.value_name("N")
.hidden(true)
.conflicts_with_all(&["length", "bytes"])
.hide(true)
.help("Yet another alias for -n/--length"),
)
.arg(
Arg::with_name("skip")
.short("s")
Arg::new("skip")
.short('s')
.long("skip")
.takes_value(true)
.value_name("N")
@@ -71,18 +78,19 @@ fn run() -> Result<(), AnyhowError> {
),
)
.arg(
Arg::with_name("block_size")
Arg::new("block_size")
.long("block-size")
.takes_value(true)
.value_name("SIZE")
.help(
"Sets the size of the `block` unit to SIZE.\n\
.help(formatcp!(
"Sets the size of the `block` unit to SIZE (default is {}).\n\
Examples: --block-size=1024, --block-size=4kB",
),
DEFAULT_BLOCK_SIZE
)),
)
.arg(
Arg::with_name("nosqueezing")
.short("v")
Arg::new("nosqueezing")
.short('v')
.long("no-squeezing")
.help(
"Displays all input data. Otherwise any number of groups of output \
@@ -91,23 +99,28 @@ fn run() -> Result<(), AnyhowError> {
),
)
.arg(
Arg::with_name("color")
Arg::new("color")
.long("color")
.takes_value(true)
.value_name("WHEN")
.possible_values(&["always", "auto", "never"])
.default_value_if("plain", None, Some("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::new("plain").short('p').long("plain").help(
"Display output with --no-characters, --no-position, --border=none, and --color=never.",
))
.arg(
Arg::with_name("border")
Arg::new("border")
.long("border")
.takes_value(true)
.value_name("STYLE")
.possible_values(&["unicode", "ascii", "none"])
.default_value_if("plain", None, Some("none"))
.default_value("unicode")
.help(
"Whether to draw a border with Unicode characters, ASCII characters, \
@@ -115,8 +128,20 @@ fn run() -> Result<(), AnyhowError> {
),
)
.arg(
Arg::with_name("display_offset")
.short("o")
Arg::new("no_chars")
.short('C')
.long("no-characters")
.help("Whether to display the character panel on the right."),
)
.arg(
Arg::new("no_position")
.short('P')
.long("no-position")
.help("Whether to display the position panel on the left."),
)
.arg(
Arg::new("display_offset")
.short('o')
.long("display-offset")
.takes_value(true)
.value_name("N")
@@ -126,9 +151,45 @@ 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.",
),
)
.arg(
Arg::new("terminal_width")
.short('t')
.long("terminal-width")
.takes_value(true)
.value_name("N")
.conflicts_with("columns")
.help(
"Sets the number of terminal columns to be displayed.\nSince the terminal \
width may not be an evenly divisible by the width per hex data column, this \
will use the greatest number of hex data columns that can fit in the requested \
width but still leave some space to the right.\nCannot be used with other \
width-setting options.",
),
)
.arg(
Arg::new("auto_width")
.short('a')
.long("auto-width")
.conflicts_with_all(&["columns", "terminal_width"])
.help(
"Sets the number of hex data columns to be adjusted according to the \
detected terminal width.\nCannot be used with other width-setting options.",
),
);
let matches = app.get_matches_safe()?;
let matches = command.get_matches();
let stdin = io::stdin();
@@ -140,12 +201,27 @@ fn run() -> Result<(), AnyhowError> {
let block_size = matches
.value_of("block_size")
.map(|bs| {
bs.parse::<i64>().map_err(|e| anyhow!(e)).and_then(|x| {
PositiveI64::new(x).ok_or_else(|| anyhow!("block size argument must be positive"))
})
if let Some(hex_number) = try_parse_as_hex_number(bs) {
return hex_number.map_err(|e| anyhow!(e)).and_then(|x| {
PositiveI64::new(x)
.ok_or_else(|| anyhow!("block size argument must be positive"))
});
}
let (num, unit) = extract_num_and_unit_from(bs)?;
if let Unit::Block { custom_size: _ } = unit {
return Err(anyhow!(
"can not use 'block(s)' as a unit to specify block size"
));
};
num.checked_mul(unit.get_multiplier())
.ok_or_else(|| anyhow!(ByteOffsetParseError::UnitMultiplicationOverflow))
.and_then(|x| {
PositiveI64::new(x)
.ok_or_else(|| anyhow!("block size argument must be positive"))
})
})
.transpose()?
.unwrap_or_else(|| PositiveI64::new(512).unwrap());
.unwrap_or_else(|| PositiveI64::new(DEFAULT_BLOCK_SIZE).unwrap());
let skip_arg = matches
.value_of("skip")
@@ -214,6 +290,10 @@ fn run() -> Result<(), AnyhowError> {
let squeeze = !matches.is_present("nosqueezing");
let show_char_panel = !matches.is_present("no_chars") && !matches.is_present("plain");
let show_position_panel = !matches.is_present("no_position") && !matches.is_present("plain");
let display_offset: u64 = matches
.value_of("display_offset")
.map(|s| {
@@ -223,13 +303,62 @@ fn run() -> Result<(), AnyhowError> {
))
})
.transpose()?
.unwrap_or(0)
.into();
.unwrap_or(0);
let columns = if let Some(columns) = matches
.value_of("columns")
.map(|s| {
s.parse::<NonZeroU16>().map(u16::from).context(anyhow!(
"failed to parse `--columns` arg {:?} as unsigned nonzero integer",
s
))
})
.transpose()?
{
columns
} else {
let terminal_width = if let Some(terminal_width) = matches
.value_of("terminal_width")
.map(|s| {
s.parse::<NonZeroU16>().map(u16::from).context(anyhow!(
"failed to parse `--columns` arg {:?} as unsigned nonzero integer",
s
))
})
.transpose()?
{
Some(terminal_width)
} else if matches.is_present("auto_width") {
Some(terminal_size().ok_or_else(|| anyhow!("not a TTY"))?.0 .0)
} else {
None
};
if let Some(terminal_width) = terminal_width {
let offset = if show_position_panel { 10 } else { 1 };
let col_width = if show_char_panel { 35 } else { 26 };
if (terminal_width - offset) / col_width < 1 {
1
} else {
(terminal_width - offset) / col_width
}
} else {
2
}
};
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_panel,
show_position_panel,
border_style,
squeeze,
columns,
);
printer.display_offset(skip_offset + display_offset);
printer.print_all(&mut reader).map_err(|e| anyhow!(e))?;
@@ -244,24 +373,7 @@ fn main() {
let result = run();
if let Err(err) = result {
if let Some(clap_err) = err.downcast_ref::<clap::Error>() {
match clap_err.kind {
// The exit code should not indicate an error for --help / --version
clap::ErrorKind::HelpDisplayed => {
eprint!("{}", clap_err); // Clap errors already have newlines
std::process::exit(0)
}
clap::ErrorKind::VersionDisplayed => {
// Version output in clap 2.33.1 (dep as of now) doesn't have a newline
// and the fix is not included even in the latest stable release
println!("");
std::process::exit(0)
}
_ => (),
}
} else {
eprintln!("Error: {:?}", err);
}
eprintln!("Error: {:?}", err);
std::process::exit(1);
}
}
@@ -283,9 +395,9 @@ impl NonNegativeI64 {
}
}
impl Into<u64> for NonNegativeI64 {
fn into(self) -> u64 {
u64::try_from(self.0)
impl From<NonNegativeI64> for u64 {
fn from(x: NonNegativeI64) -> u64 {
u64::try_from(x.0)
.expect("invariant broken: NonNegativeI64 should contain a non-negative i64 value")
}
}
@@ -307,13 +419,50 @@ impl PositiveI64 {
}
}
impl Into<u64> for PositiveI64 {
fn into(self) -> u64 {
u64::try_from(self.0)
impl From<PositiveI64> for u64 {
fn from(x: PositiveI64) -> u64 {
u64::try_from(x.0)
.expect("invariant broken: PositiveI64 should contain a positive i64 value")
}
}
#[derive(Debug, PartialEq)]
enum Unit {
Byte,
Kilobyte,
Megabyte,
Gigabyte,
Terabyte,
Kibibyte,
Mebibyte,
Gibibyte,
Tebibyte,
/// a customizable amount of bytes
Block {
custom_size: Option<NonZeroI64>,
},
}
impl Unit {
const fn get_multiplier(self) -> i64 {
match self {
Self::Byte => 1,
Self::Kilobyte => 1000,
Self::Megabyte => 1_000_000,
Self::Gigabyte => 1_000_000_000,
Self::Terabyte => 1_000_000_000_000,
Self::Kibibyte => 1 << 10,
Self::Mebibyte => 1 << 20,
Self::Gibibyte => 1 << 30,
Self::Tebibyte => 1 << 40,
Self::Block {
custom_size: Some(size),
} => size.get(),
Self::Block { custom_size: None } => DEFAULT_BLOCK_SIZE,
}
}
}
const HEX_PREFIX: &str = "0x";
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
@@ -368,33 +517,14 @@ enum ByteOffsetParseError {
InvalidUnit(String),
#[error("failed to parse integer part")]
ParseNum(#[source] std::num::ParseIntError),
#[error("count multipled by the unit overflowed a signed 64-bit integer; are you sure it should be that big?")]
#[error("count multiplied by the unit overflowed a signed 64-bit integer; are you sure it should be that big?")]
UnitMultiplicationOverflow,
}
fn parse_byte_offset(n: &str, block_size: PositiveI64) -> Result<ByteOffset, ByteOffsetParseError> {
use ByteOffsetParseError::*;
let (n, kind) = {
let mut chars = n.chars();
let next_char = chars.next();
let check_empty_after_sign = || {
if chars.clone().next().is_none() {
Err(EmptyAfterSign)
} else {
Ok(chars.as_str())
}
};
match next_char {
Some('+') => (
check_empty_after_sign()?,
ByteOffsetKind::ForwardFromLastOffset,
),
Some('-') => (check_empty_after_sign()?, ByteOffsetKind::BackwardFromEnd),
None => return Err(Empty),
_ => (n, ByteOffsetKind::ForwardFromBeginning),
}
};
let (n, kind) = process_sign_of(n)?;
let into_byte_offset = |value| {
Ok(ByteOffset {
@@ -403,9 +533,103 @@ fn parse_byte_offset(n: &str, block_size: PositiveI64) -> Result<ByteOffset, Byt
})
};
if n.starts_with(HEX_PREFIX) {
let n = &n[HEX_PREFIX.len()..];
let mut chars = n.chars();
if let Some(hex_number) = try_parse_as_hex_number(n) {
return hex_number.map(into_byte_offset)?;
}
let (num, mut unit) = extract_num_and_unit_from(n)?;
if let Unit::Block { custom_size: None } = unit {
unit = Unit::Block {
custom_size: Some(
NonZeroI64::new(block_size.into_inner()).expect("PositiveI64 was zero"),
),
};
}
num.checked_mul(unit.get_multiplier())
.ok_or(UnitMultiplicationOverflow)
.and_then(into_byte_offset)
}
/// Takes a string containing a base-10 number and an optional unit, and returns them with their proper types.
/// The unit must directly follow the number (e.g. no whitespace is allowed between them).
/// When no unit is given, [Unit::Byte] is assumed.
/// When the unit is [Unit::Block], it is returned without custom size.
/// No normalization is performed, that is "1024" is extracted to (1024, Byte), not (1, Kibibyte).
fn extract_num_and_unit_from(n: &str) -> Result<(i64, Unit), ByteOffsetParseError> {
use ByteOffsetParseError::*;
if n.is_empty() {
return Err(Empty);
}
match n.chars().position(|c| !c.is_ascii_digit()) {
Some(unit_begin_idx) => {
let (n, raw_unit) = n.split_at(unit_begin_idx);
let unit = match raw_unit.to_lowercase().as_str() {
"" => Unit::Byte, // no "b" => Byte to allow hex nums with units
"kb" => Unit::Kilobyte,
"mb" => Unit::Megabyte,
"gb" => Unit::Gigabyte,
"tb" => Unit::Terabyte,
"kib" => Unit::Kibibyte,
"mib" => Unit::Mebibyte,
"gib" => Unit::Gibibyte,
"tib" => Unit::Tebibyte,
"block" | "blocks" => Unit::Block { custom_size: None },
_ => {
return if n.is_empty() {
Err(InvalidNumAndUnit(raw_unit.to_string()))
} else {
Err(InvalidUnit(raw_unit.to_string()))
}
}
};
let num = n.parse::<i64>().map_err(|e| {
if n.is_empty() {
EmptyWithUnit(raw_unit.to_owned())
} else {
ParseNum(e)
}
})?;
Ok((num, unit))
}
None => {
// no unit part
let num = n.parse::<i64>().map_err(ParseNum)?;
Ok((num, Unit::Byte))
}
}
}
/// Extracts a [ByteOffsetKind] based on the sign at the beginning of the given string.
/// Returns the input string without the sign (or an equal string if there wasn't any sign).
fn process_sign_of(n: &str) -> Result<(&str, ByteOffsetKind), ByteOffsetParseError> {
use ByteOffsetParseError::*;
let mut chars = n.chars();
let next_char = chars.next();
let check_empty_after_sign = || {
if chars.clone().next().is_none() {
Err(EmptyAfterSign)
} else {
Ok(chars.as_str())
}
};
match next_char {
Some('+') => Ok((
check_empty_after_sign()?,
ByteOffsetKind::ForwardFromLastOffset,
)),
Some('-') => Ok((check_empty_after_sign()?, ByteOffsetKind::BackwardFromEnd)),
None => Err(Empty),
_ => Ok((n, ByteOffsetKind::ForwardFromBeginning)),
}
}
/// If `n` starts with a hex prefix, its remaining part is returned as some number (if possible),
/// otherwise None is returned.
fn try_parse_as_hex_number(n: &str) -> Option<Result<i64, ByteOffsetParseError>> {
use ByteOffsetParseError::*;
n.strip_prefix(HEX_PREFIX).map(|num| {
let mut chars = num.chars();
match chars.next() {
Some(c @ '+') | Some(c @ '-') => {
return if chars.next().is_none() {
@@ -416,54 +640,70 @@ fn parse_byte_offset(n: &str, block_size: PositiveI64) -> Result<ByteOffset, Byt
}
_ => (),
}
return i64::from_str_radix(n, 16)
.map(into_byte_offset)
.map_err(ParseNum)?;
}
i64::from_str_radix(num, 16).map_err(ParseNum)
})
}
let (num, unit) = match n.chars().position(|c| !c.is_ascii_digit()) {
Some(unit_begin_idx) => {
let (n, raw_unit) = n.split_at(unit_begin_idx);
let raw_unit_lower = raw_unit.to_lowercase();
let multiplier = [
("b", 1),
("kb", 1000i64.pow(1)),
("mb", 1000i64.pow(2)),
("gb", 1000i64.pow(3)),
("tb", 1000i64.pow(4)),
("kib", 1024i64.pow(1)),
("mib", 1024i64.pow(2)),
("gib", 1024i64.pow(3)),
("tib", 1024i64.pow(4)),
("block", block_size.into_inner()),
]
.iter()
.cloned()
.find_map(|(unit, multiplier)| {
if unit == raw_unit_lower {
Some(multiplier)
} else {
None
}
})
.ok_or_else(|| InvalidUnit(raw_unit.to_owned()));
(n, multiplier.map(|m| (Some(raw_unit), m)))
}
None => (n, Ok((None, 1))),
};
#[test]
fn unit_multipliers() {
use Unit::*;
assert_eq!(Kilobyte.get_multiplier(), 1000 * Byte.get_multiplier());
assert_eq!(Megabyte.get_multiplier(), 1000 * Kilobyte.get_multiplier());
assert_eq!(Gigabyte.get_multiplier(), 1000 * Megabyte.get_multiplier());
assert_eq!(Terabyte.get_multiplier(), 1000 * Gigabyte.get_multiplier());
match (num.parse::<i64>(), unit) {
(Ok(num), Ok((_raw_unit, unit_multiplier))) => num
.checked_mul(unit_multiplier)
.ok_or_else(|| UnitMultiplicationOverflow)
.and_then(into_byte_offset),
(Ok(_), Err(e)) => Err(e),
(Err(e), Ok((raw_unit, _unit_multiplier))) => match raw_unit {
Some(raw_unit) if num.is_empty() => Err(EmptyWithUnit(raw_unit.to_owned())),
_ => Err(ParseNum(e)),
},
(Err(_), Err(_)) => Err(InvalidNumAndUnit(n.to_owned())),
}
assert_eq!(Kibibyte.get_multiplier(), 1024 * Byte.get_multiplier());
assert_eq!(Mebibyte.get_multiplier(), 1024 * Kibibyte.get_multiplier());
assert_eq!(Gibibyte.get_multiplier(), 1024 * Mebibyte.get_multiplier());
assert_eq!(Tebibyte.get_multiplier(), 1024 * Gibibyte.get_multiplier());
}
#[test]
fn test_process_sign() {
use ByteOffsetKind::*;
use ByteOffsetParseError::*;
assert_eq!(process_sign_of("123"), Ok(("123", ForwardFromBeginning)));
assert_eq!(process_sign_of("+123"), Ok(("123", ForwardFromLastOffset)));
assert_eq!(process_sign_of("-123"), Ok(("123", BackwardFromEnd)));
assert_eq!(process_sign_of("-"), Err(EmptyAfterSign));
assert_eq!(process_sign_of("+"), Err(EmptyAfterSign));
assert_eq!(process_sign_of(""), Err(Empty));
}
#[test]
fn test_parse_as_hex() {
assert_eq!(try_parse_as_hex_number("73"), None);
assert_eq!(try_parse_as_hex_number("0x1337"), Some(Ok(0x1337)));
assert!(matches!(try_parse_as_hex_number("0xnope"), Some(Err(_))));
assert!(matches!(try_parse_as_hex_number("0x-1"), Some(Err(_))));
}
#[test]
fn extract_num_and_unit() {
use ByteOffsetParseError::*;
use Unit::*;
// byte is default unit
assert_eq!(extract_num_and_unit_from("4"), Ok((4, Byte)));
// blocks are returned without customization
assert_eq!(
extract_num_and_unit_from("2blocks"),
Ok((2, Block { custom_size: None }))
);
// no normalization is performed
assert_eq!(extract_num_and_unit_from("1024kb"), Ok((1024, Kilobyte)));
// unit without number results in error
assert_eq!(
extract_num_and_unit_from("gib"),
Err(EmptyWithUnit("gib".to_string()))
);
// empty string results in error
assert_eq!(extract_num_and_unit_from(""), Err(Empty));
// an invalid unit results in an error
assert_eq!(
extract_num_and_unit_from("25litres"),
Err(InvalidUnit("litres".to_string()))
);
}
#[test]
@@ -472,7 +712,7 @@ fn test_parse_byte_offset() {
macro_rules! success {
($input: expr, $expected_kind: ident $expected_value: expr) => {
success!($input, $expected_kind $expected_value; block_size: 512)
success!($input, $expected_kind $expected_value; block_size: DEFAULT_BLOCK_SIZE)
};
($input: expr, $expected_kind: ident $expected_value: expr; block_size: $block_size: expr) => {
assert_eq!(
@@ -490,7 +730,7 @@ fn test_parse_byte_offset() {
macro_rules! error {
($input: expr, $expected_err: expr) => {
assert_eq!(
parse_byte_offset($input, PositiveI64::new(512).unwrap()),
parse_byte_offset($input, PositiveI64::new(DEFAULT_BLOCK_SIZE).unwrap()),
Err($expected_err),
);
};
+243 -135
View File
@@ -146,20 +146,27 @@ pub struct Printer<'a, Writer: Write> {
buffer_line: Vec<u8>,
writer: &'a mut Writer,
show_color: bool,
show_char_panel: bool,
show_position_panel: bool,
border_style: BorderStyle,
header_was_printed: bool,
byte_hex_table: Vec<String>,
byte_char_table: Vec<String>,
byte_hex_panel: Vec<String>,
byte_char_panel: Vec<String>,
squeezer: Squeezer,
display_offset: u64,
/// The number of panels to draw.
columns: u16,
}
impl<'a, Writer: Write> Printer<'a, Writer> {
pub fn new(
writer: &'a mut Writer,
show_color: bool,
show_char_panel: bool,
show_position_panel: bool,
border_style: BorderStyle,
use_squeeze: bool,
columns: u16,
) -> Printer<'a, Writer> {
Printer {
idx: 1,
@@ -167,9 +174,11 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
buffer_line: vec![],
writer,
show_color,
show_char_panel,
show_position_panel,
border_style,
header_was_printed: false,
byte_hex_table: (0u8..=u8::max_value())
byte_hex_panel: (0u8..=u8::MAX)
.map(|i| {
let byte_hex = format!("{:02x} ", i);
if show_color {
@@ -179,18 +188,23 @@ 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_panel: show_char_panel
.then(|| {
(0u8..=u8::MAX)
.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(),
squeezer: Squeezer::new(use_squeeze),
.unwrap_or_default(),
squeezer: Squeezer::new(use_squeeze, 8 * columns as u64),
display_offset: 0,
columns,
}
}
@@ -199,48 +213,59 @@ 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_panel {
write!(self.writer, "{l}{h8}{c}", l = l, c = c, h8 = h8).ok();
} else {
write!(self.writer, "{}", l).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 {
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();
}
}
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 print_header(&mut self) {
if self.header_was_printed {
return;
}
if let Some(e) = self.border_style.header_elems() {
self.write_border(e)
}
self.header_was_printed = true;
}
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 print_footer(&mut self) {
if let Some(e) = self.border_style.footer_elems() {
self.write_border(e)
}
}
fn print_position_indicator(&mut self) {
if !self.header_was_printed {
self.header();
self.header_was_printed = true;
fn print_position_panel(&mut self) {
if !self.show_position_panel {
write!(&mut self.buffer_line, "{} ", self.border_style.outer_sep()).ok();
return;
}
let style = COLOR_OFFSET.normal();
@@ -259,24 +284,60 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
);
}
pub fn print_byte(&mut self, b: u8) -> io::Result<()> {
if self.idx % 16 == 1 {
self.print_position_indicator();
pub fn print_char_panel(&mut self) {
if !self.show_char_panel {
// just write newline if character panel is hidden
writeln!(&mut self.buffer_line).ok();
return;
}
write!(&mut self.buffer_line, "{}", self.byte_hex_table[b as usize])?;
let len = self.raw_line.len();
let mut idx = 1;
for &b in self.raw_line.iter() {
let _ = write!(
&mut self.buffer_line,
"{}",
self.byte_char_panel[b as usize]
);
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 < 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 % (u64::from(self.columns) * 8) == 1 {
self.print_header();
self.print_position_panel();
}
write!(&mut self.buffer_line, "{}", self.byte_hex_panel[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, "{} ", 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;
@@ -289,17 +350,34 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
if len == 0 {
if self.squeezer.active() {
self.print_position_indicator();
let _ = writeln!(
self.print_position_panel();
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(());
@@ -307,62 +385,23 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
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()
);
}
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());
if len < usize::from(8 * self.columns) {
write!(&mut self.buffer_line, "{0:1$}", "", 3 * (8 - len % 8))?;
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()
)?;
}
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()
);
}
write!(&mut self.buffer_line, "{}", self.border_style.outer_sep())?;
}
self.print_char_panel();
match squeeze_action {
SqueezeAction::Print => {
@@ -373,17 +412,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 => (),
@@ -430,14 +485,22 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
self.print_textline().ok();
if !self.header_was_printed() {
self.header();
writeln!(
self.print_header();
if self.show_position_panel {
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_panel {
write!(self.writer, "{0:>9}{0:>9}", "│").ok();
}
writeln!(self.writer).ok();
}
self.footer();
self.print_footer();
Ok(())
}
@@ -450,14 +513,22 @@ mod tests {
use super::*;
fn assert_print_all_output<Reader: Read>(input: Reader, expected_string: String) -> () {
fn assert_print_all_output<Reader: Read>(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,
2,
);
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]
@@ -496,8 +567,15 @@ mod tests {
.to_owned();
let mut output = vec![];
let mut printer: Printer<Vec<u8>> =
Printer::new(&mut output, false, 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();
@@ -505,4 +583,34 @@ mod tests {
let actual_string: &str = str::from_utf8(&output).unwrap();
assert_eq!(actual_string, expected_string)
}
#[test]
fn multiple_columns() {
let input = io::Cursor::new(b"supercalifragilisticexpialidocioussupercalifragilisticexpialidocioussupercalifragilisticexpialidocious");
let expected_string = "\
┌────────┬─────────────────────────┬─────────────────────────┬─────────────────────────┬─────────────────────────┬────────┬────────┬────────┬────────┐
│00000000│ 73 75 70 65 72 63 61 6c ┊ 69 66 72 61 67 69 6c 69 ┊ 73 74 69 63 65 78 70 69 ┊ 61 6c 69 64 6f 63 69 6f │supercal┊ifragili┊sticexpi┊alidocio│
│00000020│ 75 73 73 75 70 65 72 63 ┊ 61 6c 69 66 72 61 67 69 ┊ 6c 69 73 74 69 63 65 78 ┊ 70 69 61 6c 69 64 6f 63 │ussuperc┊alifragi┊listicex┊pialidoc│
│00000040│ 69 6f 75 73 73 75 70 65 ┊ 72 63 61 6c 69 66 72 61 ┊ 67 69 6c 69 73 74 69 63 ┊ 65 78 70 69 61 6c 69 64 │ioussupe┊rcalifra┊gilistic┊expialid│
│00000060│ 6f 63 69 6f 75 73 ┊ ┊ ┊ │ocious ┊ ┊ ┊ │
└────────┴─────────────────────────┴─────────────────────────┴─────────────────────────┴─────────────────────────┴────────┴────────┴────────┴────────┘
"
.to_owned();
let mut output = vec![];
let mut printer: Printer<Vec<u8>> = Printer::new(
&mut output,
false,
true,
true,
BorderStyle::Unicode,
true,
4,
);
printer.print_all(input).unwrap();
let actual_string: &str = str::from_utf8(&output).unwrap();
assert_eq!(actual_string, expected_string)
}
}
+29 -47
View File
@@ -22,6 +22,7 @@ enum SqueezeState {
pub struct Squeezer {
state: SqueezeState,
byte: u8,
lsize: u64,
}
#[derive(Debug, PartialEq)]
@@ -31,11 +32,8 @@ pub enum SqueezeAction {
Delete,
}
/// line size
const LSIZE: u64 = 16;
impl Squeezer {
pub fn new(enabled: bool) -> Squeezer {
pub fn new(enabled: bool, lsize: u64) -> Squeezer {
Squeezer {
state: if enabled {
SqueezeState::Probe
@@ -43,6 +41,7 @@ impl Squeezer {
SqueezeState::Disabled
},
byte: 0,
lsize,
}
}
@@ -53,7 +52,7 @@ impl Squeezer {
}
let eq = b == self.byte;
if i % LSIZE == 0 {
if i % self.lsize == 0 {
if !eq {
self.state = Probe;
} else {
@@ -68,9 +67,9 @@ impl Squeezer {
};
}
} else if !eq {
if i % LSIZE == 1 {
if i % self.lsize == 1 {
self.state = Probe;
} else if i % LSIZE != 1 {
} else if i % self.lsize != 1 {
self.state = NoSqueeze;
}
}
@@ -80,10 +79,10 @@ impl Squeezer {
pub fn active(&self) -> bool {
use self::SqueezeState::*;
match self.state {
Squeeze | SqueezeActive | SqueezeFirstLine | SqueezeActiveFirstLine => true,
_ => false,
}
matches!(
self.state,
Squeeze | SqueezeActive | SqueezeFirstLine | SqueezeActiveFirstLine
)
}
pub fn action(&self) -> SqueezeAction {
@@ -111,13 +110,14 @@ impl Squeezer {
mod tests {
use super::*;
const LSIZE: u64 = 16;
const LSIZE_USIZE: usize = LSIZE as usize;
#[test]
fn three_same_lines() {
const LINES: usize = 3;
let v = vec![0u8; LINES * LSIZE_USIZE];
let mut s = Squeezer::new(true);
let mut s = Squeezer::new(true, LSIZE);
// just initialized
assert_eq!(s.action(), SqueezeAction::Ignore);
s.advance();
@@ -128,9 +128,8 @@ mod tests {
SqueezeAction::Delete, // delete reoccurring line
];
let mut line = 0;
let mut idx = 1;
for z in v.chunks(LSIZE_USIZE) {
for (line, z) in v.chunks(LSIZE_USIZE).enumerate() {
for i in z {
s.process(*i, idx);
idx += 1;
@@ -138,7 +137,6 @@ mod tests {
let action = s.action();
s.advance();
assert_eq!(action, exp[line]);
line += 1;
}
}
@@ -146,7 +144,7 @@ mod tests {
fn incomplete_while_squeeze() {
// fourth line only has 12 bytes and should be printed
let v = vec![0u8; 3 * LSIZE_USIZE + 12];
let mut s = Squeezer::new(true);
let mut s = Squeezer::new(true, LSIZE);
// just initialized
assert_eq!(s.action(), SqueezeAction::Ignore);
s.advance();
@@ -158,16 +156,14 @@ mod tests {
SqueezeAction::Ignore, // last line only 12 bytes, print it
];
let mut line = 0;
let mut idx = 1;
for z in v.chunks(LSIZE_USIZE) {
for (line, z) in v.chunks(LSIZE_USIZE).enumerate() {
for i in z {
s.process(*i, idx);
idx += 1;
}
assert_eq!(s.action(), exp[line]);
s.advance();
line += 1;
}
}
@@ -179,7 +175,7 @@ mod tests {
v.extend(vec![1u8; 16]);
v.extend(vec![2u8; 16]);
let mut s = Squeezer::new(true);
let mut s = Squeezer::new(true, LSIZE);
// just initialized
assert_eq!(s.action(), SqueezeAction::Ignore);
s.advance();
@@ -190,9 +186,8 @@ mod tests {
SqueezeAction::Ignore, // different
];
let mut line = 0;
let mut idx = 1;
for z in v.chunks(LSIZE_USIZE) {
for (line, z) in v.chunks(LSIZE_USIZE).enumerate() {
for i in z {
s.process(*i, idx);
idx += 1;
@@ -200,7 +195,6 @@ mod tests {
let action = s.action();
assert_eq!(action, exp[line]);
s.advance();
line += 1;
}
}
@@ -212,7 +206,7 @@ mod tests {
let mut v = vec![0u8; (LINES - 1) * LSIZE_USIZE];
v.extend(vec![1u8; 16]);
let mut s = Squeezer::new(true);
let mut s = Squeezer::new(true, LSIZE);
// just initialized
assert_eq!(s.action(), SqueezeAction::Ignore);
s.advance();
@@ -223,9 +217,8 @@ mod tests {
SqueezeAction::Ignore, // different lines, print again
];
let mut line = 0;
let mut idx = 1;
for z in v.chunks(LSIZE_USIZE) {
for (line, z) in v.chunks(LSIZE_USIZE).enumerate() {
for i in z {
s.process(*i, idx);
idx += 1;
@@ -233,7 +226,6 @@ mod tests {
let action = s.action();
s.advance();
assert_eq!(action, exp[line]);
line += 1;
}
}
@@ -245,7 +237,7 @@ mod tests {
v.extend(vec![0u8; 8]);
v.extend(vec![1u8; 8]);
let mut s = Squeezer::new(true);
let mut s = Squeezer::new(true, LSIZE);
// just initialized
assert_eq!(s.action(), SqueezeAction::Ignore);
s.advance();
@@ -255,9 +247,8 @@ mod tests {
SqueezeAction::Ignore, // print squeeze symbol
];
let mut line = 0;
let mut idx = 1;
for z in v.chunks(LSIZE_USIZE) {
for (line, z) in v.chunks(LSIZE_USIZE).enumerate() {
for i in z {
s.process(*i, idx);
idx += 1;
@@ -265,7 +256,6 @@ mod tests {
let action = s.action();
s.advance();
assert_eq!(action, exp[line]);
line += 1;
}
}
@@ -280,7 +270,7 @@ mod tests {
v.extend(vec![0u8; 8]);
v.extend(vec![1u8; 8]);
let mut s = Squeezer::new(true);
let mut s = Squeezer::new(true, LSIZE);
// just initialized
assert_eq!(s.action(), SqueezeAction::Ignore);
s.advance();
@@ -291,9 +281,8 @@ mod tests {
SqueezeAction::Ignore, // print squeeze symbol
];
let mut line = 0;
let mut idx = 1;
for z in v.chunks(LSIZE_USIZE) {
for (line, z) in v.chunks(LSIZE_USIZE).enumerate() {
for i in z {
s.process(*i, idx);
idx += 1;
@@ -301,7 +290,6 @@ mod tests {
let action = s.action();
s.advance();
assert_eq!(action, exp[line]);
line += 1;
}
}
@@ -321,7 +309,7 @@ mod tests {
v.extend(vec![20u8; 16]); // print
v.extend(vec![0u8; 12]); // print, only 12 bytes
let mut s = Squeezer::new(true);
let mut s = Squeezer::new(true, LSIZE);
// just initialized
assert_eq!(s.action(), SqueezeAction::Ignore);
s.advance();
@@ -341,9 +329,8 @@ mod tests {
SqueezeAction::Ignore,
];
let mut line = 0;
let mut idx = 1;
for z in v.chunks(LSIZE_USIZE) {
for (line, z) in v.chunks(LSIZE_USIZE).enumerate() {
for i in z {
s.process(*i, idx);
idx += 1;
@@ -351,7 +338,6 @@ mod tests {
let action = s.action();
s.advance();
assert_eq!(action, exp[line]);
line += 1;
}
}
@@ -365,7 +351,7 @@ mod tests {
v.extend(vec![20u8; 16]);
v.extend(vec![20u8; 16]);
let mut s = Squeezer::new(true);
let mut s = Squeezer::new(true, LSIZE);
// just initialized
assert_eq!(s.action(), SqueezeAction::Ignore);
s.advance();
@@ -377,16 +363,14 @@ mod tests {
SqueezeAction::Print, // print '*' char
];
let mut line = 0;
let mut idx = 1;
for z in v.chunks(LSIZE_USIZE) {
for (line, z) in v.chunks(LSIZE_USIZE).enumerate() {
for i in z {
s.process(*i, idx);
idx += 1;
}
assert_eq!(s.action(), exp[line]);
s.advance();
line += 1;
}
}
@@ -399,7 +383,7 @@ mod tests {
v.extend(vec![20u8; 15]);
v.extend(vec![20u8; 16]);
let mut s = Squeezer::new(true);
let mut s = Squeezer::new(true, LSIZE);
// just initialized
assert_eq!(s.action(), SqueezeAction::Ignore);
s.advance();
@@ -410,16 +394,14 @@ mod tests {
SqueezeAction::Ignore, // print as is
];
let mut line = 0;
let mut idx = 1;
for z in v.chunks(LSIZE_USIZE) {
for (line, z) in v.chunks(LSIZE_USIZE).enumerate() {
for i in z {
s.process(*i, idx);
idx += 1;
}
assert_eq!(s.action(), exp[line]);
s.advance();
line += 1;
}
}
}
+69 -1
View File
@@ -1,7 +1,7 @@
use assert_cmd::Command;
fn hexyl() -> Command {
let mut cmd = Command::cargo_bin("hexyl").unwrap();
let mut cmd = Command::new(assert_cmd::cargo_bin!("hexyl"));
cmd.current_dir("tests/examples");
cmd
}
@@ -85,6 +85,30 @@ mod length {
.assert()
.failure();
}
#[test]
fn fail_if_length_and_count_options_are_used_simultaneously() {
hexyl()
.arg("hello_world_elf64")
.arg("--length=32")
.arg("-l=10")
.assert()
.failure();
}
}
mod bytes {
use super::hexyl;
#[test]
fn fail_if_bytes_and_count_options_are_used_simultaneously() {
hexyl()
.arg("hello_world_elf64")
.arg("--bytes=32")
.arg("-l=10")
.assert()
.failure();
}
}
mod skip {
@@ -203,3 +227,47 @@ 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-characters")
.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",
);
}
}