init
This commit is contained in:
commit
1c8e2579b9
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@ -0,0 +1 @@
|
||||
/completions/**/* linguist-generated
|
15
.github/dependabot.yml
vendored
Normal file
15
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: cargo
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: weekly
|
||||
open-pull-requests-limit: 10
|
||||
reviewers:
|
||||
- wfxr
|
||||
labels:
|
||||
- dependencies
|
||||
commit-message:
|
||||
prefix: "chore"
|
||||
prefix-development: "chore"
|
||||
include: "scope"
|
22
.github/issue_template.md
vendored
Normal file
22
.github/issue_template.md
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
<!-- ISSUES NOT FOLLOWING THIS TEMPLATE WILL BE CLOSED AND DELETED -->
|
||||
|
||||
<!-- Check all that apply [x] -->
|
||||
|
||||
## Check list
|
||||
|
||||
- [ ] I have read through the [README](https://github.com/wfxr/csview/blob/master/README.md)
|
||||
- [ ] I have searched through the existing issues
|
||||
|
||||
## Environment info
|
||||
|
||||
- OS
|
||||
- [ ] Linux
|
||||
- [ ] Mac OS X
|
||||
- [ ] Windows
|
||||
- [ ] Others:
|
||||
|
||||
## Version
|
||||
|
||||
<!-- get by running `csview --version` -->
|
||||
|
||||
## Problem / Steps to reproduce
|
29
.github/pull_request_template.md
vendored
Normal file
29
.github/pull_request_template.md
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
<!-- Check all that apply [x] -->
|
||||
|
||||
## Check list
|
||||
|
||||
- [ ] I have read through the [README](https://github.com/wfxr/csview/blob/master/README.md) (especially F.A.Q section)
|
||||
- [ ] I have searched through the existing issues or pull requests
|
||||
- [ ] I have performed a self-review of my code and commented hard-to-understand areas
|
||||
- [ ] I have made corresponding changes to the documentation (when necessary)
|
||||
|
||||
## Description
|
||||
|
||||
<!-- Please include a summary of the change(and the related issue if any). Please also include relevant motivation and context when necessary. -->
|
||||
|
||||
## Type of change
|
||||
|
||||
- [ ] Bug fix
|
||||
- [ ] New feature
|
||||
- [ ] Refactor
|
||||
- [ ] Breaking change
|
||||
- [ ] Documentation change
|
||||
- [ ] CICD related improvement
|
||||
|
||||
## Test environment
|
||||
|
||||
- OS
|
||||
- [ ] Linux
|
||||
- [ ] Mac OS X
|
||||
- [ ] Windows
|
||||
- [ ] Others:
|
342
.github/workflows/CICD.yml
vendored
Normal file
342
.github/workflows/CICD.yml
vendored
Normal file
@ -0,0 +1,342 @@
|
||||
name: CICD
|
||||
|
||||
env:
|
||||
CICD_INTERMEDIATES_DIR: "_cicd-intermediates"
|
||||
MSRV_FEATURES: "--all-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@v4
|
||||
- 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 '"description=" + .packages[0].description' | 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 }}
|
||||
description: ${{ steps.crate_metadata.outputs.description }}
|
||||
msrv: ${{ steps.crate_metadata.outputs.msrv }}
|
||||
|
||||
ensure_cargo_fmt:
|
||||
name: Ensure 'cargo fmt' has been run
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
with:
|
||||
components: rustfmt
|
||||
- uses: actions/checkout@v4
|
||||
- run: cargo fmt -- --check
|
||||
|
||||
# min_version:
|
||||
# name: Minimum supported rust version
|
||||
# runs-on: ubuntu-latest
|
||||
# needs: crate_metadata
|
||||
# steps:
|
||||
# - name: Checkout source code
|
||||
# uses: actions/checkout@v4
|
||||
#
|
||||
# - 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-20.04, use-cross: true }
|
||||
- { target: aarch64-unknown-linux-musl , os: ubuntu-20.04, use-cross: true }
|
||||
- { target: arm-unknown-linux-gnueabihf , os: ubuntu-20.04, use-cross: true }
|
||||
- { target: arm-unknown-linux-musleabihf, os: ubuntu-20.04, use-cross: true }
|
||||
- { target: i686-pc-windows-msvc , os: windows-2019 }
|
||||
- { target: i686-unknown-linux-gnu , os: ubuntu-20.04, use-cross: true }
|
||||
- { target: i686-unknown-linux-musl , os: ubuntu-20.04, use-cross: true }
|
||||
- { target: x86_64-apple-darwin , os: macos-12 }
|
||||
- { target: aarch64-apple-darwin , os: macos-14 }
|
||||
# - { target: x86_64-pc-windows-gnu , os: windows-2019 }
|
||||
- { target: x86_64-pc-windows-msvc , os: windows-2019 }
|
||||
- { target: x86_64-unknown-linux-gnu , os: ubuntu-20.04, use-cross: true }
|
||||
- { target: x86_64-unknown-linux-musl , os: ubuntu-20.04, use-cross: true }
|
||||
env:
|
||||
BUILD_CMD: cargo
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- 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@nightly
|
||||
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: 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
|
||||
unset CARGO_TEST_OPTIONS ; case ${{ matrix.job.target }} in arm-* | aarch64-*) CARGO_TEST_OPTIONS="--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: Test run
|
||||
shell: bash
|
||||
run: echo -e 'a,b,c\n1,2,3\n4,5,6\n7,8,9' | $BUILD_CMD run --locked --target=${{ matrix.job.target }}
|
||||
|
||||
- name: Strip binary
|
||||
shell: bash
|
||||
run: |
|
||||
if hash strip &>/dev/null; then
|
||||
# strip binary if possible
|
||||
strip "${{ steps.bin.outputs.BIN_PATH }}" || true
|
||||
fi
|
||||
|
||||
- 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 and LICENSE files
|
||||
cp "README.md" "LICENSE-MIT" "LICENSE-APACHE" "$ARCHIVE_DIR"
|
||||
|
||||
# Autocompletion files
|
||||
cp -r completions "${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="2020 - "$(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"
|
||||
|
||||
# Autocompletion files
|
||||
install -Dm644 'completions/bash/${{ needs.crate_metadata.outputs.name }}.bash' "${DPKG_DIR}/usr/share/bash-completion/completions/${{ needs.crate_metadata.outputs.name }}"
|
||||
install -Dm644 'completions/fish/${{ needs.crate_metadata.outputs.name }}.fish' "${DPKG_DIR}/usr/share/fish/vendor_completions.d/${{ needs.crate_metadata.outputs.name }}.fish"
|
||||
install -Dm644 'completions/zsh/_${{ needs.crate_metadata.outputs.name }}' "${DPKG_DIR}/usr/share/zsh/vendor-completions/_${{ needs.crate_metadata.outputs.name }}"
|
||||
|
||||
# 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"
|
||||
|
||||
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: ${{ needs.crate_metadata.outputs.description }}
|
||||
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@master
|
||||
with:
|
||||
name: ${{ steps.package.outputs.PKG_NAME }}
|
||||
path: ${{ steps.package.outputs.PKG_PATH }}
|
||||
|
||||
- name: "Artifact upload: Debian package"
|
||||
uses: actions/upload-artifact@master
|
||||
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 }}
|
39
.github/workflows/release.yml
vendored
Normal file
39
.github/workflows/release.yml
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*.*.*"
|
||||
|
||||
jobs:
|
||||
changelog:
|
||||
name: Generate and publish changelog
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Generate a changelog
|
||||
uses: orhun/git-cliff-action@v3
|
||||
id: git-cliff
|
||||
with:
|
||||
config: cliff.toml
|
||||
args: -v --latest --strip header
|
||||
env:
|
||||
OUTPUT: CHANGES.md
|
||||
GITHUB_REPO: ${{ github.repository }}
|
||||
|
||||
- name: Polish changelog
|
||||
shell: bash
|
||||
run: sed -i '1,2d' CHANGES.md
|
||||
|
||||
- name: Upload the changelog
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
# draft: true
|
||||
allowUpdates: true
|
||||
bodyFile: CHANGES.md
|
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
/target
|
||||
/.idea
|
||||
/flamegraph.svg
|
||||
/perf.data
|
43
.pre-commit-config.yaml
Normal file
43
.pre-commit-config.yaml
Normal file
@ -0,0 +1,43 @@
|
||||
# See https://pre-commit.com for more information
|
||||
# See https://pre-commit.com/hooks.html for more hooks
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.0.1
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
- id: check-yaml
|
||||
- id: check-added-large-files
|
||||
- id: mixed-line-ending
|
||||
- id: check-toml
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: cargo-fmt
|
||||
name: cargo fmt
|
||||
pass_filenames: false
|
||||
always_run: true
|
||||
language: system
|
||||
entry: cargo fmt
|
||||
- id: cargo-check
|
||||
name: cargo check
|
||||
pass_filenames: false
|
||||
always_run: true
|
||||
language: system
|
||||
entry: cargo check
|
||||
- id: cargo-clippy
|
||||
name: cargo clippy
|
||||
pass_filenames: false
|
||||
language: system
|
||||
always_run: true
|
||||
entry: cargo clippy
|
||||
args: ["--", "-D", "warnings"]
|
||||
- id: update-completions
|
||||
name: update shell completions
|
||||
pass_filenames: false
|
||||
language: system
|
||||
always_run: true
|
||||
entry: >
|
||||
sh -c '
|
||||
touch build.rs &&
|
||||
SHELL_COMPLETIONS_DIR=completions cargo build &&
|
||||
git add completions
|
||||
'
|
347
CHANGELOG.md
Normal file
347
CHANGELOG.md
Normal file
@ -0,0 +1,347 @@
|
||||
|
||||
## [1.3.3](https://github.com/wfxr/csview/compare/v1.3.2..v1.3.3) (2024-07-08)
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- Workaround error caused by pager env - ([988add5](https://github.com/wfxr/csview/commit/988add57b9de99c61140c68fd868ee8bec79f5a2))
|
||||
|
||||
## [1.3.2](https://github.com/wfxr/csview/compare/v1.3.1..v1.3.2) (2024-04-30)
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- Add aarch64-apple-darwin target - ([4481363](https://github.com/wfxr/csview/commit/448136378a3edab2e1669efab63cd81cde20a703))
|
||||
- Update completions for new option - ([3565cfe](https://github.com/wfxr/csview/commit/3565cfee2dd62c4a22f5752ec261aa0b628e0a4a))
|
||||
|
||||
## [1.3.1](https://github.com/wfxr/csview/compare/v1.3.0..v1.3.1) (2024-04-29)
|
||||
|
||||
### 🚀 Features
|
||||
|
||||
- Only enable pager when stdout is a tty - ([420fd03](https://github.com/wfxr/csview/commit/420fd0310db32d42315fc5dcb2b745a4c4cc6909))
|
||||
- Allow disabling pager - ([80ae054](https://github.com/wfxr/csview/commit/80ae054283d857814408d186643105b57f7c559d))
|
||||
|
||||
### 📚 Documentation
|
||||
|
||||
- Remove outdated faq - ([d814a38](https://github.com/wfxr/csview/commit/d814a389eec4a50ee6c0effc19ca601a37ff4395))
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- Remove stale.yml - ([d3ac13b](https://github.com/wfxr/csview/commit/d3ac13b72a6af52cc81ab4482c1db44670fdb307))
|
||||
|
||||
## [1.3.0](https://github.com/wfxr/csview/compare/v1.2.4..v1.3.0) (2024-04-15)
|
||||
|
||||
### 🚀 Features
|
||||
|
||||
- Add pager support ([#198](https://github.com/wfxr/csview/issues/198)) - ([47d3c0a](https://github.com/wfxr/csview/commit/47d3c0a61b6e605ff2ebb0cd4d8d9a60adf758e2))
|
||||
- Show error when no input file specified - ([1214c96](https://github.com/wfxr/csview/commit/1214c962a6ff2d20eb1bb67fff3c49053406ca5f))
|
||||
|
||||
### 🚜 Refactor
|
||||
|
||||
- Replace unmaintained `atty` ([#200](https://github.com/wfxr/csview/issues/200)) - ([d60612b](https://github.com/wfxr/csview/commit/d60612b669c41a2f4515f3a3cb067f3be185274e))
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- Update dependencies - ([b9aed24](https://github.com/wfxr/csview/commit/b9aed24bc46e725a6de1c761e3eee2c508ed5338))
|
||||
- Fix release.toml - ([8b28b89](https://github.com/wfxr/csview/commit/8b28b89824b54fd110f9b73a24d8d839e8db627b))
|
||||
- Add rust-toolchain.toml & update rustfmt.toml ([#201](https://github.com/wfxr/csview/issues/201)) - ([6fc99d4](https://github.com/wfxr/csview/commit/6fc99d432a9a0670430beef1f74e8da5c126e547))
|
||||
- Add changelog ([#199](https://github.com/wfxr/csview/issues/199)) - ([a15325d](https://github.com/wfxr/csview/commit/a15325d1ac8d9d90172247b76bb8e3cc734da6d8))
|
||||
- Add FUNDING.yml - ([0e6045f](https://github.com/wfxr/csview/commit/0e6045fb85d2ca748c7dfd7f4e075fce0641bfe1))
|
||||
|
||||
## [1.2.4](https://github.com/wfxr/csview/compare/v1.2.3..v1.2.4) (2024-03-04)
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- Update cicd config ([#191](https://github.com/wfxr/csview/issues/191)) - ([3ea5126](https://github.com/wfxr/csview/commit/3ea512652476364ab2afcbae37d9432ce7695192))
|
||||
|
||||
## [1.2.3](https://github.com/wfxr/csview/compare/v1.2.2..v1.2.3) (2024-02-22)
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- Cargo update - ([d903e78](https://github.com/wfxr/csview/commit/d903e78363b850686d2a878ab101fe50f0a6e875))
|
||||
- Update stale config - ([e39d5a9](https://github.com/wfxr/csview/commit/e39d5a9972d0e742490c068dcc49781ab761e0af))
|
||||
- Bump up dependencies - ([4e8034f](https://github.com/wfxr/csview/commit/4e8034fda7a2f212898196bf444ff7cf1229ca87))
|
||||
- Avoid unnecessary ci jobs - ([0cec5ca](https://github.com/wfxr/csview/commit/0cec5cab52cb3e21fc1a3c70830b205302833660))
|
||||
|
||||
## [1.2.2](https://github.com/wfxr/csview/compare/v1.2.1..v1.2.2) (2022-10-09)
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- Fix tests - ([9383041](https://github.com/wfxr/csview/commit/93830413d754f52b1ede1b7b0826f9e489720732))
|
||||
|
||||
### 🚜 Refactor
|
||||
|
||||
- Adjust error code - ([cf101e9](https://github.com/wfxr/csview/commit/cf101e951a59f482b8271debf7bcef52c6273105))
|
||||
- Simplify sniff logic - ([9df90a5](https://github.com/wfxr/csview/commit/9df90a547969bcd9b1695ed5c019dffb84d9c916))
|
||||
- Simplify seq logic - ([14c1c88](https://github.com/wfxr/csview/commit/14c1c88aac405bcd961d846a8949502499a65b12))
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- Upgrade clap to v4 - ([c0380e3](https://github.com/wfxr/csview/commit/c0380e306e272fa2cfd66d6394e2e643e1ac6f18))
|
||||
- Update stale config - ([4dc8ff1](https://github.com/wfxr/csview/commit/4dc8ff1b0692ba280b8dc8c9cd49f7c3712dfc59))
|
||||
- Refactor project layout - ([7b0c620](https://github.com/wfxr/csview/commit/7b0c62088e1179b0d160818c24a4baac5172d364))
|
||||
|
||||
## [1.2.1](https://github.com/wfxr/csview/compare/v1.2.0..v1.2.1) (2022-09-23)
|
||||
|
||||
### 🚜 Refactor
|
||||
|
||||
- Serialize enum in lowercase - ([1715587](https://github.com/wfxr/csview/commit/1715587a57fb27bf119fe959c5254ee5da21ab22))
|
||||
|
||||
## [1.2.0](https://github.com/wfxr/csview/compare/v1.1.0..v1.2.0) (2022-09-23)
|
||||
|
||||
### 🚀 Features
|
||||
|
||||
- Add alignment cli options - ([429eb5d](https://github.com/wfxr/csview/commit/429eb5d61cf23d5eee266dd06ee2559af280df6c))
|
||||
- Add alignment support - ([a01d227](https://github.com/wfxr/csview/commit/a01d2279f1b7b5ffccf04ee0da9a1398a6d30af8))
|
||||
- Add minimal ascii border style - ([0c5ff8e](https://github.com/wfxr/csview/commit/0c5ff8ecb85b50d3182af99891eac04b5cc55209))
|
||||
|
||||
### 📚 Documentation
|
||||
|
||||
- Update example - ([af43fc9](https://github.com/wfxr/csview/commit/af43fc9dc9ffee47425e75643aee4df8742927b0))
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- Bump up dependencies - ([d7ddc08](https://github.com/wfxr/csview/commit/d7ddc080fe2cdb5353b8372649e40dce30e5878e))
|
||||
|
||||
## [1.1.0](https://github.com/wfxr/csview/compare/v1.0.1..v1.1.0) (2022-07-02)
|
||||
|
||||
### 🚀 Features
|
||||
|
||||
- Support printing line numbers - ([95b31a5](https://github.com/wfxr/csview/commit/95b31a5700f6a4f460950f0f7baa89559d0c989b))
|
||||
|
||||
### 🚜 Refactor
|
||||
|
||||
- Fix cargo clippy warnings - ([5a1e6d9](https://github.com/wfxr/csview/commit/5a1e6d9e353313a1ebd86cd01e712458e4c94321))
|
||||
|
||||
### 📚 Documentation
|
||||
|
||||
- `csview` now in homebrew core repo - ([4fec934](https://github.com/wfxr/csview/commit/4fec9346aba10fc1b2ebfc797d83b8ce0f25a1ca))
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- Bump up dependencies - ([ba43992](https://github.com/wfxr/csview/commit/ba43992ed2e1d8087b2f9b0f9d7a5f315b04a4da))
|
||||
|
||||
## [1.0.1](https://github.com/wfxr/csview/compare/v1.0.0..v1.0.1) (2022-02-16)
|
||||
|
||||
### 📚 Documentation
|
||||
|
||||
- Update readme - ([84a8392](https://github.com/wfxr/csview/commit/84a839265227182467fafc9ef285fb289d0b0eea))
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- Remove unstable features - ([aca9261](https://github.com/wfxr/csview/commit/aca9261dd6d4e1f4245087537750b4969b82308f))
|
||||
|
||||
## [1.0.0](https://github.com/wfxr/csview/compare/v0.3.12..v1.0.0) (2022-02-16)
|
||||
|
||||
### 🚀 Features
|
||||
|
||||
- Change default style - ([2389b4a](https://github.com/wfxr/csview/commit/2389b4a75ce6b91c4188a375ba7bd6df98c3afaa))
|
||||
- Remove completion sub command - ([d29caba](https://github.com/wfxr/csview/commit/d29cababf42f9b930ef08a3af7b46eb47d78a4e6))
|
||||
- Add sniff limit option - ([56b4858](https://github.com/wfxr/csview/commit/56b485830165f8a093646b602cde55a37585e0cb))
|
||||
- Add padding and indent option - ([40d7085](https://github.com/wfxr/csview/commit/40d7085479eefe166b56858f19f62df83f0c34e6))
|
||||
- Skip title sep when there is no data - ([d53caa5](https://github.com/wfxr/csview/commit/d53caa5675094c33a673208f9ad26193058af781))
|
||||
- Replace `prettytable-rs` - ([081d965](https://github.com/wfxr/csview/commit/081d9658a038efea94ffc34f85d6903dac1f4ae4))
|
||||
- Implement table writer - ([9fdb7a6](https://github.com/wfxr/csview/commit/9fdb7a6903f0c6c85caea8990ad618893c8ca170))
|
||||
|
||||
### 🚜 Refactor
|
||||
|
||||
- Rename & clean derive traits - ([d77a5b0](https://github.com/wfxr/csview/commit/d77a5b0fe5b10ebd9900c392585b314b0f1d09b2))
|
||||
- Remove cell - ([46bd2c4](https://github.com/wfxr/csview/commit/46bd2c414778b44155c20e778cba88c5784f978d))
|
||||
- Lint - ([cf5f340](https://github.com/wfxr/csview/commit/cf5f3406175fefc8a255af2b3fee6f658d146e1b))
|
||||
- Rename - ([573e297](https://github.com/wfxr/csview/commit/573e297c52695d12a61a9faec2e4bac946cadceb))
|
||||
- Remove redundant enums - ([863c97e](https://github.com/wfxr/csview/commit/863c97e74cd4f1f1b08711fe77e63b39b2d0a37c))
|
||||
- Rename - ([d6b336a](https://github.com/wfxr/csview/commit/d6b336a4c910e26563c4877fe809110c47cbc226))
|
||||
- Tweak cli options - ([b574e79](https://github.com/wfxr/csview/commit/b574e79b7b7d055ccd515a0ffa19ce4515a8e80c))
|
||||
|
||||
### 📚 Documentation
|
||||
|
||||
- Update default style - ([bab68ce](https://github.com/wfxr/csview/commit/bab68ce17c106ffea523b522116a100132dad33a))
|
||||
- Fix time unit - ([b21642c](https://github.com/wfxr/csview/commit/b21642c5c550af87311bfc2e7ff78049d979f933))
|
||||
- Update - ([4d4461e](https://github.com/wfxr/csview/commit/4d4461e3ffec65dd2be0d6f1c87f6bd1b2c43fad))
|
||||
- Update - ([a83ad55](https://github.com/wfxr/csview/commit/a83ad555539bbe6a0e0768c01f9d0600f3bdc0cb))
|
||||
|
||||
### ⚡ Performance
|
||||
|
||||
- Add buffer on writer - ([86c6101](https://github.com/wfxr/csview/commit/86c610119d506b0a09453c5f3b3a3a1223ae5cca))
|
||||
- Remove unnecessary buffer - ([ffc59ca](https://github.com/wfxr/csview/commit/ffc59ca90e2aa2c1fdcdc1c20e9114e693dc5c71))
|
||||
|
||||
### 🧪 Testing
|
||||
|
||||
- Add no padding test - ([ca15128](https://github.com/wfxr/csview/commit/ca15128b1b2a0ec60e3f1e043946f87cbd96bb36))
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- Bump up version - ([8cd76c7](https://github.com/wfxr/csview/commit/8cd76c73a75d0db1db7687d131d54d398f5b2967))
|
||||
- NextLineHelp - ([cb795c9](https://github.com/wfxr/csview/commit/cb795c95a8ba941e32127798ab515059b2f6d33b))
|
||||
- Switched to nightly rust - ([abb2300](https://github.com/wfxr/csview/commit/abb23008218c103cb6afba38c1381181b2d79908))
|
||||
|
||||
## [0.3.11](https://github.com/wfxr/csview/compare/v0.3.10..v0.3.11) (2022-01-01)
|
||||
|
||||
### 🚜 Refactor
|
||||
|
||||
- Misc - ([35bca57](https://github.com/wfxr/csview/commit/35bca57f605fa825d56d965eff1c7ea200d5c570))
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- Update dependabot config - ([2d2cc6d](https://github.com/wfxr/csview/commit/2d2cc6d1ab09ac5349de0e426a6fc60ee267826c))
|
||||
- Clap v3 - ([569552b](https://github.com/wfxr/csview/commit/569552b57c5c5d922885aeeec515c67156b6c5ad))
|
||||
|
||||
## [0.3.10](https://github.com/wfxr/csview/compare/v0.3.9..v0.3.10) (2021-12-26)
|
||||
|
||||
### 🚀 Features
|
||||
|
||||
- Upgrade cli - ([2b40db4](https://github.com/wfxr/csview/commit/2b40db482fbe9b86fff74618590154941dd21939))
|
||||
|
||||
### 📚 Documentation
|
||||
|
||||
- Update - ([7934cf7](https://github.com/wfxr/csview/commit/7934cf758b268c7dde0caa1b91d8b503414b18ff))
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- Add rustfmt.toml - ([a0b9025](https://github.com/wfxr/csview/commit/a0b9025e930dbd947363e0149c0ffaa3332280e4))
|
||||
|
||||
### Typo
|
||||
|
||||
- Misc - ([ce696ba](https://github.com/wfxr/csview/commit/ce696ba7ff2b89680b7bc4b9bb5bb145a86872f5))
|
||||
|
||||
## [0.3.9](https://github.com/wfxr/csview/compare/v0.3.8..v0.3.9) (2021-11-23)
|
||||
|
||||
### 🚜 Refactor
|
||||
|
||||
- Clippy lint - ([f36edb1](https://github.com/wfxr/csview/commit/f36edb1bdd49c6916d76d3f3687e4cde876c58e6))
|
||||
|
||||
### 📚 Documentation
|
||||
|
||||
- Add pkgsrc installation. - ([9888062](https://github.com/wfxr/csview/commit/9888062d1b58de4f5a11ed05970c809dcab012a7))
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- Update license - ([a1de726](https://github.com/wfxr/csview/commit/a1de726f18fd22de1c4d4111a56aee2328262b75))
|
||||
- Update ci config - ([33b2b94](https://github.com/wfxr/csview/commit/33b2b946833952eeda82fa04d6d92888f4434843))
|
||||
- Update linguist - ([a82edc9](https://github.com/wfxr/csview/commit/a82edc94c48ceab598bbf510481544763e0990e1))
|
||||
- Upgrade pre-commit version - ([26fe3d8](https://github.com/wfxr/csview/commit/26fe3d86b9bdf4e1497f3deb28d21677402cae03))
|
||||
- Upgrade to 2021 edition - ([0035c2e](https://github.com/wfxr/csview/commit/0035c2e6c636fc574e589dc5b00bfb6b0e5db3e0))
|
||||
|
||||
## [0.3.8](https://github.com/wfxr/csview/compare/v0.3.7..v0.3.8) (2021-04-05)
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- Fix output when table is empty ([#8](https://github.com/wfxr/csview/issues/8)) - ([2fbe3fd](https://github.com/wfxr/csview/commit/2fbe3fd051babe2531bae92f6cca6a495841676e))
|
||||
|
||||
## [0.3.7](https://github.com/wfxr/csview/compare/v0.3.6..v0.3.7) (2021-03-19)
|
||||
|
||||
### 🚜 Refactor
|
||||
|
||||
- Improve error handling - ([67f7b44](https://github.com/wfxr/csview/commit/67f7b44dfa139ba56e24cf0b48001487fddfb0a9))
|
||||
- Error handling - ([b6c38ec](https://github.com/wfxr/csview/commit/b6c38ecd7f2060f5b906282324725f400ec8e26d))
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- Add dependabot - ([f5e5920](https://github.com/wfxr/csview/commit/f5e5920677a5f4fc8317f0fc77645de681c68ea1))
|
||||
|
||||
## [0.3.6](https://github.com/wfxr/csview/compare/v0.3.5..v0.3.6) (2021-02-07)
|
||||
|
||||
### 🚜 Refactor
|
||||
|
||||
- Minor refactor & bump up dependencies - ([6edd84e](https://github.com/wfxr/csview/commit/6edd84e90056949916797b25f5aae56ddac8ed37))
|
||||
|
||||
### 📚 Documentation
|
||||
|
||||
- Add install description for windows - ([06b3006](https://github.com/wfxr/csview/commit/06b3006971066b77a516b8c2e90ef4c306f6a781))
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- Add .gitattributes - ([ca098b0](https://github.com/wfxr/csview/commit/ca098b0e5f9de1dd65993916220e683e9f131a13))
|
||||
- Update clippy hook - ([2aafe79](https://github.com/wfxr/csview/commit/2aafe7941bdc50e33a0d5d5d1427f1828e58b77b))
|
||||
|
||||
## [0.3.5](https://github.com/wfxr/csview/compare/v0.3.4..v0.3.5) (2020-09-23)
|
||||
|
||||
### 🚀 Features
|
||||
|
||||
- Add grid style - ([3b758a9](https://github.com/wfxr/csview/commit/3b758a9a406bede7e921dcb7c716ff3e2a5ac2b2))
|
||||
|
||||
### 📚 Documentation
|
||||
|
||||
- Add macOS installation - ([985d643](https://github.com/wfxr/csview/commit/985d6439c9d79ac648e9930ee87895193d0550b7))
|
||||
- Fix table indent in README - ([5356a4d](https://github.com/wfxr/csview/commit/5356a4d462c4ffb85f3bb162bef192c5a0787d40))
|
||||
- Add arch linux installation - ([e0c178b](https://github.com/wfxr/csview/commit/e0c178b8f39b46b9a8dfdd9ba35e3f64206ac4ae))
|
||||
|
||||
## [0.3.4](https://github.com/wfxr/csview/compare/v0.3.3..v0.3.4) (2020-09-19)
|
||||
|
||||
### 🚜 Refactor
|
||||
|
||||
- Use exit code defined in sysexits.h - ([c52153e](https://github.com/wfxr/csview/commit/c52153e9f1c187953c663ee0e90c12bcc0d1c38c))
|
||||
|
||||
### 📚 Documentation
|
||||
|
||||
- Misc - ([177f555](https://github.com/wfxr/csview/commit/177f555f17aff140319388b3ba57308a2ee47499))
|
||||
- Add installation section - ([320fd43](https://github.com/wfxr/csview/commit/320fd435f97206dffafe2238af99689e1e1b16df))
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- Remove duplicated hooks - ([a0e3ca3](https://github.com/wfxr/csview/commit/a0e3ca3e85c0cab427eba54fcac7eae5a068cfc4))
|
||||
- Words - ([5691214](https://github.com/wfxr/csview/commit/5691214a66abf188e6c77f6a568dcddcc4947477))
|
||||
- Add probot-stale config - ([2f036c2](https://github.com/wfxr/csview/commit/2f036c25082e1e2eab1fc3577b3730e858302210))
|
||||
- Add issue/pr templates - ([4b1ba13](https://github.com/wfxr/csview/commit/4b1ba136ad9d5a537987d0cdec88eee64c9a8a6b))
|
||||
|
||||
## [0.3.3](https://github.com/wfxr/csview/compare/v0.3.2..v0.3.3) (2020-09-19)
|
||||
|
||||
### 🚜 Refactor
|
||||
|
||||
- Improve error handling ([#2](https://github.com/wfxr/csview/issues/2)) - ([511ac52](https://github.com/wfxr/csview/commit/511ac52313df9aa409a9f48142fb108d72ebb26a))
|
||||
|
||||
### 📚 Documentation
|
||||
|
||||
- Add credits section - ([a037d45](https://github.com/wfxr/csview/commit/a037d455327d41d25fd15e3a27fc989d1560f024))
|
||||
- Add features section - ([7cf4aa6](https://github.com/wfxr/csview/commit/7cf4aa6ae126bbc117babd04f358beddd21fb4fc))
|
||||
- Add faq section - ([841bd55](https://github.com/wfxr/csview/commit/841bd55c63a5dc7e826ba4408192afb4f89c3710))
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- Add about message - ([a2b2f9d](https://github.com/wfxr/csview/commit/a2b2f9dc50705c9fa19862e2b9501d6a2578240f))
|
||||
|
||||
### Lint
|
||||
|
||||
- Cargo clippy - ([b1cb104](https://github.com/wfxr/csview/commit/b1cb104788062bc0e88c105eee5cb9275bbc8362))
|
||||
|
||||
## [0.3.2](https://github.com/wfxr/csview/compare/v0.3.1..v0.3.2) (2020-09-18)
|
||||
|
||||
### 🚀 Features
|
||||
|
||||
- Add markdown style - ([9fb038e](https://github.com/wfxr/csview/commit/9fb038e09e5501a7d5e51a704b99467f532dc18e))
|
||||
|
||||
### 📚 Documentation
|
||||
|
||||
- Fix crates badge - ([a24e2be](https://github.com/wfxr/csview/commit/a24e2be7391029a1947c1e06565bd2f46341526b))
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- Fix a typo ([#1](https://github.com/wfxr/csview/issues/1)) - ([a5e2e39](https://github.com/wfxr/csview/commit/a5e2e3998472f70b523bbc4886f932fea960b7a9))
|
||||
|
||||
## [0.3.1](https://github.com/wfxr/csview/compare/v0.3.0..v0.3.1) (2020-09-17)
|
||||
|
||||
### 📚 Documentation
|
||||
|
||||
- Add more descriptions - ([113609f](https://github.com/wfxr/csview/commit/113609f0590190dffcad799fa9862a1b0b9012e0))
|
||||
- Update readme - ([74c07f4](https://github.com/wfxr/csview/commit/74c07f419435ac7dbc5f87422695db787cd42c7d))
|
||||
- Update readme - ([906c747](https://github.com/wfxr/csview/commit/906c7474df7bd0860d4d72f35a1714a2fb76c46e))
|
||||
- Update help messages - ([1d48b23](https://github.com/wfxr/csview/commit/1d48b23eb18d52d2efe5bfb3236682a859a7ad1c))
|
||||
|
||||
## [0.3.0] - 2020-09-17
|
||||
|
||||
### 🚀 Features
|
||||
|
||||
- Show possible values for shells - ([c2bbcbc](https://github.com/wfxr/csview/commit/c2bbcbca944d3fc27bd76314ae7ffed72c24d504))
|
||||
- Support border style - ([7be10ae](https://github.com/wfxr/csview/commit/7be10ae0148170e7ac6c3eca0797f9ae2bf83906))
|
||||
- Support tsv - ([d53fb02](https://github.com/wfxr/csview/commit/d53fb02bffab217b5cd1c55ff14defe694c73ded))
|
||||
- Add delimeter support - ([cc9a1b0](https://github.com/wfxr/csview/commit/cc9a1b075e5942e1c36f5b62077595263705c5fb))
|
||||
- Use prettytable to print - ([751980c](https://github.com/wfxr/csview/commit/751980cab7be9d9e4c4079835bb5b9a1b7ca30e7))
|
||||
|
||||
### 🚜 Refactor
|
||||
|
||||
- Remove update command - ([3002149](https://github.com/wfxr/csview/commit/300214906649498b9713ebaa69cea7128ad43220))
|
||||
|
||||
### ⚙️ Miscellaneous Tasks
|
||||
|
||||
- Add pre-commit hooks - ([cbc60d4](https://github.com/wfxr/csview/commit/cbc60d42287aef1e225961c33ff9a97f3a1c0a6d))
|
||||
- Ci & cd - ([985bd1e](https://github.com/wfxr/csview/commit/985bd1e2b9255e9a58709a376b7ce1b99f4f1fca))
|
||||
|
||||
<!-- generated by git-cliff -->
|
533
Cargo.lock
generated
Normal file
533
Cargo.lock
generated
Normal file
@ -0,0 +1,533 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648"
|
||||
dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.89"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.94"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17f6e324229dc011159fcc089755d1e2e216a90d43a7dea6853ca740b84f35e7"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e5a21b8495e732f1b3c364c9949b201ca7bae518c502c80256c96ad79eaf6ac"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8cf2dd12af7a047ad9d6da2b6b249759a22a7abc0f474c1dae1777afa4b21a73"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
"terminal_size",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_complete"
|
||||
version = "4.5.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "205d5ef6d485fa47606b98b0ddc4ead26eb850aaa86abfb562a94fb3280ecba0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||
|
||||
[[package]]
|
||||
name = "csv"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe"
|
||||
dependencies = [
|
||||
"csv-core",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "csv-core"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "csview"
|
||||
version = "1.3.3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"clap_complete",
|
||||
"csv",
|
||||
"exitcode",
|
||||
"itertools",
|
||||
"pager",
|
||||
"unicode-truncate",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
|
||||
dependencies = [
|
||||
"errno-dragonfly",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno-dragonfly"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "exitcode"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de853764b47027c2e862a995c34978ffa63c1501f2e15f987ba11bd4f9bba193"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.153"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
|
||||
|
||||
[[package]]
|
||||
name = "pager"
|
||||
version = "0.16.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2599211a5c97fbbb1061d3dc751fa15f404927e4846e07c643287d6d1f462880"
|
||||
dependencies = [
|
||||
"errno 0.2.8",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.80"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a56dea16b0a29e94408b9aa5e2940a4eedbd128a1ba20e8f7ae60fd3d465af0e"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno 0.3.8",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.197"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.197"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.59"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a6531ffc7b071655e4ce2e04bd464c4830bb585a61cabb96cf808f05172615a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "terminal_size"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7"
|
||||
dependencies = [
|
||||
"rustix",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-truncate"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"unicode-segmentation",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||
dependencies = [
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.48.5",
|
||||
"windows_aarch64_msvc 0.48.5",
|
||||
"windows_i686_gnu 0.48.5",
|
||||
"windows_i686_msvc 0.48.5",
|
||||
"windows_x86_64_gnu 0.48.5",
|
||||
"windows_x86_64_gnullvm 0.48.5",
|
||||
"windows_x86_64_msvc 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.52.5",
|
||||
"windows_aarch64_msvc 0.52.5",
|
||||
"windows_i686_gnu 0.52.5",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc 0.52.5",
|
||||
"windows_x86_64_gnu 0.52.5",
|
||||
"windows_x86_64_gnullvm 0.52.5",
|
||||
"windows_x86_64_msvc 0.52.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
|
37
Cargo.toml
Normal file
37
Cargo.toml
Normal file
@ -0,0 +1,37 @@
|
||||
[package]
|
||||
name = "csview"
|
||||
version = "1.3.3"
|
||||
authors = ["Wenxuan Zhang <wenxuangm@gmail.com>"]
|
||||
description = "A high performance csv viewer with cjk/emoji support."
|
||||
categories = ["command-line-utilities"]
|
||||
homepage = "https://github.com/wfxr/csview"
|
||||
keywords = ["csv", "pager", "viewer", "tool"]
|
||||
readme = "README.md"
|
||||
license = "MIT OR Apache-2.0"
|
||||
exclude = ["/completions"]
|
||||
repository = "https://github.com/wfxr/csview"
|
||||
edition = "2021"
|
||||
build = "build.rs"
|
||||
|
||||
[features]
|
||||
default = ["pager"]
|
||||
pager = ["dep:pager"]
|
||||
|
||||
[dependencies]
|
||||
csv = "1.3"
|
||||
clap = { version = "4", features = ["wrap_help", "derive"] }
|
||||
exitcode = "1.1"
|
||||
anyhow = "1.0"
|
||||
unicode-width = "0"
|
||||
unicode-truncate = "1.1"
|
||||
itertools = "0.13"
|
||||
[target.'cfg(target_family = "unix")'.dependencies]
|
||||
pager = { version = "0.16", optional = true }
|
||||
|
||||
[build-dependencies]
|
||||
clap = { version = "4", features = ["wrap_help", "derive"] }
|
||||
clap_complete = "4"
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
codegen-units = 1
|
1
FUNDING.yml
Normal file
1
FUNDING.yml
Normal file
@ -0,0 +1 @@
|
||||
ko_fi: wfxr
|
201
LICENSE-APACHE
Normal file
201
LICENSE-APACHE
Normal file
@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
19
LICENSE-MIT
Normal file
19
LICENSE-MIT
Normal file
@ -0,0 +1,19 @@
|
||||
Copyright (c) 2020 Wenxuan Zhang (https://wfxr.mit-license.org/2020).
|
||||
|
||||
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.
|
190
README.md
Normal file
190
README.md
Normal file
@ -0,0 +1,190 @@
|
||||
<h1 align="center">📠 csview</h1>
|
||||
<p align="center">
|
||||
<em>A high performance csv viewer with cjk/emoji support.</em>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/wfxr/csview/actions?query=workflow%3ACICD">
|
||||
<img src="https://github.com/wfxr/csview/workflows/CICD/badge.svg" alt="CICD"/>
|
||||
</a>
|
||||
<img src="https://img.shields.io/crates/l/csview.svg" alt="License"/>
|
||||
<a href="https://crates.io/crates/csview">
|
||||
<img src="https://img.shields.io/crates/v/csview.svg?colorB=319e8c" alt="Version">
|
||||
</a>
|
||||
<a href="https://github.com/wfxr/csview/releases">
|
||||
<img src="https://img.shields.io/badge/platform-%20Linux%20|%20OSX%20|%20Win%20|%20ARM-orange.svg" alt="Platform"/>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<img src="https://raw.githubusercontent.com/wfxr/i/master/csview-screenshot.png" />
|
||||
|
||||
### Features
|
||||
|
||||
* Small and *fast* (see [benchmarks](#benchmark) below).
|
||||
* Memory efficient.
|
||||
* Correctly align [CJK](https://en.wikipedia.org/wiki/CJK_characters) and emoji characters.
|
||||
* Support `tsv` and custom delimiters.
|
||||
* Support different styles, including markdown table.
|
||||
|
||||
### Usage
|
||||
```
|
||||
$ cat example.csv
|
||||
Year,Make,Model,Description,Price
|
||||
1997,Ford,E350,"ac, abs, moon",3000.00
|
||||
1999,Chevy,"Venture ""Extended Edition""","",4900.00
|
||||
1999,Chevy,"Venture ""Extended Edition, Large""",,5000.00
|
||||
1996,Jeep,Grand Cherokee,"MUST SELL! air, moon roof",4799.00
|
||||
|
||||
$ csview example.csv
|
||||
┌──────┬───────┬───────────────────────────────────┬───────────────────────────┬─────────┐
|
||||
│ Year │ Make │ Model │ Description │ Price │
|
||||
├──────┼───────┼───────────────────────────────────┼───────────────────────────┼─────────┤
|
||||
│ 1997 │ Ford │ E350 │ ac, abs, moon │ 3000.00 │
|
||||
│ 1999 │ Chevy │ Venture "Extended Edition" │ │ 4900.00 │
|
||||
│ 1999 │ Chevy │ Venture "Extended Edition, Large" │ │ 5000.00 │
|
||||
│ 1996 │ Jeep │ Grand Cherokee │ MUST SELL! air, moon roof │ 4799.00 │
|
||||
└──────┴───────┴───────────────────────────────────┴───────────────────────────┴─────────┘
|
||||
|
||||
$ head /etc/passwd | csview -H -d:
|
||||
┌────────────────────────┬───┬───────┬───────┬────────────────────────────┬─────────────────┐
|
||||
│ root │ x │ 0 │ 0 │ │ /root │
|
||||
│ bin │ x │ 1 │ 1 │ │ / │
|
||||
│ daemon │ x │ 2 │ 2 │ │ / │
|
||||
│ mail │ x │ 8 │ 12 │ │ /var/spool/mail │
|
||||
│ ftp │ x │ 14 │ 11 │ │ /srv/ftp │
|
||||
│ http │ x │ 33 │ 33 │ │ /srv/http │
|
||||
│ nobody │ x │ 65534 │ 65534 │ Nobody │ / │
|
||||
│ dbus │ x │ 81 │ 81 │ System Message Bus │ / │
|
||||
│ systemd-journal-remote │ x │ 981 │ 981 │ systemd Journal Remote │ / │
|
||||
│ systemd-network │ x │ 980 │ 980 │ systemd Network Management │ / │
|
||||
└────────────────────────┴───┴───────┴───────┴────────────────────────────┴─────────────────┘
|
||||
```
|
||||
|
||||
Run `csview --help` to view detailed usage.
|
||||
|
||||
### Installation
|
||||
|
||||
#### On Arch Linux
|
||||
|
||||
`csview` is available in the Arch User Repository. To install it from [AUR](https://aur.archlinux.org/packages/csview):
|
||||
|
||||
```
|
||||
yay -S csview
|
||||
```
|
||||
|
||||
#### On macOS
|
||||
|
||||
You can install `csview` with Homebrew:
|
||||
|
||||
```
|
||||
brew install csview
|
||||
```
|
||||
|
||||
#### On NetBSD
|
||||
|
||||
`csview` is available from the main pkgsrc Repositories. To install simply run
|
||||
|
||||
```
|
||||
pkgin install csview
|
||||
```
|
||||
|
||||
or, if you prefer to build from source using [pkgsrc](https://pkgsrc.se/textproc/csview) on any of the supported platforms:
|
||||
|
||||
```
|
||||
cd /usr/pkgsrc/textproc/csview
|
||||
make install
|
||||
```
|
||||
|
||||
#### On Windows
|
||||
|
||||
You can install `csview` with [Scoop](https://scoop.sh/):
|
||||
```
|
||||
scoop install csview
|
||||
```
|
||||
|
||||
#### From binaries
|
||||
|
||||
Pre-built versions of `csview` for various architectures are available at [Github release page](https://github.com/wfxr/csview/releases).
|
||||
|
||||
*Note that you can try the `musl` version (which is statically-linked) if runs into dependency related errors.*
|
||||
|
||||
#### From source
|
||||
|
||||
`csview` is also published on [crates.io](https://crates.io). If you have latest Rust toolchains installed you can use `cargo` to install it from source:
|
||||
|
||||
```
|
||||
cargo install --locked csview
|
||||
```
|
||||
|
||||
If you want the latest version, clone this repository and run `cargo build --release`.
|
||||
|
||||
### Benchmark
|
||||
|
||||
- [small.csv](https://gist.github.com/wfxr/567e890d4db508b3c7630a96b703a57e#file-action-csv) (10 rows, 4 cols, 695 bytes):
|
||||
|
||||
| Tool | Command | Mean Time | Min Time | Memory |
|
||||
|:----------------------------------------------------------------------------------------:|---------------------------|----------:|----------:|----------:|
|
||||
| [xsv](https://github.com/BurntSushi/xsv/tree/0.13.0) | `xsv table small.csv` | 2.0ms | 1.8ms | 3.9mb |
|
||||
| [csview](https://github.com/wfxr/csview/tree/90ff90e26c3e4c4c37818d717555b3e8f90d27e3) | `csview small.csv` | **0.3ms** | **0.1ms** | **2.4mb** |
|
||||
| [column](https://github.com/util-linux/util-linux/blob/stable/v2.37/text-utils/column.c) | `column -s, -t small.csv` | 1.3ms | 1.1ms | **2.4mb** |
|
||||
| [csvlook](https://github.com/wireservice/csvkit/tree/1.0.6) | `csvlook small.csv` | 148.1ms | 142.4ms | 27.3mb |
|
||||
|
||||
- [medium.csv](https://gist.github.com/wfxr/567e890d4db508b3c7630a96b703a57e#file-sample-csv) (10,000 rows, 10 cols, 624K bytes):
|
||||
|
||||
| Tool | Command | Mean Time | Min Time | Memory |
|
||||
|:----------------------------------------------------------------------------------------:|---------------------------|-----------:|-----------:|----------:|
|
||||
| [xsv](https://github.com/BurntSushi/xsv/tree/0.13.0) | `xsv table medium.csv` | 0.031s | 0.029s | 4.4mb |
|
||||
| [csview](https://github.com/wfxr/csview/tree/90ff90e26c3e4c4c37818d717555b3e8f90d27e3) | `csview medium.csv` | **0.017s** | **0.016s** | **2.8mb** |
|
||||
| [column](https://github.com/util-linux/util-linux/blob/stable/v2.37/text-utils/column.c) | `column -s, -t small.csv` | 0.052s | 0.050s | 9.9mb |
|
||||
| [csvlook](https://github.com/wireservice/csvkit/tree/1.0.6) | `csvlook medium.csv` | 2.664s | 2.617s | 46.8mb |
|
||||
|
||||
- `large.csv` (1,000,000 rows, 10 cols, 61M bytes, generated by concatenating [medium.csv](https://gist.github.com/wfxr/567e890d4db508b3c7630a96b703a57e#file-sample-csv) 100 times):
|
||||
|
||||
| Tool | Command | Mean Time | Min Time | Memory |
|
||||
|:----------------------------------------------------------------------------------------:|---------------------------|-----------:|-----------:|----------:|
|
||||
| [xsv](https://github.com/BurntSushi/xsv/tree/0.13.0) | `xsv table large.csv` | 2.912s | 2.820s | 4.4mb |
|
||||
| [csview](https://github.com/wfxr/csview/tree/90ff90e26c3e4c4c37818d717555b3e8f90d27e3) | `csview large.csv` | **1.686s** | **1.665s** | **2.8mb** |
|
||||
| [column](https://github.com/util-linux/util-linux/blob/stable/v2.37/text-utils/column.c) | `column -s, -t small.csv` | 5.777s | 5.759s | 767.6mb |
|
||||
| [csvlook](https://github.com/wireservice/csvkit/tree/1.0.6) | `csvlook large.csv` | 20.665s | 20.549s | 1105.7mb |
|
||||
|
||||
### F.A.Q.
|
||||
|
||||
---
|
||||
#### We already have [xsv](https://github.com/BurntSushi/xsv), why not contribute to it but build a new tool?
|
||||
|
||||
`xsv` is great. But it's aimed for analyzing and manipulating csv data.
|
||||
`csview` is designed for formatting and viewing. See also: [xsv/issues/156](https://github.com/BurntSushi/xsv/issues/156)
|
||||
|
||||
---
|
||||
#### I encountered UTF-8 related errors, how to solve it?
|
||||
|
||||
The file may use a non-UTF8 encoding. You can check the file encoding using `file` command:
|
||||
|
||||
```
|
||||
$ file -i a.csv
|
||||
a.csv: application/csv; charset=iso-8859-1
|
||||
```
|
||||
And then convert it to `utf8`:
|
||||
|
||||
```
|
||||
$ iconv -f iso-8859-1 -t UTF8//TRANSLIT a.csv -o b.csv
|
||||
$ csview b.csv
|
||||
```
|
||||
|
||||
Or do it in place:
|
||||
|
||||
```
|
||||
$ iconv -f iso-8859-1 -t UTF8//TRANSLIT a.csv | csview
|
||||
```
|
||||
|
||||
### Credits
|
||||
|
||||
* [csv-rust](https://github.com/BurntSushi/rust-csv)
|
||||
* [prettytable-rs](https://github.com/phsym/prettytable-rs)
|
||||
* [structopt](https://github.com/TeXitoi/structopt)
|
||||
|
||||
### License
|
||||
|
||||
`csview` is distributed under the terms of both the MIT License and the Apache License 2.0.
|
||||
|
||||
See the [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT) files for license details.
|
20
build.rs
Normal file
20
build.rs
Normal file
@ -0,0 +1,20 @@
|
||||
use clap::CommandFactory;
|
||||
use clap_complete::Shell;
|
||||
use std::{fs, path::Path};
|
||||
|
||||
include!("src/cli.rs");
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let outdir = std::env::var_os("SHELL_COMPLETIONS_DIR")
|
||||
.or_else(|| std::env::var_os("OUT_DIR"))
|
||||
.expect("OUT_DIR not found");
|
||||
let outdir_path = Path::new(&outdir);
|
||||
let app = &mut App::command();
|
||||
|
||||
for shell in Shell::value_variants() {
|
||||
let dir = outdir_path.join(shell.to_string());
|
||||
fs::create_dir_all(&dir)?;
|
||||
clap_complete::generate_to(*shell, app, app.get_name().to_string(), &dir)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
107
cliff.toml
Normal file
107
cliff.toml
Normal file
@ -0,0 +1,107 @@
|
||||
# git-cliff ~ configuration file
|
||||
# https://git-cliff.org/docs/configuration
|
||||
#
|
||||
# Lines starting with "#" are comments.
|
||||
# Configuration options are organized into tables and keys.
|
||||
# See documentation for more information on available options.
|
||||
|
||||
[changelog]
|
||||
# changelog header
|
||||
header = """
|
||||
"""
|
||||
# template for the changelog body
|
||||
# https://keats.github.io/tera/docs/#introduction
|
||||
body = """
|
||||
{%- macro remote_url() -%}
|
||||
https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}
|
||||
{%- endmacro -%}
|
||||
|
||||
{% macro print_commit(commit) -%}
|
||||
- {% if commit.scope %}*({{ commit.scope }})* {% endif %}\
|
||||
{% if commit.breaking %}[**breaking**] {% endif %}\
|
||||
{{ commit.message | upper_first }} - \
|
||||
([{{ commit.id | truncate(length=7, end="") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))\
|
||||
{% endmacro -%}
|
||||
|
||||
{% if version %}\
|
||||
{% if previous.version %}\
|
||||
## [{{ version | trim_start_matches(pat="v") }}]\
|
||||
({{ self::remote_url() }}/compare/{{ previous.version }}..{{ version }}) ({{ timestamp | date(format="%Y-%m-%d") }})
|
||||
{% else %}\
|
||||
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
|
||||
{% endif %}\
|
||||
{% else %}\
|
||||
## [unreleased]
|
||||
{% endif %}\
|
||||
|
||||
{% for group, commits in commits | group_by(attribute="group") %}
|
||||
### {{ group | striptags | trim | upper_first }}
|
||||
{% for commit in commits
|
||||
| filter(attribute="scope")
|
||||
| sort(attribute="scope") %}
|
||||
{{ self::print_commit(commit=commit) }}
|
||||
{%- endfor -%}
|
||||
{% raw %}\n{% endraw %}\
|
||||
{%- for commit in commits %}
|
||||
{%- if not commit.scope -%}
|
||||
{{ self::print_commit(commit=commit) }}
|
||||
{% endif -%}
|
||||
{% endfor -%}
|
||||
{% endfor %}\n
|
||||
"""
|
||||
# template for the changelog footer
|
||||
footer = """
|
||||
<!-- generated by git-cliff -->
|
||||
"""
|
||||
# remove the leading and trailing whitespace from the templates
|
||||
trim = true
|
||||
# postprocessors
|
||||
postprocessors = [
|
||||
{ pattern = '<REPO>', replace = "https://github.com/wfxr/csview" }, # replace repository URL
|
||||
]
|
||||
|
||||
[git]
|
||||
# parse the commits based on https://www.conventionalcommits.org
|
||||
conventional_commits = true
|
||||
# filter out the commits that are not conventional
|
||||
filter_unconventional = true
|
||||
# process each line of a commit as an individual commit
|
||||
split_commits = false
|
||||
# regex for preprocessing the commit messages
|
||||
commit_preprocessors = [
|
||||
{ pattern = ' (#[0-9]+)', replace = '(${1})' },
|
||||
{ pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](<REPO>/issues/${2}))" },
|
||||
]
|
||||
# regex for parsing and grouping commits
|
||||
commit_parsers = [
|
||||
{ message = "^feat", group = "<!-- 0 -->🚀 Features" },
|
||||
{ message = "^fix", group = "<!-- 1 -->🐛 Bug Fixes" },
|
||||
{ message = "^doc", group = "<!-- 3 -->📚 Documentation" },
|
||||
{ message = "^perf", group = "<!-- 4 -->⚡ Performance" },
|
||||
{ message = "^refactor\\(clippy\\)", skip = true },
|
||||
{ message = "^refactor", group = "<!-- 2 -->🚜 Refactor" },
|
||||
{ message = "^style", group = "<!-- 5 -->🎨 Styling" },
|
||||
{ message = "^test", group = "<!-- 6 -->🧪 Testing" },
|
||||
{ message = "^chore: [rR]elease", skip = true },
|
||||
{ message = "^\\(cargo-release\\)", skip = true },
|
||||
{ message = "^chore\\(deps.*\\)", skip = true },
|
||||
{ message = "^chore\\(pr\\)", skip = true },
|
||||
{ message = "^chore\\(pull\\)", skip = true },
|
||||
{ message = "^chore|^ci", group = "<!-- 7 -->⚙️ Miscellaneous Tasks" },
|
||||
{ body = ".*security", group = "<!-- 8 -->🛡️ Security" },
|
||||
{ message = "^revert", group = "<!-- 9 -->◀️ Revert" },
|
||||
]
|
||||
# protect breaking changes from being skipped due to matching a skipping commit_parser
|
||||
protect_breaking_commits = false
|
||||
# filter out the commits that are not matched by commit parsers
|
||||
filter_commits = false
|
||||
# regex for matching git tags
|
||||
tag_pattern = "v[0-9].*"
|
||||
# regex for skipping tags
|
||||
skip_tags = "beta|alpha"
|
||||
# regex for ignoring tags
|
||||
ignore_tags = "rc|v2.1.0|v2.1.1"
|
||||
# sort the tags topologically
|
||||
topo_order = false
|
||||
# sort the commits inside sections by oldest/newest order
|
||||
sort_commits = "newest"
|
86
completions/bash/csview.bash
generated
Normal file
86
completions/bash/csview.bash
generated
Normal file
@ -0,0 +1,86 @@
|
||||
_csview() {
|
||||
local i cur prev opts cmd
|
||||
COMPREPLY=()
|
||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
||||
cmd=""
|
||||
opts=""
|
||||
|
||||
for i in ${COMP_WORDS[@]}
|
||||
do
|
||||
case "${cmd},${i}" in
|
||||
",$1")
|
||||
cmd="csview"
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
case "${cmd}" in
|
||||
csview)
|
||||
opts="-H -n -t -d -s -p -i -P -h -V --no-headers --number --tsv --delimiter --style --padding --indent --sniff --header-align --body-align --disable-pager --help --version [FILE]"
|
||||
if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
|
||||
return 0
|
||||
fi
|
||||
case "${prev}" in
|
||||
--delimiter)
|
||||
COMPREPLY=($(compgen -f "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
-d)
|
||||
COMPREPLY=($(compgen -f "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
--style)
|
||||
COMPREPLY=($(compgen -W "none ascii ascii2 sharp rounded reinforced markdown grid" -- "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
-s)
|
||||
COMPREPLY=($(compgen -W "none ascii ascii2 sharp rounded reinforced markdown grid" -- "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
--padding)
|
||||
COMPREPLY=($(compgen -f "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
-p)
|
||||
COMPREPLY=($(compgen -f "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
--indent)
|
||||
COMPREPLY=($(compgen -f "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
-i)
|
||||
COMPREPLY=($(compgen -f "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
--sniff)
|
||||
COMPREPLY=($(compgen -f "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
--header-align)
|
||||
COMPREPLY=($(compgen -W "left center right" -- "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
--body-align)
|
||||
COMPREPLY=($(compgen -W "left center right" -- "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
COMPREPLY=()
|
||||
;;
|
||||
esac
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
if [[ "${BASH_VERSINFO[0]}" -eq 4 && "${BASH_VERSINFO[1]}" -ge 4 || "${BASH_VERSINFO[0]}" -gt 4 ]]; then
|
||||
complete -F _csview -o nosort -o bashdefault -o default csview
|
||||
else
|
||||
complete -F _csview -o bashdefault -o default csview
|
||||
fi
|
47
completions/elvish/csview.elv
generated
Normal file
47
completions/elvish/csview.elv
generated
Normal file
@ -0,0 +1,47 @@
|
||||
|
||||
use builtin;
|
||||
use str;
|
||||
|
||||
set edit:completion:arg-completer[csview] = {|@words|
|
||||
fn spaces {|n|
|
||||
builtin:repeat $n ' ' | str:join ''
|
||||
}
|
||||
fn cand {|text desc|
|
||||
edit:complex-candidate $text &display=$text' '(spaces (- 14 (wcswidth $text)))$desc
|
||||
}
|
||||
var command = 'csview'
|
||||
for word $words[1..-1] {
|
||||
if (str:has-prefix $word '-') {
|
||||
break
|
||||
}
|
||||
set command = $command';'$word
|
||||
}
|
||||
var completions = [
|
||||
&'csview'= {
|
||||
cand -d 'Specify the field delimiter'
|
||||
cand --delimiter 'Specify the field delimiter'
|
||||
cand -s 'Specify the border style'
|
||||
cand --style 'Specify the border style'
|
||||
cand -p 'Specify padding for table cell'
|
||||
cand --padding 'Specify padding for table cell'
|
||||
cand -i 'Specify global indent for table'
|
||||
cand --indent 'Specify global indent for table'
|
||||
cand --sniff 'Limit column widths sniffing to the specified number of rows. Specify "0" to cancel limit'
|
||||
cand --header-align 'Specify the alignment of the table header'
|
||||
cand --body-align 'Specify the alignment of the table body'
|
||||
cand -H 'Specify that the input has no header row'
|
||||
cand --no-headers 'Specify that the input has no header row'
|
||||
cand -n 'Prepend a column of line numbers to the table'
|
||||
cand --number 'Prepend a column of line numbers to the table'
|
||||
cand -t 'Use ''\t'' as delimiter for tsv'
|
||||
cand --tsv 'Use ''\t'' as delimiter for tsv'
|
||||
cand -P 'Disable pager'
|
||||
cand --disable-pager 'Disable pager'
|
||||
cand -h 'Print help'
|
||||
cand --help 'Print help'
|
||||
cand -V 'Print version'
|
||||
cand --version 'Print version'
|
||||
}
|
||||
]
|
||||
$completions[$command]
|
||||
}
|
13
completions/fish/csview.fish
generated
Normal file
13
completions/fish/csview.fish
generated
Normal file
@ -0,0 +1,13 @@
|
||||
complete -c csview -s d -l delimiter -d 'Specify the field delimiter' -r
|
||||
complete -c csview -s s -l style -d 'Specify the border style' -r -f -a "{none\t'',ascii\t'',ascii2\t'',sharp\t'',rounded\t'',reinforced\t'',markdown\t'',grid\t''}"
|
||||
complete -c csview -s p -l padding -d 'Specify padding for table cell' -r
|
||||
complete -c csview -s i -l indent -d 'Specify global indent for table' -r
|
||||
complete -c csview -l sniff -d 'Limit column widths sniffing to the specified number of rows. Specify "0" to cancel limit' -r
|
||||
complete -c csview -l header-align -d 'Specify the alignment of the table header' -r -f -a "{left\t'',center\t'',right\t''}"
|
||||
complete -c csview -l body-align -d 'Specify the alignment of the table body' -r -f -a "{left\t'',center\t'',right\t''}"
|
||||
complete -c csview -s H -l no-headers -d 'Specify that the input has no header row'
|
||||
complete -c csview -s n -l number -d 'Prepend a column of line numbers to the table'
|
||||
complete -c csview -s t -l tsv -d 'Use \'\\t\' as delimiter for tsv'
|
||||
complete -c csview -s P -l disable-pager -d 'Disable pager'
|
||||
complete -c csview -s h -l help -d 'Print help'
|
||||
complete -c csview -s V -l version -d 'Print version'
|
53
completions/powershell/_csview.ps1
generated
Normal file
53
completions/powershell/_csview.ps1
generated
Normal file
@ -0,0 +1,53 @@
|
||||
|
||||
using namespace System.Management.Automation
|
||||
using namespace System.Management.Automation.Language
|
||||
|
||||
Register-ArgumentCompleter -Native -CommandName 'csview' -ScriptBlock {
|
||||
param($wordToComplete, $commandAst, $cursorPosition)
|
||||
|
||||
$commandElements = $commandAst.CommandElements
|
||||
$command = @(
|
||||
'csview'
|
||||
for ($i = 1; $i -lt $commandElements.Count; $i++) {
|
||||
$element = $commandElements[$i]
|
||||
if ($element -isnot [StringConstantExpressionAst] -or
|
||||
$element.StringConstantType -ne [StringConstantType]::BareWord -or
|
||||
$element.Value.StartsWith('-') -or
|
||||
$element.Value -eq $wordToComplete) {
|
||||
break
|
||||
}
|
||||
$element.Value
|
||||
}) -join ';'
|
||||
|
||||
$completions = @(switch ($command) {
|
||||
'csview' {
|
||||
[CompletionResult]::new('-d', 'd', [CompletionResultType]::ParameterName, 'Specify the field delimiter')
|
||||
[CompletionResult]::new('--delimiter', 'delimiter', [CompletionResultType]::ParameterName, 'Specify the field delimiter')
|
||||
[CompletionResult]::new('-s', 's', [CompletionResultType]::ParameterName, 'Specify the border style')
|
||||
[CompletionResult]::new('--style', 'style', [CompletionResultType]::ParameterName, 'Specify the border style')
|
||||
[CompletionResult]::new('-p', 'p', [CompletionResultType]::ParameterName, 'Specify padding for table cell')
|
||||
[CompletionResult]::new('--padding', 'padding', [CompletionResultType]::ParameterName, 'Specify padding for table cell')
|
||||
[CompletionResult]::new('-i', 'i', [CompletionResultType]::ParameterName, 'Specify global indent for table')
|
||||
[CompletionResult]::new('--indent', 'indent', [CompletionResultType]::ParameterName, 'Specify global indent for table')
|
||||
[CompletionResult]::new('--sniff', 'sniff', [CompletionResultType]::ParameterName, 'Limit column widths sniffing to the specified number of rows. Specify "0" to cancel limit')
|
||||
[CompletionResult]::new('--header-align', 'header-align', [CompletionResultType]::ParameterName, 'Specify the alignment of the table header')
|
||||
[CompletionResult]::new('--body-align', 'body-align', [CompletionResultType]::ParameterName, 'Specify the alignment of the table body')
|
||||
[CompletionResult]::new('-H', 'H ', [CompletionResultType]::ParameterName, 'Specify that the input has no header row')
|
||||
[CompletionResult]::new('--no-headers', 'no-headers', [CompletionResultType]::ParameterName, 'Specify that the input has no header row')
|
||||
[CompletionResult]::new('-n', 'n', [CompletionResultType]::ParameterName, 'Prepend a column of line numbers to the table')
|
||||
[CompletionResult]::new('--number', 'number', [CompletionResultType]::ParameterName, 'Prepend a column of line numbers to the table')
|
||||
[CompletionResult]::new('-t', 't', [CompletionResultType]::ParameterName, 'Use ''\t'' as delimiter for tsv')
|
||||
[CompletionResult]::new('--tsv', 'tsv', [CompletionResultType]::ParameterName, 'Use ''\t'' as delimiter for tsv')
|
||||
[CompletionResult]::new('-P', 'P ', [CompletionResultType]::ParameterName, 'Disable pager')
|
||||
[CompletionResult]::new('--disable-pager', 'disable-pager', [CompletionResultType]::ParameterName, 'Disable pager')
|
||||
[CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help')
|
||||
[CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help')
|
||||
[CompletionResult]::new('-V', 'V ', [CompletionResultType]::ParameterName, 'Print version')
|
||||
[CompletionResult]::new('--version', 'version', [CompletionResultType]::ParameterName, 'Print version')
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
$completions.Where{ $_.CompletionText -like "$wordToComplete*" } |
|
||||
Sort-Object -Property ListItemText
|
||||
}
|
55
completions/zsh/_csview
generated
Normal file
55
completions/zsh/_csview
generated
Normal file
@ -0,0 +1,55 @@
|
||||
#compdef csview
|
||||
|
||||
autoload -U is-at-least
|
||||
|
||||
_csview() {
|
||||
typeset -A opt_args
|
||||
typeset -a _arguments_options
|
||||
local ret=1
|
||||
|
||||
if is-at-least 5.2; then
|
||||
_arguments_options=(-s -S -C)
|
||||
else
|
||||
_arguments_options=(-s -C)
|
||||
fi
|
||||
|
||||
local context curcontext="$curcontext" state line
|
||||
_arguments "${_arguments_options[@]}" : \
|
||||
'-d+[Specify the field delimiter]:DELIMITER: ' \
|
||||
'--delimiter=[Specify the field delimiter]:DELIMITER: ' \
|
||||
'-s+[Specify the border style]:STYLE:(none ascii ascii2 sharp rounded reinforced markdown grid)' \
|
||||
'--style=[Specify the border style]:STYLE:(none ascii ascii2 sharp rounded reinforced markdown grid)' \
|
||||
'-p+[Specify padding for table cell]:PADDING: ' \
|
||||
'--padding=[Specify padding for table cell]:PADDING: ' \
|
||||
'-i+[Specify global indent for table]:INDENT: ' \
|
||||
'--indent=[Specify global indent for table]:INDENT: ' \
|
||||
'--sniff=[Limit column widths sniffing to the specified number of rows. Specify "0" to cancel limit]:LIMIT: ' \
|
||||
'--header-align=[Specify the alignment of the table header]:HEADER_ALIGN:(left center right)' \
|
||||
'--body-align=[Specify the alignment of the table body]:BODY_ALIGN:(left center right)' \
|
||||
'-H[Specify that the input has no header row]' \
|
||||
'--no-headers[Specify that the input has no header row]' \
|
||||
'-n[Prepend a column of line numbers to the table]' \
|
||||
'--number[Prepend a column of line numbers to the table]' \
|
||||
'(-d --delimiter)-t[Use '\''\\t'\'' as delimiter for tsv]' \
|
||||
'(-d --delimiter)--tsv[Use '\''\\t'\'' as delimiter for tsv]' \
|
||||
'-P[Disable pager]' \
|
||||
'--disable-pager[Disable pager]' \
|
||||
'-h[Print help]' \
|
||||
'--help[Print help]' \
|
||||
'-V[Print version]' \
|
||||
'--version[Print version]' \
|
||||
'::FILE -- File to view:_files' \
|
||||
&& ret=0
|
||||
}
|
||||
|
||||
(( $+functions[_csview_commands] )) ||
|
||||
_csview_commands() {
|
||||
local commands; commands=()
|
||||
_describe -t commands 'csview commands' commands "$@"
|
||||
}
|
||||
|
||||
if [ "$funcstack[1]" = "_csview" ]; then
|
||||
_csview "$@"
|
||||
else
|
||||
compdef _csview csview
|
||||
fi
|
4
release.toml
Normal file
4
release.toml
Normal file
@ -0,0 +1,4 @@
|
||||
allow-branch = ["master"]
|
||||
pre-release-hook = ["sh", "-c", "git cliff -o CHANGELOG.md --tag {{version}} && git add CHANGELOG.md"]
|
||||
pre-release-commit-message = "chore: release {{crate_name}} version {{version}}"
|
||||
tag-message = "chore: release {{crate_name}} version {{version}}"
|
3
rust-toolchain.toml
Normal file
3
rust-toolchain.toml
Normal file
@ -0,0 +1,3 @@
|
||||
[toolchain]
|
||||
channel = "stable"
|
||||
components = ["rustfmt", "clippy", "rust-analyzer"]
|
13
rustfmt.toml
Normal file
13
rustfmt.toml
Normal file
@ -0,0 +1,13 @@
|
||||
edition = "2021"
|
||||
max_width = 120
|
||||
reorder_imports = true
|
||||
struct_lit_width = 60
|
||||
struct_variant_width = 60
|
||||
|
||||
# struct_field_align_threshold = 40
|
||||
# comment_width = 120
|
||||
# fn_single_line = false
|
||||
# imports_layout = "HorizontalVertical"
|
||||
# match_arm_blocks = false
|
||||
# overflow_delimited_expr = true
|
||||
# imports_granularity = "Crate"
|
77
src/cli.rs
Normal file
77
src/cli.rs
Normal file
@ -0,0 +1,77 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use clap::{Parser, ValueEnum, ValueHint};
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(about, version)]
|
||||
#[command(disable_help_subcommand = true)]
|
||||
#[command(next_line_help = true)]
|
||||
pub struct App {
|
||||
/// File to view.
|
||||
#[arg(name = "FILE", value_hint = ValueHint::FilePath)]
|
||||
pub file: Option<PathBuf>,
|
||||
|
||||
/// Specify that the input has no header row.
|
||||
#[arg(short = 'H', long = "no-headers")]
|
||||
pub no_headers: bool,
|
||||
|
||||
/// Prepend a column of line numbers to the table.
|
||||
#[arg(short, long, alias = "seq")]
|
||||
pub number: bool,
|
||||
|
||||
/// Use '\t' as delimiter for tsv.
|
||||
#[arg(short, long, conflicts_with = "delimiter")]
|
||||
pub tsv: bool,
|
||||
|
||||
/// Specify the field delimiter.
|
||||
#[arg(short, long, default_value_t = ',')]
|
||||
pub delimiter: char,
|
||||
|
||||
/// Specify the border style.
|
||||
#[arg(short, long, value_enum, default_value_t = TableStyle::Sharp, ignore_case = true)]
|
||||
pub style: TableStyle,
|
||||
|
||||
/// Specify padding for table cell.
|
||||
#[arg(short, long, default_value_t = 1)]
|
||||
pub padding: usize,
|
||||
|
||||
/// Specify global indent for table.
|
||||
#[arg(short, long, default_value_t = 0)]
|
||||
pub indent: usize,
|
||||
|
||||
/// Limit column widths sniffing to the specified number of rows. Specify "0" to cancel limit.
|
||||
#[arg(long, default_value_t = 1000, name = "LIMIT")]
|
||||
pub sniff: usize,
|
||||
|
||||
/// Specify the alignment of the table header.
|
||||
#[arg(long, value_enum, default_value_t = Alignment::Center, ignore_case = true)]
|
||||
pub header_align: Alignment,
|
||||
|
||||
/// Specify the alignment of the table body.
|
||||
#[arg(long, value_enum, default_value_t = Alignment::Left, ignore_case = true)]
|
||||
pub body_align: Alignment,
|
||||
|
||||
#[cfg(all(feature = "pager", unix))]
|
||||
/// Disable pager.
|
||||
#[arg(long, short = 'P')]
|
||||
pub disable_pager: bool,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, ValueEnum)]
|
||||
pub enum TableStyle {
|
||||
None,
|
||||
Ascii,
|
||||
Ascii2,
|
||||
Sharp,
|
||||
Rounded,
|
||||
Reinforced,
|
||||
Markdown,
|
||||
Grid,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, ValueEnum)]
|
||||
pub enum Alignment {
|
||||
Left,
|
||||
Center,
|
||||
Right,
|
||||
}
|
102
src/main.rs
Normal file
102
src/main.rs
Normal file
@ -0,0 +1,102 @@
|
||||
mod cli;
|
||||
mod table;
|
||||
mod util;
|
||||
|
||||
use anyhow::bail;
|
||||
use clap::Parser;
|
||||
use cli::App;
|
||||
use csv::{ErrorKind, ReaderBuilder};
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{self, BufWriter, IsTerminal, Read},
|
||||
process,
|
||||
};
|
||||
use table::TablePrinter;
|
||||
use util::table_style;
|
||||
|
||||
#[cfg(all(feature = "pager", unix))]
|
||||
use pager::Pager;
|
||||
|
||||
fn main() {
|
||||
if let Err(e) = try_main() {
|
||||
if let Some(ioerr) = e.root_cause().downcast_ref::<io::Error>() {
|
||||
if ioerr.kind() == io::ErrorKind::BrokenPipe {
|
||||
process::exit(exitcode::OK);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(csverr) = e.root_cause().downcast_ref::<csv::Error>() {
|
||||
match csverr.kind() {
|
||||
ErrorKind::Utf8 { .. } => {
|
||||
eprintln!("[error] input is not utf8 encoded");
|
||||
process::exit(exitcode::DATAERR)
|
||||
}
|
||||
ErrorKind::UnequalLengths { pos, expected_len, len } => {
|
||||
let pos_info = pos
|
||||
.as_ref()
|
||||
.map(|p| format!(" at (byte: {}, line: {}, record: {})", p.byte(), p.line(), p.record()))
|
||||
.unwrap_or_else(|| "".to_string());
|
||||
eprintln!(
|
||||
"[error] unequal lengths{}: expected length is {}, but got {}",
|
||||
pos_info, expected_len, len
|
||||
);
|
||||
process::exit(exitcode::DATAERR)
|
||||
}
|
||||
ErrorKind::Io(e) => {
|
||||
eprintln!("[error] io error: {}", e);
|
||||
process::exit(exitcode::IOERR)
|
||||
}
|
||||
e => {
|
||||
eprintln!("[error] failed to process input: {:?}", e);
|
||||
process::exit(exitcode::DATAERR)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
eprintln!("{}: {}", env!("CARGO_PKG_NAME"), e);
|
||||
std::process::exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
fn try_main() -> anyhow::Result<()> {
|
||||
let App {
|
||||
file,
|
||||
no_headers,
|
||||
number,
|
||||
tsv,
|
||||
delimiter,
|
||||
style,
|
||||
padding,
|
||||
indent,
|
||||
sniff,
|
||||
header_align,
|
||||
body_align,
|
||||
#[cfg(all(feature = "pager", unix))]
|
||||
disable_pager,
|
||||
} = App::parse();
|
||||
|
||||
#[cfg(all(feature = "pager", unix))]
|
||||
if !disable_pager && io::stdout().is_terminal() {
|
||||
match std::env::var("CSVIEW_PAGER") {
|
||||
Ok(pager) => Pager::with_pager(&pager).setup(),
|
||||
// XXX: the extra null byte can be removed once https://gitlab.com/imp/pager-rs/-/merge_requests/8 is merged
|
||||
Err(_) => Pager::with_pager("less").pager_envs(["LESS=-SF\0"]).setup(),
|
||||
}
|
||||
}
|
||||
|
||||
let stdout = io::stdout();
|
||||
let wtr = &mut BufWriter::new(stdout.lock());
|
||||
let rdr = ReaderBuilder::new()
|
||||
.delimiter(if tsv { b'\t' } else { delimiter as u8 })
|
||||
.has_headers(!no_headers)
|
||||
.from_reader(match file {
|
||||
Some(path) => Box::new(File::open(path)?) as Box<dyn Read>,
|
||||
None if io::stdin().is_terminal() => bail!("no input file specified (use -h for help)"),
|
||||
None => Box::new(io::stdin()),
|
||||
});
|
||||
|
||||
let sniff = if sniff == 0 { usize::MAX } else { sniff };
|
||||
let table = TablePrinter::new(rdr, sniff, number)?;
|
||||
table.writeln(wtr, &table_style(style, padding, indent, header_align, body_align))?;
|
||||
Ok(())
|
||||
}
|
6
src/table/mod.rs
Normal file
6
src/table/mod.rs
Normal file
@ -0,0 +1,6 @@
|
||||
mod printer;
|
||||
mod row;
|
||||
mod style;
|
||||
|
||||
pub use printer::TablePrinter;
|
||||
pub use style::{RowSep, Style, StyleBuilder};
|
260
src/table/printer.rs
Normal file
260
src/table/printer.rs
Normal file
@ -0,0 +1,260 @@
|
||||
use super::{row::Row, style::Style};
|
||||
use csv::{Reader, StringRecord};
|
||||
use std::io::{self, Result, Write};
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
pub struct TablePrinter {
|
||||
header: Option<StringRecord>,
|
||||
widths: Vec<usize>,
|
||||
records: Box<dyn Iterator<Item = csv::Result<StringRecord>>>,
|
||||
with_seq: bool,
|
||||
}
|
||||
|
||||
impl TablePrinter {
|
||||
pub(crate) fn new<R: 'static + io::Read>(mut rdr: Reader<R>, sniff_rows: usize, with_seq: bool) -> Result<Self> {
|
||||
let header = rdr.has_headers().then(|| rdr.headers()).transpose()?.cloned();
|
||||
let (widths, buf) = sniff_widths(&mut rdr, header.as_ref(), sniff_rows, with_seq)?;
|
||||
let records = Box::new(buf.into_iter().map(Ok).chain(rdr.into_records()));
|
||||
Ok(Self { header, widths, records, with_seq })
|
||||
}
|
||||
|
||||
pub(crate) fn writeln<W: Write>(self, wtr: &mut W, fmt: &Style) -> Result<()> {
|
||||
let widths = &self.widths;
|
||||
fmt.rowseps
|
||||
.top
|
||||
.map(|sep| fmt.write_row_sep(wtr, widths, &sep))
|
||||
.transpose()?;
|
||||
|
||||
let mut iter = self.records.peekable();
|
||||
|
||||
if let Some(header) = self.header {
|
||||
let row: Row = self.with_seq.then_some("#").into_iter().chain(header.iter()).collect();
|
||||
row.writeln(wtr, fmt, widths, fmt.header_align)?;
|
||||
if iter.peek().is_some() {
|
||||
fmt.rowseps
|
||||
.snd
|
||||
.map(|sep| fmt.write_row_sep(wtr, widths, &sep))
|
||||
.transpose()?;
|
||||
}
|
||||
}
|
||||
|
||||
let mut seq = 1;
|
||||
while let Some(record) = iter.next().transpose()? {
|
||||
let seq_str = self.with_seq.then(|| seq.to_string());
|
||||
let row: Row = seq_str.iter().map(|s| s.as_str()).chain(record.into_iter()).collect();
|
||||
row.writeln(wtr, fmt, widths, fmt.body_align)?;
|
||||
if let Some(mid) = &fmt.rowseps.mid {
|
||||
if iter.peek().is_some() {
|
||||
fmt.write_row_sep(wtr, widths, mid)?;
|
||||
}
|
||||
}
|
||||
seq += 1;
|
||||
}
|
||||
|
||||
fmt.rowseps
|
||||
.bot
|
||||
.map(|sep| fmt.write_row_sep(wtr, widths, &sep))
|
||||
.transpose()?;
|
||||
|
||||
wtr.flush()
|
||||
}
|
||||
}
|
||||
|
||||
fn sniff_widths<R: io::Read>(
|
||||
rdr: &mut Reader<R>,
|
||||
header: Option<&StringRecord>,
|
||||
sniff_rows: usize,
|
||||
with_seq: bool,
|
||||
) -> Result<(Vec<usize>, Vec<StringRecord>)> {
|
||||
let mut widths = Vec::new();
|
||||
let mut buf = Vec::new();
|
||||
|
||||
fn update_widths(record: &StringRecord, widths: &mut Vec<usize>) {
|
||||
widths.resize(record.len(), 0);
|
||||
record
|
||||
.into_iter()
|
||||
.map(UnicodeWidthStr::width_cjk)
|
||||
.enumerate()
|
||||
.for_each(|(i, width)| widths[i] = widths[i].max(width))
|
||||
}
|
||||
|
||||
let mut record = header.cloned().unwrap_or_default();
|
||||
update_widths(&record, &mut widths);
|
||||
|
||||
let mut seq = 1;
|
||||
while seq <= sniff_rows && rdr.read_record(&mut record)? {
|
||||
update_widths(&record, &mut widths);
|
||||
seq += 1;
|
||||
buf.push(record.clone());
|
||||
}
|
||||
|
||||
if with_seq {
|
||||
widths.insert(0, seq.to_string().width());
|
||||
}
|
||||
Ok((widths, buf))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::table::{RowSep, StyleBuilder};
|
||||
use anyhow::Result;
|
||||
use csv::ReaderBuilder;
|
||||
|
||||
macro_rules! gen_table {
|
||||
($($line:expr)*) => {
|
||||
concat!(
|
||||
$($line, "\n",)*
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_write() -> Result<()> {
|
||||
let text = "a,b,c\n1,2,3\n4,5,6";
|
||||
let rdr = ReaderBuilder::new().has_headers(true).from_reader(text.as_bytes());
|
||||
let wtr = TablePrinter::new(rdr, 3, false)?;
|
||||
|
||||
let mut buf = Vec::new();
|
||||
wtr.writeln(&mut buf, &Style::default())?;
|
||||
|
||||
assert_eq!(
|
||||
gen_table!(
|
||||
"+---+---+---+"
|
||||
"| a | b | c |"
|
||||
"+---+---+---+"
|
||||
"| 1 | 2 | 3 |"
|
||||
"+---+---+---+"
|
||||
"| 4 | 5 | 6 |"
|
||||
"+---+---+---+"
|
||||
),
|
||||
std::str::from_utf8(&buf)?
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_write_without_padding() -> Result<()> {
|
||||
let text = "a,b,c\n1,2,3\n4,5,6";
|
||||
let rdr = ReaderBuilder::new().has_headers(true).from_reader(text.as_bytes());
|
||||
let wtr = TablePrinter::new(rdr, 3, false)?;
|
||||
let fmt = StyleBuilder::default().padding(0).build();
|
||||
|
||||
let mut buf = Vec::new();
|
||||
wtr.writeln(&mut buf, &fmt)?;
|
||||
|
||||
assert_eq!(
|
||||
gen_table!(
|
||||
"+-+-+-+"
|
||||
"|a|b|c|"
|
||||
"+-+-+-+"
|
||||
"|1|2|3|"
|
||||
"+-+-+-+"
|
||||
"|4|5|6|"
|
||||
"+-+-+-+"
|
||||
),
|
||||
std::str::from_utf8(&buf)?
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_write_with_indent() -> Result<()> {
|
||||
let text = "a,b,c\n1,2,3\n4,5,6";
|
||||
let rdr = ReaderBuilder::new().has_headers(true).from_reader(text.as_bytes());
|
||||
let wtr = TablePrinter::new(rdr, 3, false)?;
|
||||
let fmt = StyleBuilder::default().indent(4).build();
|
||||
|
||||
let mut buf = Vec::new();
|
||||
wtr.writeln(&mut buf, &fmt)?;
|
||||
|
||||
assert_eq!(
|
||||
gen_table!(
|
||||
" +---+---+---+"
|
||||
" | a | b | c |"
|
||||
" +---+---+---+"
|
||||
" | 1 | 2 | 3 |"
|
||||
" +---+---+---+"
|
||||
" | 4 | 5 | 6 |"
|
||||
" +---+---+---+"
|
||||
),
|
||||
std::str::from_utf8(&buf)?
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_only_header() -> Result<()> {
|
||||
let text = "a,ab,abc";
|
||||
let rdr = ReaderBuilder::new().has_headers(true).from_reader(text.as_bytes());
|
||||
let wtr = TablePrinter::new(rdr, 3, false)?;
|
||||
let fmt = Style::default();
|
||||
|
||||
let mut buf = Vec::new();
|
||||
wtr.writeln(&mut buf, &fmt)?;
|
||||
|
||||
assert_eq!(
|
||||
gen_table!(
|
||||
"+---+----+-----+"
|
||||
"| a | ab | abc |"
|
||||
"+---+----+-----+"
|
||||
),
|
||||
std::str::from_utf8(&buf)?
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_without_header() -> Result<()> {
|
||||
let text = "1,123,35\n383,2, 17";
|
||||
let rdr = ReaderBuilder::new().has_headers(false).from_reader(text.as_bytes());
|
||||
let wtr = TablePrinter::new(rdr, 3, false)?;
|
||||
let fmt = StyleBuilder::new()
|
||||
.col_sep('│')
|
||||
.row_seps(
|
||||
RowSep::new('─', '╭', '┬', '╮'),
|
||||
RowSep::new('─', '├', '┼', '┤'),
|
||||
None,
|
||||
RowSep::new('─', '╰', '┴', '╯'),
|
||||
)
|
||||
.build();
|
||||
|
||||
let mut buf = Vec::new();
|
||||
wtr.writeln(&mut buf, &fmt)?;
|
||||
|
||||
assert_eq!(
|
||||
gen_table!(
|
||||
"╭─────┬─────┬─────╮"
|
||||
"│ 1 │ 123 │ 35 │"
|
||||
"│ 383 │ 2 │ 17 │"
|
||||
"╰─────┴─────┴─────╯"
|
||||
),
|
||||
std::str::from_utf8(&buf)?
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_with_seq() -> Result<()> {
|
||||
let text = "a,b,c\n1,2,3\n4,5,6";
|
||||
let rdr = ReaderBuilder::new().has_headers(true).from_reader(text.as_bytes());
|
||||
let wtr = TablePrinter::new(rdr, 3, true)?;
|
||||
|
||||
let mut buf = Vec::new();
|
||||
wtr.writeln(&mut buf, &Style::default())?;
|
||||
|
||||
assert_eq!(
|
||||
gen_table!(
|
||||
"+---+---+---+---+"
|
||||
"| # | a | b | c |"
|
||||
"+---+---+---+---+"
|
||||
"| 1 | 1 | 2 | 3 |"
|
||||
"+---+---+---+---+"
|
||||
"| 2 | 4 | 5 | 6 |"
|
||||
"+---+---+---+---+"
|
||||
),
|
||||
std::str::from_utf8(&buf)?
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
96
src/table/row.rs
Normal file
96
src/table/row.rs
Normal file
@ -0,0 +1,96 @@
|
||||
use std::io::{Result, Write};
|
||||
|
||||
use itertools::Itertools;
|
||||
use unicode_truncate::{Alignment, UnicodeTruncateStr};
|
||||
|
||||
use crate::table::Style;
|
||||
|
||||
/// Represent a table row made of cells
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Row<'a> {
|
||||
cells: Vec<&'a str>,
|
||||
}
|
||||
|
||||
impl<'a> FromIterator<&'a str> for Row<'a> {
|
||||
fn from_iter<I: IntoIterator<Item = &'a str>>(iter: I) -> Self {
|
||||
Self { cells: iter.into_iter().collect() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Row<'a> {
|
||||
pub fn write<T: Write>(&self, wtr: &mut T, fmt: &Style, widths: &[usize], align: Alignment) -> Result<()> {
|
||||
let sep = fmt.colseps.mid.map(|c| c.to_string()).unwrap_or_default();
|
||||
write!(wtr, "{:indent$}", "", indent = fmt.indent)?;
|
||||
fmt.colseps.lhs.map(|sep| fmt.write_col_sep(wtr, sep)).transpose()?;
|
||||
Itertools::intersperse(
|
||||
self.cells
|
||||
.iter()
|
||||
.zip(widths)
|
||||
.map(|(cell, &width)| cell.unicode_pad(width, align, true))
|
||||
.map(|s| format!("{:pad$}{}{:pad$}", "", s, "", pad = fmt.padding)),
|
||||
sep,
|
||||
)
|
||||
.try_for_each(|s| write!(wtr, "{}", s))?;
|
||||
fmt.colseps.rhs.map(|sep| fmt.write_col_sep(wtr, sep)).transpose()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn writeln<T: Write>(&self, wtr: &mut T, fmt: &Style, widths: &[usize], align: Alignment) -> Result<()> {
|
||||
self.write(wtr, fmt, widths, align).and_then(|_| writeln!(wtr))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use anyhow::Result;
|
||||
use std::str;
|
||||
|
||||
#[test]
|
||||
fn write_ascii_row() -> Result<()> {
|
||||
let row = Row::from_iter(["a", "b"]);
|
||||
let buf = &mut Vec::new();
|
||||
let fmt = Style::default();
|
||||
let widths = [3, 4];
|
||||
|
||||
row.writeln(buf, &fmt, &widths, Alignment::Left)?;
|
||||
assert_eq!("| a | b |\n", str::from_utf8(buf)?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn write_cjk_row() -> Result<()> {
|
||||
let row = Row::from_iter(["李磊(Jack)", "四川省成都市", "💍"]);
|
||||
let buf = &mut Vec::new();
|
||||
let fmt = Style::default();
|
||||
let widths = [10, 8, 2];
|
||||
|
||||
row.writeln(buf, &fmt, &widths, Alignment::Left)?;
|
||||
assert_eq!("| 李磊(Jack) | 四川省成 | 💍 |\n", str::from_utf8(buf)?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn write_align_center() -> Result<()> {
|
||||
let row = Row::from_iter(["a", "b"]);
|
||||
let buf = &mut Vec::new();
|
||||
let fmt = Style::default();
|
||||
let widths = [3, 4];
|
||||
|
||||
row.writeln(buf, &fmt, &widths, Alignment::Center)?;
|
||||
assert_eq!("| a | b |\n", str::from_utf8(buf)?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn write_align_right() -> Result<()> {
|
||||
let row = Row::from_iter(["a", "b"]);
|
||||
let buf = &mut Vec::new();
|
||||
let fmt = Style::default();
|
||||
let widths = [3, 4];
|
||||
|
||||
row.writeln(buf, &fmt, &widths, Alignment::Right)?;
|
||||
assert_eq!("| a | b |\n", str::from_utf8(buf)?);
|
||||
Ok(())
|
||||
}
|
||||
}
|
277
src/table/style.rs
Normal file
277
src/table/style.rs
Normal file
@ -0,0 +1,277 @@
|
||||
use std::io::{Result, Write};
|
||||
|
||||
use unicode_truncate::Alignment;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct RowSeps {
|
||||
/// Top separator row (top border)
|
||||
/// ```
|
||||
/// >┌───┬───┐
|
||||
/// │ a │ b │
|
||||
/// ```
|
||||
pub top: Option<RowSep>,
|
||||
/// Second separator row (between the header row and the first data row)
|
||||
/// ```
|
||||
/// ┌───┬───┐
|
||||
/// │ a │ b │
|
||||
/// >├───┼───┤
|
||||
/// ```
|
||||
pub snd: Option<RowSep>,
|
||||
/// Middle separator row (between data rows)
|
||||
/// ```
|
||||
/// >├───┼───┤
|
||||
/// │ 2 │ 2 │
|
||||
/// >├───┼───┤
|
||||
/// ```
|
||||
pub mid: Option<RowSep>,
|
||||
/// Bottom separator row (bottom border)
|
||||
/// ```
|
||||
/// │ 3 │ 3 │
|
||||
/// >└───┴───┘
|
||||
/// ```
|
||||
pub bot: Option<RowSep>,
|
||||
}
|
||||
|
||||
/// The characters used for printing a row separator
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct RowSep {
|
||||
/// Inner row separator
|
||||
/// ```
|
||||
/// ┌───┬───┐
|
||||
/// ^
|
||||
/// ```
|
||||
inner: char,
|
||||
/// Left junction separator
|
||||
/// ```
|
||||
/// ┌───┬───┐
|
||||
/// ^
|
||||
/// ```
|
||||
ljunc: char,
|
||||
/// Crossing junction separator
|
||||
/// ```
|
||||
/// ┌───┬───┐
|
||||
/// ^
|
||||
/// ```
|
||||
cjunc: char,
|
||||
/// Right junction separator
|
||||
/// ```
|
||||
/// ┌───┬───┐
|
||||
/// ^
|
||||
/// ```
|
||||
rjunc: char,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct ColSeps {
|
||||
/// Left separator column (left border)
|
||||
/// ```
|
||||
/// │ 1 │ 2 │
|
||||
/// ^
|
||||
/// ```
|
||||
pub lhs: Option<char>,
|
||||
/// Middle column separators
|
||||
/// ```
|
||||
/// │ 1 │ 2 │
|
||||
/// ^
|
||||
/// ```
|
||||
pub mid: Option<char>,
|
||||
/// Right separator column (right border)
|
||||
/// ```
|
||||
/// │ 1 │ 2 │
|
||||
/// ^
|
||||
/// ```
|
||||
pub rhs: Option<char>,
|
||||
}
|
||||
|
||||
impl RowSep {
|
||||
pub fn new(sep: char, ljunc: char, cjunc: char, rjunc: char) -> RowSep {
|
||||
RowSep { inner: sep, ljunc, cjunc, rjunc }
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for RowSep {
|
||||
fn default() -> Self {
|
||||
RowSep::new('-', '+', '+', '+')
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for RowSeps {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
top: Some(RowSep::default()),
|
||||
snd: Some(RowSep::default()),
|
||||
mid: Some(RowSep::default()),
|
||||
bot: Some(RowSep::default()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ColSeps {
|
||||
fn default() -> Self {
|
||||
Self { lhs: Some('|'), mid: Some('|'), rhs: Some('|') }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Style {
|
||||
/// Column style
|
||||
pub colseps: ColSeps,
|
||||
|
||||
/// Row style
|
||||
pub rowseps: RowSeps,
|
||||
|
||||
/// Left and right padding
|
||||
pub padding: usize,
|
||||
|
||||
/// Global indentation
|
||||
pub indent: usize,
|
||||
|
||||
/// Header alignment
|
||||
pub header_align: Alignment,
|
||||
|
||||
/// Data alignment
|
||||
pub body_align: Alignment,
|
||||
}
|
||||
|
||||
impl Default for Style {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
indent: 0,
|
||||
padding: 1,
|
||||
colseps: ColSeps::default(),
|
||||
rowseps: RowSeps::default(),
|
||||
header_align: Alignment::Center,
|
||||
body_align: Alignment::Left,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Style {
|
||||
pub fn write_row_sep<W: Write>(&self, wtr: &mut W, widths: &[usize], sep: &RowSep) -> Result<()> {
|
||||
write!(wtr, "{:indent$}", "", indent = self.indent)?;
|
||||
if self.colseps.lhs.is_some() {
|
||||
write!(wtr, "{}", sep.ljunc)?;
|
||||
}
|
||||
let mut iter = widths.iter().peekable();
|
||||
while let Some(width) = iter.next() {
|
||||
for _ in 0..width + self.padding * 2 {
|
||||
write!(wtr, "{}", sep.inner)?;
|
||||
}
|
||||
if self.colseps.mid.is_some() && iter.peek().is_some() {
|
||||
write!(wtr, "{}", sep.cjunc)?;
|
||||
}
|
||||
}
|
||||
if self.colseps.rhs.is_some() {
|
||||
write!(wtr, "{}", sep.rjunc)?;
|
||||
}
|
||||
writeln!(wtr)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn write_col_sep<W: Write>(&self, wtr: &mut W, sep: char) -> Result<()> {
|
||||
write!(wtr, "{}", sep)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone)]
|
||||
pub struct StyleBuilder {
|
||||
format: Box<Style>,
|
||||
}
|
||||
|
||||
impl StyleBuilder {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn padding(mut self, padding: usize) -> Self {
|
||||
self.format.padding = padding;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn col_sep(self, sep: impl Into<Option<char>>) -> Self {
|
||||
let sep = sep.into();
|
||||
self.col_seps(sep, sep, sep)
|
||||
}
|
||||
|
||||
pub fn col_seps<L, M, R>(mut self, lhs: L, mid: M, rhs: R) -> Self
|
||||
where
|
||||
L: Into<Option<char>>,
|
||||
M: Into<Option<char>>,
|
||||
R: Into<Option<char>>,
|
||||
{
|
||||
self.format.colseps = ColSeps { lhs: lhs.into(), mid: mid.into(), rhs: rhs.into() };
|
||||
self
|
||||
}
|
||||
|
||||
pub fn row_seps<S1, S2, S3, S4>(mut self, top: S1, snd: S2, mid: S3, bot: S4) -> Self
|
||||
where
|
||||
S1: Into<Option<RowSep>>,
|
||||
S2: Into<Option<RowSep>>,
|
||||
S3: Into<Option<RowSep>>,
|
||||
S4: Into<Option<RowSep>>,
|
||||
{
|
||||
self.format.rowseps = RowSeps {
|
||||
top: top.into(),
|
||||
snd: snd.into(),
|
||||
mid: mid.into(),
|
||||
bot: bot.into(),
|
||||
};
|
||||
self
|
||||
}
|
||||
|
||||
pub fn clear_seps(self) -> Self {
|
||||
self.col_seps(None, None, None).row_seps(None, None, None, None)
|
||||
}
|
||||
|
||||
pub fn indent(mut self, indent: usize) -> Self {
|
||||
self.format.indent = indent;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn header_align(mut self, align: Alignment) -> Self {
|
||||
self.format.header_align = align;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn body_align(mut self, align: Alignment) -> Self {
|
||||
self.format.body_align = align;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(&self) -> Style {
|
||||
*self.format
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use anyhow::Result;
|
||||
use std::str;
|
||||
|
||||
#[test]
|
||||
fn test_write_column_separator() -> Result<()> {
|
||||
let fmt = StyleBuilder::new().col_seps('|', '|', '|').padding(1).build();
|
||||
let buf = &mut Vec::new();
|
||||
|
||||
fmt.colseps.lhs.map(|sep| fmt.write_col_sep(buf, sep)).transpose()?;
|
||||
|
||||
assert_eq!("|", str::from_utf8(buf)?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_write_row_separator() -> Result<()> {
|
||||
let fmt = StyleBuilder::new().indent(4).build();
|
||||
let buf = &mut Vec::new();
|
||||
let widths = &[2, 4, 6];
|
||||
|
||||
fmt.rowseps
|
||||
.top
|
||||
.map(|sep| fmt.write_row_sep(buf, widths, &sep))
|
||||
.transpose()?;
|
||||
|
||||
assert_eq!(" +----+------+--------+\n", str::from_utf8(buf)?);
|
||||
Ok(())
|
||||
}
|
||||
}
|
74
src/util.rs
Normal file
74
src/util.rs
Normal file
@ -0,0 +1,74 @@
|
||||
use cli::Alignment;
|
||||
|
||||
use crate::{
|
||||
cli::{self, TableStyle},
|
||||
table::{RowSep, Style, StyleBuilder},
|
||||
};
|
||||
|
||||
pub fn table_style(
|
||||
style: TableStyle,
|
||||
padding: usize,
|
||||
indent: usize,
|
||||
header_align: Alignment,
|
||||
body_align: Alignment,
|
||||
) -> Style {
|
||||
let builder = match style {
|
||||
TableStyle::None => StyleBuilder::new().clear_seps(),
|
||||
TableStyle::Ascii => StyleBuilder::new().col_sep('|').row_seps(
|
||||
RowSep::new('-', '+', '+', '+'),
|
||||
RowSep::new('-', '+', '+', '+'),
|
||||
None,
|
||||
RowSep::new('-', '+', '+', '+'),
|
||||
),
|
||||
TableStyle::Ascii2 => {
|
||||
StyleBuilder::new()
|
||||
.col_seps(' ', '|', ' ')
|
||||
.row_seps(None, RowSep::new('-', ' ', '+', ' '), None, None)
|
||||
}
|
||||
TableStyle::Sharp => StyleBuilder::new().col_sep('│').row_seps(
|
||||
RowSep::new('─', '┌', '┬', '┐'),
|
||||
RowSep::new('─', '├', '┼', '┤'),
|
||||
None,
|
||||
RowSep::new('─', '└', '┴', '┘'),
|
||||
),
|
||||
TableStyle::Rounded => StyleBuilder::new().col_sep('│').row_seps(
|
||||
RowSep::new('─', '╭', '┬', '╮'),
|
||||
RowSep::new('─', '├', '┼', '┤'),
|
||||
None,
|
||||
RowSep::new('─', '╰', '┴', '╯'),
|
||||
),
|
||||
TableStyle::Reinforced => StyleBuilder::new().col_sep('│').row_seps(
|
||||
RowSep::new('─', '┏', '┬', '┓'),
|
||||
RowSep::new('─', '├', '┼', '┤'),
|
||||
None,
|
||||
RowSep::new('─', '┗', '┴', '┛'),
|
||||
),
|
||||
TableStyle::Markdown => {
|
||||
StyleBuilder::new()
|
||||
.col_sep('|')
|
||||
.row_seps(None, RowSep::new('-', '|', '|', '|'), None, None)
|
||||
}
|
||||
TableStyle::Grid => StyleBuilder::new().col_sep('│').row_seps(
|
||||
RowSep::new('─', '┌', '┬', '┐'),
|
||||
RowSep::new('─', '├', '┼', '┤'),
|
||||
RowSep::new('─', '├', '┼', '┤'),
|
||||
RowSep::new('─', '└', '┴', '┘'),
|
||||
),
|
||||
};
|
||||
builder
|
||||
.padding(padding)
|
||||
.indent(indent)
|
||||
.header_align(header_align.into())
|
||||
.body_align(body_align.into())
|
||||
.build()
|
||||
}
|
||||
|
||||
impl From<Alignment> for unicode_truncate::Alignment {
|
||||
fn from(a: Alignment) -> Self {
|
||||
match a {
|
||||
Alignment::Left => unicode_truncate::Alignment::Left,
|
||||
Alignment::Center => unicode_truncate::Alignment::Center,
|
||||
Alignment::Right => unicode_truncate::Alignment::Right,
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user