mirror of
https://github.com/sharkdp/hexyl.git
synced 2026-10-29 08:05:57 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
49484fa0f0 | ||
|
|
3661b06b60 | ||
|
|
f5814d4442 | ||
|
|
49ebf4771f | ||
|
|
4904a7e26f | ||
|
|
becc1b80f1 | ||
|
|
1fb5263c3b | ||
|
|
0ae89168ad | ||
|
|
6873867658 | ||
|
|
f15e049bf5 | ||
|
|
1d04cdf119 | ||
|
|
5d92f07e21 | ||
|
|
a4ed50e1f0 | ||
|
|
f7f7447994 | ||
|
|
e4f0e8a092 | ||
|
|
a23645ddfd | ||
|
|
7da04c6bff | ||
|
|
c497c1fac9 | ||
|
|
653cf02954 | ||
|
|
18cdbe02c5 | ||
|
|
d1ae68585f | ||
|
|
7a225fe732 | ||
|
|
1b33e516d9 | ||
|
|
55d02c933a | ||
|
|
b8ed8d5df9 | ||
|
|
641c32e395 | ||
|
|
51b28ed0b0 | ||
|
|
825100c6d6 | ||
|
|
1b1fc4b053 | ||
|
|
c3dd4e871e | ||
|
|
923bceffaa | ||
|
|
2942d2419f | ||
|
|
37d4180f9a | ||
|
|
99435cd215 | ||
|
|
27f039d72a | ||
|
|
e72422ecfb | ||
|
|
3c56ed2b0e | ||
|
|
a09ea8ee27 | ||
|
|
d6bdfe9897 | ||
|
|
7c9f7e1bd0 | ||
|
|
b1d2a47590 |
No files matched your search
@@ -1,7 +1,7 @@
|
||||
name: CICD
|
||||
|
||||
env:
|
||||
MIN_SUPPORTED_RUST_VERSION: "1.40.0"
|
||||
MIN_SUPPORTED_RUST_VERSION: "1.56.0"
|
||||
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}"
|
||||
|
||||
@@ -1,2 +1,5 @@
|
||||
/target
|
||||
**/*.rs.bk
|
||||
|
||||
# Generated files
|
||||
hexyl.1
|
||||
+23
-2
@@ -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
@@ -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
+146
-82
@@ -1,5 +1,7 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[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"
|
||||
@@ -29,15 +22,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.42"
|
||||
version = "1.0.57"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "595d3cfa7a60d4555cb5067b99f07142a08ea778de5cf993f7b75c7d8fabc486"
|
||||
checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc"
|
||||
|
||||
[[package]]
|
||||
name = "assert_cmd"
|
||||
version = "1.0.7"
|
||||
version = "2.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d20831bd004dda4c7c372c19cdabff369f794a95e955b3f13fe460e3e1ae95f"
|
||||
checksum = "93ae1ddd39efd67689deb1979d80bad3bf7f2b09c6e6117c8d1f2443b5e2f83e"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"doc-comment",
|
||||
@@ -60,21 +53,21 @@ 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 = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90682c8d613ad3373e66de8c6411e0ae2ab2571e879d2efbf73558cc66f21279"
|
||||
checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"memchr",
|
||||
@@ -83,17 +76,48 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.33.3"
|
||||
version = "3.1.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
|
||||
checksum = "d2dbdf4bdacb33466e854ce889eee8dfd5729abf7ccd7664d0a2d60cd384440b"
|
||||
dependencies = [
|
||||
"ansi_term 0.11.0",
|
||||
"atty",
|
||||
"bitflags",
|
||||
"clap_lex",
|
||||
"indexmap",
|
||||
"lazy_static",
|
||||
"strsim",
|
||||
"term_size",
|
||||
"termcolor",
|
||||
"terminal_size",
|
||||
"textwrap",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a37c35f1112dad5e6e0b1adaff798507497a18fceeb30cceb3bae7d1427b9213"
|
||||
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]]
|
||||
@@ -116,13 +140,19 @@ checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
||||
|
||||
[[package]]
|
||||
name = "float-cmp"
|
||||
version = "0.8.0"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1267f4ac4f343772758f7b1bdcbe767c218bbab93bb432acbf5162bbf85a6c4"
|
||||
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,23 +164,34 @@ 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",
|
||||
"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 = "itertools"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
@@ -163,15 +204,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.98"
|
||||
version = "0.2.126"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790"
|
||||
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.4.0"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
|
||||
[[package]]
|
||||
name = "normalize-line-endings"
|
||||
@@ -181,18 +222,24 @@ 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 = "os_str_bytes"
|
||||
version = "6.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6e46ca79eb4e21e2ec14430340c71250ab69332abf85521c95d3a8bc336aa76"
|
||||
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",
|
||||
@@ -204,43 +251,43 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "predicates-core"
|
||||
version = "1.0.2"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57e35a3326b75e49aa85f5dc6ec15b41108cf5aee58eabb1f274dd18b73c2451"
|
||||
checksum = "da1c2388b1513e1b605fcec39a95e0a9e8ef088f71443ef37099fa9ae6673fcb"
|
||||
|
||||
[[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",
|
||||
@@ -255,61 +302,75 @@ checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
|
||||
|
||||
[[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"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.73"
|
||||
version = "1.0.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7"
|
||||
checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "term_size"
|
||||
version = "0.3.2"
|
||||
name = "termcolor"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e4129646ca0ed8f45d09b929036bafad5377103edd06e50bf574b353d2b08d9"
|
||||
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 = "termtree"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
checksum = "507e9898683b6c43a9aa55b64259b721b52ba226e0f3779137e50ad114a4c90b"
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
|
||||
dependencies = [
|
||||
"term_size",
|
||||
"unicode-width",
|
||||
"terminal_size",
|
||||
]
|
||||
|
||||
[[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 +378,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,6 +414,15 @@ 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"
|
||||
|
||||
+8
-7
@@ -7,23 +7,24 @@ 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"
|
||||
|
||||
[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.0"
|
||||
predicates = "2.0"
|
||||
|
||||
[profile.release]
|
||||
|
||||
@@ -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
|
||||
```
|
||||
@@ -53,6 +53,7 @@ pacman -S hexyl
|
||||
```
|
||||
|
||||
### On Void Linux
|
||||
|
||||
```
|
||||
xbps-install hexyl
|
||||
```
|
||||
@@ -91,7 +92,7 @@ pkg install hexyl
|
||||
```
|
||||
pkg install hexyl
|
||||
```
|
||||
or
|
||||
or
|
||||
```
|
||||
apt install hexyl
|
||||
```
|
||||
@@ -116,30 +117,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 +0,0 @@
|
||||
*.bash linguist-vendored
|
||||
@@ -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
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
% 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 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)
|
||||
+10
-1
@@ -12,9 +12,18 @@ 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 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,
|
||||
);
|
||||
printer.print_all(&input[..]).unwrap();
|
||||
}
|
||||
+290
-131
@@ -4,46 +4,50 @@ extern crate clap;
|
||||
use std::convert::TryFrom;
|
||||
use std::fs::File;
|
||||
use std::io::{self, prelude::*, SeekFrom};
|
||||
use std::num::NonZeroI64;
|
||||
|
||||
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 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 +55,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 +76,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 +97,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 +126,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")
|
||||
@@ -128,7 +151,7 @@ fn run() -> Result<(), AnyhowError> {
|
||||
),
|
||||
);
|
||||
|
||||
let matches = app.get_matches_safe()?;
|
||||
let matches = command.get_matches();
|
||||
|
||||
let stdin = io::stdin();
|
||||
|
||||
@@ -140,12 +163,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 +252,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 +265,19 @@ fn run() -> Result<(), AnyhowError> {
|
||||
))
|
||||
})
|
||||
.transpose()?
|
||||
.unwrap_or(0)
|
||||
.into();
|
||||
.unwrap_or(0);
|
||||
|
||||
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,
|
||||
);
|
||||
printer.display_offset(skip_offset + display_offset);
|
||||
printer.print_all(&mut reader).map_err(|e| anyhow!(e))?;
|
||||
|
||||
@@ -244,24 +292,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 +314,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 +338,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 +436,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 +452,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 +559,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 +631,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 +649,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),
|
||||
);
|
||||
};
|
||||
|
||||
+126
-94
@@ -146,10 +146,12 @@ 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,
|
||||
}
|
||||
@@ -158,6 +160,8 @@ 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,
|
||||
) -> Printer<'a, Writer> {
|
||||
@@ -167,9 +171,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_value())
|
||||
.map(|i| {
|
||||
let byte_hex = format!("{:02x} ", i);
|
||||
if show_color {
|
||||
@@ -179,16 +185,20 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
byte_char_table: (0u8..=u8::max_value())
|
||||
.map(|i| {
|
||||
let byte_char = format!("{}", Byte(i).as_char());
|
||||
if show_color {
|
||||
Byte(i).color().paint(byte_char).to_string()
|
||||
} else {
|
||||
byte_char
|
||||
}
|
||||
byte_char_panel: show_char_panel
|
||||
.then(|| {
|
||||
(0u8..=u8::max_value())
|
||||
.map(|i| {
|
||||
let byte_char = format!("{}", Byte(i).as_char());
|
||||
if show_color {
|
||||
Byte(i).color().paint(byte_char).to_string()
|
||||
} else {
|
||||
byte_char
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
.collect(),
|
||||
.unwrap_or_default(),
|
||||
squeezer: Squeezer::new(use_squeeze),
|
||||
display_offset: 0,
|
||||
}
|
||||
@@ -199,48 +209,49 @@ 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();
|
||||
}
|
||||
|
||||
write!(self.writer, "{h25}{c}{h25}", c = c, h25 = h25).ok();
|
||||
|
||||
if self.show_char_panel {
|
||||
writeln!(self.writer, "{c}{h8}{c}{h8}{r}", c = c, h8 = h8, r = r).ok();
|
||||
} else {
|
||||
writeln!(self.writer, "{r}", r = r).ok();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn footer(&mut self) {
|
||||
if let Some(border_elements) = self.border_style.footer_elems() {
|
||||
let h = border_elements.horizontal_line;
|
||||
let h8 = h.to_string().repeat(8);
|
||||
let h25 = h.to_string().repeat(25);
|
||||
pub fn 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,12 +270,58 @@ 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 {
|
||||
let _ = write!(&mut self.buffer_line, "{}", self.border_style.inner_sep());
|
||||
}
|
||||
|
||||
idx += 1;
|
||||
}
|
||||
|
||||
if len < 8 {
|
||||
let _ = writeln!(
|
||||
&mut self.buffer_line,
|
||||
"{0:1$}{3}{0:2$}{4}",
|
||||
"",
|
||||
8 - len,
|
||||
8,
|
||||
self.border_style.inner_sep(),
|
||||
self.border_style.outer_sep(),
|
||||
);
|
||||
} else {
|
||||
let _ = writeln!(
|
||||
&mut self.buffer_line,
|
||||
"{0:1$}{2}",
|
||||
"",
|
||||
16 - len,
|
||||
self.border_style.outer_sep()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_byte(&mut self, b: u8) -> io::Result<()> {
|
||||
if self.idx % 16 == 1 {
|
||||
self.print_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);
|
||||
@@ -289,7 +346,7 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
|
||||
|
||||
if len == 0 {
|
||||
if self.squeezer.active() {
|
||||
self.print_position_indicator();
|
||||
self.print_position_panel();
|
||||
let _ = writeln!(
|
||||
&mut self.buffer_line,
|
||||
"{0:1$}{4}{0:2$}{5}{0:3$}{4}{0:3$}{5}",
|
||||
@@ -327,43 +384,10 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
|
||||
self.border_style.outer_sep()
|
||||
);
|
||||
}
|
||||
|
||||
let mut idx = 1;
|
||||
for &b in self.raw_line.iter() {
|
||||
let _ = write!(
|
||||
&mut self.buffer_line,
|
||||
"{}",
|
||||
self.byte_char_table[b as usize]
|
||||
);
|
||||
|
||||
if idx == 8 {
|
||||
let _ = write!(&mut self.buffer_line, "{}", self.border_style.inner_sep());
|
||||
}
|
||||
|
||||
idx += 1;
|
||||
}
|
||||
|
||||
if len < 8 {
|
||||
let _ = writeln!(
|
||||
&mut self.buffer_line,
|
||||
"{0:1$}{3}{0:2$}{4}",
|
||||
"",
|
||||
8 - len,
|
||||
8,
|
||||
self.border_style.inner_sep(),
|
||||
self.border_style.outer_sep(),
|
||||
);
|
||||
} else {
|
||||
let _ = writeln!(
|
||||
&mut self.buffer_line,
|
||||
"{0:1$}{2}",
|
||||
"",
|
||||
16 - len,
|
||||
self.border_style.outer_sep()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
self.print_char_panel();
|
||||
|
||||
match squeeze_action {
|
||||
SqueezeAction::Print => {
|
||||
self.buffer_line.clear();
|
||||
@@ -430,14 +454,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 +482,14 @@ 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);
|
||||
|
||||
printer.print_all(input).unwrap();
|
||||
|
||||
let actual_string: &str = str::from_utf8(&output).unwrap();
|
||||
assert_eq!(actual_string, expected_string)
|
||||
assert_eq!(actual_string, expected_string,)
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -497,7 +529,7 @@ mod tests {
|
||||
|
||||
let mut output = vec![];
|
||||
let mut printer: Printer<Vec<u8>> =
|
||||
Printer::new(&mut output, false, BorderStyle::Unicode, true);
|
||||
Printer::new(&mut output, false, true, true, BorderStyle::Unicode, true);
|
||||
printer.display_offset(0xdeadbeef);
|
||||
|
||||
printer.print_all(input).unwrap();
|
||||
|
||||
+13
-31
@@ -80,10 +80,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 {
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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",
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user