You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
bat/tests/syntax-tests/highlighted/Bash/batgrep.sh

512 lines
78 KiB
Bash

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

#!/usr/bin/env bash
# -----------------------------------------------------------------------------
# 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
# -----------------------------------------------------------------------------
printc(){
printf "$(sed "$_PRINTC_PATTERN" <<<"$1")" "${@:2}"
}
printc_init(){
case "$1" in
true)_PRINTC_PATTERN="$_PRINTC_PATTERN_ANSI";;
false)_PRINTC_PATTERN="$_PRINTC_PATTERN_PLAIN";;
"[DEFINE]"){
_PRINTC_PATTERN_ANSI=""
_PRINTC_PATTERN_PLAIN=""
local name
local ansi
while read -r name ansi;do
if [[ -z $name && -z $ansi ]]||[[ ${name:0:1} == "#" ]];then
continue
fi
ansi="${ansi/\\/\\\\}"
_PRINTC_PATTERN_PLAIN="${_PRINTC_PATTERN_PLAIN}s/%{$name}//g;"
_PRINTC_PATTERN_ANSI="${_PRINTC_PATTERN_ANSI}s/%{$name}/$ansi/g;"
done
if [ -t 1 ];then
_PRINTC_PATTERN="$_PRINTC_PATTERN_ANSI"
else
_PRINTC_PATTERN="$_PRINTC_PATTERN_PLAIN"
fi
}
esac
}
print_warning(){
printc "%{YELLOW}[%s warning]%{CLEAR}: $1%{CLEAR}\n" "batgrep" "${@:2}" 1>&2
}
print_error(){
printc "%{RED}[%s error]%{CLEAR}: $1%{CLEAR}\n" "batgrep" "${@:2}" 1>&2
}
printc_init "[DEFINE]" <<END
 CLEAR \x1B[0m
 RED \x1B[31m
 GREEN \x1B[32m
 YELLOW \x1B[33m
 BLUE \x1B[34m
 MAGENTA \x1B[35m
 CYAN \x1B[36m
 DEFAULT \x1B[39m
 DIM \x1B[2m
END
is_pager_less(){
[[ "$(pager_name)" == "less" ]]
return $?
}
is_pager_disabled(){
[[ -z "$(pager_name)" ]]
return $?
}
pager_name(){
_detect_pager 1>&2
echo "$_SCRIPT_PAGER_NAME"
}
pager_version(){
_detect_pager 1>&2
echo "$_SCRIPT_PAGER_VERSION"
}
pager_exec(){
if [[ -n $SCRIPT_PAGER_CMD ]];then
"$@"|pager_display
return $?
else
"$@"
return $?
fi
}
pager_display(){
if [[ -n $SCRIPT_PAGER_CMD ]];then
if [[ -n $SCRIPT_PAGER_ARGS ]];then
"${SCRIPT_PAGER_CMD[@]}" "${SCRIPT_PAGER_ARGS[@]}"
return $?
else
"${SCRIPT_PAGER_CMD[@]}"
return $?
fi
else
cat
return $?
fi
}
_detect_pager(){
if [[ $_SCRIPT_PAGER_DETECTED == "true" ]];then return;fi
_SCRIPT_PAGER_DETECTED=true
if [[ -z ${SCRIPT_PAGER_CMD[0]} ]];then
_SCRIPT_PAGER_VERSION=0
_SCRIPT_PAGER_NAME=""
return
fi
local output
local output1
output="$("${SCRIPT_PAGER_CMD[0]}" --version 2>&1)"
output1="$(head -n 1 <<<"$output")"
if [[ $output1 =~ ^less[[:blank:]]([[:digit:]]+) ]];then
_SCRIPT_PAGER_VERSION="${BASH_REMATCH[1]}"
_SCRIPT_PAGER_NAME="less"
else
_SCRIPT_PAGER_VERSION=0
_SCRIPT_PAGER_NAME="$(basename "${SCRIPT_PAGER_CMD[0]}")"
fi
}
_configure_pager(){
SCRIPT_PAGER_CMD=($PAGER)
SCRIPT_PAGER_ARGS=()
if [[ -n ${BAT_PAGER+x} ]];then
SCRIPT_PAGER_CMD=($BAT_PAGER)
SCRIPT_PAGER_ARGS=()
return
fi
if is_pager_less;then
SCRIPT_PAGER_CMD=("${SCRIPT_PAGER_CMD[0]}" -R --quit-if-one-screen)
if [[ "$(pager_version)" -lt 500 ]];then
SCRIPT_PAGER_CMD+=(--no-init)
fi
fi
}
if [[ -t 1 ]];then
_configure_pager
else
SCRIPT_PAGER_CMD=()
SCRIPT_PAGER_ARGS=()
fi
SHIFTOPT_HOOKS=()
setargs(){
_ARGV=("$@")
_ARGV_LAST="$((${#_ARGV[@]}-1))"
_ARGV_INDEX=0
}
shiftopt(){
[[ $_ARGV_INDEX -gt $_ARGV_LAST ]]&&return 1
OPT="${_ARGV[$_ARGV_INDEX]}"
unset OPT_VAL
if [[ $OPT =~ ^--[a-zA-Z0-9_-]+=.* ]];then
OPT_VAL="${OPT#*=}"
OPT="${OPT%%=*}"
fi
((_ARGV_INDEX++))
local hook
for hook in "${SHIFTOPT_HOOKS[@]}";do
if "$hook";then
shiftopt
return $?
fi
done
return 0
}
shiftval(){
if [[ -n ${OPT_VAL+x} ]];then
return 0
fi
if [[ $OPT =~ ^-[[:alpha:]][[:digit:]]{1,}$ ]];then
OPT_VAL="${OPT:2}"
return
fi
OPT_VAL="${_ARGV[$_ARGV_INDEX]}"
((_ARGV_INDEX++))
if [[ $OPT_VAL =~ -.* ]];then
printc "%{RED}%s: '%s' requires a value%{CLEAR}\n" "batgrep" "$ARG"
exit 1
fi
}
setargs "$@"
hook_color(){
SHIFTOPT_HOOKS+=("__shiftopt_hook__color")
__shiftopt_hook__color(){
case "$OPT" in
--no-color)OPT_COLOR=false;;
--color){
case "$OPT_VAL" in
"")OPT_COLOR=true;;
always|true)OPT_COLOR=true;;
never|false)OPT_COLOR=false;;
auto)return 0;;
*)printc "%{RED}%s: '--color' expects value of 'auto', 'always', or 'never'%{CLEAR}\n" "batgrep"
exit 1
esac
};;
*)return 1
esac
printc_init "$OPT_COLOR"
return 0
}
if [[ -z $OPT_COLOR ]];then
if [[ -t 1 ]];then
OPT_COLOR=true
else
OPT_COLOR=false
fi
printc_init "$OPT_COLOR"
fi
}
hook_pager(){
SHIFTOPT_HOOKS+=("__shiftopt_hook__pager")
__shiftopt_hook__pager(){
case "$OPT" in
\
--no-pager)shiftval
SCRIPT_PAGER_CMD=''
;;
--paging){
shiftval
case "$OPT_VAL" in
auto):;;
always):;;
never)SCRIPT_PAGER_CMD='';;
*)printc "%{RED}%s: '--paging' expects value of 'auto', 'always', or 'never'%{CLEAR}\n" "batgrep"
exit 1
esac
};;
\
--pager){
shiftval
{
SCRIPT_PAGER_CMD=($OPT_VAL)
PAGER_ARGS=()
}
};;
*)return 1
esac
}
}
hook_version(){
SHIFTOPT_HOOKS+=("__shiftopt_hook__version")
__shiftopt_hook__version(){
if [[ $OPT == "--version" ]];then
printf "%s %s\n\n%s\n%s\n" \
"batgrep" \
"2020.10.04" \
"Copyright (C) 2019-2020 eth-p | MIT License" \
"https://github.com/eth-p/bat-extras"
exit 0
fi
return 1
}
}
term_width(){
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
}
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
}
OPT_TERMINAL_WIDTH="$(term_width)"
}
bat_version(){
"bat" --version|cut -d ' ' -f 2
return
}
version_compare(){
local version="$1"
local compare="$3"
if ! [[ $version =~ \.$ ]];then
version="$version."
fi
if ! [[ $compare =~ \.$ ]];then
compare="$compare."
fi
version_compare__recurse "$version" "$2" "$compare"
return $?
}
version_compare__recurse(){
local version="$1"
local operator="$2"
local compare="$3"
local v_major="${version%%.*}"
local c_major="${compare%%.*}"
local v_minor="${version#*.}"
local c_minor="${compare#*.}"
if [[ -z $v_minor && -z $c_minor ]];then
[ "$v_major" $operator "$c_major" ]
return $?
fi
if [[ -z $v_minor ]];then
v_minor="0."
fi
if [[ -z $c_minor ]];then
c_minor="0."
fi
case "$operator" in
-eq)[[ $v_major -ne $c_major ]]&&return 1;;
-ne)[[ $v_major -ne $c_major ]]&&return 0;;
-ge|-gt)[[ $v_major -lt $c_major ]]&&return 1
[[ $v_major -gt $c_major ]]&&return 0
;;
-le|-lt)[[ $v_major -gt $c_major ]]&&return 1
[[ $v_major -lt $c_major ]]&&return 0
esac
version_compare__recurse "$v_minor" "$operator" "$c_minor"
}
hook_color
hook_pager
hook_version
hook_width
RG_ARGS=()
BAT_ARGS=()
PATTERN=""
FILES=()
OPT_CASE_SENSITIVITY=''
OPT_CONTEXT_BEFORE=2
OPT_CONTEXT_AFTER=2
OPT_FOLLOW=true
OPT_SNIP=""
OPT_HIGHLIGHT=true
OPT_SEARCH_PATTERN=false
OPT_FIXED_STRINGS=false
BAT_STYLE="header,numbers"
if version_compare "$(bat_version)" -gt "0.12";then
OPT_SNIP=",snip"
fi
if [[ -n $RIPGREP_CONFIG_PATH && -e $RIPGREP_CONFIG_PATH ]];then
for arg in $(cat "$RIPGREP_CONFIG_PATH");do
case "$arg" in
--context=*)val="${arg:10}"
OPT_CONTEXT_BEFORE="$val"
OPT_CONTEXT_AFTER="$val"
;;
--before-context=*)val="${arg:17}"
OPT_CONTEXT_BEFORE="$val"
;;
--after-context=*)val="${arg:16}"
OPT_CONTEXT_AFTER="$val"
;;
-C*)val="${arg:2}"
OPT_CONTEXT_BEFORE="$val"
OPT_CONTEXT_AFTER="$val"
;;
-B*)val="${arg:2}"
OPT_CONTEXT_BEFORE="$val"
;;
-A*)val="${arg:2}"
OPT_CONTEXT_AFTER="$val"
esac
done
fi
while shiftopt;do
case "$OPT" in
\
-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"
OPT_CONTEXT_AFTER="$OPT_VAL"
;;
-F|--fixed-strings)OPT_FIXED_STRINGS=true
RG_ARGS+=("$OPT")
;;
-U|--multiline|\
-P|--pcre2|\
-z|--search-zip|\
-w|--word-regexp|\
--one-file-system|\
--multiline-dotall|\
--ignore|--no-ignore|\
--crlf|--no-crlf|\
--hidden|--no-hidden)RG_ARGS+=("$OPT")
;;
-E|--encoding|\
-g|--glob|\
-t|--type|\
-T|--type-not|\
-m|--max-count|\
--max-depth|\
--iglob|\
--ignore-file)shiftval
RG_ARGS+=("$OPT" "$OPT_VAL")
;;
\
\
\
--no-follow)OPT_FOLLOW=false;;
--no-snip)OPT_SNIP="";;
--no-highlight)OPT_HIGHLIGHT=false;;
-p|--search-pattern)OPT_SEARCH_PATTERN=true;;
--no-search-pattern)OPT_SEARCH_PATTERN=false;;
\
--rg:*){
if [[ ${OPT:5:1} == "-" ]];then
RG_ARGS+=("${OPT:5}")
else
RG_ARGS+=("--${OPT:5}")
fi
if [[ -n $OPT_VAL ]];then
RG_ARGS+=("$OPT_VAL")
fi
};;
\
-*){
printc "%{RED}%s: unknown option '%s'%{CLEAR}\n" "batgrep" "$OPT" 1>&2
exit 1
};;
\
*){
if [ -z "$PATTERN" ];then
PATTERN="$OPT"
else
FILES+=("$OPT")
fi
}
esac
done
if [[ -z $PATTERN ]];then
print_error "no pattern provided"
exit 1
fi
SEP="$(printc "%{DIM}%${OPT_TERMINAL_WIDTH}s%{CLEAR}"|sed "s/ /─/g")"
if [[ -n $OPT_CASE_SENSITIVITY ]];then
RG_ARGS+=("$OPT_CASE_SENSITIVITY")
fi
if "$OPT_FOLLOW";then
RG_ARGS+=("--follow")
fi
if "$OPT_COLOR";then
BAT_ARGS+=("--color=always")
else
BAT_ARGS+=("--color=never")
fi
if [[ $OPT_CONTEXT_BEFORE -eq 0 && $OPT_CONTEXT_AFTER -eq 0 ]];then
OPT_SNIP=""
OPT_HIGHLIGHT=false
fi
if "$OPT_SEARCH_PATTERN";then
if is_pager_less;then
if "$OPT_FIXED_STRINGS";then
SCRIPT_PAGER_ARGS+=(-p $'\x12'"$PATTERN")
else
SCRIPT_PAGER_ARGS+=(-p "$PATTERN")
fi
elif is_pager_disabled;then
print_error "%s %s %s" \
"The -p/--search-pattern option requires a pager, but" \
'the pager was explicitly disabled by $BAT_PAGER or the' \
"--paging option."
exit 1
else
print_error "Unsupported pager '%s' for option -p/--search-pattern" \
"$(pager_name)"
exit 1
fi
fi
main(){
FOUND_FILES=()
FOUND=0
FIRST_PRINT=true
LAST_LR=()
LAST_LH=()
LAST_FILE=''
do_print(){
[[ -z $LAST_FILE ]]&&return 0
"$FIRST_PRINT"&&echo "$SEP"
FIRST_PRINT=false
"bat" "${BAT_ARGS[@]}" \
"${LAST_LR[@]}" \
"${LAST_LH[@]}" \
--style="$BAT_STYLE$OPT_SNIP" \
--paging=never \
--terminal-width="$OPT_TERMINAL_WIDTH" \
"$LAST_FILE"
echo "$SEP"
}
while IFS=':' read -r file line column text;do
((FOUND++))
if [[ $LAST_FILE != "$file" ]];then
do_print
LAST_FILE="$file"
LAST_LR=()
LAST_LH=()
fi
line_start=$((line-OPT_CONTEXT_BEFORE))
line_end=$((line+OPT_CONTEXT_AFTER))
[[ $line_start -gt 0 ]]||line_start=''
LAST_LR+=("--line-range=$line_start:$line_end")
[[ $OPT_HIGHLIGHT == "true" ]]&&LAST_LH+=("--highlight-line=$line")
done < <(rg --with-filename --vimgrep "${RG_ARGS[@]}" --context=0 --no-context-separator --sort path "$PATTERN" "${FILES[@]}")
do_print
if [[ $FOUND -eq 0 ]];then
exit 2
fi
}
pager_exec main
exit $?