34 Commits
Author SHA1 Message Date
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
10 changed files with 432 additions and 269 deletions

No files matched your search

+112 -120
View File
@@ -1,8 +1,8 @@
name: CICD name: CICD
env: env:
MIN_SUPPORTED_RUST_VERSION: "1.60.0"
CICD_INTERMEDIATES_DIR: "_cicd-intermediates" CICD_INTERMEDIATES_DIR: "_cicd-intermediates"
MSRV_FEATURES: ""
on: on:
workflow_dispatch: workflow_dispatch:
@@ -14,84 +14,102 @@ on:
- '*' - '*'
jobs: 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-20.04
steps:
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt
- uses: actions/checkout@v3
- run: cargo fmt -- --check
min_version: min_version:
name: Minimum supported rust version name: Minimum supported rust version
runs-on: ubuntu-18.04 runs-on: ubuntu-20.04
needs: crate_metadata
steps: steps:
- name: Checkout source code - name: Checkout source code
uses: actions/checkout@v2 uses: actions/checkout@v3
- name: Install rust toolchain (v${{ env.MIN_SUPPORTED_RUST_VERSION }}) - name: Install rust toolchain (v${{ needs.crate_metadata.outputs.msrv }})
uses: actions-rs/toolchain@v1 uses: dtolnay/rust-toolchain@master
with: with:
toolchain: ${{ env.MIN_SUPPORTED_RUST_VERSION }} toolchain: ${{ needs.crate_metadata.outputs.msrv }}
default: true components: clippy
profile: minimal # minimal component installation (ie, no documentation)
components: clippy, rustfmt
- name: Ensure `cargo fmt` has been run
uses: actions-rs/cargo@v1
with:
command: fmt
args: -- --check
- name: Run clippy (on minimum supported rust version to prevent warnings we can't fix) - name: Run clippy (on minimum supported rust version to prevent warnings we can't fix)
uses: actions-rs/cargo@v1 run: cargo clippy --locked --all-targets ${{ env.MSRV_FEATURES }}
with:
command: clippy
args: --locked --all-targets
- name: Run tests - name: Run tests
uses: actions-rs/cargo@v1 run: cargo test --locked ${{ env.MSRV_FEATURES }}
with:
command: test
args: --locked
build: build:
name: ${{ matrix.job.os }} (${{ matrix.job.target }}) name: ${{ matrix.job.target }} (${{ matrix.job.os }})
runs-on: ${{ matrix.job.os }} runs-on: ${{ matrix.job.os }}
needs: crate_metadata
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
job: job:
- { os: ubuntu-18.04, target: arm-unknown-linux-gnueabihf , use-cross: true } - { target: aarch64-unknown-linux-gnu , os: ubuntu-20.04, use-cross: true }
- { os: ubuntu-18.04, target: aarch64-unknown-linux-gnu , use-cross: true } - { target: arm-unknown-linux-gnueabihf , os: ubuntu-20.04, use-cross: true }
- { os: ubuntu-18.04, target: i686-unknown-linux-gnu , use-cross: true } - { target: arm-unknown-linux-musleabihf, os: ubuntu-20.04, use-cross: true }
- { os: ubuntu-18.04, target: i686-unknown-linux-musl , use-cross: true } - { target: i686-pc-windows-msvc , os: windows-2019 }
- { os: ubuntu-18.04, target: x86_64-unknown-linux-gnu } - { target: i686-unknown-linux-gnu , os: ubuntu-20.04, use-cross: true }
- { os: ubuntu-18.04, target: x86_64-unknown-linux-musl , use-cross: true } - { target: i686-unknown-linux-musl , os: ubuntu-20.04, use-cross: true }
- { os: macos-10.15 , target: x86_64-apple-darwin } - { target: x86_64-apple-darwin , os: macos-12 }
# - { os: windows-2019, target: i686-pc-windows-gnu } ## disabled; error: linker `i686-w64-mingw32-gcc` not found - { target: x86_64-pc-windows-gnu , os: windows-2019 }
- { os: windows-2019, target: i686-pc-windows-msvc } - { target: x86_64-pc-windows-msvc , os: windows-2019 }
- { os: windows-2019, target: x86_64-pc-windows-gnu } - { target: x86_64-unknown-linux-gnu , os: ubuntu-20.04, use-cross: true }
- { os: windows-2019, target: x86_64-pc-windows-msvc } - { target: x86_64-unknown-linux-musl , os: ubuntu-20.04, use-cross: true }
env:
BUILD_CMD: cargo
steps: steps:
- name: Checkout source code - name: Checkout source code
uses: actions/checkout@v2 uses: actions/checkout@v3
- name: Install prerequisites - name: Install prerequisites
shell: bash shell: bash
run: | run: |
case ${{ matrix.job.target }} in case ${{ matrix.job.target }} in
arm-unknown-linux-gnueabihf) sudo apt-get -y update ; sudo apt-get -y install gcc-arm-linux-gnueabihf ;; 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 ;; aarch64-unknown-linux-gnu) sudo apt-get -y update ; sudo apt-get -y install gcc-aarch64-linux-gnu ;;
esac esac
- name: Extract crate information
shell: bash
run: |
echo "PROJECT_NAME=$(sed -n 's/^name = "\(.*\)"/\1/p' Cargo.toml | head -n1)" >> $GITHUB_ENV
echo "PROJECT_VERSION=$(sed -n 's/^version = "\(.*\)"/\1/p' Cargo.toml | head -n1)" >> $GITHUB_ENV
echo "PROJECT_MAINTAINER=$(sed -n 's/^authors = \["\(.*\)"\]/\1/p' Cargo.toml)" >> $GITHUB_ENV
echo "PROJECT_HOMEPAGE=$(sed -n 's/^homepage = "\(.*\)"/\1/p' Cargo.toml)" >> $GITHUB_ENV
- name: Install Rust toolchain - name: Install Rust toolchain
uses: actions-rs/toolchain@v1 uses: dtolnay/rust-toolchain@stable
with: with:
toolchain: stable targets: ${{ matrix.job.target }}
target: ${{ matrix.job.target }}
override: true - name: Install cross
profile: minimal # minimal component installation (ie, no documentation) 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) - name: Show version information (Rust, cargo, GCC)
shell: bash shell: bash
@@ -104,21 +122,16 @@ jobs:
rustc -V rustc -V
- name: Build - name: Build
uses: actions-rs/cargo@v1 shell: bash
with: run: $BUILD_CMD build --locked --release --target=${{ matrix.job.target }}
use-cross: ${{ matrix.job.use-cross }}
command: build
args: --release --target=${{ matrix.job.target }}
- name: Run example - name: Run example
uses: actions-rs/cargo@v1 if: ${{ !matrix.job.use-cross }}
with: shell: bash
use-cross: ${{ matrix.job.use-cross }} run: $BUILD_CMD run --release --target=${{ matrix.job.target }} --example=simple
command: run
args: --release --target=${{ matrix.job.target }} --example=simple
- name: Strip debug information from executable - name: Set binary name & path
id: strip id: bin
shell: bash shell: bash
run: | run: |
# Figure out suffix of binary # Figure out suffix of binary
@@ -127,31 +140,13 @@ jobs:
*-pc-windows-*) EXE_suffix=".exe" ;; *-pc-windows-*) EXE_suffix=".exe" ;;
esac; esac;
# Figure out what strip tool to use if any
STRIP="strip"
case ${{ matrix.job.target }} in
arm-unknown-linux-gnueabihf) STRIP="arm-linux-gnueabihf-strip" ;;
aarch64-unknown-linux-gnu) STRIP="aarch64-linux-gnu-strip" ;;
*-pc-windows-msvc) STRIP="" ;;
esac;
# Setup paths # Setup paths
BIN_DIR="${{ env.CICD_INTERMEDIATES_DIR }}/stripped-release-bin/" BIN_NAME="${{ needs.crate_metadata.outputs.name }}${EXE_suffix}"
mkdir -p "${BIN_DIR}" BIN_PATH="target/${{ matrix.job.target }}/release/${BIN_NAME}"
BIN_NAME="${{ env.PROJECT_NAME }}${EXE_suffix}"
BIN_PATH="${BIN_DIR}/${BIN_NAME}"
# Copy the release build binary to the result location # Let subsequent steps know where to find the binary
cp "target/${{ matrix.job.target }}/release/${BIN_NAME}" "${BIN_DIR}" echo "BIN_PATH=${BIN_PATH}" >> $GITHUB_OUTPUT
echo "BIN_NAME=${BIN_NAME}" >> $GITHUB_OUTPUT
# Also strip if possible
if [ -n "${STRIP}" ]; then
"${STRIP}" "${BIN_PATH}"
fi
# Let subsequent steps know where to find the (stripped) bin
echo ::set-output name=BIN_PATH::${BIN_PATH}
echo ::set-output name=BIN_NAME::${BIN_NAME}
- name: Set testing options - name: Set testing options
id: test-options id: test-options
@@ -159,44 +154,41 @@ jobs:
run: | run: |
# test only library unit tests and binary for arm-type targets # test only library unit tests and binary for arm-type targets
unset CARGO_TEST_OPTIONS unset CARGO_TEST_OPTIONS
unset CARGO_TEST_OPTIONS ; case ${{ matrix.job.target }} in arm-* | aarch64-*) CARGO_TEST_OPTIONS="--lib --bin ${PROJECT_NAME}" ;; esac; unset CARGO_TEST_OPTIONS ; case ${{ matrix.job.target }} in arm-* | aarch64-*) CARGO_TEST_OPTIONS="--lib --bin ${{ needs.crate_metadata.outputs.name }}" ;; esac;
echo ::set-output name=CARGO_TEST_OPTIONS::${CARGO_TEST_OPTIONS} echo "CARGO_TEST_OPTIONS=${CARGO_TEST_OPTIONS}" >> $GITHUB_OUTPUT
- name: Run tests - name: Run tests
uses: actions-rs/cargo@v1 shell: bash
with: run: $BUILD_CMD test --locked --target=${{ matrix.job.target }} ${{ steps.test-options.outputs.CARGO_TEST_OPTIONS}}
use-cross: ${{ matrix.job.use-cross }}
command: test
args: --target=${{ matrix.job.target }} ${{ steps.test-options.outputs.CARGO_TEST_OPTIONS}}
- name: Setup Pandoc - name: Setup Pandoc
uses: r-lib/actions/setup-pandoc@v2 uses: r-lib/actions/setup-pandoc@v2
- name: Generate man page - name: Generate man page
run: pandoc -s -f markdown -t man -o "doc/${{ env.PROJECT_NAME }}.1" "doc/${{ env.PROJECT_NAME }}.1.md" 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 - name: Create tarball
id: package id: package
shell: bash shell: bash
run: | run: |
PKG_suffix=".tar.gz" ; case ${{ matrix.job.target }} in *-pc-windows-*) PKG_suffix=".zip" ;; esac; PKG_suffix=".tar.gz" ; case ${{ matrix.job.target }} in *-pc-windows-*) PKG_suffix=".zip" ;; esac;
PKG_BASENAME=${PROJECT_NAME}-v${PROJECT_VERSION}-${{ matrix.job.target }} PKG_BASENAME=${{ needs.crate_metadata.outputs.name }}-v${{ needs.crate_metadata.outputs.version }}-${{ matrix.job.target }}
PKG_NAME=${PKG_BASENAME}${PKG_suffix} PKG_NAME=${PKG_BASENAME}${PKG_suffix}
echo ::set-output name=PKG_NAME::${PKG_NAME} echo "PKG_NAME=${PKG_NAME}" >> $GITHUB_OUTPUT
PKG_STAGING="${{ env.CICD_INTERMEDIATES_DIR }}/package" PKG_STAGING="${{ env.CICD_INTERMEDIATES_DIR }}/package"
ARCHIVE_DIR="${PKG_STAGING}/${PKG_BASENAME}/" ARCHIVE_DIR="${PKG_STAGING}/${PKG_BASENAME}/"
mkdir -p "${ARCHIVE_DIR}" mkdir -p "${ARCHIVE_DIR}"
# Binary # Binary
cp "${{ steps.strip.outputs.BIN_PATH }}" "$ARCHIVE_DIR" cp "${{ steps.bin.outputs.BIN_PATH }}" "$ARCHIVE_DIR"
# Man page
cp "doc/${{ env.PROJECT_NAME }}.1" "$ARCHIVE_DIR"
# README, LICENSE and CHANGELOG files # README, LICENSE and CHANGELOG files
cp "README.md" "LICENSE-MIT" "LICENSE-APACHE" "CHANGELOG.md" "$ARCHIVE_DIR" 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 # base compressed package
pushd "${PKG_STAGING}/" >/dev/null pushd "${PKG_STAGING}/" >/dev/null
case ${{ matrix.job.target }} in case ${{ matrix.job.target }} in
@@ -206,7 +198,7 @@ jobs:
popd >/dev/null popd >/dev/null
# Let subsequent steps know where to find the compressed package # Let subsequent steps know where to find the compressed package
echo ::set-output name=PKG_PATH::"${PKG_STAGING}/${PKG_NAME}" echo "PKG_PATH=${PKG_STAGING}/${PKG_NAME}" >> $GITHUB_OUTPUT
- name: Create Debian package - name: Create Debian package
id: debian-package id: debian-package
@@ -218,10 +210,10 @@ jobs:
DPKG_DIR="${DPKG_STAGING}/dpkg" DPKG_DIR="${DPKG_STAGING}/dpkg"
mkdir -p "${DPKG_DIR}" mkdir -p "${DPKG_DIR}"
DPKG_BASENAME=${PROJECT_NAME} DPKG_BASENAME=${{ needs.crate_metadata.outputs.name }}
DPKG_CONFLICTS=${PROJECT_NAME}-musl DPKG_CONFLICTS=${{ needs.crate_metadata.outputs.name }}-musl
case ${{ matrix.job.target }} in *-musl) DPKG_BASENAME=${PROJECT_NAME}-musl ; DPKG_CONFLICTS=${PROJECT_NAME} ;; esac; case ${{ matrix.job.target }} in *-musl) DPKG_BASENAME=${{ needs.crate_metadata.outputs.name }}-musl ; DPKG_CONFLICTS=${{ needs.crate_metadata.outputs.name }} ;; esac;
DPKG_VERSION=${PROJECT_VERSION} DPKG_VERSION=${{ needs.crate_metadata.outputs.version }}
unset DPKG_ARCH unset DPKG_ARCH
case ${{ matrix.job.target }} in case ${{ matrix.job.target }} in
@@ -233,14 +225,14 @@ jobs:
esac; esac;
DPKG_NAME="${DPKG_BASENAME}_${DPKG_VERSION}_${DPKG_ARCH}.deb" DPKG_NAME="${DPKG_BASENAME}_${DPKG_VERSION}_${DPKG_ARCH}.deb"
echo ::set-output name=DPKG_NAME::${DPKG_NAME} echo "DPKG_NAME=${DPKG_NAME}" >> $GITHUB_OUTPUT
# Binary # Binary
install -Dm755 "${{ steps.strip.outputs.BIN_PATH }}" "${DPKG_DIR}/usr/bin/${{ steps.strip.outputs.BIN_NAME }}" install -Dm755 "${{ steps.bin.outputs.BIN_PATH }}" "${DPKG_DIR}/usr/bin/${{ steps.bin.outputs.BIN_NAME }}"
# Man page # Man page
install -Dm644 "doc/${{ env.PROJECT_NAME }}.1" "${DPKG_DIR}/usr/share/man/man1/${{ env.PROJECT_NAME }}.1" 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/${{ env.PROJECT_NAME }}.1" gzip -n --best "${DPKG_DIR}/usr/share/man/man1/${{ needs.crate_metadata.outputs.name }}.1"
# README and LICENSE # README and LICENSE
install -Dm644 "README.md" "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/README.md" install -Dm644 "README.md" "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/README.md"
@@ -251,12 +243,12 @@ jobs:
cat > "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/copyright" <<EOF cat > "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/copyright" <<EOF
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: ${{ env.PROJECT_NAME }} Upstream-Name: ${{ needs.crate_metadata.outputs.name }}
Source: ${{ env.PROJECT_HOMEPAGE }} Source: ${{ needs.crate_metadata.outputs.homepage }}
Files: * Files: *
Copyright: ${{ env.PROJECT_MAINTAINER }} Copyright: ${{ needs.crate_metadata.outputs.maintainer }}
Copyright: $COPYRIGHT_YEARS ${{ env.PROJECT_MAINTAINER }} Copyright: $COPYRIGHT_YEARS ${{ needs.crate_metadata.outputs.maintainer }}
License: Apache-2.0 or MIT License: Apache-2.0 or MIT
License: Apache-2.0 License: Apache-2.0
@@ -297,16 +289,16 @@ jobs:
Version: ${DPKG_VERSION} Version: ${DPKG_VERSION}
Section: utils Section: utils
Priority: optional Priority: optional
Maintainer: ${{ env.PROJECT_MAINTAINER }} Maintainer: ${{ needs.crate_metadata.outputs.maintainer }}
Homepage: ${{ env.PROJECT_HOMEPAGE }} Homepage: ${{ needs.crate_metadata.outputs.homepage }}
Architecture: ${DPKG_ARCH} Architecture: ${DPKG_ARCH}
Provides: ${{ env.PROJECT_NAME }} Provides: ${{ needs.crate_metadata.outputs.name }}
Conflicts: ${DPKG_CONFLICTS} Conflicts: ${DPKG_CONFLICTS}
Description: colorized hex viewer for the terminal. Description: A command-line benchmarking tool
EOF EOF
DPKG_PATH="${DPKG_STAGING}/${DPKG_NAME}" DPKG_PATH="${DPKG_STAGING}/${DPKG_NAME}"
echo ::set-output name=DPKG_PATH::${DPKG_PATH} echo "DPKG_PATH=${DPKG_PATH}" >> $GITHUB_OUTPUT
# build dpkg # build dpkg
fakeroot dpkg-deb --build "${DPKG_DIR}" "${DPKG_PATH}" fakeroot dpkg-deb --build "${DPKG_DIR}" "${DPKG_PATH}"
@@ -329,7 +321,7 @@ jobs:
shell: bash shell: bash
run: | run: |
unset IS_RELEASE ; if [[ $GITHUB_REF =~ ^refs/tags/v[0-9].* ]]; then IS_RELEASE='true' ; fi unset IS_RELEASE ; if [[ $GITHUB_REF =~ ^refs/tags/v[0-9].* ]]; then IS_RELEASE='true' ; fi
echo ::set-output name=IS_RELEASE::${IS_RELEASE} echo "IS_RELEASE=${IS_RELEASE}" >> $GITHUB_OUTPUT
- name: Publish archives and packages - name: Publish archives and packages
uses: softprops/action-gh-release@v1 uses: softprops/action-gh-release@v1
+36 -1
View File
@@ -1,4 +1,39 @@
# unreleased # 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 ## Features
Generated
+48 -12
View File
@@ -11,12 +11,6 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "anstyle"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58bb0ec944fe041c41e32dcd60b49327fcb7ff761433838878cc97ddecf16db7"
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.66" version = "1.0.66"
@@ -37,6 +31,17 @@ dependencies = [
"wait-timeout", "wait-timeout",
] ]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi 0.1.19",
"libc",
"winapi",
]
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.1.0" version = "1.1.0"
@@ -175,6 +180,15 @@ dependencies = [
"num-traits", "num-traits",
] ]
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.2.6" version = "0.2.6"
@@ -186,17 +200,17 @@ dependencies = [
[[package]] [[package]]
name = "hexyl" name = "hexyl"
version = "0.11.0" version = "0.13.0"
dependencies = [ dependencies = [
"anstyle",
"anyhow", "anyhow",
"assert_cmd", "assert_cmd",
"clap", "clap",
"const_format", "const_format",
"is-terminal",
"libc", "libc",
"owo-colors",
"predicates", "predicates",
"pretty_assertions", "pretty_assertions",
"supports-color",
"terminal_size", "terminal_size",
"thiserror", "thiserror",
] ]
@@ -217,12 +231,18 @@ version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "927609f78c2913a6f6ac3c27a4fe87f43e2a35367c0c4b0f8265e8f49a104330" checksum = "927609f78c2913a6f6ac3c27a4fe87f43e2a35367c0c4b0f8265e8f49a104330"
dependencies = [ dependencies = [
"hermit-abi", "hermit-abi 0.2.6",
"io-lifetimes", "io-lifetimes",
"rustix", "rustix",
"windows-sys", "windows-sys",
] ]
[[package]]
name = "is_ci"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "616cde7c720bb2bb5824a224687d8f77bfd38922027f01d825cd7453be5099fb"
[[package]] [[package]]
name = "itertools" name = "itertools"
version = "0.10.5" version = "0.10.5"
@@ -286,6 +306,12 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "owo-colors"
version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
[[package]] [[package]]
name = "predicates" name = "predicates"
version = "2.1.4" version = "2.1.4"
@@ -371,9 +397,9 @@ checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "0.36.4" version = "0.36.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb93e85278e08bb5788653183213d3a60fc242b10cb9be96586f5a73dcb67c23" checksum = "a3807b5d10909833d3e9acd1eb5fb988f79376ff10fce42937de71a449c4c588"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"errno", "errno",
@@ -395,6 +421,16 @@ version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "supports-color"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ba6faf2ca7ee42fdd458f4347ae0a9bd6bcc445ad7cb57ad82b383f18870d6f"
dependencies = [
"atty",
"is_ci",
]
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.105" version = "1.0.105"
+4 -3
View File
@@ -7,15 +7,16 @@ license = "MIT/Apache-2.0"
name = "hexyl" name = "hexyl"
readme = "README.md" readme = "README.md"
repository = "https://github.com/sharkdp/hexyl" repository = "https://github.com/sharkdp/hexyl"
version = "0.11.0" version = "0.13.0"
edition = "2021" edition = "2021"
rust-version = "1.60"
[dependencies] [dependencies]
anstyle = "0.2"
anyhow = "1.0" anyhow = "1.0"
const_format = "0.2" const_format = "0.2"
is-terminal = "0.4"
libc = "0.2" libc = "0.2"
owo-colors = "3"
supports-color = "1"
thiserror = "1.0" thiserror = "1.0"
terminal_size = "0.2" terminal_size = "0.2"
+1 -1
View File
@@ -31,7 +31,7 @@ If you use an older version of Ubuntu, you can download
the latest `.deb` package from the release page and install it via: the latest `.deb` package from the release page and install it via:
``` bash ``` bash
sudo dpkg -i hexyl_0.11.0_amd64.deb # adapt version number and architecture sudo dpkg -i hexyl_0.12.0_amd64.deb # adapt version number and architecture
``` ```
### On Debian ### On Debian
+1 -1
View File
@@ -1,4 +1,4 @@
% HEXYL(1) hexyl 0.11.0 | General Commands Manual % HEXYL(1) hexyl 0.12.0 | General Commands Manual
% %
% 2022-12-05 % 2022-12-05
+1 -1
View File
@@ -18,7 +18,7 @@ fn main() {
.with_border_style(BorderStyle::Unicode) .with_border_style(BorderStyle::Unicode)
.enable_squeezing(false) .enable_squeezing(false)
.num_panels(2) .num_panels(2)
.num_group_bytes(1) .group_size(1)
.build(); .build();
printer.print_all(&input[..]).unwrap(); printer.print_all(&input[..]).unwrap();
} }
+76 -30
View File
@@ -9,8 +9,6 @@ use std::num::{NonZeroI64, NonZeroU64, NonZeroU8};
use clap::builder::ArgPredicate; use clap::builder::ArgPredicate;
use clap::{crate_name, crate_version, Arg, ArgAction, ColorChoice, Command}; use clap::{crate_name, crate_version, Arg, ArgAction, ColorChoice, Command};
use is_terminal::IsTerminal;
use anyhow::{anyhow, Context, Result}; use anyhow::{anyhow, Context, Result};
use const_format::formatcp; use const_format::formatcp;
@@ -19,7 +17,7 @@ use thiserror::Error as ThisError;
use terminal_size::terminal_size; use terminal_size::terminal_size;
use hexyl::{Base, BorderStyle, Input, PrinterBuilder}; use hexyl::{Base, BorderStyle, Endianness, Input, PrinterBuilder};
const DEFAULT_BLOCK_SIZE: i64 = 512; const DEFAULT_BLOCK_SIZE: i64 = 512;
@@ -130,10 +128,17 @@ fn run() -> Result<()> {
)) ))
.arg( .arg(
Arg::new("no_chars") Arg::new("no_chars")
.short('C')
.long("no-characters") .long("no-characters")
.action(ArgAction::SetFalse) .action(ArgAction::SetFalse)
.help("Whether to display the character panel on the right."), .help("Do not show the character panel on the right."),
)
.arg(
Arg::new("chars")
.short('C')
.long("characters")
.overrides_with("no_chars")
.action(ArgAction::SetTrue)
.help("Show the character panel on the right. This is the default, unless --no-characters has been specified."),
) )
.arg( .arg(
Arg::new("no_position") Arg::new("no_position")
@@ -163,20 +168,47 @@ fn run() -> Result<()> {
.help( .help(
"Sets the number of hex data panels to be displayed. \ "Sets the number of hex data panels to be displayed. \
`--panels=auto` will display the maximum number of hex data panels \ `--panels=auto` will display the maximum number of hex data panels \
based on the current terminal width", based on the current terminal width. By default, hexyl will show \
two panels, unless the terminal is not wide enough for that.",
), ),
) )
.arg( .arg(
Arg::new("group_bytes") Arg::new("group_size")
.short('g') .short('g')
.long("group-bytes") .long("group-size")
.alias("groupsize")
.num_args(1) .num_args(1)
.value_name("N") .value_name("N")
.help( .help(
"Sets the number of octets per group to be displayed. \ "Number of bytes/octets that should be grouped together. \
The possible options are 1, 2, 4, 8. The default is 1", Possible group sizes are 1, 2, 4, 8. The default is 1. 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(
Arg::new("endianness")
.long("endianness")
.num_args(1)
.value_name("FORMAT")
.value_parser(["big", "little"])
.default_value("big")
.help(
"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(
Arg::new("little_endian_format")
.short('e')
.action(ArgAction::SetTrue)
.overrides_with("endianness")
.hide(true)
.help("An alias for '--endianness=little'."),
)
.arg( .arg(
Arg::new("base") Arg::new("base")
.short('b') .short('b')
@@ -293,8 +325,10 @@ fn run() -> Result<()> {
let show_color = match matches.get_one::<String>("color").map(String::as_ref) { let show_color = match matches.get_one::<String>("color").map(String::as_ref) {
Some("never") => false, Some("never") => false,
Some("auto") => std::io::stdout().is_terminal(), Some("always") => true,
_ => true, _ => supports_color::on(supports_color::Stream::Stdout)
.map(|level| level.has_basic)
.unwrap_or(false),
}; };
let border_style = match matches.get_one::<String>("border").map(String::as_ref) { let border_style = match matches.get_one::<String>("border").map(String::as_ref) {
@@ -322,12 +356,12 @@ fn run() -> Result<()> {
.transpose()? .transpose()?
.unwrap_or(0); .unwrap_or(0);
let max_panels_fn = |terminal_width: u64, base_digits: u64, group_bytes: u64| { let max_panels_fn = |terminal_width: u64, base_digits: u64, group_size: u64| {
let offset = if show_position_panel { 10 } else { 1 }; let offset = if show_position_panel { 10 } else { 1 };
let col_width = if show_char_panel { let col_width = if show_char_panel {
((8 / group_bytes) * (base_digits * group_bytes + 1)) + 2 + 8 ((8 / group_size) * (base_digits * group_size + 1)) + 2 + 8
} else { } else {
((8 / group_bytes) * (base_digits * group_bytes + 1)) + 2 ((8 / group_size) * (base_digits * group_size + 1)) + 2
}; };
if (terminal_width - offset) / col_width < 1 { if (terminal_width - offset) / col_width < 1 {
1 1
@@ -368,33 +402,31 @@ fn run() -> Result<()> {
Base::Hexadecimal => 2, Base::Hexadecimal => 2,
}; };
let group_bytes = if let Some(group_bytes) = matches let group_size = if let Some(group_size) = matches
.get_one::<String>("group_bytes") .get_one::<String>("group_size")
.map(|s| { .map(|s| {
s.parse::<NonZeroU8>().map(u8::from).context(anyhow!( s.parse::<NonZeroU8>().map(u8::from).context(anyhow!(
"failed to parse `--group-bytes`/`-g` arg {:?} as unsigned nonzero integer", "Failed to parse `--group-size`/`-g` argument {:?} as unsigned nonzero integer",
s s
)) ))
}) })
.transpose()? .transpose()?
{ {
if (group_bytes <= 8) && ((group_bytes & (group_bytes - 1)) == 0) { if (group_size <= 8) && ((group_size & (group_size - 1)) == 0) {
group_bytes group_size
} else { } else {
return Err(anyhow!( return Err(anyhow!(
"Possible options for the `--group-bytes`/`-g` option are 1, 2, 4 or 8. " "Possible sizes for the `--group-size`/`-g` option are 1, 2, 4 or 8. "
)); ));
} }
} else { } else {
1 1
}; };
let terminal_width = terminal_size().map(|s| s.0 .0 as u64).unwrap_or(80);
let panels = if matches.get_one::<String>("panels").map(String::as_ref) == Some("auto") { let panels = if matches.get_one::<String>("panels").map(String::as_ref) == Some("auto") {
max_panels_fn( max_panels_fn(terminal_width, base_digits, group_size.into())
terminal_size().ok_or_else(|| anyhow!("not a TTY"))?.0 .0 as u64,
base_digits,
group_bytes.into(),
)
} else if let Some(panels) = matches } else if let Some(panels) = matches
.get_one::<String>("panels") .get_one::<String>("panels")
.map(|s| { .map(|s| {
@@ -416,11 +448,24 @@ fn run() -> Result<()> {
}) })
.transpose()? .transpose()?
{ {
max_panels_fn(terminal_width, base_digits, group_bytes.into()) max_panels_fn(terminal_width, base_digits, group_size.into())
} else { } else {
2 std::cmp::min(
2,
max_panels_fn(terminal_width, base_digits, group_size.into()),
)
}; };
let little_endian_format = *matches.get_one::<bool>("little_endian_format").unwrap();
let endianness = matches.get_one::<String>("endianness");
let endianness = match (
endianness.map(|s| s.as_ref()).unwrap(),
little_endian_format,
) {
(_, true) | ("little", _) => Endianness::Little,
("big", _) => Endianness::Big,
_ => unreachable!(),
};
let stdout = io::stdout(); let stdout = io::stdout();
let mut stdout_lock = BufWriter::new(stdout.lock()); let mut stdout_lock = BufWriter::new(stdout.lock());
@@ -431,8 +476,9 @@ fn run() -> Result<()> {
.with_border_style(border_style) .with_border_style(border_style)
.enable_squeezing(squeeze) .enable_squeezing(squeeze)
.num_panels(panels) .num_panels(panels)
.num_group_bytes(group_bytes) .group_size(group_size)
.with_base(base) .with_base(base)
.endianness(endianness)
.build(); .build();
printer.display_offset(skip_offset + display_offset); printer.display_offset(skip_offset + display_offset);
printer.print_all(&mut reader).map_err(|e| anyhow!(e))?; printer.print_all(&mut reader).map_err(|e| anyhow!(e))?;
@@ -449,7 +495,7 @@ fn main() {
std::process::exit(0); std::process::exit(0);
} }
} }
eprintln!("Error: {:?}", err); eprintln!("Error: {err:?}");
std::process::exit(1); std::process::exit(1);
} }
} }
+90 -86
View File
@@ -4,7 +4,7 @@ pub use input::*;
use std::io::{self, BufReader, Read, Write}; use std::io::{self, BufReader, Read, Write};
use anstyle::{AnsiColor, Reset}; use owo_colors::{colors, Color};
pub enum Base { pub enum Base {
Binary, Binary,
@@ -13,25 +13,15 @@ pub enum Base {
Hexadecimal, Hexadecimal,
} }
#[derive(PartialEq, Eq)] const COLOR_NULL: &[u8] = colors::BrightBlack::ANSI_FG.as_bytes();
#[repr(usize)] const COLOR_OFFSET: &[u8] = colors::BrightBlack::ANSI_FG.as_bytes();
enum ByteColor { const COLOR_ASCII_PRINTABLE: &[u8] = colors::Cyan::ANSI_FG.as_bytes();
Null = 0, const COLOR_ASCII_WHITESPACE: &[u8] = colors::Green::ANSI_FG.as_bytes();
Offset = 1, const COLOR_ASCII_OTHER: &[u8] = colors::Green::ANSI_FG.as_bytes();
AsciiPrintable = 2, const COLOR_NONASCII: &[u8] = colors::Yellow::ANSI_FG.as_bytes();
AsciiWhitespace = 3, const COLOR_RESET: &[u8] = colors::Default::ANSI_FG.as_bytes();
AsciiOther = 4,
NonAscii = 5,
Reset = 6,
}
const COLOR_NULL: AnsiColor = AnsiColor::BrightBlack;
const COLOR_OFFSET: AnsiColor = AnsiColor::BrightBlack;
const COLOR_ASCII_PRINTABLE: AnsiColor = AnsiColor::Cyan;
const COLOR_ASCII_WHITESPACE: AnsiColor = AnsiColor::Green;
const COLOR_ASCII_OTHER: AnsiColor = AnsiColor::Magenta;
const COLOR_NONASCII: AnsiColor = AnsiColor::Yellow;
#[derive(Copy, Clone)]
pub enum ByteCategory { pub enum ByteCategory {
Null, Null,
AsciiPrintable, AsciiPrintable,
@@ -40,6 +30,12 @@ pub enum ByteCategory {
NonAscii, NonAscii,
} }
#[derive(Copy, Clone)]
pub enum Endianness {
Little,
Big,
}
#[derive(PartialEq)] #[derive(PartialEq)]
enum Squeezer { enum Squeezer {
Print, Print,
@@ -66,15 +62,15 @@ impl Byte {
} }
} }
fn color(self) -> ByteColor { fn color(self) -> &'static [u8] {
use crate::ByteCategory::*; use crate::ByteCategory::*;
match self.category() { match self.category() {
Null => ByteColor::Null, Null => COLOR_NULL,
AsciiPrintable => ByteColor::AsciiPrintable, AsciiPrintable => COLOR_ASCII_PRINTABLE,
AsciiWhitespace => ByteColor::AsciiWhitespace, AsciiWhitespace => COLOR_ASCII_WHITESPACE,
AsciiOther => ByteColor::AsciiOther, AsciiOther => COLOR_ASCII_OTHER,
NonAscii => ByteColor::NonAscii, NonAscii => COLOR_NONASCII,
} }
} }
@@ -168,8 +164,9 @@ pub struct PrinterBuilder<'a, Writer: Write> {
border_style: BorderStyle, border_style: BorderStyle,
use_squeeze: bool, use_squeeze: bool,
panels: u64, panels: u64,
group_bytes: u8, group_size: u8,
base: Base, base: Base,
endianness: Endianness,
} }
impl<'a, Writer: Write> PrinterBuilder<'a, Writer> { impl<'a, Writer: Write> PrinterBuilder<'a, Writer> {
@@ -182,8 +179,9 @@ impl<'a, Writer: Write> PrinterBuilder<'a, Writer> {
border_style: BorderStyle::Unicode, border_style: BorderStyle::Unicode,
use_squeeze: true, use_squeeze: true,
panels: 2, panels: 2,
group_bytes: 1, group_size: 1,
base: Base::Hexadecimal, base: Base::Hexadecimal,
endianness: Endianness::Big,
} }
} }
@@ -217,8 +215,8 @@ impl<'a, Writer: Write> PrinterBuilder<'a, Writer> {
self self
} }
pub fn num_group_bytes(mut self, num: u8) -> Self { pub fn group_size(mut self, num: u8) -> Self {
self.group_bytes = num; self.group_size = num;
self self
} }
@@ -227,6 +225,11 @@ impl<'a, Writer: Write> PrinterBuilder<'a, Writer> {
self self
} }
pub fn endianness(mut self, endianness: Endianness) -> Self {
self.endianness = endianness;
self
}
pub fn build(self) -> Printer<'a, Writer> { pub fn build(self) -> Printer<'a, Writer> {
Printer::new( Printer::new(
self.writer, self.writer,
@@ -236,8 +239,9 @@ impl<'a, Writer: Write> PrinterBuilder<'a, Writer> {
self.border_style, self.border_style,
self.use_squeeze, self.use_squeeze,
self.panels, self.panels,
self.group_bytes, self.group_size,
self.base, self.base,
self.endianness,
) )
} }
} }
@@ -250,23 +254,23 @@ pub struct Printer<'a, Writer: Write> {
show_char_panel: bool, show_char_panel: bool,
show_position_panel: bool, show_position_panel: bool,
show_color: bool, show_color: bool,
colors: Vec<String>, curr_color: Option<&'static [u8]>,
curr_color: Option<ByteColor>,
border_style: BorderStyle, border_style: BorderStyle,
byte_hex_panel: Vec<String>, byte_hex_panel: Vec<String>,
byte_char_panel: Vec<String>, byte_char_panel: Vec<String>,
// same as previous but in Fixed(242) gray color, for position panel // same as previous but in Fixed(242) gray color, for position panel
byte_hex_panel_g: Vec<String>, byte_hex_panel_g: Vec<String>,
byte_char_panel_g: Vec<String>,
squeezer: Squeezer, squeezer: Squeezer,
display_offset: u64, display_offset: u64,
/// The number of panels to draw. /// The number of panels to draw.
panels: u64, panels: u64,
squeeze_byte: usize, squeeze_byte: usize,
/// The number of octets per group. /// The number of octets per group.
group_bytes: u8, group_size: u8,
/// The number of digits used to write the base. /// The number of digits used to write the base.
base_digits: u8, base_digits: u8,
/// Whether to show groups in little or big endian format.
endianness: Endianness,
} }
impl<'a, Writer: Write> Printer<'a, Writer> { impl<'a, Writer: Write> Printer<'a, Writer> {
@@ -278,8 +282,9 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
border_style: BorderStyle, border_style: BorderStyle,
use_squeeze: bool, use_squeeze: bool,
panels: u64, panels: u64,
group_bytes: u8, group_size: u8,
base: Base, base: Base,
endianness: Endianness,
) -> Printer<'a, Writer> { ) -> Printer<'a, Writer> {
Printer { Printer {
idx: 0, idx: 0,
@@ -289,15 +294,6 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
show_position_panel, show_position_panel,
show_color, show_color,
curr_color: None, curr_color: None,
colors: vec![
COLOR_NULL.render_fg().to_string(),
COLOR_OFFSET.render_fg().to_string(),
COLOR_ASCII_PRINTABLE.render_fg().to_string(),
COLOR_ASCII_WHITESPACE.render_fg().to_string(),
COLOR_ASCII_OTHER.render_fg().to_string(),
COLOR_NONASCII.render_fg().to_string(),
Reset.render().to_string(),
],
border_style, border_style,
byte_hex_panel: (0u8..=u8::MAX) byte_hex_panel: (0u8..=u8::MAX)
.map(|i| match base { .map(|i| match base {
@@ -311,9 +307,6 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
.map(|i| format!("{}", Byte(i).as_char())) .map(|i| format!("{}", Byte(i).as_char()))
.collect(), .collect(),
byte_hex_panel_g: (0u8..=u8::MAX).map(|i| format!("{i:02x}")).collect(), byte_hex_panel_g: (0u8..=u8::MAX).map(|i| format!("{i:02x}")).collect(),
byte_char_panel_g: (0u8..=u8::MAX)
.map(|i| format!("{}", Byte(i).as_char()))
.collect(),
squeezer: if use_squeeze { squeezer: if use_squeeze {
Squeezer::Ignore Squeezer::Ignore
} else { } else {
@@ -322,13 +315,14 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
display_offset: 0, display_offset: 0,
panels, panels,
squeeze_byte: 0x00, squeeze_byte: 0x00,
group_bytes, group_size,
base_digits: match base { base_digits: match base {
Base::Binary => 8, Base::Binary => 8,
Base::Octal => 3, Base::Octal => 3,
Base::Decimal => 3, Base::Decimal => 3,
Base::Hexadecimal => 2, Base::Hexadecimal => 2,
}, },
endianness,
} }
} }
@@ -339,8 +333,8 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
fn panel_sz(&self) -> usize { fn panel_sz(&self) -> usize {
// add one to include the trailing space of a group // add one to include the trailing space of a group
let group_sz = self.base_digits as usize * self.group_bytes as usize + 1; let group_sz = self.base_digits as usize * self.group_size as usize + 1;
let group_per_panel = 8 / self.group_bytes as usize; let group_per_panel = 8 / self.group_size as usize;
// add one to include the leading space // add one to include the leading space
1 + group_sz * group_per_panel 1 + group_sz * group_per_panel
} }
@@ -354,27 +348,27 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
let h_repeat = h.to_string().repeat(self.panel_sz()); let h_repeat = h.to_string().repeat(self.panel_sz());
if self.show_position_panel { if self.show_position_panel {
write!(self.writer, "{l}{h8}{c}", l = l, c = c, h8 = h8).ok(); write!(self.writer, "{l}{h8}{c}")?;
} else { } else {
write!(self.writer, "{}", l).ok(); write!(self.writer, "{l}")?;
} }
for _ in 0..self.panels - 1 { for _ in 0..self.panels - 1 {
write!(self.writer, "{h_repeat}{c}", h_repeat = h_repeat, c = c).ok(); write!(self.writer, "{h_repeat}{c}")?;
} }
if self.show_char_panel { if self.show_char_panel {
write!(self.writer, "{h_repeat}{c}", h_repeat = h_repeat, c = c).ok(); write!(self.writer, "{h_repeat}{c}")?;
} else { } else {
write!(self.writer, "{h_repeat}", h_repeat = h_repeat).ok(); write!(self.writer, "{h_repeat}")?;
} }
if self.show_char_panel { if self.show_char_panel {
for _ in 0..self.panels - 1 { for _ in 0..self.panels - 1 {
write!(self.writer, "{h8}{c}", h8 = h8, c = c).ok(); write!(self.writer, "{h8}{c}")?;
} }
writeln!(self.writer, "{h8}{r}", h8 = h8, r = r).ok(); writeln!(self.writer, "{h8}{r}")?;
} else { } else {
writeln!(self.writer, "{r}", r = r).ok(); writeln!(self.writer, "{r}")?;
} }
Ok(()) Ok(())
@@ -402,17 +396,15 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
.as_bytes(), .as_bytes(),
)?; )?;
if self.show_color { if self.show_color {
self.writer self.writer.write_all(COLOR_OFFSET)?;
.write_all(self.colors[ByteColor::Offset as usize].as_bytes())?;
} }
if self.show_position_panel { if self.show_position_panel {
match self.squeezer { match self.squeezer {
Squeezer::Print => { Squeezer::Print => {
self.writer self.writer
.write_all(self.byte_char_panel_g[b'*' as usize].as_bytes())?; .write_all(self.byte_char_panel[b'*' as usize].as_bytes())?;
if self.show_color { if self.show_color {
self.writer self.writer.write_all(COLOR_RESET)?;
.write_all(self.colors[ByteColor::Reset as usize].as_bytes())?;
} }
self.writer.write_all(b" ")?; self.writer.write_all(b" ")?;
} }
@@ -427,8 +419,7 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
.write_all(self.byte_hex_panel_g[byte as usize].as_bytes())?; .write_all(self.byte_hex_panel_g[byte as usize].as_bytes())?;
} }
if self.show_color { if self.show_color {
self.writer self.writer.write_all(COLOR_RESET)?;
.write_all(self.colors[ByteColor::Reset as usize].as_bytes())?;
} }
} }
} }
@@ -448,8 +439,7 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
Squeezer::Ignore | Squeezer::Disabled => { Squeezer::Ignore | Squeezer::Disabled => {
if let Some(&b) = self.line_buf.get(i as usize) { if let Some(&b) = self.line_buf.get(i as usize) {
if self.show_color && self.curr_color != Some(Byte(b).color()) { if self.show_color && self.curr_color != Some(Byte(b).color()) {
self.writer self.writer.write_all(Byte(b).color())?;
.write_all(self.colors[Byte(b).color() as usize].as_bytes())?;
self.curr_color = Some(Byte(b).color()); self.curr_color = Some(Byte(b).color());
} }
self.writer self.writer
@@ -461,8 +451,7 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
} }
if i == 8 * self.panels - 1 { if i == 8 * self.panels - 1 {
if self.show_color { if self.show_color {
self.writer self.writer.write_all(COLOR_RESET)?;
.write_all(self.colors[ByteColor::Reset as usize].as_bytes())?;
self.curr_color = None; self.curr_color = None;
} }
self.writer.write_all( self.writer.write_all(
@@ -473,8 +462,7 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
)?; )?;
} else if i % 8 == 7 { } else if i % 8 == 7 {
if self.show_color { if self.show_color {
self.writer self.writer.write_all(COLOR_RESET)?;
.write_all(self.colors[ByteColor::Reset as usize].as_bytes())?;
self.curr_color = None; self.curr_color = None;
} }
self.writer.write_all( self.writer.write_all(
@@ -500,19 +488,15 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
Squeezer::Print => { Squeezer::Print => {
if !self.show_position_panel && i == 0 { if !self.show_position_panel && i == 0 {
if self.show_color { if self.show_color {
self.writer self.writer.write_all(COLOR_OFFSET)?;
.write_all(self.colors[ByteColor::Offset as usize].as_bytes())?;
} }
self.writer self.writer
.write_all(self.byte_char_panel_g[b'*' as usize].as_bytes())?; .write_all(self.byte_char_panel[b'*' as usize].as_bytes())?;
if self.show_color { if self.show_color {
self.writer self.writer.write_all(COLOR_RESET)?;
.write_all(self.colors[ByteColor::Reset as usize].as_bytes())?;
}
} else {
if i % (self.group_bytes as usize) == 0 {
self.writer.write_all(b" ")?;
} }
} else if i % (self.group_size as usize) == 0 {
self.writer.write_all(b" ")?;
} }
for _ in 0..self.base_digits { for _ in 0..self.base_digits {
self.writer.write_all(b" ")?; self.writer.write_all(b" ")?;
@@ -520,12 +504,11 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
} }
Squeezer::Delete => self.writer.write_all(b" ")?, Squeezer::Delete => self.writer.write_all(b" ")?,
Squeezer::Ignore | Squeezer::Disabled => { Squeezer::Ignore | Squeezer::Disabled => {
if i % (self.group_bytes as usize) == 0 { if i % (self.group_size as usize) == 0 {
self.writer.write_all(b" ")?; self.writer.write_all(b" ")?;
} }
if self.show_color && self.curr_color != Some(Byte(b).color()) { if self.show_color && self.curr_color != Some(Byte(b).color()) {
self.writer self.writer.write_all(Byte(b).color())?;
.write_all(self.colors[Byte(b).color() as usize].as_bytes())?;
self.curr_color = Some(Byte(b).color()); self.curr_color = Some(Byte(b).color());
} }
self.writer self.writer
@@ -536,8 +519,7 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
if i % 8 == 7 { if i % 8 == 7 {
if self.show_color { if self.show_color {
self.curr_color = None; self.curr_color = None;
self.writer self.writer.write_all(COLOR_RESET)?;
.write_all(self.colors[ByteColor::Reset as usize].as_bytes())?;
} }
self.writer.write_all(b" ")?; self.writer.write_all(b" ")?;
// byte is last in last panel // byte is last in last panel
@@ -560,8 +542,26 @@ impl<'a, Writer: Write> Printer<'a, Writer> {
Ok(()) Ok(())
} }
fn reorder_buffer_to_little_endian(&self, buf: &mut Vec<u8>) {
let n = buf.len();
let group_sz = self.group_size as usize;
for idx in (0..n).step_by(group_sz) {
let remaining = n - idx;
let total = remaining.min(group_sz);
buf[idx..idx + total].reverse();
}
}
pub fn print_bytes(&mut self) -> io::Result<()> { pub fn print_bytes(&mut self) -> io::Result<()> {
for (i, &b) in self.line_buf.clone().iter().enumerate() { let mut buf = self.line_buf.clone();
if matches!(self.endianness, Endianness::Little) {
self.reorder_buffer_to_little_endian(&mut buf);
};
for (i, &b) in buf.iter().enumerate() {
self.print_byte(i, b)?; self.print_byte(i, b)?;
} }
Ok(()) Ok(())
@@ -719,6 +719,7 @@ mod tests {
2, 2,
1, 1,
Base::Hexadecimal, Base::Hexadecimal,
Endianness::Big,
); );
printer.print_all(input).unwrap(); printer.print_all(input).unwrap();
@@ -773,6 +774,7 @@ mod tests {
2, 2,
1, 1,
Base::Hexadecimal, Base::Hexadecimal,
Endianness::Big,
); );
printer.display_offset(0xdeadbeef); printer.display_offset(0xdeadbeef);
@@ -806,6 +808,7 @@ mod tests {
4, 4,
1, 1,
Base::Hexadecimal, Base::Hexadecimal,
Endianness::Big,
); );
printer.print_all(input).unwrap(); printer.print_all(input).unwrap();
@@ -865,6 +868,7 @@ mod tests {
3, 3,
1, 1,
Base::Hexadecimal, Base::Hexadecimal,
Endianness::Big,
); );
printer.print_all(input).unwrap(); printer.print_all(input).unwrap();
+63 -14
View File
@@ -292,16 +292,16 @@ mod display_settings {
} }
} }
mod group { mod group_and_endianness {
use super::hexyl; use super::hexyl;
use super::PrettyAssert; use super::PrettyAssert;
#[test] #[test]
fn group_2_bytes() { fn group_2_bytes_be() {
hexyl() hexyl()
.arg("ascii") .arg("ascii")
.arg("--color=never") .arg("--color=never")
.arg("--group-bytes=2") .arg("--group-size=2")
.assert() .assert()
.success() .success()
.stdout( .stdout(
@@ -312,11 +312,27 @@ mod group {
} }
#[test] #[test]
fn group_4_bytes() { fn group_2_bytes_le() {
hexyl() hexyl()
.arg("ascii") .arg("ascii")
.arg("--color=never") .arg("--color=never")
.arg("--group-bytes=4") .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() .assert()
.success() .success()
.stdout( .stdout(
@@ -327,11 +343,27 @@ mod group {
} }
#[test] #[test]
fn group_8_bytes() { fn group_4_bytes_le() {
hexyl() hexyl()
.arg("ascii") .arg("ascii")
.arg("--color=never") .arg("--color=never")
.arg("--group-bytes=8") .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() .assert()
.success() .success()
.stdout( .stdout(
@@ -342,22 +374,38 @@ mod group {
} }
#[test] #[test]
fn group_bytes_plain() { 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() hexyl()
.arg("ascii") .arg("ascii")
.arg("--color=never") .arg("--color=never")
.arg("--plain") .arg("--plain")
.arg("--group-bytes=2") .arg("--group-size=2")
.assert() .assert()
.success() .success()
.stdout(" 3031 3233 3435 3637 3839 6162 6364 650a \n"); .stdout(" 3031 3233 3435 3637 3839 6162 6364 650a \n");
} }
#[test] #[test]
fn group_bytes_fill_space() { fn group_size_fill_space() {
hexyl() hexyl()
.arg("--color=never") .arg("--color=never")
.arg("--group-bytes=2") .arg("--group-size=2")
.write_stdin("abc") .write_stdin("abc")
.assert() .assert()
.success() .success()
@@ -369,12 +417,12 @@ mod group {
} }
#[test] #[test]
fn group_bytes_invalid() { fn group_size_invalid() {
hexyl() hexyl()
.arg("ascii") .arg("ascii")
.arg("--color=never") .arg("--color=never")
.arg("--plain") .arg("--plain")
.arg("--group-bytes=3") .arg("--group-size=3")
.assert() .assert()
.failure(); .failure();
} }
@@ -565,7 +613,8 @@ mod base {
.assert() .assert()
.success() .success()
.pretty_stdout( .pretty_stdout(
" 00110000 00110001 00110010 00110011 00110100 00110101 00110110 00110111 00111000 00111001 01100001 01100010 01100011 01100100 01100101 00001010 \n" " 00110000 00110001 00110010 00110011 00110100 00110101 00110110 00110111 \n \
00111000 00111001 01100001 01100010 01100011 01100100 01100101 00001010 \n",
); );
} }
} }