mirror of
https://github.com/eth-p/bat-extras.git
synced 2026-09-10 07:16:25 -04:00
Compare commits
253 commits
v2020.04.0
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3860f0f148 | ||
|
|
58e7f52717 | ||
|
|
86fd93e47e | ||
|
|
a0d3a9bd63 | ||
|
|
b977dffc54 | ||
|
|
36c77c171c | ||
|
|
6092fa5bad | ||
|
|
1cffc910d5 | ||
|
|
47cfb9ec73 | ||
|
|
32706dd581 | ||
|
|
01c2f9bb94 | ||
|
|
0acf65edde | ||
|
|
92dcb78765 | ||
|
|
ac4f8710ba | ||
|
|
aef5a424b4 | ||
|
|
3b3a8923a1 | ||
|
|
eb7ad6b21b | ||
|
|
f5b8cfb5d7 | ||
|
|
38bacab368 | ||
|
|
043d2da964 | ||
|
|
75c757817f | ||
|
|
c9e917e43a | ||
|
|
6c8879f1d7 | ||
|
|
6bd35e5aed | ||
|
|
205e9c40e1 | ||
|
|
5011f0709e | ||
|
|
82911b5b7b | ||
|
|
a427f6eeda | ||
|
|
8460b39956 | ||
|
|
3f259f1a07 | ||
|
|
bc534e9dd2 | ||
|
|
a686d6742c | ||
|
|
d5ea485a0b | ||
|
|
c4b2a12f73 | ||
|
|
f192b7a7d8 | ||
|
|
c29dfb136a | ||
|
|
2e1e768559 | ||
|
|
4039859b62 | ||
|
|
6f579b1d45 | ||
|
|
c26f22c768 | ||
|
|
895b4ee0ce | ||
|
|
ba984f470e | ||
|
|
162c21d012 | ||
|
|
d96fc92165 | ||
|
|
85aaf4875d | ||
|
|
4c220a84a3 | ||
|
|
ceaac1b917 | ||
|
|
03549d651a | ||
|
|
f47d9c4138 | ||
|
|
762ac557f4 | ||
|
|
15876936ed | ||
|
|
94fbeb5b27 | ||
|
|
d0738b7289 | ||
|
|
48fe8875f7 | ||
|
|
5ac224bc87 | ||
|
|
974073fc72 | ||
|
|
7aa73f8989 | ||
|
|
7107e1603f | ||
|
|
3e7041da7b | ||
|
|
14f36f51b7 | ||
|
|
e609d1a2c5 | ||
|
|
daf888f5ed | ||
|
|
bea36be397 | ||
|
|
673dc6fd75 | ||
|
|
97006f0f09 | ||
|
|
287398acbc | ||
|
|
e53db161a7 | ||
|
|
f07a22d536 | ||
|
|
ea604457ea | ||
|
|
998e2ff1a9 | ||
|
|
26111f9cee | ||
|
|
76906ca014 | ||
|
|
428a78837d | ||
|
|
36786ba570 | ||
|
|
e9daffde45 | ||
|
|
3917100c6e | ||
|
|
a4237efffd | ||
|
|
38014ba72d | ||
|
|
3e2e8df594 | ||
|
|
abda988cbd | ||
|
|
49f27efea2 | ||
|
|
2f2b33391a | ||
|
|
90bb604d74 | ||
|
|
ad2d788d6c | ||
|
|
10d976da55 | ||
|
|
62b8f74df2 | ||
|
|
a011290c2f | ||
|
|
20cc74e8b4 | ||
|
|
33c2c195dc | ||
|
|
462df32d4c | ||
|
|
69792e95da | ||
|
|
8ad00bd978 | ||
|
|
7803ecaba1 | ||
|
|
d8532bb35a | ||
|
|
ef0356a2d8 | ||
|
|
33e0c168e0 | ||
|
|
82ac5c4391 | ||
|
|
f280553fb1 | ||
|
|
d989b0bfde | ||
|
|
20cdf5a998 | ||
|
|
75d66fa352 | ||
|
|
a4a5f5a5fd | ||
|
|
4f0b961d12 | ||
|
|
cae57be87b | ||
|
|
a526c7927b | ||
|
|
eee3156e8a | ||
|
|
e1a0c7a349 | ||
|
|
08d2896b1a | ||
|
|
54db67408e | ||
|
|
860638715a | ||
|
|
6497bc04a0 | ||
|
|
672b4814ec | ||
|
|
2aff613888 | ||
|
|
82b444f93b | ||
|
|
94bb4b6a86 | ||
|
|
650845dee4 | ||
|
|
e4e916c63b | ||
|
|
27c68692f1 | ||
|
|
70c7509343 | ||
|
|
164142dd43 | ||
|
|
e16e05d1d4 | ||
|
|
93e2e4d048 | ||
|
|
47152d69c3 | ||
|
|
9efc5362df | ||
|
|
87525fca91 | ||
|
|
c538eadf77 | ||
|
|
bd7cb3ea9e | ||
|
|
0cefe6efe1 | ||
|
|
fa311d5119 | ||
|
|
5f88acd1f4 | ||
|
|
cfd8d29c7b | ||
|
|
e98b4efb51 | ||
|
|
dccceaf749 | ||
|
|
5f5a5e87a9 | ||
|
|
af9709452f | ||
|
|
08455b0cb8 | ||
|
|
8c11b24bef | ||
|
|
5708706436 | ||
|
|
2b2db2b506 | ||
|
|
d429af07ed | ||
|
|
98e1f2f054 | ||
|
|
dafd2addc0 | ||
|
|
0d2e999b2a | ||
|
|
988780bce9 | ||
|
|
9072ab47a1 | ||
|
|
1734cedbd9 | ||
|
|
2a28cbff3a | ||
|
|
fa32c5875d | ||
|
|
55eaf189dc | ||
|
|
c5e7f5f185 | ||
|
|
652c3e5c3b | ||
|
|
b85c7c43e3 | ||
|
|
dd07f98367 | ||
|
|
d8e7cd1d1b | ||
|
|
b275282e36 | ||
|
|
165fc69d34 | ||
|
|
eb69d61ff8 | ||
|
|
0d9468e1cf | ||
|
|
7549ffd986 | ||
|
|
65a2f7561e | ||
|
|
bb94b33353 | ||
|
|
0f6529a0d8 | ||
|
|
4761b594a6 | ||
|
|
a6a1e55522 | ||
|
|
40a66d934d | ||
|
|
de60ea0c10 | ||
|
|
b5cb20cb23 | ||
|
|
0df5cffb84 | ||
|
|
6b6016dad4 | ||
|
|
01a6e9cf15 | ||
|
|
7d2d861d7d | ||
|
|
5fc43a2d8c | ||
|
|
644c817ba2 | ||
|
|
655038878b | ||
|
|
cc8b70055e | ||
|
|
9d356b8bc4 | ||
|
|
3c5651bde9 | ||
|
|
1f7d9c3fcc | ||
|
|
da24c59751 | ||
|
|
1fff0bcc51 | ||
|
|
5f5023d056 | ||
|
|
dc50f28480 | ||
|
|
0494e41e66 | ||
|
|
fa58888298 | ||
|
|
df5b237273 | ||
|
|
e4999a7ffb | ||
|
|
38f56c1bc7 | ||
|
|
69d9c38326 | ||
|
|
990a1dc397 | ||
|
|
57be774f88 | ||
|
|
4c09718a46 | ||
|
|
149f47fa66 | ||
|
|
6052d6ee17 | ||
|
|
3029b6749f | ||
|
|
da93f2f87f | ||
|
|
9f6e5c0164 | ||
|
|
85c4cfbfe8 | ||
|
|
5fbf8adf41 | ||
|
|
43ddb984f5 | ||
|
|
f20a3ff9b8 | ||
|
|
c9f3125002 | ||
|
|
840d339c97 | ||
|
|
e250ad9b29 | ||
|
|
f9b18f7e8e | ||
|
|
875504ba06 | ||
|
|
529eb60498 | ||
|
|
a3c4fa1014 | ||
|
|
5af706fc7c | ||
|
|
63101805be | ||
|
|
c98e21df04 | ||
|
|
427baf1491 | ||
|
|
bdc2e6ea01 | ||
|
|
e7a394a154 | ||
|
|
d6db998042 | ||
|
|
360c5b819c | ||
|
|
fb9730001f | ||
|
|
f9bdcc9494 | ||
|
|
20a0058014 | ||
|
|
d29915f141 | ||
|
|
d5fa65132d | ||
|
|
50e9cd8caa | ||
|
|
275c66b213 | ||
|
|
29fb251348 | ||
|
|
7dc1c509fb | ||
|
|
19f49bb5ee | ||
|
|
57b129e1f7 | ||
|
|
820eae1e9d | ||
|
|
309a2169ba | ||
|
|
e4d790ca91 | ||
|
|
4ee7451532 | ||
|
|
9f983891fd | ||
|
|
bad5ab13a2 | ||
|
|
d81456872b | ||
|
|
a31b322272 | ||
|
|
8524f873fb | ||
|
|
2cc263f85c | ||
|
|
b0a2ca70ba | ||
|
|
7a75c55a34 | ||
|
|
76afe39c96 | ||
|
|
7754406d54 | ||
|
|
af98cf5246 | ||
|
|
91860968f0 | ||
|
|
b2bc772ad1 | ||
|
|
ab0f1b96d6 | ||
|
|
0d73f2abd5 | ||
|
|
865c8b252b | ||
|
|
e8baf911d1 | ||
|
|
e79e747e71 | ||
|
|
7fa1faf7bf | ||
|
|
9a92579100 | ||
|
|
c5927f72af | ||
|
|
9c489732e6 | ||
|
|
47cf670943 |
|
|
@ -1,98 +0,0 @@
|
|||
version: 2.1
|
||||
|
||||
executors:
|
||||
linux_alpine:
|
||||
docker:
|
||||
- image: alpine:latest
|
||||
environment:
|
||||
TERM: xterm
|
||||
|
||||
commands:
|
||||
setup:
|
||||
description: "Set up the environment needed to test and run the scripts."
|
||||
steps:
|
||||
- run:
|
||||
name: "APK: Add repository."
|
||||
command: |
|
||||
printf "\n%s\n" "http://nl.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories
|
||||
printf "\n%s\n" "http://nl.alpinelinux.org/alpine/edge/community" >> /etc/apk/repositories
|
||||
- run:
|
||||
name: "APK: Update cache."
|
||||
command: apk update
|
||||
- run:
|
||||
name: "Setup: Install build packages."
|
||||
command: apk add git bash python2 diffutils ca-certificates curl shfmt
|
||||
- run:
|
||||
name: "Setup: Install test packages."
|
||||
command: apk add util-linux coreutils
|
||||
- run:
|
||||
name: "Setup: Install runtime packages."
|
||||
command: apk add bat ripgrep ncurses
|
||||
|
||||
build:
|
||||
description: "Build the self-contained scripts."
|
||||
parameters:
|
||||
minify:
|
||||
type: string
|
||||
default: "lib"
|
||||
steps:
|
||||
- run:
|
||||
name: "Build"
|
||||
command: ./build.sh --minify=<<parameters.minify>> --no-verify
|
||||
|
||||
jobs:
|
||||
build:
|
||||
executor: linux_alpine
|
||||
steps:
|
||||
- setup
|
||||
- checkout
|
||||
- build:
|
||||
minify: "all"
|
||||
- store_artifacts:
|
||||
path: bin
|
||||
|
||||
test:
|
||||
executor: linux_alpine
|
||||
steps:
|
||||
- setup
|
||||
- checkout
|
||||
- build:
|
||||
minify: "all"
|
||||
- run:
|
||||
name: "Test: Unit Tests / Snapshots"
|
||||
command: ./test.sh --verbose --strict --snapshot:show
|
||||
|
||||
test-consistency:
|
||||
executor: linux_alpine
|
||||
steps:
|
||||
- setup
|
||||
- checkout
|
||||
- build:
|
||||
minify: "all"
|
||||
- run:
|
||||
name: "Test: Consistency"
|
||||
command: ./test.sh --compiled --verbose --snapshot:show
|
||||
|
||||
test-symlink:
|
||||
executor: linux_alpine
|
||||
steps:
|
||||
- setup
|
||||
- checkout
|
||||
- run:
|
||||
name: "Symlink"
|
||||
command: ln -s "$PWD/src/batgrep.sh" /tmp/batgrep
|
||||
- run:
|
||||
name: "Test: Symlink"
|
||||
command: /tmp/batgrep 'a' >/dev/null
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
default:
|
||||
jobs:
|
||||
- build
|
||||
- test:
|
||||
requires: [build]
|
||||
- test-consistency:
|
||||
requires: [build, test]
|
||||
- test-symlink:
|
||||
requires: [build]
|
||||
54
.github/actions/build/action.yaml
vendored
Normal file
54
.github/actions/build/action.yaml
vendored
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
name: 'Build'
|
||||
description: 'Builds bat-extras'
|
||||
inputs:
|
||||
manuals:
|
||||
description: 'Builds manuals'
|
||||
required: false
|
||||
default: true
|
||||
inline:
|
||||
description: 'Inlines executable names in script'
|
||||
required: false
|
||||
default: true
|
||||
verify:
|
||||
description: 'Verifies after building'
|
||||
required: false
|
||||
default: false
|
||||
minify:
|
||||
description: 'Minification mode (none, all, lib)'
|
||||
required: false
|
||||
default: 'none'
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
|
||||
- name: Run build script
|
||||
shell: bash
|
||||
run: |
|
||||
args=(
|
||||
--banner
|
||||
--minify="${{ inputs.minify }}"
|
||||
)
|
||||
|
||||
if "${{ inputs.manuals }}"; then
|
||||
args+=(--manuals)
|
||||
else
|
||||
args+=(--no-manuals)
|
||||
fi
|
||||
|
||||
if "${{ inputs.verify }}"; then
|
||||
args+=(--verify)
|
||||
else
|
||||
args+=(--no-verify)
|
||||
fi
|
||||
|
||||
if "${{ inputs.inline }}"; then
|
||||
args+=(--inline)
|
||||
else
|
||||
args+=(--no-inline)
|
||||
fi
|
||||
|
||||
# Run the build script.
|
||||
cd "${{ github.workspace }}"
|
||||
PATH="${{ runner.temp }}/bin:${PATH}"
|
||||
bash "${{ github.workspace }}/build.sh" "${args[@]}"
|
||||
31
.github/actions/build/create-release-notes.sh
vendored
Normal file
31
.github/actions/build/create-release-notes.sh
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#!/usr/bin/env bash
|
||||
# -----------------------------------------------------------------------------
|
||||
# bat-extras | Copyright (C) 2019-2023 eth-p | MIT License
|
||||
#
|
||||
# Repository: https://github.com/eth-p/bat-extras
|
||||
# Issues: https://github.com/eth-p/bat-extras/issues
|
||||
# -----------------------------------------------------------------------------
|
||||
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_DIR="$GITHUB_WORKSPACE"
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Overrides from release.sh:
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
batextras:get_git_workspace() {
|
||||
printf "%s\n" "${GITHUB_WORKSPACE}"
|
||||
}
|
||||
|
||||
batextras:get_current_commit() {
|
||||
printf "%s\n" "${GITHUB_SHA:-$(git -C "$GITHUB_WORKSPACE" rev-parse HEAD)}"
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Generate changelog:
|
||||
# -----------------------------------------------------------------------------
|
||||
set -euo pipefail
|
||||
|
||||
source "${PROJECT_DIR}/release.sh"
|
||||
batextras:generate_release_notes \
|
||||
"$(batextras:get_previous_tag_commit)" \
|
||||
"$(batextras:get_current_commit)"
|
||||
31
.github/actions/build/create-zipball.sh
vendored
Normal file
31
.github/actions/build/create-zipball.sh
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#!/usr/bin/env bash
|
||||
# -----------------------------------------------------------------------------
|
||||
# bat-extras | Copyright (C) 2019-2023 eth-p | MIT License
|
||||
#
|
||||
# Repository: https://github.com/eth-p/bat-extras
|
||||
# Issues: https://github.com/eth-p/bat-extras/issues
|
||||
# -----------------------------------------------------------------------------
|
||||
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_DIR="$GITHUB_WORKSPACE"
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Overrides from release.sh:
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
batextras:get_git_workspace() {
|
||||
printf "%s\n" "${GITHUB_WORKSPACE}"
|
||||
}
|
||||
|
||||
batextras:get_current_commit() {
|
||||
printf "%s\n" "${GITHUB_SHA:-$(git -C "$GITHUB_WORKSPACE" rev-parse HEAD)}"
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Generate changelog:
|
||||
# -----------------------------------------------------------------------------
|
||||
set -euo pipefail
|
||||
source "${PROJECT_DIR}/release.sh"
|
||||
|
||||
zipball_name="bat-extras-$(batextras:get_version | sed 's/\.//')"
|
||||
zipball="${PROJECT_DIR}/${zipball_name}.zip"
|
||||
batextras:create_package "$zipball"
|
||||
92
.github/actions/install-dependencies/action.yaml
vendored
Normal file
92
.github/actions/install-dependencies/action.yaml
vendored
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
name: 'Install dependencies'
|
||||
description: 'Installs all the dependencies needed.'
|
||||
inputs:
|
||||
build:
|
||||
description: 'Install build dependencies.'
|
||||
required: false
|
||||
default: true
|
||||
test:
|
||||
description: 'Install test dependencies.'
|
||||
required: true
|
||||
default: false
|
||||
|
||||
version_bat:
|
||||
description: 'The version of bat to install.'
|
||||
required: false
|
||||
default: "latest"
|
||||
|
||||
version_ripgrep:
|
||||
description: 'The version of ripgrep to install.'
|
||||
required: false
|
||||
default: "latest"
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
|
||||
- name: Create directories
|
||||
shell: bash
|
||||
run: |
|
||||
test -d "${RUNNER_TEMP}/bin" || mkdir -p "${RUNNER_TEMP}/bin"
|
||||
test -d "${RUNNER_TEMP}/dl" || mkdir -p "${RUNNER_TEMP}/dl"
|
||||
|
||||
- name: Install shfmt (build dependency)
|
||||
shell: bash
|
||||
if: ${{ env.ACT || inputs.build == 'true' }}
|
||||
run: |
|
||||
curl \
|
||||
--silent \
|
||||
--location \
|
||||
--output "${RUNNER_TEMP}/bin/shfmt" \
|
||||
"https://github.com/patrickvane/shfmt/releases/download/master/shfmt_linux_amd64"
|
||||
chmod +x "${RUNNER_TEMP}/bin/shfmt"
|
||||
|
||||
- name: Download bat (test dependency)
|
||||
uses: dsaltares/fetch-gh-release-asset@master
|
||||
if: ${{ env.ACT || inputs.test == 'true' }}
|
||||
with:
|
||||
file: "bat-v[0-9\\.]+-x86_64-unknown-linux-gnu.tar.gz"
|
||||
repo: "sharkdp/bat"
|
||||
# version: "${{ inputs.version_bat || "latest" }}"
|
||||
regex: true
|
||||
target: ".dl/"
|
||||
|
||||
- name: Install bat
|
||||
shell: bash
|
||||
if: ${{ env.ACT || inputs.test == 'true' }}
|
||||
run: |
|
||||
tar -xf \
|
||||
"${{ github.workspace }}/.dl"/bat-*.tar.* \
|
||||
-C "${{ runner.temp }}/dl/"
|
||||
|
||||
find "${{ runner.temp }}/dl" \
|
||||
-type f -iname "bat" \
|
||||
-exec mv {} "${RUNNER_TEMP}/bin/" \;
|
||||
|
||||
- name: Download ripgrep (test dependency)
|
||||
uses: dsaltares/fetch-gh-release-asset@master
|
||||
if: ${{ env.ACT || inputs.test == 'true' }}
|
||||
with:
|
||||
file: "ripgrep_[0-9\\.-]+_amd64.deb"
|
||||
repo: "BurntSushi/ripgrep"
|
||||
# version: "${{ inputs.version_ripgrep || "latest" }}"
|
||||
regex: true
|
||||
target: ".dl/"
|
||||
|
||||
- name: Install ripgrep
|
||||
shell: bash
|
||||
if: ${{ env.ACT || inputs.test == 'true' }}
|
||||
run: |
|
||||
dpkg-deb -x \
|
||||
"${{ github.workspace }}/.dl"/ripgrep_*.deb \
|
||||
"${{ runner.temp }}/dl/"
|
||||
|
||||
find "${{ runner.temp }}/dl" \
|
||||
-type f -path "*/bin/rg" \
|
||||
-exec mv {} "${{ runner.temp }}/bin/" \;
|
||||
|
||||
- name: Set executable permissions
|
||||
shell: bash
|
||||
run: |
|
||||
chmod -R +x "${{ runner.temp }}/bin"
|
||||
|
||||
33
.github/actions/test/action.yaml
vendored
Normal file
33
.github/actions/test/action.yaml
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
name: 'Test'
|
||||
description: 'Tests bat-extras'
|
||||
inputs:
|
||||
strict:
|
||||
description: 'Tests should be run under strict mode'
|
||||
required: false
|
||||
default: false
|
||||
compiled:
|
||||
description: 'Test scripts that have been built'
|
||||
required: false
|
||||
default: false
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
|
||||
- name: Run tests
|
||||
shell: bash
|
||||
run: |
|
||||
args=()
|
||||
|
||||
if "${{ inputs.compiled }}"; then
|
||||
args+=(--compiled)
|
||||
fi
|
||||
|
||||
if "${{ inputs.strict }}"; then
|
||||
args+=(--strict)
|
||||
fi
|
||||
|
||||
cd "${{ github.workspace }}"
|
||||
PATH="${{ runner.temp }}/bin:${PATH}"
|
||||
bash "${{ github.workspace }}/test.sh" "${args[@]}" \
|
||||
--verbose --snapshot:show
|
||||
45
.github/workflows/release.yaml
vendored
Normal file
45
.github/workflows/release.yaml
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
name: Release
|
||||
on:
|
||||
push:
|
||||
tags: ['*']
|
||||
|
||||
jobs:
|
||||
"Release":
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out sources
|
||||
uses: actions/checkout@v3
|
||||
- name: Install build dependencies
|
||||
uses: ./.github/actions/install-dependencies
|
||||
with:
|
||||
build: true
|
||||
test: true
|
||||
|
||||
- name: Build
|
||||
uses: ./.github/actions/build
|
||||
with:
|
||||
minify: lib
|
||||
manuals: true
|
||||
verify: true
|
||||
inline: false
|
||||
|
||||
- name: Create zipball
|
||||
run: bash "${{ github.workspace }}/.github/actions/build/create-zipball.sh"
|
||||
|
||||
- name: Generate changelog
|
||||
id: changelog
|
||||
run: |
|
||||
output_file="release-notes.md"
|
||||
output_title="Release: $(date '+%Y-%m-%d')"
|
||||
|
||||
bash "${{ github.workspace }}/.github/actions/build/create-release-notes.sh" | tee "${output_file}"
|
||||
echo "file=${output_file}" >> "$GITHUB_OUTPUT"
|
||||
echo "title=${output_title}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Create release
|
||||
if: ${{ !env.ACT }}
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
artifacts: "bat-extras-*.zip"
|
||||
bodyFile: "${{steps.changelog.outputs.file}}"
|
||||
name: "${{steps.changelog.outputs.title}}"
|
||||
96
.github/workflows/test.yaml
vendored
Normal file
96
.github/workflows/test.yaml
vendored
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
name: Test
|
||||
on:
|
||||
push: {}
|
||||
pull_request:
|
||||
types: [opened, synchronize]
|
||||
|
||||
jobs:
|
||||
"Build":
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out sources
|
||||
uses: actions/checkout@v3
|
||||
- name: Install build dependencies
|
||||
uses: ./.github/actions/install-dependencies
|
||||
with:
|
||||
build: true
|
||||
test: false
|
||||
- name: Build artifacts
|
||||
uses: ./.github/actions/build
|
||||
with:
|
||||
minify: lib
|
||||
manuals: true
|
||||
verify: false
|
||||
inline: false
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
if: ${{ !env.ACT && !failure() }}
|
||||
with:
|
||||
path: |
|
||||
${{ github.workspace }}/bin/
|
||||
${{ github.workspace }}/doc/
|
||||
|
||||
"Test":
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out sources
|
||||
uses: actions/checkout@v3
|
||||
- name: Install test dependencies
|
||||
uses: ./.github/actions/install-dependencies
|
||||
with:
|
||||
build: false
|
||||
test: true
|
||||
- name: Test scripts
|
||||
uses: ./.github/actions/test
|
||||
|
||||
"Test_Consistency":
|
||||
runs-on: ubuntu-latest
|
||||
needs: "Test"
|
||||
steps:
|
||||
- name: Check out sources
|
||||
uses: actions/checkout@v3
|
||||
- name: Install dependencies
|
||||
uses: ./.github/actions/install-dependencies
|
||||
with:
|
||||
build: true
|
||||
test: true
|
||||
- name: Build scripts
|
||||
uses: ./.github/actions/build
|
||||
with:
|
||||
minify: lib
|
||||
manuals: false
|
||||
verify: false
|
||||
inline: false
|
||||
- name: Test built scripts
|
||||
uses: ./.github/actions/test
|
||||
with:
|
||||
compiled: true
|
||||
|
||||
"Test_Symlinks":
|
||||
runs-on: ubuntu-latest
|
||||
needs: "Test"
|
||||
env:
|
||||
BAT_PAGER: 'cat'
|
||||
steps:
|
||||
- name: Check out sources
|
||||
uses: actions/checkout@v3
|
||||
- name: Install dependencies
|
||||
uses: ./.github/actions/install-dependencies
|
||||
with:
|
||||
build: false
|
||||
test: true
|
||||
- name: Prepare symlinks
|
||||
run: |
|
||||
chmod +x "${{ github.workspace }}/src/batgrep.sh"
|
||||
ln -s "${{ github.workspace }}/src/batgrep.sh" "${{ runner.temp }}/absolute-batgrep"
|
||||
(cd "${{ github.workspace }}" && ln -s "src/batgrep.sh" relative-batgrep)
|
||||
- name: Test absolute symlink
|
||||
run: |
|
||||
PATH="${{ runner.temp }}/bin:${PATH}"
|
||||
"${{ runner.temp }}/absolute-batgrep" 'a' <<< 'abc'
|
||||
- name: Test relative symlink
|
||||
run: |
|
||||
PATH="${{ runner.temp }}/bin:${PATH}"
|
||||
"${{ github.workspace }}/relative-batgrep" 'a' <<< 'abc'
|
||||
|
||||
|
||||
9
.gitignore
vendored
9
.gitignore
vendored
|
|
@ -4,9 +4,14 @@
|
|||
|
||||
# Developer
|
||||
.idea
|
||||
.vscode
|
||||
*.iml
|
||||
|
||||
# Project
|
||||
/.circleci/.config.yml
|
||||
.download
|
||||
bin
|
||||
/bin
|
||||
/man
|
||||
|
||||
# Side-Effects
|
||||
/test/data/.config/fish
|
||||
/test/data/.local/share/fish
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit f66c4e03b4577317aec6a739c42890334aefe6b9
|
||||
Subproject commit 6b97e0a531f77d2e1f10f48ebb68d4033d69e04d
|
||||
18
CONTRIBUTING.md
Normal file
18
CONTRIBUTING.md
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# Contributing
|
||||
Are you interested in contributing to `bat-extras`? That's great!
|
||||
All we ask is that you keep a few things in mind:
|
||||
|
||||
|
||||
## DOs:
|
||||
|
||||
- Use Bashisms whenever possible (unless it would make the code unclear). These are scripts written specifically for the `bash` shell, and they should take advantage of built-in functionality instead of spawning external processes.
|
||||
- Use `awk` or `sed` when it would be faster or less verbose than only using `bash` builtins.
|
||||
|
||||
## DON'Ts:
|
||||
|
||||
- Include crude or offensive language inside issues or scripts.
|
||||
- Use GNU/BSD-only features in external programs like `sed` or `awk`.
|
||||
- Use `bash` features that require a Bash version newer than 3.2.
|
||||
- Use `head` in a pipe. See [Issue #19](https://github.com/eth-p/bat-extras/issues/19) for more details.
|
||||
- Use any external program that isn't likely to come installed by default (e.g. avoid `perl` and `python`).
|
||||
- Automatically reformat scripts unless it's a pull request specifically intended for reformatting. The formatting style that we use differs from what `shfmt` and other shell script formatters will emit.
|
||||
83
README.md
83
README.md
|
|
@ -18,6 +18,12 @@ Read system manual pages (`man`) using `bat` as the manual page formatter.
|
|||
|
||||
|
||||
|
||||
### [`batpipe`](doc/batpipe.md)
|
||||
|
||||
A `less` (and soon `bat`) preprocessor for viewing more types of files in the terminal.
|
||||
|
||||
|
||||
|
||||
### [`batwatch`](doc/batwatch.md)
|
||||
|
||||
Watch for changes in one or more files, and print them with `bat`.
|
||||
|
|
@ -25,6 +31,12 @@ Watch for changes in one or more files, and print them with `bat`.
|
|||
|
||||
|
||||
|
||||
### [`batdiff`](doc/batdiff.md)
|
||||
Diff a file against the current git index, or display the diff between two files.
|
||||
<u>Requirements:</u> `bat`, `delta` (optional)
|
||||
|
||||
|
||||
|
||||
### [`prettybat`](doc/prettybat.md)
|
||||
|
||||
Pretty-print source code and highlight it with `bat`.
|
||||
|
|
@ -34,16 +46,67 @@ Pretty-print source code and highlight it with `bat`.
|
|||
|
||||
## Installation via Package Manager
|
||||
|
||||
**Homebrew:** `brew install eth-p/software/bat-extras`
|
||||
### Homebrew
|
||||
|
||||
All of the `bat-extras` scripts can be installed with `brew install bat-extras`.
|
||||
|
||||
If you would prefer to only install the specific scripts you need, you can use the `eth-p/software` tap to install individual scripts: `brew install eth-p/software/bat-extras-[SCRIPT]`
|
||||
|
||||
|
||||
### MacPorts
|
||||
|
||||
The `bat-extras` scripts can also be installed via [MacPorts](https://www.macports.org) on macOS:
|
||||
|
||||
```bash
|
||||
sudo port install bat-extras
|
||||
```
|
||||
|
||||
Port info [here](https://ports.macports.org/port/bat-extras/).
|
||||
|
||||
### Pacman
|
||||
|
||||
`bat-extras` is [officially available](https://archlinux.org/packages/extra/any/bat-extras/) on the Arch extra repository!
|
||||
|
||||
If you have the extra repository enabled, you can install `bat-extras` by running:
|
||||
|
||||
```bash
|
||||
pacman -S bat-extras
|
||||
```
|
||||
|
||||
### Gentoo
|
||||
`bat-extras` is available on **Gentoo's Guru Overlay** as `sys-apps/bat-extras`.
|
||||
|
||||
To install, first make sure you've added the [Gentoo Guru Overlay](https://wiki.gentoo.org/wiki/Project:GURU) to your local repositories, then emerge accordingly...
|
||||
|
||||
```bash
|
||||
emerge sys-apps/bat-extras
|
||||
```
|
||||
|
||||
### Fedora (Unofficial)
|
||||
`bat-extras` is available in an unofficial Fedora Copr
|
||||
[repository](https://copr.fedorainfracloud.org/coprs/awood/bat-extras/).
|
||||
**Note**: this package does not contain `prettybat` since `prettier` is not yet
|
||||
packaged for Fedora.
|
||||
|
||||
Install the Copr plugin, enable the repository, and then install the package
|
||||
by running:
|
||||
|
||||
```bash
|
||||
dnf install dnf-plugins-core
|
||||
dnf copr enable awood/bat-extras
|
||||
dnf install bat-extras
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Installation ()
|
||||
## Installation
|
||||
|
||||
[](https://github.com/eth-p/bat-extras/actions/workflows/test.yaml)
|
||||
|
||||
The scripts in this repository are designed to run as-is, provided that they aren't moved around.
|
||||
This means that you're free to just symlink `src/[script].sh` to your local bin folder.
|
||||
|
||||
If you would rather have self-contained scripts that you can place and run anywhere, you can use the `build.sh` script to create (and optionally install) them.
|
||||
If you would rather have *faster*, self-contained scripts that you can place and run anywhere, you can use the `build.sh` script to create (and optionally install) them.
|
||||
|
||||
|
||||
|
||||
|
|
@ -80,13 +143,27 @@ If you only want to install a single script, you can run the build process and c
|
|||
|
||||
|
||||
|
||||
**Manuals:**
|
||||
|
||||
The build script will automatically generate a `man` page for each of the markdown documentation files.
|
||||
This is a beta feature that uses a non-compliant Markdown "parser" written in Bash, and there is no guarantee towards the quality of the generated manual pages. If you do not want to generate manual files, you can provide the `--no-manuals` option to disable manual file generation.
|
||||
|
||||
|
||||
|
||||
**Alternate Executable:**
|
||||
|
||||
Depending on the distribution, bat may have been renamed to avoid package conflicts.
|
||||
If you wish to use these scripts on a distribution where this is the case, there is an `--alternate-executable=NAME` option which will build the scripts to use an alternate executable name.
|
||||
|
||||
You may also specify alternate executables for `ripgrep`, `delta`, `fzf`, or `git` with `--alternate-executable:PROGRAM NAME` where `PROGRAM` is one the aforementioned programs. Note that doing so may cause verification to fail.
|
||||
|
||||
|
||||
**Verification:**
|
||||
|
||||
The build script will attempt to verify the correctness of the "bin" scripts by comparing their output with their source counterparts. It is recommended to let it do this, but you can disable verification with the `--no-verify` option.
|
||||
|
||||
|
||||
|
||||
## Contributing
|
||||
|
||||
If you would like to contribute to `bat-extras`, please feel free to [open an issue on GitHub](https://github.com/eth-p/bat-extras/issues), or make a pull request. If you do the latter, please keep our [contributing guidelines](./CONTRIBUTING.md) in mind.
|
||||
|
|
|
|||
|
|
@ -1,10 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
# -----------------------------------------------------------------------------
|
||||
# bat-extras | Copyright (C) 2019 eth-p | MIT License
|
||||
# bat-extras | Copyright (C) 2020-2024 eth-p and contributors | MIT License
|
||||
#
|
||||
# Repository: https://github.com/eth-p/bat-extras
|
||||
# Issues: https://github.com/eth-p/bat-extras/issues
|
||||
# -----------------------------------------------------------------------------
|
||||
source "${LIB}/opt_hook_color.sh"
|
||||
source "${LIB}/opt_hook_pager.sh"
|
||||
source "${LIB}/opt_hook_version.sh"
|
||||
434
build.sh
434
build.sh
|
|
@ -1,19 +1,122 @@
|
|||
#!/usr/bin/env bash
|
||||
# -----------------------------------------------------------------------------
|
||||
# bat-extras | Copyright (C) 2019 eth-p | MIT License
|
||||
# bat-extras | Copyright (C) 2019-2023 eth-p | MIT License
|
||||
#
|
||||
# Repository: https://github.com/eth-p/bat-extras
|
||||
# Issues: https://github.com/eth-p/bat-extras/issues
|
||||
# -----------------------------------------------------------------------------
|
||||
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
BIN="$HERE/bin"
|
||||
SRC="$HERE/src"
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Build-as-a-Library Functions:
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Redefines a function to print a constant string whenever called.
|
||||
# This is used for lazy-loading of some getter functions.
|
||||
#
|
||||
# Arguments:
|
||||
# 1 -- The function name.
|
||||
# 2 -- The constant string to print.
|
||||
#
|
||||
# Output:
|
||||
# The constant string.
|
||||
batextras:lazy_done() {
|
||||
eval "$(printf "%s() { printf \"%%s\n\" %q; }" "$1" "$2")"
|
||||
"$1"
|
||||
}
|
||||
|
||||
# Checks to see if a function is defined.
|
||||
# Arguments:
|
||||
# 1 -- The function name.
|
||||
# If prefixed with "::", it will use "batextras:" as a namespace.
|
||||
batextras:is_function_defined() {
|
||||
local name="$1"
|
||||
if [[ "${name:0:2}" = "::" ]]; then name="batextras:${name:2}"; fi
|
||||
[[ "$(type -t "$name" || echo 'undefined')" = "function" ]]
|
||||
return $?
|
||||
}
|
||||
|
||||
# Prints the path to the project directory.
|
||||
if ! batextras:is_function_defined ::get_project_directory; then
|
||||
batextras:get_project_directory() {
|
||||
batextras:lazy_done "${FUNCNAME[0]}" \
|
||||
"$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
}
|
||||
fi
|
||||
|
||||
# Prints the path to the project source directory.
|
||||
if ! batextras:is_function_defined ::get_source_directory; then
|
||||
batextras:get_source_directory() {
|
||||
batextras:lazy_done "${FUNCNAME[0]}" \
|
||||
"$(batextras:get_project_directory)/src"
|
||||
}
|
||||
fi
|
||||
|
||||
# Prints the path to the project output directory for executables.
|
||||
if ! batextras:is_function_defined ::get_output_bin_directory; then
|
||||
batextras:get_output_bin_directory() {
|
||||
batextras:lazy_done "${FUNCNAME[0]}" \
|
||||
"$(batextras:get_project_directory)/bin"
|
||||
}
|
||||
fi
|
||||
|
||||
# Prints the path to the project output directory for manuals.
|
||||
if ! batextras:is_function_defined ::get_output_man_directory; then
|
||||
batextras:get_output_man_directory() {
|
||||
batextras:lazy_done "${FUNCNAME[0]}" \
|
||||
"$(batextras:get_project_directory)/man"
|
||||
}
|
||||
fi
|
||||
|
||||
# Prints the path to the project directory for documentation.
|
||||
if ! batextras:is_function_defined ::get_docs_directory; then
|
||||
batextras:get_docs_directory() {
|
||||
batextras:lazy_done "${FUNCNAME[0]}" \
|
||||
"$(batextras:get_project_directory)/doc"
|
||||
}
|
||||
fi
|
||||
|
||||
# Prints the declared version (in version.txt).
|
||||
if ! batextras:is_function_defined ::get_version; then
|
||||
batextras:get_version() {
|
||||
batextras:lazy_done "${FUNCNAME[0]}" \
|
||||
"$(cat "$(batextras:get_project_directory)/version.txt")"
|
||||
}
|
||||
fi
|
||||
|
||||
# Prints the paths for all source scripts in this project.
|
||||
#
|
||||
# Output:
|
||||
# One line for each script with the full path to the script.
|
||||
if ! batextras:is_function_defined ::get_source_paths; then
|
||||
batextras:get_source_paths() {
|
||||
for file in "$(batextras:get_source_directory)"/*.sh; do
|
||||
printf "%s\n" "$file"
|
||||
file_bin="$(basename -- "$file" ".sh")"
|
||||
done
|
||||
}
|
||||
fi
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Main:
|
||||
# Only run everything past this point if the script is not sourced.
|
||||
# -----------------------------------------------------------------------------
|
||||
(return 0 2>/dev/null) && return 0
|
||||
|
||||
HERE="$(batextras:get_project_directory)"
|
||||
SRC="$(batextras:get_source_directory)"
|
||||
BIN="$(batextras:get_output_bin_directory)"
|
||||
MAN="$(batextras:get_output_man_directory)"
|
||||
MAN_SRC="$(batextras:get_docs_directory)"
|
||||
LIB="$HERE/lib"
|
||||
|
||||
source "${LIB}/print.sh"
|
||||
source "${LIB}/opt.sh"
|
||||
source "${LIB}/constants.sh"
|
||||
source "${HERE}/mdroff.sh"
|
||||
# -----------------------------------------------------------------------------
|
||||
set -eo pipefail
|
||||
exec 3>&1
|
||||
|
||||
# Runs the next build step.
|
||||
#
|
||||
|
|
@ -34,32 +137,101 @@ next() {
|
|||
# Prints a build step message.
|
||||
smsg() {
|
||||
case "$2" in
|
||||
"SKIP") printc " %{YELLOW} %{DIM}%s [skipped]%{CLEAR}\n" "$1" 1>&2 ;;
|
||||
*) printc " %{YELLOW} %s...%{CLEAR}\n" "$1" 1>&2 ;;
|
||||
"SKIP") printc_msg " %{YELLOW} %{DIM}%s [skipped]%{CLEAR}\n" "$1" ;;
|
||||
*) printc_msg " %{YELLOW} %s...%{CLEAR}\n" "$1" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Prints a message to STDOUT (via FD 3).
|
||||
# Works the same as printc.
|
||||
printc_msg() {
|
||||
printc "$@" 1>&3
|
||||
}
|
||||
|
||||
# Prints a message to STDERR.
|
||||
# Works the same as printc.
|
||||
printc_err() {
|
||||
printc "$@" 1>&2
|
||||
}
|
||||
|
||||
# Escapes a sed pattern.
|
||||
# Arguments:
|
||||
# 1 -- The pattern.
|
||||
|
||||
#
|
||||
# Output:
|
||||
# The escaped string.
|
||||
sed_escape() {
|
||||
sed 's/\([][\\\/\^\$\*\.\-]\)/\\\1/g' <<< "$1"
|
||||
}
|
||||
|
||||
# Checks if the output scripts will be minified.
|
||||
# Arguments:
|
||||
# 1 "all" -- All scripts will be minified.
|
||||
# "any" -- Any scripts will be minified.
|
||||
# "lib" -- Library scripts will be minified.
|
||||
# "unsafe" -- Unsafe minifications will be applied.
|
||||
will_minify() {
|
||||
case "$1" in
|
||||
all)
|
||||
[[ "$OPT_MINIFY" =~ ^all($|\+.*) ]]
|
||||
return $? ;;
|
||||
unsafe)
|
||||
[[ "$OPT_MINIFY" =~ ^.*+unsafe(\+.*)*$ ]]
|
||||
return $? ;;
|
||||
lib)
|
||||
[[ "$OPT_MINIFY" =~ ^lib($|\+.*) ]]
|
||||
return $? ;;
|
||||
any|"")
|
||||
[[ "$OPT_MINIFY" != "none" ]]
|
||||
return $? ;;
|
||||
none)
|
||||
! will_minify any
|
||||
return $? ;;
|
||||
esac
|
||||
return 1
|
||||
}
|
||||
|
||||
# Generates the banner for the output files.
|
||||
#
|
||||
# Output:
|
||||
# The contents of banner.txt
|
||||
generate_banner() {
|
||||
local step="$1"
|
||||
if ! "$OPT_BANNER"; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Don't run it unless the comments are removed or hidden.
|
||||
if ! { will_minify all || "$OPT_COMPRESS"; }; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Only run it in the compression step if both minifying and compressing.
|
||||
if will_minify all && "$OPT_COMPRESS" && [[ "$step" != "step_compress" ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Write the banner.
|
||||
bat "${HERE}/banner.txt"
|
||||
}
|
||||
|
||||
# Build step: read
|
||||
# Reads the file from its source.
|
||||
#
|
||||
# Arguments:
|
||||
# 1 -- The source file.
|
||||
# 2 -- A description of what is being read.
|
||||
#
|
||||
# Output:
|
||||
# The file contents.
|
||||
step_read() {
|
||||
local what=""
|
||||
if [[ -n "${2:-}" ]]; then
|
||||
what=" $2"
|
||||
fi
|
||||
|
||||
cat "$1"
|
||||
smsg "Reading"
|
||||
smsg "Reading${what}"
|
||||
}
|
||||
|
||||
# Build step: preprocess
|
||||
|
|
@ -96,13 +268,14 @@ step_preprocess() {
|
|||
# Output:
|
||||
# The minified file contents.
|
||||
step_minify() {
|
||||
if [[ "$OPT_MINIFY" =~ ^all($|+.*) ]]; then
|
||||
if ! will_minify all; then
|
||||
cat
|
||||
smsg "Minifying" "SKIP"
|
||||
return 0
|
||||
fi
|
||||
|
||||
printf "#!/usr/bin/env bash\n"
|
||||
generate_banner step_minify
|
||||
pp_minify | pp_minify_unsafe
|
||||
smsg "Minifying"
|
||||
}
|
||||
|
|
@ -125,6 +298,7 @@ step_compress() {
|
|||
local wrapper
|
||||
wrapper="$({
|
||||
printf '#!/usr/bin/env bash\n'
|
||||
generate_banner step_compress
|
||||
printf "(exec -a \"\$0\" bash -c 'eval \"\$(cat <&3)\"' \"\$0\" \"\$@\" 3< <(dd bs=1 if=\"\$0\" skip=::: 2>/dev/null | gunzip)); exit \$?;\n"
|
||||
})"
|
||||
|
||||
|
|
@ -150,7 +324,7 @@ step_write() {
|
|||
smsg "Building"
|
||||
}
|
||||
|
||||
# Build step: write
|
||||
# Build step: write_install
|
||||
# Optionally writes the output script to a file.
|
||||
#
|
||||
# Arguments:
|
||||
|
|
@ -161,7 +335,6 @@ step_write() {
|
|||
#
|
||||
# Output:
|
||||
# The file contents.
|
||||
|
||||
step_write_install() {
|
||||
if [[ "$OPT_INSTALL" != true ]]; then
|
||||
cat
|
||||
|
|
@ -174,8 +347,50 @@ step_write_install() {
|
|||
smsg "Installing"
|
||||
}
|
||||
|
||||
# Build step: manpage_install
|
||||
# Optionally writes the manpage to a gzipped file.
|
||||
#
|
||||
# Arguments:
|
||||
# 1 -- The file to write to.
|
||||
#
|
||||
# Input:
|
||||
# The file contents.
|
||||
#
|
||||
# Output:
|
||||
# The file contents.
|
||||
step_manpage_install() {
|
||||
if [[ "$OPT_INSTALL" != true ]]; then
|
||||
cat
|
||||
smsg "Installing manual" "SKIP"
|
||||
return 0
|
||||
fi
|
||||
|
||||
gzip | tee "$1"
|
||||
smsg "Installing manual"
|
||||
}
|
||||
|
||||
# Build step: manpage_generate
|
||||
# Generates a manpage document from a markdown document.
|
||||
#
|
||||
# Input:
|
||||
# The markdown doc contents.
|
||||
#
|
||||
# Output:
|
||||
# The roff manpage contents.
|
||||
step_manpage_generate() {
|
||||
if [[ "$OPT_MANUALS" != true ]]; then
|
||||
cat
|
||||
smsg "Generating manual" "SKIP"
|
||||
return 0
|
||||
fi
|
||||
|
||||
(mdroff)
|
||||
smsg "Generating manual"
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Preprocessor:
|
||||
# -----------------------------------------------------------------------------
|
||||
# Preprocessor.
|
||||
|
||||
# Consolidates all scripts into a single file.
|
||||
# This follows all `source "${LIB}/..."` files and embeds them into the script.
|
||||
|
|
@ -208,10 +423,10 @@ pp_consolidate__do() {
|
|||
# Embed the script.
|
||||
echo "${indent}# --- BEGIN LIBRARY FILE: ${BASH_REMATCH[1]} ---"
|
||||
{
|
||||
if [[ "$OPT_MINIFY" = "lib" ]]; then
|
||||
if will_minify lib; then
|
||||
pp_strip_comments | pp_minify | pp_minify_unsafe
|
||||
else
|
||||
cat
|
||||
pp_strip_copyright | pp_strip_separators
|
||||
fi
|
||||
} < <(pp_consolidate__do "$((depth + 1))" < "$script") | sed "s/^/${indent}/"
|
||||
echo "${indent}# --- END LIBRARY FILE ---"
|
||||
|
|
@ -224,13 +439,13 @@ pp_consolidate__do() {
|
|||
}
|
||||
|
||||
# Inlines constants:
|
||||
# EXECUTABLE_BAT
|
||||
# EXECUTABLE_*
|
||||
# PROGRAM_*
|
||||
pp_inline_constants() {
|
||||
local constants=("EXECUTABLE_BAT" "PROGRAM")
|
||||
local constants=("PROGRAM")
|
||||
|
||||
# Determine the PROGRAM_ constants.
|
||||
local nf_constants="$( ( set -o posix ; set) | grep '^PROGRAM_' | cut -d'=' -f1)"
|
||||
local nf_constants="$( ( set -o posix ; set) | grep '^\(PROGRAM_\|EXECUTABLE_\)' | cut -d'=' -f1)"
|
||||
local line
|
||||
while read -r line; do
|
||||
constants+=("$line")
|
||||
|
|
@ -250,15 +465,26 @@ pp_inline_constants() {
|
|||
sed "${constants_pattern}"
|
||||
}
|
||||
|
||||
|
||||
# Strips comments from a Bash source file.
|
||||
pp_strip_comments() {
|
||||
sed '/^[[:space:]]*#.*$/d'
|
||||
}
|
||||
|
||||
# Strips copyright comments from the start of a Bash source file.
|
||||
pp_strip_copyright() {
|
||||
awk '/^#/ {if(!p){ next }} { p=1; print $0 }'
|
||||
}
|
||||
|
||||
# Strips separator comments from the start of a Bash source file.
|
||||
pp_strip_separators() {
|
||||
awk '/^#\s*-{5,}/ { next; } {print $0}'
|
||||
}
|
||||
|
||||
# Minify a Bash source file.
|
||||
# https://github.com/mvdan/sh
|
||||
pp_minify() {
|
||||
if [[ "$OPT_MINIFY" = "none" ]]; then
|
||||
if will_minify none; then
|
||||
cat
|
||||
return
|
||||
fi
|
||||
|
|
@ -271,7 +497,7 @@ pp_minify() {
|
|||
# Right now, this doesn't do anything.
|
||||
# This should be applied after shfmt minification.
|
||||
pp_minify_unsafe() {
|
||||
if ! [[ "$OPT_MINIFY" =~ ^.*+unsafe(+.*)*$ ]]; then
|
||||
if ! will_minify unsafe; then
|
||||
cat
|
||||
return 0
|
||||
fi
|
||||
|
|
@ -280,76 +506,161 @@ pp_minify_unsafe() {
|
|||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Options.
|
||||
# Options:
|
||||
# -----------------------------------------------------------------------------
|
||||
OPT_INSTALL=false
|
||||
OPT_COMPRESS=false
|
||||
OPT_VERIFY=true
|
||||
OPT_BANNER=true
|
||||
OPT_MANUALS=true
|
||||
OPT_INLINE=true
|
||||
OPT_MINIFY="lib"
|
||||
OPT_PREFIX="/usr/local"
|
||||
OPT_BAT="bat"
|
||||
EXECUTABLE_BAT="$(basename -- "$EXECUTABLE_BAT")"
|
||||
ALT_EXECS=()
|
||||
BUILD_FILTER=()
|
||||
|
||||
DOCS_URL="https://github.com/eth-p/bat-extras/blob/master/doc"
|
||||
DOCS_MAINTAINER="eth-p <eth-p@hidden.email>"
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Use a different default prefix when running on Termux.
|
||||
|
||||
if [[ "$(uname -o)" = "Android" ]] && [[ -n "${TERMUX_VERSION:-}" ]]; then
|
||||
OPT_PREFIX="/data/data/com.termux/files/usr/"
|
||||
else
|
||||
OPT_PREFIX="/usr/local"
|
||||
fi
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Parse arguments.
|
||||
|
||||
while shiftopt; do
|
||||
# shellcheck disable=SC2034
|
||||
case "$OPT" in
|
||||
--install) OPT_INSTALL=true ;;
|
||||
--compress) OPT_COMPRESS=true ;;
|
||||
--manuals) OPT_MANUALS="${OPT_VAL:-true}" ;;
|
||||
--no-manuals) OPT_MANUALS=false ;;
|
||||
--verify) OPT_VERIFY=true ;;
|
||||
--no-verify) OPT_VERIFY=false ;;
|
||||
--banner) OPT_BANNER=true ;;
|
||||
--no-banner) OPT_BANNER=false ;;
|
||||
--inline) OPT_INLINE=true ;;
|
||||
--no-inline) OPT_INLINE=false ;;
|
||||
--prefix) shiftval; OPT_PREFIX="$OPT_VAL" ;;
|
||||
--alternate-executable) shiftval; OPT_BAT="$OPT_VAL" ;;
|
||||
--alternate-executable) shiftval; ALT_EXECS+=("bat"); EXECUTABLE_BAT="$OPT_VAL" ;;
|
||||
--alternate-executable:bat) shiftval; ALT_EXECS+=("bat"); EXECUTABLE_BAT="$OPT_VAL" ;;
|
||||
--alternate-executable:ripgrep) shiftval; ALT_EXECS+=("ripgrep"); EXECUTABLE_RIPGREP="$OPT_VAL" ;;
|
||||
--alternate-executable:delta) shiftval; ALT_EXECS+=("delta"); EXECUTABLE_DELTA="$OPT_VAL" ;;
|
||||
--alternate-executable:fzf) shiftval; ALT_EXECS+=("fzf"); EXECUTABLE_FZF="$OPT_VAL" ;;
|
||||
--alternate-executable:git) shiftval; ALT_EXECS+=("git"); EXECUTABLE_GIT="$OPT_VAL" ;;
|
||||
--minify) shiftval; OPT_MINIFY="$OPT_VAL" ;;
|
||||
|
||||
# Print scripts.
|
||||
--show:source-paths) get_source_paths; exit 0 ;;
|
||||
|
||||
# Unknown options.
|
||||
*)
|
||||
printc "%{RED}%s: unknown option '%s'%{CLEAR}" "$PROGRAM" "$OPT"
|
||||
exit 1
|
||||
if ! [[ -f "${SRC}/${OPT}.sh" ]]; then
|
||||
printc_err "%{RED}%s: unknown option '%s'%{CLEAR}" "$PROGRAM" "$OPT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BUILD_FILTER+=("$OPT")
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ "$OPT_BAT" != "bat" ]]; then
|
||||
printc "%{YELLOW}Building executable scripts with an alternate bat executable at %{CLEAR}%s%{YELLOW}.%{CLEAR}\n" "$OPT_BAT" 1>&2
|
||||
if ! command -v "$OPT_BAT"; then
|
||||
printc "%{YELLOW}WARNING: Bash cannot execute the specified file.\n" 1>&2
|
||||
printc "%{YELLOW} The finished scripts may not run properly.%{CLEAR}\n" 1>&2
|
||||
if [[ "${#ALT_EXECS[@]}" -gt 0 ]]; then
|
||||
printc_msg "%{YELLOW}Building executable scripts with alternate executables for:%{CLEAR}\n"
|
||||
printc_msg "%{YELLOW} - %{CLEAR}%s\n" "${ALT_EXECS[@]}"
|
||||
printc_msg "\n"
|
||||
|
||||
if ! command -v "$EXECUTABLE_BAT" &>/dev/null; then
|
||||
printc_err "%{YELLOW}WARNING: Bash cannot execute bat's executable file.\n"
|
||||
printc_err "%{YELLOW} The finished scripts may not run properly.%{CLEAR}\n"
|
||||
fi
|
||||
|
||||
EXECUTABLE_BAT="$OPT_BAT"
|
||||
printc "\n" 1>&2
|
||||
# shellcheck disable=SC2034
|
||||
printc_msg "\n"
|
||||
fi
|
||||
|
||||
if [[ "$OPT_INSTALL" = true ]]; then
|
||||
printc "%{YELLOW}Installing to %{MAGENTA}%s%{YELLOW}.%{CLEAR}\n" "$OPT_PREFIX" 1>&2
|
||||
printc_msg "%{YELLOW}Installing to %{MAGENTA}%s%{YELLOW}.%{CLEAR}\n" "$OPT_PREFIX"
|
||||
else
|
||||
printc "%{YELLOW}This will not install the script.%{CLEAR}\n" 1>&2
|
||||
printc "%{YELLOW}Use %{BLUE}--install%{YELLOW} for a global install.%{CLEAR}\n\n" 1>&2
|
||||
printc_msg "%{YELLOW}This will not install the script.%{CLEAR}\n"
|
||||
printc_msg "%{YELLOW}Use %{BLUE}--install%{YELLOW} for a global install.%{CLEAR}\n\n"
|
||||
fi
|
||||
|
||||
if [[ "$OPT_INLINE" = false ]]; then
|
||||
# Prevent full executable paths from being inlined.
|
||||
while read -r exec; do
|
||||
declare "$exec=$(basename "${!exec}")"
|
||||
done < <(set | grep '^EXECUTABLE' | cut -d'=' -f1)
|
||||
fi
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Check for resources.
|
||||
|
||||
[[ -d "$BIN" ]] || mkdir "$BIN"
|
||||
|
||||
if [[ "$OPT_MINIFY" != "none" ]] && ! command -v shfmt &>/dev/null; then
|
||||
printc "%{RED}Warning: cannot find shfmt. Unable to minify scripts.%{CLEAR}\n"
|
||||
if ! will_minify none && ! command -v shfmt &>/dev/null; then
|
||||
printc_err "%{RED}Warning: cannot find shfmt. Unable to minify scripts.%{CLEAR}\n"
|
||||
OPT_MINIFY=none
|
||||
fi
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Check target directories exist.
|
||||
|
||||
[[ -d "$BIN" ]] || mkdir -p "$BIN"
|
||||
|
||||
if "$OPT_INSTALL"; then
|
||||
[[ -d "${OPT_PREFIX}/bin" ]] || mkdir -p "${OPT_PREFIX}/bin"
|
||||
[[ "$OPT_MANUALS" = "true" && ! -d "${OPT_PREFIX}/share/man/man1" ]] \
|
||||
&& mkdir -p "${OPT_PREFIX}/share/man/man1"
|
||||
fi
|
||||
|
||||
if [[ "$OPT_MANUALS" = "true" ]]; then
|
||||
[[ -d "$MAN" ]] || mkdir -p "$MAN"
|
||||
fi
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Find files.
|
||||
|
||||
SOURCES=()
|
||||
|
||||
printc "%{YELLOW}Preparing scripts...%{CLEAR}\n" 1>&2
|
||||
for file in "$SRC"/*.sh; do
|
||||
SOURCES+=("$file")
|
||||
done
|
||||
printc_msg "%{YELLOW}Preparing scripts...%{CLEAR}\n"
|
||||
while read -r file; do
|
||||
file_bin="$(basename -- "$file" ".sh")"
|
||||
buildable=false
|
||||
|
||||
if ! "$buildable" && [[ "${#BUILD_FILTER[@]}" -eq 0 ]]; then
|
||||
buildable=true
|
||||
elif ! "$buildable"; then
|
||||
for buildable_file in "${BUILD_FILTER[@]}"; do
|
||||
if [[ "$buildable_file" = "$file_bin" ]]; then
|
||||
buildable=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# If that one is allowed to build, add it to the sources list.
|
||||
if "$buildable"; then
|
||||
SOURCES+=("$file")
|
||||
else
|
||||
printc_msg " %{YELLOW}Skipping %{MAGENTA}%s%{CLEAR}\n" "$(basename "$file_bin")"
|
||||
fi
|
||||
done < <(batextras:get_source_paths)
|
||||
|
||||
if [[ "${#BUILD_FILTER[@]}" -gt 0 ]]; then
|
||||
printf "\n"
|
||||
fi
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Build files.
|
||||
|
||||
printc "%{YELLOW}Building scripts...%{CLEAR}\n" 1>&2
|
||||
printc_msg "%{YELLOW}Building scripts...%{CLEAR}\n"
|
||||
file_i=0
|
||||
file_n="${#SOURCES[@]}"
|
||||
for file in "${SOURCES[@]}"; do
|
||||
|
|
@ -359,7 +670,7 @@ for file in "${SOURCES[@]}"; do
|
|||
PROGRAM="$filename"
|
||||
PROGRAM_VERSION="$(<"${HERE}/version.txt")"
|
||||
|
||||
printc " %{YELLOW}[%s/%s] %{MAGENTA}%s%{CLEAR}\n" "$file_i" "$file_n" "$file" 1>&2
|
||||
printc_msg " %{YELLOW}[%s/%s] %{MAGENTA}%s%{CLEAR}\n" "$file_i" "$file_n" "$file"
|
||||
step_read "$file" |
|
||||
next step_preprocess |
|
||||
next step_minify |
|
||||
|
|
@ -367,46 +678,59 @@ for file in "${SOURCES[@]}"; do
|
|||
next step_write "${BIN}/${filename}" |
|
||||
next step_write_install "${OPT_PREFIX}/bin/${filename}" |
|
||||
cat >/dev/null
|
||||
|
||||
# Build manuals.
|
||||
if [[ -f "${HERE}/doc/${filename}.md" && "$OPT_MANUALS" = "true" ]]; then
|
||||
step_read "${HERE}/doc/${filename}.md" "manual" |
|
||||
next step_manpage_generate |
|
||||
next step_write "${MAN}/${filename}.1" |
|
||||
next step_manpage_install "${OPT_PREFIX}/share/man/man1/${filename}.1.gz" |
|
||||
cat >/dev/null
|
||||
fi
|
||||
done
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Verify files by running the tests.
|
||||
|
||||
if "$OPT_VERIFY"; then
|
||||
printc "\n%{YELLOW}Verifying scripts...%{CLEAR}\n" 1>&2
|
||||
printc_msg "\n%{YELLOW}Verifying scripts...%{CLEAR}\n"
|
||||
|
||||
# Run the tests.
|
||||
FAIL=0
|
||||
SKIP=0
|
||||
while read -r action data1 data2 splat; do
|
||||
[[ "$action" == "result" ]] || continue
|
||||
|
||||
printf "\x1B[G\x1B[K%s" "$data1" 1>&2
|
||||
case "$data2" in
|
||||
fail)
|
||||
printf " failed.\n" 1>&2
|
||||
printc_err "\x1B[G\x1B[K%s failed.\n" "$data1"
|
||||
((FAIL++)) || true
|
||||
;;
|
||||
|
||||
skip)
|
||||
printc_msg "\x1B[G\x1B[K%s skipped.\n" "$data1"
|
||||
((SKIP++)) || true
|
||||
;;
|
||||
|
||||
*)
|
||||
printc_msg "\x1B[G\x1B[K%s" "$data1"
|
||||
;;
|
||||
esac
|
||||
done < <("${HERE}/test.sh" --compiled --porcelain)
|
||||
done < <("${HERE}/test.sh" --compiled --porcelain --jobs=8)
|
||||
|
||||
# Print the overall result.
|
||||
printf "\x1B[G\x1B[K%s" 1>&2
|
||||
printc_msg "\x1B[G\x1B[K"
|
||||
|
||||
if [[ "$FAIL" -ne 0 ]]; then
|
||||
printc "%{RED}One or more tests failed.\n" 1>&2
|
||||
printc "Run ./test.sh for more detailed information.%{CLEAR}\n" 1>&2
|
||||
printc_err "%{RED}%s\n" "One or more tests failed."
|
||||
printc_msg "\x1B[A\x1B[G\x1B[K%{RED}%s\n" "One or more tests failed."
|
||||
printc_err "%{RED}%s%{CLEAR}\n" "Run './test.sh --failed' for more detailed information."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$SKIP" -gt 0 ]]; then
|
||||
printc "%{CYAN}One or more tests were skipped.\n" 1>&2
|
||||
printc "Run ./test.sh for more detailed information.%{CLEAR}\n" 1>&2
|
||||
printc_err "%{CYAN}One or more tests were skipped.\n"
|
||||
printc_err "Run ./test.sh for more detailed information.%{CLEAR}\n"
|
||||
fi
|
||||
|
||||
printc "%{YELLOW}Verified successfully.%{CLEAR}\n" 1>&2
|
||||
printc_msg "%{YELLOW}Verified successfully.%{CLEAR}\n"
|
||||
fi
|
||||
|
|
|
|||
59
doc/batdiff.md
Normal file
59
doc/batdiff.md
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
# bat-extras: batdiff
|
||||
|
||||
Diff a file against the current git index, or display the diff between two files.
|
||||
|
||||
This script supports using [delta](https://github.com/dandavison/delta) as an alternative highlighter for diffs.
|
||||
|
||||
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
batdiff [OPTIONS] FILE
|
||||
batdiff [OPTIONS] FILE OTHER_FILE
|
||||
batdiff --staged
|
||||
|
||||
## Environment
|
||||
|
||||
| Variable | Description |
|
||||
| ------------------------ | ------------------------------------------------ |
|
||||
| `BATDIFF_USE_DELTA=true` | If `delta` is installed, use `delta` by default. |
|
||||
|
||||
## Options
|
||||
|
||||
| Short | Long | Description |
|
||||
| ----- | ----------------------------- | ------------------------------------------------------------ |
|
||||
| `-C` | `--context=[LINES]` | The number of lines to show before and after the differing lines. |
|
||||
| | `--delta` | Display diffs using `delta`. |
|
||||
| | `--color` | Force color output. |
|
||||
| | `--no-color` | Force disable color output. |
|
||||
| | `--paging=["never"/"always"]` | Enable/disable paging. |
|
||||
| | `--pager=[PAGER]` | Specify the pager to use. |
|
||||
| | `--terminal-width=[COLS]` | Generate output for the specified terminal width. |
|
||||
| | `--staged` | Show staged changes. |
|
||||
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
This script is a part of the `bat-extras` suite of scripts. You can find install instructions [here](../README.md#installation).
|
||||
|
||||
|
||||
|
||||
## Caveats
|
||||
|
||||
**When using `bat` as the printer:**
|
||||
|
||||
- Syntax highlighting in diffs between two files is not supported.
|
||||
- Syntax highlighting in a single-file diff requires `bat` >= 0.15.
|
||||
|
||||
**When using `delta` as the printer:**
|
||||
|
||||
- The `--no-color` option does not remove all color output.
|
||||
|
||||
|
||||
|
||||
## Issues?
|
||||
|
||||
If you find an issue or have a feature suggestion, make a pull request or issue through GitHub!
|
||||
Contributions are always welcome.
|
||||
|
|
@ -6,34 +6,34 @@ Search through files or directories looking for matching regular expressions (or
|
|||
|
||||
|
||||
|
||||
## Command Line
|
||||
## Usage
|
||||
|
||||
**Synopsis:**
|
||||
|
||||
- `batgrep [OPTIONS] PATTERN [PATH...] `
|
||||
batgrep [OPTIONS] PATTERN [PATH...]
|
||||
|
||||
|
||||
|
||||
**Options:**
|
||||
## Options
|
||||
|
||||
| Short | Long | Description |
|
||||
| ----- | -------------------------- | ------------------------------------------------------------ |
|
||||
| `-i` | `--ignore-case` | Use case insensitive searching. |
|
||||
| `-s` | `--case-sensitive` | Use case sensitive searching. |
|
||||
| `-S` | `--smart-case` | Use smart case searching. |
|
||||
| `-A` | `--after-context=[LINES]` | Display the next *n* lines after a matched line. |
|
||||
| `-B` | `--before-context=[LINES]` | Display the previous `n` lines before a matched line. |
|
||||
| `-C` | `--context=[LINES]` | A combination of `--after-context` and `--before-context`. |
|
||||
| `-p` | `--search-pattern` | Tell pager to search for `PATTERN`. Currently supported pagers: `less`. |
|
||||
| | `--no-follow` | Do not follow symlinks. |
|
||||
| | `--no-snip` | Do not show the `snip` decoration.<br /><br />This is automatically enabled when `--context=0` or when `bat --version` is less than `0.12.x`. |
|
||||
| | `--no-highlight` | Do not highlight matching lines.<br /><br />This is automatically enabled when `--context=0`. |
|
||||
| | `--color` | Force color output. |
|
||||
| | `--no-color` | Force disable color output. |
|
||||
| Short | Long | Description |
|
||||
| ----- | ---------------------------- | ------------------------------------------------------------ |
|
||||
| `-i` | `--ignore-case` | Use case insensitive searching. |
|
||||
| `-s` | `--case-sensitive` | Use case sensitive searching. |
|
||||
| `-S` | `--smart-case` | Use smart case searching. |
|
||||
| `-A` | `--after-context=[LINES]` | Display the next *n* lines after a matched line. |
|
||||
| `-B` | `--before-context=[LINES]` | Display the previous `n` lines before a matched line. |
|
||||
| `-C` | `--context=[LINES]` | A combination of `--after-context` and `--before-context`. |
|
||||
| `-p` | `--search-pattern` | Tell pager to search for `PATTERN`. Currently supported pagers: `less`. |
|
||||
| | `--no-follow` | Do not follow symlinks. |
|
||||
| | `--no-snip` | Do not show the `snip` decoration.<br /><br />This is automatically enabled when `--context=0` or when `bat --version` is less than `0.12.x`. |
|
||||
| | `--no-highlight` | Do not highlight matching lines.<br /><br />This is automatically enabled when `--context=0`. |
|
||||
| | `--color` | Force color output. |
|
||||
| | `--no-color` | Force disable color output. |
|
||||
| | `--paging=["never"/"always"]`| Enable/disable paging. |
|
||||
| | `--pager=[PAGER]` | Specify the pager to use. |
|
||||
| | `--terminal-width=[COLS]` | Generate output for the specified terminal width. |
|
||||
| | `--no-separator` | Disable printing separator between files. |
|
||||
| | `--rga` | Use `ripgrep-all` instead of `ripgrep`. |
|
||||
|
||||
|
||||
|
||||
**Options (Passthrough)**:
|
||||
The following options are passed directly to ripgrep, and are not handled by this script.
|
||||
|
||||
| Short | Long | Notes |
|
||||
|
|
|
|||
|
|
@ -4,17 +4,28 @@ Read system manual pages (`man`) using `bat` as the manual page formatter.
|
|||
|
||||
Gone are the days of losing your place while reading through monotone manual pages. With `bat` and `batman`, you can read `man ifconfig` with beautiful 24-bit color and syntax higlighting.
|
||||
|
||||
If you have `fzf` installed, you can even use `batman` to search through manual pages!
|
||||
|
||||
|
||||
## Command Line
|
||||
## Usage
|
||||
|
||||
**Synopsis:**
|
||||
batman [SECTION] [ENTRY]
|
||||
|
||||
- `batman [SECTION] [ENTRY] `
|
||||
### As a Replacement for Man
|
||||
|
||||
With bash:
|
||||
|
||||
```bash
|
||||
eval "$(batman --export-env)"
|
||||
```
|
||||
|
||||
**Environment:**
|
||||
With fish:
|
||||
|
||||
```fish
|
||||
batman --export-env | source
|
||||
```
|
||||
|
||||
## Environment
|
||||
|
||||
| Variable | Description |
|
||||
| ---------- | ------------------------------------------------------------ |
|
||||
|
|
@ -22,12 +33,19 @@ Gone are the days of losing your place while reading through monotone manual pag
|
|||
|
||||
|
||||
|
||||
## Customization
|
||||
|
||||
### Changing the Theme
|
||||
|
||||
You can change the syntax highlighting theme for `batman` by setting the `BAT_THEME` environment variable before calling `batman`. The following wrapper function will change the theme to `Solarized (dark)` without affecting any other `bat` command.
|
||||
|
||||
## Caveats
|
||||
```bash
|
||||
batman() {
|
||||
BAT_THEME="Solarized (dark)" batman "$@"
|
||||
return $?
|
||||
}
|
||||
```
|
||||
|
||||
None so far.
|
||||
|
||||
|
||||
|
||||
|
|
@ -37,6 +55,18 @@ This script is a part of the `bat-extras` suite of scripts. You can find install
|
|||
|
||||
|
||||
|
||||
## Caveats
|
||||
|
||||
**Flags aren't highlighted:**
|
||||
|
||||
- This happens when you change `bat`'s theme through `bat`'s config file or the `BAT_THEME` environment variable. Not all themes provide colours for flags, and [it's a known issue](https://github.com/sharkdp/bat/issues/2115).
|
||||
- You can overriding the theme for `batman` by wrapping it in a function that sets `BAT_THEME`.
|
||||
- The following themes support manpage highlighting:
|
||||
- `Monokai Extended` / ``Monokai Extended Light`
|
||||
- `Solarized (dark)` / `Solarized (light)`
|
||||
|
||||
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
Thanks to [@sharkdp](https://github.com/sharkdp) and [@LunarLambda](https://github.com/LunarLambda) for debugging how to make this work properly in [certain environments](https://github.com/sharkdp/bat/issues/652).
|
||||
|
|
@ -46,4 +76,4 @@ Thanks to [@sharkdp](https://github.com/sharkdp) and [@LunarLambda](https://gith
|
|||
## Issues?
|
||||
|
||||
If you find an issue or have a feature suggestion, make a pull request or issue through GitHub!
|
||||
Contributions are always welcome.
|
||||
Contributions are always welcome.
|
||||
|
|
|
|||
83
doc/batpipe.md
Normal file
83
doc/batpipe.md
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
# bat-extras: batpipe
|
||||
|
||||
A `less` (and `bat`) preprocessor for viewing more types of files in the terminal.
|
||||
|
||||
|
||||
|
||||
## Usage
|
||||
Like [lesspipe](https://github.com/wofr06/lesspipe), `batpipe` is designed to work with programs that support preprocessing with the `LESSOPEN` environment variable. Setting up `batpipe` will depend on your shell:
|
||||
|
||||
**Bash:**
|
||||
|
||||
eval "$(batpipe)"
|
||||
|
||||
**Fish:**
|
||||
|
||||
eval (batpipe)
|
||||
|
||||
|
||||
|
||||
## Environment
|
||||
|
||||
| Variable | Description |
|
||||
| -------------------- | ------------------------------------------------------------ |
|
||||
| `BATPIPE_TERM_WIDTH` | Sets the terminal width provided to `bat`. If this variable starts with a hyphen (`-`), the number provided will be relative to the detected terminal size. |
|
||||
|
||||
|
||||
|
||||
## Built-in Viewers
|
||||
|
||||
| Files | Program |
|
||||
| -------------------- | --------------------------- |
|
||||
| Directories | `eza`, `ls` |
|
||||
| `*.tar`, `*.tar.gz` | `tar` |
|
||||
| `*.zip`, `*.jar` | `unzip` |
|
||||
| `*.gz` | `gunzip` |
|
||||
| `*.xz` | `xz` |
|
||||
|
||||
|
||||
## External Viewers
|
||||
|
||||
For file formats that aren't supported by default, an external file viewer can be added to `batpipe` through the external viewer API.
|
||||
|
||||
External viewers are be added to batpipe by creating bash scripts inside the `~/.config/batpipe/viewers.d/` directory.
|
||||
|
||||
### Creating Viewers
|
||||
|
||||
Viewers must define two functions and append the viewer's name to the `$BATPIPE_VIEWERS` array.
|
||||
|
||||
- `viewer_${viewer}_supports [file_basename] [file_path] [inner_file_path]`
|
||||
- `viewer_${viewer}_process [file_path] [inner_file_path]`
|
||||
|
||||
The `viewer_${viewer}_supports` function is called to determine if the external viewer is capable of viewing the provided file. If this function returns successfully, the corresponding `process` function will be called.
|
||||
|
||||
### API
|
||||
|
||||
$BATPIPE_VIEWERS -- An array of loaded file viewers.
|
||||
$BATPIPE_ENABLE_COLOR -- Whether color is supported. (`true`|`false`)
|
||||
$BATPIPE_INSIDE_LESS -- Whether batpipe is inside less. (`true`|`false`)
|
||||
|
||||
batpipe_header [pattern] [...] -- Print a viewer header line.
|
||||
batpipe_subheader [pattern] [...] -- Print a viewer subheader line.
|
||||
|
||||
strip_trailing_slashes [path] -- Strips trailing slashes from a path.
|
||||
|
||||
|
||||
|
||||
|
||||
## Caveats
|
||||
|
||||
- By default, `batpipe` will not use colors when previewed inside `less`.
|
||||
Colors must be explicitly enabled with `BATPIPE=color`.
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
This script is a part of the `bat-extras` suite of scripts. You can find install instructions [here](../README.md#installation).
|
||||
|
||||
|
||||
|
||||
## Issues?
|
||||
|
||||
If you find an issue or have a feature suggestion, make a pull request or issue through GitHub!
|
||||
Contributions are always welcome.
|
||||
|
|
@ -1,32 +1,30 @@
|
|||
# bat-extras: batwatch
|
||||
|
||||
Watch for changes in one or more files, and print them with `bat`.
|
||||
Watch for changes in files or command output, and print them with `bat`.
|
||||
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
batwatch [OPTIONS] FILE...
|
||||
|
||||
## Command Line
|
||||
|
||||
**Synopsis:**
|
||||
|
||||
- `batwatch [OPTIONS] FILE... `
|
||||
batwatch [OPTIONS] --command COMMAND [ARG...]
|
||||
|
||||
|
||||
|
||||
**Options:**
|
||||
## Options
|
||||
|
||||
| Short | Long | Description |
|
||||
| ----- | --------------------- | ------------------------------------------------------------ |
|
||||
| | `--watcher=[watcher]` | Use a specific program to watch for file changes. See [below](#watchers) for more details. |
|
||||
| | `--clear` | Clear the screen before printing the files.<br />This is enabled by default. |
|
||||
| | `--no-clear` | Do not clear the screen before printing the files. |
|
||||
| | `--color` | Force color output. |
|
||||
| | `--no-color` | Force disable color output. |
|
||||
| Short | Long | Description |
|
||||
| ----- | ---------------------- | ------------------------------------------------------------ |
|
||||
| | `--command`\|`-x` | Execute a command on an interval. |
|
||||
| | `--file`\|`-f` | Watch a file for changes. |
|
||||
| | `--watcher=[watcher]` | Use a specific program to watch for file changes. See [below](#watchers) for more details. |
|
||||
| | `--interval=[seconds]` | The interval for executing commands. |
|
||||
| | `--clear` | Clear the screen before printing the files.<br />This is enabled by default. |
|
||||
| | `--no-clear` | Do not clear the screen before printing the files. |
|
||||
| | `--color` | Force color output. |
|
||||
| | `--no-color` | Force disable color output. |
|
||||
|
||||
|
||||
|
||||
**Options (Passthrough)**:
|
||||
All remaining options are passed through to bat.
|
||||
|
||||
|
||||
|
|
@ -36,7 +34,7 @@ All remaining options are passed through to bat.
|
|||
Batwatch uses external programs to watch for file changes.
|
||||
Currently, the following programs are supported:
|
||||
|
||||
- [entr](http://entrproject.org/)
|
||||
- [entr](https://eradman.com/entrproject/)
|
||||
|
||||
There is also a fallback `poll` watcher available.
|
||||
|
||||
|
|
@ -48,13 +46,8 @@ This script is a part of the `bat-extras` suite of scripts. You can find install
|
|||
|
||||
|
||||
|
||||
## Caveats
|
||||
|
||||
None so far.
|
||||
|
||||
|
||||
|
||||
## Issues?
|
||||
|
||||
If you find an issue or have a feature suggestion, make a pull request or issue through GitHub!
|
||||
Contributions are always welcome.
|
||||
Contributions are always welcome.
|
||||
|
|
|
|||
|
|
@ -6,15 +6,14 @@ The only thing better than syntax highlighting? Syntax highlighting *and* code f
|
|||
|
||||
|
||||
|
||||
## Command Line
|
||||
## Usage
|
||||
|
||||
**Synopsis:**
|
||||
|
||||
- `prettybat [OPTIONS] [PATH...] `
|
||||
prettybat [OPTIONS] [PATH...]
|
||||
|
||||
|
||||
|
||||
**Options:**
|
||||
## Options
|
||||
|
||||
Every option is passed through to `bat`.
|
||||
See `man bat` for more information.
|
||||
|
||||
|
|
@ -22,20 +21,23 @@ See `man bat` for more information.
|
|||
|
||||
## Languages
|
||||
|
||||
| Language | Formatter |
|
||||
| -------------------- | ----------------------------------------------------------- |
|
||||
| JavaScript (JS, JSX) | [prettier](https://prettier.io/) |
|
||||
| TypeScript (TS, TSX) | [prettier](https://prettier.io/) |
|
||||
| CSS, SCSS, SASS | [prettier](https://prettier.io/) |
|
||||
| Markdown | [prettier](https://prettier.io/) |
|
||||
| JSON | [prettier](https://prettier.io/) |
|
||||
| YAML | [prettier](https://prettier.io/) |
|
||||
| HTML | [prettier](https://prettier.io/) |
|
||||
| Rust | [rustfmt](https://github.com/rust-lang/rustfmt) |
|
||||
| Bash | [shfmt](https://github.com/mvdan/sh) |
|
||||
| C | [ClangFormat](https://clang.llvm.org/docs/ClangFormat.html) |
|
||||
| C++ | [ClangFormat](https://clang.llvm.org/docs/ClangFormat.html) |
|
||||
| Objective-C | [ClangFormat](https://clang.llvm.org/docs/ClangFormat.html) |
|
||||
| Language | Formatter |
|
||||
| -------------------- | ------------------------------------------------------------------------------------------------------ |
|
||||
| JavaScript (JS, JSX) | [prettier](https://prettier.io/) |
|
||||
| TypeScript (TS, TSX) | [prettier](https://prettier.io/) |
|
||||
| CSS, SCSS, SASS | [prettier](https://prettier.io/) |
|
||||
| Markdown | [prettier](https://prettier.io/) |
|
||||
| JSON | [yq](https://mikefarah.gitbook.io/yq), [prettier](https://prettier.io/) |
|
||||
| YAML | [yq](https://mikefarah.gitbook.io/yq), [prettier](https://prettier.io/) |
|
||||
| HTML | [prettier](https://prettier.io/) |
|
||||
| SVG | [prettier](https://prettier.io/) |
|
||||
| Rust | [rustfmt](https://github.com/rust-lang/rustfmt) |
|
||||
| Bash | [shfmt](https://github.com/mvdan/sh) |
|
||||
| C | [ClangFormat](https://clang.llvm.org/docs/ClangFormat.html) |
|
||||
| C++ | [ClangFormat](https://clang.llvm.org/docs/ClangFormat.html) |
|
||||
| Objective-C | [ClangFormat](https://clang.llvm.org/docs/ClangFormat.html) |
|
||||
| Python | [black](https://black.readthedocs.io/) |
|
||||
| Elixir | [mix format](https://hexdocs.pm/mix/main/Mix.Tasks.Format.html) |
|
||||
|
||||
|
||||
|
||||
|
|
@ -43,11 +45,10 @@ See `man bat` for more information.
|
|||
|
||||
## Caveats
|
||||
|
||||
- The header displayed by bat will show `STDIN` instead of the filename.
|
||||
- The header displayed by bat will show `STDIN` instead of the filename (`bat 0.13` or older).
|
||||
- The git changes sidebar will not work with files that have been formatted.
|
||||
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
This script is a part of the `bat-extras` suite of scripts. You can find install instructions [here](../README.md#installation).
|
||||
|
|
@ -58,4 +59,3 @@ This script is a part of the `bat-extras` suite of scripts. You can find install
|
|||
|
||||
If you find an issue or have a feature suggestion, make a pull request or issue through GitHub!
|
||||
Contributions are always welcome.
|
||||
|
||||
|
|
|
|||
27
lib/check.sh
Normal file
27
lib/check.sh
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#!/usr/bin/env bash
|
||||
# -----------------------------------------------------------------------------
|
||||
# bat-extras | Copyright (C) 2020 eth-p | MIT License
|
||||
#
|
||||
# Repository: https://github.com/eth-p/bat-extras
|
||||
# Issues: https://github.com/eth-p/bat-extras/issues
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Checks that the file or directory exists.
|
||||
# Arguments:
|
||||
# 1 -- The path to check.
|
||||
check_exists() {
|
||||
[[ -e "$1" ]] && return 0
|
||||
|
||||
print_error "%s: No such file or directory" "$1"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Checks that the file is a file.
|
||||
# Arguments:
|
||||
# 1 -- The path to check.
|
||||
check_is_file() {
|
||||
[[ -f "$1" ]] && return 0
|
||||
|
||||
print_error "%s: Not a file" "$1"
|
||||
return 1
|
||||
}
|
||||
|
|
@ -1,18 +1,30 @@
|
|||
#!/usr/bin/env bash
|
||||
# -----------------------------------------------------------------------------
|
||||
# bat-extras | Copyright (C) 2019 eth-p | MIT License
|
||||
# bat-extras | Copyright (C) 2021 eth-p | MIT License
|
||||
#
|
||||
# Repository: https://github.com/eth-p/bat-extras
|
||||
# Issues: https://github.com/eth-p/bat-extras/issues
|
||||
# -----------------------------------------------------------------------------
|
||||
EXECUTABLE_BAT="bat"
|
||||
if [[ -z "$__LIB_CONSTANTS_INITIALIZED" ]]; then
|
||||
__LIB_CONSTANTS_INITIALIZED=true
|
||||
|
||||
# Constants: Executables
|
||||
EXECUTABLE_BAT="$(command -v bat 2>/dev/null || command -v batcat 2>/dev/null || echo "bat")"
|
||||
EXECUTABLE_GIT="git"
|
||||
EXECUTABLE_DELTA="delta"
|
||||
EXECUTABLE_RIPGREP="rg"
|
||||
EXECUTABLE_FZF="fzf"
|
||||
|
||||
# Constants: Program
|
||||
PROGRAM="$(basename "$0" .sh)"
|
||||
PROGRAM_HOMEPAGE="https://github.com/eth-p/bat-extras"
|
||||
PROGRAM_COPYRIGHT="Copyright (C) 2019-2020 eth-p | MIT License"
|
||||
PROGRAM_COPYRIGHT="Copyright (C) 2019-2021 eth-p | MIT License"
|
||||
PROGRAM_VERSION="$({
|
||||
TOP="$(dirname "$(dirname "${BASH_SOURCE[0]}")")"
|
||||
printf "%s" "$(cat "${TOP}/version.txt" 2>/dev/null || echo "unknown")"
|
||||
if [[ -e "${TOP}/.git" ]]; then
|
||||
printf "%s-git (%s)" "" "$(git -C "${TOP}" rev-parse --short HEAD)"
|
||||
printf "%s-git (%s)" "" "$("${EXECUTABLE_GIT}" -C "${TOP}" rev-parse --short HEAD)"
|
||||
fi
|
||||
})"
|
||||
|
||||
fi
|
||||
|
|
|
|||
18
lib/dirs.sh
Normal file
18
lib/dirs.sh
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env bash
|
||||
# -----------------------------------------------------------------------------
|
||||
# bat-extras | Copyright (C) 2021 eth-p | MIT License
|
||||
#
|
||||
# Repository: https://github.com/eth-p/bat-extras
|
||||
# Issues: https://github.com/eth-p/bat-extras/issues
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Gets a configuration directory for a command-line program.
|
||||
# Arguments:
|
||||
# 1 -- The program name.
|
||||
config_dir() {
|
||||
if [[ -n "${XDG_CONFIG_HOME+x}" ]]; then
|
||||
echo "${XDG_CONFIG_HOME}/$1"
|
||||
else
|
||||
echo "${HOME}/.config/$1"
|
||||
fi
|
||||
}
|
||||
172
lib/dsl.sh
Normal file
172
lib/dsl.sh
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
#!/usr/bin/env bash
|
||||
# -----------------------------------------------------------------------------
|
||||
# bat-extras | Copyright (C) 2020 eth-p | MIT License
|
||||
#
|
||||
# ReRSTARTitory: https://github.com/eth-p/bat-extras
|
||||
# Issues: https://github.com/eth-p/bat-extras/issues
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Parses a DSL file.
|
||||
#
|
||||
# Arguments:
|
||||
# 1 -- The DSL file.
|
||||
dsl_parse_file() {
|
||||
dsl_parse < "$1"
|
||||
return $?
|
||||
}
|
||||
|
||||
# Parses DSL data.
|
||||
# This calls callback functions to handle the parsed data:
|
||||
#
|
||||
# Format:
|
||||
# | command arg1 arg2
|
||||
# | option arg1 arg2
|
||||
#
|
||||
# Callbacks:
|
||||
# dsl_on_raw "$indent" "$line" -- Called after every line.
|
||||
# dsl_on_command "$command" "$arg1" "$arg2" ... -- Called on command lines.
|
||||
# dsl_on_command_commit -- Called after commands and their options.
|
||||
# dsl_on_option "$option" "$arg1" "$arg2" ... -- Called on option lines.
|
||||
#
|
||||
# Variables:
|
||||
# DSL_LINE_NUMBER -- The line number being parsed at the time of a callback.
|
||||
# DSL_COMMAND -- The command being parsed at the time of a callback.
|
||||
#
|
||||
# Input:
|
||||
# The DSL data to parse.
|
||||
dsl_parse() {
|
||||
local line
|
||||
local line_raw
|
||||
local line_fields
|
||||
local indent
|
||||
local command
|
||||
|
||||
DSL_LINE_NUMBER=0
|
||||
DSL_COMMAND=''
|
||||
while IFS='' read -r line_raw; do
|
||||
((DSL_LINE_NUMBER++)) || true
|
||||
|
||||
# Parse the indentation.
|
||||
# If the indentation is greater than zero, it's considered an option.
|
||||
[[ "$line_raw" =~ ^( |[[:space:]]{2,}) ]] || true
|
||||
indent="${BASH_REMATCH[1]}"
|
||||
line="${line_raw:${#indent}}"
|
||||
|
||||
if [[ -n "$line" ]] && ! [[ "$line" =~ ^# ]]; then
|
||||
# Parse the line items.
|
||||
eval "$(dsl_parse_line <<< "$line")"
|
||||
|
||||
# Call the appropriate on_* function.
|
||||
if [[ "${#indent}" -eq 0 ]]; then
|
||||
if [[ -n "$DSL_COMMAND" ]]; then
|
||||
dsl_on_command_commit
|
||||
fi
|
||||
|
||||
DSL_COMMAND="${line_fields[0]}"
|
||||
dsl_on_command "${line_fields[@]}"
|
||||
else
|
||||
dsl_on_option "${line_fields[@]}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Call the on_raw function.
|
||||
# This function can be used to echo back a line to rewrite the file.
|
||||
dsl_on_raw "$indent" "$line"
|
||||
done
|
||||
|
||||
if [[ -n "$DSL_COMMAND" ]]; then
|
||||
dsl_on_command_commit
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Parses a line into fields.
|
||||
# This parses fields with a bash-like command parameter syntax:
|
||||
#
|
||||
# "arg 1" "" arg3
|
||||
#
|
||||
# Input:
|
||||
# The line to parse.
|
||||
#
|
||||
# Output:
|
||||
# A series of bash statemtents that write the fields into an array named "line_fields".
|
||||
dsl_parse_line() {
|
||||
awk '
|
||||
{
|
||||
print "line_fields=()"
|
||||
n=0
|
||||
buffer=""
|
||||
quoted=0
|
||||
while ($0 != "") {
|
||||
quoted_once=0
|
||||
while ($0 != "") {
|
||||
# Match " ", "\", or quote.
|
||||
if (!match($0, /[\t \\"]/)) {
|
||||
buffer=sprintf("%s%s", buffer, $0)
|
||||
$0=""
|
||||
break
|
||||
}
|
||||
|
||||
# Extract the character and previous literal string.
|
||||
buffer=sprintf("%s%s", buffer, substr($0, 0, RSTART - 1))
|
||||
chr=substr($0, RSTART, RLENGTH)
|
||||
$0=substr($0, RSTART + RLENGTH)
|
||||
|
||||
# Handle the matched character.
|
||||
if (chr == "\\") {
|
||||
buffer=sprintf("%s%s", buffer, substr($0, 0, 1))
|
||||
$0=substr($0, 2)
|
||||
continue
|
||||
}
|
||||
|
||||
if (chr == "\"") {
|
||||
quoted=!quoted
|
||||
quoted_once=1
|
||||
continue
|
||||
}
|
||||
|
||||
if ((chr == " " || chr == "\t") && quoted) {
|
||||
buffer=sprintf("%s ", buffer)
|
||||
continue
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
# If the buffer is empty and it is not intentionally empty,
|
||||
# it should not be considered a separate field.
|
||||
if (buffer == "" && !quoted_once) {
|
||||
continue
|
||||
}
|
||||
|
||||
# Escape the parsed value.
|
||||
sub(/"/, "\\\"", buffer)
|
||||
sub(/\$/, "\\$", buffer)
|
||||
|
||||
# Print the parsed value.
|
||||
print sprintf("line_fields[%s]=\"%s\"", n, buffer)
|
||||
buffer=""
|
||||
n=n+1
|
||||
}
|
||||
}
|
||||
'
|
||||
}
|
||||
|
||||
dsl_on_raw() {
|
||||
# Stub
|
||||
:
|
||||
}
|
||||
|
||||
#
|
||||
#dsl_on_command() {
|
||||
# :
|
||||
#}
|
||||
#
|
||||
#dsl_on_command_commit() {
|
||||
# :
|
||||
#}
|
||||
#
|
||||
#dsl_on_option() {
|
||||
# :
|
||||
#}
|
||||
122
lib/opt.sh
122
lib/opt.sh
|
|
@ -1,19 +1,86 @@
|
|||
#!/usr/bin/env bash
|
||||
# -----------------------------------------------------------------------------
|
||||
# bat-extras | Copyright (C) 2019 eth-p | MIT License
|
||||
# bat-extras | Copyright (C) 2019-2020 eth-p | MIT License
|
||||
#
|
||||
# Repository: https://github.com/eth-p/bat-extras
|
||||
# Issues: https://github.com/eth-p/bat-extras/issues
|
||||
# -----------------------------------------------------------------------------
|
||||
source "${LIB}/constants.sh"
|
||||
|
||||
# An array of functions to call before returning from `shiftopt`.
|
||||
#
|
||||
# If one of these functions returns a successful exit code, the
|
||||
# option will be transparently skipped instead of handled.
|
||||
SHIFTOPT_HOOKS=()
|
||||
|
||||
# A setting to change how `shiftopt` will interpret short options that consist
|
||||
# of more than one character.
|
||||
#
|
||||
# Values:
|
||||
#
|
||||
# SPLIT -- Splits the option into multiple single-character short options.
|
||||
# "-abc" -> ("-a" "-b" "-c")
|
||||
#
|
||||
# VALUE -- Uses the remaining characters as the value for the short option.
|
||||
# "-abc" -> ("-a=bc")
|
||||
#
|
||||
# CONV -- Converts the argument to a long option.
|
||||
# "-abc" -> ("--abc")
|
||||
#
|
||||
# PASS -- Pass the argument along as-is.
|
||||
# "-abc" -> ("-abc")
|
||||
#
|
||||
SHIFTOPT_SHORT_OPTIONS="VALUE"
|
||||
|
||||
# Sets the internal _ARGV, _ARGV_INDEX, and _ARGV_LAST variables used when
|
||||
# parsing options with the shiftopt and shiftval functions.
|
||||
#
|
||||
# Arguments:
|
||||
# ... -- The program arguments.
|
||||
#
|
||||
# Example:
|
||||
# setargs "--long=3" "file.txt"
|
||||
setargs() {
|
||||
_ARGV=("$@")
|
||||
_ARGV_LAST="$((${#_ARGV[@]} - 1))"
|
||||
_ARGV_INDEX=0
|
||||
_ARGV_SUBINDEX=1
|
||||
}
|
||||
|
||||
# Gets all the remaining unparsed arguments and saves them to a variable.
|
||||
#
|
||||
# Arguments:
|
||||
# "-a" -- Append the arguments to the variable instead of replacing it.
|
||||
# $1 -- The variable to save the args to.
|
||||
#
|
||||
# Example:
|
||||
# getargs remaining_args
|
||||
getargs() {
|
||||
if [[ "$1" = "-a" || "$1" = "--append" ]]; then
|
||||
if [[ "${_ARGV_INDEX}" -ne "$((_ARGV_LAST+1))" ]]; then
|
||||
eval "$2=(\"\${$2[@]}\" $(printf '%q ' "${_ARGV[@]:$_ARGV_INDEX}"))"
|
||||
fi
|
||||
else
|
||||
if [[ "${_ARGV_INDEX}" -ne "$((_ARGV_LAST+1))" ]]; then
|
||||
eval "$1=($(printf '%q ' "${_ARGV[@]:$_ARGV_INDEX}"))"
|
||||
else
|
||||
eval "$1=()"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Resets the internal _ARGV* variables to the original script arguments.
|
||||
# This is the equivalent of storing the top-level $@ and using setargs with it.
|
||||
resetargs() {
|
||||
setargs "${_ARGV_ORIGINAL[@]}"
|
||||
}
|
||||
|
||||
# INTERNAL.
|
||||
#
|
||||
# Increments the argv index pointer used by `shiftopt`.
|
||||
_shiftopt_next() {
|
||||
_ARGV_SUBINDEX=1
|
||||
((_ARGV_INDEX++)) || true
|
||||
}
|
||||
|
||||
# Gets the next option passed to the script.
|
||||
|
|
@ -36,13 +103,47 @@ shiftopt() {
|
|||
OPT="${_ARGV[$_ARGV_INDEX]}"
|
||||
unset OPT_VAL
|
||||
|
||||
if [[ "$OPT" =~ ^--[a-zA-Z0-9_-]+=.* ]]; then
|
||||
if [[ "$OPT" =~ ^-[a-zA-Z0-9_-]+=.* ]]; then
|
||||
OPT_VAL="${OPT#*=}"
|
||||
OPT="${OPT%%=*}"
|
||||
fi
|
||||
|
||||
# Handle short options.
|
||||
if [[ "$OPT" =~ ^-[^-]{2,} ]]; then
|
||||
case "$SHIFTOPT_SHORT_OPTIONS" in
|
||||
# PASS mode: "-abc=0" -> ("-abc=0")
|
||||
PASS) _shiftopt_next ;;
|
||||
|
||||
# Pop array.
|
||||
((_ARGV_INDEX++))
|
||||
# CONV mode: "-abc=0" -> ("--abc=0")
|
||||
CONV) OPT="-${OPT}"; _shiftopt_next ;;
|
||||
|
||||
# VALUE mode: "-abc=0" -> ("-a=bc=0")
|
||||
VALUE) {
|
||||
OPT="${_ARGV[$_ARGV_INDEX]}"
|
||||
OPT_VAL="${OPT:2}"
|
||||
OPT="${OPT:0:2}"
|
||||
_shiftopt_next
|
||||
} ;;
|
||||
|
||||
# SPLIT mode: "-abc=0" -> ("-a=0" "-b=0" "-c=0")
|
||||
SPLIT) {
|
||||
OPT="-${OPT:$_ARGV_SUBINDEX:1}"
|
||||
((_ARGV_SUBINDEX++)) || true
|
||||
if [[ "$_ARGV_SUBINDEX" -gt "${#OPT}" ]]; then
|
||||
_shiftopt_next
|
||||
fi
|
||||
} ;;
|
||||
|
||||
# ????? mode: Treat it as pass.
|
||||
*)
|
||||
printf "shiftopt: unknown SHIFTOPT_SHORT_OPTIONS mode '%s'" \
|
||||
"$SHIFTOPT_SHORT_OPTIONS" 1>&2
|
||||
_shiftopt_next
|
||||
;;
|
||||
esac
|
||||
else
|
||||
_shiftopt_next
|
||||
fi
|
||||
|
||||
# Handle hooks.
|
||||
local hook
|
||||
|
|
@ -69,9 +170,15 @@ shiftval() {
|
|||
if [[ -n "${OPT_VAL+x}" ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
OPT_VAL="${_ARGV[$_ARGV_INDEX]}"
|
||||
((_ARGV_INDEX++))
|
||||
|
||||
if [[ "$_ARGV_SUBINDEX" -gt 1 && "$SHIFTOPT_SHORT_OPTIONS" = "SPLIT" ]]; then
|
||||
# If it's a short group argument in SPLIT mode, we grab the next argument.
|
||||
OPT_VAL="${_ARGV[$((_ARGV_INDEX+1))]}"
|
||||
else
|
||||
# Otherwise, we can handle it normally.
|
||||
OPT_VAL="${_ARGV[$_ARGV_INDEX]}"
|
||||
_shiftopt_next
|
||||
fi
|
||||
|
||||
# Error if no value is provided.
|
||||
if [[ "$OPT_VAL" =~ -.* ]]; then
|
||||
|
|
@ -82,3 +189,4 @@ shiftval() {
|
|||
|
||||
# -----------------------------------------------------------------------------
|
||||
setargs "$@"
|
||||
_ARGV_ORIGINAL=("$@")
|
||||
|
|
|
|||
32
lib/opt_hook_help.sh
Normal file
32
lib/opt_hook_help.sh
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#!/usr/bin/env bash
|
||||
# -----------------------------------------------------------------------------
|
||||
# bat-extras | Copyright (C) 2019-2020 eth-p | MIT License
|
||||
#
|
||||
# Repository: https://github.com/eth-p/bat-extras
|
||||
# Issues: https://github.com/eth-p/bat-extras/issues
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Option parser hook: --help support.
|
||||
# This will accept -h or --help, which prints the usage information and exits.
|
||||
hook_help() {
|
||||
SHIFTOPT_HOOKS+=("__shiftopt_hook__help")
|
||||
if [[ "$1" == "--no-short" ]]; then
|
||||
__shiftopt_hook__help() {
|
||||
if [[ "$OPT" = "--help" ]]; then
|
||||
show_help
|
||||
exit 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
else
|
||||
__shiftopt_hook__help() {
|
||||
if [[ "$OPT" = "--help" ]] || [[ "$OPT" = "-h" ]]; then
|
||||
show_help
|
||||
exit 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
fi
|
||||
}
|
||||
28
lib/opt_hook_width.sh
Normal file
28
lib/opt_hook_width.sh
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#!/usr/bin/env bash
|
||||
# -----------------------------------------------------------------------------
|
||||
# bat-extras | Copyright (C) 2019 eth-p | MIT License
|
||||
#
|
||||
# Repository: https://github.com/eth-p/bat-extras
|
||||
# Issues: https://github.com/eth-p/bat-extras/issues
|
||||
# -----------------------------------------------------------------------------
|
||||
source "${LIB}/term.sh"
|
||||
|
||||
# Option parser hook: --terminal-width support.
|
||||
# This will accept --terminal-width=number.
|
||||
#
|
||||
# The variable OPT_TERMINAL_WIDTH will be set.
|
||||
hook_width() {
|
||||
SHIFTOPT_HOOKS+=("__shiftopt_hook__width")
|
||||
__shiftopt_hook__width() {
|
||||
case "$OPT" in
|
||||
|
||||
--terminal-width) shiftval; OPT_TERMINAL_WIDTH="$OPT_VAL" ;;
|
||||
|
||||
*) return 1 ;;
|
||||
esac
|
||||
return 0
|
||||
}
|
||||
|
||||
# Default terminal width.
|
||||
OPT_TERMINAL_WIDTH="$(term_width)"
|
||||
}
|
||||
60
lib/pager.sh
60
lib/pager.sh
|
|
@ -12,6 +12,12 @@ is_pager_less() {
|
|||
return $?
|
||||
}
|
||||
|
||||
# Returns 0 (true) if the current pager is bat, otherwise 1 (false).
|
||||
is_pager_bat() {
|
||||
[[ "$(pager_name)" = "bat" ]]
|
||||
return $?
|
||||
}
|
||||
|
||||
# Returns 0 (true) if the current pager is disabled, otherwise 1 (false).
|
||||
is_pager_disabled() {
|
||||
[[ -z "$(pager_name)" ]]
|
||||
|
|
@ -20,13 +26,13 @@ is_pager_disabled() {
|
|||
|
||||
# Prints the detected pager name.
|
||||
pager_name() {
|
||||
_detect_pager
|
||||
_detect_pager 1>&2
|
||||
echo "$_SCRIPT_PAGER_NAME"
|
||||
}
|
||||
|
||||
# Prints the detected pager version.
|
||||
pager_version() {
|
||||
_detect_pager
|
||||
_detect_pager 1>&2
|
||||
echo "$_SCRIPT_PAGER_VERSION"
|
||||
}
|
||||
|
||||
|
|
@ -36,14 +42,12 @@ pager_version() {
|
|||
# Example:
|
||||
# pager_exec echo hi
|
||||
pager_exec() {
|
||||
if [[ -n "$1" ]]; then
|
||||
if [[ -n "$SCRIPT_PAGER_CMD" ]]; then
|
||||
"$@" | "${SCRIPT_PAGER_CMD[@]}" "${SCRIPT_PAGER_ARGS[@]}"
|
||||
return $?
|
||||
else
|
||||
"$@"
|
||||
return $?
|
||||
fi
|
||||
if [[ -n "$SCRIPT_PAGER_CMD" ]]; then
|
||||
"$@" | pager_display
|
||||
return $?
|
||||
else
|
||||
"$@"
|
||||
return $?
|
||||
fi
|
||||
}
|
||||
|
||||
|
|
@ -53,9 +57,16 @@ pager_exec() {
|
|||
# bat | pager_display
|
||||
pager_display() {
|
||||
if [[ -n "$SCRIPT_PAGER_CMD" ]]; then
|
||||
"${SCRIPT_PAGER_CMD[@]}" "${SCRIPT_PAGER_ARGS[@]}"
|
||||
if [[ -n "$SCRIPT_PAGER_ARGS" ]]; then
|
||||
"${SCRIPT_PAGER_CMD[@]}" "${SCRIPT_PAGER_ARGS[@]}"
|
||||
return $?
|
||||
else
|
||||
"${SCRIPT_PAGER_CMD[@]}"
|
||||
return $?
|
||||
fi
|
||||
else
|
||||
cat
|
||||
return $?
|
||||
fi
|
||||
}
|
||||
|
||||
|
|
@ -64,7 +75,7 @@ pager_display() {
|
|||
# Detect the pager information.
|
||||
# shellcheck disable=SC2120
|
||||
_detect_pager() {
|
||||
if [[ "$_SCRIPT_PAGER_DETECTED" = "true" && "$1" != "--force" ]]; then return; fi
|
||||
if [[ "$_SCRIPT_PAGER_DETECTED" = "true" ]]; then return; fi
|
||||
_SCRIPT_PAGER_DETECTED=true
|
||||
|
||||
# If the pager command is empty, the pager is disabled.
|
||||
|
|
@ -81,9 +92,13 @@ _detect_pager() {
|
|||
output1="$(head -n 1 <<<"$output")"
|
||||
|
||||
if [[ "$output1" =~ ^less[[:blank:]]([[:digit:]]+) ]]; then
|
||||
# shellcheck disable=SC2001
|
||||
_SCRIPT_PAGER_VERSION="${BASH_REMATCH[1]}"
|
||||
_SCRIPT_PAGER_NAME="less"
|
||||
elif [[ "$output1" =~ ^bat(cat)?[[:blank:]]([[:digit:]]+) ]]; then
|
||||
# shellcheck disable=SC2034
|
||||
__BAT_VERSION="${BASH_REMATCH[2]}"
|
||||
_SCRIPT_PAGER_VERSION="${BASH_REMATCH[2]}"
|
||||
_SCRIPT_PAGER_NAME="bat"
|
||||
else
|
||||
_SCRIPT_PAGER_VERSION=0
|
||||
_SCRIPT_PAGER_NAME="$(basename "${SCRIPT_PAGER_CMD[0]}")"
|
||||
|
|
@ -97,10 +112,15 @@ _detect_pager() {
|
|||
# 2. Use PAGER with special arguments for less
|
||||
# 3. Use PAGER
|
||||
_configure_pager() {
|
||||
SCRIPT_PAGER_CMD=("$PAGER")
|
||||
# shellcheck disable=SC2206
|
||||
SCRIPT_PAGER_ARGS=()
|
||||
if [[ -n "${PAGER+x}" ]]; then
|
||||
SCRIPT_PAGER_CMD=($PAGER)
|
||||
else
|
||||
SCRIPT_PAGER_CMD=("less")
|
||||
fi
|
||||
|
||||
# Prefer the bat pager.
|
||||
# Prefer the BAT_PAGER environment variable.
|
||||
if [[ -n "${BAT_PAGER+x}" ]]; then
|
||||
# [note]: This is intentional.
|
||||
# shellcheck disable=SC2206
|
||||
|
|
@ -108,12 +128,18 @@ _configure_pager() {
|
|||
SCRIPT_PAGER_ARGS=()
|
||||
return
|
||||
fi
|
||||
|
||||
# If the pager is bat, use less instead.
|
||||
if is_pager_bat; then
|
||||
SCRIPT_PAGER_CMD=("less")
|
||||
SCRIPT_PAGER_ARGS=()
|
||||
fi
|
||||
|
||||
# Add arguments for the less pager.
|
||||
if is_pager_less; then
|
||||
SCRIPT_PAGER_ARGS=(-R --quit-if-one-screen)
|
||||
SCRIPT_PAGER_CMD=("${SCRIPT_PAGER_CMD[0]}" -R --quit-if-one-screen)
|
||||
if [[ "$(pager_version)" -lt 500 ]]; then
|
||||
SCRIPT_PAGER_ARGS+=(--no-init)
|
||||
SCRIPT_PAGER_CMD+=(--no-init)
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
|
|
|||
26
lib/path.sh
Normal file
26
lib/path.sh
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#!/usr/bin/env bash
|
||||
# -----------------------------------------------------------------------------
|
||||
# bat-extras | Copyright (C) 2021 eth-p | MIT License
|
||||
#
|
||||
# Repository: https://github.com/eth-p/bat-extras
|
||||
# Issues: https://github.com/eth-p/bat-extras/issues
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Gets the file extension from a file path.
|
||||
# Arguments:
|
||||
# 1 -- The file path.
|
||||
extname() {
|
||||
local file="$1"
|
||||
echo ".${file##*.}"
|
||||
}
|
||||
|
||||
# Strips trailing slashes from a file path.
|
||||
# Arguments:
|
||||
# 1 -- The file path.
|
||||
strip_trailing_slashes() {
|
||||
local file="$1"
|
||||
while [[ -n "$file" && "${file: -1}" = "/" ]]; do
|
||||
file="${file:0:$((${#file}-1))}"
|
||||
done
|
||||
echo "$file"
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
# -----------------------------------------------------------------------------
|
||||
# bat-extras | Copyright (C) 2019 eth-p | MIT License
|
||||
# bat-extras | Copyright (C) 2021 eth-p | MIT License
|
||||
#
|
||||
# Repository: https://github.com/eth-p/bat-extras
|
||||
# Issues: https://github.com/eth-p/bat-extras/issues
|
||||
|
|
@ -44,7 +44,7 @@ printc_init() {
|
|||
_PRINTC_PATTERN_ANSI="${_PRINTC_PATTERN_ANSI}s/%{${name}}/${ansi}/g;"
|
||||
done
|
||||
|
||||
if [ -t 1 ]; then
|
||||
if [[ -t 1 && -z "${NO_COLOR+x}" ]]; then
|
||||
_PRINTC_PATTERN="$_PRINTC_PATTERN_ANSI"
|
||||
else
|
||||
_PRINTC_PATTERN="$_PRINTC_PATTERN_PLAIN"
|
||||
|
|
@ -81,5 +81,6 @@ printc_init "[DEFINE]" <<END
|
|||
MAGENTA \x1B[35m
|
||||
CYAN \x1B[36m
|
||||
|
||||
DEFAULT \x1B[39m
|
||||
DIM \x1B[2m
|
||||
END
|
||||
|
|
|
|||
70
lib/proc.sh
Normal file
70
lib/proc.sh
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
#!/usr/bin/env bash
|
||||
# -----------------------------------------------------------------------------
|
||||
# bat-extras | Copyright (C) 2021 eth-p | MIT License
|
||||
#
|
||||
# Repository: https://github.com/eth-p/bat-extras
|
||||
# Issues: https://github.com/eth-p/bat-extras/issues
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Gets the path to the parent executable file.
|
||||
# Arguments:
|
||||
# 1 -- The target pid. If not provided, the script's parent is used.
|
||||
parent_executable() {
|
||||
local target_pid="${1:-$PPID}"
|
||||
ps -f -p "$target_pid" | tail -n 1 | awk '{for(i=8;i<=NF;i++) printf $i" "; printf "\n"}'
|
||||
}
|
||||
|
||||
# Gets the PID of the parent executable file.
|
||||
# Arguments:
|
||||
# 1 -- The target pid. If not provided, the script's parent is used.
|
||||
parent_executable_pid() {
|
||||
local target_pid="${1:-$PPID}"
|
||||
ps -f -p "$target_pid" | tail -n 1 | awk '{print $3}'
|
||||
}
|
||||
|
||||
# Gets the path to the parent login shell.
|
||||
# Arguments:
|
||||
# 1 -- The target pid. If not provided, the script's parent is used.
|
||||
parent_shell() {
|
||||
local target_pid="${1:-$PPID}"
|
||||
local target_name
|
||||
while true; do
|
||||
{
|
||||
read -r target_pid
|
||||
read -r target_name
|
||||
|
||||
# If the parent process starts with a "-", it's a login shell.
|
||||
if [[ "${target_name:0:1}" = "-" ]]; then
|
||||
target_name="$(cut -f1 -d' ' <<< "${target_name:1}")"
|
||||
break
|
||||
fi
|
||||
|
||||
# If the parent process is one of:
|
||||
# - `*sh`; or
|
||||
# - `nu`
|
||||
# Followed by "-l", it's probably a login shell.
|
||||
if [[ "$target_name" =~ ^(.*sh|nu)\ .*-l ]]; then
|
||||
target_name="$(cut -f1 -d' ' <<< "${target_name}")"
|
||||
break
|
||||
fi
|
||||
|
||||
# If the parent process is pid 0 (init), then we haven't found a parent shell.
|
||||
# At this point, it's best to assume the shell is whatever is defined in $SHELL.
|
||||
if [[ "$target_pid" -eq 0 ]]; then
|
||||
target_name="$SHELL"
|
||||
break
|
||||
fi
|
||||
} < <({
|
||||
ps -f -p "$target_pid" \
|
||||
| tail -n 1 \
|
||||
| awk '{print $3; for(i=8;i<=NF;i++) printf $i" "; printf "\n"}'
|
||||
})
|
||||
done
|
||||
|
||||
# Ensure that the detected shell is an executable path.
|
||||
if [[ -f "$target_name" ]]; then
|
||||
echo "$target_name"
|
||||
elif ! command -v "$target_name" 2>/dev/null; then
|
||||
echo "$target_name" # It's not, but we have nothing else we can do here.
|
||||
fi
|
||||
}
|
||||
28
lib/term.sh
Normal file
28
lib/term.sh
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
# ----------------------------------------------------------------------------------------------------------------------
|
||||
# bat-extras | Copyright (C) 2020 eth-p | MIT License
|
||||
#
|
||||
# Repository: https://github.com/eth-p/bat-extras
|
||||
# Issues: https://github.com/eth-p/bat-extras/issues
|
||||
# ----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
# Gets the width of the terminal.
|
||||
# This will return 80 unless stdin is attached to the terminal.
|
||||
#
|
||||
# Returns:
|
||||
# The terminal width, or 80 if there's no TTY.
|
||||
#
|
||||
term_width() {
|
||||
# shellcheck disable=SC2155
|
||||
local width="$({ stty size 2>/dev/null || echo "22 80"; } | cut -d ' ' -f2)"
|
||||
if [[ "$width" -ne 0 ]]; then
|
||||
echo "$width"
|
||||
else
|
||||
echo "80"
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Clears the terminal using the ANSI escape sequences for erase screen and cursor absolute positioning.
|
||||
term_clear() {
|
||||
printf "\x1B[3J\x1B[2J\x1B[H"
|
||||
}
|
||||
|
|
@ -8,8 +8,11 @@
|
|||
|
||||
# Gets the current bat version.
|
||||
bat_version() {
|
||||
"$EXECUTABLE_BAT" --version | cut -d ' ' -f 2
|
||||
return
|
||||
if [[ -z "${__BAT_VERSION}" ]]; then
|
||||
__BAT_VERSION="$(command "$EXECUTABLE_BAT" --version | cut -d ' ' -f 2)"
|
||||
fi
|
||||
|
||||
echo "${__BAT_VERSION}"
|
||||
}
|
||||
|
||||
# Compares two version strings.
|
||||
|
|
|
|||
382
mdroff.sh
Executable file
382
mdroff.sh
Executable file
|
|
@ -0,0 +1,382 @@
|
|||
#!/usr/bin/env bash
|
||||
# -----------------------------------------------------------------------------
|
||||
# bat-extras | Copyright (C) 2020 eth-p | MIT License
|
||||
#
|
||||
# Repository: https://github.com/eth-p/bat-extras
|
||||
# Issues: https://github.com/eth-p/bat-extras/issues
|
||||
# -----------------------------------------------------------------------------
|
||||
# shellcheck disable=SC2021
|
||||
# shellcheck disable=SC2155
|
||||
|
||||
printf_msg() {
|
||||
# shellcheck disable=SC2059
|
||||
printf "$@" 1>&2
|
||||
}
|
||||
|
||||
printf_err() {
|
||||
# shellcheck disable=SC2059
|
||||
printf "$@" 1>&2
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# MDroff:
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
mdroff:emit:h1() {
|
||||
printf '.TH "%s" 1\n' "$1"
|
||||
}
|
||||
|
||||
mdroff:emit:h2() {
|
||||
printf '.SH "%s"\n' "$1"
|
||||
}
|
||||
|
||||
mdroff:emit:h3() {
|
||||
printf '.SS "%s"\n' "$1"
|
||||
}
|
||||
|
||||
mdroff:emit:h4() {
|
||||
printf '.SS "%s"\n' "$1"
|
||||
}
|
||||
|
||||
mdroff:emit:h5() {
|
||||
printf '.SS "%s"\n' "$1"
|
||||
}
|
||||
|
||||
mdroff:emit:line() {
|
||||
if "$MDROFF_PARAGRAPH"; then
|
||||
MDROFF_PARAGRAPH=false
|
||||
printf ".P\n%s\n" "$1"
|
||||
else
|
||||
printf ".br\n%s\n" "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
mdroff:emit:attr() {
|
||||
printf '\\fR'
|
||||
|
||||
if "$MDROFF_ATTR_STRONG"; then
|
||||
printf '\\fB'
|
||||
fi
|
||||
|
||||
if "$MDROFF_ATTR_EMPHASIS"; then
|
||||
printf '\\fI'
|
||||
fi
|
||||
|
||||
if "$MDROFF_ATTR_CODE"; then
|
||||
printf '\\fI'
|
||||
fi
|
||||
}
|
||||
|
||||
mdroff:emit:link() {
|
||||
printf "%s" "$1"
|
||||
}
|
||||
|
||||
|
||||
# shellcheck disable=SC2034
|
||||
mdroff:emit:table_start() {
|
||||
printf ".TS\n"
|
||||
printf "tab(|) box;\n"
|
||||
|
||||
# Print Header Alignment
|
||||
local temp
|
||||
for temp in "$@"; do printf "| cB "; done
|
||||
printf "|\n"
|
||||
|
||||
# Print Separator
|
||||
for temp in "$@"; do printf "| _ "; done
|
||||
printf "|\n"
|
||||
|
||||
# Print Column Alignment
|
||||
local cols=("$@")
|
||||
printf "| "
|
||||
printf "%s0 |1 " "${cols:0:$((${#@}-1))}"
|
||||
printf "%s " "${cols[$((${#@}-1))]}"
|
||||
printf "|.\n"
|
||||
}
|
||||
|
||||
mdroff:emit:table_end() {
|
||||
printf ".TE\n\n"
|
||||
}
|
||||
|
||||
mdroff:emit:table_heading() {
|
||||
local heading="$(printf "| %s " "$@")"
|
||||
printf "%s\n" "${heading:1}"
|
||||
|
||||
# Prevent tbl warning.
|
||||
for temp in "${@:2}"; do printf "|"; done
|
||||
printf "\n"
|
||||
|
||||
# Start table data.
|
||||
printf ".SP\n"
|
||||
}
|
||||
|
||||
mdroff:emit:table_row() {
|
||||
local row="$(printf "| %s " "$@")"
|
||||
printf "%s\n" "${row:1}"
|
||||
}
|
||||
|
||||
mdroff:emit:text() {
|
||||
local text="$1"
|
||||
|
||||
text="${text//<br>/ }"
|
||||
text="${text//<br\/>/ }"
|
||||
text="${text//<br \/>/ }"
|
||||
|
||||
printf "%s" "$text"
|
||||
}
|
||||
|
||||
mdroff:emit() {
|
||||
local type="$1"
|
||||
local data="$2"
|
||||
|
||||
if type "mdroff:rewrite:${type}" &>/dev/null; then
|
||||
data="$("mdroff:rewrite:${type}" "${@:2}")"
|
||||
fi
|
||||
|
||||
if type "mdroff:emit_hook:${type}" &>/dev/null; then
|
||||
"mdroff:emit_hook:${type}" "$data" "${@:3}"
|
||||
return
|
||||
fi
|
||||
|
||||
"mdroff:emit:${type}" "$data" "${@:3}"
|
||||
}
|
||||
|
||||
mdroff:trim_right() {
|
||||
# shellcheck disable=SC2001
|
||||
sed 's/[[:space:]]*$//' <<< "$1"
|
||||
}
|
||||
|
||||
mdroff:trim() {
|
||||
sed 's/^[[:space:]]*//; s/[[:space:]]*$//' <<< "$1"
|
||||
}
|
||||
|
||||
mdroff:parseln() {
|
||||
MDROFF_ATTR_STRONG=false
|
||||
MDROFF_ATTR_EMPHASIS=false
|
||||
MDROFF_ATTR_CODE=false
|
||||
|
||||
local buffer="$1"
|
||||
local before
|
||||
local found
|
||||
local pos
|
||||
|
||||
while [[ "${#buffer}" -gt 0 ]]; do
|
||||
[[ "$buffer" =~ \*{1,3}|\`|\[([^\]]+)\]\(([^\)]+)\) ]] || {
|
||||
mdroff:emit text "$(mdroff:trim_right "$buffer")"
|
||||
mdroff:emit text $'\n'
|
||||
return
|
||||
}
|
||||
|
||||
found="${BASH_REMATCH[0]}"
|
||||
pos="$(awk -v search="$found" '{print index($0,search) - 1}' <<< "$buffer")"
|
||||
|
||||
before="${buffer:0:$pos}"
|
||||
buffer="${buffer:$(($pos + ${#found}))}"
|
||||
|
||||
mdroff:emit text "$before"
|
||||
case "$found" in
|
||||
'***')
|
||||
if "$MDROFF_ATTR_STRONG" && "$MDROFF_ATTR_EMPHASIS"; then
|
||||
MDROFF_ATTR_STRONG=false
|
||||
MDROFF_ATTR_EMPHASIS=false
|
||||
else
|
||||
MDROFF_ATTR_STRONG=true
|
||||
MDROFF_ATTR_EMPHASIS=true
|
||||
fi
|
||||
mdroff:emit attr
|
||||
;;
|
||||
|
||||
'**')
|
||||
if "$MDROFF_ATTR_STRONG"; then
|
||||
MDROFF_ATTR_STRONG=false
|
||||
else
|
||||
MDROFF_ATTR_STRONG=true
|
||||
fi
|
||||
mdroff:emit attr
|
||||
;;
|
||||
|
||||
'*')
|
||||
if "$MDROFF_ATTR_EMPHASIS"; then
|
||||
MDROFF_ATTR_EMPHASIS=false
|
||||
else
|
||||
MDROFF_ATTR_EMPHASIS=true
|
||||
fi
|
||||
mdroff:emit attr
|
||||
;;
|
||||
|
||||
'`')
|
||||
if "$MDROFF_ATTR_CODE"; then
|
||||
MDROFF_ATTR_CODE=false
|
||||
else
|
||||
MDROFF_ATTR_CODE=true
|
||||
fi
|
||||
mdroff:emit attr
|
||||
;;
|
||||
|
||||
|
||||
'['*)
|
||||
mdroff:emit link "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}"
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
mdroff() {
|
||||
MDROFF_HEADING_LEVEL=0
|
||||
MDROFF_HEADING=''
|
||||
MDROFF_ATTR_STRONG=false
|
||||
MDROFF_ATTR_EMPHASIS=false
|
||||
MDROFF_ATTR_CODE=false
|
||||
MDROFF_IN_TABLE=false
|
||||
MDROFF_PARAGRAPH=false
|
||||
MDROFF_TABLE_HEADER=()
|
||||
|
||||
local line
|
||||
local empty=0
|
||||
local empty_continue=0
|
||||
while IFS='' read -r line; do
|
||||
line="$(mdroff:parseln "$line")"
|
||||
|
||||
# Empty
|
||||
if [[ "$line" =~ ^[[:space:]]*$ ]]; then
|
||||
((empty_continue++)) || true
|
||||
if "$MDROFF_IN_TABLE"; then
|
||||
mdroff:emit table_end
|
||||
fi
|
||||
|
||||
MDROFF_PARAGRAPH=true
|
||||
MDROFF_TABLE_HEADER=()
|
||||
MDROFF_IN_TABLE=false
|
||||
continue
|
||||
fi
|
||||
|
||||
empty="$empty_continue"
|
||||
empty_continue=0
|
||||
|
||||
# Headings
|
||||
if [[ "$line" =~ ^(#{1,})[[:space:]]{1,}(.*)$ ]]; then
|
||||
local level="${#BASH_REMATCH[1]}"
|
||||
local text="${BASH_REMATCH[2]}"
|
||||
|
||||
MDROFF_HEADING_LEVEL="$level"
|
||||
MDROFF_HEADING="$text"
|
||||
|
||||
mdroff:emit "h${level}" "$text"
|
||||
MDROFF_PARAGRAPH=true
|
||||
continue
|
||||
fi
|
||||
|
||||
# Tables (Partially Supported)
|
||||
if [[ "$line" =~ ^[[:space:]]*\| ]]; then
|
||||
local raw_cells=()
|
||||
local cells=()
|
||||
local table_cell
|
||||
|
||||
line="$(sed 's/^[[:space:]]*|//; s/|[[:space:]]*$//' <<< "$line")"
|
||||
|
||||
# shellcheck disable=SC2206
|
||||
IFS='|' raw_cells=($line)
|
||||
for table_cell in "${raw_cells[@]}"; do
|
||||
cells+=("$(mdroff:trim "$table_cell")")
|
||||
done
|
||||
|
||||
if [[ "${cells[0]}" =~ ^[[:space:]]*-+[[:space:]]*$ ]]; then
|
||||
# Calculate the column alignments.
|
||||
local table_alignments=()
|
||||
local table_cell
|
||||
|
||||
for table_cell in "${cells[@]}"; do
|
||||
case "$table_cell" in
|
||||
:-*:)
|
||||
table_alignments+=('c')
|
||||
;;
|
||||
:-*)
|
||||
table_alignments+=('l')
|
||||
;;
|
||||
*-:)
|
||||
table_alignments+=('r')
|
||||
;;
|
||||
*)
|
||||
table_alignments+=('l') # Unknown, but let's assume left.
|
||||
esac
|
||||
done
|
||||
|
||||
# Emit the table start and table header.
|
||||
mdroff:emit table_start "${table_alignments[@]}"
|
||||
mdroff:emit table_heading "${MDROFF_TABLE_HEADER[@]}"
|
||||
MDROFF_TABLE_HEADER=()
|
||||
continue
|
||||
fi
|
||||
|
||||
if ! "$MDROFF_IN_TABLE"; then
|
||||
MDROFF_IN_TABLE=true
|
||||
MDROFF_TABLE_HEADER=("${cells[@]}")
|
||||
else
|
||||
if [[ "${#MDROFF_TABLE_HEADER[@]}" -ne 0 ]]; then
|
||||
mdroff:emit table_heading "${MDROFF_TABLE_HEADER[@]}"
|
||||
MDROFF_TABLE_HEADER=()
|
||||
fi
|
||||
|
||||
mdroff:emit table_row "${cells[@]}"
|
||||
fi
|
||||
|
||||
MDROFF_PARAGRAPH=true
|
||||
continue
|
||||
fi
|
||||
|
||||
mdroff:emit line "$line"
|
||||
done < <(sed 's/<br *\/?>//')
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# bat-extras:
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
mdroff:rewrite:h1() {
|
||||
emitted_name=false
|
||||
emitted_description=false
|
||||
sed 's/^bat-extras: //' <<< "$1" | tr '[[:lower:]]' '[[:upper:]]'
|
||||
}
|
||||
|
||||
|
||||
mdroff:emit_hook:h2() {
|
||||
case "$MDROFF_HEADING" in
|
||||
"Installation") return ;;
|
||||
"Issues?") return ;;
|
||||
esac
|
||||
|
||||
mdroff:emit:h2 "$(tr '[[:lower:]]' '[[:upper:]]' <<< "$1")"
|
||||
}
|
||||
|
||||
mdroff:emit_hook:line() {
|
||||
if [[ "$MDROFF_HEADING_LEVEL" = "1" ]] && [[ "$emitted_name" != true ]]; then
|
||||
emitted_name=true
|
||||
printf ".SH NAME\n%s - %s\n" "$(sed 's/^bat-extras: //' <<< "$MDROFF_HEADING" | tr '[[:upper:]]' '[[:lower:]]')" "$1"
|
||||
printf ".SH DESCRIPTION\n"
|
||||
return
|
||||
fi
|
||||
|
||||
case "$MDROFF_HEADING" in
|
||||
"Installation") return ;;
|
||||
"Issues?") return ;;
|
||||
esac
|
||||
|
||||
mdroff:emit:line "$@"
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Main:
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
if [[ "${#BASH_SOURCE[@]}" -eq 1 ]]; then
|
||||
case "$1" in
|
||||
"") mdroff ;;
|
||||
*) {
|
||||
if ! [ -f "$1" ]; then
|
||||
printf_err "%s: cannot find or read file %s\n" "$0" "$1"
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
mdroff < "$1"
|
||||
} ;;
|
||||
esac
|
||||
fi
|
||||
387
release.sh
387
release.sh
|
|
@ -1,143 +1,350 @@
|
|||
#!/usr/bin/env bash
|
||||
# -----------------------------------------------------------------------------
|
||||
# bat-extras | Copyright (C) 2019 eth-p | MIT License
|
||||
# bat-extras | Copyright (C) 2019-2023 eth-p | MIT License
|
||||
#
|
||||
# Repository: https://github.com/eth-p/bat-extras
|
||||
# Issues: https://github.com/eth-p/bat-extras/issues
|
||||
# -----------------------------------------------------------------------------
|
||||
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/build.sh"
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Release-as-a-Library Functions:
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Prints the path to the git workspace.
|
||||
if ! batextras:is_function_defined ::get_git_workspace; then
|
||||
batextras:get_git_workspace() {
|
||||
batextras:lazy_done "${FUNCNAME[0]}" \
|
||||
"$(batextras:get_project_directory)"
|
||||
}
|
||||
fi
|
||||
|
||||
# Prints the commit of the latest-tagged version of bat-extras.
|
||||
if ! batextras:is_function_defined ::get_current_commit; then
|
||||
batextras:get_current_commit() {
|
||||
batextras:lazy_done "${FUNCNAME[0]}" \
|
||||
"$(batextras:git rev-parse HEAD)"
|
||||
}
|
||||
fi
|
||||
|
||||
# Prints the commit of the latest-tagged version of bat-extras.
|
||||
if ! batextras:is_function_defined ::get_previous_tag_commit; then
|
||||
batextras:get_previous_tag_commit() {
|
||||
local latest_tag
|
||||
local before_latest_tag
|
||||
{
|
||||
read -r latest_tag
|
||||
read -r before_latest_tag
|
||||
} < <(batextras:git rev-list --tags --max-count=2)
|
||||
|
||||
# If the latest commit is a tag, go to the one before that.
|
||||
if [[ "$(batextras:get_current_commit)" = "$latest_tag" ]]; then
|
||||
latest_tag="${before_latest_tag}"
|
||||
fi
|
||||
|
||||
batextras:lazy_done "${FUNCNAME[0]}" "$latest_tag"
|
||||
}
|
||||
fi
|
||||
|
||||
# Prints the ref name of the latest-tagged version of bat-extras.
|
||||
if ! batextras:is_function_defined ::get_previous_tag_name; then
|
||||
batextras:get_previous_tag_name() {
|
||||
batextras:lazy_done "${FUNCNAME[0]}" \
|
||||
"$(batextras:git describe --tags --abbrev=0 "$(batextras:get_previous_tag_commit)")"
|
||||
}
|
||||
fi
|
||||
|
||||
# Returns the suffix for a day of the month.
|
||||
#
|
||||
# Arguments:
|
||||
# 1 -- The day number.
|
||||
#
|
||||
# Output:
|
||||
# The suffix.
|
||||
batextras:day_suffix() {
|
||||
case "$1" in
|
||||
11 | 12 | 13) echo "th" ;;
|
||||
*1) echo "st" ;;
|
||||
*2) echo "nd" ;;
|
||||
*3) echo "rd" ;;
|
||||
*) echo "th" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Runs `git` within the project directory.
|
||||
#
|
||||
# This takes the same arguments as git (with the exception of `-C`), and
|
||||
# does exactly what `git` would normally do.
|
||||
batextras:git() {
|
||||
git -C "$(batextras:get_git_workspace)" "$@"
|
||||
return $?
|
||||
}
|
||||
|
||||
# Creates the zipball for release.
|
||||
# YOU MUST BUILD THE PROJECT FIRST!
|
||||
#
|
||||
# Arguments:
|
||||
# 1 -- The absolute path to the output zip file.
|
||||
#
|
||||
# Stderr:
|
||||
# Messages.
|
||||
batextras:create_package() {
|
||||
local artifact="$1"
|
||||
local bin_dir man_dir doc_dir
|
||||
bin_dir="$(batextras:get_output_bin_directory)"
|
||||
man_dir="$(batextras:get_output_man_directory)"
|
||||
doc_dir="$(batextras:get_docs_directory)"
|
||||
|
||||
(
|
||||
# Remove the old zipball, if one exists.
|
||||
if [[ -f "$artifact" ]]; then
|
||||
rm "$artifact" || return $?
|
||||
fi
|
||||
|
||||
# Add the bin directory.
|
||||
cd "$(dirname -- "$bin_dir")" || return $?
|
||||
zip -r "$artifact" "$(basename -- "$bin_dir")"
|
||||
|
||||
# Add the doc directory.
|
||||
cd "$(dirname -- "$doc_dir")" || return $?
|
||||
zip -ru "$artifact" "$(basename -- "$doc_dir")"
|
||||
|
||||
# Add the man directory.
|
||||
if [[ -d "$man_dir" ]]; then
|
||||
cd "$(dirname -- "$man_dir")" || return $?
|
||||
zip -ru "$artifact" "$(basename -- "$man_dir")"
|
||||
fi
|
||||
) 1>&2
|
||||
}
|
||||
|
||||
# Generates a Markdown changelog for all changes between two commits.
|
||||
#
|
||||
# Arguments:
|
||||
# 1 -- The first commit, exclusive.
|
||||
# 2 -- The second commit, inclusive.
|
||||
# 3 -- A filter in regex.
|
||||
#
|
||||
# Output:
|
||||
# The changelog.
|
||||
batextras:generate_changelog() {
|
||||
local start_commit="$1"
|
||||
local end_commit="$2"
|
||||
local filter="${3}"
|
||||
|
||||
# Generate sed replacement patterns.
|
||||
local script_links=()
|
||||
local script_names=()
|
||||
local script script_name
|
||||
while read -r script; do
|
||||
script_name="$(basename "$script" .sh)"
|
||||
script_names+=("$script_name")
|
||||
done < <(batextras:get_source_paths)
|
||||
|
||||
local script_pattern
|
||||
script_pattern="$(printf 's/\\(%s\\)/`\\1`/;' "${script_names[@]}")"
|
||||
|
||||
# Generate the changelog.
|
||||
local changelog=''
|
||||
local commit
|
||||
local affected_module
|
||||
local commit_message
|
||||
while read -r commit; do
|
||||
commit_message="$(batextras:git show -s --format=%s "$commit")"
|
||||
|
||||
if ! [[ "$commit_message" =~ ^([a-z-]+):[[:space:]]*(.*)$ ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
affected_module="${BASH_REMATCH[1]}"
|
||||
|
||||
# Make module names consistent.
|
||||
case "$affected_module" in
|
||||
dev | lib | mdroff) affected_module="developer" ;;
|
||||
tests) affected_module="test" ;;
|
||||
doc) affected_module="docs" ;;
|
||||
esac
|
||||
|
||||
# Append to changelog.
|
||||
if [[ "$affected_module" =~ ^($filter)$ ]]; then
|
||||
changelog="$changelog"$'\n'" - ${commit_message}"
|
||||
fi
|
||||
done < <(batextras:git rev-list "${start_commit}..${end_commit}")
|
||||
|
||||
# Print the changelog.
|
||||
changelog="$(sed "$script_pattern" <<< "$changelog")"
|
||||
printf "%s\n" "${changelog:1}"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Generates the Markdown release notes.
|
||||
#
|
||||
# Arguments:
|
||||
# 1 -- The oldest commit, exclusive.
|
||||
# 2 -- The newest commit, inclusive.
|
||||
#
|
||||
# Output:
|
||||
# The changelog.
|
||||
batextras:generate_release_notes() {
|
||||
local commit_oldest="$1"
|
||||
local commit_newest="$2"
|
||||
local commit_newest_url="https://github.com/eth-p/bat-extras/tree/${commit_newest}"
|
||||
local date_str
|
||||
|
||||
# Get the commit date.
|
||||
local date_year date_month date_day date_month_text date_day_suffix
|
||||
read -r date_year date_month date_day date_month_text \
|
||||
< <(batextras:git show -s --format="%cd" --date="format:%Y %m %d %B" "$commit_newest")
|
||||
|
||||
date_day_suffix="$(batextras:day_suffix "$date_day")"
|
||||
date_str="${date_month_text} ${date_day}${date_day_suffix}, ${date_year}"
|
||||
|
||||
# For each built script, we want to:
|
||||
# - Get the name of the script.
|
||||
# - Get a link to the documentation.
|
||||
# - Add it to the filter for non-developer items.
|
||||
local script_name script_names script_links script_filters script_list_markdown
|
||||
script_links=()
|
||||
script_names=()
|
||||
script_filters=''
|
||||
|
||||
while read -r script; do
|
||||
script_name="$(basename "$script" .sh)"
|
||||
script_names+=("$script_name")
|
||||
script_links+=("[\`${script_name}\`](https://github.com/eth-p/bat-extras/blob/${commit_newest}/doc/${script_name}.md)")
|
||||
script_filters="${script_filters}|$(printf "%q" "$script_name")"
|
||||
done < <(batextras:get_source_paths)
|
||||
|
||||
script_filters="${script_filters:1}" # Remove the leading "|"
|
||||
script_list_markdown="$(printf "%s, " "${script_links[@]:0:$((${#script_links[@]} - 1))}")"
|
||||
script_list_markdown="${script_list_markdown}and ${script_links[$((${#script_links[@]} - 1))]}"
|
||||
|
||||
# Get the changelog.
|
||||
local changelog changelog_dev
|
||||
changelog="$(batextras:generate_changelog "$commit_oldest" "$commit_newest" "$script_filters")"
|
||||
changelog_dev="$(batextras:generate_changelog "$commit_oldest" "$commit_newest" "test|developer|ci|build")"
|
||||
|
||||
# Print the template.
|
||||
{ sed '/\\$/{N;s/\\\n//;s/\n//p;}'; } <<- EOF
|
||||
This contains the latest versions of ${script_list_markdown} as of commit [${commit_newest}](${commit_newest_url}) (${date_str}).
|
||||
|
||||
**This is provided as a convenience only.**
|
||||
I would still recommend following the installation instructions in [the README](https://github.com/eth-p/bat-extras#installation-) for the most up-to-date versions.
|
||||
|
||||
### Changes
|
||||
${changelog}
|
||||
|
||||
### Developer
|
||||
<details>
|
||||
<div markdown="1">
|
||||
|
||||
${changelog_dev}
|
||||
|
||||
</div>
|
||||
</details>
|
||||
EOF
|
||||
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Main:
|
||||
# Only run everything past this point if the script is not sourced.
|
||||
# -----------------------------------------------------------------------------
|
||||
(return 0 2>/dev/null) && return 0
|
||||
|
||||
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
DATE="$(date +%Y%m%d)"
|
||||
VERSION="$(<"${HERE}/version.txt")"
|
||||
VERSION="$(< "${HERE}/version.txt")"
|
||||
VERSION_EXPECTED="$(date +%Y.%m.%d)"
|
||||
LIB="$HERE/lib"
|
||||
SRC="$HERE/src"
|
||||
source "${LIB}/print.sh"
|
||||
source "${LIB}/opt.sh"
|
||||
# -----------------------------------------------------------------------------
|
||||
set -euo pipefail
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Options.
|
||||
OPT_ARTIFACT="bat-extras-${DATE}.zip"
|
||||
OPT_SINCE=
|
||||
OPT_BIN_DIR="$HERE/bin"
|
||||
OPT_DOC_DIR="$HERE/doc"
|
||||
OPT_BAD_IDEA=false
|
||||
OPT_BIN_DIR="$(batextras:get_output_bin_directory)"
|
||||
OPT_DOC_DIR="$(batextras:get_docs_directory)"
|
||||
OPT_MAN_DIR="$(batextras:get_output_man_directory)"
|
||||
|
||||
while shiftopt; do
|
||||
case "$OPT" in
|
||||
--since)
|
||||
shiftval
|
||||
OPT_SINCE="$OPT_VAL"
|
||||
if ! git rev-parse "$OPT_SINCE" &>/dev/null; then
|
||||
printc "%{RED}%s: unknown commit or tag for '%s'\n" "$PROGRAM" "$OPT"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
--since)
|
||||
shiftval
|
||||
OPT_SINCE="$OPT_VAL"
|
||||
if ! batextras:git rev-parse "$OPT_SINCE" &> /dev/null; then
|
||||
printc "%{RED}%s: unknown commit or tag for '%s'\n" "$PROGRAM" "$OPT"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
|
||||
*)
|
||||
printc "%{RED}%s: unknown option '%s'%{CLEAR}" "$PROGRAM" "$OPT"
|
||||
exit 1
|
||||
;;
|
||||
--badidea)
|
||||
OPT_BAD_IDEA=true
|
||||
;;
|
||||
|
||||
*)
|
||||
printc "%{RED}%s: unknown option '%s'%{CLEAR}" "$PROGRAM" "$OPT"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Verify the version matches today's date.
|
||||
if [[ "$VERSION" != "$VERSION_EXPECTED" ]]; then
|
||||
printc "%{RED}The expected version does not match %{WHITE}version.txt%{RED}!%{CLEAR}\n"
|
||||
|
||||
VERSION="$(source "${LIB}/constants.sh" && echo "${PROGRAM_VERSION}")"
|
||||
VERSION_EXPECTED="$(date +%Y.%m.%d)"
|
||||
|
||||
if [[ "$VERSION" != "$VERSION_EXPECTED" ]] && ! "$OPT_BAD_IDEA"; then
|
||||
printc "%{RED}The expected version does not match %{DEFAULT}version.txt%{RED}!%{CLEAR}\n"
|
||||
printc "%{RED}Expected: %{YELLOW}%s%{CLEAR}\n" "$VERSION_EXPECTED"
|
||||
printc "%{RED}Actual: %{YELLOW}%s%{CLEAR}\n" "$VERSION"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Verify the working tree is clean-ish.
|
||||
|
||||
if ! "$OPT_BAD_IDEA"; then
|
||||
while read -r flags file; do
|
||||
if [[ "$flags" =~ M ]]; then
|
||||
printc "%{RED}Found an uncommitted change in %{DEFAULT}%s%{RED}!%{CLEAR}\n" "$file"
|
||||
exit 1
|
||||
fi
|
||||
done < <(batextras:git status --porcelain)
|
||||
fi
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Build files.
|
||||
|
||||
# Clean the old bin files.
|
||||
# Make sure it's not trying to delete /bin first, though.
|
||||
if [[ "$OPT_BIN_DIR" != "/bin" ]]; then
|
||||
rm -rf "$OPT_BIN_DIR"
|
||||
fi
|
||||
# Clean the old files.
|
||||
# Make sure it's not trying to delete /bin or /man first, though.
|
||||
if [[ "$OPT_BIN_DIR" != "/bin" ]]; then rm -rf "$OPT_BIN_DIR"; fi
|
||||
if [[ "$OPT_MAN_DIR" != "/man" ]]; then rm -rf "$OPT_MAN_DIR"; fi
|
||||
|
||||
# Generate the new bin files.
|
||||
printc "%{YELLOW}Building scripts...%{CLEAR}\n"
|
||||
"$HERE/build.sh" --minify=all &>/dev/null || {
|
||||
"$HERE/build.sh" --minify=all --alternate-executable='bat' --no-inline &>/dev/null || {
|
||||
printc "%{RED}FAILED TO BUILD SCRIPTS.%{CLEAR}\n"
|
||||
printc "%{RED}CAN NOT PROCEED WITH RELEASE.%{CLEAR}\n"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Tag release.
|
||||
|
||||
if ! "$OPT_SKIP_TAG"; then
|
||||
printc "%{YELLOW}Tagging release...%{CLEAR}\n"
|
||||
git tag "$OPT_TAG"
|
||||
fi
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Build package.
|
||||
|
||||
printc "%{YELLOW}Packaging artifacts...%{CLEAR}\n"
|
||||
zip -r "$OPT_ARTIFACT" \
|
||||
"$OPT_BIN_DIR" \
|
||||
"$OPT_DOC_DIR"
|
||||
|
||||
batextras:create_package "$OPT_ARTIFACT"
|
||||
printc "%{YELLOW}Package created as %{BLUE}%s%{YELLOW}.%{CLEAR}\n" "$OPT_ARTIFACT"
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Print template description package.
|
||||
|
||||
printc "%{YELLOW}Release description:%{CLEAR}\n"
|
||||
|
||||
# Get the commit hash.
|
||||
COMMIT="$(git rev-parse HEAD)"
|
||||
|
||||
# Get the release date string.
|
||||
DATE_DAY="$(date +%e | sed 's/ //')"
|
||||
DATE_SUFFIX=""
|
||||
case "$DATE_DAY" in
|
||||
11|12|13) DATE_SUFFIX="th" ;;
|
||||
*1) DATE_SUFFIX="st" ;;
|
||||
*2) DATE_SUFFIX="nd" ;;
|
||||
*3) DATE_SUFFIX="rd" ;;
|
||||
*) DATE_SUFFIX="th" ;;
|
||||
esac
|
||||
DATE_STR="$(date +'%B') ${DATE_DAY}${DATE_SUFFIX}, $(date +'%Y')"
|
||||
|
||||
# Get the changelog.
|
||||
CHANGELOG=''
|
||||
if [[ -n "$OPT_SINCE" ]]; then
|
||||
ref="$(git rev-parse HEAD)"
|
||||
end="$(git rev-parse "$OPT_SINCE")"
|
||||
while [[ "$ref" != "$end" ]]; do
|
||||
ref_message="$(git show -s --format=%s "$ref")"
|
||||
ref="$(git rev-parse "${ref}~1")"
|
||||
|
||||
if [[ "$ref_message" =~ ^([a-z]):[[:space:]]*(.*)$ ]]; then
|
||||
ref_message="\`${BASH_REMATCH[1]}\`: ${BASH_REMATCH[2]}"
|
||||
fi
|
||||
|
||||
# Append to changelog.
|
||||
if [[ -z "$CHANGELOG" ]]; then
|
||||
CHANGELOG=" - ${ref_message}"
|
||||
else
|
||||
CHANGELOG="$CHANGELOG"$'\n'" - ${ref_message}"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Print the template.
|
||||
sed '/\\$/{N;s/\\\n//;s/\n//p;}' <<-EOF
|
||||
This contains the latest versions of \
|
||||
[\`batgrep\`](https://github.com/eth-p/bat-extras/blob/${COMMIT}/doc/batgrep.md), \
|
||||
[\`batman\`](https://github.com/eth-p/bat-extras/blob/${COMMIT}/doc/batman.md), \
|
||||
[\`batwatch\`](https://github.com/eth-p/bat-extras/blob/${COMMIT}/doc/batwatch.md), and \
|
||||
[\`prettybat\`](https://github.com/eth-p/bat-extras/blob/${COMMIT}/doc/prettybat.md) \
|
||||
as of commit $(git rev-parse --short HEAD) (${DATE_STR}).
|
||||
|
||||
**This is provided as a convenience only.**
|
||||
I would still recommend following the installation instructions in \
|
||||
[the README](https://github.com/eth-p/bat-extras#installation-) for the most up-to-date versions.
|
||||
|
||||
### Changes
|
||||
$CHANGELOG
|
||||
EOF
|
||||
batextras:generate_release_notes \
|
||||
"$(batextras:get_previous_tag_name)" \
|
||||
"$(batextras:get_current_commit)"
|
||||
|
|
|
|||
251
src/bat-modules.sh
Executable file
251
src/bat-modules.sh
Executable file
|
|
@ -0,0 +1,251 @@
|
|||
#!/usr/bin/env bash
|
||||
# -----------------------------------------------------------------------------
|
||||
# bat-extras | Copyright (C) 2020 eth-p | MIT License
|
||||
#
|
||||
# Repository: https://github.com/eth-p/bat-extras
|
||||
# Issues: https://github.com/eth-p/bat-extras/issues
|
||||
# -----------------------------------------------------------------------------
|
||||
# shellcheck disable=SC1090
|
||||
LIB="$(cd "$(dirname "${BASH_SOURCE[0]}")" && cd "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo ".")")/../lib" && pwd)"
|
||||
source "${LIB}/constants.sh"
|
||||
source "${LIB}/print.sh"
|
||||
source "${LIB}/opt.sh"
|
||||
source "${LIB}/opt_hook_color.sh"
|
||||
source "${LIB}/opt_hook_version.sh"
|
||||
source "${LIB}/dsl.sh"
|
||||
source "${LIB}/str.sh"
|
||||
# -----------------------------------------------------------------------------
|
||||
# Init:
|
||||
# -----------------------------------------------------------------------------
|
||||
hook_color
|
||||
hook_version
|
||||
# -----------------------------------------------------------------------------
|
||||
COMMON_URL_GITHUB="https://github.com/%s.git"
|
||||
COMMON_URL_GITLAB="https://gitlab.com/%s.git"
|
||||
CONFIG_DIR="$(bat --config-dir)"
|
||||
SYNTAX_DIR="${CONFIG_DIR}/syntaxes"
|
||||
THEME_DIR="${CONFIG_DIR}/themes"
|
||||
MODULES_FILE="${CONFIG_DIR}/modules.txt"
|
||||
# -----------------------------------------------------------------------------
|
||||
# Options:
|
||||
# -----------------------------------------------------------------------------
|
||||
ACTION="help"
|
||||
|
||||
# Parse arguments.
|
||||
while shiftopt; do
|
||||
case "$OPT" in
|
||||
|
||||
--help) ACTION="help" ;;
|
||||
--update) ACTION="update" ;;
|
||||
--clear) ACTION="clear" ;;
|
||||
--setup) ACTION="setup" ;;
|
||||
--modules-file) ACTION="show_file" ;;
|
||||
|
||||
# ???
|
||||
-*) {
|
||||
printc "%{RED}%s: unknown option '%s'%{CLEAR}\n" "$PROGRAM" "$OPT" 1>&2
|
||||
exit 1
|
||||
} ;;
|
||||
|
||||
esac
|
||||
done
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Functions:
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Ensures that the modules file at $MODULES_FILE exists.
|
||||
# If it doesn't, this will print a friendly warning and exit with exit code 1.
|
||||
#
|
||||
# This will also make sure the syntaxes and themes directories exist.
|
||||
ensure_setup() {
|
||||
if ! [[ -f "$MODULES_FILE" ]]; then
|
||||
printc "%{YELLOW}The bat-modules modules file wasn't found.%{CLEAR}\n"
|
||||
printc "%{YELLOW}Use %{CLEAR}%s --setup%{YELLOW} to set up bat-modules, or%{CLEAR}\n" "${PROGRAM}"
|
||||
printc "%{YELLOW}read the documentation at %{CLEAR}%s%{YELLOW} for more info.%{CLEAR}\n" "${PROGRAM_HOMEPAGE}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "${SYNTAX_DIR}" &>/dev/null || true
|
||||
mkdir -p "${THEME_DIR}" &>/dev/null || true
|
||||
}
|
||||
|
||||
# Prints an error message that parsing
|
||||
fail_parsing() {
|
||||
print_warning "Failed to parse bat-modules file."
|
||||
print_warning "Line %s: %s" "$DSL_LINE" "$1"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Parsing:
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
dsl_on_command() {
|
||||
BM_TYPE="$(tolower "$1")"
|
||||
BM_SOURCE="$(parse_source "$2")"
|
||||
BM_OPT_CHECKOUT="master"
|
||||
|
||||
case "$BM_TYPE" in
|
||||
"syntax" | "theme") : ;;
|
||||
*) fail "unknown module type '$BM_TYPE'" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
dsl_on_option() {
|
||||
# Common options.
|
||||
case "$(tolower "$1")" in
|
||||
checkout)
|
||||
BM_OPT_CHECKOUT="$2"
|
||||
return 0 ;;
|
||||
esac
|
||||
|
||||
# Type-specific options.
|
||||
case "$BM_TYPE" in
|
||||
"syntax") on_option_for_syntax "$@" && return 0 ;;
|
||||
"theme") on_option_for_theme "$@" && return 0 ;;
|
||||
esac
|
||||
|
||||
# Unknown options.
|
||||
fail "unknown %s option '%s'" "$BM_TYPE" "$*"
|
||||
}
|
||||
|
||||
on_option_for_syntax() {
|
||||
:
|
||||
}
|
||||
|
||||
on_option_for_theme() {
|
||||
:
|
||||
}
|
||||
|
||||
# Parses a module source.
|
||||
# This takes a git url or pseudo-URL patterns such as:
|
||||
#
|
||||
# example/my-syntax-on-github
|
||||
# github:example/my-syntax
|
||||
# gitlab:example/my-syntax
|
||||
#
|
||||
# Arguments:
|
||||
# 1 -- The source string.
|
||||
parse_source() {
|
||||
local source="$1"
|
||||
|
||||
# shellcheck disable=SC2059
|
||||
case "$source" in
|
||||
"github:"* | "gh:"*)
|
||||
source="$(printf "$COMMON_URL_GITHUB" "$(cut -d':' -f2- <<< "$source")")"
|
||||
;;
|
||||
|
||||
"gitlab:"* | "gl:"*)
|
||||
source="$(printf "$COMMON_URL_GITLAB" "$(cut -d':' -f2- <<< "$source")")"
|
||||
;;
|
||||
|
||||
*)
|
||||
if [[ "$1" =~ ^([A-Za-z0-9-])+/([A-Za-z0-9-])+$ ]]; then
|
||||
parse_source "github:$1" "${@:2}"
|
||||
return $?
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "$source"
|
||||
}
|
||||
|
||||
# Parses the clone directory name of a git repo URL.
|
||||
# Arguments:
|
||||
# 1 -- The repo URL.
|
||||
parse_source_name() {
|
||||
basename "$1" .git
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Actions:
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
action:show_file() {
|
||||
printf "%s\n" "$MODULES_FILE"
|
||||
}
|
||||
|
||||
action:setup() {
|
||||
if ! [[ -f "$MODULES_FILE" ]]; then
|
||||
cat > "$MODULES_FILE" <<-EOF
|
||||
# bat-modules example file.
|
||||
# See ${PROGRAM_HOMEPAGE} for documentation and help.
|
||||
|
||||
# syntax example/syntax
|
||||
|
||||
# theme https://github.com/example/theme.git
|
||||
# checkout abcdef1
|
||||
|
||||
EOF
|
||||
fi
|
||||
"${EDITOR:-vi}" "$MODULES_FILE"
|
||||
}
|
||||
|
||||
action:help() {
|
||||
{
|
||||
printc "%{YELLOW}%s help:%{CLEAR}\n" "$PROGRAM"
|
||||
printc " --clear -- Clear the cached themes and syntaxes.\n"
|
||||
printc " --update -- Update themes and syntaxes.\n"
|
||||
printc " --setup -- Edit the bat-modules modules.txt file.\n"
|
||||
printc " --modules-file -- Show the bat-modules modules.txt file.\n"
|
||||
} 1>&2
|
||||
}
|
||||
|
||||
action:clear() {
|
||||
printc "%{YELLOW}Clearing bat syntax and theme cache...%{CLEAR}\n"
|
||||
"$EXECUTABLE_BAT" cache --clear
|
||||
}
|
||||
|
||||
action:update() {
|
||||
CHANGES=false
|
||||
|
||||
dsl_on_command_commit() {
|
||||
case "$BM_TYPE" in
|
||||
syntax) cd "$SYNTAX_DIR" ;;
|
||||
theme) cd "$THEME_DIR" ;;
|
||||
esac
|
||||
|
||||
local hash
|
||||
local name="$(parse_source_name "$BM_SOURCE")"
|
||||
printc "%{BLUE}----- %s: %s -----%{CLEAR}\n" "$BM_TYPE" "$name"
|
||||
|
||||
# If it isn't cloned, clone it.
|
||||
if ! [[ -d "$name" ]]; then
|
||||
printc "%{YELLOW}Cloning...%{CLEAR}\n"
|
||||
"$EXECUTABLE_GIT" clone "$BM_SOURCE" "$name"
|
||||
CHANGES=true
|
||||
fi
|
||||
|
||||
# If it is cloned, fetch/checkout.
|
||||
printc "%{YELLOW}Updating...%{CLEAR}\n"
|
||||
cd "$name"
|
||||
hash="$("$EXECUTABLE_GIT" rev-parse HEAD)"
|
||||
"$EXECUTABLE_GIT" fetch origin --quiet
|
||||
"$EXECUTABLE_GIT" checkout "$BM_OPT_CHECKOUT" --quiet
|
||||
hash_new="$("$EXECUTABLE_GIT" rev-parse HEAD)"
|
||||
|
||||
if [[ "$hash" != "$hash_new" ]]; then
|
||||
printc "%{YELLOW}Updated to %s.%{CLEAR}\n" "$hash_new"
|
||||
CHANGES=true
|
||||
fi
|
||||
}
|
||||
|
||||
# Parse the DSL.
|
||||
ensure_setup
|
||||
dsl_parse_file "$MODULES_FILE"
|
||||
|
||||
# If there are changes, update.
|
||||
printc "%{BLUE}----- bat-modules -----%{CLEAR}\n" "$BM_TYPE" "$name"
|
||||
printc "%{YELLOW}Done.%{CLEAR}\n"
|
||||
if "$CHANGES"; then
|
||||
printc "%{YELLOW}Rebuilding cache...%{CLEAR}\n"
|
||||
"$EXECUTABLE_BAT" cache --build
|
||||
fi
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Main:
|
||||
# -----------------------------------------------------------------------------
|
||||
action:"$ACTION"
|
||||
exit $?
|
||||
227
src/batdiff.sh
Executable file
227
src/batdiff.sh
Executable file
|
|
@ -0,0 +1,227 @@
|
|||
#!/usr/bin/env bash
|
||||
# -----------------------------------------------------------------------------
|
||||
# bat-extras | Copyright (C) 2020 eth-p | MIT License
|
||||
#
|
||||
# Repository: https://github.com/eth-p/bat-extras
|
||||
# Issues: https://github.com/eth-p/bat-extras/issues
|
||||
# -----------------------------------------------------------------------------
|
||||
# shellcheck disable=SC1090
|
||||
LIB="$(cd "$(dirname "${BASH_SOURCE[0]}")" && cd "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo ".")")/../lib" && pwd)"
|
||||
source "${LIB}/constants.sh"
|
||||
source "${LIB}/print.sh"
|
||||
source "${LIB}/pager.sh"
|
||||
source "${LIB}/opt.sh"
|
||||
source "${LIB}/opt_hook_color.sh"
|
||||
source "${LIB}/opt_hook_pager.sh"
|
||||
source "${LIB}/opt_hook_version.sh"
|
||||
source "${LIB}/opt_hook_width.sh"
|
||||
source "${LIB}/version.sh"
|
||||
# -----------------------------------------------------------------------------
|
||||
# Init:
|
||||
# -----------------------------------------------------------------------------
|
||||
hook_color
|
||||
hook_pager
|
||||
hook_version
|
||||
hook_width
|
||||
# -----------------------------------------------------------------------------
|
||||
# Options:
|
||||
# -----------------------------------------------------------------------------
|
||||
BATDIFF_USE_DELTA="${BATDIFF_USE_DELTA:-}"
|
||||
|
||||
SUPPORTS_BAT_DIFF=false
|
||||
SUPPORTS_DELTA=false
|
||||
|
||||
BAT_VERSION="$(bat_version)"
|
||||
BAT_ARGS=()
|
||||
DELTA_ARGS=()
|
||||
DELTA_VERSION='unsupported'
|
||||
GIT_ARGS=()
|
||||
|
||||
FILES=()
|
||||
OPT_TABS=
|
||||
OPT_CONTEXT=2
|
||||
OPT_STAGED=false
|
||||
OPT_ALL_CHANGES=false
|
||||
|
||||
# Set options based on bat version.
|
||||
if version_compare "$BAT_VERSION" -ge "0.15"; then
|
||||
SUPPORTS_BAT_DIFF=true
|
||||
fi
|
||||
|
||||
# Set options based on delta availability.
|
||||
if command -v "$EXECUTABLE_DELTA" &>/dev/null; then
|
||||
SUPPORTS_DELTA=true
|
||||
DELTA_VERSION="$("$EXECUTABLE_DELTA" --version | cut -d' ' -f2)"
|
||||
fi
|
||||
|
||||
# Set options based on delta version.
|
||||
# - 0.12 -- Renamed `--hunk-style` to `--hunk-header-decoration-style`.
|
||||
if version_compare "$DELTA_VERSION" -ge "0.12"; then
|
||||
DELTA_ARGS+=("--hunk-header-decoration-style=plain")
|
||||
else
|
||||
DELTA_ARGS+=("--hunk-style=plain")
|
||||
fi
|
||||
|
||||
# Parse arguments.
|
||||
while shiftopt; do
|
||||
case "$OPT" in
|
||||
|
||||
# bat options
|
||||
-C | --context | --diff-context) shiftval; OPT_CONTEXT="$OPT_VAL" ;;
|
||||
--terminal-width) shiftval; OPT_TERMINAL_WIDTH="$OPT_VAL" ;;
|
||||
--tabs) shiftval; OPT_TABS="$OPT_VAL" ;;
|
||||
|
||||
# Script options
|
||||
--all) OPT_ALL_CHANGES=true ;;
|
||||
--staged) OPT_STAGED=true; GIT_ARGS+=("--staged") ;;
|
||||
--delta) BATDIFF_USE_DELTA=true ;;
|
||||
|
||||
# ???
|
||||
-*) {
|
||||
printc "%{RED}%s: unknown option '%s'%{CLEAR}\n" "$PROGRAM" "$OPT" 1>&2
|
||||
exit 1
|
||||
} ;;
|
||||
|
||||
# Files
|
||||
*) FILES+=("$OPT") ;;
|
||||
|
||||
esac
|
||||
done
|
||||
|
||||
# Append arguments for delta/bat.
|
||||
BAT_ARGS+=("--terminal-width=${OPT_TERMINAL_WIDTH}" "--paging=never")
|
||||
DELTA_ARGS+=(
|
||||
"--width=${OPT_TERMINAL_WIDTH}"
|
||||
"--paging=never"
|
||||
)
|
||||
|
||||
if "$OPT_COLOR"; then
|
||||
BAT_ARGS+=("--color=always")
|
||||
else
|
||||
BAT_ARGS+=("--color=never")
|
||||
DELTA_ARGS+=("--theme=none")
|
||||
fi
|
||||
|
||||
if [[ -n "$OPT_TABS" ]]; then
|
||||
BAT_ARGS+=("--tabs=${OPT_TABS}")
|
||||
DELTA_ARGS+=("--tabs=${OPT_TABS}")
|
||||
fi
|
||||
|
||||
# Append arguments for git.
|
||||
GIT_ARGS+=(-U"$OPT_CONTEXT")
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Functions:
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
ensure_git_directory() {
|
||||
if ! "$EXECUTABLE_GIT" rev-parse --show-toplevel &>/dev/null; then
|
||||
print_error "Not a git repository."
|
||||
printc "\n%s\nTo view a diff between two files, use %{CYAN}%s [file] [file]%{CLEAR}." \
|
||||
"To view a diff between staged files and the working directory, enter a git repository." \
|
||||
"$PROGRAM"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Printing:
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
print_bat_diff() {
|
||||
local files=("$@")
|
||||
|
||||
# Diff two files.
|
||||
if [[ "${#files[@]}" -eq 2 ]]; then
|
||||
diff --unified="$OPT_CONTEXT" "${files[@]}" | "$EXECUTABLE_BAT" --language=diff - "${BAT_ARGS[@]}"
|
||||
return $?
|
||||
fi
|
||||
|
||||
# Diff staged git file.
|
||||
ensure_git_directory
|
||||
if "$OPT_STAGED"; then
|
||||
if false && "$SUPPORTS_DELTA"; then
|
||||
# bat doesn't support diffing staged changes against the HEAD.
|
||||
# Delta is better suited for printing diffs in this case.
|
||||
print_delta_diff "$@"
|
||||
else
|
||||
difftext="$("$EXECUTABLE_GIT" diff "${GIT_ARGS[@]}" "${files[0]}")"
|
||||
if [[ "${#difftext}" -gt 0 ]]; then
|
||||
"$EXECUTABLE_BAT" --language=diff --file-name="${files[0]}" - "${BAT_ARGS[@]}" <<< "$difftext"
|
||||
fi
|
||||
fi
|
||||
return $?
|
||||
fi
|
||||
|
||||
# Diff git file.
|
||||
if "$SUPPORTS_BAT_DIFF"; then
|
||||
"$EXECUTABLE_GIT" diff "${GIT_ARGS[@]}" --name-only -z "${files[0]}" \
|
||||
| xargs --null "$EXECUTABLE_BAT" --diff --diff-context="$OPT_CONTEXT" "${BAT_ARGS[@]}"
|
||||
else
|
||||
"$EXECUTABLE_GIT" diff "${GIT_ARGS[@]}" "${files[0]}" | "$EXECUTABLE_BAT" --language=diff - "${BAT_ARGS[@]}"
|
||||
fi
|
||||
}
|
||||
|
||||
print_delta_diff() {
|
||||
local files=("$@")
|
||||
|
||||
# Diff two files.
|
||||
if [[ "${#files[@]}" -eq 2 ]]; then
|
||||
diff --unified="$OPT_CONTEXT" "${files[@]}" | "$EXECUTABLE_DELTA" "${DELTA_ARGS[@]}"
|
||||
return $?
|
||||
fi
|
||||
|
||||
# Diff git file.
|
||||
ensure_git_directory
|
||||
"$EXECUTABLE_GIT" diff "${GIT_ARGS[@]}" "${files[0]}" | "$EXECUTABLE_DELTA" "${DELTA_ARGS[@]}"
|
||||
}
|
||||
|
||||
if [[ "$BATDIFF_USE_DELTA" = "true" && "$SUPPORTS_DELTA" = "true" ]]; then
|
||||
print_diff() {
|
||||
print_delta_diff "$@"
|
||||
return $?
|
||||
}
|
||||
else
|
||||
print_diff() {
|
||||
print_bat_diff "$@"
|
||||
return $?
|
||||
}
|
||||
fi
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Validation:
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Handle too many files.
|
||||
if [[ "${#FILES[@]}" -gt 2 ]]; then
|
||||
print_error "too many files provided"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Handle deprecated --all.
|
||||
if "$OPT_ALL_CHANGES"; then
|
||||
print_warning "argument --all is deprecated. Use '%s' instead" "$0"
|
||||
fi
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Main:
|
||||
# -----------------------------------------------------------------------------
|
||||
main() {
|
||||
if [[ "${#FILES[@]}" -eq 0 ]] || "$OPT_ALL_CHANGES"; then
|
||||
ensure_git_directory
|
||||
local file
|
||||
while read -r file; do
|
||||
if [[ -f "$file" ]]; then
|
||||
print_diff "$file"
|
||||
fi
|
||||
done < <("${EXECUTABLE_GIT}" diff "${GIT_ARGS[@]}" --name-only --diff-filter=d)
|
||||
return
|
||||
fi
|
||||
|
||||
print_diff "${FILES[@]}"
|
||||
}
|
||||
|
||||
pager_exec main
|
||||
exit $?
|
||||
260
src/batgrep.sh
260
src/batgrep.sh
|
|
@ -5,23 +5,146 @@
|
|||
# Repository: https://github.com/eth-p/bat-extras
|
||||
# Issues: https://github.com/eth-p/bat-extras/issues
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
|
||||
# shellcheck disable=SC1090
|
||||
LIB="$(cd "$(dirname "${BASH_SOURCE[0]}")" && cd "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo ".")")/../lib" && pwd)"
|
||||
source "${LIB}/constants.sh"
|
||||
source "${LIB}/print.sh"
|
||||
source "${LIB}/pager.sh"
|
||||
source "${LIB}/opt.sh"
|
||||
source "${LIB}/opt_hooks.sh"
|
||||
source "${LIB}/opt_hook_color.sh"
|
||||
source "${LIB}/opt_hook_help.sh"
|
||||
source "${LIB}/opt_hook_pager.sh"
|
||||
source "${LIB}/opt_hook_version.sh"
|
||||
source "${LIB}/opt_hook_width.sh"
|
||||
source "${LIB}/version.sh"
|
||||
# -----------------------------------------------------------------------------
|
||||
# Init:
|
||||
# -----------------------------------------------------------------------------
|
||||
hook_color
|
||||
hook_help
|
||||
hook_pager
|
||||
hook_version
|
||||
hook_width
|
||||
# -----------------------------------------------------------------------------
|
||||
# Help:
|
||||
# -----------------------------------------------------------------------------
|
||||
show_help() {
|
||||
cat <<-'EOF'
|
||||
Quickly search through and highlight files using ripgrep.
|
||||
|
||||
Search through files or directories looking for matching regular expressions (or fixed strings with -F), and print the output using bat for an easy and syntax-highlighted experience.
|
||||
|
||||
Usage: batgrep [OPTIONS] PATTERN [PATH...]
|
||||
|
||||
Arguments:
|
||||
[OPTIONS]
|
||||
See Options below
|
||||
PATTERN
|
||||
Pattern passed to ripgrep
|
||||
[PATH...]
|
||||
Path(s) to search
|
||||
|
||||
Options:
|
||||
-i, --ignore-case:
|
||||
Use case insensitive searching.
|
||||
|
||||
-s, --case-sensitive:
|
||||
Use case sensitive searching.
|
||||
|
||||
-S, --smart-case:
|
||||
Use smart case searching
|
||||
|
||||
-A, --after-context=[LINES]:
|
||||
Display the next n lines after a matched line.
|
||||
|
||||
-B, --before-context=[LINES]:
|
||||
Display the previous n lines before a matched line.
|
||||
|
||||
-C, --context=[LINES]:
|
||||
A combination of --after-context and --before-context
|
||||
|
||||
-p, --search-pattern:
|
||||
Tell pager to search for PATTERN. Currently supported pagers: less.
|
||||
|
||||
--no-follow:
|
||||
Do not follow symlinks
|
||||
|
||||
--no-snip:
|
||||
Do not show the snip decoration
|
||||
|
||||
This is automatically enabled when --context=0 or when bat --version is less than 0.12.x
|
||||
|
||||
--no-highlight:
|
||||
Do not highlight matching lines.
|
||||
|
||||
This is automatically enabled when --context=0.
|
||||
|
||||
--color:
|
||||
Force color output.
|
||||
|
||||
--no-color:
|
||||
Force disable color output.
|
||||
|
||||
--paging=["never"/"always"]:
|
||||
Enable/disable paging.
|
||||
|
||||
--pager=[PAGER]:
|
||||
Specify the pager to use.
|
||||
|
||||
--terminal-width=[COLS]:
|
||||
Generate output for the specified terminal width.
|
||||
|
||||
--no-separator:
|
||||
Disable printing separator between files.
|
||||
|
||||
--rga:
|
||||
Use ripgrep-all instead of ripgrep.
|
||||
|
||||
Options passed directly to ripgrep:
|
||||
-F, --fixed-strings
|
||||
|
||||
-U, --multiline
|
||||
|
||||
-P, --pcre2
|
||||
|
||||
-z, --search-zip
|
||||
|
||||
-w, --word-regexp
|
||||
|
||||
--one-file-system
|
||||
|
||||
--multiline-dotall
|
||||
|
||||
--ignore, --no-ignore
|
||||
|
||||
--crlf, --no-crlf
|
||||
|
||||
--hidden, --no-hidden
|
||||
|
||||
-E --encoding:
|
||||
This is unsupported by bat, and may cause issues when trying to display unsupported encodings.
|
||||
|
||||
-g, --glob
|
||||
|
||||
-t, --type
|
||||
|
||||
-T, --type-not
|
||||
|
||||
-m, --max-count
|
||||
|
||||
--max-depth
|
||||
|
||||
--iglob
|
||||
|
||||
--ignore-file
|
||||
EOF
|
||||
}
|
||||
# -----------------------------------------------------------------------------
|
||||
# Options:
|
||||
# -----------------------------------------------------------------------------
|
||||
RIPGREP="$EXECUTABLE_RIPGREP"
|
||||
RG_ARGS=()
|
||||
BAT_ARGS=()
|
||||
PATTERN=""
|
||||
|
|
@ -34,24 +157,61 @@ OPT_SNIP=""
|
|||
OPT_HIGHLIGHT=true
|
||||
OPT_SEARCH_PATTERN=false
|
||||
OPT_FIXED_STRINGS=false
|
||||
BAT_STYLE="header,numbers"
|
||||
OPT_NO_SEPARATOR=false
|
||||
BAT_STYLE="${BAT_STYLE:-header,numbers}"
|
||||
|
||||
# Set options based on the bat version.
|
||||
if version_compare "$(bat_version)" -gt "0.12"; then
|
||||
OPT_SNIP=",snip"
|
||||
fi
|
||||
|
||||
# Parse RIPGREP_CONFIG_PATH.
|
||||
if [[ -n "$RIPGREP_CONFIG_PATH" && -e "$RIPGREP_CONFIG_PATH" ]]; then
|
||||
# shellcheck disable=SC2046
|
||||
setargs $(cat "$RIPGREP_CONFIG_PATH")
|
||||
while shiftopt; do
|
||||
case "$OPT" in
|
||||
-A | --after-context) shiftval; OPT_CONTEXT_AFTER="$OPT_VAL" ;;
|
||||
-B | --before-context) shiftval; OPT_CONTEXT_BEFORE="$OPT_VAL" ;;
|
||||
-C | --context)
|
||||
shiftval
|
||||
OPT_CONTEXT_BEFORE="$OPT_VAL"
|
||||
OPT_CONTEXT_AFTER="$OPT_VAL"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
fi
|
||||
|
||||
# Parse arguments.
|
||||
shopt -s extglob # Needed to handle -u
|
||||
|
||||
# First handle -u specially - it can be repeated multiple times in a single
|
||||
# short argument, and repeating it 1, 2, or 3 times causes different effects.
|
||||
resetargs
|
||||
SHIFTOPT_SHORT_OPTIONS="PASS"
|
||||
while shiftopt; do
|
||||
case "$OPT" in
|
||||
[-]+(u) )
|
||||
RG_ARGS+=("$OPT")
|
||||
;;
|
||||
esac
|
||||
done
|
||||
resetargs
|
||||
SHIFTOPT_SHORT_OPTIONS="VALUE"
|
||||
while shiftopt; do
|
||||
case "$OPT" in
|
||||
|
||||
# ripgrep options
|
||||
[-]+([u]) ) ;; # Ignore - handled in first loop.
|
||||
--unrestricted)
|
||||
RG_ARGS+=("$OPT")
|
||||
;;
|
||||
-i | --ignore-case) OPT_CASE_SENSITIVITY="--ignore-case" ;;
|
||||
-s | --case-sensitive) OPT_CASE_SENSITIVITY="--case-sensitive" ;;
|
||||
-S | --smart-case) OPT_CASE_SENSITIVITY="--smart-case" ;;
|
||||
|
||||
-A | --after-context) shiftval; OPT_CONTEXT_AFTER="$OPT_VAL" ;;
|
||||
-B | --before-context) shiftval; OPT_CONTEXT_BEFORE="$OPT_VAL" ;;
|
||||
|
||||
-C | --context)
|
||||
shiftval
|
||||
OPT_CONTEXT_BEFORE="$OPT_VAL"
|
||||
|
|
@ -95,6 +255,15 @@ while shiftopt; do
|
|||
--no-highlight) OPT_HIGHLIGHT=false ;;
|
||||
-p | --search-pattern) OPT_SEARCH_PATTERN=true ;;
|
||||
--no-search-pattern) OPT_SEARCH_PATTERN=false ;;
|
||||
--no-separator) OPT_NO_SEPARATOR=true ;;
|
||||
--rga) {
|
||||
if ! rga --version | grep 'ripgrep-all' &>/dev/null; then
|
||||
printc "%{RED}%s: option '--rga' requires ripgrep-all to be installed%{CLEAR}\n" "$PROGRAM" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
RIPGREP='rga'
|
||||
};;
|
||||
|
||||
# Option forwarding
|
||||
--rg:*) {
|
||||
|
|
@ -108,6 +277,9 @@ while shiftopt; do
|
|||
fi
|
||||
} ;;
|
||||
|
||||
# --
|
||||
--) getargs -a FILES; break ;;
|
||||
|
||||
# ???
|
||||
-*) {
|
||||
printc "%{RED}%s: unknown option '%s'%{CLEAR}\n" "$PROGRAM" "$OPT" 1>&2
|
||||
|
|
@ -115,25 +287,22 @@ while shiftopt; do
|
|||
} ;;
|
||||
|
||||
# Search
|
||||
*) {
|
||||
if [ -z "$PATTERN" ]; then
|
||||
PATTERN="$OPT"
|
||||
else
|
||||
FILES+=("$OPT")
|
||||
fi
|
||||
} ;;
|
||||
*) FILES+=("$OPT") ;;
|
||||
|
||||
esac
|
||||
done
|
||||
|
||||
# Use the first file as a pattern.
|
||||
PATTERN="${FILES[0]}"
|
||||
FILES=("${FILES[@]:1}")
|
||||
|
||||
if [[ -z "$PATTERN" ]]; then
|
||||
print_error "no pattern provided"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Generate separator.
|
||||
COLS="$(tput cols)"
|
||||
SEP="$(printc "%{DIM}%${COLS}s%{CLEAR}" | sed "s/ /─/g")"
|
||||
SEP="$(printc "%{DIM}%${OPT_TERMINAL_WIDTH}s%{CLEAR}" | sed "s/ /─/g")"
|
||||
|
||||
# Append ripgrep and bat arguments.
|
||||
if [[ -n "$OPT_CASE_SENSITIVITY" ]]; then
|
||||
|
|
@ -191,12 +360,50 @@ main() {
|
|||
LAST_LR=()
|
||||
LAST_LH=()
|
||||
LAST_FILE=''
|
||||
READ_FROM_STDIN=false
|
||||
NO_SEPARATOR="$OPT_NO_SEPARATOR"
|
||||
|
||||
if [[ "$BAT_STYLE" = *grid* ]]; then
|
||||
NO_SEPARATOR=true
|
||||
fi
|
||||
|
||||
|
||||
# If we found no files being provided and STDIN to not be attached to a tty,
|
||||
# we capture STDIN to a variable. This variable will later be written to
|
||||
# the STDIN file descriptors of both ripgrep and bat.
|
||||
if ! [[ -t 0 ]] && [[ "${#FILES[@]}" -eq 0 ]]; then
|
||||
READ_FROM_STDIN=true
|
||||
IFS='' STDIN_DATA="$(cat)"
|
||||
fi
|
||||
|
||||
do_ripgrep_search() {
|
||||
local COMMON_RG_ARGS=(
|
||||
--with-filename \
|
||||
--vimgrep \
|
||||
"${RG_ARGS[@]}" \
|
||||
--context 0 \
|
||||
--sort path \
|
||||
-- \
|
||||
"$PATTERN" \
|
||||
"${FILES[@]}" \
|
||||
)
|
||||
|
||||
if "$READ_FROM_STDIN"; then
|
||||
"$RIPGREP" "${COMMON_RG_ARGS[@]}" <<< "$STDIN_DATA"
|
||||
return $?
|
||||
else
|
||||
"$RIPGREP" "${COMMON_RG_ARGS[@]}"
|
||||
return $?
|
||||
fi
|
||||
}
|
||||
|
||||
do_print() {
|
||||
[[ -z "$LAST_FILE" ]] && return 0
|
||||
|
||||
# Print the separator.
|
||||
"$FIRST_PRINT" && echo "$SEP"
|
||||
if ! "$NO_SEPARATOR"; then
|
||||
"$FIRST_PRINT" && echo "$SEP"
|
||||
fi
|
||||
FIRST_PRINT=false
|
||||
|
||||
# Print the file.
|
||||
|
|
@ -205,19 +412,34 @@ main() {
|
|||
"${LAST_LH[@]}" \
|
||||
--style="${BAT_STYLE}${OPT_SNIP}" \
|
||||
--paging=never \
|
||||
--terminal-width="$COLS" \
|
||||
--terminal-width="$OPT_TERMINAL_WIDTH" \
|
||||
"$LAST_FILE"
|
||||
|
||||
# Print the separator.
|
||||
echo "$SEP"
|
||||
if ! "$NO_SEPARATOR"; then
|
||||
echo "$SEP"
|
||||
fi
|
||||
}
|
||||
|
||||
do_print_from_file_or_stdin() {
|
||||
if [[ "$LAST_FILE" = "<stdin>" ]]; then
|
||||
# If the file is from STDIN, we provide the STDIN
|
||||
# contents to bat and tell it to read from STDIN.
|
||||
LAST_FILE="-"
|
||||
do_print <<< "$STDIN_DATA"
|
||||
return $?
|
||||
else
|
||||
do_print
|
||||
return $?
|
||||
fi
|
||||
}
|
||||
|
||||
# shellcheck disable=SC2034
|
||||
while IFS=':' read -r file line column; do
|
||||
while IFS=':' read -r file line column text; do
|
||||
((FOUND++))
|
||||
|
||||
if [[ "$LAST_FILE" != "$file" ]]; then
|
||||
do_print
|
||||
do_print_from_file_or_stdin
|
||||
LAST_FILE="$file"
|
||||
LAST_LR=()
|
||||
LAST_LH=()
|
||||
|
|
@ -230,8 +452,8 @@ main() {
|
|||
|
||||
LAST_LR+=("--line-range=${line_start}:${line_end}")
|
||||
[[ "$OPT_HIGHLIGHT" = "true" ]] && LAST_LH+=("--highlight-line=${line}")
|
||||
done < <(rg --with-filename --vimgrep "${RG_ARGS[@]}" --sort path "$PATTERN" "${FILES[@]}")
|
||||
do_print
|
||||
done < <(do_ripgrep_search)
|
||||
do_print_from_file_or_stdin
|
||||
|
||||
# Exit.
|
||||
if [[ "$FOUND" -eq 0 ]]; then
|
||||
|
|
|
|||
|
|
@ -6,36 +6,110 @@
|
|||
# Issues: https://github.com/eth-p/bat-extras/issues
|
||||
# -----------------------------------------------------------------------------
|
||||
# shellcheck disable=SC1090 disable=SC2155
|
||||
LIB="$(cd "$(dirname "${BASH_SOURCE[0]}")" && cd "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo ".")")/../lib" && pwd)"
|
||||
if [[ -n "${MANPAGER}" ]]; then BAT_PAGER="$MANPAGER"; fi
|
||||
SELF_NC="${BASH_SOURCE:-$0}"
|
||||
SELF="$(cd "$(dirname "${SELF_NC}")" && cd "$(dirname "$(readlink "${SELF_NC}" || echo ".")")" && pwd)/$(basename "$(readlink "${SELF_NC}" || echo "${SELF_NC}")")"
|
||||
LIB="$(cd "$(dirname "${SELF_NC}")" && cd "$(dirname "$(readlink "${SELF_NC}" || echo ".")")/../lib" && pwd)"
|
||||
source "${LIB}/constants.sh"
|
||||
source "${LIB}/pager.sh"
|
||||
source "${LIB}/print.sh"
|
||||
source "${LIB}/opt.sh"
|
||||
source "${LIB}/opt_hooks.sh"
|
||||
source "${LIB}/opt_hook_color.sh"
|
||||
source "${LIB}/opt_hook_version.sh"
|
||||
# -----------------------------------------------------------------------------
|
||||
hook_color
|
||||
hook_pager
|
||||
hook_version
|
||||
# -----------------------------------------------------------------------------
|
||||
FORWARDED_ARGS=()
|
||||
MAN_ARGS=()
|
||||
BAT_ARGS=()
|
||||
OPT_EXPORT_ENV=false
|
||||
|
||||
SHIFTOPT_SHORT_OPTIONS="SPLIT"
|
||||
while shiftopt; do
|
||||
case "$OPT" in
|
||||
--export-env) OPT_EXPORT_ENV=true ;;
|
||||
--paging|--pager|--wrap) shiftval; FORWARDED_ARGS+=("${OPT}=${OPT_VAL}");
|
||||
BAT_ARGS+=("${OPT}=${OPT_VAL}") ;;
|
||||
*) MAN_ARGS+=("$OPT") ;;
|
||||
esac
|
||||
done
|
||||
|
||||
while shiftopt; do MAN_ARGS+=("$OPT"); done
|
||||
if "$OPT_COLOR"; then
|
||||
BAT_ARGS=("--color=always --decorations=always")
|
||||
BAT_ARGS+=("--color=always" "--decorations=always")
|
||||
else
|
||||
BAT_ARGS=("--color=never --decorations=never")
|
||||
BAT_ARGS+=("--color=never" "--decorations=never")
|
||||
fi
|
||||
|
||||
if [[ -z "${BAT_STYLE+x}" ]]; then
|
||||
export BAT_STYLE="grid"
|
||||
fi
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
export MANPAGER='sh -c "col -bx | '"$(printf "%q" "$EXECUTABLE_BAT")"' --language=man --style=grid '"${BAT_ARGS[*]}"'"'
|
||||
# When called as the manpager, do some preprocessing and feed everything to bat.
|
||||
|
||||
if [[ "${BATMAN_IS_BEING_MANPAGER:-}" = "yes" ]]; then
|
||||
print_manpage() {
|
||||
sed -e 's/\x1B\[[0-9;]*m//g; s/.\x08//g' \
|
||||
| "$EXECUTABLE_BAT" --language=man "${BAT_ARGS[@]}"
|
||||
exit $?
|
||||
}
|
||||
|
||||
if [[ "${#MAN_ARGS[@]}" -eq 1 ]]; then
|
||||
# The input was passed as a file.
|
||||
cat "${MAN_ARGS[0]}" | print_manpage
|
||||
else
|
||||
# The input was passed via stdin.
|
||||
cat | print_manpage
|
||||
fi
|
||||
|
||||
exit
|
||||
fi
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
if [[ -n "${MANPAGER}" ]]; then BAT_PAGER="$MANPAGER"; fi
|
||||
export MANPAGER="env BATMAN_IS_BEING_MANPAGER=yes bash $(printf "%q " "$SELF" "${FORWARDED_ARGS[@]}")"
|
||||
export MANPAGER="${MANPAGER%"${MANPAGER##*[![:space:]]}"}"
|
||||
export MANROFFOPT='-c'
|
||||
|
||||
if [[ -n "${SCRIPT_PAGER_CMD}" ]]; then
|
||||
export BAT_PAGER="$(printf "%q " "${SCRIPT_PAGER_CMD[@]}" "${SCRIPT_PAGER_ARGS[@]}")"
|
||||
else
|
||||
unset BAT_PAGER
|
||||
# If `--export-env`, print exports to use batman as the manpager directly.
|
||||
if "$OPT_EXPORT_ENV"; then
|
||||
printf "export %s=%q\n" \
|
||||
"MANPAGER" "$MANPAGER" \
|
||||
"MANROFFOPT" "$MANROFFOPT"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# If no argument is provided and fzf is installed, use fzf to search for man pages.
|
||||
if [[ "${#MAN_ARGS[@]}" -eq 0 ]] && [[ -z "$BATMAN_LEVEL" ]] && command -v "$EXECUTABLE_FZF" &>/dev/null; then
|
||||
export BATMAN_LEVEL=1
|
||||
|
||||
selected_page="$(man -k . | "$EXECUTABLE_FZF" --delimiter=" - " --reverse -e --preview="
|
||||
echo {1} \
|
||||
| sed 's/, /\n/g;' \
|
||||
| sed 's/\([^(]*\)(\([0-9A-Za-z ]\))/\2\t\1/g' \
|
||||
| BAT_STYLE=plain xargs -n2 batman --color=always --paging=never
|
||||
")"
|
||||
|
||||
if [[ -z "$selected_page" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Some entries from `man -k .` may include "synonyms" of a man page's title.
|
||||
# For example, the manual for kubectl-edit will appear as:
|
||||
#
|
||||
# kubectl-edit(1), kubectl edit(1) - Edit a resource on the server
|
||||
#
|
||||
# `man` only needs one name/title, so we're taking the first one here.
|
||||
selected_page_unaliased="$(echo "$selected_page" | cut -d, -f1)"
|
||||
|
||||
# Convert the page(section) format to something that can be fed to the man command.
|
||||
while read -r line; do
|
||||
if [[ "$line" =~ ^(.*)\(([0-9a-zA-Z ]+)\) ]]; then
|
||||
MAN_ARGS+=("${BASH_REMATCH[2]}" "$(echo ${BASH_REMATCH[1]} | xargs)")
|
||||
fi
|
||||
done <<< "$selected_page_unaliased"
|
||||
fi
|
||||
|
||||
# Run man.
|
||||
command man "${MAN_ARGS[@]}"
|
||||
exit $?
|
||||
|
|
|
|||
523
src/batpipe.sh
Executable file
523
src/batpipe.sh
Executable file
|
|
@ -0,0 +1,523 @@
|
|||
#!/usr/bin/env bash
|
||||
# -----------------------------------------------------------------------------
|
||||
# bat-extras | Copyright (C) 2021 eth-p | MIT License
|
||||
#
|
||||
# Repository: https://github.com/eth-p/bat-extras
|
||||
# Issues: https://github.com/eth-p/bat-extras/issues
|
||||
# -----------------------------------------------------------------------------
|
||||
#
|
||||
# EXTERNAL VIEWERS FOR BATPIPE:
|
||||
#
|
||||
# External viewers can be added to batpipe by creating bash scripts
|
||||
# inside the `~/.config/batpipe/viewers.d/` directory.
|
||||
#
|
||||
# CREATING A VIEWER:
|
||||
#
|
||||
# Viewers must define two functions and append the viewer's name to the
|
||||
# `BATPIPE_VIEWERS` array.
|
||||
#
|
||||
# - viewer_${viewer}_supports [file_basename] [file_path] [inner_file_path]
|
||||
# If this returns 0, the viewer's process function will be used.
|
||||
#
|
||||
# - viewer_${viewer}_process [file_path] [inner_file_path]
|
||||
#
|
||||
# VIEWER API:
|
||||
#
|
||||
# $BATPIPE_VIEWERS -- An array of loaded file viewers.
|
||||
# $BATPIPE_ENABLE_COLOR -- Whether color is supported. (`true`|`false`)
|
||||
# $BATPIPE_INSIDE_LESS -- Whether batpipe is inside less. (`true`|`false`)
|
||||
# $TERM_WIDTH -- The terminal width. (only supported in `less`)
|
||||
#
|
||||
# batpipe_header [pattern] [...] -- Print a viewer header line.
|
||||
# batpipe_subheader [pattern] [...] -- Print a viewer subheader line.
|
||||
#
|
||||
# bat -- Use `bat` for highlighting. If running inside `bat`, does nothing.
|
||||
#
|
||||
# strip_trailing_slashes [path] -- Strips trailing slashes from a path.
|
||||
#
|
||||
# -----------------------------------------------------------------------------
|
||||
# shellcheck disable=SC1090 disable=SC2155
|
||||
SELF_NC="${BASH_SOURCE:-$0}"
|
||||
SELF="$(cd "$(dirname "${SELF_NC}")" && cd "$(dirname "$(readlink "${SELF_NC}" || echo ".")")" && pwd)/$(basename "${SELF_NC}")"
|
||||
LIB="$(cd "$(dirname "${SELF_NC}")" && cd "$(dirname "$(readlink "${SELF_NC}" || echo ".")")/../lib" && pwd)"
|
||||
source "${LIB}/constants.sh"
|
||||
source "${LIB}/dirs.sh"
|
||||
source "${LIB}/str.sh"
|
||||
source "${LIB}/print.sh"
|
||||
source "${LIB}/path.sh"
|
||||
source "${LIB}/proc.sh"
|
||||
source "${LIB}/opt.sh"
|
||||
source "${LIB}/version.sh"
|
||||
source "${LIB}/term.sh"
|
||||
# -----------------------------------------------------------------------------
|
||||
# Usage/Install:
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
if [[ "$#" -eq 0 ]]; then
|
||||
# If writing to a terminal, display instructions and help.
|
||||
if [[ -t 1 ]]; then
|
||||
printc "%{DIM}# %s, %s.\n# %s\n# %s\n# %s\n# \n# %s%{CLEAR}\n" \
|
||||
"$PROGRAM" \
|
||||
"a bat-based preprocessor for less and bat" \
|
||||
"Version: $PROGRAM_VERSION" \
|
||||
"Homepage: $PROGRAM_HOMEPAGE" \
|
||||
"$PROGRAM_COPYRIGHT" \
|
||||
"To use $PROGRAM, eval the output of this command in your shell init script."
|
||||
fi
|
||||
|
||||
# Detect the shell.
|
||||
#
|
||||
# This will directly check if the parent is a non-sh/bash shell, since
|
||||
# there's a good chance that `bash` or `sh` will be invoking it.
|
||||
case "$(basename -- "$(parent_executable | cut -f1 -d' ')")" in
|
||||
fish) detected_shell="fish" ;;
|
||||
nu) detected_shell="nu" ;;
|
||||
*) detected_shell="$(parent_shell)" ;;
|
||||
esac
|
||||
|
||||
# Print the commands required to add `batpipe` to the environment variables.
|
||||
case "$(basename -- "${detected_shell:bash}")" in
|
||||
fish) # Fish
|
||||
printc '%{YELLOW}set -x %{CLEAR}LESSOPEN %{CYAN}"|%q %%s"%{CLEAR};\n' "$SELF"
|
||||
printc '%{YELLOW}set -e %{CLEAR}LESSCLOSE;\n'
|
||||
;;
|
||||
nu) # Nushell
|
||||
printc '%{BLUE}$env%{CLEAR}.LESSOPEN = %{CYAN}"|%q %%s"%{CLEAR}\n' "$SELF"
|
||||
if [[ "${LESSCLOSE:-}" != "" ]]; then
|
||||
printc '%{BLUE}hide-env%{CLEAR} LESSCLOSE\n' "$SELF"
|
||||
fi
|
||||
;;
|
||||
*) # Bash-like
|
||||
printc '%{MAGENTA}LESSOPEN%{CLEAR}=%{CYAN}"|%s %%s"%{CLEAR};\n' "$SELF"
|
||||
printc '%{YELLOW}export%{CLEAR} LESSOPEN;\n' "$SELF"
|
||||
printc '%{YELLOW}unset%{CLEAR} LESSCLOSE;\n'
|
||||
;;
|
||||
esac
|
||||
|
||||
# Print the commands required to use color in `less` with `batpipe`.
|
||||
if [[ -t 1 ]]; then
|
||||
printc "\n%{DIM}# The following will enable colors when using batpipe with less:%{CLEAR}\n"
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2016
|
||||
case "$(basename -- "${detected_shell:bash}")" in
|
||||
fish) # Fish
|
||||
printc '%{YELLOW}set -x %{CLEAR}LESS %{CYAN}"%{MAGENTA}$LESS%{CYAN} -R"%{CLEAR};\n' "$SELF"
|
||||
printc '%{YELLOW}set -x %{CLEAR}BATPIPE %{CYAN}"color"%{CLEAR};\n'
|
||||
;;
|
||||
nu) # Nushell
|
||||
printc '%{BLUE}$env%{CLEAR}.LESS = %{CYAN}$"%{MAGENTA}($env.LESS)%{CYAN} -R"%{CLEAR}\n' "$SELF"
|
||||
printc '%{BLUE}$env%{CLEAR}.BATPIPE = %{CYAN}"color"%{CLEAR}\n' "$SELF"
|
||||
;;
|
||||
*) # Bash-like
|
||||
printc '%{MAGENTA}LESS%{CLEAR}=%{CYAN}"%{MAGENTA}$LESS%{CYAN} -R"%{CLEAR};\n' "$SELF"
|
||||
printc '%{MAGENTA}BATPIPE%{CLEAR}=%{CYAN}"color"%{CLEAR};\n' "$SELF"
|
||||
printc '%{YELLOW}export%{CLEAR} LESS;\n' "$SELF"
|
||||
printc '%{YELLOW}export%{CLEAR} BATPIPE;\n' "$SELF"
|
||||
;;
|
||||
esac
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Init:
|
||||
# -----------------------------------------------------------------------------
|
||||
BATPIPE_INSIDE_LESS=false
|
||||
BATPIPE_INSIDE_BAT=false
|
||||
TERM_WIDTH="$(term_width)"
|
||||
|
||||
if [[ -n "${BATPIPE_TERM_WIDTH:-}" ]]; then
|
||||
if [[ "${BATPIPE_TERM_WIDTH:0:1}" = "-" ]]; then
|
||||
TERM_WIDTH=$((TERM_WIDTH + BATPIPE_TERM_WIDTH)) || true
|
||||
else
|
||||
TERM_WIDTH="$BATPIPE_TERM_WIDTH"
|
||||
fi
|
||||
fi
|
||||
|
||||
BATPIPE_PARENT_EXECUTABLE_PID="$PPID"
|
||||
for i in 1 2 3; do
|
||||
BATPIPE_PARENT_EXECUTABLE="${BATPIPE_DEBUG_PARENT_EXECUTABLE:-$(parent_executable "$BATPIPE_PARENT_EXECUTABLE_PID")}"
|
||||
BATPIPE_PARENT_EXECUTABLE_BASENAME="$(basename -- "${BATPIPE_PARENT_EXECUTABLE}" | cut -d' ' -f1)"
|
||||
BATPIPE_PARENT_EXECUTABLE_PID="$(parent_executable_pid "$BATPIPE_PARENT_EXECUTABLE_PID")"
|
||||
|
||||
if [[ "${BATPIPE_PARENT_EXECUTABLE_BASENAME}" = "less" ]]; then
|
||||
BATPIPE_INSIDE_LESS=true
|
||||
break
|
||||
elif [[ "${BATPIPE_PARENT_EXECUTABLE_BASENAME}" == "$(basename -- "$EXECUTABLE_BAT")" ]]; then
|
||||
BATPIPE_INSIDE_BAT=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ -n "${BATPIPE_DEBUG:-}" ]]; then
|
||||
printf "batpipe debug:\n"
|
||||
printf " %s: %s\n" \
|
||||
"BATPIPE_INSIDE_LESS" "${BATPIPE_INSIDE_LESS}" \
|
||||
"BATPIPE_INSIDE_BAT" "${BATPIPE_INSIDE_BAT}"
|
||||
printf "\n"
|
||||
fi
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Viewers:
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
if ! command -v eza &> /dev/null
|
||||
then
|
||||
BATPIPE_VIEWERS=("eza" "ls" "tar" "tar_gz" "unzip" "gunzip" "xz")
|
||||
else
|
||||
BATPIPE_VIEWERS=("exa" "ls" "tar" "tar_bz2" "unzip" "gunzip" "xz")
|
||||
fi
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
viewer_exa_supports() {
|
||||
[[ -d "$2" ]] || return 1
|
||||
command -v "exa" &> /dev/null || return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
viewer_eza_supports() {
|
||||
[[ -d "$2" ]] || return 1
|
||||
command -v "eza" &> /dev/null || return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
viewer_exa_process() {
|
||||
local dir="$(strip_trailing_slashes "$1")"
|
||||
batpipe_header "Viewing contents of directory: %{PATH}%s" "$dir"
|
||||
if "$BATPIPE_ENABLE_COLOR"; then
|
||||
exa -la --color=always "$1" 2>&1
|
||||
else
|
||||
exa -la --color=never "$1" 2>&1
|
||||
fi
|
||||
return $?
|
||||
}
|
||||
viewer_eza_process() {
|
||||
local dir="$(strip_trailing_slashes "$1")"
|
||||
batpipe_header "Viewing contents of directory: %{PATH}%s" "$dir"
|
||||
if "$BATPIPE_ENABLE_COLOR"; then
|
||||
eza -la --color=always "$1" 2>&1
|
||||
else
|
||||
eza -la --color=never "$1" 2>&1
|
||||
fi
|
||||
return $?
|
||||
}
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
viewer_ls_supports() {
|
||||
[[ -d "$2" ]]
|
||||
return $?
|
||||
}
|
||||
|
||||
viewer_ls_process() {
|
||||
local dir="$(strip_trailing_slashes "$1")"
|
||||
batpipe_header "Viewing contents of directory: %{PATH}%s" "$dir"
|
||||
ls -lA "$1" 2>&1
|
||||
return $?
|
||||
}
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
viewer_tar_supports() {
|
||||
command -v "tar" &> /dev/null || return 1
|
||||
|
||||
case "$1" in
|
||||
*.tar | *.tar.*) return 0 ;;
|
||||
esac
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
viewer_tar_process() {
|
||||
if [[ -n "$2" ]]; then
|
||||
tar $3 -xf "$1" -O "$2" | bat --file-name="$1/$2"
|
||||
else
|
||||
batpipe_archive_header
|
||||
tar $3 -tvf "$1"
|
||||
return $?
|
||||
fi
|
||||
}
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
viewer_tar_gz_supports() {
|
||||
command -v "tar" &> /dev/null || return 1
|
||||
command -v "gzip" &> /dev/null || return 1
|
||||
|
||||
case "$1" in
|
||||
*.tar.gz | *.tgz) return 0 ;;
|
||||
esac
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
viewer_tar_gz_process() {
|
||||
viewer_tar_process "$1" "$2" -z
|
||||
}
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
viewer_tar_bz2_supports() {
|
||||
command -v "tar" &> /dev/null || return 1
|
||||
command -v "bzip2" &> /dev/null || return 1
|
||||
|
||||
case "$1" in
|
||||
*.tar.bz2 | *.tbz) return 0 ;;
|
||||
esac
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
viewer_tar_bz2_process() {
|
||||
viewer_tar_process "$1" "$2" -j
|
||||
}
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
viewer_unzip_supports() {
|
||||
command -v "unzip" &> /dev/null || return 1
|
||||
|
||||
case "$1" in
|
||||
*.zip) return 0 ;;
|
||||
esac
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
viewer_unzip_process() {
|
||||
if [[ -n "$2" ]]; then
|
||||
unzip -p "$1" "$2" | bat --file-name="$1/$2"
|
||||
else
|
||||
batpipe_archive_header
|
||||
unzip -l "$1"
|
||||
return $?
|
||||
fi
|
||||
}
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
viewer_gunzip_supports() {
|
||||
command -v "gunzip" &> /dev/null || return 1
|
||||
[[ -z "$3" ]] || return 1
|
||||
|
||||
case "$2" in
|
||||
*.gz) return 0 ;;
|
||||
esac
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
viewer_gunzip_process() {
|
||||
gunzip -k -c "$1" | bat --file-name="$1"
|
||||
return $?
|
||||
}
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
viewer_xz_supports() {
|
||||
command -v "xz" &> /dev/null || return 1
|
||||
[[ -z "$3" ]] || return 1
|
||||
|
||||
case "$2" in
|
||||
*.xz) return 0 ;;
|
||||
esac
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
viewer_xz_process() {
|
||||
xz --decompress -k -c "$1" | bat --file-name="$1"
|
||||
return $?
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Functions:
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Print a header for batpipe messages.
|
||||
# Arguments:
|
||||
# 1 -- The printc formatting string.
|
||||
# ... -- The printc formatting arguments.
|
||||
batpipe_header() {
|
||||
local pattern="${1//%{C\}/%{C\}%{HEADER\}}"
|
||||
printc "%{HEADER}==> $pattern%{C}\n" "${@:2}"
|
||||
}
|
||||
|
||||
# Print a subheader for batpipe messages.
|
||||
# Arguments:
|
||||
# 1 -- The printc formatting string.
|
||||
# ... -- The printc formatting arguments.
|
||||
batpipe_subheader() {
|
||||
local pattern="${1//%{C\}/%{C\}%{SUBHEADER\}}"
|
||||
printc "%{SUBHEADER}==> $pattern%{C}\n" "${@:2}"
|
||||
}
|
||||
|
||||
batpipe_archive_header() {
|
||||
batpipe_header "Viewing contents of archive: %{PATH}%s" "$1"
|
||||
batpipe_subheader "To view files within the archive, add the file path after the archive."
|
||||
}
|
||||
|
||||
# Executes `bat` (or `cat`, if already running from within `bat`).
|
||||
# Supports the `--file-name` argument if the bat version is new enough.
|
||||
#
|
||||
# NOTE: The `--key=value` option syntax is required for full compatibility.
|
||||
bat() {
|
||||
# Conditionally enable forwarding of certain arguments.
|
||||
if [[ -z "$__BAT_VERSION" ]]; then
|
||||
__BAT_VERSION="$(bat_version)"
|
||||
|
||||
__bat_forward_arg_file_name() { :; }
|
||||
|
||||
if version_compare "$__BAT_VERSION" -ge "0.14"; then
|
||||
__bat_forward_arg_file_name() {
|
||||
__bat_forward_args+=("--file-name" "$1")
|
||||
}
|
||||
fi
|
||||
fi
|
||||
|
||||
# Parse arguments intended for bat.
|
||||
__bat_batpipe_args=()
|
||||
__bat_forward_args=()
|
||||
__bat_files=()
|
||||
setargs "$@"
|
||||
while shiftopt; do
|
||||
case "$OPT" in
|
||||
--file-name)
|
||||
shiftval
|
||||
__bat_forward_arg_file_name "$OPT_VAL"
|
||||
;;
|
||||
|
||||
# Disallowed forwarding.
|
||||
--paging) shiftval ;;
|
||||
--decorations) shiftval ;;
|
||||
--style) shiftval ;;
|
||||
--terminal-width) shiftval ;;
|
||||
--plain | -p | -pp | -ppp) : ;;
|
||||
|
||||
# Forward remaining.
|
||||
-*) {
|
||||
__bat_forward_args+=("$OPT")
|
||||
if [[ -n "$OPT_VAL" ]]; then
|
||||
__bat_forward_args+=("$OPT_VAL")
|
||||
fi
|
||||
} ;;
|
||||
|
||||
*) {
|
||||
__bat_forward_args+=("$OPT")
|
||||
__bat_files=("$OPT")
|
||||
} ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Insert batpipe arguments.
|
||||
if "$BATPIPE_INSIDE_LESS"; then
|
||||
__bat_batpipe_args+=(--decorations=always)
|
||||
__bat_batpipe_args+=(--terminal-width="$TERM_WIDTH")
|
||||
if "$BATPIPE_ENABLE_COLOR"; then
|
||||
__bat_batpipe_args+=(--color=always)
|
||||
else
|
||||
__bat_batpipe_args+=(--color=never)
|
||||
fi
|
||||
fi
|
||||
|
||||
if "$BATPIPE_INSIDE_BAT"; then
|
||||
if [[ "${#__bat_files[@]}" -eq 0 ]]; then
|
||||
cat
|
||||
else
|
||||
cat "${__bat_files[@]}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Execute the real bat.
|
||||
command "$EXECUTABLE_BAT" --paging=never "${__bat_batpipe_args[@]}" "${__bat_forward_args[@]}"
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Colors:
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
printc_init "[DEFINE]" << END
|
||||
C \x1B[0m
|
||||
SUBPATH \x1B[2;35m
|
||||
PATH \x1B[0;35m
|
||||
HEADER \x1B[0;36m
|
||||
SUBHEADER \x1B[2;36m
|
||||
END
|
||||
|
||||
# Enable color output if:
|
||||
# - Parent is not less OR BATPIPE=color; AND
|
||||
# - NO_COLOR is not defined.
|
||||
#
|
||||
# shellcheck disable=SC2034
|
||||
if [[ "$BATPIPE_INSIDE_LESS" == "false" || "$BATPIPE" == "color" ]] && [[ -z "${NO_COLOR+x}" ]]; then
|
||||
BATPIPE_ENABLE_COLOR=true
|
||||
printc_init true
|
||||
else
|
||||
BATPIPE_ENABLE_COLOR=false
|
||||
printc_init false
|
||||
fi
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Main:
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
__CONFIG_DIR="$(config_dir batpipe)"
|
||||
__TARGET_INSIDE=""
|
||||
__TARGET_FILE="$(strip_trailing_slashes "$1")"
|
||||
|
||||
# Determine the target file by walking upwards from the specified path.
|
||||
# This allows inner paths of archives to be used.
|
||||
while ! [[ -e "$__TARGET_FILE" ]]; do
|
||||
__TARGET_INSIDE="$(basename -- "${__TARGET_FILE}")/${__TARGET_INSIDE}"
|
||||
__TARGET_FILE="$(dirname -- "${__TARGET_FILE}")"
|
||||
done
|
||||
|
||||
# If the target file isn't actually a file, then the inner path should be appended.
|
||||
if ! [[ -f "$__TARGET_FILE" ]]; then
|
||||
__TARGET_FILE="${__TARGET_FILE}/${__TARGET_INSIDE}"
|
||||
__TARGET_INSIDE=""
|
||||
fi
|
||||
|
||||
# If an inner path exists or the target file isn't a directory, the target file should not have trailing slashes.
|
||||
if [[ -n "$__TARGET_INSIDE" ]] || ! [[ -d "$__TARGET_FILE" ]]; then
|
||||
__TARGET_FILE="$(strip_trailing_slashes "$__TARGET_FILE")"
|
||||
fi
|
||||
|
||||
# Remove trailing slash of the inner target path.
|
||||
__TARGET_INSIDE="$(strip_trailing_slashes "$__TARGET_INSIDE")"
|
||||
__TARGET_BASENAME="$(basename -- "$__TARGET_FILE")"
|
||||
|
||||
# Stop bat from calling this recursively.
|
||||
unset LESSOPEN
|
||||
unset LESSCLOSE
|
||||
|
||||
# Load external viewers.
|
||||
if [[ -d "${__CONFIG_DIR}/viewers.d" ]]; then
|
||||
unset LIB
|
||||
unset SELF
|
||||
|
||||
shopt -s nullglob
|
||||
for viewer_script in "${__CONFIG_DIR}/viewers.d"/*; do
|
||||
source "${viewer_script}"
|
||||
done
|
||||
shopt -u nullglob
|
||||
fi
|
||||
|
||||
# Try opening the file with the first viewer that supports it.
|
||||
for viewer in "${BATPIPE_VIEWERS[@]}"; do
|
||||
if "viewer_${viewer}_supports" "$__TARGET_BASENAME" "$__TARGET_FILE" "$__TARGET_INSIDE" 1>&2; then
|
||||
"viewer_${viewer}_process" "$__TARGET_FILE" "$__TARGET_INSIDE"
|
||||
exit $?
|
||||
fi
|
||||
done
|
||||
|
||||
# No supported viewer. Just pass it through (if using bat).
|
||||
if [[ "$BATPIPE_INSIDE_BAT" == true ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# No supported viewer... highlight it using bat.
|
||||
if [[ -f "$1" ]]; then
|
||||
bat "$1"
|
||||
fi
|
||||
216
src/batwatch.sh
216
src/batwatch.sh
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
# -----------------------------------------------------------------------------
|
||||
# bat-extras | Copyright (C) 2019 eth-p | MIT License
|
||||
# bat-extras | Copyright (C) 2019-2020 eth-p | MIT License
|
||||
#
|
||||
# Repository: https://github.com/eth-p/bat-extras
|
||||
# Issues: https://github.com/eth-p/bat-extras/issues
|
||||
|
|
@ -9,15 +9,27 @@
|
|||
LIB="$(cd "$(dirname "${BASH_SOURCE[0]}")" && cd "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo ".")")/../lib" && pwd)"
|
||||
source "${LIB}/constants.sh"
|
||||
source "${LIB}/opt.sh"
|
||||
source "${LIB}/opt_hooks.sh"
|
||||
source "${LIB}/opt_hook_color.sh"
|
||||
source "${LIB}/opt_hook_help.sh"
|
||||
source "${LIB}/opt_hook_version.sh"
|
||||
source "${LIB}/opt_hook_width.sh"
|
||||
source "${LIB}/print.sh"
|
||||
source "${LIB}/pager.sh"
|
||||
source "${LIB}/version.sh"
|
||||
# -----------------------------------------------------------------------------
|
||||
# Init:
|
||||
# -----------------------------------------------------------------------------
|
||||
hook_color
|
||||
hook_pager
|
||||
hook_version
|
||||
hook_width
|
||||
hook_help
|
||||
# -----------------------------------------------------------------------------
|
||||
# Help:
|
||||
# -----------------------------------------------------------------------------
|
||||
show_help() {
|
||||
echo 'Usage: batwatch --file [--watcher entr|poll][--[no-]clear] <file> [<file> ...]'
|
||||
echo ' batwatch --command [-n<interval>] <command> [<arg> ...]'
|
||||
}
|
||||
# -----------------------------------------------------------------------------
|
||||
# Watchers:
|
||||
# -----------------------------------------------------------------------------
|
||||
|
|
@ -29,20 +41,20 @@ WATCHERS=("entr" "poll")
|
|||
watcher_entr_watch() {
|
||||
ENTR_ARGS=()
|
||||
|
||||
if [[ "$OPT_CLEAR" = "true" ]]; then
|
||||
if [[ "$OPT_CLEAR" == "true" ]]; then
|
||||
ENTR_ARGS+=('-c')
|
||||
fi
|
||||
|
||||
entr "${ENTR_ARGS[@]}" \
|
||||
"$EXECUTABLE_BAT" "${BAT_ARGS[@]}" \
|
||||
--terminal-width="$TERM_WIDTH" \
|
||||
--terminal-width="$OPT_TERMINAL_WIDTH" \
|
||||
--paging=never \
|
||||
"$@" \
|
||||
< <(printf "%s\n" "$@")
|
||||
}
|
||||
|
||||
watcher_entr_supported() {
|
||||
command -v entr &>/dev/null
|
||||
command -v entr &> /dev/null
|
||||
return $?
|
||||
}
|
||||
|
||||
|
|
@ -56,19 +68,22 @@ determine_stat_variant() {
|
|||
return 0
|
||||
fi
|
||||
|
||||
# Try GNU stat.
|
||||
if stat -c '%z' "$0" &>/dev/null; then
|
||||
POLL_STAT_COMMAND=(stat -c '%z')
|
||||
POLL_STAT_VARIANT='gnu'
|
||||
return 0
|
||||
fi
|
||||
local variant name flags ts
|
||||
for variant in "gnu -c %Z" "bsd -f %m"; do
|
||||
read -r name flags <<< "$variant"
|
||||
|
||||
# Try BSD stat.
|
||||
if stat -f '%m' "$0" &>/dev/null; then
|
||||
POLL_STAT_COMMAND=(stat -f '%m')
|
||||
POLL_STAT_VARIANT='bsd'
|
||||
return 0
|
||||
fi
|
||||
# save the results of the stat command
|
||||
if read -r ts < <(stat ${flags} "$0" 2> /dev/null); then
|
||||
|
||||
# verify that the value is an epoch timestamp
|
||||
# before proceeding
|
||||
if [[ "${ts}" =~ ^[0-9]+$ ]]; then
|
||||
POLL_STAT_COMMAND=(stat ${flags})
|
||||
POLL_STAT_VARIANT="$name"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
|
@ -92,17 +107,15 @@ watcher_poll_watch() {
|
|||
while true; do
|
||||
if "$modified"; then
|
||||
modified=false
|
||||
|
||||
if [[ "$OPT_CLEAR" = "true" ]]; then
|
||||
clear
|
||||
fi
|
||||
|
||||
clear
|
||||
"$EXECUTABLE_BAT" "${BAT_ARGS[@]}" \
|
||||
--terminal-width="$TERM_WIDTH" \
|
||||
--terminal-width="$OPT_TERMINAL_WIDTH" \
|
||||
--paging=never \
|
||||
"${files[@]}"
|
||||
|
||||
fi
|
||||
|
||||
# Check if the file has been modified.
|
||||
local i=0
|
||||
for file in "${files[@]}"; do
|
||||
time="$("${POLL_STAT_COMMAND[@]}" "$file")"
|
||||
|
|
@ -115,7 +128,12 @@ watcher_poll_watch() {
|
|||
((i++))
|
||||
done
|
||||
|
||||
sleep 1
|
||||
# Wait for "q" to exit, or check again after a few seconds.
|
||||
local input
|
||||
read -r -t "${OPT_INTERVAL}" input
|
||||
if [[ "$input" =~ [q|Q] ]]; then
|
||||
exit
|
||||
fi
|
||||
done
|
||||
|
||||
"${POLL_STAT_COMMAND[@]}" "$@"
|
||||
|
|
@ -135,7 +153,7 @@ determine_watcher() {
|
|||
local watcher
|
||||
for watcher in "${WATCHERS[@]}"; do
|
||||
if "watcher_${watcher}_supported"; then
|
||||
echo "$watcher"
|
||||
OPT_WATCHER="$watcher"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
|
@ -146,12 +164,13 @@ determine_watcher() {
|
|||
# -----------------------------------------------------------------------------
|
||||
# Options:
|
||||
# -----------------------------------------------------------------------------
|
||||
BAT_ARGS=()
|
||||
BAT_ARGS=(--paging=never)
|
||||
FILES=()
|
||||
FILES_HAS_DIRECTORY=false
|
||||
OPT_MODE=file
|
||||
OPT_INTERVAL=3
|
||||
OPT_CLEAR=true
|
||||
OPT_WATCHER=""
|
||||
TERM_WIDTH="$(tput cols)"
|
||||
|
||||
# Set options based on tty.
|
||||
if [[ -t 1 ]]; then
|
||||
|
|
@ -162,38 +181,52 @@ fi
|
|||
while shiftopt; do
|
||||
case "$OPT" in
|
||||
|
||||
# Script options
|
||||
--watcher) shiftval; OPT_WATCHER="$OPT_VAL" ;;
|
||||
--clear) OPT_CLEAR=true ;;
|
||||
--no-clear) OPT_CLEAR=false ;;
|
||||
--terminal-width) shiftval; TERM_WIDTH="$OPT_VAL" ;;
|
||||
# Script options
|
||||
--watcher) shiftval; OPT_WATCHER="$OPT_VAL" ;;
|
||||
--interval|-n) shiftval; OPT_INTERVAL="$OPT_VAL" ;;
|
||||
--file|-f) OPT_MODE=file ;;
|
||||
--command|-x) OPT_MODE=command ;;
|
||||
--clear) OPT_CLEAR=true ;;
|
||||
--no-clear) OPT_CLEAR=false ;;
|
||||
|
||||
# bat/Pager options
|
||||
-*) BAT_ARGS+=("$OPT=$OPT_VAL") ;;
|
||||
# bat/Pager options
|
||||
-*) BAT_ARGS+=("$OPT=$OPT_VAL") ;;
|
||||
|
||||
# Files
|
||||
*) {
|
||||
FILES+=("$OPT")
|
||||
} ;;
|
||||
# Files
|
||||
*) {
|
||||
FILES+=("$OPT")
|
||||
if [[ "$OPT_MODE" = "command" ]]; then
|
||||
getargs --append FILES
|
||||
break
|
||||
fi
|
||||
} ;;
|
||||
|
||||
esac
|
||||
done
|
||||
|
||||
# Validate that a file/command was provided.
|
||||
if [[ ${#FILES[@]} -eq 0 ]]; then
|
||||
print_error "no files provided"
|
||||
if [[ "$OPT_MODE" = "file" ]]; then
|
||||
print_error "no files provided"
|
||||
else
|
||||
print_error "no command provided"
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
for file in "${FILES[@]}"; do
|
||||
if ! [[ -e "$file" ]]; then
|
||||
print_error "'%s' does not exist" "$file"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -d "$file" ]]; then
|
||||
FILES_HAS_DIRECTORY=true
|
||||
fi
|
||||
done
|
||||
|
||||
# Validate that the provided files exist.
|
||||
if [[ "$OPT_MODE" = "file" ]]; then
|
||||
for file in "${FILES[@]}"; do
|
||||
if ! [[ -e "$file" ]]; then
|
||||
print_error "'%s' does not exist" "$file"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -d "$file" ]]; then
|
||||
FILES_HAS_DIRECTORY=true
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Append bat arguments.
|
||||
if "$OPT_COLOR"; then
|
||||
|
|
@ -202,33 +235,76 @@ else
|
|||
BAT_ARGS+=("--color=never")
|
||||
fi
|
||||
|
||||
# Initialize clear command based on whether or not ANSI should be used.
|
||||
if [[ "$OPT_CLEAR" == "true" ]]; then
|
||||
if "$OPT_COLOR"; then
|
||||
clear() {
|
||||
term_clear || return $?
|
||||
}
|
||||
fi
|
||||
else
|
||||
clear() {
|
||||
:
|
||||
}
|
||||
fi
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Main:
|
||||
# -----------------------------------------------------------------------------
|
||||
# Determine the watcher.
|
||||
if [[ -z "$OPT_WATCHER" ]]; then
|
||||
if ! OPT_WATCHER="$(determine_watcher)"; then
|
||||
print_error "Your system does not have any supported watchers."
|
||||
printc "Please read the documentation at %{BLUE}%s%{CLEAR} for more details.\n" "$PROGRAM_HOMEPAGE" 1>&2
|
||||
exit 2
|
||||
if [[ "$OPT_MODE" = "file" ]]; then
|
||||
# Determine the watcher.
|
||||
if [[ -z "$OPT_WATCHER" ]]; then
|
||||
if ! determine_watcher; then
|
||||
print_error "Your system does not have any supported watchers."
|
||||
printc "Please read the documentation at %{BLUE}%s%{CLEAR} for more details.\n" "$PROGRAM_HOMEPAGE" 1>&2
|
||||
exit 2
|
||||
fi
|
||||
else
|
||||
if ! type "watcher_${OPT_WATCHER}_supported" &> /dev/null; then
|
||||
print_error "Unknown watcher: '%s'" "$OPT_WATCHER"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! "watcher_${OPT_WATCHER}_supported" &> /dev/null; then
|
||||
print_error "Unsupported watcher: '%s'" "$OPT_WATCHER"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
main() {
|
||||
"watcher_${OPT_WATCHER}_watch" "${FILES[@]}"
|
||||
return $?
|
||||
}
|
||||
else
|
||||
if ! type "watcher_${OPT_WATCHER}_supported" &>/dev/null; then
|
||||
print_error "Unknown watcher: '%s'" "$OPT_WATCHER"
|
||||
exit 1
|
||||
|
||||
# Set bat's header to show the command.
|
||||
BAT_VERSION="$(bat_version)"
|
||||
if version_compare "$BAT_VERSION" -ge "0.14"; then
|
||||
BAT_ARGS+=(--file-name="${FILES[*]}")
|
||||
fi
|
||||
|
||||
if ! "watcher_${OPT_WATCHER}_supported" &>/dev/null; then
|
||||
print_error "Unsupported watcher: '%s'" "$OPT_WATCHER"
|
||||
exit 1
|
||||
fi
|
||||
main() {
|
||||
local last_rendered
|
||||
local rendered
|
||||
local term_width="$(term_width)"
|
||||
BAT_ARGS+=("--terminal-width=$term_width")
|
||||
|
||||
while true; do
|
||||
IFS='' rendered="$("${FILES[@]}" 2>&1 | "$EXECUTABLE_BAT" "${BAT_ARGS[@]}")"
|
||||
if [ "$rendered" != "$last_rendered" ]; then
|
||||
# Only clear and redraw if there's a change.
|
||||
# This reduces excessive flickering.
|
||||
last_rendered="$rendered"
|
||||
clear
|
||||
printf "%s\n" "$rendered"
|
||||
rendered=''
|
||||
fi
|
||||
|
||||
sleep "${OPT_INTERVAL}" || exit 1
|
||||
done
|
||||
}
|
||||
fi
|
||||
|
||||
# Run the main function.
|
||||
main() {
|
||||
"watcher_${OPT_WATCHER}_watch" "${FILES[@]}"
|
||||
return $?
|
||||
}
|
||||
|
||||
pager_exec main
|
||||
main
|
||||
exit $?
|
||||
|
|
|
|||
183
src/prettybat.sh
183
src/prettybat.sh
|
|
@ -12,6 +12,9 @@ source "${LIB}/opt.sh"
|
|||
source "${LIB}/opt_hook_version.sh"
|
||||
source "${LIB}/str.sh"
|
||||
source "${LIB}/print.sh"
|
||||
source "${LIB}/version.sh"
|
||||
source "${LIB}/check.sh"
|
||||
source "${LIB}/term.sh"
|
||||
# -----------------------------------------------------------------------------
|
||||
# Init:
|
||||
# -----------------------------------------------------------------------------
|
||||
|
|
@ -20,16 +23,20 @@ hook_version
|
|||
# Formatters:
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
FORMATTERS=("prettier" "rustfmt" "shfmt" "clangformat")
|
||||
FORMATTERS=(
|
||||
"yq" "prettier" "rustfmt" "shfmt" "clangformat"
|
||||
"black" "mix_format" "column"
|
||||
)
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
formatter_prettier_supports() {
|
||||
case "$1" in
|
||||
.js | .jsx | \
|
||||
.js | .jsx | \
|
||||
.ts | .tsx | \
|
||||
.css | .scss | .sass | \
|
||||
.html | \
|
||||
.graphql | .gql | \
|
||||
.html | .svg | \
|
||||
.json | \
|
||||
.md | \
|
||||
.yml)
|
||||
|
|
@ -41,7 +48,14 @@ formatter_prettier_supports() {
|
|||
}
|
||||
|
||||
formatter_prettier_process() {
|
||||
prettier --stdin --stdin-filepath "$1" 2>/dev/null
|
||||
# Rewrite the file extension to hackily support SVG.
|
||||
local file="$1"
|
||||
local fext="$(extname "$file")"
|
||||
case "$fext" in
|
||||
.svg) file="$(basename -- "$file" "$fext").html" ;;
|
||||
esac
|
||||
|
||||
prettier --stdin --stdin-filepath "$file" 2>/dev/null
|
||||
return $?
|
||||
}
|
||||
|
||||
|
|
@ -88,12 +102,122 @@ formatter_shfmt_process() {
|
|||
return $?
|
||||
}
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
formatter_black_supports() {
|
||||
case "$1" in
|
||||
.py | \
|
||||
.py3 | \
|
||||
.pyw | \
|
||||
.pyi)
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
formatter_black_process() {
|
||||
black --code "$(cat -)"
|
||||
return $?
|
||||
}
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
formatter_mix_format_supports() {
|
||||
case "$1" in
|
||||
.ex | \
|
||||
.exs | \
|
||||
.eex | \
|
||||
.heex)
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
formatter_mix_format_process() {
|
||||
mix format
|
||||
return $?
|
||||
}
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
formatter_column_supports() {
|
||||
case "$1" in
|
||||
.tsv)
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
formatter_column_process() {
|
||||
local needs_newline=true
|
||||
local args=(
|
||||
-t
|
||||
-s $'\t'
|
||||
-c "$TERMINAL_WIDTH"
|
||||
)
|
||||
|
||||
if column --help &>/dev/null; then
|
||||
# GNU `column`
|
||||
args+=(--keep-empty-lines)
|
||||
needs_newline=false
|
||||
fi
|
||||
|
||||
{ { "$needs_newline" && sed 's/$/\n/'; } || cat; } | column "${args[@]}"
|
||||
}
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
formatter_yq_supports__version_ok() {
|
||||
local yq_version
|
||||
yq_version=$(yq --version | sed 's/^.* version v//')
|
||||
|
||||
# If it's older than yq version 4, replace the functions to save processing.
|
||||
if version_compare "$yq_version" -lt 4.0; then
|
||||
formatter_yq_supports() { return 1; }
|
||||
formatter_yq_supports__version_ok() { return 1; }
|
||||
return 1
|
||||
fi
|
||||
|
||||
# It's supported.
|
||||
formatter_yq_supports__version_ok() { return 0; }
|
||||
return 0
|
||||
}
|
||||
|
||||
formatter_yq_supports() {
|
||||
case "$1" in
|
||||
.yaml | yml | \
|
||||
.json)
|
||||
formatter_yq_supports__version_ok
|
||||
return $?
|
||||
;;
|
||||
esac
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
formatter_yq_process() {
|
||||
local args=()
|
||||
case "$1" in
|
||||
*.json) args+=(--output-format json) ;;
|
||||
esac
|
||||
|
||||
yq --prettyPrint --indent 4 "${args[@]}" \
|
||||
| sed -e ':l' -e 's/^\(\t*\) /\1\t/g; t l'
|
||||
return $?
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Functions:
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# This function will map a bat `--language=...` argument into an appropriate
|
||||
# file extension for the language provided. This must be hardcoded for
|
||||
# file extension for the language provided. This should be hardcoded for
|
||||
# performance reasons.
|
||||
map_language_to_extension() {
|
||||
local ext=".txt"
|
||||
|
|
@ -107,11 +231,17 @@ map_language_to_extension() {
|
|||
css) ext=".css" ;;
|
||||
scss) ext=".scss" ;;
|
||||
sass) ext=".sass" ;;
|
||||
svg ) ext=".svg" ;;
|
||||
html | htm | shtml | xhtml) ext=".html" ;;
|
||||
json) ext=".json" ;;
|
||||
md | mdown | markdown) ext=".md" ;;
|
||||
yaml | yml) ext=".yml" ;;
|
||||
rust | rs) ext=".rs" ;;
|
||||
graphql | gql) ext=".graphql" ;;
|
||||
python | py) ext=".py" ;;
|
||||
elixir | ex) ext=".ex" ;;
|
||||
exs) ext=".exs" ;;
|
||||
tsv) ext=".tsv" ;;
|
||||
esac
|
||||
|
||||
echo "$ext"
|
||||
|
|
@ -138,28 +268,38 @@ extname() {
|
|||
}
|
||||
|
||||
print_file() {
|
||||
if [[ "${#BAT_ARGS[@]}" -eq 0 ]]; then
|
||||
if [[ "${#PRINT_ARGS[@]}" -eq 0 ]]; then
|
||||
"$EXECUTABLE_BAT" "$@"
|
||||
return $?
|
||||
else
|
||||
"$EXECUTABLE_BAT" "${BAT_ARGS[@]}" "$@"
|
||||
"$EXECUTABLE_BAT" "${PRINT_ARGS[@]}" "$@"
|
||||
return $?
|
||||
fi
|
||||
}
|
||||
|
||||
process_file() {
|
||||
PRINT_ARGS=("${BAT_ARGS[@]}")
|
||||
local file="$1"
|
||||
local ext="$2"
|
||||
local fext="$ext"
|
||||
local lang="${ext:1}"
|
||||
local formatter
|
||||
|
||||
# Check that the file exists, and is a file.
|
||||
if [[ "$file" != "-" ]]; then
|
||||
check_exists "$file" || return 1
|
||||
check_is_file "$file" || return 1
|
||||
fi
|
||||
|
||||
# Determine the formatter.
|
||||
if [[ -n "$OPT_LANGUAGE" ]]; then
|
||||
lang="$OPT_LANGUAGE"
|
||||
fext="$(map_language_to_extension "$lang")"
|
||||
fi
|
||||
|
||||
formatter="$(map_extension_to_formatter "$fext")"
|
||||
if [[ "$ext" != "-" ]]; then
|
||||
formatter="$(map_extension_to_formatter "$fext")"
|
||||
fi
|
||||
|
||||
# Debug: Print the name and formatter.
|
||||
if "$DEBUG_PRINT_FORMATTER"; then
|
||||
|
|
@ -167,6 +307,9 @@ process_file() {
|
|||
return 0
|
||||
fi
|
||||
|
||||
# Calculate additional print arguments.
|
||||
forward_file_name "$file"
|
||||
|
||||
# Print the formatted file.
|
||||
if [[ "$formatter" = "none" ]]; then
|
||||
if [[ -z "$OPT_LANGUAGE" ]]; then
|
||||
|
|
@ -184,7 +327,7 @@ process_file() {
|
|||
# shellcheck disable=SC2094 disable=SC2181
|
||||
if [[ "$file" = "-" ]]; then
|
||||
data_raw="$(cat -)"
|
||||
data_formatted="$("formatter_${formatter}_process" "$file" 2>/dev/null <<<"$data_raw")"
|
||||
data_formatted="$("formatter_${formatter}_process" "STDIN${fext}" 2>/dev/null <<<"$data_raw")"
|
||||
|
||||
if [[ $? -ne 0 ]]; then
|
||||
print_warning "'STDIN': Unable to format with '%s'" "$formatter"
|
||||
|
|
@ -205,6 +348,19 @@ process_file() {
|
|||
return $?
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Version-Specific Features:
|
||||
# -----------------------------------------------------------------------------
|
||||
BAT_VERSION="$(bat_version)"
|
||||
|
||||
forward_file_name() { :; }
|
||||
|
||||
if version_compare "$BAT_VERSION" -ge "0.14"; then
|
||||
forward_file_name() {
|
||||
PRINT_ARGS+=("--file-name" "$1")
|
||||
}
|
||||
fi
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Main:
|
||||
# -----------------------------------------------------------------------------
|
||||
|
|
@ -213,6 +369,8 @@ OPT_LANGUAGE=
|
|||
FILES=()
|
||||
DEBUG_PRINT_FORMATTER=false
|
||||
|
||||
TERMINAL_WIDTH="$(term_width)"
|
||||
|
||||
# Parse arguments.
|
||||
while shiftopt; do
|
||||
case "$OPT" in
|
||||
|
|
@ -225,9 +383,14 @@ while shiftopt; do
|
|||
# Debug options
|
||||
--debug:formatter) DEBUG_PRINT_FORMATTER=true ;;
|
||||
|
||||
# Read from stdin
|
||||
-) FILES+=("-") ;;
|
||||
|
||||
# bat options
|
||||
-*) {
|
||||
BAT_ARGS+=("$OPT=$OPT_VAL")
|
||||
if [[ -n "$OPT_VAL" ]]; then BAT_ARGS+=("$OPT=$OPT_VAL");
|
||||
else BAT_ARGS+=("$OPT");
|
||||
fi
|
||||
} ;;
|
||||
|
||||
# Files
|
||||
|
|
|
|||
8
test.sh
8
test.sh
|
|
@ -23,13 +23,19 @@ export TEST_SHIM_PATH="${HERE}/test/shim"
|
|||
export SNAPSHOT_DIR="${HERE}/test/snapshot"
|
||||
|
||||
OPT_ARGV=()
|
||||
SHIFTOPT_SHORT_OPTIONS="PASS"
|
||||
while shiftopt; do
|
||||
case "$OPT" in
|
||||
--compiled)
|
||||
TEST_ENV_BIN_DIR="${HERE}/bin"
|
||||
TEST_ENV_BIN_SUFFIX=""
|
||||
;;
|
||||
*) OPT_ARGV+=("$OPT") ;;
|
||||
*)
|
||||
if [[ "$OPT_VAL" ]]; then
|
||||
OPT_ARGV+=("${OPT}=${OPT_VAL}")
|
||||
else
|
||||
OPT_ARGV+=("$OPT")
|
||||
fi ;;
|
||||
esac
|
||||
done
|
||||
|
||||
|
|
|
|||
BIN
test/data/compressed.txt.gz
Normal file
BIN
test/data/compressed.txt.gz
Normal file
Binary file not shown.
3
test/shim/batdiff.sh
Normal file
3
test/shim/batdiff.sh
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
batdiff() {
|
||||
"${BIN_DIR}/batdiff${BIN_SUFFIX}" "$@" || return $?
|
||||
}
|
||||
7
test/shim/batpipe.sh
Normal file
7
test/shim/batpipe.sh
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
batpipe() {
|
||||
"$(batpipe_path)" "$@" || return $?
|
||||
}
|
||||
|
||||
batpipe_path() {
|
||||
echo "${BIN_DIR}/batpipe${BIN_SUFFIX}"
|
||||
}
|
||||
|
|
@ -1,9 +1,15 @@
|
|||
#!/usr/bin/env bash
|
||||
exec 3<&0
|
||||
|
||||
# Find the real bat.
|
||||
HERE="$(cd "$(dirname "$0")" && pwd)"
|
||||
while read -d ':' -r dir; do
|
||||
if [[ "$dir" == "$HERE" ]]; then continue; fi
|
||||
if [[ "$dir" == "$HERE" || -z "$dir" ]]; then continue; fi
|
||||
if [[ -f "${dir}/bat" ]]; then
|
||||
exec "${dir}/bat" "$@" --theme="Monokai Extended"
|
||||
exec "${dir}/bat" "$@" --no-config --theme="Monokai Extended" <&3
|
||||
fi
|
||||
done <<<"$PATH"
|
||||
done <<<"$PATH:"
|
||||
|
||||
# Print error and exit.
|
||||
echo "bat was not found on \$PATH" 1>&2
|
||||
exit 127
|
||||
|
|
|
|||
4
test/shimexec/fish
Executable file
4
test/shimexec/fish
Executable file
|
|
@ -0,0 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
# Run bash, but with executable name as `fish`.
|
||||
exec -a "${SHIM_ARGV0:-fish}" bash "$@"
|
||||
exit $?
|
||||
|
|
@ -12,4 +12,10 @@ EOF
|
|||
exit 0
|
||||
fi
|
||||
|
||||
cat "$1"
|
||||
FILES=()
|
||||
while [[ $# -gt 0 ]]; do
|
||||
-*) : ;;
|
||||
*) FILES+=("$1")
|
||||
done
|
||||
|
||||
cat "${FILES[@]}"
|
||||
|
|
|
|||
7
test/shimexec/nu
Executable file
7
test/shimexec/nu
Executable file
|
|
@ -0,0 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
# Run bash, but with executable name as `nu`.
|
||||
#
|
||||
# Spawn the process in the background and wait on it to ensure we keep
|
||||
# the fake shell as a parent process.
|
||||
exec -a "${SHIM_ARGV0:-nu}" bash "$@"
|
||||
exit $?
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
case "$1" in
|
||||
cols) echo 80 ;;
|
||||
lines) echo 22 ;;
|
||||
size) echo "20 80" ;;
|
||||
esac
|
||||
0
test/snapshot/batdiff/test_version.stderr.snapshot
Normal file
0
test/snapshot/batdiff/test_version.stderr.snapshot
Normal file
3
test/snapshot/batdiff/test_version.stdout.snapshot
Normal file
3
test/snapshot/batdiff/test_version.stdout.snapshot
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
batdiff
|
||||
Copyright (C) 2019-2021 eth-p | MIT License
|
||||
https://github.com/eth-p/bat-extras
|
||||
0
test/snapshot/batgrep/test_help.stderr.snapshot
Normal file
0
test/snapshot/batgrep/test_help.stderr.snapshot
Normal file
107
test/snapshot/batgrep/test_help.stdout.snapshot
Normal file
107
test/snapshot/batgrep/test_help.stdout.snapshot
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
Quickly search through and highlight files using ripgrep.
|
||||
|
||||
Search through files or directories looking for matching regular expressions (or fixed strings with -F), and print the output using bat for an easy and syntax-highlighted experience.
|
||||
|
||||
Usage: batgrep [OPTIONS] PATTERN [PATH...]
|
||||
|
||||
Arguments:
|
||||
[OPTIONS]
|
||||
See Options below
|
||||
PATTERN
|
||||
Pattern passed to ripgrep
|
||||
[PATH...]
|
||||
Path(s) to search
|
||||
|
||||
Options:
|
||||
-i, --ignore-case:
|
||||
Use case insensitive searching.
|
||||
|
||||
-s, --case-sensitive:
|
||||
Use case sensitive searching.
|
||||
|
||||
-S, --smart-case:
|
||||
Use smart case searching
|
||||
|
||||
-A, --after-context=[LINES]:
|
||||
Display the next n lines after a matched line.
|
||||
|
||||
-B, --before-context=[LINES]:
|
||||
Display the previous n lines before a matched line.
|
||||
|
||||
-C, --context=[LINES]:
|
||||
A combination of --after-context and --before-context
|
||||
|
||||
-p, --search-pattern:
|
||||
Tell pager to search for PATTERN. Currently supported pagers: less.
|
||||
|
||||
--no-follow:
|
||||
Do not follow symlinks
|
||||
|
||||
--no-snip:
|
||||
Do not show the snip decoration
|
||||
|
||||
This is automatically enabled when --context=0 or when bat --version is less than 0.12.x
|
||||
|
||||
--no-highlight:
|
||||
Do not highlight matching lines.
|
||||
|
||||
This is automatically enabled when --context=0.
|
||||
|
||||
--color:
|
||||
Force color output.
|
||||
|
||||
--no-color:
|
||||
Force disable color output.
|
||||
|
||||
--paging=["never"/"always"]:
|
||||
Enable/disable paging.
|
||||
|
||||
--pager=[PAGER]:
|
||||
Specify the pager to use.
|
||||
|
||||
--terminal-width=[COLS]:
|
||||
Generate output for the specified terminal width.
|
||||
|
||||
--no-separator:
|
||||
Disable printing separator between files.
|
||||
|
||||
--rga:
|
||||
Use ripgrep-all instead of ripgrep.
|
||||
|
||||
Options passed directly to ripgrep:
|
||||
-F, --fixed-strings
|
||||
|
||||
-U, --multiline
|
||||
|
||||
-P, --pcre2
|
||||
|
||||
-z, --search-zip
|
||||
|
||||
-w, --word-regexp
|
||||
|
||||
--one-file-system
|
||||
|
||||
--multiline-dotall
|
||||
|
||||
--ignore, --no-ignore
|
||||
|
||||
--crlf, --no-crlf
|
||||
|
||||
--hidden, --no-hidden
|
||||
|
||||
-E --encoding:
|
||||
This is unsupported by bat, and may cause issues when trying to display unsupported encodings.
|
||||
|
||||
-g, --glob
|
||||
|
||||
-t, --type
|
||||
|
||||
-T, --type-not
|
||||
|
||||
-m, --max-count
|
||||
|
||||
--max-depth
|
||||
|
||||
--iglob
|
||||
|
||||
--ignore-file
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
[2m────────────────────────────────────────────────────────────────────────────────[0m
|
||||
File: [1mfile.txt[0m
|
||||
[38;5;238m 1[0m [48;5;236;38;5;231mcat[0m[48;5;236m [0m
|
||||
[38;5;238m 2[0m [38;5;231mdog[0m
|
||||
[38;5;238m 3[0m [48;5;236;38;5;231mcar[0m[48;5;236m [0m
|
||||
[38;5;238m 4[0m [38;5;231mfrog[0m
|
||||
[38;5;238m 5[0m [38;5;231mfox[0m
|
||||
[38;5;246m 1[0m [48;5;236;38;5;231mcat[0m[48;5;236m [0m
|
||||
[38;5;246m 2[0m [38;5;231mdog[0m
|
||||
[38;5;246m 3[0m [48;5;236;38;5;231mcar[0m[48;5;236m [0m
|
||||
[38;5;246m 4[0m [38;5;231mfrog[0m
|
||||
[38;5;246m 5[0m [38;5;231mfox[0m
|
||||
[2m────────────────────────────────────────────────────────────────────────────────[0m
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
File: [1mfile.txt[0m
|
||||
[38;5;246m 1[0m [48;5;236;38;5;231mcat[0m[48;5;236m [0m
|
||||
[38;5;246m 2[0m [38;5;231mdog[0m
|
||||
[38;5;246m 3[0m [48;5;236;38;5;231mcar[0m[48;5;236m [0m
|
||||
[38;5;246m 4[0m [38;5;231mfrog[0m
|
||||
[38;5;246m 5[0m [38;5;231mfox[0m
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
[38;5;246m────────────────────────────────────────────────────────────────────────────────[0m
|
||||
[48;5;236;38;5;231mcat[0m[48;5;236m [0m
|
||||
[38;5;231mdog[0m
|
||||
[48;5;236;38;5;231mcar[0m[48;5;236m [0m
|
||||
[38;5;231mfrog[0m
|
||||
[38;5;231mfox[0m
|
||||
[38;5;246m────────────────────────────────────────────────────────────────────────────────[0m
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
────────────────────────────────────────────────────────────────────────────────
|
||||
cat
|
||||
dog
|
||||
car
|
||||
frog
|
||||
fox
|
||||
────────────────────────────────────────────────────────────────────────────────
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
batgrep
|
||||
Copyright (C) 2019-2020 eth-p | MIT License
|
||||
Copyright (C) 2019-2021 eth-p | MIT License
|
||||
https://github.com/eth-p/bat-extras
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
batman
|
||||
Copyright (C) 2019-2020 eth-p | MIT License
|
||||
Copyright (C) 2019-2021 eth-p | MIT License
|
||||
https://github.com/eth-p/bat-extras
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
[38;5;246m───────┬────────────────────────────────[0m
|
||||
[38;5;246m│ [0mFile: [1mfile.txt[0m
|
||||
[38;5;246m───────┼────────────────────────────────[0m
|
||||
[38;5;246m 1[0m [38;5;246m│[0m [38;5;231mcat[0m
|
||||
[38;5;246m 2[0m [38;5;246m│[0m [38;5;231mdog[0m
|
||||
[38;5;246m 3[0m [38;5;246m│[0m [38;5;231mcar[0m
|
||||
[38;5;246m 4[0m [38;5;246m│[0m [38;5;231mfrog[0m
|
||||
[38;5;246m 5[0m [38;5;246m│[0m [38;5;231mfox[0m
|
||||
[38;5;246m 6[0m [38;5;246m│[0m [38;5;231mclocks[0m
|
||||
[38;5;246m 7[0m [38;5;246m│[0m [38;5;231mbash[0m
|
||||
[38;5;246m 8[0m [38;5;246m│[0m [38;5;231m$300[0m
|
||||
[38;5;246m 9[0m [38;5;246m│[0m [38;5;231m^$!@[0m
|
||||
[38;5;246m───────┴────────────────────────────────[0m
|
||||
[38;5;246m───────┬────────────────────────────────────────────────────[0m
|
||||
[38;5;246m│ [0mFile: [1mfile.txt[0m
|
||||
[38;5;246m───────┼────────────────────────────────────────────────────[0m
|
||||
[38;5;246m 1[0m [38;5;246m│[0m [38;5;231mcat[0m
|
||||
[38;5;246m 2[0m [38;5;246m│[0m [38;5;231mdog[0m
|
||||
[38;5;246m 3[0m [38;5;246m│[0m [38;5;231mcar[0m
|
||||
[38;5;246m 4[0m [38;5;246m│[0m [38;5;231mfrog[0m
|
||||
[38;5;246m 5[0m [38;5;246m│[0m [38;5;231mfox[0m
|
||||
[38;5;246m 6[0m [38;5;246m│[0m [38;5;231mclocks[0m
|
||||
[38;5;246m 7[0m [38;5;246m│[0m [38;5;231mbash[0m
|
||||
[38;5;246m 8[0m [38;5;246m│[0m [38;5;231m$300[0m
|
||||
[38;5;246m 9[0m [38;5;246m│[0m [38;5;231m^$!@[0m
|
||||
[38;5;246m───────┴────────────────────────────────────────────────────[0m
|
||||
4
test/snapshot/batwatch/test_displayed.stdout.snapshot
Normal file
4
test/snapshot/batwatch/test_displayed.stdout.snapshot
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
echo Hello, test world!
|
||||
if true; then
|
||||
! true
|
||||
fi
|
||||
2
test/snapshot/batwatch/test_help.stdout.snapshot
Normal file
2
test/snapshot/batwatch/test_help.stdout.snapshot
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
Usage: batwatch --file [--watcher entr|poll][--[no-]clear] <file> [<file> ...]
|
||||
batwatch --command [-n<interval>] <command> [<arg> ...]
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
batwatch
|
||||
Copyright (C) 2019-2020 eth-p | MIT License
|
||||
Copyright (C) 2019-2021 eth-p | MIT License
|
||||
https://github.com/eth-p/bat-extras
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
prettybat
|
||||
Copyright (C) 2019-2020 eth-p | MIT License
|
||||
Copyright (C) 2019-2021 eth-p | MIT License
|
||||
https://github.com/eth-p/bat-extras
|
||||
|
|
|
|||
12
test/suite/batdiff.sh
Normal file
12
test/suite/batdiff.sh
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
setup() {
|
||||
use_shim 'batdiff'
|
||||
}
|
||||
|
||||
test:version() {
|
||||
description "Test 'batdiff --version'"
|
||||
snapshot stdout
|
||||
snapshot stderr
|
||||
|
||||
batdiff --version | awk 'FNR <= 1 { print $1 }'
|
||||
batdiff --version | awk 'p{print} /^$/ { p=1 }'
|
||||
}
|
||||
|
|
@ -2,6 +2,8 @@ HAS_RIPGREP=false
|
|||
|
||||
setup() {
|
||||
use_shim 'batgrep'
|
||||
|
||||
unset BAT_STYLE
|
||||
|
||||
if command -v rg &>/dev/null; then
|
||||
HAS_RIPGREP=true
|
||||
|
|
@ -14,12 +16,21 @@ require_rg() {
|
|||
fi
|
||||
}
|
||||
|
||||
test:help() {
|
||||
description "Test 'batgrep --help'"
|
||||
snapshot stdout
|
||||
batgrep --help
|
||||
|
||||
assert batgrep --help
|
||||
batgrep --help | grep -q 'Usage'
|
||||
}
|
||||
|
||||
test:version() {
|
||||
description "Test 'batgrep --version'"
|
||||
snapshot stdout
|
||||
snapshot stderr
|
||||
|
||||
batgrep --version | head -n1 | cut -d' ' -f1
|
||||
batgrep --version | awk 'FNR <= 1 { print $1 }'
|
||||
batgrep --version | awk 'p{print} /^$/ { p=1 }'
|
||||
}
|
||||
|
||||
|
|
@ -92,3 +103,43 @@ test:option_context() {
|
|||
|
||||
batgrep -C 0 '\$' file.txt
|
||||
}
|
||||
|
||||
test:search_from_stdin() {
|
||||
description "Should be able to search through stdin."
|
||||
snapshot stdout
|
||||
snapshot stderr
|
||||
|
||||
require_rg
|
||||
|
||||
cat file.txt | batgrep "^ca"
|
||||
}
|
||||
|
||||
test:respects_bat_style() {
|
||||
description "Should respect the BAT_STYLE variable."
|
||||
snapshot stdout
|
||||
snapshot stderr
|
||||
|
||||
require_rg
|
||||
|
||||
BAT_STYLE="grid" batgrep "ca" file.txt --color=always
|
||||
}
|
||||
|
||||
test:output_without_separator() {
|
||||
description "Snapshot test for output without separator"
|
||||
snapshot stdout
|
||||
snapshot stderr
|
||||
|
||||
require_rg
|
||||
|
||||
batgrep "ca" file.txt --no-separator --color=always
|
||||
}
|
||||
|
||||
test:sanity_rg_works() {
|
||||
description "Ensure the ripgrep executable works"
|
||||
|
||||
require_rg
|
||||
|
||||
rg --version
|
||||
rg "ca" file.txt | grep "ca" || fail "Ripgrep executable not working."
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,6 @@ test:version() {
|
|||
snapshot stdout
|
||||
snapshot stderr
|
||||
|
||||
batman --version | head -n1 | cut -d' ' -f1
|
||||
batman --version | awk 'FNR <= 1 { print $1 }'
|
||||
batman --version | awk 'p{print} /^$/ { p=1 }'
|
||||
}
|
||||
|
|
|
|||
61
test/suite/batpipe.sh
Normal file
61
test/suite/batpipe.sh
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
setup() {
|
||||
use_shim 'batpipe'
|
||||
}
|
||||
|
||||
test:detected_bash_shell() {
|
||||
description "Test it can detect a bash shell."
|
||||
command -v "bash" &>/dev/null || skip "Test requires bash shell."
|
||||
|
||||
output="$(SHELL="bash" bash --login -c "{ \"$(batpipe_path)\"; }")" # This hack prevents bash from exec()'ing itself.
|
||||
grep '^LESSOPEN=' <<< "$output" >/dev/null || fail "Detected the wrong shell for bash."
|
||||
}
|
||||
|
||||
test:detected_fish_shell() {
|
||||
description "Test it can detect a fish shell."
|
||||
|
||||
# Note: We don't use bash's `-c` option when testing with a fake fish shell.
|
||||
# Bash `-c` will automatically exec() into the last process, which loses the
|
||||
# argv0 we intentionally named after a different shell.
|
||||
|
||||
# Test detection via `*sh -l` parent process.
|
||||
output="$(printf "%q" "$(batpipe_path)" | fish -l)"
|
||||
grep '^set -x' <<< "$output" >/dev/null || fail 'Detected wrong shell when checking parent process args.'
|
||||
|
||||
# Test detection via hypen-prefixed parent process.
|
||||
output="$(printf "%q" "$(batpipe_path)" | SHIM_ARGV0='-fish' fish)"
|
||||
grep '^set -x' <<< "$output" >/dev/null || fail 'Detected wrong shell when checking parent process.'
|
||||
}
|
||||
|
||||
test:detected_nu_shell() {
|
||||
description "Test it can detect a nushell shell."
|
||||
|
||||
# Note: We don't use bash's `-c` option when testing with a fake nu shell.
|
||||
# Bash `-c` will automatically exec() into the last process, which loses the
|
||||
# argv0 we intentionally named after a different shell.
|
||||
|
||||
# Test detection via `*sh -l` parent process.
|
||||
output="$(printf "%q" "$(batpipe_path)" | nu -l)"
|
||||
grep '^\$env' <<< "$output" >/dev/null || fail 'Detected wrong shell when checking parent process args.'
|
||||
|
||||
# Test detection via hypen-prefixed parent process.
|
||||
output="$(printf "%q" "$(batpipe_path)" | SHIM_ARGV0='-nu' nu -l)"
|
||||
grep '^\$env' <<< "$output" >/dev/null || fail 'Detected wrong shell when checking parent process.'
|
||||
}
|
||||
|
||||
test:viewer_gzip() {
|
||||
description "Test it can view .gz files."
|
||||
command -v "gunzip" &>/dev/null || skip "Test requires gunzip."
|
||||
|
||||
assert_equal "$(batpipe compressed.txt.gz)" "OK"
|
||||
}
|
||||
|
||||
test:batpipe_term_width() {
|
||||
description "Test support for BATPIPE_TERM_WIDTH"
|
||||
snapshot STDOUT
|
||||
|
||||
export BATPIPE=color
|
||||
export BATPIPE_DEBUG_PARENT_EXECUTABLE=less
|
||||
|
||||
BATPIPE_TERM_WIDTH=40 batpipe file.txt
|
||||
BATPIPE_TERM_WIDTH=-20 batpipe file.txt
|
||||
}
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
#!/bin/bash
|
||||
|
||||
setup() {
|
||||
use_shim 'batwatch'
|
||||
}
|
||||
|
|
@ -7,6 +9,23 @@ test:version() {
|
|||
snapshot stdout
|
||||
snapshot stderr
|
||||
|
||||
batwatch --version | head -n1 | cut -d' ' -f1
|
||||
batwatch --version | awk 'FNR <= 1 { print $1 }'
|
||||
batwatch --version | awk 'p{print} /^$/ { p=1 }'
|
||||
}
|
||||
|
||||
test:help() {
|
||||
description "Test 'batwatch --help'"
|
||||
snapshot stdout
|
||||
batwatch --help
|
||||
|
||||
assert batwatch --help
|
||||
batwatch --help | grep -q 'Usage'
|
||||
}
|
||||
|
||||
test:displayed() {
|
||||
description "Test 'batwatch <file>': <file> should be displayed'"
|
||||
snapshot stdout
|
||||
|
||||
batwatch --no-clear --watcher poll file.sh <<< "q"
|
||||
batwatch --watcher poll file.sh <<< "q" | grep -q "Hello"
|
||||
}
|
||||
|
|
|
|||
98
test/suite/lib_dsl.sh
Normal file
98
test/suite/lib_dsl.sh
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
setup() {
|
||||
source "${LIB}/dsl.sh"
|
||||
}
|
||||
|
||||
# Expect functions.
|
||||
expect_dsl_command() {
|
||||
EXPECTED_DSL_ARGS=("$@")
|
||||
CALLED="not called"
|
||||
|
||||
dsl_on_command() {
|
||||
expect_equal "$# args" "${#EXPECTED_DSL_ARGS[@]} args"
|
||||
CALLED="called"
|
||||
local arg
|
||||
local i=0
|
||||
for arg in "$@"; do
|
||||
expect_equal "$arg" "${EXPECTED_DSL_ARGS[$i]}"
|
||||
((i++)) || true
|
||||
done
|
||||
}
|
||||
|
||||
dsl_parse
|
||||
expect_equal "$CALLED" "called"
|
||||
}
|
||||
|
||||
expect_dsl_option() {
|
||||
EXPECTED_DSL_ARGS=("$@")
|
||||
CALLED="not called"
|
||||
|
||||
dsl_on_option() {
|
||||
expect_equal "$# args" "${#EXPECTED_DSL_ARGS[@]} args"
|
||||
CALLED="called"
|
||||
local arg
|
||||
local i=0
|
||||
for arg in "$@"; do
|
||||
expect_equal "$arg" "${EXPECTED_DSL_ARGS[$i]}"
|
||||
((i++)) || true
|
||||
done
|
||||
}
|
||||
|
||||
dsl_parse
|
||||
expect_equal "$CALLED" "called"
|
||||
}
|
||||
|
||||
# Stub methods.
|
||||
dsl_on_command() {
|
||||
:
|
||||
}
|
||||
|
||||
dsl_on_command_commit() {
|
||||
:
|
||||
}
|
||||
|
||||
dsl_on_option() {
|
||||
:
|
||||
}
|
||||
|
||||
# Test cases.
|
||||
test:parse_command() {
|
||||
description "Parses a DSL command."
|
||||
|
||||
expect_dsl_command "my-command" <<-EOF
|
||||
my-command
|
||||
EOF
|
||||
}
|
||||
|
||||
test:parse_simple_args() {
|
||||
description "Parses a DSL command with simple args"
|
||||
|
||||
expect_dsl_command "my-command" "arg1" "arg2" "arg3" <<-EOF
|
||||
my-command arg1 arg2 arg3
|
||||
EOF
|
||||
}
|
||||
|
||||
test:parse_quoted_args() {
|
||||
description "Parses a DSL command with quoted args"
|
||||
|
||||
expect_dsl_command "my-command" "arg 1" "" "arg3" <<-EOF
|
||||
my-command "arg 1" "" "arg3
|
||||
EOF
|
||||
}
|
||||
|
||||
test:parse_escaped_args() {
|
||||
description "Parses a DSL command with escaped args"
|
||||
|
||||
# Note: Bash will escape the \\ into \. It's only doubled in this heredoc.
|
||||
expect_dsl_command "my-command" "arg\"1" "arg 2" "arg\\3" <<-EOF
|
||||
my-command arg\"1 arg\ 2 arg\\\\3
|
||||
EOF
|
||||
}
|
||||
|
||||
test:parse_option() {
|
||||
description "Parses a DSL option with simple arguments"
|
||||
|
||||
expect_dsl_option "my-option" "1" "2" "3" <<-EOF
|
||||
my-command
|
||||
my-option 1 2 3
|
||||
EOF
|
||||
}
|
||||
|
|
@ -1,16 +1,22 @@
|
|||
setup() {
|
||||
set - pos1 \
|
||||
--val1 for_val1 \
|
||||
--val2=for_val2 \
|
||||
pos2 \
|
||||
--flag1 \
|
||||
-v3=for_val3 \
|
||||
-v4 for_val4 \
|
||||
--flag2
|
||||
set - --long-implicit implicit_value \
|
||||
--long-explicit=explicit_value \
|
||||
-i implicit \
|
||||
-x=explicit \
|
||||
-I1 group_implicit \
|
||||
-X2=group_explicit \
|
||||
positional_1 \
|
||||
positional_2 \
|
||||
--after-positional
|
||||
|
||||
source "${LIB}/print.sh"
|
||||
source "${LIB}/opt.sh"
|
||||
}
|
||||
|
||||
assert_opt_name() {
|
||||
assert [ "$OPT" = "$1" ]
|
||||
}
|
||||
|
||||
assert_opt_value() {
|
||||
assert [ "$OPT_VAL" = "$1" ]
|
||||
}
|
||||
|
|
@ -19,11 +25,12 @@ assert_opt_valueless() {
|
|||
assert [ -z "$OPT_VAL" ]
|
||||
}
|
||||
|
||||
|
||||
test:long() {
|
||||
description "Parse long options."
|
||||
|
||||
while shiftopt; do
|
||||
if [[ "$OPT" = "--flag1" ]]; then
|
||||
if [[ "$OPT" = "--long-implicit" ]]; then
|
||||
assert_opt_valueless
|
||||
return
|
||||
fi
|
||||
|
|
@ -32,13 +39,13 @@ test:long() {
|
|||
fail 'Failed to find option.'
|
||||
}
|
||||
|
||||
test:long_value_implicit() {
|
||||
test:long_implicit() {
|
||||
description "Parse long options in '--long value' syntax."
|
||||
|
||||
while shiftopt; do
|
||||
if [[ "$OPT" = "--val1" ]]; then
|
||||
if [[ "$OPT" = "--long-implicit" ]]; then
|
||||
shiftval
|
||||
assert_opt_value 'for_val1'
|
||||
assert_opt_value 'implicit_value'
|
||||
return
|
||||
fi
|
||||
done
|
||||
|
|
@ -46,13 +53,14 @@ test:long_value_implicit() {
|
|||
fail 'Failed to find option.'
|
||||
}
|
||||
|
||||
test:long_value_explicit() {
|
||||
test:long_explicit() {
|
||||
description "Parse long options in '--long=value' syntax."
|
||||
|
||||
while shiftopt; do
|
||||
if [[ "$OPT" = "--val2" ]]; then
|
||||
if [[ "$OPT" = "--long-explicit" ]]; then
|
||||
assert_opt_value 'explicit_value'
|
||||
shiftval
|
||||
assert_opt_value 'for_val2'
|
||||
assert_opt_value 'explicit_value'
|
||||
return
|
||||
fi
|
||||
done
|
||||
|
|
@ -60,13 +68,40 @@ test:long_value_explicit() {
|
|||
fail 'Failed to find option.'
|
||||
}
|
||||
|
||||
test:short_value_implicit() {
|
||||
test:short_default() {
|
||||
description "Parse short options in '-k' syntax."
|
||||
|
||||
while shiftopt; do
|
||||
if [[ "$OPT" = "-i" ]]; then
|
||||
assert_opt_valueless
|
||||
return
|
||||
fi
|
||||
done
|
||||
|
||||
fail 'Failed to find option.'
|
||||
}
|
||||
|
||||
test:short() {
|
||||
description "Parse short options in '-k val' syntax."
|
||||
|
||||
while shiftopt; do
|
||||
if [[ "$OPT" = "-i" ]]; then
|
||||
shiftopt
|
||||
assert_opt_valueless
|
||||
return
|
||||
fi
|
||||
done
|
||||
|
||||
fail 'Failed to find option.'
|
||||
}
|
||||
|
||||
test:short_implicit() {
|
||||
description "Parse short options in '-k value' syntax."
|
||||
|
||||
while shiftopt; do
|
||||
if [[ "$OPT" = "-v4" ]]; then
|
||||
if [[ "$OPT" = "-i" ]]; then
|
||||
shiftval
|
||||
assert_opt_value 'for_val4'
|
||||
assert_opt_value 'implicit'
|
||||
return
|
||||
fi
|
||||
done
|
||||
|
|
@ -74,15 +109,341 @@ test:short_value_implicit() {
|
|||
fail 'Failed to find option.'
|
||||
}
|
||||
|
||||
test:short_value_explicit() {
|
||||
test:short_explicit() {
|
||||
description "Parse short options in '-k=value' syntax."
|
||||
|
||||
while shiftopt; do
|
||||
if [[ "$OPT" =~ ^-v3 ]]; then
|
||||
assert_equal "$OPT" "-v3=for_val3"
|
||||
if [[ "$OPT" = "-x" ]]; then
|
||||
assert_opt_value 'explicit'
|
||||
shiftval
|
||||
assert_opt_value 'explicit'
|
||||
return
|
||||
fi
|
||||
done
|
||||
|
||||
fail 'Failed to find option.'
|
||||
}
|
||||
|
||||
test:short_default_mode() {
|
||||
description "Ensure the default mode for '-abc' is VALUE."
|
||||
assert_equal "$SHIFTOPT_SHORT_OPTIONS" "VALUE"
|
||||
}
|
||||
|
||||
test:short_split_none() {
|
||||
description "Parse short options in '-abc' syntax with SPLIT mode."
|
||||
SHIFTOPT_SHORT_OPTIONS="SPLIT"
|
||||
|
||||
local found=0
|
||||
while shiftopt; do
|
||||
case "$OPT" in
|
||||
"-I"|"-1")
|
||||
assert_opt_valueless
|
||||
((found++)) || true
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
assert_equal "$found" 2
|
||||
}
|
||||
|
||||
test:short_split_implicit() {
|
||||
description "Parse short options in '-abc val' syntax with SPLIT mode."
|
||||
SHIFTOPT_SHORT_OPTIONS="SPLIT"
|
||||
|
||||
local found=0
|
||||
while shiftopt; do
|
||||
case "$OPT" in
|
||||
"-I"|"-1")
|
||||
assert_opt_valueless
|
||||
shiftval
|
||||
assert_opt_value "group_implicit"
|
||||
((found++)) || true
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
assert_equal "$found" 2
|
||||
}
|
||||
|
||||
test:short_split_explicit() {
|
||||
description "Parse short options in '-abc=val' syntax with SPLIT mode."
|
||||
SHIFTOPT_SHORT_OPTIONS="SPLIT"
|
||||
|
||||
local found=0
|
||||
while shiftopt; do
|
||||
case "$OPT" in
|
||||
"-X"|"-2")
|
||||
assert_opt_value "group_explicit"
|
||||
((found++)) || true
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
assert_equal "$found" 2
|
||||
}
|
||||
|
||||
test:short_pass_none() {
|
||||
description "Parse short options in '-abc' syntax with PASS mode."
|
||||
SHIFTOPT_SHORT_OPTIONS="PASS"
|
||||
|
||||
local found=0
|
||||
while shiftopt; do
|
||||
case "$OPT" in
|
||||
"-I"|"-1") fail "Short group -I1 was split." ;;
|
||||
"-I1")
|
||||
assert_opt_valueless
|
||||
((found++)) || true
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
assert_equal "$found" 1
|
||||
}
|
||||
|
||||
test:short_pass_implicit() {
|
||||
description "Parse short options in '-abc val' syntax with PASS mode."
|
||||
SHIFTOPT_SHORT_OPTIONS="PASS"
|
||||
|
||||
local found=0
|
||||
while shiftopt; do
|
||||
case "$OPT" in
|
||||
"-I"|"-1") fail "Short group -I1 was split." ;;
|
||||
"-I1")
|
||||
assert_opt_valueless
|
||||
shiftval
|
||||
assert_opt_value "group_implicit"
|
||||
((found++)) || true
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
assert_equal "$found" 1
|
||||
}
|
||||
|
||||
test:short_pass_explicit() {
|
||||
description "Parse short options in '-abc=val' syntax with PASS mode."
|
||||
SHIFTOPT_SHORT_OPTIONS="PASS"
|
||||
|
||||
local found=0
|
||||
while shiftopt; do
|
||||
case "$OPT" in
|
||||
"-X"|"-2") fail "Short group -X2 was split." ;;
|
||||
"-X2")
|
||||
assert_opt_value "group_explicit"
|
||||
((found++)) || true
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
assert_equal "$found" 1
|
||||
}
|
||||
|
||||
test:short_conv_none() {
|
||||
description "Parse short options in '-abc' syntax with CONV mode."
|
||||
SHIFTOPT_SHORT_OPTIONS="CONV"
|
||||
|
||||
local found=0
|
||||
while shiftopt; do
|
||||
case "$OPT" in
|
||||
"-I"|"-1") fail "Short group -I1 was split." ;;
|
||||
"-I1") fail "Short group -I1 was not converted." ;;
|
||||
"--I1")
|
||||
assert_opt_valueless
|
||||
((found++)) || true
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
assert_equal "$found" 1
|
||||
}
|
||||
|
||||
test:short_conv_implicit() {
|
||||
description "Parse short options in '-abc val' syntax with CONV mode."
|
||||
SHIFTOPT_SHORT_OPTIONS="CONV"
|
||||
|
||||
local found=0
|
||||
while shiftopt; do
|
||||
case "$OPT" in
|
||||
"-I"|"-1") fail "Short group -I1 was split." ;;
|
||||
"-I1") fail "Short group -I1 was not converted." ;;
|
||||
"--I1")
|
||||
assert_opt_valueless
|
||||
shiftval
|
||||
assert_opt_value "group_implicit"
|
||||
((found++)) || true
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
assert_equal "$found" 1
|
||||
}
|
||||
|
||||
test:short_conv_explicit() {
|
||||
description "Parse short options in '-abc=val' syntax with CONV mode."
|
||||
SHIFTOPT_SHORT_OPTIONS="CONV"
|
||||
|
||||
local found=0
|
||||
while shiftopt; do
|
||||
case "$OPT" in
|
||||
"-X"|"-2") fail "Short group -X2 was split." ;;
|
||||
"-X2") fail "Short group -X2 was not converted." ;;
|
||||
"--X2")
|
||||
assert_opt_value "group_explicit"
|
||||
((found++)) || true
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
assert_equal "$found" 1
|
||||
}
|
||||
|
||||
test:short_value_none() {
|
||||
description "Parse short options in '-abc' syntax with VALUE mode."
|
||||
SHIFTOPT_SHORT_OPTIONS="VALUE"
|
||||
|
||||
local found=0
|
||||
while shiftopt; do
|
||||
case "$OPT" in
|
||||
"-I1") fail "Short group -I1 was not truncated." ;;
|
||||
"-I")
|
||||
assert_opt_value "1"
|
||||
((found++)) || true
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
assert_equal "$found" 1
|
||||
}
|
||||
|
||||
test:short_value_implicit() {
|
||||
description "Parse short options in '-abc val' syntax with VALUE mode."
|
||||
SHIFTOPT_SHORT_OPTIONS="VALUE"
|
||||
|
||||
local found=0
|
||||
while shiftopt; do
|
||||
case "$OPT" in
|
||||
"-I1") fail "Short group -I1 was not truncated." ;;
|
||||
"-I")
|
||||
shiftval
|
||||
assert_opt_value "1"
|
||||
((found++)) || true
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
assert_equal "$found" 1
|
||||
}
|
||||
|
||||
test:short_value_explicit() {
|
||||
description "Parse short options in '-abc=val' syntax with VALUE mode."
|
||||
SHIFTOPT_SHORT_OPTIONS="VALUE"
|
||||
|
||||
local found=0
|
||||
while shiftopt; do
|
||||
case "$OPT" in
|
||||
"-X2") fail "Short group -X2 was not truncated." ;;
|
||||
"-X")
|
||||
assert_opt_value "2=group_explicit"
|
||||
((found++)) || true
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
assert_equal "$found" 1
|
||||
}
|
||||
|
||||
test:hook() {
|
||||
description "Option hooks."
|
||||
|
||||
SHIFTOPT_HOOKS=("example_hook")
|
||||
|
||||
found=false
|
||||
example_hook() {
|
||||
if [[ "$OPT" = "--long-implicit" ]]; then
|
||||
found=true
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
while shiftopt; do
|
||||
if [[ "$OPT" = "--long-implicit" ]]; then
|
||||
fail "Option was not filtered by hook."
|
||||
fi
|
||||
done
|
||||
|
||||
if ! "$found"; then
|
||||
fail "Option was not found by hook."
|
||||
fi
|
||||
}
|
||||
|
||||
test:fn_setargs() {
|
||||
description "Function setargs."
|
||||
|
||||
setargs "--setarg=true"
|
||||
shiftopt || true
|
||||
shiftval
|
||||
|
||||
assert_opt_name "--setarg"
|
||||
assert_opt_value "true"
|
||||
}
|
||||
|
||||
test:fn_resetargs() {
|
||||
description "Function resetargs."
|
||||
|
||||
setargs "--setarg=true"
|
||||
resetargs
|
||||
shiftopt || true
|
||||
|
||||
assert_opt_name "--long-implicit"
|
||||
}
|
||||
|
||||
# shellcheck disable=SC2154
|
||||
test:fn_getargs() {
|
||||
description "Function getargs."
|
||||
|
||||
setargs "--one=two" "three" "--four"
|
||||
shiftopt
|
||||
|
||||
getargs args
|
||||
|
||||
assert_equal 2 "${#args[@]}"
|
||||
assert_equal "three" "${args[0]}"
|
||||
assert_equal "--four" "${args[1]}"
|
||||
|
||||
# Ensure getargs doesn't remove remaining arguments.
|
||||
shiftopt
|
||||
assert_opt_name "three"
|
||||
|
||||
# Ensure it doesn't set an empty string.
|
||||
args=(one two)
|
||||
setargs
|
||||
getargs args
|
||||
assert_equal 0 "${#args[@]}"
|
||||
}
|
||||
|
||||
test:fn_getargs_append() {
|
||||
description "Function getargs -a."
|
||||
|
||||
setargs "--two=three" "four"
|
||||
|
||||
args=(zero one)
|
||||
getargs -a args
|
||||
|
||||
assert_equal 4 "${#args[@]}"
|
||||
assert_equal "zero" "${args[0]}"
|
||||
assert_equal "one" "${args[1]}"
|
||||
assert_equal "--two=three" "${args[2]}"
|
||||
assert_equal "four" "${args[3]}"
|
||||
|
||||
# Ensure it doesn't append empty strings.
|
||||
args=()
|
||||
setargs "zero" "one"
|
||||
getargs -a args
|
||||
assert_equal 2 "${#args[@]}"
|
||||
|
||||
args=(zero one)
|
||||
setargs
|
||||
getargs -a args
|
||||
assert_equal 2 "${#args[@]}"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,69 +6,119 @@ use_pager() {
|
|||
unset BAT_PAGER
|
||||
export PAGER="$1"
|
||||
|
||||
SCRIPT_PAGER_CMD=("$PAGER")
|
||||
SCRIPT_PAGER_ARGS=()
|
||||
|
||||
_detect_pager --force
|
||||
_configure_pager
|
||||
_detect_pager
|
||||
}
|
||||
|
||||
use_no_pager() {
|
||||
unset BAT_PAGER
|
||||
unset PAGER
|
||||
|
||||
_configure_pager
|
||||
_detect_pager
|
||||
}
|
||||
|
||||
use_bat_pager() {
|
||||
unset PAGER
|
||||
export BAT_PAGER="$1"
|
||||
|
||||
SCRIPT_PAGER_CMD=($BAT_PAGER)
|
||||
SCRIPT_PAGER_ARGS=()
|
||||
|
||||
_detect_pager --force
|
||||
_configure_pager
|
||||
_detect_pager
|
||||
}
|
||||
|
||||
test:less_detection() {
|
||||
description "Identify less"
|
||||
|
||||
use_pager "less" && expect_equal "$(pager_name)" "less"
|
||||
use_pager "less_but_renamed" && expect_equal "$(pager_name)" "less"
|
||||
use_pager "tput" && expect_equal "$(pager_name)" "tput"
|
||||
(use_pager "less" && expect_equal "$(pager_name)" "less")
|
||||
(use_pager "less_but_renamed" && expect_equal "$(pager_name)" "less")
|
||||
(use_pager "stty" && expect_equal "$(pager_name)" "stty")
|
||||
}
|
||||
|
||||
test:bat_detection() {
|
||||
description "Ensure bat is replaced with less as pager"
|
||||
|
||||
use_pager "bat"
|
||||
expect_equal "$(pager_name)" "less"
|
||||
expect array_contains "-R" in "${SCRIPT_PAGER_CMD[@]}"
|
||||
}
|
||||
|
||||
test:less_version() {
|
||||
description "Identify less version"
|
||||
|
||||
export MOCK_LESS_VERSION=473
|
||||
use_pager "less" && expect_equal "$(pager_version)" "473"
|
||||
(
|
||||
export MOCK_LESS_VERSION=473
|
||||
use_pager "less" && expect_equal "$(pager_version)" "473"
|
||||
)
|
||||
|
||||
export MOCK_LESS_VERSION=551
|
||||
use_pager "less" && expect_equal "$(pager_version)" "551"
|
||||
(
|
||||
export MOCK_LESS_VERSION=551
|
||||
use_pager "less" && expect_equal "$(pager_version)" "551"
|
||||
)
|
||||
}
|
||||
|
||||
test:less_args() {
|
||||
description "Automatically select appropriate less args"
|
||||
|
||||
export MOCK_LESS_VERSION=473
|
||||
use_pager "less"
|
||||
expect array_contains "-R" in "${SCRIPT_PAGER_ARGS[@]}"
|
||||
expect array_contains "--quit-if-one-screen" in "${SCRIPT_PAGER_ARGS[@]}"
|
||||
expect array_contains "--no-init" in "${SCRIPT_PAGER_ARGS[@]}"
|
||||
# When pager is "less".
|
||||
(
|
||||
export MOCK_LESS_VERSION=473
|
||||
use_pager "less"
|
||||
expect array_contains "-R" in "${SCRIPT_PAGER_CMD[@]}"
|
||||
expect array_contains "--quit-if-one-screen" in "${SCRIPT_PAGER_CMD[@]}"
|
||||
expect array_contains "--no-init" in "${SCRIPT_PAGER_CMD[@]}"
|
||||
)
|
||||
|
||||
export MOCK_LESS_VERSION=551
|
||||
use_pager "less"
|
||||
expect array_contains "-R" in "${SCRIPT_PAGER_ARGS[@]}"
|
||||
expect array_contains "--quit-if-one-screen" in "${SCRIPT_PAGER_ARGS[@]}"
|
||||
expect ! array_contains "--no-init" in "${SCRIPT_PAGER_ARGS[@]}"
|
||||
# When pager is equivalent of "less".
|
||||
(
|
||||
export MOCK_LESS_VERSION=551
|
||||
use_pager "less"
|
||||
expect array_contains "-R" in "${SCRIPT_PAGER_CMD[@]}"
|
||||
expect array_contains "--quit-if-one-screen" in "${SCRIPT_PAGER_CMD[@]}"
|
||||
expect ! array_contains "--no-init" in "${SCRIPT_PAGER_CMD[@]}"
|
||||
)
|
||||
}
|
||||
|
||||
test:less_args_not_less() {
|
||||
description "Don't give non-less pagers the less args"
|
||||
|
||||
use_pager "not_less"
|
||||
expect_equal "${#SCRIPT_PAGER_ARGS[@]}" 0
|
||||
echo "${SCRIPT_PAGER_CMD[@]}"
|
||||
expect_equal "${#SCRIPT_PAGER_CMD[@]}" 1
|
||||
}
|
||||
|
||||
test:env_bat_pager() {
|
||||
description "Check that BAT_PAGER is being used"
|
||||
|
||||
use_bat_pager "not_less"
|
||||
expect_equal "$SCRIPT_PAGER_CMD" "not_less"
|
||||
expect_equal "${SCRIPT_PAGER_CMD[0]}" "not_less"
|
||||
|
||||
use_bat_pager "not_less but not_more"
|
||||
expect_equal "$SCRIPT_PAGER_CMD" "not_less"
|
||||
expect_equal "${SCRIPT_PAGER_CMD[0]}" "not_less"
|
||||
expect_equal "${SCRIPT_PAGER_CMD[1]}" "but"
|
||||
expect_equal "${SCRIPT_PAGER_CMD[2]}" "not_more"
|
||||
}
|
||||
|
||||
test:env_no_pager() {
|
||||
description "Check that no PAGER or BAT_PAGER defaults to less"
|
||||
|
||||
use_no_pager
|
||||
expect_equal "${SCRIPT_PAGER_CMD[0]}" "less"
|
||||
expect array_contains "-R" in "${SCRIPT_PAGER_CMD[@]}"
|
||||
}
|
||||
|
||||
test:args_copied_from_pager() {
|
||||
description "Check that the pager args are correct with PAGER."
|
||||
|
||||
use_pager "less --some-argument"
|
||||
expect_equal "${SCRIPT_PAGER_CMD[0]}" "less"
|
||||
expect_not_equal "${SCRIPT_PAGER_CMD[1]}" "--some-argument"
|
||||
}
|
||||
|
||||
test:args_copied_from_bat_pager() {
|
||||
description "Check that the pager args are correct with PAGER."
|
||||
|
||||
use_bat_pager "less --some-argument"
|
||||
assert_equal "${#SCRIPT_PAGER_CMD[@]}" 2
|
||||
expect_equal "${SCRIPT_PAGER_CMD[0]}" "less"
|
||||
expect_equal "${SCRIPT_PAGER_CMD[1]}" "--some-argument"
|
||||
}
|
||||
|
|
|
|||
74
test/suite/perf.sh
Normal file
74
test/suite/perf.sh
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
# This test suite is meant to check the performance impact of loading the library scripts used in bat-extras.
|
||||
# Whether or not it completes successfully doesn't matter.
|
||||
|
||||
# Test cases.
|
||||
test:perf_baseline() {
|
||||
description "The baseline for test execution time"
|
||||
exit 0
|
||||
}
|
||||
|
||||
test:perf_lib_constants() {
|
||||
description "Record how long it takes to load the constants.sh library"
|
||||
source "${LIB}/constants.sh"
|
||||
exit 0
|
||||
}
|
||||
|
||||
test:perf_lib_dsl() {
|
||||
description "Record how long it takes to load the dsl.sh library"
|
||||
source "${LIB}/dsl.sh"
|
||||
exit 0
|
||||
}
|
||||
|
||||
test:perf_lib_opt() {
|
||||
description "Record how long it takes to load the opt.sh library"
|
||||
source "${LIB}/opt.sh"
|
||||
exit 0
|
||||
}
|
||||
|
||||
test:perf_lib_opt_hook_color() {
|
||||
description "Record how long it takes to load the opt_hook_color.sh library"
|
||||
source "${LIB}/opt_hook_color.sh"
|
||||
exit 0
|
||||
}
|
||||
|
||||
test:perf_lib_opt_hook_pager() {
|
||||
description "Record how long it takes to load the opt_hook_pager.sh library"
|
||||
source "${LIB}/opt_hook_pager.sh"
|
||||
exit 0
|
||||
}
|
||||
|
||||
test:perf_lib_opt_hook_version() {
|
||||
description "Record how long it takes to load the opt_hook_version.sh library"
|
||||
source "${LIB}/opt_hook_version.sh"
|
||||
exit 0
|
||||
}
|
||||
|
||||
test:perf_lib_opt_hook_width() {
|
||||
description "Record how long it takes to load the opt_hook_width.sh library"
|
||||
source "${LIB}/opt_hook_width.sh"
|
||||
exit 0
|
||||
}
|
||||
|
||||
test:perf_lib_pager() {
|
||||
description "Record how long it takes to load the pager.sh library"
|
||||
source "${LIB}/pager.sh"
|
||||
exit 0
|
||||
}
|
||||
|
||||
test:perf_lib_print() {
|
||||
description "Record how long it takes to load the print.sh library"
|
||||
source "${LIB}/print.sh"
|
||||
exit 0
|
||||
}
|
||||
|
||||
test:perf_lib_str() {
|
||||
description "Record how long it takes to load the str.sh library"
|
||||
source "${LIB}/str.sh"
|
||||
exit 0
|
||||
}
|
||||
|
||||
test:perf_lib_version() {
|
||||
description "Record how long it takes to load the version.sh library"
|
||||
source "${LIB}/version.sh"
|
||||
exit 0
|
||||
}
|
||||
|
|
@ -7,6 +7,19 @@ test:version() {
|
|||
snapshot stdout
|
||||
snapshot stderr
|
||||
|
||||
prettybat --version | head -n1 | cut -d' ' -f1
|
||||
prettybat --version | awk 'FNR <= 1 { print $1 }'
|
||||
prettybat --version | awk 'p{print} /^$/ { p=1 }'
|
||||
}
|
||||
|
||||
test:read_from_pipe() {
|
||||
description "Test 'prettybat -'"
|
||||
|
||||
assert_equal "ABC" "$(echo "ABC" | prettybat)"
|
||||
assert_equal "ABC" "$(echo "ABC" | prettybat -)"
|
||||
}
|
||||
|
||||
test:read_from_pipe_with_formatter() {
|
||||
description "Test 'prettybat - -lsh'"
|
||||
|
||||
assert_equal "-: shfmt" "$(echo "" | prettybat - -lsh --debug:formatter)"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
2020.04.08
|
||||
2024.08.24
|
||||
|
|
|
|||
Loading…
Reference in a new issue