375 Commits
Author SHA1 Message Date
David Peter 6ecc29b9c8 Remove sponsors 2026-04-30 10:24:05 +02:00
David Peter 8eb6d4771c Bump version to v0.17.0 2026-02-14 13:53:54 +01:00
David Peter 5d05382df8 Update README 2026-02-14 13:50:33 +01:00
David Peter 626f03bfbd Fix #254 2026-02-14 13:49:10 +01:00
n4n5 04d74bae47 feat: handle standard input "-" (#257) 2026-02-14 13:33:23 +01:00
n4n5 96e427cb4a Improve crate && fix CI (#256)
* feat: improve crate

* fix: CI
2026-02-14 13:09:13 +01:00
Filip Czaplicki 7f8db4f113 Add colors to --help (#253)
Thank you!
2026-02-14 13:08:00 +01:00
王品呈 2e2643782d Add option to output result in C include file style (#242) (#246)
* feat: Implement "-i/-include" option

* make clippy happy

Suppress clippy warning for too many arguments in Printer struct

* add tests & use buffered reading for include mode to handle large files

* Update CHANGELOG
2025-10-19 21:38:21 +02:00
David Peter 269860ba7e Update README 2025-09-23 19:38:25 +02:00
David Peter 2c8be77181 Update README 2025-09-04 09:00:22 +02:00
David Peter f16e2c96ea Fix CHANGELOG formatting 2025-08-31 21:40:15 +02:00
Friedrich 'friedɀ' SchwedlerandDavid Peter 585d06293a Add shell completion (#251)
* add commandline argument to generate shell completion

* update changelog

* fixup! add commandline argument to generate shell completion

* Update option name and description

---------

Co-authored-by: David Peter <mail@david-peter.de>
2025-08-31 21:39:17 +02:00
David Peter 909dd7d947 Update Windows runners 2025-08-31 21:22:59 +02:00
David Peter 5a295296fe Fix formatting 2025-08-31 21:21:22 +02:00
David Peter 38301f3759 Fix clippy, CI 2025-08-31 21:17:54 +02:00
Niclas SchwarzloseandDavid Peter f2547aed69 Add new braille character table and color schemes (#247)
* Add new braille character table and color schemes

* Add character for tab and change color for 0x7f

---------

Co-authored-by: David Peter <mail@david-peter.de>
2025-08-31 21:13:57 +02:00
Dan Hipschman 9ef7c346dd Enable custom colors with environment variables (#248)
* Enable custom colors with environment variables

* Rename HEXYL_XYZ env vars to HEXYL_COLOR_XYZ
2025-06-16 22:41:37 +02:00
Regis Boudinot 6220cae644 Check if terminal_width is less than offset and return 1 (see #244) (#245) 2025-06-08 21:35:42 +02:00
David Peter ad553e9e33 Merge pull request #249 from dan-hipschman/fix-ci
Fix CI
2025-06-08 21:11:18 +02:00
Dan Hipschman fbbd5e3733 Fix CI 2025-05-13 15:18:02 -07:00
David Peter 742c2fcbfd Update README 2025-03-09 19:29:26 +01:00
David Peter 79f7076b02 Merge pull request #239 from ilmanzo/issue238
Fix issue #238
2025-03-02 19:28:12 +01:00
David Peter cba09bf7b7 Merge pull request #241 from saulvaldelvira/master
Fix some clippy warnings
2025-02-19 21:39:49 +01:00
Saúl Valdelvira 06ff4b750e Fix some clippy warnings
Changes:
- Elid lifetimes when possible
- Use a slice instead of a Vec as function argument
- Rewrite &[b'*''] to b"*"
2025-02-19 12:44:08 +01:00
Andrea Manzini 630d92fb8f Fix issue #238 2025-01-26 18:54:13 +01:00
David Peter abc20a380c Bump version 2024-12-27 14:43:18 +01:00
David Peter dd89c22327 Remove color reference from README 2024-12-27 14:42:27 +01:00
David Peter 45a557e0df Merge pull request #235 from sahinfalcon/print-colour-table
PR #229 • Add option to print color table
2024-12-27 14:41:12 +01:00
David Peter 73cfd05a10 Minor updates 2024-12-27 14:37:04 +01:00
Taylan Sahin 37e9ef6a64 cargo fmt 2024-12-27 14:35:04 +01:00
Taylan Sahin 568f38ae77 PR #229 • Add option to print color table 2024-12-27 14:35:03 +01:00
David Peter 6e0bff2cc5 Merge pull request #234 from Integral-Tech/error-on-dir
fix: throw an error when try to view a directory
2024-12-27 14:29:34 +01:00
David Peter 1783fe6a9b Merge pull request #233 from lunrenyi/patch-1
docs(install): add x-cmd method to install hexyl
2024-12-27 14:26:02 +01:00
David Peter 733b9e12e4 Fix CI 2024-12-27 14:25:01 +01:00
David Peter 19198c2aac Minor updates 2024-12-27 14:23:02 +01:00
Integral c65b298e60 fix: throw an error when try to view a directory 2024-11-21 00:55:37 +08:00
lunrenyi f986c196d2 docs(install): add x-cmd method to install hexyl 2024-11-12 14:30:33 +08:00
David Peter dbed12e423 Update MSRV 2024-10-29 22:44:53 +01:00
David Peter 1927610953 Update MSRV 2024-10-29 22:42:12 +01:00
David Peter f8531b3e44 Updates for v0.15.0 2024-10-29 22:17:12 +01:00
David Peter 427a5524e1 Merge pull request #226 from v1gnesh/master
Add codepage 1047 for EBCDIC
2024-09-08 13:09:17 +02:00
v1gnesh 120cf29adf Add codepage 1047 for EBCDIC 2024-08-04 15:18:38 +05:30
David Peter d2cc025c6f Merge pull request #225 from sorairolake/rewrite-in-derive-api
Rewrite CLI using the derive API
2024-07-16 21:29:59 +02:00
Shun Sakai f8b87cc5e2 Change help output
Even if `-h` is specified, other than the first sentence will also be
printed.
2024-07-02 18:23:30 +09:00
Shun Sakai 252a6dbef4 Rewrite CLI using derive API 2024-07-01 22:39:28 +09:00
David Peter 16cc5d9757 Merge pull request #222 from wxpppp/master
deps: bump libc from 0.2.147 to 0.2.155
2024-06-22 21:35:19 +02:00
wangweijie d51086e0da deps: bump libc from 0.2.147 to 0.2.155
Signed-off-by: wangweijie <wangweijie@loongson.cn>
2024-06-06 10:17:30 +08:00
David Peter d8a26da964 Merge pull request #216 from FilipRazek/fix-upload-artifact-job
ci: Fix Debian artifact names
2024-01-25 09:15:36 +01:00
Filip Razek dcce9e1011 ci: Fix Debian artifact names 2024-01-24 22:38:28 +01:00
David Peter 651087ca9d Remove 'simple' adjective 2023-12-11 23:42:43 +01:00
David Peter 3bd84fd5cb Adapt version number 2023-12-11 23:42:22 +01:00
David Peter 0634a06470 Update CHANGELOG 2023-12-11 23:38:51 +01:00
David Peter 7a9234c182 Merge pull request #212 from sharkdp/add-ascii-character-table
Add pure ASCII character table
2023-12-11 23:31:17 +01:00
David Peter 45fa72ec3b Add ASCII character table
closes #36
2023-12-11 23:22:36 +01:00
David Peter 711627bfe8 Rename ascii-only to 'default', as it is not only ASCII 2023-12-11 23:00:49 +01:00
David Peter ba89e88dfd Update dependencies 2023-12-11 22:58:42 +01:00
David Peter 1792090799 Merge pull request #211 from sharifhsn/devzero
`/dev/zero` fix (final)
2023-12-11 22:55:38 +01:00
Sharif Haason 33d5b4dbda Flush output on first print for /dev/zero fix 2023-12-11 16:41:26 -05:00
David Peter 921327f2ae Merge pull request #210 from sharkdp/fix-no-color
Fix NO_COLOR behavior
2023-12-11 20:11:38 +01:00
David Peter 4bf875095c Fix NO_COLOR behavior 2023-12-11 20:06:10 +01:00
David Peter a78c00b10d Remove unused character_table field 2023-12-11 19:47:59 +01:00
David Peter 2bab0c769e Merge pull request #195 from sharifhsn/cp437
Implement character table control and codepage 437 option
2023-12-11 19:42:12 +01:00
Sharif Haason 1310b1d19e Adjust color function to not take character_table as arg 2023-12-11 13:33:44 -05:00
Sharif Haason a56b3b0c46 Adjust color function to not include character_table 2023-12-11 13:32:46 -05:00
Sharif Haason 7ca00279ed Correct docs 2023-12-10 13:21:23 -05:00
Sharif Haason dfb5d57ee7 Remove block coloring option for refactor 2023-12-10 13:21:23 -05:00
Sharif Haason a0a7d6761f Refactor color components into new module 2023-12-10 13:21:23 -05:00
Sharif Haason 7ef8e5aae4 Add test for code page 437 2023-12-10 13:21:23 -05:00
Sharif Haason 8d5b355b76 Correct asterisk colorization 2023-12-10 13:21:23 -05:00
Sharif Haason 19f325a691 Implement block character table 2023-12-10 13:21:23 -05:00
Sharif Haason 10ddbbad7d Use U+FB00 LATIN SMALL LIGATURE FF (ff) for FFh 2023-12-10 13:21:23 -05:00
Sharif Haason 58c8c06317 Clarify use of ␀ 2023-12-10 13:21:23 -05:00
sharifandDavid Peter 78477a90c9 Close quotation in help text
Co-authored-by: David Peter <sharkdp@users.noreply.github.com>
2023-12-10 13:21:23 -05:00
Sharif Haason 9362c2313a Attribute original author of CP437 2023-12-10 13:21:23 -05:00
Sharif Haason e363f2fdc4 Remove old as_char implementation 2023-12-10 13:21:23 -05:00
Sharif Haason 29e3350e69 Rename CharTable to CharacterTable 2023-12-10 13:21:23 -05:00
Sharif Haason 0c192e979b Make CharTable non-exhaustive 2023-12-10 13:21:23 -05:00
Sharif Haason c4f91959ef Add default value for character table 2023-12-10 13:21:23 -05:00
Sharif Haason 4e66357618 Use hyphens instead of underscores 2023-12-10 13:21:23 -05:00
Sharif Haason 6a230d34a4 Implement character table control and codepage 437 option 2023-12-10 13:21:23 -05:00
David Peter 663e4c19ff Merge pull request #208 from 0323pin/master
fix for ...
2023-09-23 21:49:32 +02:00
pin 894ca71b40 fix for ...
https://github.com/sharkdp/hexyl/pull/206#issuecomment-1722295392
2023-09-23 20:01:55 +02:00
David Peter e85953eeb5 Merge pull request #206 from 0323pin/master
Add NetBSD
2023-09-11 08:43:18 +02:00
pin f5ce9946f6 Add NetBSD 2023-09-11 08:35:32 +02:00
David Peter 668054fe50 Merge pull request #205 from cdump/master
fix arch linux repo link in readme
2023-08-27 22:17:32 +02:00
Maxim Andreev d6cb7af643 fix arch linux repo link in readme 2023-08-27 22:11:29 +03:00
David Peter 7b59a3f374 Merge pull request #203 from VlkrS/OpenBSD-Instruction-Fix
Correct OpenBSD instructions
2023-08-21 19:16:46 +02:00
VlkrS 3c69797f23 Correct OpenBSD instructions
I'm terribly sorry, but I just noticed that a copy&paste mistake slipped though in my initial PR.
2023-08-21 17:27:30 +02:00
David Peter 7e9bc5138d Merge pull request #202 from GrigorenkoPV/deps
Vet dependencies
2023-08-21 16:39:54 +02:00
David Peter ce70246f80 Merge pull request #201 from GrigorenkoPV/tests
Move tests to a separate `#[cfg(test)]` module
2023-08-21 16:39:22 +02:00
David Peter a306c82024 Merge pull request #199 from VlkrS/openbsd-doc
Add instructions for OpenBSD
2023-08-21 16:37:49 +02:00
Pavel Grigorenko e1e53335d3 Move tests to a separate #[cfg(test)] module 2023-08-21 16:01:22 +03:00
Pavel Grigorenko c9f113c8c4 cargo update 2023-08-21 15:42:40 +03:00
Pavel Grigorenko 59557bd433 Bump predicates to not depend on both 2.x & 3.x 2023-08-21 15:42:02 +03:00
VlkrS 39a94379c6 Add instructions for OpenBSD
Mention OpenBSD in README.md
2023-08-06 20:39:31 +02:00
David Peter 5981fc8725 Bump MSRV to 1.66 2023-07-26 08:54:15 +02:00
David Peter f4515b0f14 Update CHANGELOG 2023-07-26 08:51:26 +02:00
David Peter e3d406dd95 Update dependencies 2023-07-26 08:47:03 +02:00
David Peter b6b7e2c79a Merge pull request #197 from sharifhsn/stdin-fix
Correctly handle discontinuous input i.e. stdin
2023-07-23 13:07:31 +02:00
Sharif Haason dfad7b3faf Refactor to avoid code duplication 2023-06-20 10:55:07 -04:00
Sharif Haason ef9b530d6a Finish comment 2023-06-20 10:46:48 -04:00
Sharif Haason a3268b8791 Correctly handle discontinuous input i.e. stdin 2023-06-20 10:45:13 -04:00
David Peter 2a534483c8 Update README.md 2023-05-25 15:27:04 +02:00
David Peter e6ba196bcb Merge pull request #193 from v0idx/master
Add color reference table to README.md
2023-05-25 15:26:11 +02:00
David Peter d0bd971382 Merge pull request #192 from LemmingAvalanche/master
Bump version in readme (0.13.0)
2023-05-25 15:24:41 +02:00
v0idx 8eed3cadbb Add color reference table to README.md 2023-05-22 02:33:41 +01:00
Kristoffer Haugsbakk 38a9662ea5 Bump version in readme (0.13.0) 2023-05-18 17:31:31 +02:00
David Peter e10136d203 Updates for 0.13 2023-05-10 22:19:07 +02:00
David Peter 5f0373184f Add --characters, change meaning of -C
This changes the meaning of `-C` to "show the character panel". The long
version `--no-characters` can still be used to hide the character panel.

closes #187
2023-05-10 22:09:19 +02:00
David Peter 57d18482ba Add Copy and Clone for Endianness 2023-04-26 14:53:37 +02:00
David Peter 816779e968 Merge pull request #189 from RinHizakura/master
Support both little and big endian dump
2023-04-25 09:20:23 +02:00
David Peter 9be018fbb9 Add -e alias for --endianness=little 2023-04-25 09:12:26 +02:00
David Peter cba717b783 Minor doc comment adjustment 2023-04-25 08:51:31 +02:00
David Peter 580f865c4a Rename function 2023-04-25 08:50:55 +02:00
David Peter 20450310c9 Help text adjustments, do not require group-size to be present 2023-04-25 08:48:39 +02:00
RinHizakura b251575d94 Change design for endianness command line option 2023-04-24 23:44:49 +08:00
RinHizakura 58b038af27 Change le to non-abbreviated name little endian 2023-04-24 23:13:28 +08:00
RinHizakura d703cdfd78 Fix comment error and grammarly 2023-04-24 23:10:25 +08:00
RinHizakura 43f8b92502 Fix test for endianness 2023-04-24 22:59:23 +08:00
RinHizakura a966896d3f Fix integration test module name 2023-04-24 22:59:23 +08:00
RinHizakura 08b903270f Change endianness from boolean type to enum 2023-04-24 22:59:19 +08:00
David Peter dd601e4792 Run cargo fmt 2023-04-21 21:28:52 +02:00
RinHizakura 564cf64b1b Support both little and big endian dump 2023-04-21 21:26:43 +02:00
David Peter c24280620a Merge pull request #191 from sharkdp/ci-sync
CI update
2023-04-21 21:25:27 +02:00
David Peter bfa2726e05 CI update 2023-04-21 21:02:49 +02:00
David Peter d6af232691 Merge pull request #188 from sharkdp/ci-update
CI: macos 12
2023-02-26 19:53:56 +01:00
David Peter cc6987e270 CI: macos 12 2023-02-26 13:44:08 +01:00
David Peter ee56a3396d Bump version 2022-12-07 23:48:29 +01:00
David Peter 4833c2afe4 Merge pull request #183 from sharifhsn/owo
Use `owo-colors` instead of `anstyle`
2022-12-07 23:42:54 +01:00
sharifandDavid Peter dfd7bdef49 Update src/bin/hexyl.rs
Co-authored-by: David Peter <sharkdp@users.noreply.github.com>
2022-12-07 17:33:35 -05:00
sharif fd4aee2b85 Merge branch 'master' into owo 2022-12-07 16:51:30 -05:00
Sharif Haason cf8e7ec079 Revert default color option to always 2022-12-07 16:48:20 -05:00
Sharif Haason faa9866d11 Change group_bytes to satisfy merge conflict 2022-12-07 16:44:11 -05:00
David Peter 1df35eeb63 Renme --group-bytes to --group-size
For `xxd`-compatibility reasons

see #121
2022-12-07 21:50:12 +01:00
David Peter 437a15f3d6 One panel by default is terminal is not wide enough
closes #182
2022-12-07 21:35:34 +01:00
David Peter 70fa092df1 Do not fail if output is not a TTY for --panels=auto
closes #184
2022-12-07 21:33:20 +01:00
Sharif Haason b2f0e75ed2 Satisfy clippy 2022-12-06 13:22:34 -05:00
Sharif Haason 4fc0c1f1b0 Replace anstyle with owo-colors 2022-12-06 11:27:16 -05:00
Sharif Haason 4ce6e9d799 Remove now unnecessary byte_char_panel_g 2022-12-06 11:26:19 -05:00
Sharif Haason 5bd76fd11b Replace is-terminal with supports-color and make auto default for color 2022-12-06 11:24:53 -05:00
David Peter c7e2235293 Update CHANGELOG 2022-12-05 10:01:03 +01:00
David Peter 421bd73ec1 Revert "Replace libc with rustix"
This reverts commit 571312dd6e.
2022-12-05 09:52:27 +01:00
David Peter e888021a48 Update version in README, man page 2022-12-05 09:48:10 +01:00
David Peter 7d38f70918 Show 0x00-bytes as '⋄' instead of '0', closes #166 2022-12-05 09:45:38 +01:00
David Peter c6af2edda8 Bump version 2022-12-05 09:32:07 +01:00
David Peter a7fadfaaf2 Update dependencies 2022-12-05 09:31:43 +01:00
David Peter 8577a17b14 Ignore EPIPE silently
fixes a regression introduced in a6aeabfde4

closes #181
2022-12-05 09:30:13 +01:00
David Peter 2d8b600c48 Update CHANGELOG 2022-12-05 09:11:47 +01:00
David Peter f8601e5bc9 Merge pull request #180 from sharifhsn/altdeps
Replace outdated dependencies
2022-12-05 09:03:40 +01:00
David Peter 9770b89cf4 Merge pull request #178 from sharifhsn/base
[feature] Implement alternate bases
2022-12-05 09:03:03 +01:00
Sharif Haason 571312dd6e Replace libc with rustix 2022-12-04 21:48:10 -05:00
Sharif Haason fcd09fffac Relax anstyle version 2022-12-04 21:43:03 -05:00
Sharif Haason 188e753675 Replace atty with is-terminal 2022-12-04 21:42:44 -05:00
Sharif Haason 030235afb7 Improve help text for --base 2022-12-04 21:36:42 -05:00
Sharif Haason 7847e8cd33 Remove debug statement 2022-11-27 19:45:33 -05:00
Sharif Haason 32f4ce9987 cargo fmt 2022-11-27 17:52:29 -05:00
Sharif Haason 2a4b17a162 Add tests for alternate base 2022-11-27 17:32:18 -05:00
Sharif Haason 5e3c49f933 cargo fmt 2022-11-27 17:19:48 -05:00
Sharif Haason fc794b290c Account for new panel arguments 2022-11-27 17:19:33 -05:00
Sharif Haason e6000a56f4 Parse -b argument 2022-11-27 17:18:38 -05:00
Sharif Haason 2861cd51ac Adjust panel calculation to account for base and group 2022-11-27 17:17:52 -05:00
Sharif Haason a8cffbb6df Move group_bytes so it can be used for panels 2022-11-27 17:17:25 -05:00
Sharif Haason 7bb6343d2a Add --base/-b argument 2022-11-27 17:16:48 -05:00
Sharif Haason 7de17c4f35 Adjust spaces on empty lines 2022-11-27 17:15:26 -05:00
Sharif Haason ec61c2a789 Print header only if non-empty 2022-11-27 17:14:30 -05:00
Sharif Haason 7f7b88a914 Adjust tests 2022-11-27 17:13:36 -05:00
Sharif Haason 85fa75ba67 Differentiate format on base 2022-11-27 17:11:55 -05:00
Sharif Haason d5d645fc48 Add Base to Printer 2022-11-27 17:11:21 -05:00
David Peter 8d3aa65134 Merge pull request #176 from sharifhsn/anstyle
Change `ansi_term` to `anstyle`
2022-11-27 21:02:26 +01:00
Sharif Haason 252b4e84c3 Merge branch 'master' into anstyle 2022-11-27 10:03:53 -05:00
Sharif Haason 3dc118d0ad cargo update 2022-11-27 09:47:38 -05:00
Mikhail Katychev b1ff8b6ce4 added squeeze tests 2022-11-26 20:18:21 +01:00
David Peter fe65792b96 Add CHANGELOG entry 2022-11-26 13:07:06 +01:00
David Peter 31c0bcfeae Improve error messages 2022-11-26 13:07:06 +01:00
RinHizakura c0f94ad6aa Refine the support of byte grouping 2022-11-26 13:07:06 +01:00
RinHizakura 55fed5e3c0 Fix for clap4 2022-11-26 13:07:06 +01:00
RinHizakura aeee0a1033 Add new integration tests for group bytes feature 2022-11-26 13:07:06 +01:00
RinHizakura 179c8f40a2 Support byte grouping 2022-11-26 13:07:06 +01:00
Sharif Haason fb2500d7d6 Include Cargo.lock 2022-11-19 11:40:03 -05:00
Sharif Haason ad9ecda952 Remove once_cell dependency 2022-11-19 11:04:59 -05:00
Sharif Haason c43effefd6 cargo fmt 2022-11-19 11:04:13 -05:00
Sharif Haason 0b6454ed9d Use Vec of enums for color instead of HashMap 2022-11-19 10:50:31 -05:00
Sharif Haason 557ae66ed5 Update Cargo.lock 2022-11-18 16:15:49 -05:00
Sharif Haason df1afdc73f Merge branch 'anstyle' of https://github.com/sharifhsn/hexyl into anstyle 2022-11-18 16:15:12 -05:00
Sharif Haason 9106b899b2 Bump MSRV 2022-11-18 19:22:24 +01:00
Sharif Haason df1c36e5a7 Satisfy clippy 2022-11-18 19:22:24 +01:00
Sharif Haason ac610f7bad Add get_one and fix ordering 2022-11-18 19:22:24 +01:00
Sharif Haason 767740865f Update predicate for default_value_if 2022-11-18 19:22:24 +01:00
Sharif Haason 1fb324f411 Use ArgAction for flags 2022-11-18 19:22:24 +01:00
Sharif Haason 3d0bc3d0eb Replace 'value_of with get_one::<String>` 2022-11-18 19:22:24 +01:00
Sharif Haason 8a52261a50 Replace possible_values with value_parser 2022-11-18 19:22:24 +01:00
Sharif Haason ccc4fb9ba9 Replace takes_value with num_args 2022-11-18 19:22:24 +01:00
Sharif Haason 0baa22f152 DeriveDisplayOrder now default 2022-11-18 19:22:24 +01:00
Sharif Haason 165ced9307 Update to clap 4.0 2022-11-18 19:22:24 +01:00
Sharif Haason 3888a20dfe Bump MSRV 2022-11-18 11:06:18 -05:00
Sharif Haason 75b37fa125 Use compatible lockfile 2022-11-18 11:01:39 -05:00
Sharif Haason 794e1935e3 Prerender color strings for better performance 2022-11-18 10:39:54 -05:00
Sharif Haason c49aa079b4 Add color only when needed 2022-11-18 08:19:13 -05:00
Sharif Haason 675ef6d4a8 Remove calls to ansi_term 2022-11-17 22:33:49 -05:00
Sharif Haason eade38c94a Explicitly paint with style formatting 2022-11-17 22:33:03 -05:00
Sharif Haason 98ceec18cd Replace colors with ANSI styles 2022-11-17 22:15:53 -05:00
Sharif Haason a49f295acc Replace deprecated ansi_term with anstyle 2022-11-17 22:12:00 -05:00
Sharif Haason 0caab15255 Document the main loop 2022-11-13 22:15:41 +01:00
Sharif Haason 828fb210ce Use repeat byte when discovering squeeze 2022-11-13 22:15:41 +01:00
Sharif Haason 1e43783616 Clean up flags for ergonomics 2022-11-13 22:15:41 +01:00
Sharif Haason 6b7cfefec6 Use repeated byte optimization on nonzero bytes 2022-11-13 22:15:41 +01:00
Sharif Haason 5f82942f98 Add second check if read fails unexpectedly 2022-11-13 22:15:41 +01:00
Sharif Haason f6a1c4e8e3 Add unit tests for new implementation of squeeze 2022-11-13 22:15:41 +01:00
Sharif Haason b4fb1b079c Print last line only when squeezed 2022-11-13 22:15:41 +01:00
Sharif Haason f9f59d653d Print asterisk when no position panel 2022-11-13 22:15:41 +01:00
Sharif Haason c82695f0a9 Fix incomplete line ending when squeezed 2022-11-13 22:15:41 +01:00
Sharif Haason 9d938b11ed Remove unnecessary ending case (covered by next) 2022-11-13 22:15:41 +01:00
Sharif Haason d5982c0eb0 Optimize line check when squeezing zero bytes 2022-11-13 22:15:41 +01:00
Sharif Haason 1502419ad4 Document byte_hex_panel_g 2022-11-13 22:15:41 +01:00
Sharif Haason f5be845d70 Satisfy clippy 2022-11-13 22:15:41 +01:00
Sharif Haason 664025477b Alter when position panel is called 2022-11-13 22:15:41 +01:00
Sharif Haason 074bc791c2 Fix incomplete line ending 2022-11-13 22:15:41 +01:00
Sharif Haason 77a4ad25f1 Remove unnecessary import 2022-11-13 22:15:41 +01:00
Sharif Haason ca31d466ba Keep newline consistent 2022-11-13 22:15:41 +01:00
Sharif Haason 945e7a3472 Remove unnecessary squeezer module 2022-11-13 22:15:41 +01:00
Sharif Haason 75d612ff11 Alter newline usage 2022-11-13 22:15:41 +01:00
Sharif Haason 15e8abfc9a Complete architectural rewrite (intentionally fails) 2022-11-13 22:15:41 +01:00
Sharif Haason b36d74ed9d Track squeeze_byte correctly 2022-11-13 22:15:41 +01:00
Sharif Haason 094bf63f02 Eliminate unnecessary call to active 2022-11-13 22:15:41 +01:00
Sharif Haason e0e870de27 Store squeezed byte instead of pushing to vector 2022-11-13 22:15:41 +01:00
Sharif Haason 966421c522 Undo inlining to satisfy MSRV 2022-11-13 22:15:41 +01:00
Sharif Haason 166c2cc46b Inline StdoutLock variable 2022-11-13 22:15:41 +01:00
Sharif Haason 74a5e4bc84 Print first line always 2022-11-13 22:15:41 +01:00
Sharif Haason 363ea0a586 Undo perf regression on squeezer 2022-11-13 22:15:41 +01:00
Sharif Haason 1c4c7ed9a5 Satisfy clippy 2022-11-13 22:15:41 +01:00
Sharif Haason b5c224c119 Fix for no position panel 2022-11-13 22:15:41 +01:00
Sharif Haason d6e34d9dd2 Fix issues with hello_world_elf64 2022-11-13 22:15:41 +01:00
Sharif Haason 1cb346bd13 Fixes --no-characters causes output artifacts when squeezing lines #171 2022-11-13 22:15:41 +01:00
Sharif Haason daa40900bd Fix char panel showing even if disabled 2022-11-13 22:15:41 +01:00
Sharif Haason d98c6edb55 Fix overflow when printing without char panel 2022-11-13 22:15:41 +01:00
Sharif Haason 73bfc68cd0 cargo fmt 2022-11-13 22:15:41 +01:00
Sharif Haason 5d3f36d066 Remove write! formatting from hot loop 2022-11-13 22:15:41 +01:00
Sharif Haason d214bc63f1 Precalculate position formatting in Printer state 2022-11-13 22:15:41 +01:00
Sharif Haason a6aeabfde4 Refactor code to replace manual buffering with BufReader and BufWriter 2022-11-13 22:15:41 +01:00
Sharif Haason 9602667991 Rename with_panels to num_panels 2022-10-04 18:09:47 +02:00
Sharif Haason 9ccf18f4c0 Update CHANGELOG.md with PrinterBuilder 2022-10-04 18:09:47 +02:00
Sharif Haason aa921ca184 Rename with_squeeze to enable_squeezing 2022-10-04 18:09:47 +02:00
Sharif Haason 4823523b7d Remove superfluous with_writer function 2022-10-04 18:09:47 +02:00
Sharif Haason 4569c8f871 Self-document simple.rs example with builder API 2022-10-04 18:09:47 +02:00
Sharif Haason 80163764c3 Implement builder pattern 2022-10-04 18:09:47 +02:00
Sharif Haason 9bc81820e7 Update CHANGELOG 2022-09-11 21:45:06 +02:00
Sharif Haason 273ef0c045 Remove short options for panels and terminal-width 2022-09-11 21:45:06 +02:00
Sharif Haason ac1a67e90c Fix abbreviation clash 2022-09-11 21:45:06 +02:00
Sharif Haason 12324d615a Rename --columns to --panels 2022-09-11 21:45:06 +02:00
Sharif Haason 6b062ba127 Fix typo 2022-09-11 21:45:06 +02:00
Sharif Haason 8c7c3a073c Use --columns=auto instead of --auto-width 2022-09-11 21:45:06 +02:00
Sharif Haason 0565901fad Return a proper error if terminal size fails 2022-09-11 21:45:06 +02:00
Sharif Haason 41b3241718 Change columns type to u16 2022-09-11 21:45:06 +02:00
Sharif Haason 975a406d20 Remove debugging line 2022-09-11 21:45:06 +02:00
Sharif Haason aa43c20f39 Bump MSRV 2022-09-11 21:45:06 +02:00
Sharif Haason 1fdd770093 Implement -a and -t for terminal width setting 2022-09-11 21:45:06 +02:00
Sharif Haason a3fde45c18 Added test for multiple columns 2022-09-11 21:45:06 +02:00
Sharif Haason 85659a9cd6 Prevent overflow when columns >= 32 2022-09-11 21:45:06 +02:00
sharifandDavid Peter 2a4a22c9cb Update src/squeezer.rs
Co-authored-by: David Peter <sharkdp@users.noreply.github.com>
2022-09-11 21:45:06 +02:00
Sharif Haason b820bdfeca cargo fmt 2022-09-11 21:45:06 +02:00
Sharif Haason b9348ffb1d Adds --columns for Print using custom width #13 2022-09-11 21:45:06 +02: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
David Peter c3e9cb9518 Bump MSRV 2021-07-11 20:09:28 +02:00
David Peter 3489998c67 cargo fmt 2021-07-11 20:09:28 +02:00
David Peter 4594d29f73 Bump version to 0.9.0 2021-07-11 20:09:28 +02:00
David Peter cc73f01c34 Update dependencies 2021-07-11 20:09:28 +02:00
David Peter 6da15cd1e9 Added alias notice in help text 2021-07-11 19:57:55 +02:00
David Peter c82ccd5a59 Add CHANGELOG entry 2021-07-11 19:57:55 +02:00
TheDoctor314 19d2805729 Add alias '-l' for '-n/--length'
Set `.hidden(true)` option

This won't clutter the help text too much.
2021-07-11 19:57:55 +02:00
David Peter 06387bba3e Add GitHub actions badge 2021-07-11 19:16:53 +02:00
David Peter 595803e5e2 Migrate to GitHub actions 2021-07-11 19:16:06 +02:00
Herby Gillot 3793559d6f README: add MacPorts instructions 2021-06-07 19:00:11 +02:00
Mihir Gadgil 71626c28e9 Update CHANGELOG.md 2021-05-07 10:05:16 +02:00
Mihir Gadgil 532eab762d Fix #131
Don't print the error for version output, instead add a newline print.
Move the eprint for help only.
2021-05-07 10:05:16 +02:00
dm9pZCAq 642eff6061 README: added Gentoo instruction 2021-02-13 20:36:44 +01:00
Gabriel Arazas 15dc96a946 Add installation instructions for Guix 2020-11-25 12:18:16 +01:00
sharkdp 6b2cc80cc1 Change ASCII file to contain increasing hex digits 2020-11-01 22:56:59 +01:00
sharkdp 1db77094da Organize integration tests into modules 2020-11-01 22:56:59 +01:00
sharkdp 8c3f2230c6 Better error message when seek fails
> hexyl "$(which hexyl)" --skip=-5gib
    Error: Failed to jump to the desired input position. This could be
    caused by a negative offset that is too large or by an input that is not
    seek-able (e.g. if the input comes from a pipe).

ref: #114
2020-11-01 22:56:59 +01:00
sharkdp 66f8508b57 Add stdin test 2020-11-01 21:35:35 +01:00
sharkdp afb249e854 Run cargo fmt 2020-11-01 21:04:39 +01:00
sharkdp 9432677d3a Disallow block sizes of 0
closes #110
2020-10-31 10:17:19 +01:00
Tom Milligan 524a6c607f bin: offset should add to skip, not override it 2020-10-31 10:00:03 +01:00
sharkdp d69a7d8e04 Update CHANGELOG 2020-10-30 21:58:02 +01:00
sharkdp b1c8606918 Print warning on empty content
closes #107
closes #108
2020-10-30 21:58:02 +01:00
sharkdp d9723592bf Add CONTRIBUTING guide 2020-10-30 20:04:08 +01:00
sharkdp 23fbb5b027 Update CHANGELOG 2020-10-30 20:02:16 +01:00
sharkdp 4d7004f06b Move CHANGELOG entry 2020-10-30 19:57:07 +01:00
purvesh-linux11 c4ed6d9936 add snapstore link to readme 2020-10-30 19:56:44 +01:00
purvesh-linux11 aab0596ea9 add snap information in changelog 2020-10-30 19:56:44 +01:00
purvesh-linux11 7500efffa5 add snap installation steps in redme 2020-10-30 19:56:44 +01:00
sharkdp 80e8026416 Update CHANGELOG 2020-10-30 19:00:36 +01:00
David Peter 13452f5174 Fix .gitattributes
Branch: fix-105
2020-10-30 10:07:24 +01:00
sharkdp 48ff6ff956 Bump min. required Rust version to 1.39 2020-10-30 10:07:24 +01:00
sharkdp 54cab89821 Force LF line ending to fix tests on Windows 2020-10-30 10:07:24 +01:00
sharkdp bb6a3c0650 Add test for --length, fix #105 2020-10-30 10:07:24 +01:00
sharkdp 09c22e09b9 Add simple integration tests 2020-10-30 10:07:24 +01:00
suchenguo cc5b308fc9 two New Installation ways
I added two new installation ways of Termux.
2020-08-17 21:25:26 +02:00
Erich Gubler 153b1cccdf feat: make signs significant for byte offsets 2020-08-15 14:11:10 +02:00
sharkdp 7217a60e6e Switch back to MSVC 2020-08-15 14:05:24 +02:00
Erich Gubler 13aec946a3 improvement: make diagnostics for flags involving byte count parsing actually good
This adds an error type called `ByteCountParseError` with a vanilla
`std::error::Error` implementation. The code could be significantly
compressed with a dependency like `thiserror`.

I opted to implement a separate error type for `parse_byte_count` rather
than using `anyhow`'s small ecosystem of error types there (though they
are used in `<binary>::run`) because it allows pairing diagnostic
results with tests, incl. those already written. This can be helpful in
preventing regressions in error diagnostics.
2020-06-17 18:05:42 +02:00
Erich Gubler e0da7b3f82 style: normalize indentation of doc strings literals for args help 2020-06-17 18:05:42 +02:00
Erich Gubler e29a63358d improvement: elide type of reader 2020-06-17 18:05:42 +02:00
Erich Gubler 2bdf5d768f feat: use anyhow for more structured error messages and better error reporting flexibility
This significantly changes the structure of potential output of
top-level errors.  Before, errors that have a `source` were printed on a
single line, with the `source` omitted. Now, an error with a `source`
will be printed like:

```
Error: <`Display` impl of error>

Caused by:
    <`Display` impl of `source` error>
```

If there are multiple `source` errors in a chain, then it will be of the
form:

```
Error: <`Display` impl of error>

Caused by:
    0: <`Display` impl of first `source` error>
    1: <`Display` impl of `source` of `source` error>
    # etc.
```

Now, in practice this never happened before, since the only error
type that ever could return from `<binary>::run` was `std::io::Error`,
which has no `source`. However, `source`s can start being added if, say,
future work involved using `anyhow::Context::context` or custom errors
that implement `std::Error::source` are added to the codebase. I believe
this is a good choice going forward, but I definitely want to foster
discussion and acceptance for it in the open first!
2020-06-17 18:05:42 +02:00
sharkdp a7892881f3 Wrap help text at 90 characters 2020-06-08 23:19:56 +02:00
sharkdp 921a138962 Update version in README 2020-06-07 15:57:20 +02:00
sharkdp f8f410b8ee Simplify is_printable check, closes #78 2020-06-07 15:26:07 +02:00
sharkdp 7307077a66 Run lib example on TravisCI 2020-06-07 15:14:14 +02:00
sharkdp 3ca002638c Improve help text 2020-06-07 15:12:35 +02:00
sharkdp ccfceaf58c Minor formatting 2020-06-07 15:12:35 +02:00
sharkdp 751b670d5b Fix clippy suggestions 2020-06-07 15:12:35 +02:00
sharkdp 478cc25ffd Bump version to 0.8.0 2020-06-07 15:12:35 +02:00
sharkdp b1c4b0bf2b Update dependencies 2020-06-07 15:12:35 +02:00
sharkdp 1951c59b0c Add CHANGELOG 2020-06-07 15:12:35 +02:00
Erich Gubler ddc3a5c04a BREAKING CHANGE: improvement: change byte counts to be a positive i64 (with newtype PositiveI64) instead of a u64 to take advantage of new skip impl for --seek with non-Seek Inputs like STDIN
This is technically a breaking change because it halves the upper range
of accepted values for byte counts. I thought that fine under the
assumption it will be rare for users to ever want to specify something
in the upper half of `u64`'s value range, especially considering that
this can pave the way for having negative byte offsets (instead of just
counts).
2020-06-07 11:08:01 +02:00
Erich Gubler 6d5c61b671 BREAKING CHANGE: improvement(lib): use u64 for Printer::display_offset and Squeezer::process, not usize
Technically a breaking change for architectures where
`size_of::<usize>() > size_of::<u64>()`, but that strikes me as
extremely unlikely.

This change is important because most file seek offsets, even on older
architectures with word sizes smaller than `u32`, accept a `u64`. In
particular, Rust's own `std` acknowledges this. So, we're actually going
against prior art in Rust by using a `usize`.
2020-06-07 11:08:01 +02:00
Erich Gubler c5c8d1190f BREAKING CHANGE: feat(lib): skip forward when relative forward seeks are specified on non-seekable streams
This is technically a breaking change, since the data and behavior of
`Input` is exposed publicly. However, it seems unlikely to me that
clients actually depended on a failure in the case that's being changed.
2020-06-07 11:08:01 +02:00
Erich Gubler 1459616d27 improvement: use or instead of unwrap_or_else for display_offset 2020-06-07 11:08:01 +02:00
Erich Gubler 8af8a94699 improvement(lib): align string literals better for black-box tests 2020-05-28 18:44:23 +02:00
Erich Gubler 07cdc97e74 improvement: replace trim_start_matches with slicing op 2020-05-28 18:43:53 +02:00
Erich Gubler bcca1fae03 feat: add block unit and block-size option 2020-05-28 18:43:53 +02:00
Erich Gubler 48ad95efe6 feat: add units system to decimals with {k,m,g,t}[[i]b] support 2020-05-28 18:43:53 +02:00
Erich Gubler 3b3889967c refactor: extract "0x" literal into HEX_PREFIX 2020-05-28 18:43:53 +02:00
Erich Gubler 57f1fb4dc4 BREAKING CHANGE: improvement: disallow leading '+' after "0x" prefix for u64 parse 2020-05-28 18:43:53 +02:00
Erich Gubler ef40be0d53 improvement: fix or_fun_call lint from clippy 2020-05-28 18:43:53 +02:00
Erich Gubler 6b235b1d2e improvement: remove unused atty import 2020-05-28 18:43:53 +02:00
notramo 7cff10b274 Added Void Linux package install to README 2020-05-26 20:03:09 +02:00
Mario Reder 5327b71215 fix review comments 2020-05-13 18:55:24 +02:00
Mario Reder c336259159 skip option error messages and display offset 2020-05-13 18:55:24 +02:00
sharkdp 133fdd9156 Remove unnecessary RefCell, backport to Rust 1.36 2020-05-13 18:55:24 +02:00
Mario Reder 244f71691d feat: add skip option
resolves #16 and #87
2020-05-13 18:55:24 +02:00
sharkdp 6f73f4c0f0 Remove custom .github folder 2020-03-16 07:55:46 +01:00
sharkdp 7843b2d038 Update links 2020-03-15 11:33:08 +01:00
25 changed files with 4617 additions and 1173 deletions

No files matched your search

-1
View File
@@ -1 +0,0 @@
github: sharkdp
+336
View File
@@ -0,0 +1,336 @@
name: CICD
env:
CICD_INTERMEDIATES_DIR: "_cicd-intermediates"
MSRV_FEATURES: ""
on:
workflow_dispatch:
pull_request:
push:
branches:
- master
tags:
- '*'
jobs:
crate_metadata:
name: Extract crate metadata
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Extract crate information
id: crate_metadata
run: |
cargo metadata --no-deps --format-version 1 | jq -r '"name=" + .packages[0].name' | tee -a $GITHUB_OUTPUT
cargo metadata --no-deps --format-version 1 | jq -r '"version=" + .packages[0].version' | tee -a $GITHUB_OUTPUT
cargo metadata --no-deps --format-version 1 | jq -r '"maintainer=" + .packages[0].authors[0]' | tee -a $GITHUB_OUTPUT
cargo metadata --no-deps --format-version 1 | jq -r '"homepage=" + .packages[0].homepage' | tee -a $GITHUB_OUTPUT
cargo metadata --no-deps --format-version 1 | jq -r '"msrv=" + .packages[0].rust_version' | tee -a $GITHUB_OUTPUT
outputs:
name: ${{ steps.crate_metadata.outputs.name }}
version: ${{ steps.crate_metadata.outputs.version }}
maintainer: ${{ steps.crate_metadata.outputs.maintainer }}
homepage: ${{ steps.crate_metadata.outputs.homepage }}
msrv: ${{ steps.crate_metadata.outputs.msrv }}
ensure_cargo_fmt:
name: Ensure 'cargo fmt' has been run
runs-on: ubuntu-24.04
steps:
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt
- uses: actions/checkout@v3
- run: cargo fmt -- --check
min_version:
name: Minimum supported rust version
runs-on: ubuntu-24.04
needs: crate_metadata
steps:
- name: Checkout source code
uses: actions/checkout@v3
- name: Install rust toolchain (v${{ needs.crate_metadata.outputs.msrv }})
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ needs.crate_metadata.outputs.msrv }}
components: clippy
- name: Run clippy (on minimum supported rust version to prevent warnings we can't fix)
run: cargo clippy --locked --all-targets ${{ env.MSRV_FEATURES }}
- name: Run tests
run: cargo test --locked ${{ env.MSRV_FEATURES }}
build:
name: ${{ matrix.job.target }} (${{ matrix.job.os }})
runs-on: ${{ matrix.job.os }}
needs: crate_metadata
strategy:
fail-fast: false
matrix:
job:
- { target: aarch64-unknown-linux-gnu , os: ubuntu-24.04, use-cross: true }
- { target: arm-unknown-linux-gnueabihf , os: ubuntu-24.04, use-cross: true }
- { target: arm-unknown-linux-musleabihf, os: ubuntu-24.04, use-cross: true }
- { target: i686-pc-windows-msvc , os: windows-2025 }
- { target: i686-unknown-linux-gnu , os: ubuntu-24.04, use-cross: true }
- { target: i686-unknown-linux-musl , os: ubuntu-24.04, use-cross: true }
- { target: x86_64-apple-darwin , os: macos-15-intel }
- { target: aarch64-apple-darwin , os: macos-15 }
# Was causing CI failures unrelated to app logic
# - { target: x86_64-pc-windows-gnu , os: windows-2019 }
- { target: x86_64-pc-windows-msvc , os: windows-2025 }
- { target: x86_64-unknown-linux-gnu , os: ubuntu-24.04, use-cross: true }
- { target: x86_64-unknown-linux-musl , os: ubuntu-24.04, use-cross: true }
env:
BUILD_CMD: cargo
steps:
- name: Checkout source code
uses: actions/checkout@v3
- name: Install prerequisites
shell: bash
run: |
case ${{ matrix.job.target }} in
arm-unknown-linux-*) sudo apt-get -y update ; sudo apt-get -y install gcc-arm-linux-gnueabihf ;;
aarch64-unknown-linux-gnu) sudo apt-get -y update ; sudo apt-get -y install gcc-aarch64-linux-gnu ;;
esac
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.job.target }}
- name: Install cross
if: matrix.job.use-cross
uses: taiki-e/install-action@v2
with:
tool: cross
- name: Overwrite build command env variable
if: matrix.job.use-cross
shell: bash
run: echo "BUILD_CMD=cross" >> $GITHUB_ENV
- name: Show version information (Rust, cargo, GCC)
shell: bash
run: |
gcc --version || true
rustup -V
rustup toolchain list
rustup default
cargo -V
rustc -V
- name: Build
shell: bash
run: $BUILD_CMD build --locked --release --target=${{ matrix.job.target }}
- name: Run example
if: ${{ !matrix.job.use-cross }}
shell: bash
run: $BUILD_CMD run --release --target=${{ matrix.job.target }} --example=simple
- name: Set binary name & path
id: bin
shell: bash
run: |
# Figure out suffix of binary
EXE_suffix=""
case ${{ matrix.job.target }} in
*-pc-windows-*) EXE_suffix=".exe" ;;
esac;
# Setup paths
BIN_NAME="${{ needs.crate_metadata.outputs.name }}${EXE_suffix}"
BIN_PATH="target/${{ matrix.job.target }}/release/${BIN_NAME}"
# Let subsequent steps know where to find the binary
echo "BIN_PATH=${BIN_PATH}" >> $GITHUB_OUTPUT
echo "BIN_NAME=${BIN_NAME}" >> $GITHUB_OUTPUT
- name: Set testing options
id: test-options
shell: bash
run: |
# test only library unit tests and binary for arm-type targets
unset CARGO_TEST_OPTIONS
case ${{ matrix.job.target }} in arm-* | aarch64-*) CARGO_TEST_OPTIONS="--lib --bin ${{ needs.crate_metadata.outputs.name }}" ;; esac;
echo "CARGO_TEST_OPTIONS=${CARGO_TEST_OPTIONS}" >> $GITHUB_OUTPUT
- name: Run tests
shell: bash
run: $BUILD_CMD test --locked --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/${{ needs.crate_metadata.outputs.name }}.1" "doc/${{ needs.crate_metadata.outputs.name }}.1.md"
- name: Create tarball
id: package
shell: bash
run: |
PKG_suffix=".tar.gz" ; case ${{ matrix.job.target }} in *-pc-windows-*) PKG_suffix=".zip" ;; esac;
PKG_BASENAME=${{ needs.crate_metadata.outputs.name }}-v${{ needs.crate_metadata.outputs.version }}-${{ matrix.job.target }}
PKG_NAME=${PKG_BASENAME}${PKG_suffix}
echo "PKG_NAME=${PKG_NAME}" >> $GITHUB_OUTPUT
PKG_STAGING="${{ env.CICD_INTERMEDIATES_DIR }}/package"
ARCHIVE_DIR="${PKG_STAGING}/${PKG_BASENAME}/"
mkdir -p "${ARCHIVE_DIR}"
# Binary
cp "${{ steps.bin.outputs.BIN_PATH }}" "$ARCHIVE_DIR"
# README, LICENSE and CHANGELOG files
cp "README.md" "LICENSE-MIT" "LICENSE-APACHE" "CHANGELOG.md" "$ARCHIVE_DIR"
# Man page
cp "doc/${{ needs.crate_metadata.outputs.name }}.1" "$ARCHIVE_DIR"
# base compressed package
pushd "${PKG_STAGING}/" >/dev/null
case ${{ matrix.job.target }} in
*-pc-windows-*) 7z -y a "${PKG_NAME}" "${PKG_BASENAME}"/* | tail -2 ;;
*) tar czf "${PKG_NAME}" "${PKG_BASENAME}"/* ;;
esac;
popd >/dev/null
# Let subsequent steps know where to find the compressed package
echo "PKG_PATH=${PKG_STAGING}/${PKG_NAME}" >> $GITHUB_OUTPUT
- name: Create Debian package
id: debian-package
shell: bash
if: startsWith(matrix.job.os, 'ubuntu')
run: |
COPYRIGHT_YEARS="2018 - "$(date "+%Y")
DPKG_STAGING="${{ env.CICD_INTERMEDIATES_DIR }}/debian-package"
DPKG_DIR="${DPKG_STAGING}/dpkg"
mkdir -p "${DPKG_DIR}"
DPKG_BASENAME=${{ needs.crate_metadata.outputs.name }}
DPKG_CONFLICTS=${{ needs.crate_metadata.outputs.name }}-musl
case ${{ matrix.job.target }} in *-musl*) DPKG_BASENAME=${{ needs.crate_metadata.outputs.name }}-musl ; DPKG_CONFLICTS=${{ needs.crate_metadata.outputs.name }} ;; esac;
DPKG_VERSION=${{ needs.crate_metadata.outputs.version }}
unset DPKG_ARCH
case ${{ matrix.job.target }} in
aarch64-*-linux-*) DPKG_ARCH=arm64 ;;
arm-*-linux-*hf) DPKG_ARCH=armhf ;;
i686-*-linux-*) DPKG_ARCH=i686 ;;
x86_64-*-linux-*) DPKG_ARCH=amd64 ;;
*) DPKG_ARCH=notset ;;
esac;
DPKG_NAME="${DPKG_BASENAME}_${DPKG_VERSION}_${DPKG_ARCH}.deb"
echo "DPKG_NAME=${DPKG_NAME}" >> $GITHUB_OUTPUT
# Binary
install -Dm755 "${{ steps.bin.outputs.BIN_PATH }}" "${DPKG_DIR}/usr/bin/${{ steps.bin.outputs.BIN_NAME }}"
# Man page
install -Dm644 'doc/${{ needs.crate_metadata.outputs.name }}.1' "${DPKG_DIR}/usr/share/man/man1/${{ needs.crate_metadata.outputs.name }}.1"
gzip -n --best "${DPKG_DIR}/usr/share/man/man1/${{ needs.crate_metadata.outputs.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"
install -Dm644 "LICENSE-APACHE" "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/LICENSE-APACHE"
install -Dm644 "CHANGELOG.md" "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/changelog"
gzip -n --best "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/changelog"
cat > "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/copyright" <<EOF
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: ${{ needs.crate_metadata.outputs.name }}
Source: ${{ needs.crate_metadata.outputs.homepage }}
Files: *
Copyright: ${{ needs.crate_metadata.outputs.maintainer }}
Copyright: $COPYRIGHT_YEARS ${{ needs.crate_metadata.outputs.maintainer }}
License: Apache-2.0 or MIT
License: Apache-2.0
On Debian systems, the complete text of the Apache-2.0 can be found in the
file /usr/share/common-licenses/Apache-2.0.
License: MIT
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
.
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
EOF
chmod 644 "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/copyright"
# control file
mkdir -p "${DPKG_DIR}/DEBIAN"
cat > "${DPKG_DIR}/DEBIAN/control" <<EOF
Package: ${DPKG_BASENAME}
Version: ${DPKG_VERSION}
Section: utils
Priority: optional
Maintainer: ${{ needs.crate_metadata.outputs.maintainer }}
Homepage: ${{ needs.crate_metadata.outputs.homepage }}
Architecture: ${DPKG_ARCH}
Provides: ${{ needs.crate_metadata.outputs.name }}
Conflicts: ${DPKG_CONFLICTS}
Description: A command-line benchmarking tool
EOF
DPKG_PATH="${DPKG_STAGING}/${DPKG_NAME}"
echo "DPKG_PATH=${DPKG_PATH}" >> $GITHUB_OUTPUT
# build dpkg
fakeroot dpkg-deb --build "${DPKG_DIR}" "${DPKG_PATH}"
- name: "Artifact upload: tarball"
uses: actions/upload-artifact@main
with:
name: ${{ steps.package.outputs.PKG_NAME }}
path: ${{ steps.package.outputs.PKG_PATH }}
- name: "Artifact upload: Debian package"
uses: actions/upload-artifact@main
if: steps.debian-package.outputs.DPKG_NAME
with:
name: ${{ steps.debian-package.outputs.DPKG_NAME }}
path: ${{ steps.debian-package.outputs.DPKG_PATH }}
- name: Check for release
id: is-release
shell: bash
run: |
unset IS_RELEASE ; if [[ $GITHUB_REF =~ ^refs/tags/v[0-9].* ]]; then IS_RELEASE='true' ; fi
echo "IS_RELEASE=${IS_RELEASE}" >> $GITHUB_OUTPUT
- name: Publish archives and packages
uses: softprops/action-gh-release@v1
if: steps.is-release.outputs.IS_RELEASE
with:
files: |
${{ steps.package.outputs.PKG_PATH }}
${{ steps.debian-package.outputs.DPKG_PATH }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+3
View File
@@ -1,2 +1,5 @@
/target
**/*.rs.bk
# Generated files
hexyl.1
-79
View File
@@ -1,79 +0,0 @@
language: rust
cache: cargo
matrix:
include:
# Stable channel.
- os: linux
rust: stable
env: TARGET=x86_64-unknown-linux-gnu
- os: linux
rust: stable
env: TARGET=x86_64-unknown-linux-musl
- os: osx
rust: stable
env: TARGET=x86_64-apple-darwin
- os: windows
rust: stable
env: TARGET=x86_64-pc-windows-gnu
# Minimum Rust supported channel.
- os: linux
rust: 1.31.0
env: TARGET=x86_64-unknown-linux-gnu
addons:
apt:
packages:
# needed to build deb packages
- fakeroot
env:
global:
# Default target on travis-ci.
# Used as conditional check in the install stage
- HOST=x86_64-unknown-linux-gnu
# Used on the deployment script
- PROJECT_NAME=hexyl
install:
# prevent target re-add error from rustup
- if [[ $TRAVIS_OS_NAME = linux && $HOST != $TARGET ]]; then rustup target add $TARGET; fi
script:
# Incorporate TARGET env var to the build and test process
- cargo build --target $TARGET --verbose
- cargo test --target $TARGET --verbose
before_deploy:
- bash ci/before_deploy.bash
deploy:
provider: releases
# NOTE updating the `api_key.secure`
# - go to: https://github.com/settings/tokens/new
# - generate new token using `public_repo` scope
# - encrypt it using: `travis encrypt API_KEY_HERE`
# - paste the output below
api_key:
secure: "XHpyp21JUWI6GkV7APTwPZiJQJkRJ13E/9VALuWvDrNYF00OE8m+T0ZbG+N1WCuwewa2QQChqd5yBDlwJn+LlDPqstie69xjCt7PEhvI5ERZlbT8KUtMLI4bFIudsaa6LS6phWi/6aKb4cfn0nEYmWhpqfVfsn4Hh4F9OyOFSRmMSSXziU3kxLdIBBO4jOfoDYz+4KUX48CtIhmFy6dSb4G22jzVXL3ixGq895lVFlUzfiGJhHXoS+6KsOx1q0eIEMPC6V0VTT1loBNxKpjBPQ1b0KysCim/jRnr9mB3ko/4yWcMtIvCaZxTaQXWsQn9wAEN62x3ruKugZh3LJbtaxSvnH9PMntXZliz1HJw3Hpmn+tGLxAOm+uwHRz2C/T2ibemgmw6F8KjsjdNv7Nc2//ErIbmMvV4OlJjJI2Q3LWjnYa2gqI0L0sMqUz9HAfiY/BXLSxp19LgSvZPuHNVzMfh9ovF+Rdk1I3TyoByS8ZUi2ngnra8bSjmjtWHmkntOksjWNG6iobpjz9UxdWXPWxNJHQbRfEyTJSISpClykcSZWj+E2+tfuB3YvuRUaVOIhA3THdOSsqEesl3jkUeIhQqgRhE+Uq/XqB7MdfZ9ZTX8ZgfGFL0gjygviuWznTb0q5i4t1SgEJ2ie+ykjVyqQWa0dePtaQp8yx2PtzchJs="
# for uploading multiple files
file_glob: true
# NOTE explanation on each env variable
# - PROJECT_NAME: name of the project, set on the `env.global` above
# - TRAVIS_TAG: tag name that the build is being deployed for, usually the version number
# - TARGET: target triple of the build
file:
- $PROJECT_NAME-$TRAVIS_TAG-$TARGET.*
- $PROJECT_NAME*.deb
# don't delete artifacts from previous stage
skip_cleanup: true
on:
# deploy only if we push a tag
tags: true
# deploy only on stable channel that has TARGET env variable sets
condition: $TRAVIS_RUST_VERSION = stable && $TARGET != "x86_64-pc-windows-gnu"
notifications:
email:
on_success: never
+271
View File
@@ -0,0 +1,271 @@
# v0.17.0
## Features
- Add option to output result in C include file style, see #242 (@wpcwzy)
- Add `--color-scheme` option, see #247 (@aticu)
- Add `braille` character table, see #247 (@aticu)
- Add command line argument to generate shell completion, see #155 (@friedz)
- Add colors to `--help`/`-h`, see #253 (@starsep)
## Bugfixes
- Fix memory allocation bug when terminal width is less than 10, see #244 (@selfup)
# v0.16.0
## Features
* New `--print-color-table` option, see #229 (@sahinfalcon)
## Bugfixes
- Throw an error when try to view a directory, see #234 (@Integral-Tech)
# v0.15.0
## Features
- Add codepage 1047 for EBCDIC, see #226 (@v1gnesh)
## Other
- Rewrite CLI using the derive API, see #225 (@sorairolake)
# v0.14.0
## Features
* New `--character-table` option, with the ability to use [codepage 437](https://www.azabani.com/2020/11/15/xd.html), see #194 and #195 (@sharifhsn)
* New `--character-table=ascii` option for a ASCII-only character table, see #212 and #36 (@sharkdp)
## Bugfixes
* Show output when doing `hexyl /dev/zero`, see #211 (@sharifhsn)
* Respect NO_COLOR environment variable, see #210 (@sharkdp)
# v0.13.1
## Bugfixes
- Correctly handle discontinuous input (stdin), see #196 and #197 (@sharifhsn)
# v0.13.0
## Features
- Support both little and big Endian dumps using `--endianness={little,big}`, see #189 and #104 (@RinHizakura)
## Changes
- **Breaking**: Changed the meaning of the short flag `-C` to be consistent with `hexdump -C`. Previously, this would *hide* the character panel, but now `-C` *shows* the character panel, in case it has been previously (e.g. in an `alias`) disabled with `--no-characters`, see #187 (@sharkdp)
## `hexyl` as a library
- New `endianness` method for `PrinterBuilder`
# v0.12.0
## Features
- Only show one panel by default if the terminal width is not wide enough for two panels, see #182 (@sharkdp)
- Respect the `NO_COLOR` environment variable, see #179 (@sharifhsn)
## Bugfixes
- Do not fail with an error if `--panels=auto` is used and the output is piped, see #184 (@sharkdp)
## Changes
- Breaking: For `xxd`-compatibility reasons, `--group_bytes` has been renamed to `--group-size` (with an `--groupsize` alias), see #121 (@sharkdp)
## `hexyl` as a library
- Breaking: `num_group_bytes` has been renamed to `group_size`.
# v0.11.0
## Features
- Significantly improved performance, see #173 and #176 (@sharifhsn)
- Added variable panels through the `--panels` and `--terminal-width` flags, see [#13](https://github.com/sharkdp/hexyl/issues/13) and [#164](https://github.com/sharkdp/hexyl/pull/164) (@sharifhsn)
- Added new `--group-bytes`/`-g` option, see #104 and #170 (@RinHizakura)
- Added new `--base B` option (where `B` can be `binary`, `octal`, `decimal` or `hexadecimal`), see #147 and #178 (@sharifhsn)
- Show actual zero bytes as `⋄` in the character panel (previously: `0`), in order not to confuse them with ASCII
`0` bytes if colors are deactivated. Closes #166 (@sharkdp)
## `hexyl` as a library
- Breaking change: `Printer::new` is deprecated as a part of the public API. Alternatively, you can now construct a `Printer` using the `PrinterBuilder` builder API, see [#168](https://github.com/sharkdp/hexyl/pull/168). (@sharifhsn)
## Other
- More tests for the squeezing feature, see #177 (@mkatychev)
## Thank you
Special thanks go to @sharifhsn, not just for the new features,
bugfixes and performance improvements. But also for many internal
improvements of the code base and other maintenance tasks.
# 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
## Changes
- Breaking change (binary): setting the `-o/--display-offset` flag no longer overrides the value set by `--skip` [#115](https://github.com/sharkdp/hexyl/issues/115). The first displayed address is now the sum of the two values - this matches the behaviour of `xxd`.
## Features
- Allow relative and negative byte offsets (e.g. `hexyl --skip=-1block`), see #99 (@ErichDonGubler)
- Added `-l` as another alias for '-n/--length' (`xxd` compatibility), see #121 and #135 (@TheDoctor314)
## Bugfixes
- Argument `--length` silently takes precedence over `--bytes`, see #105
- Print warning on empty content, see #107 and #108
- Disallow block sizes of zero, see #110
- Fix newline appearing in `--version` output, see #131 and #133 (@scimas)
## Other
- Better diagnostic messages, see #98 (@ErichDonGubler)
## Packaging
- `hexyl` is now available on snapstore, see #116 (@purveshpatel511)
# v0.8.0
## Features
- A new `--skip <N>` / `-s <N>` option can be used to skip the first `N` bytes of the input, see #16, #88 (@Tarnadas, @MaxJohansen, @ErichDonGubler)
- The `--length`/`--bytes`/`--skip`/`--display-offset` options can now take units for their value argument, for example:
``` bash
hexyl /dev/random --length=1KiB
hexyl $(which hexyl) --skip=1MiB --length=10KiB
```
Both decimal SI prefixes (kB, MB, …) as well as binary IEC prefixes (KiB, MiB, …) are supported.
In addition, there is a new `--block-size <SIZE>` option that can be used to control the size of the `block`
unit:
``` bash
hexyl /dev/random --block-size=4kB --length=2block
```
See: #44 (@ErichDonGubler and @aswild)
## Other
- Various improvements throughout the code base by @ErichDonGubler
## Packaging
- `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
## 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
- `hexyl` can now be used as a library, see #67 (@tommilligan)
- Added a new `-o`/`--display-offset` option to add a certain offset to the
reported file positions, see #57 (@tommilligan)
## Bugfixes
- Remove additional space on short input, see #69 (@nalshihabi)
## Other
- Performance improvements, see #73 and #66
# v0.5.1
## Bugfixes
- A bug in the squeezing logic caused a wrong hexdump, see #62 (@awidegreen)
- 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 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)
## Changes
- Print header immediately before the first line, see #51 (@mziter)
# v0.4.0
## Features
- Added a new `--color=always/auto/never` option which can be used
to control `hexyl`s color output, see #30 (@bennetthardwick)
- Use 16 colors instead of 256, see #38
## Changes
- Various speed improvements, see #33 (@kballard)
## Bugfixes
- 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
+29
View File
@@ -0,0 +1,29 @@
# Contributing
Thank you for considering to contribute to `hexyl`!
## Add an entry to the changelog
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 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
subsections (Features, Bugfixes, …). Please add your entry to the subsection
that best describes your change
Entries follow this format:
```
- Short description of what has been changed, see #123 (@user)
```
Here, `#123` is the number of the original issue and/or your pull request.
Please replace `@user` by your GitHub username.
## Adding a new feature
Please consider opening a [ticket](https://github.com/sharkdp/hexyl/issues/new)
first in order to give us a chance to discuss the feature first.
Generated
+519 -96
View File
@@ -1,161 +1,584 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "ansi_term"
version = "0.11.0"
name = "aho-corasick"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr",
]
[[package]]
name = "ansi_term"
version = "0.12.1"
name = "anstream"
version = "0.6.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23a1e53f0f5d86382dafe1cf314783b2044280f406e7e1506368220ad11b1338"
dependencies = [
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
]
[[package]]
name = "atty"
version = "0.2.14"
name = "anstyle"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8365de52b16c035ff4fcafe0092ba9390540e3e352870ac09933bebcaa2c8c56"
[[package]]
name = "anstyle-parse"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
dependencies = [
"hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
dependencies = [
"anstyle",
"windows-sys 0.59.0",
]
[[package]]
name = "anyhow"
version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c042108f3ed77fd83760a5fd79b53be043192bb3b9dba91d8c574c0ada7850c8"
[[package]]
name = "assert_cmd"
version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c5bcfa8749ac45dd12cb11055aeeb6b27a3895560d60d71e3c23bf979e60514"
dependencies = [
"anstyle",
"bstr",
"libc",
"predicates",
"predicates-core",
"predicates-tree",
"wait-timeout",
]
[[package]]
name = "autocfg"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "bitflags"
version = "1.2.1"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
[[package]]
name = "bstr"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c"
dependencies = [
"memchr",
"regex-automata",
"serde",
]
[[package]]
name = "clap"
version = "2.33.0"
version = "4.5.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8"
dependencies = [
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"term_size 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"clap_builder",
"clap_derive",
]
[[package]]
name = "hermit-abi"
version = "0.1.8"
name = "clap_builder"
version = "4.5.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54"
dependencies = [
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)",
"anstream",
"anstyle",
"clap_lex",
"strsim",
"terminal_size",
]
[[package]]
name = "clap_complete"
version = "4.5.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5abde44486daf70c5be8b8f8f1b66c49f86236edf6fa2abadb4d961c4c6229a"
dependencies = [
"clap",
]
[[package]]
name = "clap_derive"
version = "4.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "clap_lex"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
[[package]]
name = "colorchoice"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
[[package]]
name = "const_format"
version = "0.2.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50c655d81ff1114fb0dcdea9225ea9f0cc712a6f8d189378e82bdf62a473a64b"
dependencies = [
"const_format_proc_macros",
]
[[package]]
name = "const_format_proc_macros"
version = "0.2.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eff1a44b93f47b1bac19a27932f5c591e43d1ba357ee4f61526c8a25603f0eb1"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "diff"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
[[package]]
name = "difflib"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
[[package]]
name = "errno"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
dependencies = [
"libc",
"windows-sys 0.52.0",
]
[[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 = "heck"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "hexyl"
version = "0.7.0"
version = "0.17.0"
dependencies = [
"ansi_term 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
"atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
"anyhow",
"assert_cmd",
"clap",
"clap_complete",
"const_format",
"libc",
"owo-colors",
"predicates",
"pretty_assertions",
"supports-color",
"terminal_size",
"thiserror",
]
[[package]]
name = "kernel32-sys"
version = "0.2.2"
name = "is_ci"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
checksum = "7655c9839580ee829dfacba1d1278c2b7883e50a277ff7541299489d6bdfdc45"
[[package]]
name = "is_terminal_polyfill"
version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "libc"
version = "0.2.67"
version = "0.2.161"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1"
[[package]]
name = "linux-raw-sys"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "normalize-line-endings"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be"
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]]
name = "owo-colors"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb37767f6569cd834a413442455e0f066d0d522de8630436e2a1761d9726ba56"
[[package]]
name = "predicates"
version = "3.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e9086cc7640c29a356d1a29fd134380bee9d8f79a17410aa76e7ad295f42c97"
dependencies = [
"anstyle",
"difflib",
"float-cmp",
"normalize-line-endings",
"predicates-core",
"regex",
]
[[package]]
name = "predicates-core"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae8177bee8e75d6846599c6b9ff679ed51e882816914eec639944d7c9aa11931"
[[package]]
name = "predicates-tree"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41b740d195ed3166cd147c8047ec98db0e22ec019eb8eeb76d343b795304fb13"
dependencies = [
"predicates-core",
"termtree",
]
[[package]]
name = "pretty_assertions"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d"
dependencies = [
"diff",
"yansi",
]
[[package]]
name = "proc-macro2"
version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "rustix"
version = "0.38.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa260229e6538e52293eeb577aabd09945a09d6d9cc0fc550ed7529056c2e32a"
dependencies = [
"bitflags",
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.52.0",
]
[[package]]
name = "serde"
version = "1.0.214"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.214"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "strsim"
version = "0.8.0"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "term_size"
version = "0.3.1"
name = "supports-color"
version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8775305acf21c96926c900ad056abeef436701108518cf890020387236ac5a77"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"is_ci",
]
[[package]]
name = "textwrap"
version = "0.11.0"
name = "syn"
version = "2.0.85"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56"
dependencies = [
"term_size 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-width"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "vec_map"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi-build"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-i686-pc-windows-gnu"
name = "terminal_size"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f599bd7ca042cfdf8f4512b277c02ba102247820f9d9d4a9f521f496751a6ef"
dependencies = [
"rustix",
"windows-sys 0.59.0",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
name = "termtree"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76"
[metadata]
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum ansi_term 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
"checksum hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)" = "eb147597cdf94ed43ab7a9038716637d2d1bf2bc571da995d0028dec06bd3018"
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
"checksum term_size 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9e5b9a66db815dcfd2da92db471106457082577c3c278d4138ab3e3b4e189327"
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "thiserror"
version = "1.0.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "unicode-ident"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
[[package]]
name = "unicode-xid"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
[[package]]
name = "utf8parse"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "wait-timeout"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
dependencies = [
"libc",
]
[[package]]
name = "windows-sys"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "yansi"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
+19 -6
View File
@@ -1,22 +1,35 @@
[package]
authors = ["David Peter <mail@david-peter.de>"]
categories = ["command-line-utilities"]
keywords = ["hex", "viewer"]
description = "A command-line hex viewer"
homepage = "https://github.com/sharkdp/hexyl"
license = "MIT/Apache-2.0"
name = "hexyl"
readme = "README.md"
repository = "https://github.com/sharkdp/hexyl"
version = "0.7.0"
edition = "2018"
version = "0.17.0"
edition = "2021"
rust-version = "1.88"
[dependencies]
ansi_term = "0.12"
atty = "0.2"
anyhow = "1.0"
const_format = "0.2"
libc = "0.2"
owo-colors = "4"
supports-color = "3"
thiserror = "1.0"
terminal_size = "0.4"
clap_complete = "4"
[dependencies.clap]
version = "2"
features = ["suggestions", "color", "wrap_help"]
version = "4"
features = ["derive", "wrap_help"]
[dev-dependencies]
assert_cmd = "2.1"
predicates = "3.0"
pretty_assertions = "1.4.0"
[profile.release]
lto = true
+121 -11
View File
@@ -1,10 +1,10 @@
![](doc/logo.svg)
[![Build Status](https://travis-ci.org/sharkdp/hexyl.svg?branch=master)](https://travis-ci.org/sharkdp/hexyl)
[![CICD](https://github.com/sharkdp/hexyl/actions/workflows/CICD.yml/badge.svg)](https://github.com/sharkdp/hexyl/actions/workflows/CICD.yml)
[![](https://img.shields.io/crates/l/hexyl.svg?colorB=22ba4c)](https://crates.io/crates/hexyl)
![](https://img.shields.io/crates/v/hexyl.svg?colorB=00aa88)
`hexyl` is a simple hex viewer for the terminal. It uses a colored output to distinguish different categories
`hexyl` is a 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).
## Preview
@@ -17,13 +17,14 @@ of bytes (NULL bytes, printable ASCII characters, ASCII whitespace characters, o
![](https://i.imgur.com/f8nm8g6.png)
## Installation
### On Ubuntu
*... 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 +32,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.7.0_amd64.deb # adapt version number and architecture
sudo dpkg -i hexyl_0.15.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,54 +45,163 @@ 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/):
You can install `hexyl` from [the official package repository](https://archlinux.org/packages/extra/x86_64/hexyl/):
```
pacman -S hexyl
```
### On Void Linux
```
xbps-install hexyl
```
### On Gentoo Linux
Available in [dm9pZCAq overlay](https://github.com/gentoo-mirror/dm9pZCAq)
```
sudo eselect repository enable dm9pZCAq
sudo emerge --sync dm9pZCAq
sudo emerge sys-apps/hexyl::dm9pZCAq
```
### On macOS
Via [Homebrew](https://brew.sh):
```
brew install hexyl
```
...or via [MacPorts](https://www.macports.org):
```
sudo port install hexyl
```
### On FreeBSD
```
pkg install hexyl
```
### On NetBSD
```
pkgin install hexyl
```
### On OpenBSD
```
doas pkg_add hexyl
```
### on Termux
```
pkg install hexyl
```
or
```
apt install hexyl
```
### Via Nix
```
nix-env -i hexyl
```
### Via Guix
```
guix package -i hexyl
```
Or add the `hexyl` package in the list of packages to be installed in your system configuration (e.g., `/etc/config.scm`).
### On other distributions
Check out the [release page](https://github.com/sharkdp/hexyl/releases) for binary builds.
### 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.31 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
```
### Via [X-CMD](https://x-cmd.com)
```
x env use hexyl
```
## Configuration
`hexyl` colors can be configured via environment variables. The variables used are as follows:
* `HEXYL_COLOR_ASCII_PRINTABLE`: Any non-whitespace printable ASCII character
* `HEXYL_COLOR_ASCII_WHITESPACE`: Whitespace such as space or newline (only visible in middle panel with byte values)
* `HEXYL_COLOR_ASCII_OTHER`: Any other ASCII character (< `0x80`) besides null
* `HEXYL_COLOR_NULL`: The null byte (`0x00`)
* `HEXYL_COLOR_NONASCII`: Any non-ASCII byte (> `0x7F`)
* `HEXYL_COLOR_OFFSET`: The lefthand file offset
The colors can be any of the 8 standard terminal colors: `black`, `blue`, `cyan`, `green`, `magenta`, `red`,
`yellow` and `white`. The "bright" variants are also supported (e.g., `bright blue`). Additionally, you can use
the RGB hex format, `#abcdef`. For example, `HEXYL_COLOR_ASCII_PRINTABLE=blue HEXYL_COLOR_ASCII_WHITESPACE="bright green"
HEXYL_COLOR_ASCII_OTHER="#ff7f99"`.
## 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
+159
View File
@@ -0,0 +1,159 @@
% HEXYL(1) hexyl 0.12.0 | General Commands Manual
%
% 2022-12-05
# 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.
# ENVIRONMENT VARIABLES
**hexyl** colors can be configured via environment variables. The variables used are as follows:
: - **HEXYL_COLOR_ASCII_PRINTABLE**: Any non-whitespace printable ASCII character
- **HEXYL_COLOR_ASCII_WHITESPACE**: Whitespace such as space or newline (only visible in middle panel with byte values)
- **HEXYL_COLOR_ASCII_OTHER**: Any other ASCII character (< **0x80**) besides null
- **HEXYL_COLOR_NULL**: The null byte (**0x00**)
- **HEXYL_COLOR_NONASCII**: Any non-ASCII byte (> **0x7F**)
- **HEXYL_COLOR_OFFSET**: The lefthand file offset
The colors can be any of the 8 standard terminal colors: **black**, **blue**, **cyan**, **green**, **magenta**, **red**,
**yellow** and **white**. The "bright" variants are also supported (e.g., **bright blue**). Additionally, you can use
the RGB hex format, **#abcdef**. For example, **HEXYL_COLOR_ASCII_PRINTABLE=blue HEXYL_COLOR_ASCII_WHITESPACE="bright green"
HEXYL_COLOR_ASCII_OTHER="#ff7f99"**.
# 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)
+11 -7
View File
@@ -1,9 +1,9 @@
use std::io;
use hexyl::{BorderStyle, Printer};
use hexyl::{BorderStyle, PrinterBuilder};
fn main() {
let input = vec![
let input = [
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44,
0x52, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x44, 0x08, 0x02, 0x00, 0x00, 0x00,
];
@@ -11,10 +11,14 @@ fn main() {
let stdout = io::stdout();
let mut handle = stdout.lock();
let show_color = 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 = PrinterBuilder::new(&mut handle)
.show_color(true)
.show_char_panel(true)
.show_position_panel(true)
.with_border_style(BorderStyle::Unicode)
.enable_squeezing(false)
.num_panels(2)
.group_size(1)
.build();
printer.print_all(&input[..]).unwrap();
}
-154
View File
@@ -1,154 +0,0 @@
#[macro_use]
extern crate clap;
use atty;
use std::fs::File;
use std::io::{self, prelude::*};
use clap::{App, AppSettings, Arg};
use atty::Stream;
use hexyl::{BorderStyle, Printer};
fn run() -> Result<(), Box<dyn std::error::Error>> {
let app = App::new(crate_name!())
.setting(AppSettings::ColorAuto)
.setting(AppSettings::ColoredHelp)
.setting(AppSettings::DeriveDisplayOrder)
.setting(AppSettings::UnifiedHelpMessage)
.version(crate_version!())
.about(crate_description!())
.arg(Arg::with_name("file").help("File to display"))
.arg(
Arg::with_name("length")
.short("n")
.long("length")
.takes_value(true)
.value_name("N")
.help("Read only N bytes from the input"),
)
.arg(
Arg::with_name("bytes")
.short("c")
.long("bytes")
.takes_value(true)
.value_name("N")
.help("An alias for -n/--length"),
)
.arg(
Arg::with_name("nosqueezing")
.short("v")
.long("no-squeezing")
.help(
"Displays all input data. Otherwise any number of groups of output \
lines which would be identical to the preceding group of lines, are \
replaced with a line comprised of a single asterisk.",
),
)
.arg(
Arg::with_name("color")
.long("color")
.takes_value(true)
.value_name("when")
.possible_values(&["always", "auto", "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::with_name("border")
.long("border")
.takes_value(true)
.possible_values(&["unicode", "ascii", "none"])
.default_value("unicode")
.help("Whether to draw a border with unicode or ASCII characters, or none at all"),
)
.arg(
Arg::with_name("display_offset")
.short("o")
.long("display-offset")
.takes_value(true)
.value_name("OFFSET")
.help("Add OFFSET to the displayed file position."),
);
let matches = app.get_matches_safe()?;
let stdin = io::stdin();
let mut reader: Box<dyn Read> = match matches.value_of("file") {
Some(filename) => Box::new(File::open(filename)?),
None => Box::new(stdin.lock()),
};
let length_arg = matches.value_of("length").or(matches.value_of("bytes"));
if let Some(length) = length_arg.and_then(parse_hex_or_int) {
reader = Box::new(reader.take(length));
}
let show_color = match matches.value_of("color") {
Some("never") => false,
Some("auto") => atty::is(Stream::Stdout),
_ => true,
};
let border_style = match matches.value_of("border") {
Some("unicode") => BorderStyle::Unicode,
Some("ascii") => BorderStyle::Ascii,
_ => BorderStyle::None,
};
let squeeze = !matches.is_present("nosqueezing");
let display_offset = matches
.value_of("display_offset")
.and_then(parse_hex_or_int)
.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);
printer.display_offset(display_offset as usize);
printer.print_all(&mut reader)?;
Ok(())
}
fn main() {
// Enable ANSI support for Windows
#[cfg(windows)]
let _ = ansi_term::enable_ansi_support();
let result = run();
if let Err(err) = result {
if let Some(clap_err) = err.downcast_ref::<clap::Error>() {
eprint!("{}", clap_err); // Clap errors already have newlines
match clap_err.kind {
// The exit code should not indicate an error for --help / --version
clap::ErrorKind::HelpDisplayed | clap::ErrorKind::VersionDisplayed => {
std::process::exit(0)
}
_ => (),
}
} else {
eprintln!("Error: {}", err);
}
std::process::exit(1);
}
}
fn parse_hex_or_int(n: &str) -> Option<u64> {
if n.starts_with("0x") {
u64::from_str_radix(n.trim_start_matches("0x"), 16).ok()
} else {
n.parse::<u64>().ok()
}
}
+184
View File
@@ -0,0 +1,184 @@
use owo_colors::{colors, AnsiColors, Color, DynColors, OwoColorize};
use std::str::FromStr;
use std::sync::LazyLock;
pub static COLOR_NULL: LazyLock<String> =
LazyLock::new(|| init_color("NULL", AnsiColors::BrightBlack));
pub static COLOR_OFFSET: LazyLock<String> =
LazyLock::new(|| init_color("OFFSET", AnsiColors::BrightBlack));
pub static COLOR_ASCII_PRINTABLE: LazyLock<String> =
LazyLock::new(|| init_color("ASCII_PRINTABLE", AnsiColors::Cyan));
pub static COLOR_ASCII_WHITESPACE: LazyLock<String> =
LazyLock::new(|| init_color("ASCII_WHITESPACE", AnsiColors::Green));
pub static COLOR_ASCII_OTHER: LazyLock<String> =
LazyLock::new(|| init_color("ASCII_OTHER", AnsiColors::Green));
pub static COLOR_NONASCII: LazyLock<String> =
LazyLock::new(|| init_color("NONASCII", AnsiColors::Yellow));
pub const COLOR_RESET: &str = colors::Default::ANSI_FG;
fn init_color(name: &str, default_ansi: AnsiColors) -> String {
let default = DynColors::Ansi(default_ansi);
let env_var = format!("HEXYL_COLOR_{name}");
let color = match std::env::var(env_var).as_deref() {
Ok(color) => match DynColors::from_str(color) {
Ok(color) => color,
_ => default,
},
_ => default,
};
// owo_colors' API isn't designed to get the terminal codes directly for
// dynamic colors, so we use this hack to get them from the LHS of some text.
format!("{}", "|".color(color))
.split_once("|")
.unwrap()
.0
.to_owned()
}
pub const COLOR_NULL_RGB: &[u8] = &rgb_bytes(100, 100, 100);
pub const COLOR_DEL: &[u8] = &rgb_bytes(64, 128, 0);
pub const COLOR_GRADIENT_NONASCII: [[u8; 19]; 128] =
generate_color_gradient(&[(255, 0, 0, 0.0), (255, 255, 0, 0.66), (255, 255, 255, 1.0)]);
pub const COLOR_GRADIENT_ASCII_NONPRINTABLE: [[u8; 19]; 31] =
generate_color_gradient(&[(255, 0, 255, 0.0), (128, 0, 255, 1.0)]);
pub const COLOR_GRADIENT_ASCII_PRINTABLE: [[u8; 19]; 95] =
generate_color_gradient(&[(0, 128, 255, 0.0), (0, 255, 128, 1.0)]);
const fn as_dec(byte: u8) -> [u8; 3] {
[
b'0' + (byte / 100),
b'0' + ((byte % 100) / 10),
b'0' + (byte % 10),
]
}
const fn rgb_bytes(r: u8, g: u8, b: u8) -> [u8; 19] {
let mut buf = *b"\x1b[38;2;rrr;ggg;bbbm";
// r 7
buf[7] = as_dec(r)[0];
buf[8] = as_dec(r)[1];
buf[9] = as_dec(r)[2];
// g 11
buf[11] = as_dec(g)[0];
buf[12] = as_dec(g)[1];
buf[13] = as_dec(g)[2];
// b 15
buf[15] = as_dec(b)[0];
buf[16] = as_dec(b)[1];
buf[17] = as_dec(b)[2];
buf
}
const fn generate_color_gradient<const N: usize>(stops: &[(u8, u8, u8, f64)]) -> [[u8; 19]; N] {
let mut out = [rgb_bytes(0, 0, 0); N];
assert!(stops.len() >= 2, "need at least two stops for the gradient");
let mut byte = 0;
while byte < N {
let relative_byte = byte as f64 / N as f64;
let mut i = 1;
while i < stops.len() && stops[i].3 < relative_byte {
i += 1;
}
if i >= stops.len() {
i = stops.len() - 1;
}
let prev_stop = stops[i - 1];
let stop = stops[i];
let diff = stop.3 - prev_stop.3;
let t = (relative_byte - prev_stop.3) / diff;
let r = (prev_stop.0 as f64 + (t * (stop.0 as f64 - prev_stop.0 as f64))) as u8;
let g = (prev_stop.1 as f64 + (t * (stop.1 as f64 - prev_stop.1 as f64))) as u8;
let b = (prev_stop.2 as f64 + (t * (stop.2 as f64 - prev_stop.2 as f64))) as u8;
out[byte] = rgb_bytes(r, g, b);
byte += 1;
}
out
}
#[rustfmt::skip]
pub const CP437: [char; 256] = [
// Copyright (c) 2016, Delan Azabani <delan@azabani.com>
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
// modified to use the ⋄ character instead of ␀
// use https://en.wikipedia.org/w/index.php?title=Code_page_437&oldid=978947122
// not ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/PC/CP437.TXT
// because we want the graphic versions of 01h–1Fh + 7Fh
'⋄','☺','☻','♥','♦','♣','♠','•','◘','○','◙','♂','♀','♪','♫','☼',
'►','◄','↕','‼','¶','§','▬','↨','↑','↓','→','←','∟','↔','▲','▼',
' ','!','"','#','$','%','&','\'','(',')','*','+',',','-','.','/',
'0','1','2','3','4','5','6','7','8','9',':',';','<','=','>','?',
'@','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O',
'P','Q','R','S','T','U','V','W','X','Y','Z','[','\\',']','^','_',
'`','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o',
'p','q','r','s','t','u','v','w','x','y','z','{','|','}','~','⌂',
'Ç','ü','é','â','ä','à','å','ç','ê','ë','è','ï','î','ì','Ä','Å',
'É','æ','Æ','ô','ö','ò','û','ù','ÿ','Ö','Ü','¢','£','¥','₧','ƒ',
'á','í','ó','ú','ñ','Ñ','ª','º','¿','⌐','¬','½','¼','¡','«','»',
'░','▒','▓','│','┤','╡','╢','╖','╕','╣','║','╗','╝','╜','╛','┐',
'└','┴','┬','├','─','┼','╞','╟','╚','╔','╩','╦','╠','═','╬','╧',
'╨','╤','╥','╙','╘','╒','╓','╫','╪','┘','┌','█','▄','▌','▐','▀',
'α','ß','Γ','π','Σ','σ','µ','τ','Φ','Θ','Ω','δ','∞','φ','ε','∩',
'≡','±','≥','≤','⌠','⌡','÷','≈','°','∙','·','√','ⁿ','²','■','ff',
];
#[rustfmt::skip]
pub const CP1047: [char; 256] = [
//
// Copyright (c) 2016,2024 IBM Corporation and other Contributors.
//
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// which accompanies this distribution, and is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// Contributors:
// Mark Taylor - Initial Contribution
//
// ref1 https://github.com/ibm-messaging/mq-smf-csv/blob/master/src/smfConv.c
// ref2 https://web.archive.org/web/20150607033635/http://www-01.ibm.com/software/globalization/cp/cp01047.html
'.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.',
'.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.',
'.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.',
'.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.',
' ','.','.','.','.','.','.','.','.','.','$','.','<','(','+','|',
'&','.','.','.','.','.','.','.','.','.','!','$','*',')',';','.',
'-','/','.','.','.','.','.','.','.','.','.',',','%','_','>','?',
'.','.','.','.','.','.','.','.','.','.',':','#','@','\'','=','.',
'.','a','b','c','d','e','f','g','h','i','.','{','.','(','+','.',
'.','j','k','l','m','n','o','p','q','r','.','}','.',')','.','.',
'.','~','s','t','u','v','w','x','y','z','.','.','.','.','.','.',
'.','.','.','.','.','.','.','.','.','.','[',']','.','.','.','-',
'{','A','B','C','D','E','F','G','H','I','.','.','.','.','.','.',
'}','J','K','L','M','N','O','P','Q','R','.','.','.','.','.','.',
'.','.','S','T','U','V','W','X','Y','Z','.','.','.','.','.','.',
'0','1','2','3','4','5','6','7','8','9','.','.','.','.','.','.'
];
+64
View File
@@ -0,0 +1,64 @@
use std::fs;
use std::io::{self, copy, sink, Read, Seek, SeekFrom};
pub enum Input<'a> {
File(fs::File),
Stdin(io::StdinLock<'a>),
}
impl Read for Input<'_> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match *self {
Input::File(ref mut file) => file.read(buf),
Input::Stdin(ref mut stdin) => stdin.read(buf),
}
}
}
impl Seek for Input<'_> {
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
fn try_skip<R>(reader: R, pos: SeekFrom, err_desc: &'static str) -> io::Result<u64>
where
R: Read,
{
let cant_seek_abs_err = || Err(io::Error::other(err_desc));
let offset = match pos {
SeekFrom::Current(o) => u64::try_from(o).or_else(|_e| cant_seek_abs_err())?,
SeekFrom::Start(_) | SeekFrom::End(_) => cant_seek_abs_err()?,
};
copy(&mut reader.take(offset), &mut sink())
}
match *self {
Input::File(ref mut file) => {
let seek_res = file.seek(pos);
if let Err(Some(libc::ESPIPE)) = seek_res.as_ref().map_err(|err| err.raw_os_error())
{
try_skip(
file,
pos,
"Pipes only support seeking forward with a relative offset",
)
} else {
seek_res
}
}
Input::Stdin(ref mut stdin) => try_skip(
stdin,
pos,
"STDIN only supports seeking forward with a relative offset",
),
}
}
}
impl<'a> Input<'a> {
pub fn into_inner(self) -> Box<dyn Read + 'a> {
match self {
Input::File(file) => Box::new(file),
Input::Stdin(stdin) => Box::new(stdin),
}
}
}
+944 -292
View File
File diff suppressed because it is too large. Load diff
+835
View File
@@ -0,0 +1,835 @@
use std::fs::File;
use std::io::{self, prelude::*, BufWriter, SeekFrom};
use std::num::{NonZeroI64, NonZeroU64};
use std::path::PathBuf;
use clap::builder::styling::{AnsiColor, Effects};
use clap::builder::ArgPredicate;
use clap::builder::Styles;
use clap::{ArgAction, CommandFactory, Parser, ValueEnum};
use clap_complete::aot::{generate, Shell};
use anyhow::{anyhow, bail, Context, Result};
use const_format::formatcp;
use thiserror::Error as ThisError;
use terminal_size::terminal_size;
use hexyl::{
Base, BorderStyle, CharacterTable, ColorScheme, Endianness, IncludeMode, Input, PrinterBuilder,
};
use hexyl::{
COLOR_ASCII_OTHER, COLOR_ASCII_PRINTABLE, COLOR_ASCII_WHITESPACE, COLOR_NONASCII, COLOR_NULL,
COLOR_RESET,
};
#[cfg(test)]
mod tests;
const DEFAULT_BLOCK_SIZE: i64 = 512;
const LENGTH_HELP_TEXT: &str = "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. The short \
option '-l' can be used as an alias.
Examples: --length=64, --length=4KiB, --length=0xff";
const SKIP_HELP_TEXT: &str = "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.";
const BLOCK_SIZE_HELP_TEXT: &str = "Sets the size of the `block` unit to SIZE.
Examples: --block-size=1024, --block-size=4kB";
const DISPLAY_OFFSET_HELP_TEXT: &str = "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.";
const TERMINAL_WIDTH_HELP_TEXT: &str = "Sets the number of terminal columns to be displayed.
Since 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 panels that can \
fit in the requested width but still leave some space to \
the right.
Cannot be used with other width-setting options.";
const STYLES: Styles = Styles::styled()
.header(AnsiColor::Green.on_default().effects(Effects::BOLD))
.usage(AnsiColor::Green.on_default().effects(Effects::BOLD))
.literal(AnsiColor::Cyan.on_default().effects(Effects::BOLD))
.placeholder(AnsiColor::Cyan.on_default());
#[derive(Debug, Parser)]
#[command(version, about, max_term_width(90), styles = STYLES)]
struct Opt {
/// The file to display. If no FILE argument is given, read from STDIN.
#[arg(value_name("FILE"))]
file: Option<PathBuf>,
#[arg(
help(LENGTH_HELP_TEXT),
short('n'),
long,
visible_short_alias('c'),
visible_alias("bytes"),
short_alias('l'),
value_name("N")
)]
length: Option<String>,
#[arg(help(SKIP_HELP_TEXT), short, long, value_name("N"))]
skip: Option<String>,
#[arg(
help(BLOCK_SIZE_HELP_TEXT),
long,
default_value(formatcp!("{DEFAULT_BLOCK_SIZE}")),
value_name("SIZE")
)]
block_size: String,
/// Displays all input data. Otherwise any number of groups of output lines
/// which would be identical to the preceding group of lines, are replaced
/// with a line comprised of a single asterisk.
#[arg(short('v'), long)]
no_squeezing: bool,
/// When to use colors.
#[arg(
long,
value_enum,
default_value_t,
value_name("WHEN"),
default_value_if("plain", ArgPredicate::IsPresent, Some("never"))
)]
color: ColorWhen,
/// Whether to draw a border.
#[arg(
long,
value_enum,
default_value_t,
value_name("STYLE"),
default_value_if("plain", ArgPredicate::IsPresent, Some("none"))
)]
border: BorderStyle,
/// Display output with --no-characters, --no-position, --border=none, and
/// --color=never.
#[arg(short, long)]
plain: bool,
/// Do not show the character panel on the right.
#[arg(long)]
no_characters: bool,
/// Show the character panel on the right. This is the default, unless
/// --no-characters has been specified.
#[arg(
short('C'),
long,
action(ArgAction::SetTrue),
overrides_with("no_characters")
)]
characters: (),
/// Defines how bytes are mapped to characters.
#[arg(long, value_enum, default_value_t, value_name("FORMAT"))]
character_table: CharacterTable,
/// Defines the color scheme for the characters.
#[arg(long, value_enum, default_value_t, value_name("FORMAT"))]
color_scheme: ColorScheme,
/// Whether to display the position panel on the left.
#[arg(short('P'), long)]
no_position: bool,
#[arg(
help(DISPLAY_OFFSET_HELP_TEXT),
short('o'),
long,
default_value("0"),
value_name("N")
)]
display_offset: String,
/// Sets the number of hex data panels to be displayed. `--panels=auto` will
/// display the maximum number of hex data panels based on the current
/// terminal width. By default, hexyl will show two panels, unless the
/// terminal is not wide enough for that.
#[arg(long, value_name("N"))]
panels: Option<String>,
/// Number of bytes/octets that should be grouped together. You can use the
/// '--endianness' option to control the ordering of the bytes within a
/// group. '--groupsize' can be used as an alias (xxd-compatibility).
#[arg(
short('g'),
long,
value_enum,
default_value_t,
alias("groupsize"),
value_name("N")
)]
group_size: GroupSize,
/// Whether to print out groups in little-endian or big-endian format. This
/// option only has an effect if the '--group-size' is larger than 1. '-e'
/// can be used as an alias for '--endianness=little'.
#[arg(long, value_enum, default_value_t, value_name("FORMAT"))]
endianness: Endianness,
/// An alias for '--endianness=little'.
#[arg(short('e'), hide(true), overrides_with("endianness"))]
little_endian_format: bool,
/// Sets the base used for the bytes. The possible options are binary,
/// octal, decimal, and hexadecimal.
#[arg(short('b'), long, default_value("hexadecimal"), value_name("B"))]
base: String,
#[arg(
help(TERMINAL_WIDTH_HELP_TEXT),
long,
value_name("N"),
conflicts_with("panels")
)]
terminal_width: Option<NonZeroU64>,
/// Print a table showing how different types of bytes are colored.
#[arg(long)]
print_color_table: bool,
/// Output in C include file style (similar to xxd -i).
#[arg(
short('i'),
long("include"),
help = "Output in C include file style",
conflicts_with("little_endian_format"),
conflicts_with("endianness")
)]
include_mode: bool,
/// Show shell completion for a certain shell
#[arg(long, value_name("SHELL"))]
completion: Option<Shell>,
}
#[derive(Clone, Debug, Default, ValueEnum)]
enum ColorWhen {
/// Always use colorized output.
#[default]
Always,
/// Only displays colors if the output goes to an interactive terminal.
Auto,
/// Do not use colorized output.
Never,
/// Override the NO_COLOR environment variable.
Force,
}
#[derive(Clone, Debug, Default, ValueEnum)]
enum GroupSize {
/// Grouped together every byte/octet.
#[default]
#[value(name = "1")]
One,
/// Grouped together every 2 bytes/octets.
#[value(name = "2")]
Two,
/// Grouped together every 4 bytes/octets.
#[value(name = "4")]
Four,
/// Grouped together every 8 bytes/octets.
#[value(name = "8")]
Eight,
}
impl From<GroupSize> for u8 {
fn from(number: GroupSize) -> Self {
match number {
GroupSize::One => 1,
GroupSize::Two => 2,
GroupSize::Four => 4,
GroupSize::Eight => 8,
}
}
}
fn run() -> Result<()> {
let opt = Opt::parse();
if opt.print_color_table {
return print_color_table().map_err(|e| anyhow!(e));
}
if let Some(sh) = opt.completion {
let mut cmd = Opt::command();
let name = cmd.get_name().to_string();
generate(sh, &mut cmd, name, &mut io::stdout());
return Ok(());
}
let stdin = io::stdin();
let mut reader = match &opt.file {
Some(filename) => {
if filename.as_os_str() == "-" {
Input::Stdin(stdin.lock())
} else {
if filename.is_dir() {
bail!("'{}' is a directory.", filename.to_string_lossy());
}
let file = File::open(filename)?;
Input::File(file)
}
}
None => Input::Stdin(stdin.lock()),
};
if let Some(hex_number) = try_parse_as_hex_number(&opt.block_size) {
return hex_number
.map_err(|e| anyhow!(e))
.and_then(|x| {
PositiveI64::new(x).ok_or_else(|| anyhow!("block size argument must be positive"))
})
.map(|_| ());
}
let (num, unit) = extract_num_and_unit_from(&opt.block_size)?;
if let Unit::Block { custom_size: _ } = unit {
return Err(anyhow!(
"can not use 'block(s)' as a unit to specify block size"
));
};
let 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"))
})?;
let skip_arg = opt
.skip
.as_ref()
.map(|s| {
parse_byte_offset(s, block_size).context(anyhow!(
"failed to parse `--skip` arg {:?} as byte count",
s
))
})
.transpose()?;
let skip_offset = if let Some(ByteOffset { kind, value }) = skip_arg {
let value = value.into_inner();
reader
.seek(match kind {
ByteOffsetKind::ForwardFromBeginning | ByteOffsetKind::ForwardFromLastOffset => {
SeekFrom::Current(value)
}
ByteOffsetKind::BackwardFromEnd => SeekFrom::End(value.checked_neg().unwrap()),
})
.map_err(|_| {
anyhow!(
"Failed to jump to the desired input position. \
This could be caused by a negative offset that is too large or by \
an input that is not seek-able (e.g. if the input comes from a pipe)."
)
})?
} else {
0
};
let parse_byte_count = |s| -> Result<u64> {
Ok(parse_byte_offset(s, block_size)?
.assume_forward_offset_from_start()?
.into())
};
let mut reader = if let Some(ref length) = opt.length {
let length = parse_byte_count(length).context(anyhow!(
"failed to parse `--length` arg {:?} as byte count",
length
))?;
Box::new(reader.take(length))
} else {
reader.into_inner()
};
let no_color = std::env::var_os("NO_COLOR").is_some();
let show_color = match opt.color {
ColorWhen::Never => false,
ColorWhen::Always => !no_color,
ColorWhen::Force => true,
ColorWhen::Auto => {
if no_color {
false
} else {
supports_color::on(supports_color::Stream::Stdout)
.map(|level| level.has_basic)
.unwrap_or(false)
}
}
};
let border_style = opt.border;
let &squeeze = &!opt.no_squeezing;
let show_char_panel = !opt.no_characters && !opt.plain;
let show_position_panel = !opt.no_position && !opt.plain;
let display_offset: u64 = parse_byte_count(&opt.display_offset).context(anyhow!(
"failed to parse `--display-offset` arg {:?} as byte count",
opt.display_offset
))?;
let max_panels_fn = |terminal_width: u64, base_digits: u64, group_size: u64| {
let offset = if show_position_panel { 10 } else { 1 };
let col_width = if show_char_panel {
((8 / group_size) * (base_digits * group_size + 1)) + 2 + 8
} else {
((8 / group_size) * (base_digits * group_size + 1)) + 2
};
if (terminal_width.saturating_sub(offset)) / col_width < 1 {
1
} else {
(terminal_width - offset) / col_width
}
};
let base = if let Ok(base_num) = opt.base.parse::<u8>() {
match base_num {
2 => Ok(Base::Binary),
8 => Ok(Base::Octal),
10 => Ok(Base::Decimal),
16 => Ok(Base::Hexadecimal),
_ => Err(anyhow!(
"The number provided is not a valid base. Valid bases are 2, 8, 10, and 16."
)),
}
} else {
match opt.base.as_str() {
"b" | "bin" | "binary" => Ok(Base::Binary),
"o" | "oct" | "octal" => Ok(Base::Octal),
"d" | "dec" | "decimal" => Ok(Base::Decimal),
"x" | "hex" | "hexadecimal" => Ok(Base::Hexadecimal),
_ => Err(anyhow!(
"The base provided is not valid. Valid bases are \"b\", \"o\", \"d\", and \"x\"."
)),
}
}?;
let base_digits = match base {
Base::Binary => 8,
Base::Octal => 3,
Base::Decimal => 3,
Base::Hexadecimal => 2,
};
let group_size = u8::from(opt.group_size);
let terminal_width = terminal_size().map(|s| s.0 .0 as u64).unwrap_or(80);
let panels = if opt.panels.as_deref() == Some("auto") {
max_panels_fn(terminal_width, base_digits, group_size.into())
} else if let Some(panels) = opt.panels {
panels
.parse::<NonZeroU64>()
.map(u64::from)
.context(anyhow!(
"failed to parse `--panels` arg {:?} as unsigned nonzero integer",
panels
))?
} else if let Some(terminal_width) = opt.terminal_width {
max_panels_fn(terminal_width.into(), base_digits, group_size.into())
} else {
std::cmp::min(
2,
max_panels_fn(terminal_width, base_digits, group_size.into()),
)
};
let endianness = if opt.little_endian_format {
Endianness::Little
} else {
opt.endianness
};
let character_table = opt.character_table;
let color_scheme = opt.color_scheme;
let mut stdout = BufWriter::new(io::stdout().lock());
let include_mode = match opt.include_mode {
// include mode on
true => {
if let Some(include_file) = opt.file {
// input from a file
if include_file.as_os_str() == "-" {
IncludeMode::File("stdin".to_string())
} else {
IncludeMode::File(
include_file
.file_name()
.and_then(|n| n.to_str())
.unwrap_or("file")
.to_string(),
)
}
} else {
// input from stdin
IncludeMode::Stdin
}
}
// include mode off
false => IncludeMode::Off,
};
let mut printer = PrinterBuilder::new(&mut stdout)
.show_color(show_color)
.show_char_panel(show_char_panel)
.show_position_panel(show_position_panel)
.with_border_style(border_style)
.enable_squeezing(squeeze)
.num_panels(panels)
.group_size(group_size)
.with_base(base)
.endianness(endianness)
.character_table(character_table)
.include_mode(include_mode)
.color_scheme(color_scheme)
.build();
printer.display_offset(skip_offset + display_offset);
printer.print_all(&mut reader).map_err(|e| anyhow!(e))?;
Ok(())
}
fn main() {
let result = run();
if let Err(err) = result {
if let Some(io_error) = err.downcast_ref::<io::Error>() {
if io_error.kind() == ::std::io::ErrorKind::BrokenPipe {
std::process::exit(0);
}
}
eprintln!("Error: {err:?}");
std::process::exit(1);
}
}
#[derive(Clone, Copy, Debug, Default, Hash, Eq, Ord, PartialEq, PartialOrd)]
pub struct NonNegativeI64(i64);
impl NonNegativeI64 {
pub fn new(x: i64) -> Option<Self> {
if x.is_negative() {
None
} else {
Some(Self(x))
}
}
pub fn into_inner(self) -> i64 {
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")
}
}
fn print_color_table() -> io::Result<()> {
let mut stdout = BufWriter::new(io::stdout().lock());
writeln!(stdout, "hexyl color reference:\n")?;
// NULL bytes
stdout.write_all(COLOR_NULL.as_bytes())?;
writeln!(stdout, "⋄ NULL bytes (0x00)")?;
stdout.write_all(COLOR_RESET.as_bytes())?;
// ASCII printable
stdout.write_all(COLOR_ASCII_PRINTABLE.as_bytes())?;
writeln!(stdout, "a ASCII printable characters (0x20 - 0x7E)")?;
stdout.write_all(COLOR_RESET.as_bytes())?;
// ASCII whitespace
stdout.write_all(COLOR_ASCII_WHITESPACE.as_bytes())?;
writeln!(stdout, "_ ASCII whitespace (0x09 - 0x0D, 0x20)")?;
stdout.write_all(COLOR_RESET.as_bytes())?;
// ASCII other
stdout.write_all(COLOR_ASCII_OTHER.as_bytes())?;
writeln!(
stdout,
"• ASCII control characters (except NULL and whitespace)"
)?;
stdout.write_all(COLOR_RESET.as_bytes())?;
// Non-ASCII
stdout.write_all(COLOR_NONASCII.as_bytes())?;
writeln!(stdout, "× Non-ASCII bytes (0x80 - 0xFF)")?;
stdout.write_all(COLOR_RESET.as_bytes())?;
Ok(())
}
#[derive(Clone, Copy, Debug, Default, Hash, Eq, Ord, PartialEq, PartialOrd)]
pub struct PositiveI64(i64);
impl PositiveI64 {
pub fn new(x: i64) -> Option<Self> {
if x < 1 {
None
} else {
Some(Self(x))
}
}
pub fn into_inner(self) -> i64 {
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)]
enum ByteOffsetKind {
ForwardFromBeginning,
ForwardFromLastOffset,
BackwardFromEnd,
}
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
struct ByteOffset {
value: NonNegativeI64,
kind: ByteOffsetKind,
}
#[derive(Clone, Debug, ThisError)]
#[error(
"negative offset specified, but only positive offsets (counts) are accepted in this context"
)]
struct NegativeOffsetSpecifiedError;
impl ByteOffset {
fn assume_forward_offset_from_start(
&self,
) -> Result<NonNegativeI64, NegativeOffsetSpecifiedError> {
let &Self { value, kind } = self;
match kind {
ByteOffsetKind::ForwardFromBeginning | ByteOffsetKind::ForwardFromLastOffset => {
Ok(value)
}
ByteOffsetKind::BackwardFromEnd => Err(NegativeOffsetSpecifiedError),
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, ThisError)]
enum ByteOffsetParseError {
#[error("no character data found, did you forget to write it?")]
Empty,
#[error("no digits found after sign, did you forget to write them?")]
EmptyAfterSign,
#[error(
"found {0:?} sign after hex prefix ({:?}); signs should go before it",
HEX_PREFIX
)]
SignFoundAfterHexPrefix(char),
#[error("{0:?} is not of the expected form <pos-integer>[<unit>]")]
InvalidNumAndUnit(String),
#[error("{0:?} is a valid unit, but an integer should come before it")]
EmptyWithUnit(String),
#[error("invalid unit {0:?}")]
InvalidUnit(String),
#[error("failed to parse integer part")]
ParseNum(#[source] std::num::ParseIntError),
#[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) = process_sign_of(n)?;
let into_byte_offset = |value| {
Ok(ByteOffset {
value: NonNegativeI64::new(value).unwrap(),
kind,
})
};
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() {
Err(EmptyAfterSign)
} else {
Err(SignFoundAfterHexPrefix(c))
}
}
_ => (),
}
i64::from_str_radix(num, 16).map_err(ParseNum)
})
}
-423
View File
@@ -1,423 +0,0 @@
#[derive(Debug, PartialEq)]
enum SqueezeState {
/// not enabled
Disabled,
/// Will be set from all states if equal condition can't be hold up.
/// Set if previous byte is not equal the current processed byte.
NoSqueeze,
/// Valid for a whole line to identify if it is candidate for squeezing
Probe,
/// Squeeze line parsing is active, but EOL is not reached yet
SqueezeActive,
/// Squeeze line, EOL is reached, will influence the action
Squeeze,
/// same as Squeeze, however this is only for the first line after
/// the squeeze candidate has been set.
SqueezeFirstLine,
/// same as SqueezeActive, however this is only for the first line after
/// the squeeze candidate has been set.
SqueezeActiveFirstLine,
}
pub struct Squeezer {
state: SqueezeState,
byte: u8,
}
#[derive(Debug, PartialEq)]
pub enum SqueezeAction {
Ignore,
Print,
Delete,
}
/// line size
const LSIZE: usize = 16;
impl Squeezer {
pub fn new(enabled: bool) -> Squeezer {
Squeezer {
state: if enabled {
SqueezeState::Probe
} else {
SqueezeState::Disabled
},
byte: 0,
}
}
pub fn process(&mut self, b: u8, i: usize) {
use self::SqueezeState::*;
if self.state == Disabled {
return;
}
let eq = b == self.byte;
if i % LSIZE == 0 {
if !eq {
self.state = Probe;
} else {
self.state = match self.state {
NoSqueeze => Probe,
Probe => SqueezeActiveFirstLine,
SqueezeActiveFirstLine => SqueezeFirstLine,
SqueezeFirstLine => SqueezeActive,
SqueezeActive => Squeeze,
Squeeze => SqueezeActive,
Disabled => Disabled,
};
}
} else if !eq {
if i % LSIZE == 1 {
self.state = Probe;
} else if i % LSIZE != 1 {
self.state = NoSqueeze;
}
}
self.byte = b;
}
pub fn active(&self) -> bool {
use self::SqueezeState::*;
match self.state {
Squeeze | SqueezeActive | SqueezeFirstLine | SqueezeActiveFirstLine => true,
_ => false,
}
}
pub fn action(&self) -> SqueezeAction {
match self.state {
SqueezeState::SqueezeFirstLine => SqueezeAction::Print,
SqueezeState::Squeeze => SqueezeAction::Delete,
_ => SqueezeAction::Ignore,
}
}
pub fn advance(&mut self) {
match self.state {
SqueezeState::SqueezeFirstLine => {
self.state = SqueezeState::SqueezeActive;
}
SqueezeState::Squeeze => {
self.state = SqueezeState::SqueezeActive;
}
_ => {}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn three_same_lines() {
const LINES: usize = 3;
let v = vec![0u8; LINES * LSIZE];
let mut s = Squeezer::new(true);
// just initialized
assert_eq!(s.action(), SqueezeAction::Ignore);
s.advance();
let exp = vec![
SqueezeAction::Ignore, // first line, print as is
SqueezeAction::Print, // print squeeze symbol
SqueezeAction::Delete, // delete reoccurring line
];
let mut line = 0;
let mut idx = 1;
for z in v.chunks(LSIZE) {
for i in z {
s.process(*i, idx);
idx += 1;
}
let action = s.action();
s.advance();
assert_eq!(action, exp[line]);
line += 1;
}
}
#[test]
fn incomplete_while_squeeze() {
// fourth line only has 12 bytes and should be printed
let v = vec![0u8; 3 * LSIZE + 12];
let mut s = Squeezer::new(true);
// just initialized
assert_eq!(s.action(), SqueezeAction::Ignore);
s.advance();
let exp = vec![
SqueezeAction::Ignore, // first line, print as is
SqueezeAction::Print, // print squeeze symbol
SqueezeAction::Delete, // delete reoccurring line
SqueezeAction::Ignore, // last line only 12 bytes, print it
];
let mut line = 0;
let mut idx = 1;
for z in v.chunks(LSIZE) {
for i in z {
s.process(*i, idx);
idx += 1;
}
assert_eq!(s.action(), exp[line]);
s.advance();
line += 1;
}
}
#[test]
/// all three lines are different, print all
fn three_different_lines() {
let mut v: Vec<u8> = vec![];
v.extend(vec![0u8; 16]);
v.extend(vec![1u8; 16]);
v.extend(vec![2u8; 16]);
let mut s = Squeezer::new(true);
// just initialized
assert_eq!(s.action(), SqueezeAction::Ignore);
s.advance();
let exp = vec![
SqueezeAction::Ignore, // first line, print as is
SqueezeAction::Ignore, // different
SqueezeAction::Ignore, // different
];
let mut line = 0;
let mut idx = 1;
for z in v.chunks(LSIZE) {
for i in z {
s.process(*i, idx);
idx += 1;
}
let action = s.action();
assert_eq!(action, exp[line]);
s.advance();
line += 1;
}
}
#[test]
/// first two lines same, hence squeeze symbol, third line diff, hence
/// print
fn one_squeeze_no_delete() {
const LINES: usize = 3;
let mut v = vec![0u8; (LINES - 1) * LSIZE];
v.extend(vec![1u8; 16]);
let mut s = Squeezer::new(true);
// just initialized
assert_eq!(s.action(), SqueezeAction::Ignore);
s.advance();
let exp = vec![
SqueezeAction::Ignore, // first line, print as is
SqueezeAction::Print, // print squeeze symbol
SqueezeAction::Ignore, // different lines, print again
];
let mut line = 0;
let mut idx = 1;
for z in v.chunks(LSIZE) {
for i in z {
s.process(*i, idx);
idx += 1;
}
let action = s.action();
s.advance();
assert_eq!(action, exp[line]);
line += 1;
}
}
#[test]
/// First line all eq, 2nd half eq with first line, then change
fn second_line_different() {
const LINES: usize = 2;
let mut v = vec![0u8; (LINES - 1) * LSIZE];
v.extend(vec![0u8; 8]);
v.extend(vec![1u8; 8]);
let mut s = Squeezer::new(true);
// just initialized
assert_eq!(s.action(), SqueezeAction::Ignore);
s.advance();
let exp = vec![
SqueezeAction::Ignore, // first line, print as is
SqueezeAction::Ignore, // print squeeze symbol
];
let mut line = 0;
let mut idx = 1;
for z in v.chunks(LSIZE) {
for i in z {
s.process(*i, idx);
idx += 1;
}
let action = s.action();
s.advance();
assert_eq!(action, exp[line]);
line += 1;
}
}
#[test]
/// all three lines never become squeeze candidate (diff within line)
fn never_squeeze_candidate() {
let mut v = vec![];
v.extend(vec![0u8; 8]);
v.extend(vec![1u8; 8]);
v.extend(vec![0u8; 8]);
v.extend(vec![1u8; 8]);
v.extend(vec![0u8; 8]);
v.extend(vec![1u8; 8]);
let mut s = Squeezer::new(true);
// just initialized
assert_eq!(s.action(), SqueezeAction::Ignore);
s.advance();
let exp = vec![
SqueezeAction::Ignore, // first line, print as is
SqueezeAction::Ignore, // print squeeze symbol
SqueezeAction::Ignore, // print squeeze symbol
];
let mut line = 0;
let mut idx = 1;
for z in v.chunks(LSIZE) {
for i in z {
s.process(*i, idx);
idx += 1;
}
let action = s.action();
s.advance();
assert_eq!(action, exp[line]);
line += 1;
}
}
#[test]
fn mix_everything() {
let mut v = vec![];
v.extend(vec![10u8; 16]); // print
v.extend(vec![20u8; 16]); // print
v.extend(vec![0u8; 16]); // print
v.extend(vec![0u8; 16]); // *
v.extend(vec![10u8; 16]); // print
v.extend(vec![20u8; 16]); // print
v.extend(vec![0u8; 16]); // print
v.extend(vec![0u8; 16]); // *
v.extend(vec![0u8; 16]); // delete
v.extend(vec![0u8; 16]); // delete*
v.extend(vec![20u8; 16]); // print
v.extend(vec![0u8; 12]); // print, only 12 bytes
let mut s = Squeezer::new(true);
// just initialized
assert_eq!(s.action(), SqueezeAction::Ignore);
s.advance();
let exp = vec![
SqueezeAction::Ignore,
SqueezeAction::Ignore,
SqueezeAction::Ignore,
SqueezeAction::Print,
SqueezeAction::Ignore,
SqueezeAction::Ignore,
SqueezeAction::Ignore,
SqueezeAction::Print,
SqueezeAction::Delete,
SqueezeAction::Delete,
SqueezeAction::Ignore,
SqueezeAction::Ignore,
];
let mut line = 0;
let mut idx = 1;
for z in v.chunks(LSIZE) {
for i in z {
s.process(*i, idx);
idx += 1;
}
let action = s.action();
s.advance();
assert_eq!(action, exp[line]);
line += 1;
}
}
#[test]
fn last_char_diff() {
// see issue #62
let mut v = vec![];
v.extend(vec![20u8; 16]);
v.extend(vec![20u8; 15]);
v.push(61);
v.extend(vec![20u8; 16]);
v.extend(vec![20u8; 16]);
let mut s = Squeezer::new(true);
// just initialized
assert_eq!(s.action(), SqueezeAction::Ignore);
s.advance();
let exp = vec![
SqueezeAction::Ignore, // print as is
SqueezeAction::Ignore, // print as is
SqueezeAction::Ignore, // print as is
SqueezeAction::Print, // print '*' char
];
let mut line = 0;
let mut idx = 1;
for z in v.chunks(LSIZE) {
for i in z {
s.process(*i, idx);
idx += 1;
}
assert_eq!(s.action(), exp[line]);
s.advance();
line += 1;
}
}
#[test]
fn first_char_diff() {
// see issue #62
let mut v = vec![];
v.extend(vec![20u8; 16]);
v.push(61);
v.extend(vec![20u8; 15]);
v.extend(vec![20u8; 16]);
let mut s = Squeezer::new(true);
// just initialized
assert_eq!(s.action(), SqueezeAction::Ignore);
s.advance();
let exp = vec![
SqueezeAction::Ignore, // print as is
SqueezeAction::Ignore, // print as is
SqueezeAction::Ignore, // print as is
];
let mut line = 0;
let mut idx = 1;
for z in v.chunks(LSIZE) {
for i in z {
s.process(*i, idx);
idx += 1;
}
assert_eq!(s.action(), exp[line]);
s.advance();
line += 1;
}
}
}
+156
View File
@@ -0,0 +1,156 @@
use super::*;
#[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());
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]
fn test_parse_byte_offset() {
use ByteOffsetParseError::*;
macro_rules! success {
($input: expr, $expected_kind: ident $expected_value: expr) => {
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!(
parse_byte_offset($input, PositiveI64::new($block_size).unwrap()),
Ok(
ByteOffset {
value: NonNegativeI64::new($expected_value).unwrap(),
kind: ByteOffsetKind::$expected_kind,
}
),
);
};
}
macro_rules! error {
($input: expr, $expected_err: expr) => {
assert_eq!(
parse_byte_offset($input, PositiveI64::new(DEFAULT_BLOCK_SIZE).unwrap()),
Err($expected_err),
);
};
}
success!("0", ForwardFromBeginning 0);
success!("1", ForwardFromBeginning 1);
success!("1", ForwardFromBeginning 1);
success!("100", ForwardFromBeginning 100);
success!("+100", ForwardFromLastOffset 100);
success!("0x0", ForwardFromBeginning 0);
success!("0xf", ForwardFromBeginning 15);
success!("0xdeadbeef", ForwardFromBeginning 3_735_928_559);
success!("1KB", ForwardFromBeginning 1000);
success!("2MB", ForwardFromBeginning 2000000);
success!("3GB", ForwardFromBeginning 3000000000);
success!("4TB", ForwardFromBeginning 4000000000000);
success!("+4TB", ForwardFromLastOffset 4000000000000);
success!("1GiB", ForwardFromBeginning 1073741824);
success!("2TiB", ForwardFromBeginning 2199023255552);
success!("+2TiB", ForwardFromLastOffset 2199023255552);
success!("0xff", ForwardFromBeginning 255);
success!("0xEE", ForwardFromBeginning 238);
success!("+0xFF", ForwardFromLastOffset 255);
success!("1block", ForwardFromBeginning 512; block_size: 512);
success!("2block", ForwardFromBeginning 1024; block_size: 512);
success!("1block", ForwardFromBeginning 4; block_size: 4);
success!("2block", ForwardFromBeginning 8; block_size: 4);
// empty string is invalid
error!("", Empty);
// These are also bad.
error!("+", EmptyAfterSign);
error!("-", EmptyAfterSign);
error!("K", InvalidNumAndUnit("K".to_owned()));
error!("k", InvalidNumAndUnit("k".to_owned()));
error!("m", InvalidNumAndUnit("m".to_owned()));
error!("block", EmptyWithUnit("block".to_owned()));
// leading/trailing space is invalid
error!(" 0", InvalidNumAndUnit(" 0".to_owned()));
error!("0 ", InvalidUnit(" ".to_owned()));
// Signs after the hex prefix make no sense
error!("0x-12", SignFoundAfterHexPrefix('-'));
// This was previously accepted but shouldn't be.
error!("0x+12", SignFoundAfterHexPrefix('+'));
// invalid suffix
error!("1234asdf", InvalidUnit("asdf".to_owned()));
// bad numbers
error!("asdf1234", InvalidNumAndUnit("asdf1234".to_owned()));
error!("a1s2d3f4", InvalidNumAndUnit("a1s2d3f4".to_owned()));
// multiplication overflows u64
error!("20000000TiB", UnitMultiplicationOverflow);
assert!(
match parse_byte_offset("99999999999999999999", PositiveI64::new(512).unwrap()) {
// We can't check against the kind of the `ParseIntError`, so we'll just make sure it's the
// same as trying to do the parse directly.
Err(ParseNum(e)) => e == "99999999999999999999".parse::<i64>().unwrap_err(),
_ => false,
}
);
}
+1
View File
@@ -0,0 +1 @@
ascii text eol=lf
+1
View File
@@ -0,0 +1 @@
0123456789abcde
View File
Whitespace-only changes.
BIN
View File
Binary file not shown.
+964
View File
@@ -0,0 +1,964 @@
use assert_cmd::Command;
fn hexyl() -> Command {
let mut cmd = Command::new(assert_cmd::cargo_bin!("hexyl"));
cmd.current_dir("tests/examples");
cmd
}
trait PrettyAssert<S>
where
S: AsRef<str>,
{
fn pretty_stdout(self, other: S);
}
// https://github.com/assert-rs/assert_cmd/issues/121#issuecomment-849937376
//
impl<S> PrettyAssert<S> for assert_cmd::assert::Assert
where
S: AsRef<str>,
{
fn pretty_stdout(self, other: S) {
println!("{}", other.as_ref().len());
let self_str = String::from_utf8(self.get_output().stdout.clone()).unwrap();
println!("{}", self_str.len());
pretty_assertions::assert_eq!(self_str, other.as_ref());
}
}
mod basic {
use super::hexyl;
#[test]
fn can_print_simple_ascii_file() {
hexyl()
.arg("ascii")
.arg("--color=never")
.assert()
.success()
.stdout(
"┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐\n\
│00000000│ 30 31 32 33 34 35 36 37 ┊ 38 39 61 62 63 64 65 0a │01234567┊89abcde_│\n\
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘\n",
);
}
#[test]
fn can_read_input_from_stdin() {
hexyl()
.arg("--color=never")
.write_stdin("abc")
.assert()
.success()
.stdout(
"┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐\n\
│00000000│ 61 62 63 ┊ │abc ┊ │\n\
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘\n",
);
}
#[test]
fn fails_on_non_existing_input() {
hexyl().arg("non-existing").assert().failure();
}
#[test]
fn prints_warning_on_empty_content() {
hexyl()
.arg("empty")
.arg("--color=never")
.assert()
.success()
.stdout(
"┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐\n\
│ │ No content │ │ │ │\n\
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘\n",
);
}
}
mod length {
use super::hexyl;
#[test]
fn length_restricts_output_size() {
hexyl()
.arg("hello_world_elf64")
.arg("--color=never")
.arg("--length=32")
.assert()
.success()
.stdout(
"┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐\n\
│00000000│ 7f 45 4c 46 02 01 01 00 ┊ 00 00 00 00 00 00 00 00 │•ELF•••⋄┊⋄⋄⋄⋄⋄⋄⋄⋄│\n\
│00000010│ 02 00 3e 00 01 00 00 00 ┊ 00 10 40 00 00 00 00 00 │•⋄>⋄•⋄⋄⋄┊⋄•@⋄⋄⋄⋄⋄│\n\
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘\n",
);
}
#[test]
fn fail_if_length_and_bytes_options_are_used_simultaneously() {
hexyl()
.arg("hello_world_elf64")
.arg("--length=32")
.arg("--bytes=10")
.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 {
use super::hexyl;
#[test]
fn basic() {
hexyl()
.arg("ascii")
.arg("--color=never")
.arg("--skip=2")
.arg("--length=4")
.assert()
.success()
.stdout(
"┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐\n\
│00000002│ 32 33 34 35 ┊ │2345 ┊ │\n\
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘\n",
);
}
#[test]
fn prints_warning_when_skipping_past_the_end() {
hexyl()
.arg("ascii")
.arg("--color=never")
.arg("--skip=1000")
.assert()
.success()
.stdout(
"┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐\n\
│ │ No content │ │ │ │\n\
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘\n",
);
}
#[test]
fn negative_offset() {
hexyl()
.arg("ascii")
.arg("--color=never")
.arg("--skip=-4")
.arg("--length=3")
.assert()
.success()
.stdout(
"┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐\n\
│0000000c│ 63 64 65 ┊ │cde ┊ │\n\
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘\n",
);
}
#[test]
fn fails_if_negative_offset_is_too_large() {
hexyl()
.arg("ascii")
.arg("--color=never")
.arg("--skip=-1MiB")
.assert()
.failure()
.stderr(predicates::str::contains("Failed to jump"));
}
}
mod display_offset {
use super::hexyl;
#[test]
fn basic() {
hexyl()
.arg("ascii")
.arg("--color=never")
.arg("--display-offset=0xc0ffee")
.assert()
.success()
.stdout(
"┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐\n\
│00c0ffee│ 30 31 32 33 34 35 36 37 ┊ 38 39 61 62 63 64 65 0a │01234567┊89abcde_│\n\
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘\n",
);
}
#[test]
fn display_offset_and_skip() {
hexyl()
.arg("hello_world_elf64")
.arg("--color=never")
.arg("--display-offset=0x20")
.arg("--skip=0x10")
.arg("--length=0x10")
.assert()
.success()
.stdout(
"┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐\n\
│00000030│ 02 00 3e 00 01 00 00 00 ┊ 00 10 40 00 00 00 00 00 │•⋄>⋄•⋄⋄⋄┊⋄•@⋄⋄⋄⋄⋄│\n\
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘\n",
);
}
}
mod blocksize {
use super::hexyl;
#[test]
fn fails_for_zero_or_negative_blocksize() {
hexyl()
.arg("ascii")
.arg("--block-size=0")
.assert()
.failure();
hexyl()
.arg("ascii")
.arg("--block-size=-16")
.assert()
.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",
);
}
}
mod group_and_endianness {
use super::hexyl;
use super::PrettyAssert;
#[test]
fn group_2_bytes_be() {
hexyl()
.arg("ascii")
.arg("--color=never")
.arg("--group-size=2")
.assert()
.success()
.stdout(
"┌────────┬─────────────────────┬─────────────────────┬────────┬────────┐\n\
│00000000│ 3031 3233 3435 3637 ┊ 3839 6162 6364 650a │01234567┊89abcde_│\n\
└────────┴─────────────────────┴─────────────────────┴────────┴────────┘\n",
);
}
#[test]
fn group_2_bytes_le() {
hexyl()
.arg("ascii")
.arg("--color=never")
.arg("--group-size=2")
.arg("--endianness=little")
.assert()
.success()
.stdout(
"┌────────┬─────────────────────┬─────────────────────┬────────┬────────┐\n\
│00000000│ 3130 3332 3534 3736 ┊ 3938 6261 6463 0a65 │01234567┊89abcde_│\n\
└────────┴─────────────────────┴─────────────────────┴────────┴────────┘\n",
);
}
#[test]
fn group_4_bytes_be() {
hexyl()
.arg("ascii")
.arg("--color=never")
.arg("--group-size=4")
.assert()
.success()
.stdout(
"┌────────┬───────────────────┬───────────────────┬────────┬────────┐\n\
│00000000│ 30313233 34353637 ┊ 38396162 6364650a │01234567┊89abcde_│\n\
└────────┴───────────────────┴───────────────────┴────────┴────────┘\n",
);
}
#[test]
fn group_4_bytes_le() {
hexyl()
.arg("ascii")
.arg("--color=never")
.arg("--group-size=4")
.arg("--endianness=little")
.assert()
.success()
.stdout(
"┌────────┬───────────────────┬───────────────────┬────────┬────────┐\n\
│00000000│ 33323130 37363534 ┊ 62613938 0a656463 │01234567┊89abcde_│\n\
└────────┴───────────────────┴───────────────────┴────────┴────────┘\n",
);
}
#[test]
fn group_8_bytes_be() {
hexyl()
.arg("ascii")
.arg("--color=never")
.arg("--group-size=8")
.assert()
.success()
.stdout(
"┌────────┬──────────────────┬──────────────────┬────────┬────────┐\n\
│00000000│ 3031323334353637 ┊ 383961626364650a │01234567┊89abcde_│\n\
└────────┴──────────────────┴──────────────────┴────────┴────────┘\n",
);
}
#[test]
fn group_8_bytes_le() {
hexyl()
.arg("ascii")
.arg("--color=never")
.arg("--group-size=8")
.arg("--endianness=little")
.assert()
.success()
.stdout(
"┌────────┬──────────────────┬──────────────────┬────────┬────────┐\n\
│00000000│ 3736353433323130 ┊ 0a65646362613938 │01234567┊89abcde_│\n\
└────────┴──────────────────┴──────────────────┴────────┴────────┘\n",
);
}
#[test]
fn group_size_plain() {
hexyl()
.arg("ascii")
.arg("--color=never")
.arg("--plain")
.arg("--group-size=2")
.assert()
.success()
.stdout(" 3031 3233 3435 3637 3839 6162 6364 650a \n");
}
#[test]
fn group_size_fill_space() {
hexyl()
.arg("--color=never")
.arg("--group-size=2")
.write_stdin("abc")
.assert()
.success()
.stdout(
"┌────────┬─────────────────────┬─────────────────────┬────────┬────────┐\n\
│00000000│ 6162 63 ┊ │abc ┊ │\n\
└────────┴─────────────────────┴─────────────────────┴────────┴────────┘\n",
);
}
#[test]
fn group_size_invalid() {
hexyl()
.arg("ascii")
.arg("--color=never")
.arg("--plain")
.arg("--group-size=3")
.assert()
.failure();
}
#[test]
fn squeeze_no_chars() {
hexyl()
.arg("hello_world_elf64")
.arg("--color=never")
.arg("--skip=1024")
.arg("--length=4096")
.arg("--no-characters")
.assert()
.success()
.pretty_stdout(
"\
┌────────┬─────────────────────────┬─────────────────────────┐
│00000400│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │
│* │ ┊ │
│00001000│ ba 0e 00 00 00 b9 00 20 ┊ 40 00 bb 01 00 00 00 b8 │
│00001010│ 04 00 00 00 cd 80 b8 01 ┊ 00 00 00 cd 80 00 00 00 │
│00001020│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │
│* │ ┊ │
│00001400│ ┊ │
└────────┴─────────────────────────┴─────────────────────────┘
",
);
}
#[test]
fn squeeze_no_chars_one_panel() {
hexyl()
.arg("hello_world_elf64")
.arg("--color=never")
.arg("--skip=1024")
.arg("--length=4096")
.arg("--no-characters")
.arg("--panels=1")
.assert()
.success()
.pretty_stdout(
"\
┌────────┬─────────────────────────┐
│00000400│ 00 00 00 00 00 00 00 00 │
│* │ │
│00001000│ ba 0e 00 00 00 b9 00 20 │
│00001008│ 40 00 bb 01 00 00 00 b8 │
│00001010│ 04 00 00 00 cd 80 b8 01 │
│00001018│ 00 00 00 cd 80 00 00 00 │
│00001020│ 00 00 00 00 00 00 00 00 │
│* │ │
│00001400│ │
└────────┴─────────────────────────┘
",
);
}
#[test]
fn squeeze_no_position() {
hexyl()
.arg("hello_world_elf64")
.arg("--color=never")
.arg("--skip=1024")
.arg("--length=4096")
.arg("--no-position")
.assert()
.success()
.pretty_stdout(
"\
┌─────────────────────────┬─────────────────────────┬────────┬────────┐
│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │⋄⋄⋄⋄⋄⋄⋄⋄┊⋄⋄⋄⋄⋄⋄⋄⋄│
│* ┊ │ ┊ │
│ ba 0e 00 00 00 b9 00 20 ┊ 40 00 bb 01 00 00 00 b8 │ו⋄⋄⋄×⋄ ┊@⋄ו⋄⋄⋄×│
│ 04 00 00 00 cd 80 b8 01 ┊ 00 00 00 cd 80 00 00 00 │•⋄⋄⋄××ו┊⋄⋄⋄××⋄⋄⋄│
│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │⋄⋄⋄⋄⋄⋄⋄⋄┊⋄⋄⋄⋄⋄⋄⋄⋄│
│* ┊ │ ┊ │
│* ┊ │ ┊ │
└─────────────────────────┴─────────────────────────┴────────┴────────┘
",
);
}
#[test]
fn squeeze_no_position_one_panel() {
hexyl()
.arg("hello_world_elf64")
.arg("--color=never")
.arg("--skip=1024")
.arg("--length=4096")
.arg("--no-position")
.arg("--panels=1")
.assert()
.success()
.pretty_stdout(
"\
┌─────────────────────────┬────────┐
│ 00 00 00 00 00 00 00 00 │⋄⋄⋄⋄⋄⋄⋄⋄│
│* │ │
│ ba 0e 00 00 00 b9 00 20 │ו⋄⋄⋄×⋄ │
│ 40 00 bb 01 00 00 00 b8 │@⋄ו⋄⋄⋄×│
│ 04 00 00 00 cd 80 b8 01 │•⋄⋄⋄××ו│
│ 00 00 00 cd 80 00 00 00 │⋄⋄⋄××⋄⋄⋄│
│ 00 00 00 00 00 00 00 00 │⋄⋄⋄⋄⋄⋄⋄⋄│
│* │ │
│* │ │
└─────────────────────────┴────────┘
",
);
}
#[test]
fn squeeze_odd_panels_remainder_bytes() {
hexyl()
.arg("hello_world_elf64")
.arg("--color=never")
.arg("--skip=1024")
.arg("--length=4092") // 4 byte remainder
.arg("--panels=3")
.assert()
.success()
.pretty_stdout(
"\
┌────────┬─────────────────────────┬─────────────────────────┬─────────────────────────┬────────┬────────┬────────┐
│00000400│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │⋄⋄⋄⋄⋄⋄⋄⋄┊⋄⋄⋄⋄⋄⋄⋄⋄┊⋄⋄⋄⋄⋄⋄⋄⋄│
│* │ ┊ ┊ │ ┊ ┊ │
│00001000│ ba 0e 00 00 00 b9 00 20 ┊ 40 00 bb 01 00 00 00 b8 ┊ 04 00 00 00 cd 80 b8 01 │ו⋄⋄⋄×⋄ ┊@⋄ו⋄⋄⋄×┊•⋄⋄⋄××ו│
│00001018│ 00 00 00 cd 80 00 00 00 ┊ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │⋄⋄⋄××⋄⋄⋄┊⋄⋄⋄⋄⋄⋄⋄⋄┊⋄⋄⋄⋄⋄⋄⋄⋄│
│00001030│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │⋄⋄⋄⋄⋄⋄⋄⋄┊⋄⋄⋄⋄⋄⋄⋄⋄┊⋄⋄⋄⋄⋄⋄⋄⋄│
│* │ ┊ ┊ │ ┊ ┊ │
│000013f0│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 ┊ │⋄⋄⋄⋄⋄⋄⋄⋄┊⋄⋄⋄⋄ ┊ │
└────────┴─────────────────────────┴─────────────────────────┴─────────────────────────┴────────┴────────┴────────┘
",
);
}
#[test]
fn squeeze_plain() {
hexyl()
.arg("hello_world_elf64")
.arg("--color=never")
.arg("--skip=1024")
.arg("--length=4096")
.arg("--plain")
.assert()
.success()
.pretty_stdout(
" \
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
*
ba 0e 00 00 00 b9 00 20 40 00 bb 01 00 00 00 b8
04 00 00 00 cd 80 b8 01 00 00 00 cd 80 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
*
*
",
);
}
#[test]
fn squeeze_plain_remainder() {
hexyl()
.arg("hello_world_elf64")
.arg("--color=never")
.arg("--skip=1024")
.arg("--length=4092") // 4 byte remainder
.arg("--plain")
.assert()
.success()
.pretty_stdout(
" \
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
*
ba 0e 00 00 00 b9 00 20 40 00 bb 01 00 00 00 b8
04 00 00 00 cd 80 b8 01 00 00 00 cd 80 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
*
00 00 00 00 00 00 00 00 00 00 00 00
",
);
}
}
mod base {
use super::hexyl;
use super::PrettyAssert;
#[test]
fn base2() {
hexyl()
.arg("ascii")
.arg("--plain")
.arg("--base=binary")
.assert()
.success()
.pretty_stdout(
" 00110000 00110001 00110010 00110011 00110100 00110101 00110110 00110111 \n \
00111000 00111001 01100001 01100010 01100011 01100100 01100101 00001010 \n",
);
}
}
mod character_table {
use super::hexyl;
use super::PrettyAssert;
#[test]
fn ascii() {
hexyl()
.arg("hello_world_elf64")
.arg("--color=never")
.arg("--character-table=ascii")
.assert()
.success()
.pretty_stdout(
"┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐
│00000000│ 7f 45 4c 46 02 01 01 00 ┊ 00 00 00 00 00 00 00 00 │.ELF....┊........│
│00000010│ 02 00 3e 00 01 00 00 00 ┊ 00 10 40 00 00 00 00 00 │..>.....┊..@.....│
│00000020│ 40 00 00 00 00 00 00 00 ┊ 28 20 00 00 00 00 00 00 │@.......┊( ......│
│00000030│ 00 00 00 00 40 00 38 00 ┊ 03 00 40 00 04 00 03 00 │....@.8.┊..@.....│
│00000040│ 01 00 00 00 04 00 00 00 ┊ 00 00 00 00 00 00 00 00 │........┊........│
│00000050│ 00 00 40 00 00 00 00 00 ┊ 00 00 40 00 00 00 00 00 │..@.....┊..@.....│
│00000060│ e8 00 00 00 00 00 00 00 ┊ e8 00 00 00 00 00 00 00 │........┊........│
│00000070│ 00 10 00 00 00 00 00 00 ┊ 01 00 00 00 05 00 00 00 │........┊........│
│00000080│ 00 10 00 00 00 00 00 00 ┊ 00 10 40 00 00 00 00 00 │........┊..@.....│
│00000090│ 00 10 40 00 00 00 00 00 ┊ 1d 00 00 00 00 00 00 00 │..@.....┊........│
│000000a0│ 1d 00 00 00 00 00 00 00 ┊ 00 10 00 00 00 00 00 00 │........┊........│
│000000b0│ 01 00 00 00 06 00 00 00 ┊ 00 20 00 00 00 00 00 00 │........┊. ......│
│000000c0│ 00 20 40 00 00 00 00 00 ┊ 00 20 40 00 00 00 00 00 │. @.....┊. @.....│
│000000d0│ 0e 00 00 00 00 00 00 00 ┊ 0e 00 00 00 00 00 00 00 │........┊........│
│000000e0│ 00 10 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │........┊........│
│000000f0│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │........┊........│
│* │ ┊ │ ┊ │
│00001000│ ba 0e 00 00 00 b9 00 20 ┊ 40 00 bb 01 00 00 00 b8 │....... ┊@.......│
│00001010│ 04 00 00 00 cd 80 b8 01 ┊ 00 00 00 cd 80 00 00 00 │........┊........│
│00001020│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │........┊........│
│* │ ┊ │ ┊ │
│00002000│ 48 65 6c 6c 6f 2c 20 77 ┊ 6f 72 6c 64 21 0a 00 2e │Hello, w┊orld!...│
│00002010│ 73 68 73 74 72 74 61 62 ┊ 00 2e 74 65 78 74 00 2e │shstrtab┊..text..│
│00002020│ 64 61 74 61 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │data....┊........│
│00002030│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │........┊........│
│* │ ┊ │ ┊ │
│00002060│ 00 00 00 00 00 00 00 00 ┊ 0b 00 00 00 01 00 00 00 │........┊........│
│00002070│ 06 00 00 00 00 00 00 00 ┊ 00 10 40 00 00 00 00 00 │........┊..@.....│
│00002080│ 00 10 00 00 00 00 00 00 ┊ 1d 00 00 00 00 00 00 00 │........┊........│
│00002090│ 00 00 00 00 00 00 00 00 ┊ 10 00 00 00 00 00 00 00 │........┊........│
│000020a0│ 00 00 00 00 00 00 00 00 ┊ 11 00 00 00 01 00 00 00 │........┊........│
│000020b0│ 03 00 00 00 00 00 00 00 ┊ 00 20 40 00 00 00 00 00 │........┊. @.....│
│000020c0│ 00 20 00 00 00 00 00 00 ┊ 0e 00 00 00 00 00 00 00 │. ......┊........│
│000020d0│ 00 00 00 00 00 00 00 00 ┊ 04 00 00 00 00 00 00 00 │........┊........│
│000020e0│ 00 00 00 00 00 00 00 00 ┊ 01 00 00 00 03 00 00 00 │........┊........│
│000020f0│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │........┊........│
│00002100│ 0e 20 00 00 00 00 00 00 ┊ 17 00 00 00 00 00 00 00 │. ......┊........│
│00002110│ 00 00 00 00 00 00 00 00 ┊ 01 00 00 00 00 00 00 00 │........┊........│
│00002120│ 00 00 00 00 00 00 00 00 ┊ │........┊ │
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘
",
);
}
#[test]
fn codepage_437() {
hexyl()
.arg("hello_world_elf64")
.arg("--color=never")
.arg("--character-table=codepage-437")
.assert()
.success()
.pretty_stdout(
"┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐
│00000000│ 7f 45 4c 46 02 01 01 00 ┊ 00 00 00 00 00 00 00 00 │⌂ELF☻☺☺⋄┊⋄⋄⋄⋄⋄⋄⋄⋄│
│00000010│ 02 00 3e 00 01 00 00 00 ┊ 00 10 40 00 00 00 00 00 │☻⋄>⋄☺⋄⋄⋄┊⋄►@⋄⋄⋄⋄⋄│
│00000020│ 40 00 00 00 00 00 00 00 ┊ 28 20 00 00 00 00 00 00 │@⋄⋄⋄⋄⋄⋄⋄┊( ⋄⋄⋄⋄⋄⋄│
│00000030│ 00 00 00 00 40 00 38 00 ┊ 03 00 40 00 04 00 03 00 │⋄⋄⋄⋄@⋄8⋄┊♥⋄@⋄♦⋄♥⋄│
│00000040│ 01 00 00 00 04 00 00 00 ┊ 00 00 00 00 00 00 00 00 │☺⋄⋄⋄♦⋄⋄⋄┊⋄⋄⋄⋄⋄⋄⋄⋄│
│00000050│ 00 00 40 00 00 00 00 00 ┊ 00 00 40 00 00 00 00 00 │⋄⋄@⋄⋄⋄⋄⋄┊⋄⋄@⋄⋄⋄⋄⋄│
│00000060│ e8 00 00 00 00 00 00 00 ┊ e8 00 00 00 00 00 00 00 │Φ⋄⋄⋄⋄⋄⋄⋄┊Φ⋄⋄⋄⋄⋄⋄⋄│
│00000070│ 00 10 00 00 00 00 00 00 ┊ 01 00 00 00 05 00 00 00 │⋄►⋄⋄⋄⋄⋄⋄┊☺⋄⋄⋄♣⋄⋄⋄│
│00000080│ 00 10 00 00 00 00 00 00 ┊ 00 10 40 00 00 00 00 00 │⋄►⋄⋄⋄⋄⋄⋄┊⋄►@⋄⋄⋄⋄⋄│
│00000090│ 00 10 40 00 00 00 00 00 ┊ 1d 00 00 00 00 00 00 00 │⋄►@⋄⋄⋄⋄⋄┊↔⋄⋄⋄⋄⋄⋄⋄│
│000000a0│ 1d 00 00 00 00 00 00 00 ┊ 00 10 00 00 00 00 00 00 │↔⋄⋄⋄⋄⋄⋄⋄┊⋄►⋄⋄⋄⋄⋄⋄│
│000000b0│ 01 00 00 00 06 00 00 00 ┊ 00 20 00 00 00 00 00 00 │☺⋄⋄⋄♠⋄⋄⋄┊⋄ ⋄⋄⋄⋄⋄⋄│
│000000c0│ 00 20 40 00 00 00 00 00 ┊ 00 20 40 00 00 00 00 00 │⋄ @⋄⋄⋄⋄⋄┊⋄ @⋄⋄⋄⋄⋄│
│000000d0│ 0e 00 00 00 00 00 00 00 ┊ 0e 00 00 00 00 00 00 00 │♫⋄⋄⋄⋄⋄⋄⋄┊♫⋄⋄⋄⋄⋄⋄⋄│
│000000e0│ 00 10 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │⋄►⋄⋄⋄⋄⋄⋄┊⋄⋄⋄⋄⋄⋄⋄⋄│
│000000f0│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │⋄⋄⋄⋄⋄⋄⋄⋄┊⋄⋄⋄⋄⋄⋄⋄⋄│
│* │ ┊ │ ┊ │
│00001000│ ba 0e 00 00 00 b9 00 20 ┊ 40 00 bb 01 00 00 00 b8 │║♫⋄⋄⋄╣⋄ ┊@⋄╗☺⋄⋄⋄╕│
│00001010│ 04 00 00 00 cd 80 b8 01 ┊ 00 00 00 cd 80 00 00 00 │♦⋄⋄⋄═Ç╕☺┊⋄⋄⋄═Ç⋄⋄⋄│
│00001020│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │⋄⋄⋄⋄⋄⋄⋄⋄┊⋄⋄⋄⋄⋄⋄⋄⋄│
│* │ ┊ │ ┊ │
│00002000│ 48 65 6c 6c 6f 2c 20 77 ┊ 6f 72 6c 64 21 0a 00 2e │Hello, w┊orld!◙⋄.│
│00002010│ 73 68 73 74 72 74 61 62 ┊ 00 2e 74 65 78 74 00 2e │shstrtab┊⋄.text⋄.│
│00002020│ 64 61 74 61 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │data⋄⋄⋄⋄┊⋄⋄⋄⋄⋄⋄⋄⋄│
│00002030│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │⋄⋄⋄⋄⋄⋄⋄⋄┊⋄⋄⋄⋄⋄⋄⋄⋄│
│* │ ┊ │ ┊ │
│00002060│ 00 00 00 00 00 00 00 00 ┊ 0b 00 00 00 01 00 00 00 │⋄⋄⋄⋄⋄⋄⋄⋄┊♂⋄⋄⋄☺⋄⋄⋄│
│00002070│ 06 00 00 00 00 00 00 00 ┊ 00 10 40 00 00 00 00 00 │♠⋄⋄⋄⋄⋄⋄⋄┊⋄►@⋄⋄⋄⋄⋄│
│00002080│ 00 10 00 00 00 00 00 00 ┊ 1d 00 00 00 00 00 00 00 │⋄►⋄⋄⋄⋄⋄⋄┊↔⋄⋄⋄⋄⋄⋄⋄│
│00002090│ 00 00 00 00 00 00 00 00 ┊ 10 00 00 00 00 00 00 00 │⋄⋄⋄⋄⋄⋄⋄⋄┊►⋄⋄⋄⋄⋄⋄⋄│
│000020a0│ 00 00 00 00 00 00 00 00 ┊ 11 00 00 00 01 00 00 00 │⋄⋄⋄⋄⋄⋄⋄⋄┊◄⋄⋄⋄☺⋄⋄⋄│
│000020b0│ 03 00 00 00 00 00 00 00 ┊ 00 20 40 00 00 00 00 00 │♥⋄⋄⋄⋄⋄⋄⋄┊⋄ @⋄⋄⋄⋄⋄│
│000020c0│ 00 20 00 00 00 00 00 00 ┊ 0e 00 00 00 00 00 00 00 │⋄ ⋄⋄⋄⋄⋄⋄┊♫⋄⋄⋄⋄⋄⋄⋄│
│000020d0│ 00 00 00 00 00 00 00 00 ┊ 04 00 00 00 00 00 00 00 │⋄⋄⋄⋄⋄⋄⋄⋄┊♦⋄⋄⋄⋄⋄⋄⋄│
│000020e0│ 00 00 00 00 00 00 00 00 ┊ 01 00 00 00 03 00 00 00 │⋄⋄⋄⋄⋄⋄⋄⋄┊☺⋄⋄⋄♥⋄⋄⋄│
│000020f0│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │⋄⋄⋄⋄⋄⋄⋄⋄┊⋄⋄⋄⋄⋄⋄⋄⋄│
│00002100│ 0e 20 00 00 00 00 00 00 ┊ 17 00 00 00 00 00 00 00 │♫ ⋄⋄⋄⋄⋄⋄┊↨⋄⋄⋄⋄⋄⋄⋄│
│00002110│ 00 00 00 00 00 00 00 00 ┊ 01 00 00 00 00 00 00 00 │⋄⋄⋄⋄⋄⋄⋄⋄┊☺⋄⋄⋄⋄⋄⋄⋄│
│00002120│ 00 00 00 00 00 00 00 00 ┊ │⋄⋄⋄⋄⋄⋄⋄⋄┊ │
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘
",
);
}
#[test]
fn codepage_1047() {
hexyl()
.arg("hello_world_elf64")
.arg("--color=never")
.arg("--character-table=codepage-1047")
.assert()
.success()
.pretty_stdout(
"┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐
│00000000│ 7f 45 4c 46 02 01 01 00 ┊ 00 00 00 00 00 00 00 00 │..<.....┊........│
│00000010│ 02 00 3e 00 01 00 00 00 ┊ 00 10 40 00 00 00 00 00 │........┊.. .....│
│00000020│ 40 00 00 00 00 00 00 00 ┊ 28 20 00 00 00 00 00 00 │ .......┊........│
│00000030│ 00 00 00 00 40 00 38 00 ┊ 03 00 40 00 04 00 03 00 │.... ...┊.. .....│
│00000040│ 01 00 00 00 04 00 00 00 ┊ 00 00 00 00 00 00 00 00 │........┊........│
│00000050│ 00 00 40 00 00 00 00 00 ┊ 00 00 40 00 00 00 00 00 │.. .....┊.. .....│
│00000060│ e8 00 00 00 00 00 00 00 ┊ e8 00 00 00 00 00 00 00 │Y.......┊Y.......│
│00000070│ 00 10 00 00 00 00 00 00 ┊ 01 00 00 00 05 00 00 00 │........┊........│
│00000080│ 00 10 00 00 00 00 00 00 ┊ 00 10 40 00 00 00 00 00 │........┊.. .....│
│00000090│ 00 10 40 00 00 00 00 00 ┊ 1d 00 00 00 00 00 00 00 │.. .....┊........│
│000000a0│ 1d 00 00 00 00 00 00 00 ┊ 00 10 00 00 00 00 00 00 │........┊........│
│000000b0│ 01 00 00 00 06 00 00 00 ┊ 00 20 00 00 00 00 00 00 │........┊........│
│000000c0│ 00 20 40 00 00 00 00 00 ┊ 00 20 40 00 00 00 00 00 │.. .....┊.. .....│
│000000d0│ 0e 00 00 00 00 00 00 00 ┊ 0e 00 00 00 00 00 00 00 │........┊........│
│000000e0│ 00 10 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │........┊........│
│000000f0│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │........┊........│
│* │ ┊ │ ┊ │
│00001000│ ba 0e 00 00 00 b9 00 20 ┊ 40 00 bb 01 00 00 00 b8 │[.......┊ .].....│
│00001010│ 04 00 00 00 cd 80 b8 01 ┊ 00 00 00 cd 80 00 00 00 │........┊........│
│00001020│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │........┊........│
│* │ ┊ │ ┊ │
│00002000│ 48 65 6c 6c 6f 2c 20 77 ┊ 6f 72 6c 64 21 0a 00 2e │..%%?...┊?.%.....│
│00002010│ 73 68 73 74 72 74 61 62 ┊ 00 2e 74 65 78 74 00 2e │....../.┊........│
│00002020│ 64 61 74 61 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │././....┊........│
│00002030│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │........┊........│
│* │ ┊ │ ┊ │
│00002060│ 00 00 00 00 00 00 00 00 ┊ 0b 00 00 00 01 00 00 00 │........┊........│
│00002070│ 06 00 00 00 00 00 00 00 ┊ 00 10 40 00 00 00 00 00 │........┊.. .....│
│00002080│ 00 10 00 00 00 00 00 00 ┊ 1d 00 00 00 00 00 00 00 │........┊........│
│00002090│ 00 00 00 00 00 00 00 00 ┊ 10 00 00 00 00 00 00 00 │........┊........│
│000020a0│ 00 00 00 00 00 00 00 00 ┊ 11 00 00 00 01 00 00 00 │........┊........│
│000020b0│ 03 00 00 00 00 00 00 00 ┊ 00 20 40 00 00 00 00 00 │........┊.. .....│
│000020c0│ 00 20 00 00 00 00 00 00 ┊ 0e 00 00 00 00 00 00 00 │........┊........│
│000020d0│ 00 00 00 00 00 00 00 00 ┊ 04 00 00 00 00 00 00 00 │........┊........│
│000020e0│ 00 00 00 00 00 00 00 00 ┊ 01 00 00 00 03 00 00 00 │........┊........│
│000020f0│ 00 00 00 00 00 00 00 00 ┊ 00 00 00 00 00 00 00 00 │........┊........│
│00002100│ 0e 20 00 00 00 00 00 00 ┊ 17 00 00 00 00 00 00 00 │........┊........│
│00002110│ 00 00 00 00 00 00 00 00 ┊ 01 00 00 00 00 00 00 00 │........┊........│
│00002120│ 00 00 00 00 00 00 00 00 ┊ │........┊ │
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘
",
);
}
}
mod colors {
use super::hexyl;
use owo_colors::{colors, Color};
use std::collections::HashMap;
// This is a helper for testing color in output. Writing tests to expect
// raw color codes is ugly and hard to look at. Loading expected output
// from files works fine, but you end up with a lot of files for all the
// tests, and you have to cross-reference the file with the test that uses
// it. The files also suffer from the same problem of being hard to
// visually inspect. Just catting the file to see the colorized output
// loses the nuance of where exactly the color codes appear (before or
// after spaces, for example), or whether there are redundant codes.
//
// So this ColorMap solves the problem neatly by having two inputs:
// - the easy to read expected output in plain format without any colors
// - a mapping with identical structure except some characters replaced
// with single character color codes.
// This makes it easy to reference the output and expected colors side by
// side, and provides fairly precise control over exactly where color codes
// are expected (the only caveat being you can't have two color codes back
// to back). ColorMap combines these into the actual expected output.
//
// The color mapping needs to be identical to the expected output, except
// it has some chars replaced by color code stand ins. These are replaced
// with the actual color codes by the colorize method. The '.' character
// is also ignored (it doesn't need to match the input). This makes the
// color map more readable and avoids input characters from conflicting
// with color chars.
struct ColorMap {
text_map: &'static str,
char_to_color: HashMap<char, &'static str>,
}
impl ColorMap {
fn from(text_map: &'static str) -> Self {
ColorMap {
text_map,
char_to_color: HashMap::new(),
}
}
fn with<C: Color>(&mut self, c: char) -> &mut Self {
self.char_to_color.insert(c, C::ANSI_FG);
self
}
fn colorize(&self, input: &str) -> String {
let mut output = String::new();
let mut input_chars = input.chars();
for c in self.text_map.chars() {
let next_input = input_chars.next().expect("input and color map don't match");
if let Some(color) = self.char_to_color.get(&c) {
output.push_str(color);
} else if c != '.' {
// ignore '.' in the mapping for readability
assert_eq!(c, next_input, "input and color map don't match");
}
output.push(next_input);
}
output
}
}
#[test]
fn hex_colors() {
let input = b"He\x11\0 \xff\0\xdd";
let expected_text = "\
┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐\n\
│00000000│ 48 65 11 00 20 ff 00 dd ┊ │He•⋄ ×⋄×┊ │\n\
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘\n";
let expected = ColorMap::from(
"\
┌────────┬─────────────────────────┬─────────────────────────┬────────┬────────┐\n\
│r.......d y. .. b. c. g. m. c. m.d┊ d│y.bcgmcmd d\n\
└────────┴─────────────────────────┴─────────────────────────┴────────┴────────┘\n",
)
.with::<colors::Red>('r')
.with::<colors::Default>('d')
.with::<colors::Yellow>('y')
.with::<colors::Blue>('b')
.with::<colors::Green>('g')
.with::<colors::BrightMagenta>('m')
.with::<colors::CustomColor<0xab, 0xcd, 0xef>>('c')
.colorize(expected_text);
hexyl()
.write_stdin(input)
.arg("--color=always")
.env("HEXYL_COLOR_OFFSET", "red")
.env("HEXYL_COLOR_ASCII_PRINTABLE", "yellow")
.env("HEXYL_COLOR_ASCII_WHITESPACE", "green")
.env("HEXYL_COLOR_ASCII_OTHER", "blue")
.env("HEXYL_COLOR_NONASCII", "bright magenta")
.env("HEXYL_COLOR_NULL", "#abcdef")
.assert()
.success()
.stdout(expected);
}
#[test]
fn binary_colors() {
let input = b"He\x11\0 \xff\0\xdd";
let expected_text = "\
┌────────┬─────────────────────────────────────────────────────────────────────────┬────────┐\n\
│00000000│ 01001000 01100101 00010001 00000000 00100000 11111111 00000000 11011101 │He•⋄ ×⋄×│\n\
└────────┴─────────────────────────────────────────────────────────────────────────┴────────┘\n";
let expected = ColorMap::from(
"\
┌────────┬─────────────────────────────────────────────────────────────────────────┬────────┐\n\
│r.......d y....... ........ b....... c....... g....... m....... c....... m.......d│y.bcgmcmd\n\
└────────┴─────────────────────────────────────────────────────────────────────────┴────────┘\n"
)
.with::<colors::Red>('r')
.with::<colors::Default>('d')
.with::<colors::Yellow>('y')
.with::<colors::Blue>('b')
.with::<colors::Green>('g')
.with::<colors::BrightMagenta>('m')
.with::<colors::CustomColor<0xab, 0xcd, 0xef>>('c')
.colorize(expected_text);
hexyl()
.write_stdin(input)
.arg("--color=always")
.arg("--panels=1")
.arg("--base=binary")
.env("HEXYL_COLOR_OFFSET", "red")
.env("HEXYL_COLOR_ASCII_PRINTABLE", "yellow")
.env("HEXYL_COLOR_ASCII_WHITESPACE", "green")
.env("HEXYL_COLOR_ASCII_OTHER", "blue")
.env("HEXYL_COLOR_NONASCII", "bright magenta")
.env("HEXYL_COLOR_NULL", "#abcdef")
.assert()
.success()
.stdout(expected);
}
#[test]
fn groupsize_colors() {
let input = b"He\x11\0 \xff\0\xdd";
let expected_text = "\
┌────────┬─────────────────────┬────────┐\n\
│00000000│ 4865 1100 20ff 00dd │He•⋄ ×⋄×│\n\
└────────┴─────────────────────┴────────┘\n";
let expected = ColorMap::from(
"\
┌────────┬─────────────────────┬────────┐\n\
│r.......d y... b.c. g.m. c.m.d│y.bcgmcmd\n\
└────────┴─────────────────────┴────────┘\n",
)
.with::<colors::Red>('r')
.with::<colors::Default>('d')
.with::<colors::Yellow>('y')
.with::<colors::Blue>('b')
.with::<colors::Green>('g')
.with::<colors::BrightMagenta>('m')
.with::<colors::CustomColor<0xab, 0xcd, 0xef>>('c')
.colorize(expected_text);
hexyl()
.write_stdin(input)
.arg("--color=always")
.arg("--panels=1")
.arg("--groupsize=2")
.env("HEXYL_COLOR_OFFSET", "red")
.env("HEXYL_COLOR_ASCII_PRINTABLE", "yellow")
.env("HEXYL_COLOR_ASCII_WHITESPACE", "green")
.env("HEXYL_COLOR_ASCII_OTHER", "blue")
.env("HEXYL_COLOR_NONASCII", "bright magenta")
.env("HEXYL_COLOR_NULL", "#abcdef")
.assert()
.success()
.stdout(expected);
}
}