mirror of
https://github.com/sharkdp/bat.git
synced 2025-09-01 10:52:24 +01:00
Compare commits
193 Commits
v0.23.0
...
dependabot
Author | SHA1 | Date | |
---|---|---|---|
|
15178bca3f | ||
|
05ccdcd27b | ||
|
f76f905771 | ||
|
c963e80343 | ||
|
c76ed99db2 | ||
|
06aef22943 | ||
|
128b0d6dd3 | ||
|
15dc20109f | ||
|
5c4bcd6611 | ||
|
ecf4029dc7 | ||
|
ea1fbacf76 | ||
|
497342fabb | ||
|
bf56cd90f0 | ||
|
0acb979e9e | ||
|
b89dc15be1 | ||
|
28990bc451 | ||
|
748e2a681f | ||
|
bfa0b5241f | ||
|
4af4bfc0f1 | ||
|
51203ff750 | ||
|
96cef9a24e | ||
|
b43d31b75a | ||
|
ad3ff26960 | ||
|
86b40993c3 | ||
|
31bed250ba | ||
|
7658334645 | ||
|
491ae70aa9 | ||
|
d64c568196 | ||
|
b5982a6174 | ||
|
04e7d2a313 | ||
|
bcc2de86b4 | ||
|
1296aea836 | ||
|
5498c24c33 | ||
|
79a03b4299 | ||
|
f3a5e9a73c | ||
|
2710a19ecb | ||
|
6d0ef259f6 | ||
|
b1577cc083 | ||
|
28d947fd8b | ||
|
b000db8f32 | ||
|
116a6cc9a8 | ||
|
c8291a36b7 | ||
|
8180c76890 | ||
|
a0f33b1cdc | ||
|
8b60dae81c | ||
|
4b33093f9e | ||
|
3d87b25b19 | ||
|
f2f6902279 | ||
|
c0b17e73e1 | ||
|
94544d963b | ||
|
72abbd22de | ||
|
64e10ffb21 | ||
|
35d8146bba | ||
|
a5a7ede698 | ||
|
b551049706 | ||
|
99cfc13eab | ||
|
4b0b5afa13 | ||
|
d343428441 | ||
|
16e409ec87 | ||
|
94d059f258 | ||
|
c8b9de889d | ||
|
75340d54f9 | ||
|
b28383e0fa | ||
|
8e866db281 | ||
|
0eb157e090 | ||
|
85636c28bc | ||
|
a70e5c6c65 | ||
|
32e01f740b | ||
|
7b20f8fc7b | ||
|
86ac48d68e | ||
|
c42fc810ea | ||
|
6baebd79fa | ||
|
c6cae09f99 | ||
|
fc9546854f | ||
|
32da58e723 | ||
|
63aaa03013 | ||
|
fbe9b6f15f | ||
|
c946ddb012 | ||
|
e5c81ed41e | ||
|
0937d575fd | ||
|
4382be5e7c | ||
|
d89df18de2 | ||
|
9fcc57e496 | ||
|
8e35a56712 | ||
|
9f795dd947 | ||
|
721f956c1c | ||
|
db4cdc1cb8 | ||
|
e455f93a1e | ||
|
d756d6f1ed | ||
|
6568fb775d | ||
|
d376a4b631 | ||
|
6e5fd36882 | ||
|
c7cc4b5c59 | ||
|
db76091a53 | ||
|
506fe65474 | ||
|
69c326fd41 | ||
|
466b275e87 | ||
|
319c675f3e | ||
|
5a240f36b9 | ||
|
e2bf85e749 | ||
|
fe73010a5e | ||
|
150c04acb6 | ||
|
433176ab54 | ||
|
b56021ffa9 | ||
|
ac2953c070 | ||
|
d6e11b59e7 | ||
|
f49278cfaa | ||
|
9b73eda957 | ||
|
ed99a3a104 | ||
|
e32ad0b048 | ||
|
3abc0c0fc4 | ||
|
b06f13f0c5 | ||
|
a721cc31f3 | ||
|
1e52785d35 | ||
|
9ba3b6ed13 | ||
|
72e1a40bab | ||
|
33a89410d4 | ||
|
b2c28cdddb | ||
|
906e774372 | ||
|
d929becefc | ||
|
103a2f0d9b | ||
|
d33b2e158e | ||
|
d295b3a394 | ||
|
81a217b1f3 | ||
|
bb17f74757 | ||
|
75928d20f8 | ||
|
2cc45eea1a | ||
|
7dbc6e3da4 | ||
|
f34b852aa8 | ||
|
4b04f901fe | ||
|
26111950b3 | ||
|
f21d3502e1 | ||
|
5687af8bc7 | ||
|
0f5f51f9ba | ||
|
32c0e1fb45 | ||
|
34440f1b0c | ||
|
f1d6cc7a64 | ||
|
628ba5d31f | ||
|
e24150ca3f | ||
|
d580445aef | ||
|
48dc2b0d90 | ||
|
82664e3c82 | ||
|
1893405cbf | ||
|
00b7e3b864 | ||
|
7826e506f8 | ||
|
6dd8b28b0d | ||
|
b720af8a06 | ||
|
b1fbcc8a6e | ||
|
9bf74d687f | ||
|
783d4877e1 | ||
|
8b187e6997 | ||
|
c46c53320b | ||
|
7f884fa582 | ||
|
8676bbf97f | ||
|
77069b368c | ||
|
70e49bd32b | ||
|
5042f969e5 | ||
|
876f5d4113 | ||
|
39d9d64e1e | ||
|
8e866babfc | ||
|
f8c700027e | ||
|
7639e8b406 | ||
|
149dec6953 | ||
|
b420c42aff | ||
|
3da7adb763 | ||
|
165e5da6b9 | ||
|
c5a9fdff93 | ||
|
8aac5acc0a | ||
|
7162e38d50 | ||
|
63ac60a3a0 | ||
|
9683bfdb3f | ||
|
e155f56484 | ||
|
e828d7840a | ||
|
52f7a5a06f | ||
|
baa1476d8d | ||
|
6be56972b6 | ||
|
08445eba91 | ||
|
2298422e85 | ||
|
c5731b9079 | ||
|
458e818ab4 | ||
|
993b33b5b4 | ||
|
ba95955fe6 | ||
|
57cc0d8435 | ||
|
60a9ac041f | ||
|
33997106da | ||
|
1b2c69aee8 | ||
|
87e87a349a | ||
|
e49235e119 | ||
|
1712ec9e73 | ||
|
3ca8c43a67 | ||
|
01f1b1efe8 | ||
|
c7905a6029 | ||
|
d27aaffead |
23
.github/workflows/Auto-merge-dependabot-PRs.yml
vendored
Normal file
23
.github/workflows/Auto-merge-dependabot-PRs.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
# This workflow triggers auto-merge of any PR that dependabot creates so that
|
||||
# PRs will be merged automatically without maintainer intervention if CI passes
|
||||
name: Auto-merge dependabot PRs
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened]
|
||||
|
||||
jobs:
|
||||
auto-merge:
|
||||
if: github.repository == 'sharkdp/bat' && startsWith(github.head_ref, 'dependabot/')
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: auto-merge
|
||||
url: https://github.com/sharkdp/bat/blob/main/.github/workflows/Auto-merge-dependabot-PRs.yml
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.AUTO_MERGE_GITHUB_TOKEN }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: |
|
||||
gh pr review ${{ github.event.pull_request.number }} --comment --body "If CI passes, this dependabot PR will be [auto-merged](https://github.com/sharkdp/bat/blob/main/.github/workflows/Auto-merge-dependabot-PRs.yml) 🚀"
|
||||
- run: |
|
||||
gh pr merge --auto --squash ${{ github.event.pull_request.number }}
|
203
.github/workflows/CICD.yml
vendored
203
.github/workflows/CICD.yml
vendored
@@ -2,6 +2,7 @@ name: CICD
|
||||
|
||||
env:
|
||||
CICD_INTERMEDIATES_DIR: "_cicd-intermediates"
|
||||
MSRV_FEATURES: --no-default-features --features minimal-application,bugreport,build-assets
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
@@ -13,6 +14,43 @@ on:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
all-jobs:
|
||||
if: always() # Otherwise this job is skipped if the matrix job fails
|
||||
name: all-jobs
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- crate_metadata
|
||||
- ensure_cargo_fmt
|
||||
- min_version
|
||||
- license_checks
|
||||
- test_with_new_syntaxes_and_themes
|
||||
- test_with_system_config
|
||||
- documentation
|
||||
- cargo-audit
|
||||
- build
|
||||
steps:
|
||||
- run: jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}'
|
||||
|
||||
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 '"msrv=" + .packages[0].rust_version' | tee -a $GITHUB_OUTPUT
|
||||
outputs:
|
||||
name: ${{ steps.crate_metadata.outputs.name }}
|
||||
version: ${{ steps.crate_metadata.outputs.version }}
|
||||
maintainer: ${{ steps.crate_metadata.outputs.maintainer }}
|
||||
homepage: ${{ steps.crate_metadata.outputs.homepage }}
|
||||
msrv: ${{ steps.crate_metadata.outputs.msrv }}
|
||||
|
||||
ensure_cargo_fmt:
|
||||
name: Ensure 'cargo fmt' has been run
|
||||
runs-on: ubuntu-20.04
|
||||
@@ -20,46 +58,42 @@ jobs:
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
components: rustfmt
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- run: cargo fmt -- --check
|
||||
|
||||
license_checks:
|
||||
name: License checks
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true # we especially want to perform license checks on submodules
|
||||
- run: tests/scripts/license-checks.sh
|
||||
|
||||
min_version:
|
||||
name: Minimum supported rust version
|
||||
runs-on: ubuntu-20.04
|
||||
env:
|
||||
MSRV_FEATURES: --no-default-features --features minimal-application,bugreport,build-assets
|
||||
needs: crate_metadata
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Get the MSRV from the package metadata
|
||||
id: msrv
|
||||
run: cargo metadata --no-deps --format-version 1 | jq -r '"version=" + (.packages[] | select(.name == "bat")).rust_version' >> $GITHUB_OUTPUT
|
||||
- name: Install rust toolchain (v${{ steps.msrv.outputs.version }})
|
||||
- name: Install rust toolchain (v${{ needs.crate_metadata.outputs.msrv }})
|
||||
uses: dtolnay/rust-toolchain@master
|
||||
with:
|
||||
toolchain: ${{ steps.msrv.outputs.version }}
|
||||
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 }}
|
||||
|
||||
license_checks:
|
||||
name: License checks
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true # we especially want to perform license checks on submodules
|
||||
- run: tests/scripts/license-checks.sh
|
||||
|
||||
test_with_new_syntaxes_and_themes:
|
||||
name: Run tests with updated syntaxes and themes
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Git checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true # we need all syntax and theme submodules
|
||||
- name: Install Rust toolchain
|
||||
@@ -88,7 +122,7 @@ jobs:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Git checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Prepare environment variables
|
||||
run: |
|
||||
echo "BAT_SYSTEM_CONFIG_PREFIX=$GITHUB_WORKSPACE/tests/examples/system_config" >> $GITHUB_ENV
|
||||
@@ -104,7 +138,7 @@ jobs:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Git checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
- name: Check documentation
|
||||
@@ -114,29 +148,37 @@ jobs:
|
||||
- name: Show man page
|
||||
run: man $(find . -name bat.1)
|
||||
|
||||
cargo-audit:
|
||||
name: cargo audit
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: cargo audit
|
||||
|
||||
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: 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-10.15 }
|
||||
- { 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 }
|
||||
- { target: aarch64-unknown-linux-gnu , os: ubuntu-20.04, dpkg_arch: arm64, use-cross: true }
|
||||
- { target: arm-unknown-linux-gnueabihf , os: ubuntu-20.04, dpkg_arch: armhf, use-cross: true }
|
||||
- { target: arm-unknown-linux-musleabihf, os: ubuntu-20.04, dpkg_arch: musl-linux-armhf, use-cross: true }
|
||||
- { target: i686-pc-windows-msvc , os: windows-2019, }
|
||||
- { target: i686-unknown-linux-gnu , os: ubuntu-20.04, dpkg_arch: i686, use-cross: true }
|
||||
- { target: i686-unknown-linux-musl , os: ubuntu-20.04, dpkg_arch: musl-linux-i686, use-cross: true }
|
||||
- { target: x86_64-apple-darwin , os: macos-12, }
|
||||
- { 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, dpkg_arch: amd64, use-cross: true }
|
||||
- { target: x86_64-unknown-linux-musl , os: ubuntu-20.04, dpkg_arch: musl-linux-amd64, use-cross: true }
|
||||
env:
|
||||
BUILD_CMD: cargo
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install prerequisites
|
||||
shell: bash
|
||||
@@ -146,14 +188,6 @@ jobs:
|
||||
aarch64-unknown-linux-gnu) sudo apt-get -y update ; sudo apt-get -y install gcc-aarch64-linux-gnu ;;
|
||||
esac
|
||||
|
||||
- name: Extract crate information
|
||||
shell: bash
|
||||
run: |
|
||||
echo "PROJECT_NAME=$(sed -n 's/^name = "\(.*\)"/\1/p' Cargo.toml | head -n1)" >> $GITHUB_ENV
|
||||
echo "PROJECT_VERSION=$(sed -n 's/^version = "\(.*\)"/\1/p' Cargo.toml | head -n1)" >> $GITHUB_ENV
|
||||
echo "PROJECT_MAINTAINER=$(sed -n 's/^authors = \["\(.*\)"\]/\1/p' Cargo.toml)" >> $GITHUB_ENV
|
||||
echo "PROJECT_HOMEPAGE=$(sed -n 's/^homepage = "\(.*\)"/\1/p' Cargo.toml)" >> $GITHUB_ENV
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
@@ -184,7 +218,7 @@ jobs:
|
||||
shell: bash
|
||||
run: $BUILD_CMD build --locked --release --target=${{ matrix.job.target }}
|
||||
|
||||
- name: Set bin name & path
|
||||
- name: Set binary name & path
|
||||
id: bin
|
||||
shell: bash
|
||||
run: |
|
||||
@@ -195,10 +229,10 @@ jobs:
|
||||
esac;
|
||||
|
||||
# Setup paths
|
||||
BIN_NAME="${{ env.PROJECT_NAME }}${EXE_suffix}"
|
||||
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 bin
|
||||
# Let subsequent steps know where to find the binary
|
||||
echo "BIN_PATH=${BIN_PATH}" >> $GITHUB_OUTPUT
|
||||
echo "BIN_NAME=${BIN_NAME}" >> $GITHUB_OUTPUT
|
||||
|
||||
@@ -208,12 +242,18 @@ jobs:
|
||||
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="--lib --bin ${PROJECT_NAME}" ;; esac;
|
||||
unset CARGO_TEST_OPTIONS ; case ${{ matrix.job.target }} in arm-* | aarch64-*) CARGO_TEST_OPTIONS="--lib --bin ${{ needs.crate_metadata.outputs.name }}" ;; esac;
|
||||
echo "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}}
|
||||
run: |
|
||||
if [[ ${{ matrix.job.os }} = windows-* ]]
|
||||
then
|
||||
powershell.exe -command "$BUILD_CMD test --locked --target=${{ matrix.job.target }} ${{ steps.test-options.outputs.CARGO_TEST_OPTIONS}}"
|
||||
else
|
||||
$BUILD_CMD test --locked --target=${{ matrix.job.target }} ${{ steps.test-options.outputs.CARGO_TEST_OPTIONS}}
|
||||
fi
|
||||
|
||||
- name: Run bat
|
||||
shell: bash
|
||||
@@ -248,7 +288,7 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
PKG_suffix=".tar.gz" ; case ${{ matrix.job.target }} in *-pc-windows-*) PKG_suffix=".zip" ;; esac;
|
||||
PKG_BASENAME=${PROJECT_NAME}-v${PROJECT_VERSION}-${{ matrix.job.target }}
|
||||
PKG_BASENAME=${{ needs.crate_metadata.outputs.name }}-v${{ needs.crate_metadata.outputs.version }}-${{ matrix.job.target }}
|
||||
PKG_NAME=${PKG_BASENAME}${PKG_suffix}
|
||||
echo "PKG_NAME=${PKG_NAME}" >> $GITHUB_OUTPUT
|
||||
|
||||
@@ -260,17 +300,17 @@ jobs:
|
||||
# Binary
|
||||
cp "${{ steps.bin.outputs.BIN_PATH }}" "$ARCHIVE_DIR"
|
||||
|
||||
# Man page
|
||||
cp 'target/${{ matrix.job.target }}/release/build/${{ env.PROJECT_NAME }}'-*/out/assets/manual/bat.1 "$ARCHIVE_DIR"
|
||||
|
||||
# README, LICENSE and CHANGELOG files
|
||||
cp "README.md" "LICENSE-MIT" "LICENSE-APACHE" "CHANGELOG.md" "$ARCHIVE_DIR"
|
||||
|
||||
# Man page
|
||||
cp 'target/${{ matrix.job.target }}/release/build/${{ needs.crate_metadata.outputs.name }}'-*/out/assets/manual/bat.1 "$ARCHIVE_DIR"
|
||||
|
||||
# Autocompletion files
|
||||
cp 'target/${{ matrix.job.target }}/release/build/${{ env.PROJECT_NAME }}'-*/out/assets/completions/bat.bash "$ARCHIVE_DIR/autocomplete/${{ env.PROJECT_NAME }}.bash"
|
||||
cp 'target/${{ matrix.job.target }}/release/build/${{ env.PROJECT_NAME }}'-*/out/assets/completions/bat.fish "$ARCHIVE_DIR/autocomplete/${{ env.PROJECT_NAME }}.fish"
|
||||
cp 'target/${{ matrix.job.target }}/release/build/${{ env.PROJECT_NAME }}'-*/out/assets/completions/_bat.ps1 "$ARCHIVE_DIR/autocomplete/_${{ env.PROJECT_NAME }}.ps1"
|
||||
cp 'target/${{ matrix.job.target }}/release/build/${{ env.PROJECT_NAME }}'-*/out/assets/completions/bat.zsh "$ARCHIVE_DIR/autocomplete/${{ env.PROJECT_NAME }}.zsh"
|
||||
cp 'target/${{ matrix.job.target }}/release/build/${{ needs.crate_metadata.outputs.name }}'-*/out/assets/completions/bat.bash "$ARCHIVE_DIR/autocomplete/${{ needs.crate_metadata.outputs.name }}.bash"
|
||||
cp 'target/${{ matrix.job.target }}/release/build/${{ needs.crate_metadata.outputs.name }}'-*/out/assets/completions/bat.fish "$ARCHIVE_DIR/autocomplete/${{ needs.crate_metadata.outputs.name }}.fish"
|
||||
cp 'target/${{ matrix.job.target }}/release/build/${{ needs.crate_metadata.outputs.name }}'-*/out/assets/completions/_bat.ps1 "$ARCHIVE_DIR/autocomplete/_${{ needs.crate_metadata.outputs.name }}.ps1"
|
||||
cp 'target/${{ matrix.job.target }}/release/build/${{ needs.crate_metadata.outputs.name }}'-*/out/assets/completions/bat.zsh "$ARCHIVE_DIR/autocomplete/${{ needs.crate_metadata.outputs.name }}.zsh"
|
||||
|
||||
# base compressed package
|
||||
pushd "${PKG_STAGING}/" >/dev/null
|
||||
@@ -293,20 +333,11 @@ jobs:
|
||||
DPKG_DIR="${DPKG_STAGING}/dpkg"
|
||||
mkdir -p "${DPKG_DIR}"
|
||||
|
||||
DPKG_BASENAME=${PROJECT_NAME}
|
||||
DPKG_CONFLICTS=${PROJECT_NAME}-musl
|
||||
case ${{ matrix.job.target }} in *-musl) DPKG_BASENAME=${PROJECT_NAME}-musl ; DPKG_CONFLICTS=${PROJECT_NAME} ;; esac;
|
||||
DPKG_VERSION=${PROJECT_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_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 }}
|
||||
DPKG_ARCH="${{ matrix.job.dpkg_arch }}"
|
||||
DPKG_NAME="${DPKG_BASENAME}_${DPKG_VERSION}_${DPKG_ARCH}.deb"
|
||||
echo "DPKG_NAME=${DPKG_NAME}" >> $GITHUB_OUTPUT
|
||||
|
||||
@@ -314,13 +345,13 @@ jobs:
|
||||
install -Dm755 "${{ steps.bin.outputs.BIN_PATH }}" "${DPKG_DIR}/usr/bin/${{ steps.bin.outputs.BIN_NAME }}"
|
||||
|
||||
# Man page
|
||||
install -Dm644 'target/${{ matrix.job.target }}/release/build/${{ env.PROJECT_NAME }}'-*/out/assets/manual/bat.1 "${DPKG_DIR}/usr/share/man/man1/${{ env.PROJECT_NAME }}.1"
|
||||
gzip -n --best "${DPKG_DIR}/usr/share/man/man1/${{ env.PROJECT_NAME }}.1"
|
||||
install -Dm644 'target/${{ matrix.job.target }}/release/build/${{ needs.crate_metadata.outputs.name }}'-*/out/assets/manual/bat.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 'target/${{ matrix.job.target }}/release/build/${{ env.PROJECT_NAME }}'-*/out/assets/completions/bat.bash "${DPKG_DIR}/usr/share/bash-completion/completions/${{ env.PROJECT_NAME }}"
|
||||
install -Dm644 'target/${{ matrix.job.target }}/release/build/${{ env.PROJECT_NAME }}'-*/out/assets/completions/bat.fish "${DPKG_DIR}/usr/share/fish/vendor_completions.d/${{ env.PROJECT_NAME }}.fish"
|
||||
install -Dm644 'target/${{ matrix.job.target }}/release/build/${{ env.PROJECT_NAME }}'-*/out/assets/completions/bat.zsh "${DPKG_DIR}/usr/share/zsh/vendor-completions/_${{ env.PROJECT_NAME }}"
|
||||
install -Dm644 'target/${{ matrix.job.target }}/release/build/${{ needs.crate_metadata.outputs.name }}'-*/out/assets/completions/bat.bash "${DPKG_DIR}/usr/share/bash-completion/completions/${{ needs.crate_metadata.outputs.name }}"
|
||||
install -Dm644 'target/${{ matrix.job.target }}/release/build/${{ needs.crate_metadata.outputs.name }}'-*/out/assets/completions/bat.fish "${DPKG_DIR}/usr/share/fish/vendor_completions.d/${{ needs.crate_metadata.outputs.name }}.fish"
|
||||
install -Dm644 'target/${{ matrix.job.target }}/release/build/${{ needs.crate_metadata.outputs.name }}'-*/out/assets/completions/bat.zsh "${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"
|
||||
@@ -331,12 +362,12 @@ jobs:
|
||||
|
||||
cat > "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/copyright" <<EOF
|
||||
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: ${{ env.PROJECT_NAME }}
|
||||
Source: ${{ env.PROJECT_HOMEPAGE }}
|
||||
Upstream-Name: ${{ needs.crate_metadata.outputs.name }}
|
||||
Source: ${{ needs.crate_metadata.outputs.homepage }}
|
||||
|
||||
Files: *
|
||||
Copyright: ${{ env.PROJECT_MAINTAINER }}
|
||||
Copyright: $COPYRIGHT_YEARS ${{ env.PROJECT_MAINTAINER }}
|
||||
Copyright: ${{ needs.crate_metadata.outputs.maintainer }}
|
||||
Copyright: $COPYRIGHT_YEARS ${{ needs.crate_metadata.outputs.maintainer }}
|
||||
License: Apache-2.0 or MIT
|
||||
|
||||
License: Apache-2.0
|
||||
@@ -377,10 +408,10 @@ jobs:
|
||||
Version: ${DPKG_VERSION}
|
||||
Section: utils
|
||||
Priority: optional
|
||||
Maintainer: ${{ env.PROJECT_MAINTAINER }}
|
||||
Homepage: ${{ env.PROJECT_HOMEPAGE }}
|
||||
Maintainer: ${{ needs.crate_metadata.outputs.maintainer }}
|
||||
Homepage: ${{ needs.crate_metadata.outputs.homepage }}
|
||||
Architecture: ${DPKG_ARCH}
|
||||
Provides: ${{ env.PROJECT_NAME }}
|
||||
Provides: ${{ needs.crate_metadata.outputs.name }}
|
||||
Conflicts: ${DPKG_CONFLICTS}
|
||||
Description: cat(1) clone with wings.
|
||||
A cat(1) clone with syntax highlighting and Git integration.
|
||||
@@ -421,3 +452,15 @@ jobs:
|
||||
${{ steps.debian-package.outputs.DPKG_PATH }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
winget:
|
||||
name: Publish to Winget
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
steps:
|
||||
- uses: vedantmgoyal2009/winget-releaser@v2
|
||||
with:
|
||||
identifier: sharkdp.bat
|
||||
installers-regex: '-pc-windows-msvc\.zip$'
|
||||
token: ${{ secrets.WINGET_TOKEN }}
|
||||
|
43
.github/workflows/require-changelog-for-PRs.yml
vendored
Normal file
43
.github/workflows/require-changelog-for-PRs.yml
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
name: Changelog
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
check-changelog:
|
||||
name: Check for changelog entry
|
||||
runs-on: ubuntu-latest
|
||||
# dependabot PRs are automerged if CI passes; we shouldn't block these
|
||||
if: github.actor != 'dependabot[bot]'
|
||||
env:
|
||||
PR_NUMBER: ${{ github.event.number }}
|
||||
PR_BASE: ${{ github.base_ref }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Fetch PR base
|
||||
run: git fetch --no-tags --prune --depth=1 origin
|
||||
|
||||
# cannot use `github.actor`: the triggering commit may be authored by a maintainer
|
||||
- name: Get PR submitter
|
||||
id: get-submitter
|
||||
run: curl -sSfL https://api.github.com/repos/sharkdp/bat/pulls/${PR_NUMBER} | jq -r '"submitter=" + .user.login' | tee -a $GITHUB_OUTPUT
|
||||
|
||||
- name: Search for added line in changelog
|
||||
env:
|
||||
PR_SUBMITTER: ${{ steps.get-submitter.outputs.submitter }}
|
||||
run: |
|
||||
ADDED=$(git diff -U0 "origin/${PR_BASE}" HEAD -- CHANGELOG.md | grep -P '^\+[^\+].+$')
|
||||
echo "Added lines in CHANGELOG.md:"
|
||||
echo "$ADDED"
|
||||
|
||||
escape_regex_meta_chars() {
|
||||
# https://stackoverflow.com/a/16951928/4473405
|
||||
sed 's/[][\.|$(){}?+*^]/\\&/g' <<< "$*"
|
||||
}
|
||||
|
||||
double_escape_slash_for_bash() {
|
||||
sed 's/\\/\\\\/g' <<< "$*"
|
||||
}
|
||||
|
||||
echo "Grepping for PR info:"
|
||||
grep "#${PR_NUMBER}\\b.*[(]@$(quote ${PR_SUBMITTER})[)]" <<< "$ADDED"
|
6
.gitmodules
vendored
6
.gitmodules
vendored
@@ -254,3 +254,9 @@
|
||||
[submodule "assets/syntaxes/02_Extra/Crontab"]
|
||||
path = assets/syntaxes/02_Extra/Crontab
|
||||
url = https://github.com/michaelblyons/SublimeSyntax-Crontab
|
||||
[submodule "assets/syntaxes/02_Extra/NSIS"]
|
||||
path = assets/syntaxes/02_Extra/NSIS
|
||||
url = https://github.com/SublimeText/NSIS
|
||||
[submodule "assets/syntaxes/02_Extra/vscode-wgsl"]
|
||||
path = assets/syntaxes/02_Extra/vscode-wgsl
|
||||
url = https://github.com/PolyMeilex/vscode-wgsl.git
|
||||
|
74
CHANGELOG.md
74
CHANGELOG.md
@@ -1,3 +1,77 @@
|
||||
# unreleased
|
||||
|
||||
## Features
|
||||
|
||||
## Bugfixes
|
||||
|
||||
- Fix `NO_COLOR` support, see #2767 (@acuteenvy)
|
||||
|
||||
## Other
|
||||
|
||||
- Upgrade to Rust 2021 edition #2748 (@cyqsimon)
|
||||
- Refactor and cleanup build script #2756 (@cyqsimon)
|
||||
- Checks changelog has been written to for PRs in CI #2766 (@cyqsimon)
|
||||
- Use GitHub API to get correct PR submitter #2791 (@cyqsimon)
|
||||
- Minor benchmark script improvements #2768 (@cyqsimon)
|
||||
- Update Arch Linux package URL in README files #2779 (@brunobell)
|
||||
- Update and improve `zsh` completion, see #2772 (@okapia)
|
||||
- Use proper Architecture for Debian packages built for musl, see #2811 (@Enselic)
|
||||
- Pull in fix for unsafe-libyaml security advisory, see #2812 (@dtolnay)
|
||||
- Update git-version dependency to use Syn v2, see #2816 (@dtolnay)
|
||||
|
||||
## Syntaxes
|
||||
|
||||
- `cmd-help`: scope subcommands followed by other terms, and other misc improvements, see #2819 (@victor-gp)
|
||||
- Upgrade JQ syntax, see #2820 (@dependabot[bot])
|
||||
|
||||
## Themes
|
||||
|
||||
## `bat` as a library
|
||||
|
||||
|
||||
# v0.24.0
|
||||
|
||||
## Features
|
||||
|
||||
- Add environment variable `BAT_PAGING`, see #2629 (@einfachIrgendwer0815)
|
||||
- Add opt-in (`--features lessopen`) support for `LESSOPEN` and `LESSCLOSE`. See #1597, #1739, #2444, #2602, and #2662 (@Anomalocaridid)
|
||||
|
||||
## Bugfixes
|
||||
|
||||
- Fix `more` not being found on Windows when provided via `BAT_PAGER`, see #2570, #2580, and #2651 (@mataha)
|
||||
- Switched default behavior of `--map-syntax` to be case insensitive #2520
|
||||
- Updated version of `serde_yaml` to `0.9`. See #2627 (@Raghav-Bell)
|
||||
- Fix arithmetic overflow in `LineRange::from` and `LineRange::parse_range`, see #2674, #2698 (@skoriop)
|
||||
- Fix paging not happening when stdout is interactive but stdin is not, see #2574 (@Nigecat)
|
||||
- Make `-pp` override `--paging` and vice versa when passed as a later argument, see #2660 (@J-Kappes)
|
||||
|
||||
## Other
|
||||
|
||||
- Output directory for generated assets (completion, manual) can be customized, see #2515 (@tranzystorek-io)
|
||||
- Use the `is-terminal` crate instead of `atty`, see #2530 (@nickelc)
|
||||
- Add Winget Releaser workflow, see #2519 (@sitiom)
|
||||
- Bump MSRV to 1.70, see #2651 (@mataha)
|
||||
|
||||
## Syntaxes
|
||||
|
||||
- Associate `os-release` with `bash` syntax, see #2587 (@cyqsimon)
|
||||
- Associate `Containerfile` with `Dockerfile` syntax, see #2606 (@einfachIrgendwer0815)
|
||||
- Replaced quotes with double quotes so fzf integration example script works on windows and linux. see #2095 (@johnmatthiggins)
|
||||
- Associate `ksh` files with `bash` syntax, see #2633 (@johnmatthiggins)
|
||||
- Associate `sarif` files with `JSON` syntax, see #2695 (@rhysd)
|
||||
- Associate `ron` files with `rust` syntax, see #2427 (@YeungOnion)
|
||||
- Add support for [WebGPU Shader Language](https://www.w3.org/TR/WGSL/), see #2692 (@rhysd)
|
||||
- Add `.dpkg-new` and `.dpkg-tmp` to ignored suffixe, see #2595 (@scop)
|
||||
- fix: Add syntax mapping `*.jsonl` => `json`, see #2539 (@WinterCore)
|
||||
- Update `Julia` syntax, see #2553 (@dependabot)
|
||||
- add `NSIS` support, see #2577 (@idleberg)
|
||||
- Update `ssh-config`, see #2697 (@mrmeszaros)
|
||||
|
||||
## `bat` as a library
|
||||
|
||||
- Add optional output_buffer arg to `Controller::run()` and `Controller::run_with_error_handler()`, see #2618 (@Piturnah)
|
||||
|
||||
|
||||
# v0.23.0
|
||||
|
||||
## Features
|
||||
|
915
Cargo.lock
generated
915
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
70
Cargo.toml
70
Cargo.toml
@@ -3,14 +3,14 @@ authors = ["David Peter <mail@david-peter.de>"]
|
||||
categories = ["command-line-utilities"]
|
||||
description = "A cat(1) clone with wings."
|
||||
homepage = "https://github.com/sharkdp/bat"
|
||||
license = "MIT/Apache-2.0"
|
||||
license = "MIT OR Apache-2.0"
|
||||
name = "bat"
|
||||
repository = "https://github.com/sharkdp/bat"
|
||||
version = "0.23.0"
|
||||
version = "0.24.0"
|
||||
exclude = ["assets/syntaxes/*", "assets/themes/*"]
|
||||
build = "build.rs"
|
||||
edition = '2018'
|
||||
rust-version = "1.64"
|
||||
build = "build/main.rs"
|
||||
edition = '2021'
|
||||
rust-version = "1.70"
|
||||
|
||||
[features]
|
||||
default = ["application"]
|
||||
@@ -25,15 +25,15 @@ application = [
|
||||
# Mainly for developers that want to iterate quickly
|
||||
# Be aware that the included features might change in the future
|
||||
minimal-application = [
|
||||
"atty",
|
||||
"clap",
|
||||
"dirs",
|
||||
"etcetera",
|
||||
"paging",
|
||||
"regex-onig",
|
||||
"wild",
|
||||
]
|
||||
git = ["git2"] # Support indicating git modifications
|
||||
paging = ["shell-words", "grep-cli"] # Support applying a pager on the output
|
||||
lessopen = ["run_script", "os_str_bytes"] # Support $LESSOPEN preprocessor
|
||||
build-assets = ["syntect/yaml-load", "syntect/plist-load", "regex", "walkdir"]
|
||||
|
||||
# You need to use one of these if you depend on bat as a library:
|
||||
@@ -41,64 +41,68 @@ regex-onig = ["syntect/regex-onig"] # Use the "oniguruma" regex engine
|
||||
regex-fancy = ["syntect/regex-fancy"] # Use the rust-only "fancy-regex" engine
|
||||
|
||||
[dependencies]
|
||||
atty = { version = "0.2.14", optional = true }
|
||||
nu-ansi-term = "0.47.0"
|
||||
nu-ansi-term = "0.49.0"
|
||||
ansi_colours = "^1.2"
|
||||
bincode = "1.0"
|
||||
console = "0.15.5"
|
||||
console = "0.15.7"
|
||||
flate2 = "1.0"
|
||||
once_cell = "1.17"
|
||||
once_cell = "1.19"
|
||||
thiserror = "1.0"
|
||||
wild = { version = "2.1", optional = true }
|
||||
wild = { version = "2.2", optional = true }
|
||||
content_inspector = "0.2.4"
|
||||
encoding = "0.2"
|
||||
shell-words = { version = "1.1.0", optional = true }
|
||||
unicode-width = "0.1.10"
|
||||
unicode-width = "0.1.11"
|
||||
globset = "0.4"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_yaml = "0.8"
|
||||
serde_yaml = "0.9.28"
|
||||
semver = "1.0"
|
||||
path_abs = { version = "0.5", default-features = false }
|
||||
clircle = "0.3"
|
||||
clircle = "0.4"
|
||||
bugreport = { version = "0.5.0", optional = true }
|
||||
dirs = { version = "5.0.0", optional = true }
|
||||
grep-cli = { version = "0.1.7", optional = true }
|
||||
regex = { version = "1.7.0", optional = true }
|
||||
walkdir = { version = "2.0", optional = true }
|
||||
bytesize = { version = "1.1.0" }
|
||||
etcetera = { version = "0.8.0", optional = true }
|
||||
grep-cli = { version = "0.1.10", optional = true }
|
||||
regex = { version = "1.10.2", optional = true }
|
||||
walkdir = { version = "2.4", optional = true }
|
||||
bytesize = { version = "1.3.0" }
|
||||
encoding_rs = "0.8.33"
|
||||
os_str_bytes = { version = "~6.6", optional = true }
|
||||
run_script = { version = "^0.10.1", optional = true}
|
||||
|
||||
[dependencies.git2]
|
||||
version = "0.16"
|
||||
version = "0.18"
|
||||
optional = true
|
||||
default-features = false
|
||||
|
||||
[dependencies.syntect]
|
||||
version = "5.0.0"
|
||||
version = "5.1.0"
|
||||
default-features = false
|
||||
features = ["parsing"]
|
||||
|
||||
[dependencies.clap]
|
||||
version = "4.1.8"
|
||||
version = "4.4.12"
|
||||
optional = true
|
||||
features = ["wrap_help", "cargo"]
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
dirs = "5.0.0"
|
||||
plist = "1.3"
|
||||
home = "0.5.9"
|
||||
plist = "1.5.1"
|
||||
|
||||
[dev-dependencies]
|
||||
assert_cmd = "2.0.8"
|
||||
expect-test = "1.4.0"
|
||||
serial_test = "0.6.0"
|
||||
predicates = "2.1.5"
|
||||
assert_cmd = "2.0.12"
|
||||
expect-test = "1.4.1"
|
||||
serial_test = { version = "2.0.0", default-features = false }
|
||||
predicates = "3.0.4"
|
||||
wait-timeout = "0.2.0"
|
||||
tempfile = "3.3.0"
|
||||
tempfile = "3.8.1"
|
||||
|
||||
[target.'cfg(unix)'.dev-dependencies]
|
||||
nix = { version = "0.26.2", default-features = false, features = ["term"] }
|
||||
nix = { version = "0.26.4", default-features = false, features = ["term"] }
|
||||
|
||||
[build-dependencies]
|
||||
anyhow = "1.0.78"
|
||||
|
||||
[build-dependencies.clap]
|
||||
version = "4.1.8"
|
||||
version = "4.4.12"
|
||||
optional = true
|
||||
features = ["wrap_help", "cargo"]
|
||||
|
||||
|
41
README.md
41
README.md
@@ -32,6 +32,16 @@ A special *thank you* goes to our biggest <a href="doc/sponsors.md">sponsors</a>
|
||||
<sup>Add Single Sign-On (and more) in minutes instead of months.</sup>
|
||||
</a>
|
||||
|
||||
<a href="https://www.warp.dev/?utm_source=github&utm_medium=referral&utm_campaign=bat_20231001">
|
||||
<img src="doc/sponsors/warp-logo.png" width="200" alt="Warp">
|
||||
<br>
|
||||
<strong>Warp is a modern, Rust-based terminal with AI built in<br>so you and your team can build great software, faster.</strong>
|
||||
<br>
|
||||
<sub>Feel more productive on the command line with parameterized commands,</sub>
|
||||
<br>
|
||||
<sup>autosuggestions, and an IDE-like text editor.</sup>
|
||||
</a>
|
||||
|
||||
### Syntax highlighting
|
||||
|
||||
`bat` supports syntax highlighting for a large number of programming and markup
|
||||
@@ -118,7 +128,7 @@ use `bat`s `--color=always` option to force colorized output. You can also use `
|
||||
option to restrict the load times for long files:
|
||||
|
||||
```bash
|
||||
fzf --preview 'bat --color=always --style=numbers --line-range=:500 {}'
|
||||
fzf --preview "bat --color=always --style=numbers --line-range=:500 {}"
|
||||
```
|
||||
|
||||
For more information, see [`fzf`'s `README`](https://github.com/junegunn/fzf#preview-window).
|
||||
@@ -228,12 +238,23 @@ help() {
|
||||
|
||||
Then you can do `$ help cp` or `$ help git commit`.
|
||||
|
||||
When you are using `zsh`, you can also use global aliases to override `-h` and `--help` entirely:
|
||||
|
||||
```bash
|
||||
alias -g -- -h='-h 2>&1 | bat --language=help --style=plain'
|
||||
alias -g -- --help='--help 2>&1 | bat --language=help --style=plain'
|
||||
```
|
||||
|
||||
This way, you can keep on using `cp --help`, but get colorized help pages.
|
||||
|
||||
Be aware that in some cases, `-h` may not be a shorthand of `--help` (for example with `ls`).
|
||||
|
||||
Please report any issues with the help syntax in [this repository](https://github.com/victor-gp/cmd-help-sublime-syntax).
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
[](https://repology.org/project/bat-cat/versions)
|
||||
[](https://repology.org/project/bat-cat/versions)
|
||||
|
||||
### On Ubuntu (using `apt`)
|
||||
*... and other Debian-based Linux distributions.*
|
||||
@@ -275,7 +296,7 @@ apk add bat
|
||||
|
||||
### On Arch Linux
|
||||
|
||||
You can install [the `bat` package](https://www.archlinux.org/packages/community/x86_64/bat/)
|
||||
You can install [the `bat` package](https://www.archlinux.org/packages/extra/x86_64/bat/)
|
||||
from the official sources:
|
||||
|
||||
```bash
|
||||
@@ -390,6 +411,14 @@ take a look at the ["Using `bat` on Windows"](#using-bat-on-windows) section.
|
||||
|
||||
You will need to install the [Visual C++ Redistributable](https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads) package.
|
||||
|
||||
#### With WinGet
|
||||
|
||||
You can install `bat` via [WinGet](https://learn.microsoft.com/en-us/windows/package-manager/winget):
|
||||
|
||||
```bash
|
||||
winget install sharkdp.bat
|
||||
```
|
||||
|
||||
#### With Chocolatey
|
||||
|
||||
You can install `bat` via [Chocolatey](https://chocolatey.org/packages/Bat):
|
||||
@@ -418,7 +447,7 @@ binaries are also available: look for archives with `musl` in the file name.
|
||||
|
||||
### From source
|
||||
|
||||
If you want to build `bat` from source, you need Rust 1.64.0 or
|
||||
If you want to build `bat` from source, you need Rust 1.70.0 or
|
||||
higher. You can then use `cargo` to build everything:
|
||||
|
||||
```bash
|
||||
@@ -684,9 +713,7 @@ Windows 10 natively supports colors in both `conhost.exe` (Command Prompt) and P
|
||||
well as in newer versions of bash. On earlier versions of Windows, you can use
|
||||
[Cmder](http://cmder.net/), which includes [ConEmu](https://conemu.github.io/).
|
||||
|
||||
**Note:** The Git and MSYS versions of `less` do not correctly interpret colors on Windows. If you
|
||||
don’t have any other pagers installed, you can disable paging entirely by passing `--paging=never`
|
||||
or by setting `BAT_PAGER` to an empty string.
|
||||
**Note:** Old versions of `less` do not correctly interpret colors on Windows. To fix this, you can add the optional Unix tools to your PATH when installing Git. If you don’t have any other pagers installed, you can disable paging entirely by passing `--paging=never` or by setting `BAT_PAGER` to an empty string.
|
||||
|
||||
### Cygwin
|
||||
|
||||
|
BIN
assets/acknowledgements.bin
vendored
BIN
assets/acknowledgements.bin
vendored
Binary file not shown.
2
assets/completions/_bat.ps1.in
vendored
2
assets/completions/_bat.ps1.in
vendored
@@ -59,6 +59,8 @@ Register-ArgumentCompleter -Native -CommandName '{{PROJECT_EXECUTABLE}}' -Script
|
||||
[CompletionResult]::new('--unbuffered', 'unbuffered', [CompletionResultType]::ParameterName, 'unbuffered')
|
||||
[CompletionResult]::new('--no-config', 'no-config', [CompletionResultType]::ParameterName, 'Do not use the configuration file')
|
||||
[CompletionResult]::new('--no-custom-assets', 'no-custom-assets', [CompletionResultType]::ParameterName, 'Do not load custom assets')
|
||||
[CompletionResult]::new('--lessopen', 'lessopen', [CompletionResultType]::ParameterName, 'Enable the $LESSOPEN preprocessor')
|
||||
[CompletionResult]::new('--no-lessopen', 'no-lessopen', [CompletionResultType]::ParameterName, 'Disable the $LESSOPEN preprocessor if enabled (overrides --lessopen)')
|
||||
[CompletionResult]::new('--config-file', 'config-file', [CompletionResultType]::ParameterName, 'Show path to the configuration file.')
|
||||
[CompletionResult]::new('--generate-config-file', 'generate-config-file', [CompletionResultType]::ParameterName, 'Generates a default configuration file.')
|
||||
[CompletionResult]::new('--config-dir', 'config-dir', [CompletionResultType]::ParameterName, 'Show bat''s configuration directory.')
|
||||
|
4
assets/completions/bat.bash.in
vendored
4
assets/completions/bat.bash.in
vendored
@@ -32,7 +32,7 @@ __bat_escape_completions()
|
||||
}
|
||||
|
||||
_bat() {
|
||||
local cur prev words cword split=false
|
||||
local cur prev words split=false
|
||||
if declare -F _init_completion >/dev/null 2>&1; then
|
||||
_init_completion -s || return 0
|
||||
else
|
||||
@@ -78,6 +78,7 @@ _bat() {
|
||||
--list-themes | \
|
||||
--line-range | \
|
||||
-L | --list-languages | \
|
||||
--lessopen | \
|
||||
--diagnostic | \
|
||||
--acknowledgements | \
|
||||
-h | --help | \
|
||||
@@ -171,6 +172,7 @@ _bat() {
|
||||
--style
|
||||
--line-range
|
||||
--list-languages
|
||||
--lessopen
|
||||
--diagnostic
|
||||
--acknowledgements
|
||||
--help
|
||||
|
10
assets/completions/bat.fish.in
vendored
10
assets/completions/bat.fish.in
vendored
@@ -147,6 +147,8 @@ complete -c $bat -s d -l diff -d "Only show lines with Git changes" -n __bat_no_
|
||||
|
||||
complete -c $bat -l diff-context -x -d "Show N context lines around Git changes" -n "__fish_seen_argument -s d -l diff"
|
||||
|
||||
complete -c $bat -l generate-config-file -f -d "Generates a default configuration file" -n __fish_is_first_arg
|
||||
|
||||
complete -c $bat -l file-name -x -d "Specify the display name" -n __bat_no_excl_args
|
||||
|
||||
complete -c $bat -s f -l force-colorization -d "Force color and decorations" -n __bat_no_excl_args
|
||||
@@ -163,6 +165,8 @@ complete -c $bat -l italic-text -x -a "$italic_text_opts" -d "When to use italic
|
||||
|
||||
complete -c $bat -s l -l language -x -k -a "(__bat_complete_list_languages)" -d "Set the syntax highlighting language" -n __bat_no_excl_args
|
||||
|
||||
complete -c $bat -l lessopen -d "Enable the $LESSOPEN preprocessor" -n __fish_is_first_arg
|
||||
|
||||
complete -c $bat -s r -l line-range -x -d "Only print lines [M]:[N] (either optional)" -n __bat_no_excl_args
|
||||
|
||||
complete -c $bat -l list-languages -f -d "List syntax highlighting languages" -n __fish_is_first_arg
|
||||
@@ -171,6 +175,12 @@ complete -c $bat -l list-themes -f -d "List syntax highlighting themes" -n __fis
|
||||
|
||||
complete -c $bat -s m -l map-syntax -x -a "(__bat_complete_map_syntax)" -d "Map <glob pattern>:<language syntax>" -n __bat_no_excl_args
|
||||
|
||||
complete -c $bat -l no-config -d "Do not use the configuration file"
|
||||
|
||||
complete -c $bat -l no-custom-assets -d "Do not load custom assets"
|
||||
|
||||
complete -c $bat -l no-lessopen -d "Disable the $LESSOPEN preprocessor if enabled (overrides --lessopen)"
|
||||
|
||||
complete -c $bat -s n -l number -d "Only show line numbers, no other decorations" -n __bat_no_excl_args
|
||||
|
||||
complete -c $bat -l pager -x -a "$pager_opts" -d "Which pager to use" -n __bat_no_excl_args
|
||||
|
113
assets/completions/bat.zsh.in
vendored
113
assets/completions/bat.zsh.in
vendored
@@ -1,19 +1,20 @@
|
||||
#compdef {{PROJECT_EXECUTABLE}}
|
||||
|
||||
local context state state_descr line
|
||||
local curcontext="$curcontext" ret=1
|
||||
local -a state state_descr line
|
||||
typeset -A opt_args
|
||||
|
||||
(( $+functions[_{{PROJECT_EXECUTABLE}}_cache_subcommand] )) ||
|
||||
_{{PROJECT_EXECUTABLE}}_cache_subcommand() {
|
||||
local -a args
|
||||
args=(
|
||||
'(-b --build -c --clear)'{-b,--build}'[Initialize or update the syntax/theme cache]'
|
||||
'(-b --build -c --clear)'{-c,--clear}'[Remove the cached syntax definitions and themes]'
|
||||
'(--source)'--source='[Use a different directory to load syntaxes and themes from]:directory:_files -/'
|
||||
'(--target)'--target='[Use a different directory to store the cached syntax and theme set]:directory:_files -/'
|
||||
'(--blank)'--blank'[Create completely new syntax and theme sets]'
|
||||
'(: -)'{-h,--help}'[Prints help information]'
|
||||
'*: :'
|
||||
'(-b --build -c --clear)'{-b,--build}'[initialize or update the syntax/theme cache]'
|
||||
'(-b --build -c --clear)'{-c,--clear}'[remove the cached syntax definitions and themes]'
|
||||
--source='[specify directory to load syntaxes and themes from]:directory:_files -/'
|
||||
--target='[specify directory to store the cached syntax and theme set in]:directory:_files -/'
|
||||
--blank'[create completely new syntax and theme sets]'
|
||||
--acknowledgements'[build acknowledgements.bin]'
|
||||
'(: -)'{-h,--help}'[show help information]'
|
||||
)
|
||||
|
||||
_arguments -S -s $args
|
||||
@@ -23,67 +24,79 @@ _{{PROJECT_EXECUTABLE}}_cache_subcommand() {
|
||||
_{{PROJECT_EXECUTABLE}}_main() {
|
||||
local -a args
|
||||
args=(
|
||||
'(-A --show-all)'{-A,--show-all}'[Show non-printable characters (space, tab, newline, ..)]'
|
||||
'*'{-p,--plain}'[Show plain style (alias for `--style=plain`), repeat twice to disable disable automatic paging (alias for `--paging=never`)]'
|
||||
'(-l --language)'{-l+,--language=}'[Set the language for syntax highlighting]:<language>:->language'
|
||||
'(-H --highlight-line)'{-H,--highlight-line}'[Highlight lines N through M]:<N\:M>...'
|
||||
'(--file-name)'--file-name'[Specify the name to display for a file]:<name>...:_files'
|
||||
'(-d --diff)'--diff'[Only show lines that have been added/removed/modified]'
|
||||
'(--diff-context)'--diff-context'[Include N lines of context around added/removed/modified lines when using `--diff`]:<N> (lines):()'
|
||||
'(--tabs)'--tabs'[Set the tab width to T spaces]:<T> (tab width):()'
|
||||
'(--wrap)'--wrap='[Specify the text-wrapping mode]:<when>:(auto never character)'
|
||||
'(--terminal-width)'--terminal-width'[Explicitly set the width of the terminal instead of determining it automatically]:<width>'
|
||||
'(-n --number)'{-n,--number}'[Show line numbers]'
|
||||
'(--color)'--color='[When to use colors]:<when>:(auto never always)'
|
||||
'(--italic-text)'--italic-text='[Use italics in output]:<when>:(always never)'
|
||||
'(--decorations)'--decorations='[When to show the decorations]:<when>:(auto never always)'
|
||||
'(--paging)'--paging='[Specify when to use the pager]:<when>:(auto never always)'
|
||||
'(-m --map-syntax)'{-m+,--map-syntax=}'[Use the specified syntax for files matching the glob pattern]:<glob\:syntax>...'
|
||||
'(--theme)'--theme='[Set the color theme for syntax highlighting]:<theme>:->theme'
|
||||
'(: --list-themes --list-languages -L)'--list-themes'[Display all supported highlighting themes]'
|
||||
'(--style)'--style='[Comma-separated list of style elements to display]:<components>:->style'
|
||||
'(-r --line-range)'{-r+,--line-range=}'[Only print the lines from N to M]:<N\:M>...'
|
||||
'(: --list-themes --list-languages -L)'{-L,--list-languages}'[Display all supported languages]'
|
||||
'(: --no-config)'--no-config'[Do not use the configuration file]'
|
||||
'(: --no-custom-assets)'--no-custom-assets'[Do not load custom assets]'
|
||||
'(: --config-dir)'--config-dir'[Show bat'"'"'s configuration directory]'
|
||||
'(: --config-file)'--config-file'[Show path to the configuration file]'
|
||||
'(: --generate-config-file)'--generate-config-file'[Generates a default configuration file]'
|
||||
'(: --cache-dir)'--cache-dir'[Show bat'"'"'s cache directory]'
|
||||
'(: -)'{-h,--help}'[Print this help message]'
|
||||
'(: -)'{-V,--version}'[Show version information]'
|
||||
'*: :_files'
|
||||
'(-A --show-all)'{-A,--show-all}'[show non-printable characters (space, tab, newline, ..)]'
|
||||
--nonprintable-notation='[specify how to display non-printable characters when using --show-all]:notation:(caret unicode)'
|
||||
\*{-p,--plain}'[show plain style (alias for `--style=plain`), repeat twice to disable disable automatic paging (alias for `--paging=never`)]'
|
||||
'(-l --language)'{-l+,--language=}'[set the language for syntax highlighting]:language:->languages'
|
||||
\*{-H+,--highlight-line=}'[highlight specified block of lines]:start\:end'
|
||||
\*--file-name='[specify the name to display for a file]:name:_files'
|
||||
'(-d --diff)'--diff'[only show lines that have been added/removed/modified]'
|
||||
--diff-context='[specify lines of context around added/removed/modified lines when using `--diff`]:lines'
|
||||
--tabs='[set the tab width]:tab width [4]'
|
||||
--wrap='[specify the text-wrapping mode]:mode [auto]:(auto never character)'
|
||||
'!(--wrap)'{-S,--chop-long-lines}
|
||||
--terminal-width='[explicitly set the width of the terminal instead of determining it automatically]:width'
|
||||
'(-n --number --diff --diff-context)'{-n,--number}'[show line numbers]'
|
||||
--color='[specify when to use colors]:when:(auto never always)'
|
||||
--italic-text='[use italics in output]:when:(always never)'
|
||||
--decorations='[specify when to show the decorations]:when:(auto never always)'
|
||||
--paging='[specify when to use the pager]:when:(auto never always)'
|
||||
'(-m --map-syntax)'{-m+,--map-syntax=}'[map a glob pattern to an existing syntax name]: :->syntax-maps'
|
||||
'(--theme)'--theme='[set the color theme for syntax highlighting]:theme:->themes'
|
||||
'(: --list-themes --list-languages -L)'--list-themes'[show all supported highlighting themes]'
|
||||
--style='[comma-separated list of style elements to display]: : _values "style [default]"
|
||||
default auto full plain changes header header-filename header-filesize grid rule numbers snip'
|
||||
\*{-r+,--line-range=}'[only print the specified line range]:start\:end'
|
||||
'(* -)'{-L,--list-languages}'[display all supported languages]'
|
||||
"--no-config[don't use the configuration file]"
|
||||
"--no-custom-assets[don't load custom assets]"
|
||||
'(--no-lessopen)'--lessopen'[enable the $LESSOPEN preprocessor]'
|
||||
'(--lessopen)'--no-lessopen'[disable the $LESSOPEN preprocessor if enabled (overrides --lessopen)]'
|
||||
'(* -)'--config-dir"[show bat's configuration directory]"
|
||||
'(* -)'--config-file'[show path to the configuration file]'
|
||||
'(* -)'--generate-config-file'[generate a default configuration file]'
|
||||
'(* -)'--cache-dir"[show bat's cache directory]"
|
||||
'(* -)'{-h,--help}'[show help information]'
|
||||
'(* -)'{-V,--version}'[show version information]'
|
||||
'*: :{ _files || compadd cache }'
|
||||
)
|
||||
|
||||
_arguments -S -s $args
|
||||
_arguments -S -s $args && ret=0
|
||||
|
||||
case "$state" in
|
||||
language)
|
||||
syntax-maps)
|
||||
if ! compset -P '*:'; then
|
||||
_message -e patterns 'glob pattern:language'
|
||||
return
|
||||
fi
|
||||
;& # fall-through
|
||||
|
||||
languages)
|
||||
local IFS=$'\n'
|
||||
local -a languages
|
||||
languages=( $({{PROJECT_EXECUTABLE}} --list-languages | awk -F':|,' '{ for (i = 1; i <= NF; ++i) printf("%s:%s\n", $i, $1) }') )
|
||||
|
||||
_describe 'language' languages
|
||||
_describe 'language' languages && ret=0
|
||||
;;
|
||||
|
||||
theme)
|
||||
local IFS=$'\n'
|
||||
local -a themes
|
||||
themes=( $({{PROJECT_EXECUTABLE}} --list-themes | sort) )
|
||||
themes)
|
||||
local -a themes expl
|
||||
themes=( ${(f)"$(_call_program themes {{PROJECT_EXECUTABLE}} --list-themes)"} )
|
||||
|
||||
_values 'theme' $themes
|
||||
;;
|
||||
|
||||
style)
|
||||
_values -s , 'style' default auto full plain changes header header-filename header-filesize grid rule numbers snip
|
||||
_wanted themes expl 'theme' compadd -a themes && ret=0
|
||||
;;
|
||||
esac
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
case $words[2] in
|
||||
cache)
|
||||
## Completion of the 'cache' command itself is removed for better UX
|
||||
## See https://github.com/sharkdp/bat/issues/2085#issuecomment-1271646802
|
||||
shift words
|
||||
(( CURRENT-- ))
|
||||
curcontext="${curcontext%:*}-${words[1]}:"
|
||||
_{{PROJECT_EXECUTABLE}}_cache_subcommand
|
||||
;;
|
||||
|
||||
|
19
assets/manual/bat.1.in
vendored
19
assets/manual/bat.1.in
vendored
@@ -25,7 +25,7 @@ either '--language value', '--language=value', '-l value' or '-lvalue'.
|
||||
Show non\-printable characters like space, tab or newline. Use '\-\-tabs' to
|
||||
control the width of the tab\-placeholders.
|
||||
.HP
|
||||
\fB\-\-nonprintable\-notation\fR
|
||||
\fB\-\-nonprintable\-notation\fR <notation>
|
||||
.IP
|
||||
Specify how to display non-printable characters when using \-\-show\-all.
|
||||
|
||||
@@ -243,6 +243,23 @@ If you ever want to remove the custom languages, you can clear the cache with `\
|
||||
Similarly to custom languages, {{PROJECT_EXECUTABLE}} supports Sublime Text \fB.tmTheme\fR themes.
|
||||
These can be installed to `\fB$({{PROJECT_EXECUTABLE}} --config-dir)/themes\fR`, and are added to the cache with
|
||||
`\fB{{PROJECT_EXECUTABLE}} cache --build`.
|
||||
|
||||
.SH "INPUT PREPROCESSOR"
|
||||
Much like less(1) does, {{PROJECT_EXECUTABLE}} supports input preprocessors via the LESSOPEN and LESSCLOSE environment variables.
|
||||
In addition, {{PROJECT_EXECUTABLE}} attempts to be as compatible with less's preprocessor implementation as possible.
|
||||
|
||||
To use the preprocessor, call:
|
||||
|
||||
\fB{{PROJECT_EXECUTABLE}} --lessopen\fR
|
||||
|
||||
Alternatively, the preprocessor may be enabled by default by adding the '\-\-lessopen' option to the configuration file.
|
||||
|
||||
To temporarily disable the preprocessor if it is enabled by default, call:
|
||||
|
||||
\fB{{PROJECT_EXECUTABLE}} --no-lessopen\fR
|
||||
|
||||
For more information, see the "INPUT PREPROCESSOR" section of less(1).
|
||||
|
||||
.SH "MORE INFORMATION"
|
||||
|
||||
For more information and up-to-date documentation, visit the {{PROJECT_EXECUTABLE}} repo:
|
||||
|
BIN
assets/syntaxes.bin
vendored
BIN
assets/syntaxes.bin
vendored
Binary file not shown.
2
assets/syntaxes/02_Extra/Docker
vendored
2
assets/syntaxes/02_Extra/Docker
vendored
Submodule assets/syntaxes/02_Extra/Docker updated: 9e9a518aed...0f6b7bc87a
2
assets/syntaxes/02_Extra/Julia
vendored
2
assets/syntaxes/02_Extra/Julia
vendored
Submodule assets/syntaxes/02_Extra/Julia updated: 4fde0fdedd...98233f96d4
1
assets/syntaxes/02_Extra/NSIS
vendored
Submodule
1
assets/syntaxes/02_Extra/NSIS
vendored
Submodule
Submodule assets/syntaxes/02_Extra/NSIS added at 619a65a04e
2
assets/syntaxes/02_Extra/SublimeJQ
vendored
2
assets/syntaxes/02_Extra/SublimeJQ
vendored
Submodule assets/syntaxes/02_Extra/SublimeJQ updated: 687058289c...b7e53e5d86
2
assets/syntaxes/02_Extra/cmd-help
vendored
2
assets/syntaxes/02_Extra/cmd-help
vendored
Submodule assets/syntaxes/02_Extra/cmd-help updated: f41e5fc838...b150d84534
2
assets/syntaxes/02_Extra/ssh-config
vendored
2
assets/syntaxes/02_Extra/ssh-config
vendored
Submodule assets/syntaxes/02_Extra/ssh-config updated: e1012e9f13...bf49e9181c
1
assets/syntaxes/02_Extra/vscode-wgsl
vendored
Submodule
1
assets/syntaxes/02_Extra/vscode-wgsl
vendored
Submodule
Submodule assets/syntaxes/02_Extra/vscode-wgsl added at acf26718d7
198
assets/syntaxes/02_Extra/wgsl.sublime-syntax
vendored
Normal file
198
assets/syntaxes/02_Extra/wgsl.sublime-syntax
vendored
Normal file
@@ -0,0 +1,198 @@
|
||||
%YAML 1.2
|
||||
---
|
||||
# http://www.sublimetext.com/docs/syntax.html
|
||||
name: WGSL
|
||||
file_extensions:
|
||||
- wgsl
|
||||
scope: source.wgsl
|
||||
contexts:
|
||||
main:
|
||||
- include: line_comments
|
||||
- include: block_comments
|
||||
- include: keywords
|
||||
- include: attributes
|
||||
- include: functions
|
||||
- include: function_calls
|
||||
- include: constants
|
||||
- include: types
|
||||
- include: variables
|
||||
- include: punctuation
|
||||
attributes:
|
||||
- match: '(@)([A-Za-z_]+)'
|
||||
comment: attribute declaration
|
||||
scope: meta.attribute.wgsl
|
||||
captures:
|
||||
1: keyword.operator.attribute.at
|
||||
2: entity.name.attribute.wgsl
|
||||
block_comments:
|
||||
- match: /\*\*/
|
||||
comment: empty block comments
|
||||
scope: comment.block.wgsl
|
||||
- match: /\*\*
|
||||
comment: block documentation comments
|
||||
push:
|
||||
- meta_scope: comment.block.documentation.wgsl
|
||||
- match: \*/
|
||||
pop: true
|
||||
- include: block_comments
|
||||
- match: /\*(?!\*)
|
||||
comment: block comments
|
||||
push:
|
||||
- meta_scope: comment.block.wgsl
|
||||
- match: \*/
|
||||
pop: true
|
||||
- include: block_comments
|
||||
constants:
|
||||
- match: '(-?\b[0-9][0-9]*\.[0-9][0-9]*)([eE][+-]?[0-9]+)?\b'
|
||||
comment: decimal float literal
|
||||
scope: constant.numeric.float.wgsl
|
||||
- match: '-?\b0x[0-9a-fA-F]+\b|\b0\b|-?\b[1-9][0-9]*\b'
|
||||
comment: int literal
|
||||
scope: constant.numeric.decimal.wgsl
|
||||
- match: '\b0x[0-9a-fA-F]+u\b|\b0u\b|\b[1-9][0-9]*u\b'
|
||||
comment: uint literal
|
||||
scope: constant.numeric.decimal.wgsl
|
||||
- match: \b(true|false)\b
|
||||
comment: boolean constant
|
||||
scope: constant.language.boolean.wgsl
|
||||
function_calls:
|
||||
- match: '([A-Za-z0-9_]+)(\()'
|
||||
comment: function/method calls
|
||||
captures:
|
||||
1: entity.name.function.wgsl
|
||||
2: punctuation.brackets.round.wgsl
|
||||
push:
|
||||
- meta_scope: meta.function.call.wgsl
|
||||
- match: \)
|
||||
captures:
|
||||
0: punctuation.brackets.round.wgsl
|
||||
pop: true
|
||||
- include: line_comments
|
||||
- include: block_comments
|
||||
- include: keywords
|
||||
- include: attributes
|
||||
- include: function_calls
|
||||
- include: constants
|
||||
- include: types
|
||||
- include: variables
|
||||
- include: punctuation
|
||||
functions:
|
||||
- match: '\b(fn)\s+([A-Za-z0-9_]+)((\()|(<))'
|
||||
comment: function definition
|
||||
captures:
|
||||
1: keyword.other.fn.wgsl
|
||||
2: entity.name.function.wgsl
|
||||
4: punctuation.brackets.round.wgsl
|
||||
push:
|
||||
- meta_scope: meta.function.definition.wgsl
|
||||
- match: '\{'
|
||||
captures:
|
||||
0: punctuation.brackets.curly.wgsl
|
||||
pop: true
|
||||
- include: line_comments
|
||||
- include: block_comments
|
||||
- include: keywords
|
||||
- include: attributes
|
||||
- include: function_calls
|
||||
- include: constants
|
||||
- include: types
|
||||
- include: variables
|
||||
- include: punctuation
|
||||
keywords:
|
||||
- match: \b(bitcast|block|break|case|continue|continuing|default|discard|else|elseif|enable|fallthrough|for|function|if|loop|private|read|read_write|return|storage|switch|uniform|while|workgroup|write)\b
|
||||
comment: other keywords
|
||||
scope: keyword.control.wgsl
|
||||
- match: \b(asm|const|do|enum|handle|mat|premerge|regardless|typedef|unless|using|vec|void)\b
|
||||
comment: reserved keywords
|
||||
scope: keyword.control.wgsl
|
||||
- match: \b(let|var)\b
|
||||
comment: storage keywords
|
||||
scope: keyword.other.wgsl storage.type.wgsl
|
||||
- match: \b(type)\b
|
||||
comment: type keyword
|
||||
scope: keyword.declaration.type.wgsl storage.type.wgsl
|
||||
- match: \b(enum)\b
|
||||
comment: enum keyword
|
||||
scope: keyword.declaration.enum.wgsl storage.type.wgsl
|
||||
- match: \b(struct)\b
|
||||
comment: struct keyword
|
||||
scope: keyword.declaration.struct.wgsl storage.type.wgsl
|
||||
- match: \bfn\b
|
||||
comment: fn
|
||||
scope: keyword.other.fn.wgsl
|
||||
- match: (\^|\||\|\||&&|<<|>>|!)(?!=)
|
||||
comment: logical operators
|
||||
scope: keyword.operator.logical.wgsl
|
||||
- match: '&(?![&=])'
|
||||
comment: logical AND, borrow references
|
||||
scope: keyword.operator.borrow.and.wgsl
|
||||
- match: (\+=|-=|\*=|/=|%=|\^=|&=|\|=|<<=|>>=)
|
||||
comment: assignment operators
|
||||
scope: keyword.operator.assignment.wgsl
|
||||
- match: '(?<![<>])=(?!=|>)'
|
||||
comment: single equal
|
||||
scope: keyword.operator.assignment.equal.wgsl
|
||||
- match: (=(=)?(?!>)|!=|<=|(?<!=)>=)
|
||||
comment: comparison operators
|
||||
scope: keyword.operator.comparison.wgsl
|
||||
- match: '(([+%]|(\*(?!\w)))(?!=))|(-(?!>))|(/(?!/))'
|
||||
comment: math operators
|
||||
scope: keyword.operator.math.wgsl
|
||||
- match: \.(?!\.)
|
||||
comment: dot access
|
||||
scope: keyword.operator.access.dot.wgsl
|
||||
- match: '->'
|
||||
comment: dashrocket, skinny arrow
|
||||
scope: keyword.operator.arrow.skinny.wgsl
|
||||
line_comments:
|
||||
- match: \s*//.*
|
||||
comment: single line comment
|
||||
scope: comment.line.double-slash.wgsl
|
||||
punctuation:
|
||||
- match: ','
|
||||
comment: comma
|
||||
scope: punctuation.comma.wgsl
|
||||
- match: '[{}]'
|
||||
comment: curly braces
|
||||
scope: punctuation.brackets.curly.wgsl
|
||||
- match: '[()]'
|
||||
comment: parentheses, round brackets
|
||||
scope: punctuation.brackets.round.wgsl
|
||||
- match: ;
|
||||
comment: semicolon
|
||||
scope: punctuation.semi.wgsl
|
||||
- match: '[\[\]]'
|
||||
comment: square brackets
|
||||
scope: punctuation.brackets.square.wgsl
|
||||
- match: '(?<![=-])[<>]'
|
||||
comment: angle brackets
|
||||
scope: punctuation.brackets.angle.wgsl
|
||||
types:
|
||||
- match: \b(bool|i32|u32|f32)\b
|
||||
comment: scalar Types
|
||||
scope: storage.type.wgsl
|
||||
- match: \b(i64|u64|f64)\b
|
||||
comment: reserved scalar Types
|
||||
scope: storage.type.wgsl
|
||||
- match: \b(vec2i|vec3i|vec4i|vec2u|vec3u|vec4u|vec2f|vec3f|vec4f|vec2h|vec3h|vec4h)\b
|
||||
comment: vector type aliasses
|
||||
scope: storage.type.wgsl
|
||||
- match: \b(mat2x2f|mat2x3f|mat2x4f|mat3x2f|mat3x3f|mat3x4f|mat4x2f|mat4x3f|mat4x4f|mat2x2h|mat2x3h|mat2x4h|mat3x2h|mat3x3h|mat3x4h|mat4x2h|mat4x3h|mat4x4h)\b
|
||||
comment: matrix type aliasses
|
||||
scope: storage.type.wgsl
|
||||
- match: '\b(vec[2-4]|mat[2-4]x[2-4])\b'
|
||||
comment: vector/matrix types
|
||||
scope: storage.type.wgsl
|
||||
- match: \b(atomic)\b
|
||||
comment: atomic types
|
||||
scope: storage.type.wgsl
|
||||
- match: \b(array)\b
|
||||
comment: array types
|
||||
scope: storage.type.wgsl
|
||||
- match: '\b([A-Z][A-Za-z0-9]*)\b'
|
||||
comment: Custom type
|
||||
scope: entity.name.type.wgsl
|
||||
variables:
|
||||
- match: '\b(?<!(?<!\.)\.)(?:r#(?!(crate|[Ss]elf|super)))?[a-z0-9_]+\b'
|
||||
comment: variables
|
||||
scope: variable.other.wgsl
|
2
assets/themes/zenburn
vendored
2
assets/themes/zenburn
vendored
Submodule assets/themes/zenburn updated: 43dc527731...e627f1cb22
106
build.rs
106
build.rs
@@ -1,106 +0,0 @@
|
||||
// TODO: Re-enable generation of shell completion files (below) when clap 3 is out.
|
||||
// For more details, see https://github.com/sharkdp/bat/issues/372
|
||||
|
||||
// For bat-as-a-library, no build script is required. The build script is for
|
||||
// the manpage and completions, which are only relevant to the bat application.
|
||||
#[cfg(not(feature = "application"))]
|
||||
fn main() {}
|
||||
|
||||
#[cfg(feature = "application")]
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
use std::collections::HashMap;
|
||||
use std::error::Error;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
// Read environment variables.
|
||||
let project_name = option_env!("PROJECT_NAME").unwrap_or("bat");
|
||||
let executable_name = option_env!("PROJECT_EXECUTABLE").unwrap_or(project_name);
|
||||
let executable_name_uppercase = executable_name.to_uppercase();
|
||||
static PROJECT_VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
/// Generates a file from a template.
|
||||
fn template(
|
||||
variables: &HashMap<&str, &str>,
|
||||
in_file: &str,
|
||||
out_file: impl AsRef<Path>,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let mut content = fs::read_to_string(in_file)?;
|
||||
|
||||
for (variable_name, value) in variables {
|
||||
// Replace {{variable_name}} by the value
|
||||
let pattern = format!("{{{{{variable_name}}}}}", variable_name = variable_name);
|
||||
content = content.replace(&pattern, value);
|
||||
}
|
||||
|
||||
fs::write(out_file, content)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
let mut variables = HashMap::new();
|
||||
variables.insert("PROJECT_NAME", project_name);
|
||||
variables.insert("PROJECT_EXECUTABLE", executable_name);
|
||||
variables.insert("PROJECT_EXECUTABLE_UPPERCASE", &executable_name_uppercase);
|
||||
variables.insert("PROJECT_VERSION", PROJECT_VERSION);
|
||||
|
||||
let out_dir_env = std::env::var_os("OUT_DIR").expect("OUT_DIR to be set in build.rs");
|
||||
let out_dir = Path::new(&out_dir_env);
|
||||
|
||||
fs::create_dir_all(out_dir.join("assets/manual")).unwrap();
|
||||
fs::create_dir_all(out_dir.join("assets/completions")).unwrap();
|
||||
|
||||
template(
|
||||
&variables,
|
||||
"assets/manual/bat.1.in",
|
||||
out_dir.join("assets/manual/bat.1"),
|
||||
)?;
|
||||
template(
|
||||
&variables,
|
||||
"assets/completions/bat.bash.in",
|
||||
out_dir.join("assets/completions/bat.bash"),
|
||||
)?;
|
||||
template(
|
||||
&variables,
|
||||
"assets/completions/bat.fish.in",
|
||||
out_dir.join("assets/completions/bat.fish"),
|
||||
)?;
|
||||
template(
|
||||
&variables,
|
||||
"assets/completions/_bat.ps1.in",
|
||||
out_dir.join("assets/completions/_bat.ps1"),
|
||||
)?;
|
||||
template(
|
||||
&variables,
|
||||
"assets/completions/bat.zsh.in",
|
||||
out_dir.join("assets/completions/bat.zsh"),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// #[macro_use]
|
||||
// extern crate clap;
|
||||
|
||||
// use clap::Shell;
|
||||
// use std::fs;
|
||||
|
||||
// include!("src/clap_app.rs");
|
||||
|
||||
// const BIN_NAME: &str = "bat";
|
||||
|
||||
// fn main() {
|
||||
// let outdir = std::env::var_os("SHELL_COMPLETIONS_DIR").or(std::env::var_os("OUT_DIR"));
|
||||
|
||||
// let outdir = match outdir {
|
||||
// None => return,
|
||||
// Some(outdir) => outdir,
|
||||
// };
|
||||
|
||||
// fs::create_dir_all(&outdir).unwrap();
|
||||
|
||||
// let mut app = build_app(true);
|
||||
// app.gen_completions(BIN_NAME, Shell::Bash, &outdir);
|
||||
// app.gen_completions(BIN_NAME, Shell::Fish, &outdir);
|
||||
// app.gen_completions(BIN_NAME, Shell::Zsh, &outdir);
|
||||
// app.gen_completions(BIN_NAME, Shell::PowerShell, &outdir);
|
||||
// }
|
67
build/application.rs
Normal file
67
build/application.rs
Normal file
@@ -0,0 +1,67 @@
|
||||
use std::{env, fs, path::PathBuf};
|
||||
|
||||
use crate::util::render_template;
|
||||
|
||||
/// Generate manpage and shell completions for the bat application.
|
||||
pub fn gen_man_and_comp() -> anyhow::Result<()> {
|
||||
println!("cargo:rerun-if-changed=assets/manual/");
|
||||
println!("cargo:rerun-if-changed=assets/completions/");
|
||||
|
||||
println!("cargo:rerun-if-env-changed=PROJECT_NAME");
|
||||
println!("cargo:rerun-if-env-changed=PROJECT_EXECUTABLE");
|
||||
println!("cargo:rerun-if-env-changed=CARGO_PKG_VERSION");
|
||||
println!("cargo:rerun-if-env-changed=BAT_ASSETS_GEN_DIR");
|
||||
|
||||
// Read environment variables.
|
||||
let project_name = env::var("PROJECT_NAME").unwrap_or("bat".into());
|
||||
let executable_name = env::var("PROJECT_EXECUTABLE").unwrap_or(project_name.clone());
|
||||
let executable_name_uppercase = executable_name.to_uppercase();
|
||||
let project_version = env::var("CARGO_PKG_VERSION")?;
|
||||
|
||||
let variables = [
|
||||
("PROJECT_NAME", project_name),
|
||||
("PROJECT_EXECUTABLE", executable_name),
|
||||
("PROJECT_EXECUTABLE_UPPERCASE", executable_name_uppercase),
|
||||
("PROJECT_VERSION", project_version),
|
||||
]
|
||||
.into_iter()
|
||||
.collect();
|
||||
|
||||
let Some(out_dir) = env::var_os("BAT_ASSETS_GEN_DIR")
|
||||
.or_else(|| env::var_os("OUT_DIR"))
|
||||
.map(PathBuf::from)
|
||||
else {
|
||||
anyhow::bail!("BAT_ASSETS_GEN_DIR or OUT_DIR should be set for build.rs");
|
||||
};
|
||||
|
||||
fs::create_dir_all(out_dir.join("assets/manual")).unwrap();
|
||||
fs::create_dir_all(out_dir.join("assets/completions")).unwrap();
|
||||
|
||||
render_template(
|
||||
&variables,
|
||||
"assets/manual/bat.1.in",
|
||||
out_dir.join("assets/manual/bat.1"),
|
||||
)?;
|
||||
render_template(
|
||||
&variables,
|
||||
"assets/completions/bat.bash.in",
|
||||
out_dir.join("assets/completions/bat.bash"),
|
||||
)?;
|
||||
render_template(
|
||||
&variables,
|
||||
"assets/completions/bat.fish.in",
|
||||
out_dir.join("assets/completions/bat.fish"),
|
||||
)?;
|
||||
render_template(
|
||||
&variables,
|
||||
"assets/completions/_bat.ps1.in",
|
||||
out_dir.join("assets/completions/_bat.ps1"),
|
||||
)?;
|
||||
render_template(
|
||||
&variables,
|
||||
"assets/completions/bat.zsh.in",
|
||||
out_dir.join("assets/completions/bat.zsh"),
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
14
build/main.rs
Normal file
14
build/main.rs
Normal file
@@ -0,0 +1,14 @@
|
||||
#[cfg(feature = "application")]
|
||||
mod application;
|
||||
mod util;
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
// only watch manually-designated files
|
||||
// see: https://doc.rust-lang.org/cargo/reference/build-scripts.html#rerun-if-changed
|
||||
println!("cargo:rerun-if-changed=build/");
|
||||
|
||||
#[cfg(feature = "application")]
|
||||
application::gen_man_and_comp()?;
|
||||
|
||||
Ok(())
|
||||
}
|
21
build/util.rs
Normal file
21
build/util.rs
Normal file
@@ -0,0 +1,21 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::{collections::HashMap, fs, path::Path};
|
||||
|
||||
/// Generates a file from a template.
|
||||
pub fn render_template(
|
||||
variables: &HashMap<&str, String>,
|
||||
in_file: &str,
|
||||
out_file: impl AsRef<Path>,
|
||||
) -> anyhow::Result<()> {
|
||||
let mut content = fs::read_to_string(in_file)?;
|
||||
|
||||
for (variable_name, value) in variables {
|
||||
// Replace {{variable_name}} by the value
|
||||
let pattern = format!("{{{{{variable_name}}}}}");
|
||||
content = content.replace(&pattern, value);
|
||||
}
|
||||
|
||||
fs::write(out_file, content)?;
|
||||
Ok(())
|
||||
}
|
@@ -181,7 +181,7 @@ man 2 select
|
||||
|
||||
## インストール
|
||||
|
||||
[](https://repology.org/project/bat-cat/versions)
|
||||
[](https://repology.org/project/bat-cat/versions)
|
||||
|
||||
### On Ubuntu (`apt` を使用)
|
||||
*... や他のDebianベースのLinuxディストリビューション*
|
||||
@@ -219,7 +219,7 @@ apk add bat
|
||||
|
||||
### On Arch Linux
|
||||
|
||||
[Arch Linuxの公式リソース](https://www.archlinux.org/packages/community/x86_64/bat/)
|
||||
[Arch Linuxの公式リソース](https://www.archlinux.org/packages/extra/x86_64/bat/)
|
||||
からインストールできます。
|
||||
|
||||
```bash
|
||||
@@ -366,7 +366,7 @@ ansible-galaxy install aeimer.install_bat
|
||||
### From source
|
||||
|
||||
|
||||
`bat` をソースからビルドしたいならば、Rust 1.64.0 以上の環境が必要です。
|
||||
`bat` をソースからビルドしたいならば、Rust 1.70.0 以上の環境が必要です。
|
||||
`cargo` を使用してビルドすることができます:
|
||||
|
||||
```bash
|
||||
|
@@ -214,7 +214,7 @@ man 2 select
|
||||
|
||||
## 설치
|
||||
|
||||
[](https://repology.org/project/bat-cat/versions)
|
||||
[](https://repology.org/project/bat-cat/versions)
|
||||
|
||||
### Ubuntu에서 (`apt` 사용)
|
||||
*... 그리고 다른 Debian 기반의 Linux 배포판들에서.*
|
||||
@@ -264,7 +264,7 @@ apk add bat
|
||||
### Arch Linux에서
|
||||
|
||||
공식 소스를 통해
|
||||
[`bat` 패키지](https://www.archlinux.org/packages/community/x86_64/bat/)를
|
||||
[`bat` 패키지](https://www.archlinux.org/packages/extra/x86_64/bat/)를
|
||||
설치할 수 있습니다:
|
||||
|
||||
```bash
|
||||
@@ -416,7 +416,7 @@ scoop install bat
|
||||
|
||||
### 소스에서
|
||||
|
||||
`bat`의 소스를 빌드하기 위해서는, Rust 1.64.0 이상이 필요합니다.
|
||||
`bat`의 소스를 빌드하기 위해서는, Rust 1.70.0 이상이 필요합니다.
|
||||
`cargo`를 이용해 전부 빌드할 수 있습니다:
|
||||
|
||||
```bash
|
||||
|
@@ -12,7 +12,7 @@
|
||||
<a href="#установка">Установка</a> •
|
||||
<a href="#кастомизация">Кастомизация</a> •
|
||||
<a href="#цели-и-альтернативы">Цели и альтернативы </a><br>
|
||||
[<a href="../README.md">English]
|
||||
[<a href="../README.md">English</a>]
|
||||
[<a href="README-zh.md">中文</a>]
|
||||
[<a href="README-ja.md">日本語</a>]
|
||||
[<a href="README-ko.md">한국어</a>]
|
||||
@@ -130,8 +130,8 @@ git show v0.6.0:src/main.rs | bat -l rs
|
||||
|
||||
#### `xclip`
|
||||
|
||||
Нумерация стро и отображение изменений затрудняет копирование содержимого файлов в буфер обмена.
|
||||
Чтобы спроваиться с этим, используйте флаг `-p`/`--plain` или просто перенаправьте стандартный вывод в `xclip`:
|
||||
Нумерация строк и отображение изменений затрудняет копирование содержимого файлов в буфер обмена.
|
||||
Чтобы справиться с этим, используйте флаг `-p`/`--plain` или просто перенаправьте стандартный вывод в `xclip`:
|
||||
```bash
|
||||
bat main.cpp | xclip
|
||||
```
|
||||
@@ -160,7 +160,7 @@ man 2 select
|
||||
|
||||
## Установка
|
||||
|
||||
[](https://repology.org/project/bat-cat/versions)
|
||||
[](https://repology.org/project/bat-cat/versions)
|
||||
|
||||
### Ubuntu (с помощью `apt`)
|
||||
*... и другие дистрибутивы основанные на Debian.*
|
||||
@@ -201,7 +201,7 @@ apk add bat
|
||||
|
||||
### Arch Linux
|
||||
|
||||
Вы можете установить [`bat`](https://www.archlinux.org/packages/community/x86_64/bat/) из официального источника:
|
||||
Вы можете установить [`bat`](https://www.archlinux.org/packages/extra/x86_64/bat/) из официального источника:
|
||||
|
||||
```bash
|
||||
pacman -S bat
|
||||
@@ -344,7 +344,7 @@ ansible-galaxy install aeimer.install_bat
|
||||
|
||||
### Из исходников
|
||||
|
||||
Если вы желаете установить `bat` из исходников, вам понадобится Rust 1.64.0 или выше. После этого используйте `cargo`, чтобы все скомпилировать:
|
||||
Если вы желаете установить `bat` из исходников, вам понадобится Rust 1.70.0 или выше. После этого используйте `cargo`, чтобы все скомпилировать:
|
||||
|
||||
```bash
|
||||
cargo install --locked bat
|
||||
@@ -487,7 +487,7 @@ bat --generate-config-file
|
||||
# Использовать синтаксис C++ для всех Arduino .ino файлов
|
||||
--map-syntax "*.ino:C++"
|
||||
|
||||
# Использовать синтаксик Git Ignore для всех файлов .ignore
|
||||
# Использовать синтаксис Git Ignore для всех файлов .ignore
|
||||
--map-syntax ".ignore:Git Ignore"
|
||||
```
|
||||
|
||||
@@ -535,7 +535,7 @@ bat() {
|
||||
`bat` поддерживает терминалы *с* и *без* поддержки truecolor. Однако подсветка синтаксиса не оптимизирована для терминалов с 8-битными цветами, и рекомендуется использовать терминалы с поддержкой 24-битных цветов (`terminator`, `konsole`, `iTerm2`, ...).
|
||||
Смотрите [эту статью](https://gist.github.com/XVilka/8346728) для полного списка терминалов.
|
||||
|
||||
Удостовертесь, что переменная `COLORTERM` равна `truecolor` или
|
||||
Удостоверьтесь, что переменная `COLORTERM` равна `truecolor` или
|
||||
`24bit`. Иначе `bat` не сможет определить поддержку 24-битных цветов (и будет использовать 8-битные).
|
||||
|
||||
### Текст и номера строк плохо видны
|
||||
@@ -550,7 +550,7 @@ bat() {
|
||||
``` bash
|
||||
iconv -f ISO-8859-1 -t UTF-8 my-file.php | bat
|
||||
```
|
||||
Внимание: вам может понадобится флаг `-l`/`--language`, если `bat` не сможет автоматически определить синтаксис.
|
||||
Внимание: вам может понадобиться флаг `-l`/`--language`, если `bat` не сможет автоматически определить синтаксис.
|
||||
|
||||
## Разработка
|
||||
|
||||
@@ -568,7 +568,7 @@ cargo test
|
||||
# Установка (релизная версия)
|
||||
cargo install --locked
|
||||
|
||||
# Компилирование исполняего файла bat с другим синтаксисом и темами
|
||||
# Компилирование исполняемого файла bat с другим синтаксисом и темами
|
||||
bash assets/create.sh
|
||||
cargo install --locked --force
|
||||
```
|
||||
@@ -592,6 +592,6 @@ cargo install --locked --force
|
||||
## Лицензия
|
||||
Copyright (c) 2018-2021 [Разработчики bat](https://github.com/sharkdp/bat).
|
||||
|
||||
`bat` распостраняется под лицензями MIT License и Apache License 2.0 (на выбор пользователя).
|
||||
`bat` распространяется под лицензиями MIT License и Apache License 2.0 (на выбор пользователя).
|
||||
|
||||
Смотрите [LICENSE-APACHE](LICENSE-APACHE) и [LICENSE-MIT](LICENSE-MIT) для более подробного ознакомления.
|
||||
|
@@ -191,7 +191,7 @@ man 2 select
|
||||
|
||||
## 安装
|
||||
|
||||
[](https://repology.org/project/bat-cat/versions)
|
||||
[](https://repology.org/project/bat-cat/versions)
|
||||
|
||||
### Ubuntu (使用 `apt`)
|
||||
|
||||
@@ -232,7 +232,7 @@ apk add bat
|
||||
|
||||
### Arch Linux
|
||||
|
||||
你可以用下面下列命令从官方源中安装[`bat`包](https://www.archlinux.org/packages/community/x86_64/bat/):
|
||||
你可以用下面下列命令从官方源中安装[`bat`包](https://www.archlinux.org/packages/extra/x86_64/bat/):
|
||||
|
||||
```bash
|
||||
pacman -S bat
|
||||
@@ -372,7 +372,7 @@ scoop install bat
|
||||
|
||||
### 从源码编译
|
||||
|
||||
如果你想要自己构建`bat`,那么你需要安装有高于1.64.0版本的 Rust。
|
||||
如果你想要自己构建`bat`,那么你需要安装有高于1.70.0版本的 Rust。
|
||||
|
||||
使用以下命令编译。
|
||||
|
||||
|
@@ -16,6 +16,9 @@ in the `.sublime-syntax` format.
|
||||
2. If the Sublime Text syntax is only available as a `.tmLanguage` file, open the file in
|
||||
Sublime Text and convert it to a `.sublime-syntax` file via *Tools* -> *Developer* ->
|
||||
*New Syntax from XXX.tmLanguage...*. Save the new file in the `assets/syntaxes` folder.
|
||||
If only `.tmLanguage.json` or `.tmLanguage.yml` file is available, use
|
||||
[PackageDev](https://packagecontrol.io/packages/PackageDev) to convert it to `.tmLanguage.plist`
|
||||
format and then rename the converted file to `.tmLanguage` file.
|
||||
|
||||
3. Run the `assets/create.sh` script. It calls `bat cache --build` to parse all available
|
||||
`.sublime-syntax` files and serialize them to a `syntaxes.bin` file.
|
||||
@@ -84,6 +87,7 @@ The following files have been manually modified after converting from a `.tmLang
|
||||
* `Org mode.sublime-syntax` => removed `task` file type.
|
||||
* `Robot.sublime_syntax` => changed name to "Robot Framework", added `.resource` extension.
|
||||
* `SML.sublime_syntax` => removed `ml` file type.
|
||||
* `wgsl.sublime-syntax` => added `wgsl` file extension.
|
||||
|
||||
### Non-submodule additions
|
||||
|
||||
|
@@ -89,8 +89,8 @@ Options:
|
||||
|
||||
--paging <when>
|
||||
Specify when to use the pager. To disable the pager, use --paging=never' or its
|
||||
alias,'-P'. To disable the pager permanently, set BAT_PAGER to an empty string. To control
|
||||
which pager is used, see the '--pager' option. Possible values: *auto*, never, always.
|
||||
alias,'-P'. To disable the pager permanently, set BAT_PAGING to 'never'. To control which
|
||||
pager is used, see the '--pager' option. Possible values: *auto*, never, always.
|
||||
|
||||
--pager <command>
|
||||
Determine which pager is used. This option will override the PAGER and BAT_PAGER
|
||||
|
@@ -9,7 +9,16 @@
|
||||
- [ ] Update the version and the min. supported Rust version in `README.md` and
|
||||
`doc/README-*.md`. Check with
|
||||
`git grep -i -e 'rust.*1\.' -e '1\..*rust' | grep README | grep -v tests/`.
|
||||
- [ ] Update `CHANGELOG.md`. Introduce a section for the new release.
|
||||
|
||||
## CHANGELOG.md updates
|
||||
|
||||
- [ ] Go to https://github.com/sharkdp/bat/releases/new, click "Choose a tag",
|
||||
type the name of the tag that will be created later, click "Generate release
|
||||
notes". DO NOT ACTUALLY CREATE ANY RELEASE IN THIS STEP.
|
||||
- [ ] Compare current `CHANGELOG.md` with auto-generated release notes and add
|
||||
missing entries. Expect in particular dependabot PRs to not be in
|
||||
`CHANGELOG.md` since they are [auto-merged] if CI passes.
|
||||
- [ ] Introduce a section for the new release and perform final touch-ups.
|
||||
|
||||
## Update syntaxes and themes (build assets)
|
||||
|
||||
@@ -71,3 +80,5 @@
|
||||
|
||||
|
||||
```
|
||||
|
||||
[auto-merged]: https://github.com/sharkdp/bat/blob/master/.github/workflows/Auto-merge-dependabot-PRs.yml
|
||||
|
BIN
doc/sponsors/warp-logo.png
Normal file
BIN
doc/sponsors/warp-logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 817 KiB |
17
examples/buffer.rs
Normal file
17
examples/buffer.rs
Normal file
@@ -0,0 +1,17 @@
|
||||
use bat::{assets::HighlightingAssets, config::Config, controller::Controller, Input};
|
||||
|
||||
fn main() {
|
||||
let mut buffer = String::new();
|
||||
let config = Config {
|
||||
colored_output: true,
|
||||
..Default::default()
|
||||
};
|
||||
let assets = HighlightingAssets::from_binary();
|
||||
let controller = Controller::new(&config, &assets);
|
||||
let input = Input::from_file(file!());
|
||||
controller
|
||||
.run(vec![input.into()], Some(&mut buffer))
|
||||
.unwrap();
|
||||
|
||||
println!("{buffer}");
|
||||
}
|
@@ -23,7 +23,8 @@ fn main() {
|
||||
}],
|
||||
};
|
||||
|
||||
let bytes = serde_yaml::to_vec(&person).unwrap();
|
||||
let mut bytes = Vec::with_capacity(128);
|
||||
serde_yaml::to_writer(&mut bytes, &person).unwrap();
|
||||
PrettyPrinter::new()
|
||||
.language("yaml")
|
||||
.line_numbers(true)
|
||||
|
@@ -404,7 +404,7 @@ fn macos_dark_mode_active() -> bool {
|
||||
const PREFERENCES_FILE: &str = "Library/Preferences/.GlobalPreferences.plist";
|
||||
const STYLE_KEY: &str = "AppleInterfaceStyle";
|
||||
|
||||
let preferences_file = dirs::home_dir()
|
||||
let preferences_file = home::home_dir()
|
||||
.map(|home| home.join(PREFERENCES_FILE))
|
||||
.expect("Could not get home directory");
|
||||
|
||||
|
@@ -1,9 +1,8 @@
|
||||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
use std::io::IsTerminal;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use atty::{self, Stream};
|
||||
|
||||
use crate::{
|
||||
clap_app,
|
||||
config::{get_args_from_config_file, get_args_from_env_opts_var, get_args_from_env_vars},
|
||||
@@ -30,6 +29,10 @@ fn is_truecolor_terminal() -> bool {
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn env_no_color() -> bool {
|
||||
env::var_os("NO_COLOR").is_some_and(|x| !x.is_empty())
|
||||
}
|
||||
|
||||
pub struct App {
|
||||
pub matches: ArgMatches,
|
||||
interactive_output: bool,
|
||||
@@ -40,7 +43,7 @@ impl App {
|
||||
#[cfg(windows)]
|
||||
let _ = nu_ansi_term::enable_ansi_support();
|
||||
|
||||
let interactive_output = atty::is(Stream::Stdout);
|
||||
let interactive_output = std::io::stdout().is_terminal();
|
||||
|
||||
Ok(App {
|
||||
matches: Self::matches(interactive_output)?,
|
||||
@@ -104,7 +107,7 @@ impl App {
|
||||
// If we are reading from stdin, only enable paging if we write to an
|
||||
// interactive terminal and if we do not *read* from an interactive
|
||||
// terminal.
|
||||
if self.interactive_output && !atty::is(Stream::Stdin) {
|
||||
if self.interactive_output && !std::io::stdin().is_terminal() {
|
||||
PagingMode::QuitIfOneScreen
|
||||
} else {
|
||||
PagingMode::Never
|
||||
@@ -208,7 +211,7 @@ impl App {
|
||||
|| match self.matches.get_one::<String>("color").map(|s| s.as_str()) {
|
||||
Some("always") => true,
|
||||
Some("never") => false,
|
||||
Some("auto") => env::var_os("NO_COLOR").is_none() && self.interactive_output,
|
||||
Some("auto") => !env_no_color() && self.interactive_output,
|
||||
_ => unreachable!("other values for --color are not allowed"),
|
||||
},
|
||||
paging_mode,
|
||||
@@ -282,6 +285,8 @@ impl App {
|
||||
.map(HighlightedLineRanges)
|
||||
.unwrap_or_default(),
|
||||
use_custom_assets: !self.matches.get_flag("no-custom-assets"),
|
||||
#[cfg(feature = "lessopen")]
|
||||
use_lessopen: self.matches.get_flag("lessopen"),
|
||||
})
|
||||
}
|
||||
|
||||
|
@@ -19,7 +19,7 @@ static VERSION: Lazy<String> = Lazy::new(|| {
|
||||
});
|
||||
|
||||
pub fn build_app(interactive_output: bool) -> Command {
|
||||
let color_when = if interactive_output && env::var_os("NO_COLOR").is_none() {
|
||||
let color_when = if interactive_output && !crate::app::env_no_color() {
|
||||
ColorChoice::Auto
|
||||
} else {
|
||||
ColorChoice::Never
|
||||
@@ -79,6 +79,7 @@ pub fn build_app(interactive_output: bool) -> Command {
|
||||
Arg::new("plain")
|
||||
.overrides_with("plain")
|
||||
.overrides_with("number")
|
||||
.overrides_with("paging")
|
||||
.short('p')
|
||||
.long("plain")
|
||||
.action(ArgAction::Count)
|
||||
@@ -303,6 +304,7 @@ pub fn build_app(interactive_output: bool) -> Command {
|
||||
.long("paging")
|
||||
.overrides_with("paging")
|
||||
.overrides_with("no-paging")
|
||||
.overrides_with("plain")
|
||||
.value_name("when")
|
||||
.value_parser(["auto", "never", "always"])
|
||||
.default_value("auto")
|
||||
@@ -311,7 +313,7 @@ pub fn build_app(interactive_output: bool) -> Command {
|
||||
.long_help(
|
||||
"Specify when to use the pager. To disable the pager, use \
|
||||
--paging=never' or its alias,'-P'. To disable the pager permanently, \
|
||||
set BAT_PAGER to an empty string. To control which pager is used, see the \
|
||||
set BAT_PAGING to 'never'. To control which pager is used, see the \
|
||||
'--pager' option. Possible values: *auto*, never, always."
|
||||
),
|
||||
)
|
||||
@@ -497,7 +499,28 @@ pub fn build_app(interactive_output: bool) -> Command {
|
||||
.action(ArgAction::SetTrue)
|
||||
.hide(true)
|
||||
.help("Do not load custom assets"),
|
||||
)
|
||||
);
|
||||
|
||||
#[cfg(feature = "lessopen")]
|
||||
{
|
||||
app = app
|
||||
.arg(
|
||||
Arg::new("lessopen")
|
||||
.long("lessopen")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help("Enable the $LESSOPEN preprocessor"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("no-lessopen")
|
||||
.long("no-lessopen")
|
||||
.action(ArgAction::SetTrue)
|
||||
.overrides_with("lessopen")
|
||||
.hide(true)
|
||||
.help("Disable the $LESSOPEN preprocessor if enabled (overrides --lessopen)"),
|
||||
)
|
||||
}
|
||||
|
||||
app = app
|
||||
.arg(
|
||||
Arg::new("config-file")
|
||||
.long("config-file")
|
||||
@@ -536,7 +559,7 @@ pub fn build_app(interactive_output: bool) -> Command {
|
||||
.alias("diagnostics")
|
||||
.action(ArgAction::SetTrue)
|
||||
.hide_short_help(true)
|
||||
.help("Show diagnostic information for bug reports.")
|
||||
.help("Show diagnostic information for bug reports."),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("acknowledgements")
|
||||
|
@@ -142,6 +142,7 @@ pub fn get_args_from_env_vars() -> Vec<OsString> {
|
||||
("--tabs", "BAT_TABS"),
|
||||
("--theme", "BAT_THEME"),
|
||||
("--pager", "BAT_PAGER"),
|
||||
("--paging", "BAT_PAGING"),
|
||||
("--style", "BAT_STYLE"),
|
||||
]
|
||||
.iter()
|
||||
|
@@ -1,12 +1,11 @@
|
||||
use std::env;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use etcetera::BaseStrategy;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
/// Wrapper for 'dirs' that treats MacOS more like Linux, by following the XDG specification.
|
||||
/// The `XDG_CACHE_HOME` environment variable is checked first. `BAT_CONFIG_DIR`
|
||||
/// is then checked before the `XDG_CONFIG_HOME` environment variable.
|
||||
/// The fallback directories are `~/.cache/bat` and `~/.config/bat`, respectively.
|
||||
/// Wrapper for 'etcetera' that checks BAT_CACHE_PATH and BAT_CONFIG_DIR and falls back to the
|
||||
/// Windows known folder locations on Windows & the XDG Base Directory Specification everywhere else.
|
||||
pub struct BatProjectDirs {
|
||||
cache_dir: PathBuf,
|
||||
config_dir: PathBuf,
|
||||
@@ -14,25 +13,24 @@ pub struct BatProjectDirs {
|
||||
|
||||
impl BatProjectDirs {
|
||||
fn new() -> Option<BatProjectDirs> {
|
||||
let cache_dir = BatProjectDirs::get_cache_dir()?;
|
||||
let basedirs = etcetera::choose_base_strategy().ok()?;
|
||||
|
||||
// Checks whether or not $BAT_CONFIG_DIR exists. If it doesn't, set our config dir
|
||||
// to our system's default configuration home.
|
||||
let config_dir =
|
||||
if let Some(config_dir_op) = env::var_os("BAT_CONFIG_DIR").map(PathBuf::from) {
|
||||
config_dir_op
|
||||
} else {
|
||||
#[cfg(target_os = "macos")]
|
||||
let config_dir_op = env::var_os("XDG_CONFIG_HOME")
|
||||
.map(PathBuf::from)
|
||||
.filter(|p| p.is_absolute())
|
||||
.or_else(|| dirs::home_dir().map(|d| d.join(".config")));
|
||||
// Checks whether or not `$BAT_CACHE_PATH` exists. If it doesn't, set the cache dir to our
|
||||
// system's default cache home.
|
||||
let cache_dir = if let Some(cache_dir) = env::var_os("BAT_CACHE_PATH").map(PathBuf::from) {
|
||||
cache_dir
|
||||
} else {
|
||||
basedirs.cache_dir().join("bat")
|
||||
};
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
let config_dir_op = dirs::config_dir();
|
||||
|
||||
config_dir_op.map(|d| d.join("bat"))?
|
||||
};
|
||||
// Checks whether or not `$BAT_CONFIG_DIR` exists. If it doesn't, set the config dir to our
|
||||
// system's default configuration home.
|
||||
let config_dir = if let Some(config_dir) = env::var_os("BAT_CONFIG_DIR").map(PathBuf::from)
|
||||
{
|
||||
config_dir
|
||||
} else {
|
||||
basedirs.config_dir().join("bat")
|
||||
};
|
||||
|
||||
Some(BatProjectDirs {
|
||||
cache_dir,
|
||||
@@ -40,25 +38,6 @@ impl BatProjectDirs {
|
||||
})
|
||||
}
|
||||
|
||||
fn get_cache_dir() -> Option<PathBuf> {
|
||||
// on all OS prefer BAT_CACHE_PATH if set
|
||||
let cache_dir_op = env::var_os("BAT_CACHE_PATH").map(PathBuf::from);
|
||||
if cache_dir_op.is_some() {
|
||||
return cache_dir_op;
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
let cache_dir_op = env::var_os("XDG_CACHE_HOME")
|
||||
.map(PathBuf::from)
|
||||
.filter(|p| p.is_absolute())
|
||||
.or_else(|| dirs::home_dir().map(|d| d.join(".cache")));
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
let cache_dir_op = dirs::cache_dir();
|
||||
|
||||
cache_dir_op.map(|d| d.join("bat"))
|
||||
}
|
||||
|
||||
pub fn cache_dir(&self) -> &Path {
|
||||
&self.cache_dir
|
||||
}
|
||||
|
@@ -206,7 +206,7 @@ pub fn list_themes(cfg: &Config, config_dir: &Path, cache_dir: &Path) -> Result<
|
||||
)?;
|
||||
config.theme = theme.to_string();
|
||||
Controller::new(&config, &assets)
|
||||
.run(vec![theme_preview_file()])
|
||||
.run(vec![theme_preview_file()], None)
|
||||
.ok();
|
||||
writeln!(stdout)?;
|
||||
}
|
||||
@@ -230,7 +230,7 @@ pub fn list_themes(cfg: &Config, config_dir: &Path, cache_dir: &Path) -> Result<
|
||||
fn run_controller(inputs: Vec<Input>, config: &Config, cache_dir: &Path) -> Result<bool> {
|
||||
let assets = assets_from_cache_or_binary(config.use_custom_assets, cache_dir)?;
|
||||
let controller = Controller::new(config, &assets);
|
||||
controller.run(inputs)
|
||||
controller.run(inputs, None)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bugreport")]
|
||||
@@ -255,6 +255,7 @@ fn invoke_bugreport(app: &App, cache_dir: &Path) {
|
||||
"LANG",
|
||||
"LC_ALL",
|
||||
"BAT_PAGER",
|
||||
"BAT_PAGING",
|
||||
"BAT_CACHE_PATH",
|
||||
"BAT_CONFIG_PATH",
|
||||
"BAT_OPTS",
|
||||
|
@@ -90,6 +90,10 @@ pub struct Config<'a> {
|
||||
/// Whether or not to allow custom assets. If this is false or if custom assets (a.k.a.
|
||||
/// cached assets) are not available, assets from the binary will be used instead.
|
||||
pub use_custom_assets: bool,
|
||||
|
||||
// Whether or not to use $LESSOPEN if set
|
||||
#[cfg(feature = "lessopen")]
|
||||
pub use_lessopen: bool,
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "minimal-application", feature = "paging"))]
|
||||
|
@@ -6,33 +6,47 @@ use crate::config::{Config, VisibleLines};
|
||||
use crate::diff::{get_git_diff, LineChanges};
|
||||
use crate::error::*;
|
||||
use crate::input::{Input, InputReader, OpenedInput};
|
||||
#[cfg(feature = "lessopen")]
|
||||
use crate::lessopen::LessOpenPreprocessor;
|
||||
#[cfg(feature = "git")]
|
||||
use crate::line_range::LineRange;
|
||||
use crate::line_range::{LineRanges, RangeCheckResult};
|
||||
use crate::output::OutputType;
|
||||
#[cfg(feature = "paging")]
|
||||
use crate::paging::PagingMode;
|
||||
use crate::printer::{InteractivePrinter, Printer, SimplePrinter};
|
||||
use crate::printer::{InteractivePrinter, OutputHandle, Printer, SimplePrinter};
|
||||
|
||||
use clircle::{Clircle, Identifier};
|
||||
|
||||
pub struct Controller<'a> {
|
||||
config: &'a Config<'a>,
|
||||
assets: &'a HighlightingAssets,
|
||||
#[cfg(feature = "lessopen")]
|
||||
preprocessor: Option<LessOpenPreprocessor>,
|
||||
}
|
||||
|
||||
impl<'b> Controller<'b> {
|
||||
pub fn new<'a>(config: &'a Config, assets: &'a HighlightingAssets) -> Controller<'a> {
|
||||
Controller { config, assets }
|
||||
Controller {
|
||||
config,
|
||||
assets,
|
||||
#[cfg(feature = "lessopen")]
|
||||
preprocessor: LessOpenPreprocessor::new().ok(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(&self, inputs: Vec<Input>) -> Result<bool> {
|
||||
self.run_with_error_handler(inputs, default_error_handler)
|
||||
pub fn run(
|
||||
&self,
|
||||
inputs: Vec<Input>,
|
||||
output_buffer: Option<&mut dyn std::fmt::Write>,
|
||||
) -> Result<bool> {
|
||||
self.run_with_error_handler(inputs, output_buffer, default_error_handler)
|
||||
}
|
||||
|
||||
pub fn run_with_error_handler(
|
||||
&self,
|
||||
inputs: Vec<Input>,
|
||||
output_buffer: Option<&mut dyn std::fmt::Write>,
|
||||
handle_error: impl Fn(&Error, &mut dyn Write),
|
||||
) -> Result<bool> {
|
||||
let mut output_type;
|
||||
@@ -74,7 +88,10 @@ impl<'b> Controller<'b> {
|
||||
clircle::Identifier::stdout()
|
||||
};
|
||||
|
||||
let writer = output_type.handle()?;
|
||||
let mut writer = match output_buffer {
|
||||
Some(buf) => OutputHandle::FmtWrite(buf),
|
||||
None => OutputHandle::IoWrite(output_type.handle()?),
|
||||
};
|
||||
let mut no_errors: bool = true;
|
||||
let stderr = io::stderr();
|
||||
|
||||
@@ -82,16 +99,23 @@ impl<'b> Controller<'b> {
|
||||
let identifier = stdout_identifier.as_ref();
|
||||
let is_first = index == 0;
|
||||
let result = if input.is_stdin() {
|
||||
self.print_input(input, writer, io::stdin().lock(), identifier, is_first)
|
||||
self.print_input(input, &mut writer, io::stdin().lock(), identifier, is_first)
|
||||
} else {
|
||||
// Use dummy stdin since stdin is actually not used (#1902)
|
||||
self.print_input(input, writer, io::empty(), identifier, is_first)
|
||||
self.print_input(input, &mut writer, io::empty(), identifier, is_first)
|
||||
};
|
||||
if let Err(error) = result {
|
||||
if attached_to_pager {
|
||||
handle_error(&error, writer);
|
||||
} else {
|
||||
handle_error(&error, &mut stderr.lock());
|
||||
match writer {
|
||||
// It doesn't make much sense to send errors straight to stderr if the user
|
||||
// provided their own buffer, so we just return it.
|
||||
OutputHandle::FmtWrite(_) => return Err(error),
|
||||
OutputHandle::IoWrite(ref mut writer) => {
|
||||
if attached_to_pager {
|
||||
handle_error(&error, writer);
|
||||
} else {
|
||||
handle_error(&error, &mut stderr.lock());
|
||||
}
|
||||
}
|
||||
}
|
||||
no_errors = false;
|
||||
}
|
||||
@@ -103,12 +127,23 @@ impl<'b> Controller<'b> {
|
||||
fn print_input<R: BufRead>(
|
||||
&self,
|
||||
input: Input,
|
||||
writer: &mut dyn Write,
|
||||
writer: &mut OutputHandle,
|
||||
stdin: R,
|
||||
stdout_identifier: Option<&Identifier>,
|
||||
is_first: bool,
|
||||
) -> Result<()> {
|
||||
let mut opened_input = input.open(stdin, stdout_identifier)?;
|
||||
let mut opened_input = {
|
||||
#[cfg(feature = "lessopen")]
|
||||
match self.preprocessor {
|
||||
Some(ref preprocessor) if self.config.use_lessopen => {
|
||||
preprocessor.open(input, stdin, stdout_identifier)?
|
||||
}
|
||||
_ => input.open(stdin, stdout_identifier)?,
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "lessopen"))]
|
||||
input.open(stdin, stdout_identifier)?
|
||||
};
|
||||
#[cfg(feature = "git")]
|
||||
let line_changes = if self.config.visible_lines.diff_mode()
|
||||
|| (!self.config.loop_through && self.config.style_components.changes())
|
||||
@@ -164,7 +199,7 @@ impl<'b> Controller<'b> {
|
||||
fn print_file(
|
||||
&self,
|
||||
printer: &mut dyn Printer,
|
||||
writer: &mut dyn Write,
|
||||
writer: &mut OutputHandle,
|
||||
input: &mut OpenedInput,
|
||||
add_header_padding: bool,
|
||||
#[cfg(feature = "git")] line_changes: &Option<LineChanges>,
|
||||
@@ -202,7 +237,7 @@ impl<'b> Controller<'b> {
|
||||
fn print_file_ranges(
|
||||
&self,
|
||||
printer: &mut dyn Printer,
|
||||
writer: &mut dyn Write,
|
||||
writer: &mut OutputHandle,
|
||||
reader: &mut InputReader,
|
||||
line_ranges: &LineRanges,
|
||||
) -> Result<()> {
|
||||
|
@@ -7,6 +7,8 @@ pub enum Error {
|
||||
#[error(transparent)]
|
||||
Io(#[from] ::std::io::Error),
|
||||
#[error(transparent)]
|
||||
Fmt(#[from] ::std::fmt::Error),
|
||||
#[error(transparent)]
|
||||
SyntectError(#[from] ::syntect::Error),
|
||||
#[error(transparent)]
|
||||
SyntectLoadingError(#[from] ::syntect::LoadingError),
|
||||
@@ -26,6 +28,12 @@ pub enum Error {
|
||||
InvalidPagerValueBat,
|
||||
#[error("{0}")]
|
||||
Msg(String),
|
||||
#[cfg(feature = "lessopen")]
|
||||
#[error(transparent)]
|
||||
VarError(#[from] ::std::env::VarError),
|
||||
#[cfg(feature = "lessopen")]
|
||||
#[error(transparent)]
|
||||
CommandParseError(#[from] ::shell_words::ParseError),
|
||||
}
|
||||
|
||||
impl From<&'static str> for Error {
|
||||
|
@@ -256,7 +256,7 @@ pub(crate) struct InputReader<'a> {
|
||||
}
|
||||
|
||||
impl<'a> InputReader<'a> {
|
||||
fn new<R: BufRead + 'a>(mut reader: R) -> InputReader<'a> {
|
||||
pub(crate) fn new<R: BufRead + 'a>(mut reader: R) -> InputReader<'a> {
|
||||
let mut first_line = vec![];
|
||||
reader.read_until(b'\n', &mut first_line).ok();
|
||||
|
||||
|
401
src/lessopen.rs
Normal file
401
src/lessopen.rs
Normal file
@@ -0,0 +1,401 @@
|
||||
#![cfg(feature = "lessopen")]
|
||||
|
||||
use std::convert::TryFrom;
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::{BufRead, BufReader, Cursor, Read, Write};
|
||||
use std::path::PathBuf;
|
||||
use std::str;
|
||||
|
||||
use clircle::{Clircle, Identifier};
|
||||
use os_str_bytes::RawOsString;
|
||||
use run_script::{IoOptions, ScriptOptions};
|
||||
|
||||
use crate::error::Result;
|
||||
use crate::{
|
||||
bat_warning,
|
||||
input::{Input, InputKind, InputReader, OpenedInput, OpenedInputKind},
|
||||
};
|
||||
|
||||
/// Preprocess files and/or stdin using $LESSOPEN and $LESSCLOSE
|
||||
pub(crate) struct LessOpenPreprocessor {
|
||||
lessopen: String,
|
||||
lessclose: Option<String>,
|
||||
command_options: ScriptOptions,
|
||||
kind: LessOpenKind,
|
||||
/// Whether or not data piped via stdin is to be preprocessed
|
||||
preprocess_stdin: bool,
|
||||
}
|
||||
|
||||
enum LessOpenKind {
|
||||
Piped,
|
||||
PipedIgnoreExitCode,
|
||||
TempFile,
|
||||
}
|
||||
|
||||
impl LessOpenPreprocessor {
|
||||
/// Create a new instance of LessOpenPreprocessor
|
||||
/// Will return Ok if and only if $LESSOPEN is set and contains exactly one %s
|
||||
pub(crate) fn new() -> Result<LessOpenPreprocessor> {
|
||||
let lessopen = env::var("LESSOPEN")?;
|
||||
|
||||
// Ignore $LESSOPEN if it does not contains exactly one %s
|
||||
// Note that $LESSCLOSE has no such requirement
|
||||
if lessopen.match_indices("%s").count() != 1 {
|
||||
let error_msg = "LESSOPEN ignored: must contain exactly one %s";
|
||||
bat_warning!("{}", error_msg);
|
||||
return Err(error_msg.into());
|
||||
}
|
||||
|
||||
// "||" means pipe directly to bat without making a temporary file
|
||||
// Also, if preprocessor output is empty and exit code is zero, use the empty output
|
||||
// Otherwise, if output is empty and exit code is nonzero, use original file contents
|
||||
let (kind, lessopen) = if lessopen.starts_with("||") {
|
||||
(LessOpenKind::Piped, lessopen.chars().skip(2).collect())
|
||||
// "|" means pipe, but ignore exit code, always using preprocessor output
|
||||
} else if lessopen.starts_with('|') {
|
||||
(
|
||||
LessOpenKind::PipedIgnoreExitCode,
|
||||
lessopen.chars().skip(1).collect(),
|
||||
)
|
||||
// If neither appear, write output to a temporary file and read from that
|
||||
} else {
|
||||
(LessOpenKind::TempFile, lessopen)
|
||||
};
|
||||
|
||||
// "-" means that stdin is preprocessed along with files and may appear alongside "|" and "||"
|
||||
let (stdin, lessopen) = if lessopen.starts_with('-') {
|
||||
(true, lessopen.chars().skip(1).collect())
|
||||
} else {
|
||||
(false, lessopen)
|
||||
};
|
||||
|
||||
let mut command_options = ScriptOptions::new();
|
||||
command_options.runner = env::var("SHELL").ok();
|
||||
command_options.input_redirection = IoOptions::Pipe;
|
||||
|
||||
Ok(Self {
|
||||
lessopen: lessopen.replacen("%s", "$1", 1),
|
||||
lessclose: env::var("LESSCLOSE")
|
||||
.ok()
|
||||
.map(|str| str.replacen("%s", "$1", 1).replacen("%s", "$2", 1)),
|
||||
command_options,
|
||||
kind,
|
||||
preprocess_stdin: stdin,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn open<'a, R: BufRead + 'a>(
|
||||
&self,
|
||||
input: Input<'a>,
|
||||
mut stdin: R,
|
||||
stdout_identifier: Option<&Identifier>,
|
||||
) -> Result<OpenedInput<'a>> {
|
||||
let (lessopen_stdout, path_str, kind) = match input.kind {
|
||||
InputKind::OrdinaryFile(ref path) => {
|
||||
let path_str = match path.to_str() {
|
||||
Some(str) => str,
|
||||
None => return input.open(stdin, stdout_identifier),
|
||||
};
|
||||
|
||||
let (exit_code, lessopen_stdout, _) = match run_script::run(
|
||||
&self.lessopen,
|
||||
&vec![path_str.to_string()],
|
||||
&self.command_options,
|
||||
) {
|
||||
Ok(output) => output,
|
||||
Err(_) => return input.open(stdin, stdout_identifier),
|
||||
};
|
||||
|
||||
if self.fall_back_to_original_file(&lessopen_stdout, exit_code) {
|
||||
return input.open(stdin, stdout_identifier);
|
||||
}
|
||||
|
||||
(
|
||||
RawOsString::from_string(lessopen_stdout),
|
||||
path_str.to_string(),
|
||||
OpenedInputKind::OrdinaryFile(path.to_path_buf()),
|
||||
)
|
||||
}
|
||||
InputKind::StdIn => {
|
||||
if self.preprocess_stdin {
|
||||
if let Some(stdout) = stdout_identifier {
|
||||
let input_identifier = Identifier::try_from(clircle::Stdio::Stdin)
|
||||
.map_err(|e| format!("Stdin: Error identifying file: {}", e))?;
|
||||
if stdout.surely_conflicts_with(&input_identifier) {
|
||||
return Err("IO circle detected. The input from stdin is also an output. Aborting to avoid infinite loop.".into());
|
||||
}
|
||||
}
|
||||
|
||||
// stdin isn't Clone, so copy it to a cloneable buffer
|
||||
let mut stdin_buffer = Vec::new();
|
||||
stdin.read_to_end(&mut stdin_buffer).unwrap();
|
||||
|
||||
let mut lessopen_handle = match run_script::spawn(
|
||||
&self.lessopen,
|
||||
&vec!["-".to_string()],
|
||||
&self.command_options,
|
||||
) {
|
||||
Ok(handle) => handle,
|
||||
Err(_) => {
|
||||
return input.open(stdin, stdout_identifier);
|
||||
}
|
||||
};
|
||||
|
||||
if lessopen_handle
|
||||
.stdin
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.write_all(&stdin_buffer.clone())
|
||||
.is_err()
|
||||
{
|
||||
return input.open(stdin, stdout_identifier);
|
||||
}
|
||||
|
||||
let lessopen_output = match lessopen_handle.wait_with_output() {
|
||||
Ok(output) => output,
|
||||
Err(_) => {
|
||||
return input.open(Cursor::new(stdin_buffer), stdout_identifier);
|
||||
}
|
||||
};
|
||||
|
||||
if lessopen_output.stdout.is_empty()
|
||||
&& (!lessopen_output.status.success()
|
||||
|| matches!(self.kind, LessOpenKind::PipedIgnoreExitCode))
|
||||
{
|
||||
return input.open(Cursor::new(stdin_buffer), stdout_identifier);
|
||||
}
|
||||
|
||||
(
|
||||
RawOsString::assert_from_raw_vec(lessopen_output.stdout),
|
||||
"-".to_string(),
|
||||
OpenedInputKind::StdIn,
|
||||
)
|
||||
} else {
|
||||
return input.open(stdin, stdout_identifier);
|
||||
}
|
||||
}
|
||||
InputKind::CustomReader(_) => {
|
||||
return input.open(stdin, stdout_identifier);
|
||||
}
|
||||
};
|
||||
|
||||
Ok(OpenedInput {
|
||||
kind,
|
||||
reader: InputReader::new(BufReader::new(
|
||||
if matches!(self.kind, LessOpenKind::TempFile) {
|
||||
// Remove newline at end of temporary file path returned by $LESSOPEN
|
||||
let stdout = match lessopen_stdout.strip_suffix("\n") {
|
||||
Some(stripped) => stripped.to_owned(),
|
||||
None => lessopen_stdout,
|
||||
};
|
||||
|
||||
let stdout = stdout.into_os_string();
|
||||
|
||||
let file = match File::open(PathBuf::from(&stdout)) {
|
||||
Ok(file) => file,
|
||||
Err(_) => {
|
||||
return input.open(stdin, stdout_identifier);
|
||||
}
|
||||
};
|
||||
|
||||
Preprocessed {
|
||||
kind: PreprocessedKind::TempFile(file),
|
||||
lessclose: self.lessclose.clone(),
|
||||
command_args: vec![path_str, stdout.to_str().unwrap().to_string()],
|
||||
command_options: self.command_options.clone(),
|
||||
}
|
||||
} else {
|
||||
Preprocessed {
|
||||
kind: PreprocessedKind::Piped(Cursor::new(lessopen_stdout.into_raw_vec())),
|
||||
lessclose: self.lessclose.clone(),
|
||||
command_args: vec![path_str, "-".to_string()],
|
||||
command_options: self.command_options.clone(),
|
||||
}
|
||||
},
|
||||
)),
|
||||
metadata: input.metadata,
|
||||
description: input.description,
|
||||
})
|
||||
}
|
||||
|
||||
fn fall_back_to_original_file(&self, lessopen_output: &str, exit_code: i32) -> bool {
|
||||
lessopen_output.is_empty()
|
||||
&& (exit_code != 0 || matches!(self.kind, LessOpenKind::PipedIgnoreExitCode))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
/// For testing purposes only
|
||||
/// Create an instance of LessOpenPreprocessor with specified valued for $LESSOPEN and $LESSCLOSE
|
||||
fn mock_new(lessopen: Option<&str>, lessclose: Option<&str>) -> Result<LessOpenPreprocessor> {
|
||||
if let Some(command) = lessopen {
|
||||
env::set_var("LESSOPEN", command)
|
||||
} else {
|
||||
env::remove_var("LESSOPEN")
|
||||
}
|
||||
|
||||
if let Some(command) = lessclose {
|
||||
env::set_var("LESSCLOSE", command)
|
||||
} else {
|
||||
env::remove_var("LESSCLOSE")
|
||||
}
|
||||
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
enum PreprocessedKind {
|
||||
Piped(Cursor<Vec<u8>>),
|
||||
TempFile(File),
|
||||
}
|
||||
|
||||
impl Read for PreprocessedKind {
|
||||
fn read(&mut self, buf: &mut [u8]) -> std::result::Result<usize, std::io::Error> {
|
||||
match self {
|
||||
PreprocessedKind::Piped(data) => data.read(buf),
|
||||
PreprocessedKind::TempFile(data) => data.read(buf),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Preprocessed {
|
||||
kind: PreprocessedKind,
|
||||
lessclose: Option<String>,
|
||||
command_args: Vec<String>,
|
||||
command_options: ScriptOptions,
|
||||
}
|
||||
|
||||
impl Read for Preprocessed {
|
||||
fn read(&mut self, buf: &mut [u8]) -> std::result::Result<usize, std::io::Error> {
|
||||
self.kind.read(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Preprocessed {
|
||||
fn drop(&mut self) {
|
||||
if let Some(ref command) = self.lessclose {
|
||||
self.command_options.output_redirection = IoOptions::Inherit;
|
||||
|
||||
run_script::run(command, &self.command_args, &self.command_options)
|
||||
.expect("failed to run $LESSCLOSE to clean up file");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
// All tests here are serial because they all involve reading and writing environment variables
|
||||
// Running them in parallel causes these tests and some others to randomly fail
|
||||
use serial_test::serial;
|
||||
|
||||
use super::*;
|
||||
|
||||
/// Reset environment variables after each test as a precaution
|
||||
fn reset_env_vars() {
|
||||
env::remove_var("LESSOPEN");
|
||||
env::remove_var("LESSCLOSE");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn test_just_lessopen() -> Result<()> {
|
||||
let preprocessor = LessOpenPreprocessor::mock_new(Some("|batpipe %s"), None)?;
|
||||
|
||||
assert_eq!(preprocessor.lessopen, "batpipe $1");
|
||||
assert!(preprocessor.lessclose.is_none());
|
||||
|
||||
reset_env_vars();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn test_just_lessclose() -> Result<()> {
|
||||
let preprocessor = LessOpenPreprocessor::mock_new(None, Some("lessclose.sh %s %s"));
|
||||
|
||||
assert!(preprocessor.is_err());
|
||||
|
||||
reset_env_vars();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn test_both_lessopen_and_lessclose() -> Result<()> {
|
||||
let preprocessor =
|
||||
LessOpenPreprocessor::mock_new(Some("lessopen.sh %s"), Some("lessclose.sh %s %s"))?;
|
||||
|
||||
assert_eq!(preprocessor.lessopen, "lessopen.sh $1");
|
||||
assert_eq!(preprocessor.lessclose.unwrap(), "lessclose.sh $1 $2");
|
||||
|
||||
reset_env_vars();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn test_lessopen_prefixes() -> Result<()> {
|
||||
let preprocessor = LessOpenPreprocessor::mock_new(Some("batpipe %s"), None)?;
|
||||
|
||||
assert_eq!(preprocessor.lessopen, "batpipe $1");
|
||||
assert!(matches!(preprocessor.kind, LessOpenKind::TempFile));
|
||||
assert!(!preprocessor.preprocess_stdin);
|
||||
|
||||
let preprocessor = LessOpenPreprocessor::mock_new(Some("|batpipe %s"), None)?;
|
||||
|
||||
assert_eq!(preprocessor.lessopen, "batpipe $1");
|
||||
assert!(matches!(
|
||||
preprocessor.kind,
|
||||
LessOpenKind::PipedIgnoreExitCode
|
||||
));
|
||||
assert!(!preprocessor.preprocess_stdin);
|
||||
|
||||
let preprocessor = LessOpenPreprocessor::mock_new(Some("||batpipe %s"), None)?;
|
||||
|
||||
assert_eq!(preprocessor.lessopen, "batpipe $1");
|
||||
assert!(matches!(preprocessor.kind, LessOpenKind::Piped));
|
||||
assert!(!preprocessor.preprocess_stdin);
|
||||
|
||||
let preprocessor = LessOpenPreprocessor::mock_new(Some("-batpipe %s"), None)?;
|
||||
|
||||
assert_eq!(preprocessor.lessopen, "batpipe $1");
|
||||
assert!(matches!(preprocessor.kind, LessOpenKind::TempFile));
|
||||
assert!(preprocessor.preprocess_stdin);
|
||||
|
||||
let preprocessor = LessOpenPreprocessor::mock_new(Some("|-batpipe %s"), None)?;
|
||||
|
||||
assert_eq!(preprocessor.lessopen, "batpipe $1");
|
||||
assert!(matches!(
|
||||
preprocessor.kind,
|
||||
LessOpenKind::PipedIgnoreExitCode
|
||||
));
|
||||
assert!(preprocessor.preprocess_stdin);
|
||||
|
||||
let preprocessor = LessOpenPreprocessor::mock_new(Some("||-batpipe %s"), None)?;
|
||||
|
||||
assert_eq!(preprocessor.lessopen, "batpipe $1");
|
||||
assert!(matches!(preprocessor.kind, LessOpenKind::Piped));
|
||||
assert!(preprocessor.preprocess_stdin);
|
||||
|
||||
reset_env_vars();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn replace_part_of_argument() -> Result<()> {
|
||||
let preprocessor =
|
||||
LessOpenPreprocessor::mock_new(Some("|echo File:%s"), Some("echo File:%s Temp:%s"))?;
|
||||
|
||||
assert_eq!(preprocessor.lessopen, "echo File:$1");
|
||||
assert_eq!(preprocessor.lessclose.unwrap(), "echo File:$1 Temp:$2");
|
||||
|
||||
reset_env_vars();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
@@ -34,6 +34,8 @@ mod diff;
|
||||
pub mod error;
|
||||
pub mod input;
|
||||
mod less;
|
||||
#[cfg(feature = "lessopen")]
|
||||
mod lessopen;
|
||||
pub mod line_range;
|
||||
pub(crate) mod nonprintable_notation;
|
||||
mod output;
|
||||
|
@@ -53,7 +53,7 @@ impl LineRange {
|
||||
let more_lines = &line_numbers[1][1..]
|
||||
.parse()
|
||||
.map_err(|_| "Invalid character after +")?;
|
||||
new_range.lower + more_lines
|
||||
new_range.lower.saturating_add(*more_lines)
|
||||
} else if first_byte == Some(b'-') {
|
||||
// this will prevent values like "-+5" even though "+5" is valid integer
|
||||
if line_numbers[1][1..].bytes().next() == Some(b'+') {
|
||||
@@ -128,6 +128,13 @@ fn test_parse_plus() {
|
||||
assert_eq!(50, range.upper);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_plus_overflow() {
|
||||
let range = LineRange::from(&format!("{}:+1", usize::MAX)).expect("Shouldn't fail on test!");
|
||||
assert_eq!(usize::MAX, range.lower);
|
||||
assert_eq!(usize::MAX, range.upper);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_plus_fail() {
|
||||
let range = LineRange::from("40:+z");
|
||||
|
@@ -114,6 +114,10 @@ impl OutputType {
|
||||
p.args(args);
|
||||
}
|
||||
p.env("LESSCHARSET", "UTF-8");
|
||||
|
||||
#[cfg(feature = "lessopen")]
|
||||
// Ensures that 'less' does not preprocess input again if '$LESSOPEN' is set.
|
||||
p.arg("--no-lessopen");
|
||||
} else {
|
||||
p.args(args);
|
||||
};
|
||||
|
@@ -91,31 +91,27 @@ pub fn replace_nonprintable(
|
||||
});
|
||||
line_idx = 0;
|
||||
}
|
||||
// carriage return
|
||||
'\x0D' => output.push_str(match nonprintable_notation {
|
||||
NonprintableNotation::Caret => "^M",
|
||||
NonprintableNotation::Unicode => "␍",
|
||||
}),
|
||||
// null
|
||||
'\x00' => output.push_str(match nonprintable_notation {
|
||||
NonprintableNotation::Caret => "^@",
|
||||
NonprintableNotation::Unicode => "␀",
|
||||
}),
|
||||
// bell
|
||||
'\x07' => output.push_str(match nonprintable_notation {
|
||||
NonprintableNotation::Caret => "^G",
|
||||
NonprintableNotation::Unicode => "␇",
|
||||
}),
|
||||
// backspace
|
||||
'\x08' => output.push_str(match nonprintable_notation {
|
||||
NonprintableNotation::Caret => "^H",
|
||||
NonprintableNotation::Unicode => "␈",
|
||||
}),
|
||||
// escape
|
||||
'\x1B' => output.push_str(match nonprintable_notation {
|
||||
NonprintableNotation::Caret => "^[",
|
||||
NonprintableNotation::Unicode => "␛",
|
||||
}),
|
||||
// ASCII control characters
|
||||
'\x00'..='\x1F' => {
|
||||
let c = u32::from(chr);
|
||||
|
||||
match nonprintable_notation {
|
||||
NonprintableNotation::Caret => {
|
||||
let caret_character = char::from_u32(0x40 + c).unwrap();
|
||||
write!(output, "^{caret_character}").ok();
|
||||
}
|
||||
|
||||
NonprintableNotation::Unicode => {
|
||||
let replacement_symbol = char::from_u32(0x2400 + c).unwrap();
|
||||
output.push(replacement_symbol)
|
||||
}
|
||||
}
|
||||
}
|
||||
// delete
|
||||
'\x7F' => match nonprintable_notation {
|
||||
NonprintableNotation::Caret => output.push_str("^?"),
|
||||
NonprintableNotation::Unicode => output.push('\u{2421}'),
|
||||
},
|
||||
// printable ASCII
|
||||
c if c.is_ascii_alphanumeric()
|
||||
|| c.is_ascii_punctuation()
|
||||
|
@@ -300,7 +300,7 @@ impl<'a> PrettyPrinter<'a> {
|
||||
|
||||
// Run the controller
|
||||
let controller = Controller::new(&self.config, &self.assets);
|
||||
controller.run(inputs.into_iter().map(|i| i.into()).collect())
|
||||
controller.run(inputs.into_iter().map(|i| i.into()).collect(), None)
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,4 +1,5 @@
|
||||
use std::io::Write;
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
use std::vec::Vec;
|
||||
|
||||
use nu_ansi_term::Color::{Fixed, Green, Red, Yellow};
|
||||
@@ -15,8 +16,7 @@ use syntect::parsing::SyntaxSet;
|
||||
|
||||
use content_inspector::ContentType;
|
||||
|
||||
use encoding::all::{UTF_16BE, UTF_16LE};
|
||||
use encoding::{DecoderTrap, Encoding};
|
||||
use encoding_rs::{UTF_16BE, UTF_16LE};
|
||||
|
||||
use unicode_width::UnicodeWidthChar;
|
||||
|
||||
@@ -36,21 +36,35 @@ use crate::terminal::{as_terminal_escaped, to_ansi_color};
|
||||
use crate::vscreen::AnsiStyle;
|
||||
use crate::wrapping::WrappingMode;
|
||||
|
||||
pub enum OutputHandle<'a> {
|
||||
IoWrite(&'a mut dyn io::Write),
|
||||
FmtWrite(&'a mut dyn fmt::Write),
|
||||
}
|
||||
|
||||
impl<'a> OutputHandle<'a> {
|
||||
fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> Result<()> {
|
||||
match self {
|
||||
Self::IoWrite(handle) => handle.write_fmt(args).map_err(Into::into),
|
||||
Self::FmtWrite(handle) => handle.write_fmt(args).map_err(Into::into),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait Printer {
|
||||
fn print_header(
|
||||
&mut self,
|
||||
handle: &mut dyn Write,
|
||||
handle: &mut OutputHandle,
|
||||
input: &OpenedInput,
|
||||
add_header_padding: bool,
|
||||
) -> Result<()>;
|
||||
fn print_footer(&mut self, handle: &mut dyn Write, input: &OpenedInput) -> Result<()>;
|
||||
fn print_footer(&mut self, handle: &mut OutputHandle, input: &OpenedInput) -> Result<()>;
|
||||
|
||||
fn print_snip(&mut self, handle: &mut dyn Write) -> Result<()>;
|
||||
fn print_snip(&mut self, handle: &mut OutputHandle) -> Result<()>;
|
||||
|
||||
fn print_line(
|
||||
&mut self,
|
||||
out_of_range: bool,
|
||||
handle: &mut dyn Write,
|
||||
handle: &mut OutputHandle,
|
||||
line_number: usize,
|
||||
line_buffer: &[u8],
|
||||
) -> Result<()>;
|
||||
@@ -69,25 +83,25 @@ impl<'a> SimplePrinter<'a> {
|
||||
impl<'a> Printer for SimplePrinter<'a> {
|
||||
fn print_header(
|
||||
&mut self,
|
||||
_handle: &mut dyn Write,
|
||||
_handle: &mut OutputHandle,
|
||||
_input: &OpenedInput,
|
||||
_add_header_padding: bool,
|
||||
) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_footer(&mut self, _handle: &mut dyn Write, _input: &OpenedInput) -> Result<()> {
|
||||
fn print_footer(&mut self, _handle: &mut OutputHandle, _input: &OpenedInput) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_snip(&mut self, _handle: &mut dyn Write) -> Result<()> {
|
||||
fn print_snip(&mut self, _handle: &mut OutputHandle) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_line(
|
||||
&mut self,
|
||||
out_of_range: bool,
|
||||
handle: &mut dyn Write,
|
||||
handle: &mut OutputHandle,
|
||||
_line_number: usize,
|
||||
line_buffer: &[u8],
|
||||
) -> Result<()> {
|
||||
@@ -100,7 +114,19 @@ impl<'a> Printer for SimplePrinter<'a> {
|
||||
);
|
||||
write!(handle, "{}", line)?;
|
||||
} else {
|
||||
handle.write_all(line_buffer)?
|
||||
match handle {
|
||||
OutputHandle::IoWrite(handle) => handle.write_all(line_buffer)?,
|
||||
OutputHandle::FmtWrite(handle) => {
|
||||
write!(
|
||||
handle,
|
||||
"{}",
|
||||
std::str::from_utf8(line_buffer).map_err(|_| Error::Msg(
|
||||
"encountered invalid utf8 while printing to non-io buffer"
|
||||
.to_string()
|
||||
))?
|
||||
)?;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
@@ -218,7 +244,11 @@ impl<'a> InteractivePrinter<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
fn print_horizontal_line_term(&mut self, handle: &mut dyn Write, style: Style) -> Result<()> {
|
||||
fn print_horizontal_line_term(
|
||||
&mut self,
|
||||
handle: &mut OutputHandle,
|
||||
style: Style,
|
||||
) -> Result<()> {
|
||||
writeln!(
|
||||
handle,
|
||||
"{}",
|
||||
@@ -227,7 +257,7 @@ impl<'a> InteractivePrinter<'a> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_horizontal_line(&mut self, handle: &mut dyn Write, grid_char: char) -> Result<()> {
|
||||
fn print_horizontal_line(&mut self, handle: &mut OutputHandle, grid_char: char) -> Result<()> {
|
||||
if self.panel_width == 0 {
|
||||
self.print_horizontal_line_term(handle, self.colors.grid)?;
|
||||
} else {
|
||||
@@ -257,7 +287,7 @@ impl<'a> InteractivePrinter<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn print_header_component_indent(&mut self, handle: &mut dyn Write) -> std::io::Result<()> {
|
||||
fn print_header_component_indent(&mut self, handle: &mut OutputHandle) -> Result<()> {
|
||||
if self.config.style_components.grid() {
|
||||
write!(
|
||||
handle,
|
||||
@@ -285,7 +315,7 @@ impl<'a> InteractivePrinter<'a> {
|
||||
impl<'a> Printer for InteractivePrinter<'a> {
|
||||
fn print_header(
|
||||
&mut self,
|
||||
handle: &mut dyn Write,
|
||||
handle: &mut OutputHandle,
|
||||
input: &OpenedInput,
|
||||
add_header_padding: bool,
|
||||
) -> Result<()> {
|
||||
@@ -384,7 +414,7 @@ impl<'a> Printer for InteractivePrinter<'a> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_footer(&mut self, handle: &mut dyn Write, _input: &OpenedInput) -> Result<()> {
|
||||
fn print_footer(&mut self, handle: &mut OutputHandle, _input: &OpenedInput) -> Result<()> {
|
||||
if self.config.style_components.grid()
|
||||
&& (self.content_type.map_or(false, |c| c.is_text()) || self.config.show_nonprintable)
|
||||
{
|
||||
@@ -394,7 +424,7 @@ impl<'a> Printer for InteractivePrinter<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn print_snip(&mut self, handle: &mut dyn Write) -> Result<()> {
|
||||
fn print_snip(&mut self, handle: &mut OutputHandle) -> Result<()> {
|
||||
let panel = self.create_fake_panel(" ...");
|
||||
let panel_count = panel.chars().count();
|
||||
|
||||
@@ -421,7 +451,7 @@ impl<'a> Printer for InteractivePrinter<'a> {
|
||||
fn print_line(
|
||||
&mut self,
|
||||
out_of_range: bool,
|
||||
handle: &mut dyn Write,
|
||||
handle: &mut OutputHandle,
|
||||
line_number: usize,
|
||||
line_buffer: &[u8],
|
||||
) -> Result<()> {
|
||||
@@ -431,27 +461,25 @@ impl<'a> Printer for InteractivePrinter<'a> {
|
||||
self.config.tab_width,
|
||||
self.config.nonprintable_notation,
|
||||
)
|
||||
.into()
|
||||
} else {
|
||||
let line = match self.content_type {
|
||||
match self.content_type {
|
||||
Some(ContentType::BINARY) | None => {
|
||||
return Ok(());
|
||||
}
|
||||
Some(ContentType::UTF_16LE) => UTF_16LE
|
||||
.decode(line_buffer, DecoderTrap::Replace)
|
||||
.map_err(|_| "Invalid UTF-16LE")?,
|
||||
Some(ContentType::UTF_16BE) => UTF_16BE
|
||||
.decode(line_buffer, DecoderTrap::Replace)
|
||||
.map_err(|_| "Invalid UTF-16BE")?,
|
||||
_ => String::from_utf8_lossy(line_buffer).to_string(),
|
||||
};
|
||||
// Remove byte order mark from the first line if it exists
|
||||
if line_number == 1 {
|
||||
match line.strip_prefix('\u{feff}') {
|
||||
Some(stripped) => stripped.to_string(),
|
||||
None => line,
|
||||
Some(ContentType::UTF_16LE) => UTF_16LE.decode_with_bom_removal(line_buffer).0,
|
||||
Some(ContentType::UTF_16BE) => UTF_16BE.decode_with_bom_removal(line_buffer).0,
|
||||
_ => {
|
||||
let line = String::from_utf8_lossy(line_buffer);
|
||||
if line_number == 1 {
|
||||
match line.strip_prefix('\u{feff}') {
|
||||
Some(stripped) => stripped.to_string().into(),
|
||||
None => line,
|
||||
}
|
||||
} else {
|
||||
line
|
||||
}
|
||||
}
|
||||
} else {
|
||||
line
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -63,6 +63,12 @@ impl<'a> SyntaxMapping<'a> {
|
||||
MappingTarget::MapTo("Bourne Again Shell (bash)"),
|
||||
)
|
||||
.unwrap();
|
||||
mapping
|
||||
.insert(
|
||||
"os-release",
|
||||
MappingTarget::MapTo("Bourne Again Shell (bash)"),
|
||||
)
|
||||
.unwrap();
|
||||
mapping
|
||||
.insert("*.pac", MappingTarget::MapTo("JavaScript (Babel)"))
|
||||
.unwrap();
|
||||
@@ -70,6 +76,10 @@ impl<'a> SyntaxMapping<'a> {
|
||||
.insert("fish_history", MappingTarget::MapTo("YAML"))
|
||||
.unwrap();
|
||||
|
||||
for glob in ["*.jsonl", "*.sarif"] {
|
||||
mapping.insert(glob, MappingTarget::MapTo("JSON")).unwrap();
|
||||
}
|
||||
|
||||
// See #2151, https://nmap.org/book/nse-language.html
|
||||
mapping
|
||||
.insert("*.nse", MappingTarget::MapTo("Lua"))
|
||||
@@ -80,6 +90,14 @@ impl<'a> SyntaxMapping<'a> {
|
||||
.insert("rails", MappingTarget::MapToUnknown)
|
||||
.unwrap();
|
||||
|
||||
mapping
|
||||
.insert("Containerfile", MappingTarget::MapTo("Dockerfile"))
|
||||
.unwrap();
|
||||
|
||||
mapping
|
||||
.insert("*.ksh", MappingTarget::MapTo("Bourne Again Shell (bash)"))
|
||||
.unwrap();
|
||||
|
||||
// Nginx and Apache syntax files both want to style all ".conf" files
|
||||
// see #1131 and #1137
|
||||
mapping
|
||||
@@ -138,19 +156,30 @@ impl<'a> SyntaxMapping<'a> {
|
||||
.insert("*.hook", MappingTarget::MapTo("INI"))
|
||||
.unwrap();
|
||||
|
||||
mapping
|
||||
.insert("*.ron", MappingTarget::MapTo("Rust"))
|
||||
.unwrap();
|
||||
|
||||
// Global git config files rooted in `$XDG_CONFIG_HOME/git/` or `$HOME/.config/git/`
|
||||
// See e.g. https://git-scm.com/docs/git-config#FILES
|
||||
if let Some(xdg_config_home) =
|
||||
std::env::var_os("XDG_CONFIG_HOME").filter(|val| !val.is_empty())
|
||||
{
|
||||
insert_git_config_global(&mut mapping, &xdg_config_home);
|
||||
}
|
||||
if let Some(default_config_home) = std::env::var_os("HOME")
|
||||
.filter(|val| !val.is_empty())
|
||||
.map(|home| Path::new(&home).join(".config"))
|
||||
{
|
||||
insert_git_config_global(&mut mapping, &default_config_home);
|
||||
}
|
||||
match (
|
||||
std::env::var_os("XDG_CONFIG_HOME").filter(|val| !val.is_empty()),
|
||||
std::env::var_os("HOME")
|
||||
.filter(|val| !val.is_empty())
|
||||
.map(|home| Path::new(&home).join(".config")),
|
||||
) {
|
||||
(Some(xdg_config_home), Some(default_config_home))
|
||||
if xdg_config_home == default_config_home => {
|
||||
insert_git_config_global(&mut mapping, &xdg_config_home)
|
||||
}
|
||||
(Some(xdg_config_home), Some(default_config_home)) /* else guard */ => {
|
||||
insert_git_config_global(&mut mapping, &xdg_config_home);
|
||||
insert_git_config_global(&mut mapping, &default_config_home)
|
||||
}
|
||||
(Some(config_home), None) => insert_git_config_global(&mut mapping, &config_home),
|
||||
(None, Some(config_home)) => insert_git_config_global(&mut mapping, &config_home),
|
||||
(None, None) => (),
|
||||
};
|
||||
|
||||
fn insert_git_config_global(mapping: &mut SyntaxMapping, config_home: impl AsRef<Path>) {
|
||||
let git_config_path = config_home.as_ref().join("git");
|
||||
@@ -182,7 +211,7 @@ impl<'a> SyntaxMapping<'a> {
|
||||
|
||||
pub fn insert(&mut self, from: &str, to: MappingTarget<'a>) -> Result<()> {
|
||||
let glob = GlobBuilder::new(from)
|
||||
.case_insensitive(false)
|
||||
.case_insensitive(true)
|
||||
.literal_separator(true)
|
||||
.build()?;
|
||||
self.mappings.push((glob.compile_matcher(), to));
|
||||
@@ -220,48 +249,76 @@ impl<'a> SyntaxMapping<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic() {
|
||||
let mut map = SyntaxMapping::empty();
|
||||
map.insert("/path/to/Cargo.lock", MappingTarget::MapTo("TOML"))
|
||||
.ok();
|
||||
map.insert("/path/to/.ignore", MappingTarget::MapTo("Git Ignore"))
|
||||
.ok();
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn basic() {
|
||||
let mut map = SyntaxMapping::empty();
|
||||
map.insert("/path/to/Cargo.lock", MappingTarget::MapTo("TOML"))
|
||||
.ok();
|
||||
map.insert("/path/to/.ignore", MappingTarget::MapTo("Git Ignore"))
|
||||
.ok();
|
||||
|
||||
assert_eq!(
|
||||
map.get_syntax_for("/path/to/Cargo.lock"),
|
||||
Some(MappingTarget::MapTo("TOML"))
|
||||
);
|
||||
assert_eq!(map.get_syntax_for("/path/to/other.lock"), None);
|
||||
assert_eq!(
|
||||
map.get_syntax_for("/path/to/Cargo.lock"),
|
||||
Some(MappingTarget::MapTo("TOML"))
|
||||
);
|
||||
assert_eq!(map.get_syntax_for("/path/to/other.lock"), None);
|
||||
|
||||
assert_eq!(
|
||||
map.get_syntax_for("/path/to/.ignore"),
|
||||
Some(MappingTarget::MapTo("Git Ignore"))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn user_can_override_builtin_mappings() {
|
||||
let mut map = SyntaxMapping::builtin();
|
||||
|
||||
assert_eq!(
|
||||
map.get_syntax_for("/etc/profile"),
|
||||
Some(MappingTarget::MapTo("Bourne Again Shell (bash)"))
|
||||
);
|
||||
map.insert("/etc/profile", MappingTarget::MapTo("My Syntax"))
|
||||
.ok();
|
||||
assert_eq!(
|
||||
map.get_syntax_for("/etc/profile"),
|
||||
Some(MappingTarget::MapTo("My Syntax"))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn builtin_mappings() {
|
||||
let map = SyntaxMapping::builtin();
|
||||
|
||||
assert_eq!(
|
||||
map.get_syntax_for("/path/to/build"),
|
||||
Some(MappingTarget::MapToUnknown)
|
||||
);
|
||||
assert_eq!(
|
||||
map.get_syntax_for("/path/to/.ignore"),
|
||||
Some(MappingTarget::MapTo("Git Ignore"))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn user_can_override_builtin_mappings() {
|
||||
let mut map = SyntaxMapping::builtin();
|
||||
|
||||
assert_eq!(
|
||||
map.get_syntax_for("/etc/profile"),
|
||||
Some(MappingTarget::MapTo("Bourne Again Shell (bash)"))
|
||||
);
|
||||
map.insert("/etc/profile", MappingTarget::MapTo("My Syntax"))
|
||||
.ok();
|
||||
assert_eq!(
|
||||
map.get_syntax_for("/etc/profile"),
|
||||
Some(MappingTarget::MapTo("My Syntax"))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn builtin_mappings() {
|
||||
let map = SyntaxMapping::builtin();
|
||||
|
||||
assert_eq!(
|
||||
map.get_syntax_for("/path/to/build"),
|
||||
Some(MappingTarget::MapToUnknown)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// verifies that SyntaxMapping::builtin() doesn't repeat `Glob`-based keys
|
||||
fn no_duplicate_builtin_keys() {
|
||||
let mappings = SyntaxMapping::builtin().mappings;
|
||||
for i in 0..mappings.len() {
|
||||
let tail = mappings[i + 1..].into_iter();
|
||||
let (dupl, _): (Vec<_>, Vec<_>) =
|
||||
tail.partition(|item| item.0.glob() == mappings[i].0.glob());
|
||||
|
||||
// emit repeats on failure
|
||||
assert_eq!(
|
||||
dupl.len(),
|
||||
0,
|
||||
"Glob pattern `{}` mapped to multiple: {:?}",
|
||||
mappings[i].0.glob().glob(),
|
||||
{
|
||||
let (_, mut dupl_targets): (Vec<GlobMatcher>, Vec<MappingTarget>) =
|
||||
dupl.into_iter().cloned().unzip();
|
||||
dupl_targets.push(mappings[i].1)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -20,7 +20,9 @@ impl Default for IgnoredSuffixes<'_> {
|
||||
".orig",
|
||||
// Debian and derivatives apt/dpkg/ucf backups
|
||||
".dpkg-dist",
|
||||
".dpkg-new",
|
||||
".dpkg-old",
|
||||
".dpkg-tmp",
|
||||
".ucf-dist",
|
||||
".ucf-new",
|
||||
".ucf-old",
|
||||
|
9
tests/benchmarks/run-benchmarks.sh
vendored
9
tests/benchmarks/run-benchmarks.sh
vendored
@@ -49,7 +49,8 @@ REPORT="$RESULT_DIR/report.md"
|
||||
TARGET_DIR="$(get_cargo_target_dir)"
|
||||
TARGET_RELEASE="${TARGET_DIR}/release/bat"
|
||||
|
||||
WARMUP_COUNT=3
|
||||
: ${WARMUP_COUNT:=3}
|
||||
: ${RUN_COUNT:=10}
|
||||
|
||||
# Determine which target to benchmark.
|
||||
BAT=''
|
||||
@@ -88,6 +89,7 @@ hyperfine \
|
||||
"$(printf "%q" "$BAT") --no-config" \
|
||||
--command-name "bat" \
|
||||
--warmup "$WARMUP_COUNT" \
|
||||
--runs "$RUN_COUNT" \
|
||||
--export-markdown "$RESULT_DIR/startup-time.md" \
|
||||
--export-json "$RESULT_DIR/startup-time.json"
|
||||
cat "$RESULT_DIR/startup-time.md" >> "$REPORT"
|
||||
@@ -98,6 +100,7 @@ hyperfine \
|
||||
"$(printf "%q" "$BAT") --no-config --color=always startup-time-src/small-CpuInfo-file.cpuinfo" \
|
||||
--command-name "bat … small-CpuInfo-file.cpuinfo" \
|
||||
--warmup "$WARMUP_COUNT" \
|
||||
--runs "$RUN_COUNT" \
|
||||
--export-markdown "$RESULT_DIR/startup-time-with-syntax-highlighting.md" \
|
||||
--export-json "$RESULT_DIR/startup-time-with-syntax-highlighting.json"
|
||||
cat "$RESULT_DIR/startup-time-with-syntax-highlighting.md" >> "$REPORT"
|
||||
@@ -108,6 +111,7 @@ hyperfine \
|
||||
"$(printf "%q" "$BAT") --no-config --color=always startup-time-src/small-Markdown-file.md" \
|
||||
--command-name "bat … small-Markdown-file.md" \
|
||||
--warmup "$WARMUP_COUNT" \
|
||||
--runs "$RUN_COUNT" \
|
||||
--export-markdown "$RESULT_DIR/startup-time-with-syntax-with-dependencies.md" \
|
||||
--export-json "$RESULT_DIR/startup-time-with-syntax-with-dependencies.json"
|
||||
cat "$RESULT_DIR/startup-time-with-syntax-with-dependencies.md" >> "$REPORT"
|
||||
@@ -118,6 +122,7 @@ hyperfine \
|
||||
"$(printf "%q" "$BAT") --no-config --language=txt --style=plain highlighting-speed-src/numpy_test_multiarray.py" \
|
||||
--command-name 'bat … --language=txt numpy_test_multiarray.py' \
|
||||
--warmup "$WARMUP_COUNT" \
|
||||
--runs "$RUN_COUNT" \
|
||||
--export-markdown "$RESULT_DIR/plain-text-speed.md" \
|
||||
--export-json "$RESULT_DIR/plain-text-speed.json"
|
||||
cat "$RESULT_DIR/plain-text-speed.md" >> "$REPORT"
|
||||
@@ -129,6 +134,7 @@ for wrap in character never; do
|
||||
|
||||
heading "Syntax highlighting speed --wrap=${wrap}: \`$filename\`"
|
||||
hyperfine --warmup "$WARMUP_COUNT" \
|
||||
--runs "$RUN_COUNT" \
|
||||
"$(printf "%q" "$BAT") --no-config --style=full --color=always --wrap=${wrap} --terminal-width=80 '$SRC'" \
|
||||
--command-name "bat … ${filename}" \
|
||||
--export-markdown "$RESULT_DIR/syntax-highlighting-speed-${filename}.md" \
|
||||
@@ -143,6 +149,7 @@ hyperfine \
|
||||
"$(printf "%q" "$BAT") --no-config --language=txt --style=plain many-small-files/*.txt" \
|
||||
--command-name 'bat … --language=txt *.txt' \
|
||||
--warmup "$WARMUP_COUNT" \
|
||||
--runs "$RUN_COUNT" \
|
||||
--export-markdown "$RESULT_DIR/many-small-files-speed.md" \
|
||||
--export-json "$RESULT_DIR/many-small-files-speed.json"
|
||||
cat "$RESULT_DIR/many-small-files-speed.md" >> "$REPORT"
|
||||
|
5
tests/examples/bat-windows.conf
vendored
Normal file
5
tests/examples/bat-windows.conf
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
# Make sure that the pager gets executed
|
||||
--paging=always
|
||||
|
||||
# Output a dummy message for the integration test and system wide config test.
|
||||
--pager="echo.bat dummy-pager-from-config"
|
BIN
tests/examples/control_characters.txt
vendored
Normal file
BIN
tests/examples/control_characters.txt
vendored
Normal file
Binary file not shown.
1
tests/examples/map-syntax_case.Config
vendored
Normal file
1
tests/examples/map-syntax_case.Config
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"test": "value"}
|
53
tests/github-actions.rs
Normal file
53
tests/github-actions.rs
Normal file
@@ -0,0 +1,53 @@
|
||||
#[test]
|
||||
fn all_jobs_not_missing_any_jobs() {
|
||||
let yaml: serde_yaml::Value =
|
||||
serde_yaml::from_reader(std::fs::File::open(".github/workflows/CICD.yml").unwrap())
|
||||
.unwrap();
|
||||
let jobs = yaml.get("jobs").unwrap();
|
||||
|
||||
// Get all jobs that all-jobs depends on:
|
||||
//
|
||||
// jobs:
|
||||
// all-jobs:
|
||||
// needs:
|
||||
// - this
|
||||
// - list
|
||||
// - ...
|
||||
let actual = jobs
|
||||
.get("all-jobs")
|
||||
.unwrap()
|
||||
.get("needs")
|
||||
.unwrap()
|
||||
.as_sequence()
|
||||
.unwrap();
|
||||
|
||||
// Get all jobs used in CI, except the ones we want to ignore:
|
||||
//
|
||||
// jobs:
|
||||
// this: ...
|
||||
// list: ...
|
||||
// ...
|
||||
let exceptions = [
|
||||
"all-jobs", // 'all-jobs' should not reference itself
|
||||
"winget", // only used when publishing a release
|
||||
];
|
||||
let expected = jobs
|
||||
.as_mapping()
|
||||
.unwrap()
|
||||
.keys()
|
||||
.filter_map(|k| {
|
||||
if exceptions.contains(&k.as_str().unwrap_or_default()) {
|
||||
None
|
||||
} else {
|
||||
Some(k)
|
||||
}
|
||||
})
|
||||
.map(ToOwned::to_owned)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Make sure they match
|
||||
assert_eq!(
|
||||
*actual, expected,
|
||||
"`all-jobs` should depend on all other jobs"
|
||||
);
|
||||
}
|
@@ -34,6 +34,14 @@ use utils::mocked_pagers;
|
||||
|
||||
const EXAMPLES_DIR: &str = "tests/examples";
|
||||
|
||||
fn get_config() -> &'static str {
|
||||
if cfg!(windows) {
|
||||
"bat-windows.conf"
|
||||
} else {
|
||||
"bat.conf"
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic() {
|
||||
bat()
|
||||
@@ -300,8 +308,10 @@ fn no_args_doesnt_break() {
|
||||
// this test exists.
|
||||
let OpenptyResult { master, slave } = openpty(None, None).expect("Couldn't open pty.");
|
||||
let mut master = unsafe { File::from_raw_fd(master) };
|
||||
let stdin = unsafe { Stdio::from_raw_fd(slave) };
|
||||
let stdout = unsafe { Stdio::from_raw_fd(slave) };
|
||||
let stdin_file = unsafe { File::from_raw_fd(slave) };
|
||||
let stdout_file = stdin_file.try_clone().unwrap();
|
||||
let stdin = Stdio::from(stdin_file);
|
||||
let stdout = Stdio::from(stdout_file);
|
||||
|
||||
let mut child = bat_raw_command()
|
||||
.stdin(stdin)
|
||||
@@ -589,37 +599,49 @@ fn do_not_exit_directory() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn pager_basic() {
|
||||
bat()
|
||||
.env("PAGER", "echo pager-output")
|
||||
.arg("--paging=always")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::eq("pager-output\n").normalize());
|
||||
mocked_pagers::with_mocked_versions_of_more_and_most_in_path(|| {
|
||||
bat()
|
||||
.env("PAGER", mocked_pagers::from("echo pager-output"))
|
||||
.arg("--paging=always")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("pager-output\n").normalize());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn pager_basic_arg() {
|
||||
bat()
|
||||
.arg("--pager=echo pager-output")
|
||||
.arg("--paging=always")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::eq("pager-output\n").normalize());
|
||||
mocked_pagers::with_mocked_versions_of_more_and_most_in_path(|| {
|
||||
bat()
|
||||
.arg(format!(
|
||||
"--pager={}",
|
||||
mocked_pagers::from("echo pager-output")
|
||||
))
|
||||
.arg("--paging=always")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("pager-output\n").normalize());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn pager_overwrite() {
|
||||
bat()
|
||||
.env("PAGER", "echo other-pager")
|
||||
.env("BAT_PAGER", "echo pager-output")
|
||||
.arg("--paging=always")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::eq("pager-output\n").normalize());
|
||||
mocked_pagers::with_mocked_versions_of_more_and_most_in_path(|| {
|
||||
bat()
|
||||
.env("PAGER", mocked_pagers::from("echo other-pager"))
|
||||
.env("BAT_PAGER", mocked_pagers::from("echo pager-output"))
|
||||
.arg("--paging=always")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("pager-output\n").normalize());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -635,55 +657,73 @@ fn pager_disable() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn pager_arg_override_env_withconfig() {
|
||||
bat_with_config()
|
||||
.env("BAT_CONFIG_PATH", "bat.conf")
|
||||
.env("PAGER", "echo another-pager")
|
||||
.env("BAT_PAGER", "echo other-pager")
|
||||
.arg("--pager=echo pager-output")
|
||||
.arg("--paging=always")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::eq("pager-output\n").normalize());
|
||||
mocked_pagers::with_mocked_versions_of_more_and_most_in_path(|| {
|
||||
bat_with_config()
|
||||
.env("BAT_CONFIG_PATH", get_config())
|
||||
.env("PAGER", mocked_pagers::from("echo another-pager"))
|
||||
.env("BAT_PAGER", mocked_pagers::from("echo other-pager"))
|
||||
.arg(format!(
|
||||
"--pager={}",
|
||||
mocked_pagers::from("echo pager-output")
|
||||
))
|
||||
.arg("--paging=always")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("pager-output\n").normalize());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn pager_arg_override_env_noconfig() {
|
||||
bat()
|
||||
.env("PAGER", "echo another-pager")
|
||||
.env("BAT_PAGER", "echo other-pager")
|
||||
.arg("--pager=echo pager-output")
|
||||
.arg("--paging=always")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::eq("pager-output\n").normalize());
|
||||
mocked_pagers::with_mocked_versions_of_more_and_most_in_path(|| {
|
||||
bat()
|
||||
.env("PAGER", mocked_pagers::from("echo another-pager"))
|
||||
.env("BAT_PAGER", mocked_pagers::from("echo other-pager"))
|
||||
.arg(format!(
|
||||
"--pager={}",
|
||||
mocked_pagers::from("echo pager-output")
|
||||
))
|
||||
.arg("--paging=always")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("pager-output\n").normalize());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn pager_env_bat_pager_override_config() {
|
||||
bat_with_config()
|
||||
.env("BAT_CONFIG_PATH", "bat.conf")
|
||||
.env("PAGER", "echo other-pager")
|
||||
.env("BAT_PAGER", "echo pager-output")
|
||||
.arg("--paging=always")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::eq("pager-output\n").normalize());
|
||||
mocked_pagers::with_mocked_versions_of_more_and_most_in_path(|| {
|
||||
bat_with_config()
|
||||
.env("BAT_CONFIG_PATH", get_config())
|
||||
.env("PAGER", mocked_pagers::from("echo other-pager"))
|
||||
.env("BAT_PAGER", mocked_pagers::from("echo pager-output"))
|
||||
.arg("--paging=always")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("pager-output\n").normalize());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn pager_env_pager_nooverride_config() {
|
||||
bat_with_config()
|
||||
.env("BAT_CONFIG_PATH", "bat.conf")
|
||||
.env("PAGER", "echo other-pager")
|
||||
.arg("--paging=always")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::eq("dummy-pager-from-config\n").normalize());
|
||||
mocked_pagers::with_mocked_versions_of_more_and_most_in_path(|| {
|
||||
bat_with_config()
|
||||
.env("BAT_CONFIG_PATH", get_config())
|
||||
.env("PAGER", mocked_pagers::from("echo other-pager"))
|
||||
.arg("--paging=always")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("dummy-pager-from-config\n").normalize());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -809,15 +849,18 @@ fn alias_pager_disable() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn alias_pager_disable_long_overrides_short() {
|
||||
bat()
|
||||
.env("PAGER", "echo pager-output")
|
||||
.arg("-P")
|
||||
.arg("--paging=always")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::eq("pager-output\n").normalize());
|
||||
mocked_pagers::with_mocked_versions_of_more_and_most_in_path(|| {
|
||||
bat()
|
||||
.env("PAGER", mocked_pagers::from("echo pager-output"))
|
||||
.arg("-P")
|
||||
.arg("--paging=always")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("pager-output\n").normalize());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -832,6 +875,42 @@ fn disable_pager_if_disable_paging_flag_comes_after_paging() {
|
||||
.stdout(predicate::eq("hello world\n").normalize());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn disable_pager_if_pp_flag_comes_after_paging() {
|
||||
bat()
|
||||
.env("PAGER", "echo pager-output")
|
||||
.arg("--paging=always")
|
||||
.arg("-pp")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::eq("hello world\n").normalize());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enable_pager_if_disable_paging_flag_comes_before_paging() {
|
||||
bat()
|
||||
.env("PAGER", "echo pager-output")
|
||||
.arg("-P")
|
||||
.arg("--paging=always")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::eq("pager-output\n").normalize());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enable_pager_if_pp_flag_comes_before_paging() {
|
||||
bat()
|
||||
.env("PAGER", "echo pager-output")
|
||||
.arg("-pp")
|
||||
.arg("--paging=always")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::eq("pager-output\n").normalize());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pager_failed_to_parse() {
|
||||
bat()
|
||||
@@ -843,6 +922,20 @@ fn pager_failed_to_parse() {
|
||||
.stderr(predicate::str::contains("Could not parse pager command"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn env_var_bat_paging() {
|
||||
mocked_pagers::with_mocked_versions_of_more_and_most_in_path(|| {
|
||||
bat()
|
||||
.env("BAT_PAGER", mocked_pagers::from("echo pager-output"))
|
||||
.env("BAT_PAGING", "always")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("pager-output\n").normalize());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn diagnostic_sanity_check() {
|
||||
bat()
|
||||
@@ -901,13 +994,16 @@ fn config_location_from_bat_config_dir_variable() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn config_read_arguments_from_file() {
|
||||
bat_with_config()
|
||||
.env("BAT_CONFIG_PATH", "bat.conf")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::eq("dummy-pager-from-config\n").normalize());
|
||||
mocked_pagers::with_mocked_versions_of_more_and_most_in_path(|| {
|
||||
bat_with_config()
|
||||
.env("BAT_CONFIG_PATH", get_config())
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("dummy-pager-from-config\n").normalize());
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
@@ -1632,6 +1728,25 @@ fn show_all_with_caret_notation() {
|
||||
.assert()
|
||||
.stdout("hello·world^J\n├──┤^M^@^G^H^[")
|
||||
.stderr("");
|
||||
|
||||
bat()
|
||||
.arg("--show-all")
|
||||
.arg("--nonprintable-notation=caret")
|
||||
.arg("control_characters.txt")
|
||||
.assert()
|
||||
.stdout("^@^A^B^C^D^E^F^G^H├─┤^J\n^K^L^M^N^O^P^Q^R^S^T^U^V^W^X^Y^Z^[^\\^]^^^_^?")
|
||||
.stderr("");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn show_all_with_unicode() {
|
||||
bat()
|
||||
.arg("--show-all")
|
||||
.arg("--nonprintable-notation=unicode")
|
||||
.arg("control_characters.txt")
|
||||
.assert()
|
||||
.stdout("␀␁␂␃␄␅␆␇␈├─┤␊\n␋␌␍␎␏␐␑␒␓␔␕␖␗␘␙␚␛␜␝␞␟␡")
|
||||
.stderr("");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -2014,3 +2129,304 @@ fn acknowledgements() {
|
||||
)
|
||||
.stderr("");
|
||||
}
|
||||
|
||||
#[cfg(unix)] // Expected output assumed that tests are run on a Unix-like system
|
||||
#[cfg(feature = "lessopen")]
|
||||
#[test]
|
||||
fn lessopen_file_piped() {
|
||||
bat()
|
||||
.env("LESSOPEN", "|echo File is %s")
|
||||
.arg("--lessopen")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("File is test.txt\n");
|
||||
}
|
||||
|
||||
#[cfg(unix)] // Expected output assumed that tests are run on a Unix-like system
|
||||
#[cfg(feature = "lessopen")]
|
||||
#[test]
|
||||
fn lessopen_stdin_piped() {
|
||||
bat()
|
||||
.env("LESSOPEN", "|cat")
|
||||
.arg("--lessopen")
|
||||
.write_stdin("hello world\n")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("hello world\n");
|
||||
}
|
||||
|
||||
#[cfg(unix)] // Expected output assumed that tests are run on a Unix-like system
|
||||
#[cfg(feature = "lessopen")]
|
||||
#[test]
|
||||
#[serial] // Randomly fails otherwise
|
||||
fn lessopen_and_lessclose_file_temp() {
|
||||
// This is mainly to test that $LESSCLOSE gets passed the correct file paths
|
||||
// In this case, the original file and the temporary file returned by $LESSOPEN
|
||||
bat()
|
||||
// Need a %s for $LESSOPEN to be valid
|
||||
.env("LESSOPEN", "echo empty.txt && echo %s >/dev/null")
|
||||
.env("LESSCLOSE", "echo lessclose: %s %s")
|
||||
.arg("--lessopen")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("lessclose: test.txt empty.txt\n");
|
||||
}
|
||||
|
||||
#[cfg(unix)] // Expected output assumed that tests are run on a Unix-like system
|
||||
#[cfg(feature = "lessopen")]
|
||||
#[test]
|
||||
#[serial] // Randomly fails otherwise
|
||||
fn lessopen_and_lessclose_file_piped() {
|
||||
// This is mainly to test that $LESSCLOSE gets passed the correct file paths
|
||||
// In these cases, the original file and a dash
|
||||
bat()
|
||||
// This test will not work properly if $LESSOPEN does not output anything
|
||||
.env("LESSOPEN", "|cat %s")
|
||||
.env("LESSCLOSE", "echo lessclose: %s %s")
|
||||
.arg("--lessopen")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("hello world\nlessclose: test.txt -\n");
|
||||
|
||||
bat()
|
||||
.env("LESSOPEN", "||cat %s")
|
||||
.env("LESSCLOSE", "echo lessclose: %s %s")
|
||||
.arg("--lessopen")
|
||||
.arg("empty.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("lessclose: empty.txt -\n");
|
||||
}
|
||||
|
||||
#[cfg(unix)] // Expected output assumed that tests are run on a Unix-like system
|
||||
#[cfg(feature = "lessopen")]
|
||||
#[test]
|
||||
#[serial] // Randomly fails otherwise
|
||||
#[ignore = "randomly failing on some systems"]
|
||||
fn lessopen_and_lessclose_stdin_temp() {
|
||||
// This is mainly to test that $LESSCLOSE gets passed the correct file paths
|
||||
// In this case, a dash and the temporary file returned by $LESSOPEN
|
||||
bat()
|
||||
// Need a %s for $LESSOPEN to be valid
|
||||
.env("LESSOPEN", "-echo empty.txt && echo %s >/dev/null")
|
||||
.env("LESSCLOSE", "echo lessclose: %s %s")
|
||||
.arg("--lessopen")
|
||||
.write_stdin("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("lessclose: - empty.txt\n");
|
||||
}
|
||||
|
||||
#[cfg(unix)] // Expected output assumed that tests are run on a Unix-like system
|
||||
#[cfg(feature = "lessopen")]
|
||||
#[test]
|
||||
#[serial] // Randomly fails otherwise
|
||||
fn lessopen_and_lessclose_stdin_piped() {
|
||||
// This is mainly to test that $LESSCLOSE gets passed the correct file paths
|
||||
// In these cases, two dashes
|
||||
bat()
|
||||
// This test will not work properly if $LESSOPEN does not output anything
|
||||
// Need a %s for $LESSOPEN to be valid
|
||||
.env("LESSOPEN", "|-cat test.txt && echo %s >/dev/null")
|
||||
.env("LESSCLOSE", "echo lessclose: %s %s")
|
||||
.arg("--lessopen")
|
||||
.write_stdin("empty.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("hello world\nlessclose: - -\n");
|
||||
|
||||
bat()
|
||||
// Need a %s for $LESSOPEN to be valid
|
||||
.env("LESSOPEN", "||-cat empty.txt && echo %s >/dev/null")
|
||||
.env("LESSCLOSE", "echo lessclose: %s %s")
|
||||
.arg("--lessopen")
|
||||
.write_stdin("empty.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("lessclose: - -\n");
|
||||
}
|
||||
|
||||
#[cfg(unix)] // Expected output assumed that tests are run on a Unix-like system
|
||||
#[cfg(feature = "lessopen")]
|
||||
#[test]
|
||||
fn lessopen_handling_empty_output_file() {
|
||||
bat()
|
||||
// Need a %s for $LESSOPEN to be valid
|
||||
.env("LESSOPEN", "|cat empty.txt && echo %s >/dev/null")
|
||||
.arg("--lessopen")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("hello world\n");
|
||||
|
||||
bat()
|
||||
// Need a %s for $LESSOPEN to be valid
|
||||
.env("LESSOPEN", "|cat nonexistent.txt && echo %s >/dev/null")
|
||||
.arg("--lessopen")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("hello world\n");
|
||||
|
||||
bat()
|
||||
// Need a %s for $LESSOPEN to be valid
|
||||
.env("LESSOPEN", "||cat empty.txt && echo %s >/dev/null")
|
||||
.arg("--lessopen")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("");
|
||||
|
||||
bat()
|
||||
// Need a %s for $LESSOPEN to be valid
|
||||
.env("LESSOPEN", "||cat nonexistent.txt && echo %s >/dev/null")
|
||||
.arg("--lessopen")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("hello world\n");
|
||||
}
|
||||
|
||||
#[cfg(unix)] // Expected output assumed that tests are run on a Unix-like system
|
||||
#[cfg(feature = "lessopen")]
|
||||
#[test]
|
||||
// FIXME
|
||||
fn lessopen_handling_empty_output_stdin() {
|
||||
bat()
|
||||
// Need a %s for $LESSOPEN to be valid
|
||||
.env("LESSOPEN", "|-cat empty.txt && echo %s >/dev/null")
|
||||
.arg("--lessopen")
|
||||
.write_stdin("hello world\n")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("hello world\n");
|
||||
|
||||
bat()
|
||||
// Need a %s for $LESSOPEN to be valid
|
||||
.env("LESSOPEN", "|-cat nonexistent.txt && echo %s >/dev/null")
|
||||
.arg("--lessopen")
|
||||
.write_stdin("hello world\n")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("hello world\n");
|
||||
|
||||
bat()
|
||||
// Need a %s for $LESSOPEN to be valid
|
||||
.env("LESSOPEN", "||-cat empty.txt && echo %s >/dev/null")
|
||||
.arg("--lessopen")
|
||||
.write_stdin("hello world\n")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("");
|
||||
|
||||
bat()
|
||||
// Need a %s for $LESSOPEN to be valid
|
||||
.env("LESSOPEN", "||-cat nonexistent.txt && echo %s >/dev/null")
|
||||
.arg("--lessopen")
|
||||
.write_stdin("hello world\n")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("hello world\n");
|
||||
}
|
||||
|
||||
#[cfg(unix)] // Expected output assumed that tests are run on a Unix-like system
|
||||
#[cfg(feature = "lessopen")]
|
||||
#[test]
|
||||
fn lessopen_uses_shell() {
|
||||
bat()
|
||||
.env("LESSOPEN", "|cat < %s")
|
||||
.arg("--lessopen")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("hello world\n");
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[cfg(feature = "lessopen")]
|
||||
#[test]
|
||||
fn do_not_use_lessopen_by_default() {
|
||||
bat()
|
||||
.env("LESSOPEN", "|echo File is %s")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("hello world\n");
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[cfg(feature = "lessopen")]
|
||||
#[test]
|
||||
fn do_not_use_lessopen_if_overridden() {
|
||||
bat()
|
||||
.env("LESSOPEN", "|echo File is %s")
|
||||
.arg("--lessopen")
|
||||
.arg("--no-lessopen")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("hello world\n");
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[cfg(feature = "lessopen")]
|
||||
#[test]
|
||||
fn lessopen_validity() {
|
||||
bat()
|
||||
.env("LESSOPEN", "|echo File is test.txt")
|
||||
.arg("--lessopen")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("hello world\n")
|
||||
.stderr(
|
||||
"\u{1b}[33m[bat warning]\u{1b}[0m: LESSOPEN ignored: must contain exactly one %s\n",
|
||||
);
|
||||
|
||||
bat()
|
||||
.env("LESSOPEN", "|echo File is %s")
|
||||
.arg("--lessopen")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("File is test.txt\n")
|
||||
.stderr("");
|
||||
|
||||
bat()
|
||||
.env("LESSOPEN", "|echo %s is %s")
|
||||
.arg("--lessopen")
|
||||
.arg("test.txt")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout("hello world\n")
|
||||
.stderr(
|
||||
"\u{1b}[33m[bat warning]\u{1b}[0m: LESSOPEN ignored: must contain exactly one %s\n",
|
||||
);
|
||||
}
|
||||
|
||||
// Regression test for issue #2520 and PR #2650
|
||||
// Syntax highlighting should be the same regardless of
|
||||
// --map-syntax' case or file extension's case
|
||||
#[test]
|
||||
fn highlighting_independant_from_map_syntax_case() {
|
||||
let expected = bat()
|
||||
.arg("-f")
|
||||
.arg("--map-syntax=*.config:JSON")
|
||||
.arg("map-syntax_case.Config")
|
||||
.assert()
|
||||
.get_output()
|
||||
.stdout
|
||||
.clone();
|
||||
|
||||
bat()
|
||||
.arg("-f")
|
||||
.arg("--map-syntax=*.Config:JSON")
|
||||
.arg("map-syntax_case.Config")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(expected)
|
||||
.stderr("");
|
||||
}
|
||||
|
1
tests/mocked-pagers/echo.bat
Normal file
1
tests/mocked-pagers/echo.bat
Normal file
@@ -0,0 +1 @@
|
||||
ECHO %*
|
@@ -8,11 +8,13 @@ import os
|
||||
import argparse
|
||||
from multiprocessing import Pool
|
||||
|
||||
# Avoid 'default' theme because it can choose a different theme based on
|
||||
# the appearance settings on macOS.
|
||||
BAT_OPTIONS = [
|
||||
"--no-config",
|
||||
"--style=plain",
|
||||
"--color=always",
|
||||
"--theme=default",
|
||||
"--theme=Monokai Extended",
|
||||
"--italic-text=always",
|
||||
]
|
||||
|
||||
|
32
tests/syntax-tests/highlighted/JQ/sample.jq
vendored
32
tests/syntax-tests/highlighted/JQ/sample.jq
vendored
@@ -1,31 +1,31 @@
|
||||
[38;2;249;38;114mimport[0m[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;230;219;116m../imported-file[0m[38;2;230;219;116m"[0m[38;2;248;248;242m [0m[38;2;248;248;242m;[0m
|
||||
|
||||
[38;2;117;113;94m#[0m[38;2;117;113;94m With Comments ![0m
|
||||
[38;2;249;38;114mdef[0m[38;2;248;248;242m [0m[38;2;166;226;46mweird[0m[38;2;248;248;242m([0m[3;38;2;253;151;31m$a[0m[38;2;248;248;242m; [0m[3;38;2;253;151;31m$b[0m[38;2;248;248;242m; [0m[3;38;2;253;151;31m$c[0m[38;2;248;248;242m)[0m[38;2;248;248;242m:[0m
|
||||
[38;2;248;248;242m [0m[38;2;248;248;242m[ [0m[38;2;255;255;255m$a[0m[38;2;248;248;242m, [0m[38;2;255;255;255m$b[0m[38;2;248;248;242m, [0m[38;2;255;255;255m$c[0m[38;2;248;248;242m ][0m[38;2;248;248;242m | [0m[38;2;102;217;239mtranspose[0m[38;2;248;248;242m | [0m[38;2;249;38;114mreduce[0m[38;2;248;248;242m .[0m[38;2;248;248;242m[][0m[38;2;248;248;242m[][0m[38;2;248;248;242m [0m[38;2;249;38;114mas[0m[38;2;248;248;242m [0m[38;2;255;255;255m$item[0m[38;2;248;248;242m [0m[38;2;248;248;242m([0m
|
||||
[38;2;248;248;242m [0m[38;2;248;248;242m[][0m[38;2;248;248;242m;[0m
|
||||
[38;2;248;248;242m . + [0m[38;2;255;255;255m$item[0m[38;2;248;248;242m.property[0m
|
||||
[38;2;248;248;242m )[0m
|
||||
[38;2;249;38;114mdef[0m[38;2;248;248;242m [0m[38;2;166;226;46mweird[0m[38;2;248;248;242m([0m[3;38;2;253;151;31m$a[0m[38;2;248;248;242m;[0m[38;2;248;248;242m [0m[3;38;2;253;151;31m$b[0m[38;2;248;248;242m;[0m[38;2;248;248;242m [0m[3;38;2;253;151;31m$c[0m[38;2;248;248;242m)[0m[38;2;248;248;242m:[0m
|
||||
[38;2;248;248;242m [0m[38;2;248;248;242m[[0m[38;2;248;248;242m [0m[38;2;255;255;255m$[0m[38;2;255;255;255ma[0m[38;2;248;248;242m, [0m[38;2;255;255;255m$[0m[38;2;255;255;255mb[0m[38;2;248;248;242m, [0m[38;2;255;255;255m$[0m[38;2;255;255;255mc[0m[38;2;248;248;242m [0m[38;2;248;248;242m][0m[38;2;248;248;242m [0m[38;2;249;38;114m|[0m[38;2;248;248;242m [0m[38;2;102;217;239mtranspose[0m[38;2;248;248;242m [0m[38;2;249;38;114m|[0m[38;2;248;248;242m [0m[38;2;249;38;114mreduce[0m[38;2;248;248;242m [0m[38;2;248;248;242m.[0m[38;2;248;248;242m[[0m[38;2;248;248;242m][0m[38;2;248;248;242m[[0m[38;2;248;248;242m][0m[38;2;248;248;242m [0m[38;2;249;38;114mas[0m[38;2;248;248;242m [0m[38;2;255;255;255m$[0m[38;2;255;255;255mitem[0m[38;2;248;248;242m [0m[38;2;248;248;242m([0m
|
||||
[38;2;248;248;242m [0m[38;2;248;248;242m[[0m[38;2;248;248;242m][0m[38;2;248;248;242m;[0m
|
||||
[38;2;248;248;242m [0m[38;2;248;248;242m.[0m[38;2;248;248;242m [0m[38;2;249;38;114m+[0m[38;2;248;248;242m [0m[38;2;255;255;255m$[0m[38;2;255;255;255mitem[0m[38;2;248;248;242m.[0m[38;2;248;248;242mproperty[0m
|
||||
[38;2;248;248;242m [0m[38;2;248;248;242m)[0m
|
||||
[38;2;248;248;242m;[0m
|
||||
|
||||
[38;2;248;248;242m. | weird [0m[38;2;248;248;242m(.a; .b; .c)[0m[38;2;248;248;242m |[0m
|
||||
[38;2;248;248;242m.[0m[38;2;248;248;242m [0m[38;2;249;38;114m|[0m[38;2;248;248;242m weird [0m[38;2;248;248;242m([0m[38;2;248;248;242m.[0m[38;2;248;248;242ma[0m[38;2;248;248;242m;[0m[38;2;248;248;242m [0m[38;2;248;248;242m.[0m[38;2;248;248;242mb[0m[38;2;248;248;242m;[0m[38;2;248;248;242m [0m[38;2;248;248;242m.[0m[38;2;248;248;242mc[0m[38;2;248;248;242m)[0m[38;2;248;248;242m [0m[38;2;249;38;114m|[0m
|
||||
|
||||
[38;2;248;248;242m([0m
|
||||
|
||||
[38;2;249;38;114mif[0m[38;2;248;248;242m [0m[38;2;248;248;242m(. | [0m[38;2;102;217;239mcontains[0m[38;2;248;248;242m([0m[38;2;230;219;116m"[0m[38;2;230;219;116mnever[0m[38;2;230;219;116m"[0m[38;2;248;248;242m)[0m[38;2;248;248;242m )[0m[38;2;248;248;242m [0m[38;2;249;38;114mthen[0m
|
||||
[38;2;249;38;114mif[0m[38;2;248;248;242m [0m[38;2;248;248;242m([0m[38;2;248;248;242m.[0m[38;2;248;248;242m [0m[38;2;249;38;114m|[0m[38;2;248;248;242m [0m[38;2;102;217;239mcontains[0m[38;2;248;248;242m([0m[38;2;230;219;116m"[0m[38;2;230;219;116mnever[0m[38;2;230;219;116m"[0m[38;2;248;248;242m)[0m[38;2;248;248;242m [0m[38;2;248;248;242m)[0m[38;2;248;248;242m [0m[38;2;249;38;114mthen[0m
|
||||
[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;230;219;116mWhy yes[0m[38;2;230;219;116m"[0m
|
||||
[38;2;249;38;114melse[0m
|
||||
[38;2;248;248;242m [0m[38;2;190;132;255m12.23[0m
|
||||
[38;2;249;38;114mend[0m
|
||||
|
||||
[38;2;248;248;242m)[0m[38;2;248;248;242m [0m[38;2;249;38;114mas[0m[38;2;248;248;242m [0m[38;2;255;255;255m$never[0m[38;2;248;248;242m |[0m
|
||||
[38;2;248;248;242m)[0m[38;2;248;248;242m [0m[38;2;249;38;114mas[0m[38;2;248;248;242m [0m[38;2;255;255;255m$[0m[38;2;255;255;255mnever[0m[38;2;248;248;242m [0m[38;2;249;38;114m|[0m
|
||||
|
||||
[38;2;248;248;242m{[0m
|
||||
[38;2;248;248;242m [0m[38;2;166;226;46mhello[0m[38;2;248;248;242m,[0m
|
||||
[38;2;248;248;242m [0m[38;2;166;226;46mwhy[0m[38;2;248;248;242m:[0m[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;230;219;116mbecause[0m[38;2;230;219;116m"[0m[38;2;248;248;242m,[0m
|
||||
[38;2;248;248;242m [0m[38;2;166;226;46mhello[0m[38;2;248;248;242m:[0m[38;2;248;248;242m [0m[38;2;248;248;242m( weird | [0m[38;2;102;217;239mascii_upcase[0m[38;2;248;248;242m )[0m[38;2;248;248;242m,[0m
|
||||
[38;2;248;248;242m [0m[38;2;166;226;46mformat_eg[0m[38;2;248;248;242m:[0m[38;2;248;248;242m [0m[38;2;248;248;242m( . | [0m[38;2;190;132;255m@json[0m[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;230;219;116mMy json string [0m[38;2;190;132;255m\([0m[38;2;248;248;242m . | this | part | just | white | ascii_upcase | transpose[0m[38;2;190;132;255m)[0m[38;2;230;219;116m"[0m[38;2;248;248;242m )[0m[38;2;248;248;242m,[0m
|
||||
[38;2;248;248;242m [0m[38;2;166;226;46mnever[0m[38;2;248;248;242m:[0m[38;2;248;248;242m [0m[38;2;255;255;255m$never[0m[38;2;248;248;242m,[0m
|
||||
[38;2;248;248;242m [0m[38;2;166;226;46mhello[0m[38;2;248;248;242m:[0m[38;2;248;248;242m [0m[38;2;248;248;242m([0m[38;2;248;248;242m weird [0m[38;2;249;38;114m|[0m[38;2;248;248;242m [0m[38;2;102;217;239mascii_upcase[0m[38;2;248;248;242m [0m[38;2;248;248;242m)[0m[38;2;248;248;242m,[0m
|
||||
[38;2;248;248;242m [0m[38;2;166;226;46mformat_eg[0m[38;2;248;248;242m:[0m[38;2;248;248;242m [0m[38;2;248;248;242m([0m[38;2;248;248;242m [0m[38;2;248;248;242m.[0m[38;2;248;248;242m [0m[38;2;249;38;114m|[0m[38;2;248;248;242m [0m[38;2;190;132;255m@json[0m[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;230;219;116mMy json string [0m[38;2;190;132;255m\([0m[38;2;248;248;242m . | this | part | just | white | ascii_upcase | transpose[0m[38;2;190;132;255m)[0m[38;2;230;219;116m"[0m[38;2;248;248;242m [0m[38;2;248;248;242m)[0m[38;2;248;248;242m,[0m
|
||||
[38;2;248;248;242m [0m[38;2;166;226;46mnever[0m[38;2;248;248;242m:[0m[38;2;248;248;242m [0m[38;2;255;255;255m$[0m[38;2;255;255;255mnever[0m[38;2;248;248;242m,[0m
|
||||
[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;230;219;116mliteral_key[0m[38;2;230;219;116m"[0m[38;2;248;248;242m:[0m[38;2;248;248;242m literal_value[0m[38;2;248;248;242m,[0m
|
||||
[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;230;219;116mthis[0m[38;2;230;219;116m"[0m[38;2;248;248;242m:[0m[38;2;248;248;242m [0m[38;2;190;132;255m12.1e12[0m[38;2;248;248;242m,[0m
|
||||
[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;230;219;116mpart[0m[38;2;230;219;116m"[0m[38;2;248;248;242m:[0m[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;230;219;116malmost[0m[38;2;230;219;116m"[0m
|
||||
@@ -38,8 +38,8 @@
|
||||
[38;2;248;248;242m [0m[38;2;166;226;46msimilar[0m[38;2;248;248;242m:[0m[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;230;219;116mbut not quite[0m[38;2;230;219;116m"[0m
|
||||
[38;2;248;248;242m [0m[38;2;248;248;242m}[0m
|
||||
[38;2;248;248;242m [0m[38;2;248;248;242m}[0m
|
||||
[38;2;248;248;242m ][0m[38;2;248;248;242m,[0m
|
||||
[38;2;248;248;242m}[0m[38;2;248;248;242m | [0m[38;2;248;248;242m([0m
|
||||
[38;2;248;248;242m [0m[38;2;248;248;242m][0m[38;2;248;248;242m,[0m
|
||||
[38;2;248;248;242m}[0m[38;2;248;248;242m [0m[38;2;249;38;114m|[0m[38;2;248;248;242m [0m[38;2;248;248;242m([0m
|
||||
[38;2;248;248;242m [0m
|
||||
[38;2;248;248;242m [0m[38;2;117;113;94m#[0m[38;2;117;113;94m And with very basic brace matching[0m
|
||||
[38;2;248;248;242m [0m
|
||||
@@ -47,13 +47,13 @@
|
||||
[38;2;248;248;242m [0m[38;2;248;248;240m][0m[38;2;248;248;242m [0m
|
||||
[38;2;248;248;242m [0m
|
||||
[38;2;248;248;242m [0m[38;2;117;113;94m#[0m[38;2;117;113;94m Other invalid ends[0m
|
||||
[38;2;248;248;242m [0m[38;2;248;248;242m( [0m[38;2;248;248;242m[ [0m[38;2;248;248;240m}[0m[38;2;248;248;242m [0m[38;2;248;248;240m][0m[38;2;248;248;242m )[0m
|
||||
[38;2;248;248;242m [0m[38;2;248;248;242m([0m[38;2;248;248;242m [0m[38;2;248;248;242m[[0m[38;2;248;248;242m [0m[38;2;248;248;240m}[0m[38;2;248;248;242m [0m[38;2;248;248;240m][0m[38;2;248;248;242m )[0m
|
||||
|
||||
[38;2;248;248;242m [0m[38;2;117;113;94m#[0m[38;2;117;113;94m A "valid" sequence[0m
|
||||
[38;2;248;248;242m [0m[38;2;248;248;242m( [0m[38;2;248;248;242m[ [0m[38;2;248;248;242m{ [0m[38;2;166;226;46mkey[0m[38;2;248;248;242m:[0m[38;2;248;248;242m [0m[38;2;248;248;242m()[0m[38;2;248;248;242m [0m[38;2;248;248;242m,[0m[38;2;248;248;242m [0m[38;2;166;226;46mother_key[0m[38;2;248;248;242m:[0m[38;2;248;248;242m( [0m[38;2;248;248;242m[ [0m[38;2;248;248;242m[][0m[38;2;248;248;242m [0m[38;2;248;248;242m[[0m[38;2;248;248;242m[][0m[38;2;248;248;242m][0m[38;2;248;248;242m ][0m[38;2;248;248;242m )[0m[38;2;248;248;242m,[0m[38;2;248;248;242m [0m[38;2;166;226;46mgaga[0m[38;2;248;248;242m }[0m[38;2;248;248;242m ][0m[38;2;248;248;242m )[0m
|
||||
[38;2;248;248;242m [0m[38;2;248;248;242m([0m[38;2;248;248;242m [0m[38;2;248;248;242m[[0m[38;2;248;248;242m [0m[38;2;248;248;242m{[0m[38;2;248;248;242m [0m[38;2;166;226;46mkey[0m[38;2;248;248;242m:[0m[38;2;248;248;242m [0m[38;2;248;248;242m([0m[38;2;248;248;242m)[0m[38;2;248;248;242m [0m[38;2;248;248;242m,[0m[38;2;248;248;242m [0m[38;2;166;226;46mother_key[0m[38;2;248;248;242m:[0m[38;2;248;248;242m([0m[38;2;248;248;242m [0m[38;2;248;248;242m[[0m[38;2;248;248;242m [0m[38;2;248;248;242m[[0m[38;2;248;248;242m][0m[38;2;248;248;242m [0m[38;2;248;248;242m[[0m[38;2;248;248;242m[[0m[38;2;248;248;242m][0m[38;2;248;248;242m][0m[38;2;248;248;242m [0m[38;2;248;248;242m][0m[38;2;248;248;242m [0m[38;2;248;248;242m)[0m[38;2;248;248;242m,[0m[38;2;248;248;242m [0m[38;2;166;226;46mgaga[0m[38;2;248;248;242m [0m[38;2;248;248;242m}[0m[38;2;248;248;242m [0m[38;2;248;248;242m][0m[38;2;248;248;242m [0m[38;2;248;248;242m)[0m
|
||||
|
||||
[38;2;248;248;242m [0m[38;2;117;113;94m#[0m[38;2;117;113;94m A "invalid" sequence[0m
|
||||
[38;2;248;248;242m [0m[38;2;248;248;242m( [0m[38;2;248;248;242m[ [0m[38;2;248;248;242m{ [0m[38;2;166;226;46mkey[0m[38;2;248;248;242m:[0m[38;2;248;248;242m [0m[38;2;248;248;242m()[0m[38;2;248;248;242m [0m[38;2;248;248;242m,[0m[38;2;248;248;242m [0m[38;2;166;226;46mother_key[0m[38;2;248;248;242m:[0m[38;2;248;248;242m( [0m[38;2;248;248;242m[ [0m[38;2;248;248;242m[][0m[38;2;248;248;242m [0m[38;2;248;248;242m[[0m[38;2;248;248;242m[][0m[38;2;248;248;242m ][0m[38;2;248;248;242m [0m[38;2;248;248;240m)[0m[38;2;248;248;242m, gaga [0m[38;2;248;248;240m}[0m[38;2;248;248;242m ] )[0m
|
||||
[38;2;248;248;242m [0m[38;2;248;248;242m([0m[38;2;248;248;242m [0m[38;2;248;248;242m[[0m[38;2;248;248;242m [0m[38;2;248;248;242m{[0m[38;2;248;248;242m [0m[38;2;166;226;46mkey[0m[38;2;248;248;242m:[0m[38;2;248;248;242m [0m[38;2;248;248;242m([0m[38;2;248;248;242m)[0m[38;2;248;248;242m [0m[38;2;248;248;242m,[0m[38;2;248;248;242m [0m[38;2;166;226;46mother_key[0m[38;2;248;248;242m:[0m[38;2;248;248;242m([0m[38;2;248;248;242m [0m[38;2;248;248;242m[[0m[38;2;248;248;242m [0m[38;2;248;248;242m[[0m[38;2;248;248;242m][0m[38;2;248;248;242m [0m[38;2;248;248;242m[[0m[38;2;248;248;242m[[0m[38;2;248;248;242m][0m[38;2;248;248;242m [0m[38;2;248;248;242m][0m[38;2;248;248;242m [0m[38;2;248;248;240m)[0m[38;2;248;248;242m, gaga [0m[38;2;248;248;240m}[0m[38;2;248;248;242m ] )[0m
|
||||
|
||||
[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;230;219;116mA string[0m[38;2;190;132;255m\[0m[38;2;190;132;255mn[0m[38;2;230;219;116m whith escaped characters [0m[38;2;190;132;255m\[0m[38;2;190;132;255m"[0m[38;2;230;219;116m because we can[0m[38;2;230;219;116m"[0m
|
||||
[38;2;248;248;242m)[0m
|
||||
|
61
tests/syntax-tests/highlighted/NSIS/test.nsi
vendored
Normal file
61
tests/syntax-tests/highlighted/NSIS/test.nsi
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
[38;2;117;113;94m/*[0m
|
||||
[38;2;117;113;94m * Multi-line[0m
|
||||
[38;2;117;113;94m * Comment[0m
|
||||
[38;2;117;113;94m [0m[38;2;117;113;94m*/[0m
|
||||
|
||||
[38;2;117;113;94m#[0m[38;2;117;113;94m Single-line comment[0m
|
||||
[38;2;117;113;94m;[0m[38;2;117;113;94m Another-single line comment[0m
|
||||
|
||||
[38;2;117;113;94m;[0m[38;2;117;113;94m Includes[0m
|
||||
[38;2;249;38;114m!include[0m[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;230;219;116mLogicLib.nsh[0m[38;2;230;219;116m"[0m
|
||||
|
||||
[38;2;117;113;94m;[0m[38;2;117;113;94m Defines[0m
|
||||
[38;2;249;38;114m!define[0m[38;2;248;248;242m ARCHITECTURE [0m[38;2;230;219;116m"[0m[38;2;230;219;116mx64[0m[38;2;230;219;116m"[0m
|
||||
|
||||
[38;2;117;113;94m;[0m[38;2;117;113;94m Compile time command[0m
|
||||
[38;2;249;38;114m!echo[0m[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;230;219;116mBuilding [0m[38;2;190;132;255m${ARCHITECTURE}[0m[38;2;230;219;116m script[0m[38;2;230;219;116m"[0m
|
||||
|
||||
[38;2;117;113;94m;[0m[38;2;117;113;94m Macro definition[0m
|
||||
[38;2;249;38;114m!macro[0m[38;2;248;248;242m SayHello name[0m
|
||||
[38;2;249;38;114m !ifdef[0m[38;2;248;248;242m name[0m
|
||||
[38;2;249;38;114m !echo[0m[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;230;219;116mHello, [0m[38;2;190;132;255m${name}[0m[38;2;230;219;116m"[0m
|
||||
[38;2;249;38;114m !else[0m
|
||||
[38;2;249;38;114m !echo[0m[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;230;219;116mHello, world[0m[38;2;230;219;116m"[0m
|
||||
[38;2;249;38;114m !endif[0m
|
||||
[38;2;249;38;114m!macroend[0m
|
||||
|
||||
[38;2;117;113;94m;[0m[38;2;117;113;94m Macro usage[0m
|
||||
[38;2;249;38;114m!insertmacro[0m[38;2;248;248;242m SayHello [0m[38;2;230;219;116m"[0m[38;2;230;219;116mJohn Doe[0m[38;2;230;219;116m"[0m
|
||||
|
||||
[38;2;117;113;94m;[0m[38;2;117;113;94m Settings[0m
|
||||
[38;2;249;38;114mName[0m[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;230;219;116minstaller_name[0m[38;2;230;219;116m"[0m
|
||||
[38;2;249;38;114mOutFile[0m[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;230;219;116minstaller_name.exe[0m[38;2;230;219;116m"[0m
|
||||
[38;2;249;38;114mRequestExecutionLevel[0m[38;2;248;248;242m [0m[38;2;166;226;46muser[0m
|
||||
[38;2;249;38;114mCRCCheck[0m[38;2;248;248;242m [0m[38;2;190;132;255mon[0m
|
||||
[38;2;249;38;114mUnicode[0m[38;2;248;248;242m [0m[38;2;190;132;255mtrue[0m
|
||||
|
||||
[38;2;249;38;114m!ifdef[0m[38;2;248;248;242m [0m[38;2;190;132;255m${ARCHITECTURE}[0m
|
||||
[38;2;249;38;114m InstallDir[0m[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;255;255;255m$PROGRAMFILES64[0m[38;2;230;219;116m\installer_name[0m[38;2;230;219;116m"[0m
|
||||
[38;2;249;38;114m!else[0m
|
||||
[38;2;249;38;114m InstallDir[0m[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;255;255;255m$PROGRAMFILES[0m[38;2;230;219;116m\installer_name[0m[38;2;230;219;116m"[0m
|
||||
[38;2;249;38;114m!endif[0m
|
||||
|
||||
[38;2;117;113;94m;[0m[38;2;117;113;94m Pages[0m
|
||||
[38;2;249;38;114mPage[0m[38;2;248;248;242m [0m[38;2;166;226;46mcomponents[0m
|
||||
[38;2;249;38;114mPage[0m[38;2;248;248;242m [0m[38;2;166;226;46minstfiles[0m
|
||||
|
||||
[38;2;117;113;94m;[0m[38;2;117;113;94m Functions[0m
|
||||
[38;2;166;226;46mFunction[0m[38;2;248;248;242m PrintTestStrings[0m
|
||||
[38;2;249;38;114m DetailPrint[0m[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;230;219;116mThe install button reads [0m[38;2;255;255;255m$(^InstallBtn)[0m[38;2;230;219;116m"[0m
|
||||
[38;2;249;38;114m DetailPrint[0m[38;2;248;248;242m [0m[38;2;230;219;116m'[0m[38;2;230;219;116mHere comes a[0m[38;2;190;132;255m$\n[0m[38;2;190;132;255m$\r[0m[38;2;230;219;116mline-break![0m[38;2;230;219;116m'[0m
|
||||
[38;2;249;38;114m DetailPrint[0m[38;2;248;248;242m [0m[38;2;230;219;116m`[0m[38;2;230;219;116mEscape the dollar-sign: [0m[38;2;190;132;255m$$[0m[38;2;230;219;116m`[0m
|
||||
[38;2;166;226;46mFunctionEnd[0m
|
||||
|
||||
[38;2;117;113;94m;[0m[38;2;117;113;94m Sections[0m
|
||||
[38;2;166;226;46mSection[0m[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;230;219;116msection_name[0m[38;2;230;219;116m"[0m[38;2;248;248;242m section_index[0m
|
||||
[38;2;249;38;114m Call[0m[38;2;248;248;242m PrintTestStrings [0m
|
||||
|
||||
[38;2;248;248;242m [0m[38;2;117;113;94m;[0m[38;2;117;113;94m NSIS plugin call[0m
|
||||
[3;38;2;166;226;46m nsExec::ExecToLog[0m[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;230;219;116mcalc.exe[0m[38;2;230;219;116m"[0m
|
||||
[38;2;166;226;46mSectionEnd[0m
|
||||
|
@@ -1,36 +1,36 @@
|
||||
[38;2;166;226;46m␀[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;117;113;94m\u{1}[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;117;113;94m\u{2}[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;117;113;94m\u{3}[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;117;113;94m\u{4}[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;117;113;94m\u{5}[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;117;113;94m\u{6}[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;248;248;242m␁[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;248;248;242m␂[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;248;248;242m␃[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;248;248;242m␄[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;248;248;242m␅[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;248;248;242m␆[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;166;226;46m␇[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;166;226;46m␈[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;190;132;255m├──┤[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;249;38;114m␊[0m
|
||||
[38;2;249;38;114m␊[0m
|
||||
[38;2;117;113;94m\u{b}[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;117;113;94m\u{c}[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;248;248;242m␋[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;248;248;242m␌[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;249;38;114m␊[0m
|
||||
[38;2;117;113;94m\u{e}[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;117;113;94m\u{f}[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;117;113;94m\u{10}[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;117;113;94m\u{11}[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;117;113;94m\u{12}[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;117;113;94m\u{13}[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;117;113;94m\u{14}[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;117;113;94m\u{15}[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;117;113;94m\u{16}[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;117;113;94m\u{17}[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;117;113;94m\u{18}[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;117;113;94m\u{19}[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;117;113;94m\u{1a}[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;248;248;242m␎[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;248;248;242m␏[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;248;248;242m␐[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;248;248;242m␑[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;248;248;242m␒[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;248;248;242m␓[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;248;248;242m␔[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;248;248;242m␕[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;248;248;242m␖[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;248;248;242m␗[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;248;248;242m␘[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;248;248;242m␙[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;248;248;242m␚[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;166;226;46m␛[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;117;113;94m\u{1c}[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;117;113;94m\u{1d}[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;117;113;94m\u{1e}[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;117;113;94m\u{1f}[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;248;248;242m␜[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;248;248;242m␝[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;248;248;242m␞[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;248;248;242m␟[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;102;217;239m·[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;248;248;242m![0m[38;2;249;38;114m␊[0m
|
||||
[38;2;248;248;242m"[0m[38;2;249;38;114m␊[0m
|
||||
@@ -126,7 +126,7 @@
|
||||
[38;2;248;248;242m|[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;248;248;242m}[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;248;248;242m~[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;117;113;94m\u{7f}[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;248;248;242m␡[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;117;113;94m\u{80}[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;117;113;94m\u{81}[0m[38;2;249;38;114m␊[0m
|
||||
[38;2;117;113;94m\u{82}[0m[38;2;249;38;114m␊[0m
|
||||
|
@@ -1,5 +1,8 @@
|
||||
[38;2;117;113;94m#[0m[38;2;117;113;94m A comment[0m
|
||||
|
||||
[38;2;249;38;114mIdentityFile[0m[38;2;248;248;242m [0m[38;2;230;219;116m"[0m[38;2;230;219;116mcustom/id_ed25519[0m[38;2;230;219;116m"[0m
|
||||
[38;2;249;38;114mPort[0m[38;2;248;248;242m [0m[38;2;190;132;255m1984[0m
|
||||
|
||||
[38;2;249;38;114mHost[0m[38;2;248;248;242m [0m[38;2;166;226;46mexample.com[0m
|
||||
[38;2;248;248;242m [0m[38;2;249;38;114mUser[0m[38;2;248;248;242m [0m[38;2;230;219;116md[0m[38;2;230;219;116mummy[0m
|
||||
[38;2;248;248;242m [0m[38;2;249;38;114mCompression[0m[38;2;248;248;242m [0m[38;2;190;132;255mno[0m
|
||||
|
20
tests/syntax-tests/highlighted/WGSL/test.wgsl
vendored
Normal file
20
tests/syntax-tests/highlighted/WGSL/test.wgsl
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
[3;38;2;102;217;239mstruct[0m[38;2;248;248;242m [0m[38;2;166;226;46mVertexOut[0m[38;2;248;248;242m [0m[38;2;248;248;242m{[0m
|
||||
[38;2;248;248;242m [0m[38;2;249;38;114m@[0m[38;2;166;226;46mbuiltin[0m[38;2;248;248;242m([0m[38;2;255;255;255mposition[0m[38;2;248;248;242m)[0m[38;2;248;248;242m [0m[38;2;255;255;255mposition[0m[38;2;248;248;242m : [0m[3;38;2;102;217;239mvec4f[0m[38;2;248;248;242m,[0m
|
||||
[38;2;248;248;242m [0m[38;2;249;38;114m@[0m[38;2;166;226;46mlocation[0m[38;2;248;248;242m([0m[38;2;190;132;255m0[0m[38;2;248;248;242m)[0m[38;2;248;248;242m [0m[38;2;255;255;255mcolor[0m[38;2;248;248;242m : [0m[3;38;2;102;217;239mvec4f[0m
|
||||
[38;2;248;248;242m}[0m
|
||||
|
||||
[38;2;249;38;114m@[0m[38;2;166;226;46mvertex[0m
|
||||
[38;2;249;38;114mfn[0m[38;2;248;248;242m [0m[38;2;166;226;46mvertex_main[0m[38;2;248;248;242m([0m[38;2;249;38;114m@[0m[38;2;166;226;46mlocation[0m[38;2;248;248;242m([0m[38;2;190;132;255m0[0m[38;2;248;248;242m)[0m[38;2;248;248;242m [0m[38;2;255;255;255mposition[0m[38;2;248;248;242m: [0m[3;38;2;102;217;239mvec4f[0m[38;2;248;248;242m,[0m
|
||||
[38;2;248;248;242m [0m[38;2;249;38;114m@[0m[38;2;166;226;46mlocation[0m[38;2;248;248;242m([0m[38;2;190;132;255m1[0m[38;2;248;248;242m)[0m[38;2;248;248;242m [0m[38;2;255;255;255mcolor[0m[38;2;248;248;242m: [0m[3;38;2;102;217;239mvec4f[0m[38;2;248;248;242m)[0m[38;2;248;248;242m [0m[38;2;249;38;114m->[0m[38;2;248;248;242m [0m[38;2;166;226;46mVertexOut[0m
|
||||
[38;2;248;248;242m{[0m
|
||||
[38;2;248;248;242m [0m[3;38;2;102;217;239mvar[0m[38;2;248;248;242m [0m[38;2;255;255;255moutput[0m[38;2;248;248;242m : [0m[38;2;166;226;46mVertexOut[0m[38;2;248;248;242m;[0m
|
||||
[38;2;248;248;242m [0m[38;2;255;255;255moutput[0m[38;2;249;38;114m.[0m[38;2;248;248;242mposition [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[38;2;255;255;255mposition[0m[38;2;248;248;242m;[0m
|
||||
[38;2;248;248;242m [0m[38;2;255;255;255moutput[0m[38;2;249;38;114m.[0m[38;2;248;248;242mcolor [0m[38;2;249;38;114m=[0m[38;2;248;248;242m [0m[38;2;255;255;255mcolor[0m[38;2;248;248;242m;[0m
|
||||
[38;2;248;248;242m [0m[38;2;249;38;114mreturn[0m[38;2;248;248;242m [0m[38;2;255;255;255moutput[0m[38;2;248;248;242m;[0m
|
||||
[38;2;248;248;242m}[0m
|
||||
|
||||
[38;2;249;38;114m@[0m[38;2;166;226;46mfragment[0m
|
||||
[38;2;249;38;114mfn[0m[38;2;248;248;242m [0m[38;2;166;226;46mfragment_main[0m[38;2;248;248;242m([0m[38;2;248;248;242mfragData: [0m[38;2;166;226;46mVertexOut[0m[38;2;248;248;242m)[0m[38;2;248;248;242m [0m[38;2;249;38;114m->[0m[38;2;248;248;242m [0m[38;2;249;38;114m@[0m[38;2;166;226;46mlocation[0m[38;2;248;248;242m([0m[38;2;190;132;255m0[0m[38;2;248;248;242m)[0m[38;2;248;248;242m [0m[3;38;2;102;217;239mvec4f[0m
|
||||
[38;2;248;248;242m{[0m
|
||||
[38;2;248;248;242m [0m[38;2;249;38;114mreturn[0m[38;2;248;248;242m fragData[0m[38;2;249;38;114m.[0m[38;2;248;248;242mcolor[0m[38;2;248;248;242m;[0m
|
||||
[38;2;248;248;242m}[0m
|
@@ -4,8 +4,8 @@
|
||||
[38;2;248;248;242mUse '--help' instead of '-h' to see a more detailed version of the help text.[0m
|
||||
|
||||
[38;2;246;170;17mUSAGE:[0m
|
||||
[38;2;248;248;242m bat [OPTIONS] [FILE]...[0m
|
||||
[38;2;248;248;242m bat <SUBCOMMAND>[0m
|
||||
[38;2;248;248;242m [0m[38;2;190;132;255mbat[0m[38;2;248;248;242m [OPTIONS] [FILE]...[0m
|
||||
[38;2;248;248;242m [0m[38;2;190;132;255mbat[0m[38;2;248;248;242m <SUBCOMMAND>[0m
|
||||
|
||||
[38;2;246;170;17mARGS:[0m
|
||||
[38;2;248;248;242m [0m[38;2;249;38;114m<FILE>...[0m[38;2;248;248;242m File(s) to print / concatenate. Use '-' for standard input.[0m
|
||||
|
61
tests/syntax-tests/source/NSIS/test.nsi
vendored
Normal file
61
tests/syntax-tests/source/NSIS/test.nsi
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Multi-line
|
||||
* Comment
|
||||
*/
|
||||
|
||||
# Single-line comment
|
||||
; Another-single line comment
|
||||
|
||||
; Includes
|
||||
!include "LogicLib.nsh"
|
||||
|
||||
; Defines
|
||||
!define ARCHITECTURE "x64"
|
||||
|
||||
; Compile time command
|
||||
!echo "Building ${ARCHITECTURE} script"
|
||||
|
||||
; Macro definition
|
||||
!macro SayHello name
|
||||
!ifdef name
|
||||
!echo "Hello, ${name}"
|
||||
!else
|
||||
!echo "Hello, world"
|
||||
!endif
|
||||
!macroend
|
||||
|
||||
; Macro usage
|
||||
!insertmacro SayHello "John Doe"
|
||||
|
||||
; Settings
|
||||
Name "installer_name"
|
||||
OutFile "installer_name.exe"
|
||||
RequestExecutionLevel user
|
||||
CRCCheck on
|
||||
Unicode true
|
||||
|
||||
!ifdef ${ARCHITECTURE}
|
||||
InstallDir "$PROGRAMFILES64\installer_name"
|
||||
!else
|
||||
InstallDir "$PROGRAMFILES\installer_name"
|
||||
!endif
|
||||
|
||||
; Pages
|
||||
Page components
|
||||
Page instfiles
|
||||
|
||||
; Functions
|
||||
Function PrintTestStrings
|
||||
DetailPrint "The install button reads $(^InstallBtn)"
|
||||
DetailPrint 'Here comes a$\n$\rline-break!'
|
||||
DetailPrint `Escape the dollar-sign: $$`
|
||||
FunctionEnd
|
||||
|
||||
; Sections
|
||||
Section "section_name" section_index
|
||||
Call PrintTestStrings
|
||||
|
||||
; NSIS plugin call
|
||||
nsExec::ExecToLog "calc.exe"
|
||||
SectionEnd
|
||||
|
@@ -1,5 +1,8 @@
|
||||
# A comment
|
||||
|
||||
IdentityFile "custom/id_ed25519"
|
||||
Port 1984
|
||||
|
||||
Host example.com
|
||||
User dummy
|
||||
Compression no
|
||||
|
5
tests/syntax-tests/source/WGSL/LICENSE.md
vendored
Normal file
5
tests/syntax-tests/source/WGSL/LICENSE.md
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
The `test.wgsl` file has been added from https://developer.mozilla.org/en-US/docs/Web/API/WebGPU_API under the following license:
|
||||
|
||||
```
|
||||
Any copyright is dedicated to the Public Domain: https://creativecommons.org/publicdomain/zero/1.0/
|
||||
```
|
20
tests/syntax-tests/source/WGSL/test.wgsl
vendored
Normal file
20
tests/syntax-tests/source/WGSL/test.wgsl
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
struct VertexOut {
|
||||
@builtin(position) position : vec4f,
|
||||
@location(0) color : vec4f
|
||||
}
|
||||
|
||||
@vertex
|
||||
fn vertex_main(@location(0) position: vec4f,
|
||||
@location(1) color: vec4f) -> VertexOut
|
||||
{
|
||||
var output : VertexOut;
|
||||
output.position = position;
|
||||
output.color = color;
|
||||
return output;
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fragment_main(fragData: VertexOut) -> @location(0) vec4f
|
||||
{
|
||||
return fragData.color;
|
||||
}
|
@@ -17,6 +17,9 @@ pub fn bat_raw_command_with_config() -> Command {
|
||||
cmd.env_remove("COLORTERM");
|
||||
cmd.env_remove("NO_COLOR");
|
||||
cmd.env_remove("PAGER");
|
||||
cmd.env_remove("LESSOPEN");
|
||||
cmd.env_remove("LESSCLOSE");
|
||||
cmd.env_remove("SHELL");
|
||||
cmd
|
||||
}
|
||||
|
||||
|
@@ -17,11 +17,16 @@ fn get_mocked_pagers_dir() -> PathBuf {
|
||||
/// On Unix: 'most' -> 'most'
|
||||
/// On Windows: 'most' -> 'most.bat'
|
||||
pub fn from(base: &str) -> String {
|
||||
if cfg!(windows) {
|
||||
format!("{}.bat", base)
|
||||
} else {
|
||||
String::from(base)
|
||||
let mut cmd_and_args = shell_words::split(base).unwrap();
|
||||
let suffix = if cfg!(windows) { ".bat" } else { "" };
|
||||
let mut out_cmd = format!("{}{}", cmd_and_args.first().unwrap(), suffix);
|
||||
|
||||
if (cmd_and_args.len() > 1) {
|
||||
out_cmd.push(' ');
|
||||
out_cmd.push_str(cmd_and_args[1..].to_vec().join(" ").as_str());
|
||||
}
|
||||
|
||||
out_cmd
|
||||
}
|
||||
|
||||
/// Prepends a directory to the PATH environment variable
|
||||
@@ -62,6 +67,11 @@ pub fn with_mocked_versions_of_more_and_most_in_path(actual_test: fn()) {
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("I am most"));
|
||||
Command::new(from("echo"))
|
||||
.arg("foobar")
|
||||
.assert()
|
||||
.success()
|
||||
.stdout(predicate::str::contains("foobar"));
|
||||
|
||||
// Now run the actual test
|
||||
actual_test();
|
||||
|
Reference in New Issue
Block a user