Compare commits

..

No commits in common. "master" and "v2021.04.06" have entirely different histories.

46 changed files with 367 additions and 1862 deletions

107
.circleci/config.yml Normal file
View file

@ -0,0 +1,107 @@
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 openssh bash python3 diffutils ca-certificates curl shfmt
- run:
name: "Setup: Install test packages."
command: apk add util-linux coreutils fish
- 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"
manuals:
type: string
default: "false"
steps:
- run:
name: "Build"
command: ./build.sh --minify=<<parameters.minify>> --manuals=<<parameters.manuals>> --no-verify
jobs:
build:
executor: linux_alpine
steps:
- setup
- checkout
- build:
minify: "all"
manuals: "true"
- build:
minify: "all"
manuals: "true"
- store_artifacts:
path: bin
- store_artifacts:
path: man
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]

View file

@ -1,54 +0,0 @@
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[@]}"

View file

@ -1,31 +0,0 @@
#!/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)"

View file

@ -1,31 +0,0 @@
#!/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"

View file

@ -1,92 +0,0 @@
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"

View file

@ -1,33 +0,0 @@
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

View file

@ -1,45 +0,0 @@
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}}"

View file

@ -1,96 +0,0 @@
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'

1
.gitignore vendored
View file

@ -4,7 +4,6 @@
# Developer
.idea
.vscode
*.iml
# Project

@ -1 +1 @@
Subproject commit 6b97e0a531f77d2e1f10f48ebb68d4033d69e04d
Subproject commit b8651c00a648f23147e4f4cfb14a1562acb13b54

View file

@ -48,60 +48,14 @@ Pretty-print source code and highlight it with `bat`.
### Homebrew
All of the `bat-extras` scripts can be installed with `brew install bat-extras`.
All of the `bat-extras` scripts can be installed with `brew install eth-p/software/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]`
If you would only like to install one of the scripts, you can use `brew install eth-p/software/bat-extras-[SCRIPT]` to install it.
### 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
```
&nbsp;
## Installation
[![Test](https://github.com/eth-p/bat-extras/actions/workflows/test.yaml/badge.svg)](https://github.com/eth-p/bat-extras/actions/workflows/test.yaml)
## Installation (![CircleCI](https://circleci.com/gh/eth-p/bat-extras.svg?style=svg))
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.
@ -143,10 +97,11 @@ If you only want to install a single script, you can run the build process and c
**Manuals:**
**Manuals:** (EXPERIMENTAL)
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.
You can specify `--manuals` to have the build script generate a `man` page for each of the markdown documentation files.
This is an experimental feature that uses a non-compliant Markdown "parser" written in Bash, and there is no guarantee
as for the quality of the generated manual pages.
@ -155,7 +110,6 @@ This is a beta feature that uses a non-compliant Markdown "parser" written in Ba
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:**

View file

@ -1,5 +1,5 @@
# -----------------------------------------------------------------------------
# bat-extras | Copyright (C) 2020-2024 eth-p and contributors | MIT License
# bat-extras | Copyright (C) 2020 eth-p and contributors | MIT License
#
# Repository: https://github.com/eth-p/bat-extras
# Issues: https://github.com/eth-p/bat-extras/issues

256
build.sh
View file

@ -1,119 +1,19 @@
#!/usr/bin/env bash
# -----------------------------------------------------------------------------
# bat-extras | Copyright (C) 2019-2023 eth-p | MIT License
# 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
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# 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)"
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
BIN="$HERE/bin"
SRC="$HERE/src"
MAN="$HERE/man"
MAN_SRC="$HERE/doc"
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
@ -220,18 +120,12 @@ generate_banner() {
#
# 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${what}"
smsg "Reading"
}
# Build step: preprocess
@ -324,7 +218,7 @@ step_write() {
smsg "Building"
}
# Build step: write_install
# Build step: write
# Optionally writes the output script to a file.
#
# Arguments:
@ -347,47 +241,6 @@ 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:
# -----------------------------------------------------------------------------
@ -516,25 +369,12 @@ OPT_MANUALS=true
OPT_INLINE=true
OPT_MINIFY="lib"
OPT_PREFIX="/usr/local"
EXECUTABLE_BAT="$(basename -- "$EXECUTABLE_BAT")"
ALT_EXECS=()
OPT_BAT="$(basename "$EXECUTABLE_BAT")"
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
@ -542,47 +382,33 @@ while shiftopt; do
--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; 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" ;;
--alternate-executable) shiftval; OPT_BAT="$OPT_VAL" ;;
--minify) shiftval; OPT_MINIFY="$OPT_VAL" ;;
# Print scripts.
--show:source-paths) get_source_paths; exit 0 ;;
# Unknown options.
*)
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 [[ "${#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"
if [[ "$OPT_BAT" != "bat" ]]; then
printc_msg "%{YELLOW}Building executable scripts with an alternate bat executable %{CLEAR}%s%{YELLOW}.%{CLEAR}\n" "$OPT_BAT"
if ! command -v "$OPT_BAT" &>/dev/null; then
printc_err "%{YELLOW}WARNING: Bash cannot execute the specified file.\n"
printc_err "%{YELLOW} The finished scripts may not run properly.%{CLEAR}\n"
fi
# shellcheck disable=SC2034
EXECUTABLE_BAT="$OPT_BAT"
printc_msg "\n"
fi
@ -615,12 +441,6 @@ fi
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
# -----------------------------------------------------------------------------
@ -629,33 +449,56 @@ fi
SOURCES=()
printc_msg "%{YELLOW}Preparing scripts...%{CLEAR}\n"
while read -r file; do
for file in "$SRC"/*.sh; 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
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)
done
if [[ "${#BUILD_FILTER[@]}" -gt 0 ]]; then
printf "\n"
printf "\n"
fi
# -----------------------------------------------------------------------------
# Build manuals.
if [[ "$OPT_MANUALS" = "true" ]]; then
source "${HERE}/mdroff.sh"
if ! [[ -d "$MAN" ]]; then
mkdir -p "$MAN"
fi
printc_msg "%{YELLOW}Building manuals...%{CLEAR}\n"
for source in "${SOURCES[@]}"; do
name="$(basename "$source" .sh)"
doc="${MAN_SRC}/${name}.md"
docout="${MAN}/${name}.1"
if ! [[ -f "$doc" ]]; then
continue
fi
printc_msg " %{YELLOW} %{MAGENTA}%s%{CLEAR}\n" "$(basename "$docout")"
(mdroff < "$doc" > "${MAN}/${name}.1")
done
printc_msg "\n"
fi
# -----------------------------------------------------------------------------
# Build files.
@ -678,15 +521,6 @@ 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
# -----------------------------------------------------------------------------

View file

@ -11,13 +11,8 @@ This script supports using [delta](https://github.com/dandavison/delta) as an al
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
@ -30,7 +25,6 @@ This script supports using [delta](https://github.com/dandavison/delta) as an al
| | `--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. |

View file

@ -31,8 +31,6 @@ Search through files or directories looking for matching regular expressions (or
| | `--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`. |
The following options are passed directly to ripgrep, and are not handled by this script.

View file

@ -4,26 +4,13 @@ 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!
## Usage
batman [SECTION] [ENTRY]
### As a Replacement for Man
With bash:
```bash
eval "$(batman --export-env)"
```
With fish:
```fish
batman --export-env | source
```
## Environment
@ -33,21 +20,6 @@ batman --export-env | source
## 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.
```bash
batman() {
BAT_THEME="Solarized (dark)" batman "$@"
return $?
}
```
## Installation
@ -55,18 +27,6 @@ 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).

View file

@ -17,19 +17,11 @@ Like [lesspipe](https://github.com/wofr06/lesspipe), `batpipe` is designed to wo
## 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` |
| Directories | `exa`, `ls` |
| `*.tar`, `*.tar.gz` | `tar` |
| `*.zip`, `*.jar` | `unzip` |
| `*.gz` | `gunzip` |
@ -59,7 +51,7 @@ The `viewer_${viewer}_supports` function is called to determine if the external
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.

View file

@ -34,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](https://eradman.com/entrproject/)
- [entr](http://entrproject.org/)
There is also a fallback `poll` watcher available.

View file

@ -21,23 +21,22 @@ 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 | [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) |
| 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/) |
| 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/) |

View file

@ -13,7 +13,6 @@ EXECUTABLE_BAT="$(command -v bat 2>/dev/null || command -v batcat 2>/dev/null ||
EXECUTABLE_GIT="git"
EXECUTABLE_DELTA="delta"
EXECUTABLE_RIPGREP="rg"
EXECUTABLE_FZF="fzf"
# Constants: Program
PROGRAM="$(basename "$0" .sh)"

View file

@ -12,12 +12,6 @@ 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)" ]]
@ -92,13 +86,9 @@ _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]}")"
@ -113,14 +103,10 @@ _detect_pager() {
# 3. Use PAGER
_configure_pager() {
# shellcheck disable=SC2206
SCRIPT_PAGER_CMD=($PAGER)
SCRIPT_PAGER_ARGS=()
if [[ -n "${PAGER+x}" ]]; then
SCRIPT_PAGER_CMD=($PAGER)
else
SCRIPT_PAGER_CMD=("less")
fi
# Prefer the BAT_PAGER environment variable.
# Prefer the bat pager.
if [[ -n "${BAT_PAGER+x}" ]]; then
# [note]: This is intentional.
# shellcheck disable=SC2206
@ -128,12 +114,6 @@ _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

View file

@ -39,11 +39,8 @@ parent_shell() {
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
# If the parent process has "*sh " followed by "-l", it's probably a login shell.
if [[ "$target_name" =~ sh\ .*-l ]]; then
target_name="$(cut -f1 -d' ' <<< "${target_name}")"
break
fi

View file

@ -8,11 +8,8 @@
# Gets the current bat version.
bat_version() {
if [[ -z "${__BAT_VERSION}" ]]; then
__BAT_VERSION="$(command "$EXECUTABLE_BAT" --version | cut -d ' ' -f 2)"
fi
echo "${__BAT_VERSION}"
command "$EXECUTABLE_BAT" --version | cut -d ' ' -f 2
return
}
# Compares two version strings.

View file

@ -115,16 +115,6 @@ mdroff:emit:table_row() {
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"
@ -141,11 +131,6 @@ mdroff:emit() {
"mdroff:emit:${type}" "$data" "${@:3}"
}
mdroff:trim_right() {
# shellcheck disable=SC2001
sed 's/[[:space:]]*$//' <<< "$1"
}
mdroff:trim() {
sed 's/^[[:space:]]*//; s/[[:space:]]*$//' <<< "$1"
}
@ -162,8 +147,7 @@ mdroff:parseln() {
while [[ "${#buffer}" -gt 0 ]]; do
[[ "$buffer" =~ \*{1,3}|\`|\[([^\]]+)\]\(([^\)]+)\) ]] || {
mdroff:emit text "$(mdroff:trim_right "$buffer")"
mdroff:emit text $'\n'
printf "%s\n" "$(mdroff:trim "$buffer")"
return
}
@ -173,7 +157,7 @@ mdroff:parseln() {
before="${buffer:0:$pos}"
buffer="${buffer:$(($pos + ${#found}))}"
mdroff:emit text "$before"
printf "%s" "$before"
case "$found" in
'***')
if "$MDROFF_ATTR_STRONG" && "$MDROFF_ATTR_EMPHASIS"; then

View file

@ -1,256 +1,10 @@
#!/usr/bin/env bash
# -----------------------------------------------------------------------------
# bat-extras | Copyright (C) 2019-2023 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 "$(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")"
@ -260,23 +14,22 @@ SRC="$HERE/src"
source "${LIB}/print.sh"
source "${LIB}/opt.sh"
# -----------------------------------------------------------------------------
set -euo pipefail
# -----------------------------------------------------------------------------
# Options.
OPT_ARTIFACT="bat-extras-${DATE}.zip"
OPT_SINCE=
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)"
OPT_BIN_DIR="$HERE/bin"
OPT_DOC_DIR="$HERE/doc"
OPT_MAN_DIR="$HERE/man"
while shiftopt; do
case "$OPT" in
--since)
shiftval
OPT_SINCE="$OPT_VAL"
if ! batextras:git rev-parse "$OPT_SINCE" &> /dev/null; then
if ! git rev-parse "$OPT_SINCE" &> /dev/null; then
printc "%{RED}%s: unknown commit or tag for '%s'\n" "$PROGRAM" "$OPT"
exit 1
fi
@ -295,10 +48,6 @@ done
# -----------------------------------------------------------------------------
# Verify the version matches today's date.
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"
@ -306,18 +55,6 @@ if [[ "$VERSION" != "$VERSION_EXPECTED" ]] && ! "$OPT_BAD_IDEA"; then
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.
@ -338,13 +75,110 @@ printc "%{YELLOW}Building scripts...%{CLEAR}\n"
# Build package.
printc "%{YELLOW}Packaging artifacts...%{CLEAR}\n"
batextras:create_package "$OPT_ARTIFACT"
(
rm "$OPT_ARTIFACT"
cd "$(dirname "$OPT_BIN_DIR")"
zip -r "$OPT_ARTIFACT" "$(basename "$OPT_BIN_DIR")"
cd "$(dirname "$OPT_DOC_DIR")"
zip -ru "$OPT_ARTIFACT" "$(basename "$OPT_DOC_DIR")"
if [[ -d "$OPT_MAN_DIR" ]]; then
cd "$(dirname "$OPT_MAN_DIR")"
zip -ru "$OPT_ARTIFACT" "$(basename "$OPT_MAN_DIR")"
fi
)
printc "%{YELLOW}Package created as %{BLUE}%s%{YELLOW}.%{CLEAR}\n" "$OPT_ARTIFACT"
# -----------------------------------------------------------------------------
# Print template description package.
printc "%{YELLOW}Release description:%{CLEAR}\n"
batextras:generate_release_notes \
"$(batextras:get_previous_tag_name)" \
"$(batextras:get_current_commit)"
# Get the commit hash.
COMMIT="$(git rev-parse HEAD)"
COMMIT_URL="https://github.com/eth-p/bat-extras/tree/${COMMIT}"
# 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 script names.
script_links=()
script_names=()
for script in "$SRC"/*.sh; do
script_name="$(basename "$script" .sh)"
script_names+=("$script_name")
script_links+=("[\`${script_name}\`](https://github.com/eth-p/bat-extras/blob/${COMMIT}/doc/${script_name}.md)")
done
script_pattern="$(printf 's/\\(%s\\)/`\\1`/;' "${script_names[@]}")"
SCRIPTS="$(printf "%s, " "${script_links[@]:0:$((${#script_links[@]} - 1))}")"
SCRIPTS="${SCRIPTS}and ${script_links[$((${#script_links[@]} - 1))]}"
# Get the changelog.
CHANGELOG_DEV=''
CHANGELOG=''
if [[ -n "$OPT_SINCE" ]]; then
ref="$(git rev-parse HEAD)"
end="$(git rev-parse "$OPT_SINCE")"
while [[ "$ref" != "$end" ]]; do
is_developer=false
ref_message="$(git show -s --format=%s "$ref")"
ref="$(git rev-parse "${ref}~1")"
if [[ "$ref_message" =~ ^([a-z-]+):[[:space:]]*(.*)$ ]]; then
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
# Switch to the correct changelog.
case "$affected_module" in
test | developer | ci | build) is_developer=true ;;
esac
fi
# Append to changelog.
if "$is_developer"; then
CHANGELOG_DEV="$CHANGELOG_DEV"$'\n'" - ${ref_message}"
else
CHANGELOG="$CHANGELOG"$'\n'" - ${ref_message}"
fi
done
fi
CHANGELOG="$(sed "$script_pattern" <<< "$CHANGELOG")"
CHANGELOG_DEV="$(sed "$script_pattern" <<< "$CHANGELOG_DEV")"
# Print the template.
sed '/\\$/{N;s/\\\n//;s/\n//p;}' <<- EOF
This contains the latest versions of $SCRIPTS as of commit [$(git rev-parse --short HEAD)]($COMMIT_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

View file

@ -34,13 +34,10 @@ 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.
@ -51,15 +48,6 @@ 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.
@ -73,7 +61,6 @@ while shiftopt; do
# Script options
--all) OPT_ALL_CHANGES=true ;;
--staged) OPT_STAGED=true; GIT_ARGS+=("--staged") ;;
--delta) BATDIFF_USE_DELTA=true ;;
# ???
@ -90,10 +77,7 @@ done
# Append arguments for delta/bat.
BAT_ARGS+=("--terminal-width=${OPT_TERMINAL_WIDTH}" "--paging=never")
DELTA_ARGS+=(
"--width=${OPT_TERMINAL_WIDTH}"
"--paging=never"
)
DELTA_ARGS+=("--width=${OPT_TERMINAL_WIDTH}" "--paging=never" "--hunk-style=plain")
if "$OPT_COLOR"; then
BAT_ARGS+=("--color=always")
@ -107,27 +91,9 @@ if [[ -n "$OPT_TABS" ]]; then
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=("$@")
@ -137,28 +103,11 @@ print_bat_diff() {
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[@]}"
"$EXECUTABLE_BAT" --diff --diff-context="$OPT_CONTEXT" "${files[0]}" "${BAT_ARGS[@]}"
else
"$EXECUTABLE_GIT" diff "${GIT_ARGS[@]}" "${files[0]}" | "$EXECUTABLE_BAT" --language=diff - "${BAT_ARGS[@]}"
"$EXECUTABLE_GIT" diff -U"$OPT_CONTEXT" "${files[0]}" | "$EXECUTABLE_BAT" --language=diff - "${BAT_ARGS[@]}"
fi
}
@ -172,8 +121,7 @@ print_delta_diff() {
fi
# Diff git file.
ensure_git_directory
"$EXECUTABLE_GIT" diff "${GIT_ARGS[@]}" "${files[0]}" | "$EXECUTABLE_DELTA" "${DELTA_ARGS[@]}"
"$EXECUTABLE_GIT" diff -U"$OPT_CONTEXT" "${files[0]}" | "$EXECUTABLE_DELTA" "${DELTA_ARGS[@]}"
}
if [[ "$BATDIFF_USE_DELTA" = "true" && "$SUPPORTS_DELTA" = "true" ]]; then
@ -210,13 +158,12 @@ fi
# -----------------------------------------------------------------------------
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)
done < <("${EXECUTABLE_GIT}" diff --name-only --diff-filter=d)
return
fi

View file

@ -5,8 +5,6 @@
# 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"
@ -14,7 +12,6 @@ source "${LIB}/print.sh"
source "${LIB}/pager.sh"
source "${LIB}/opt.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"
@ -23,128 +20,12 @@ 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=""
@ -157,8 +38,7 @@ OPT_SNIP=""
OPT_HIGHLIGHT=true
OPT_SEARCH_PATTERN=false
OPT_FIXED_STRINGS=false
OPT_NO_SEPARATOR=false
BAT_STYLE="${BAT_STYLE:-header,numbers}"
BAT_STYLE="header,numbers"
# Set options based on the bat version.
if version_compare "$(bat_version)" -gt "0.12"; then
@ -183,29 +63,11 @@ if [[ -n "$RIPGREP_CONFIG_PATH" && -e "$RIPGREP_CONFIG_PATH" ]]; then
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" ;;
@ -255,15 +117,6 @@ 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:*) {
@ -277,9 +130,6 @@ while shiftopt; do
fi
} ;;
# --
--) getargs -a FILES; break ;;
# ???
-*) {
printc "%{RED}%s: unknown option '%s'%{CLEAR}\n" "$PROGRAM" "$OPT" 1>&2
@ -287,15 +137,17 @@ while shiftopt; do
} ;;
# Search
*) FILES+=("$OPT") ;;
*) {
if [ -z "$PATTERN" ]; then
PATTERN="$OPT"
else
FILES+=("$OPT")
fi
} ;;
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
@ -361,12 +213,6 @@ main() {
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
@ -382,17 +228,17 @@ main() {
--vimgrep \
"${RG_ARGS[@]}" \
--context 0 \
--no-context-separator \
--sort path \
-- \
"$PATTERN" \
"${FILES[@]}" \
)
if "$READ_FROM_STDIN"; then
"$RIPGREP" "${COMMON_RG_ARGS[@]}" <<< "$STDIN_DATA"
"$EXECUTABLE_RIPGREP" "${COMMON_RG_ARGS[@]}" <<< "$STDIN_DATA"
return $?
else
"$RIPGREP" "${COMMON_RG_ARGS[@]}"
"$EXECUTABLE_RIPGREP" "${COMMON_RG_ARGS[@]}"
return $?
fi
}
@ -401,9 +247,7 @@ main() {
[[ -z "$LAST_FILE" ]] && return 0
# Print the separator.
if ! "$NO_SEPARATOR"; then
"$FIRST_PRINT" && echo "$SEP"
fi
"$FIRST_PRINT" && echo "$SEP"
FIRST_PRINT=false
# Print the file.
@ -416,9 +260,7 @@ main() {
"$LAST_FILE"
# Print the separator.
if ! "$NO_SEPARATOR"; then
echo "$SEP"
fi
echo "$SEP"
}
do_print_from_file_or_stdin() {

View file

@ -6,9 +6,8 @@
# Issues: https://github.com/eth-p/bat-extras/issues
# -----------------------------------------------------------------------------
# shellcheck disable=SC1090 disable=SC2155
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)"
LIB="$(cd "$(dirname "${BASH_SOURCE[0]}")" && cd "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo ".")")/../lib" && pwd)"
if [[ -n "${MANPAGER}" ]]; then BAT_PAGER="$MANPAGER"; fi
source "${LIB}/constants.sh"
source "${LIB}/pager.sh"
source "${LIB}/print.sh"
@ -19,17 +18,12 @@ source "${LIB}/opt_hook_version.sh"
hook_color
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}") ;;
--paging|--pager) shiftval; BAT_ARGS+=("${OPT}=${OPT_VAL}") ;;
*) MAN_ARGS+=("$OPT") ;;
esac
done
@ -40,76 +34,9 @@ else
BAT_ARGS+=("--color=never" "--decorations=never")
fi
if [[ -z "${BAT_STYLE+x}" ]]; then
export BAT_STYLE="grid"
fi
# -----------------------------------------------------------------------------
# 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 MANPAGER='sh -c "col -bx | '"$(printf "%q" "$EXECUTABLE_BAT")"' --language=man --style=grid '$(printf "%q " "${BAT_ARGS[@]}")'"'
export MANROFFOPT='-c'
# 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 $?

View file

@ -37,9 +37,8 @@
#
# -----------------------------------------------------------------------------
# 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)"
SELF="$(cd "$(dirname "${BASH_SOURCE[0]}")" && cd "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo ".")")" && pwd)/$(basename "${BASH_SOURCE[0]}")"
LIB="$(cd "$(dirname "${BASH_SOURCE[0]}")" && cd "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo ".")")/../lib" && pwd)"
source "${LIB}/constants.sh"
source "${LIB}/dirs.sh"
source "${LIB}/str.sh"
@ -67,13 +66,13 @@ if [[ "$#" -eq 0 ]]; then
# 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
# This will directly check if the parent is fish, since there's a
# good chance that `bash` or `sh` will be invoking fish.
if [[ "$(basename -- "$(parent_executable | cut -f1 -d' ')")" == "fish" ]]; then
detected_shell="fish"
else
detected_shell="$(parent_shell)"
fi
# Print the commands required to add `batpipe` to the environment variables.
case "$(basename -- "${detected_shell:bash}")" in
@ -81,12 +80,6 @@ if [[ "$#" -eq 0 ]]; then
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"
@ -96,7 +89,7 @@ if [[ "$#" -eq 0 ]]; then
# 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"
printc "\n%{DIM}# The following will enable colors when using batpipe with less:\n"
fi
# shellcheck disable=SC2016
@ -105,10 +98,6 @@ if [[ "$#" -eq 0 ]]; then
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"
@ -126,47 +115,17 @@ 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"
if [[ "$(basename -- "$(parent_executable "$(parent_executable_pid)" | cut -f1 -d' ')")" == less ]]; then
BATPIPE_INSIDE_LESS=true
elif [[ "$(basename -- "$(parent_executable | cut -f1 -d' ')")" == "$(basename -- "$EXECUTABLE_BAT")" ]]; then
BATPIPE_INSIDE_BAT=true
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
BATPIPE_VIEWERS=("exa" "ls" "tar" "unzip" "gunzip" "xz")
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -176,12 +135,6 @@ viewer_exa_supports() {
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"
@ -192,16 +145,6 @@ viewer_exa_process() {
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 $?
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -231,50 +174,17 @@ viewer_tar_supports() {
viewer_tar_process() {
if [[ -n "$2" ]]; then
tar $3 -xf "$1" -O "$2" | bat --file-name="$1/$2"
tar -xf "$1" -O "$2" | bat --file-name="$1/$2"
else
batpipe_archive_header
tar $3 -tvf "$1"
batpipe_header "Viewing contents of archive: %{PATH}%s" "$1"
batpipe_subheader "To view files within the archive, add the file path after the archive."
tar -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
@ -289,7 +199,8 @@ viewer_unzip_process() {
if [[ -n "$2" ]]; then
unzip -p "$1" "$2" | bat --file-name="$1/$2"
else
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."
unzip -l "$1"
return $?
fi
@ -353,11 +264,6 @@ batpipe_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.
#

View file

@ -284,22 +284,9 @@ else
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
clear
"${FILES[@]}" 2>&1 | "$EXECUTABLE_BAT" "${BAT_ARGS[@]}"
sleep "${OPT_INTERVAL}" || exit 1
done
}

View file

@ -14,7 +14,6 @@ source "${LIB}/str.sh"
source "${LIB}/print.sh"
source "${LIB}/version.sh"
source "${LIB}/check.sh"
source "${LIB}/term.sh"
# -----------------------------------------------------------------------------
# Init:
# -----------------------------------------------------------------------------
@ -23,10 +22,7 @@ hook_version
# Formatters:
# -----------------------------------------------------------------------------
FORMATTERS=(
"yq" "prettier" "rustfmt" "shfmt" "clangformat"
"black" "mix_format" "column"
)
FORMATTERS=("prettier" "rustfmt" "shfmt" "clangformat" "black")
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -122,96 +118,6 @@ formatter_black_process() {
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:
# -----------------------------------------------------------------------------
@ -239,9 +145,6 @@ map_language_to_extension() {
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"
@ -369,8 +272,6 @@ OPT_LANGUAGE=
FILES=()
DEBUG_PRINT_FORMATTER=false
TERMINAL_WIDTH="$(term_width)"
# Parse arguments.
while shiftopt; do
case "$OPT" in
@ -388,9 +289,7 @@ while shiftopt; do
# bat options
-*) {
if [[ -n "$OPT_VAL" ]]; then BAT_ARGS+=("$OPT=$OPT_VAL");
else BAT_ARGS+=("$OPT");
fi
BAT_ARGS+=("$OPT=$OPT_VAL")
} ;;
# Files

View file

@ -1,4 +1,14 @@
#!/usr/bin/env bash
# Run bash, but with executable name as `fish`.
exec -a "${SHIM_ARGV0:-fish}" bash "$@"
exit $?
# Find the real fish.
HERE="$(cd "$(dirname "$0")" && pwd)"
while read -d ':' -r dir; do
if [[ "$dir" == "$HERE" || -z "$dir" ]]; then continue; fi
if [[ -f "${dir}/fish" ]]; then
TMPDIR= "${dir}/fish" "$@"
exit $?
fi
done <<<"$PATH:"
# Print error and exit.
echo "fish was not found on \$PATH" 1>&2
exit 127

View file

@ -12,10 +12,4 @@ EOF
exit 0
fi
FILES=()
while [[ $# -gt 0 ]]; do
-*) : ;;
*) FILES+=("$1")
done
cat "${FILES[@]}"
cat "$1"

View file

@ -1,7 +0,0 @@
#!/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 $?

View file

@ -1,107 +0,0 @@
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

View file

@ -1,8 +1,8 @@
────────────────────────────────────────────────────────────────────────────────
File: file.txt
 1 cat 
 2 dog
 3 car 
 4 frog
 5 fox
 1 cat 
 2 dog
 3 car 
 4 frog
 5 fox
────────────────────────────────────────────────────────────────────────────────

View file

@ -1,6 +0,0 @@
File: file.txt
 1 cat 
 2 dog
 3 car 
 4 frog
 5 fox

View file

@ -1,7 +0,0 @@
────────────────────────────────────────────────────────────────────────────────
cat 
dog
car 
frog
fox
────────────────────────────────────────────────────────────────────────────────

View file

@ -1,26 +0,0 @@
───────┬────────────────────────────────
│ File: file.txt
───────┼────────────────────────────────
 1 │ cat
 2 │ dog
 3 │ car
 4 │ frog
 5 │ fox
 6 │ clocks
 7 │ bash
 8 │ $300
 9 │ ^$!@
───────┴────────────────────────────────
───────┬────────────────────────────────────────────────────
│ File: file.txt
───────┼────────────────────────────────────────────────────
 1 │ cat
 2 │ dog
 3 │ car
 4 │ frog
 5 │ fox
 6 │ clocks
 7 │ bash
 8 │ $300
 9 │ ^$!@
───────┴────────────────────────────────────────────────────

View file

@ -2,8 +2,6 @@ HAS_RIPGREP=false
setup() {
use_shim 'batgrep'
unset BAT_STYLE
if command -v rg &>/dev/null; then
HAS_RIPGREP=true
@ -16,15 +14,6 @@ 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
@ -113,33 +102,3 @@ test:search_from_stdin() {
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."
}

View file

@ -11,35 +11,11 @@ test:detected_bash_shell() {
}
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.'
description "Test it can detect a bash shell."
command -v "fish" &>/dev/null || skip "Test requires fish shell."
output="$(SHELL="fish" fish --login -c "$(batpipe_path)")"
grep '^set -x' <<< "$output" >/dev/null || fail "Detected the wrong shell for fish."
}
test:viewer_gzip() {
@ -48,14 +24,3 @@ test:viewer_gzip() {
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
}

View file

@ -10,14 +10,6 @@ use_pager() {
_detect_pager
}
use_no_pager() {
unset BAT_PAGER
unset PAGER
_configure_pager
_detect_pager
}
use_bat_pager() {
unset PAGER
export BAT_PAGER="$1"
@ -34,14 +26,6 @@ test:less_detection() {
(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"
@ -98,14 +82,6 @@ test:env_bat_pager() {
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."

View file

@ -1 +1 @@
2024.08.24
2021.04.06