155 lines
3.2 KiB
Bash
155 lines
3.2 KiB
Bash
command -v \
|
||
echo.error \
|
||
echo.status \
|
||
echo.success \
|
||
echo.success.color \
|
||
rg \
|
||
sed \
|
||
utils.check-errors \
|
||
utils.colors.green \
|
||
utils.yN \
|
||
&>/dev/null || return 0
|
||
|
||
|
||
frog() {
|
||
eval "$(usage.reset)"
|
||
|
||
local USAGE__description='
|
||
find-and-replace for all files in the current directory
|
||
|
||
frog = [F]ix [R]ip[G]rep ... and "o" because 🐸
|
||
'
|
||
|
||
local USAGE__options='
|
||
-s, --search <sed regex> the regex to search for
|
||
-r, --replace <string> replacement value
|
||
|
||
-d, --delete delete instead having a replacement value
|
||
--trim trim trailing spaces from all files in the work-tree
|
||
|
||
-h, --help print this message
|
||
'
|
||
|
||
local USAGE__args='
|
||
\$1 search regex
|
||
\$2 replacement value
|
||
'
|
||
|
||
local SEARCH_REGEX REPLACE_VALUE DELETE=false TRIM=false
|
||
|
||
local _S ERRORS=0 POSITIONAL_ARGUMENT_COUNT=0
|
||
while [[ $# -gt 0 ]]
|
||
do
|
||
_S=1
|
||
|
||
case $1 in
|
||
( -s | --search )
|
||
_S=2
|
||
SEARCH_REGEX="$2"
|
||
;;
|
||
|
||
( -r | --replace )
|
||
_S=2
|
||
REPLACE_VALUE="$2"
|
||
;;
|
||
|
||
( -d | --delete )
|
||
_S=1
|
||
DELETE=true
|
||
;;
|
||
|
||
( --trim )
|
||
_S=1
|
||
TRIM=true
|
||
DELETE=true
|
||
SEARCH_REGEX='\s+$'
|
||
;;
|
||
|
||
( -h | --help )
|
||
utils.io.usage
|
||
return 0
|
||
;;
|
||
|
||
( * )
|
||
((POSITIONAL_ARGUMENT_COUNT+=1))
|
||
case ${POSITIONAL_ARGUMENT_COUNT} in
|
||
( 1 )
|
||
case "${SEARCH_REGEX}" in
|
||
( '' )
|
||
SEARCH_REGEX="$1"
|
||
;;
|
||
( * )
|
||
[ ! "${REPLACE_VALUE}" ] \
|
||
&& REPLACE_VALUE="$1" \
|
||
|| echo.error "too many arguments" \
|
||
;
|
||
;;
|
||
esac
|
||
;;
|
||
|
||
( 2 )
|
||
[ ! "${REPLACE_VALUE}" ] \
|
||
&& REPLACE_VALUE="$1" \
|
||
|| echo.error "too many arguments" \
|
||
;
|
||
;;
|
||
|
||
( * )
|
||
echo.error "unknown argument '$1'"
|
||
;;
|
||
esac
|
||
;;
|
||
esac
|
||
|
||
[[ ${_S} -le $# ]] \
|
||
&& shift ${_S} \
|
||
|| echo.error "argument error for '$1'" \
|
||
|| shift $#
|
||
done
|
||
|
||
[ ! "${SEARCH_REGEX}" ] && [ ! "${REPLACE_VALUE}" ] && [[ ${DELETE} =~ false ]] && [[ ${POSITIONAL_ARGUMENT_COUNT} -eq 0 ]] \
|
||
&& utils.io.usage \
|
||
&& return 0 \
|
||
;
|
||
|
||
[ "${SEARCH_REGEX}" ] \
|
||
|| echo.error "missing search regex"
|
||
|
||
[ ! "${REPLACE_VALUE}" ] && [[ ${DELETE} =~ false ]] \
|
||
&& echo.error "missing replacement value"
|
||
|
||
[ "${REPLACE_VALUE}" ] && [[ ${DELETE} =~ true ]] \
|
||
&& echo.error "cannot use '--delete' with a replacement value"
|
||
|
||
utils.check-errors || return $?
|
||
|
||
##########################################
|
||
|
||
local FILES_MATCHED=($(rg -l -- "${SEARCH_REGEX}"))
|
||
[[ ${#FILES_MATCHED[@]} -gt 0 ]] || {
|
||
echo.status "no files contain '${SEARCH_REGEX}' in the current tree; nothing to do"
|
||
return 0
|
||
}
|
||
|
||
clear
|
||
|
||
rg -- "${SEARCH_REGEX}" ${FILES_MATCHED[@]}
|
||
|
||
echo.status "showing matches from $(utils.colors.green)${#FILES_MATCHED[@]} file(s)$(echo.status.color) in the current directory"
|
||
utils.yN "replace all matches with '${REPLACE_VALUE}'?" || return 1
|
||
|
||
[[ ${TRIM} =~ true ]] && SEARCH_REGEX='\s\+$'
|
||
|
||
local FILENAME
|
||
for FILENAME in ${FILES_MATCHED[@]}
|
||
do
|
||
sed -i "s${SEARCH_REGEX}${REPLACE_VALUE}g" "${FILENAME}" \
|
||
|| echo.error "failed to update '${FILENAME}'"
|
||
done
|
||
|
||
[[ ${ERRORS} -eq 0 ]] \
|
||
&& echo.success "successfully replaced '${SEARCH_REGEX}' with '${REPLACE_VALUE}'" \
|
||
|| echo.error "something went wrong (see above)" \
|
||
;
|
||
}
|