[bash,zsh] Work around a quirk of macOS awk

macOS awk is a variant of nawk, but it contains a unique patch for the
UTF-8 support.  However, this patch causes the problem.  If the input
contains any non-UTF-8 data, macOS awk stops processing and does not
do anything, instead of ignoring the unrecognized data and continue
the processing.  However, the contents of the ssh configuration and
/etc/hosts is not under the control of fzf, so we cannot fix the input
when those files contain non-UTF-8 data.  To work around this
behavior, one can set the locale to LC_ALL=C to treat the input data
with the plain 8-bit encoding.
This commit is contained in:
Koichi Murase
2025-06-04 13:11:00 +09:00
committed by Junegunn Choi
parent ec521e47aa
commit 09194c24f2
4 changed files with 119 additions and 21 deletions

View File

@@ -25,6 +25,32 @@ __fzf_defaults() {
echo "${FZF_DEFAULT_OPTS-} $2"
}
# This function performs `exec awk "$@"` safely by working around awk
# compatibility issues.
#
# Note: To reduce an extra fork, this function performs "exec" so is expected
# to be run as the last command in a subshell.
#
# Note: This function is included with {completion,key-bindings}.{bash,zsh} and
# synchronized.
__fzf_exec_awk() {
if [[ -z ${__fzf_awk-} ]]; then
__fzf_awk=awk
# choose the faster mawk if: it's installed && build date >= 20230322 &&
# version >= 1.3.4
local n x y z d
IFS=' .' read n x y z d <<< $(command mawk -W version 2> /dev/null)
[[ $n == mawk ]] && (( d >= 20230302 && (x * 1000 + y) * 1000 + z >= 1003004 )) && __fzf_awk=mawk
fi
# Note: macOS awk has a quirk that it stops processing at all when it sees
# any data not following UTF-8 in the input stream when the current LC_CTYPE
# specifies the UTF-8 encoding. To work around this quirk, one needs to
# specify LC_ALL=C to change the current encoding to the plain one.
LC_ALL=C exec "$__fzf_awk" "$@"
}
__fzf_select__() {
FZF_DEFAULT_COMMAND=${FZF_CTRL_T_COMMAND:-} \
FZF_DEFAULT_OPTS=$(__fzf_defaults "--reverse --walker=file,dir,follow,hidden --scheme=path" "${FZF_CTRL_T_OPTS-} -m") \
@@ -74,13 +100,7 @@ if command -v perl > /dev/null; then
}
else # awk - fallback for POSIX systems
__fzf_history__() {
local output script n x y z d
if [[ -z $__fzf_awk ]]; then
__fzf_awk=awk
# choose the faster mawk if: it's installed && build date >= 20230322 && version >= 1.3.4
IFS=' .' read n x y z d <<< $(command mawk -W version 2> /dev/null)
[[ $n == mawk ]] && (( d >= 20230302 && (x *1000 +y) *1000 +z >= 1003004 )) && __fzf_awk=mawk
fi
local output script
[[ $(HISTTIMEFORMAT='' builtin history 1) =~ [[:digit:]]+ ]] # how many history entries
script='function P(b) { ++n; sub(/^[ *]/, "", b); if (!seen[b]++) { printf "%d\t%s%c", '$((BASH_REMATCH + 1))' - n, b, 0 } }
NR==1 { b = substr($0, 2); next }
@@ -90,7 +110,7 @@ else # awk - fallback for POSIX systems
output=$(
set +o pipefail
builtin fc -lnr -2147483648 2> /dev/null | # ( $'\t '<lines>$'\n' )* ; <lines> ::= [^\n]* ( $'\n'<lines> )*
command $__fzf_awk "$script" | # ( <counter>$'\t'<lines>$'\000' )*
__fzf_exec_awk "$script" | # ( <counter>$'\t'<lines>$'\000' )*
FZF_DEFAULT_OPTS=$(__fzf_defaults "" "-n2..,.. --scheme=history --bind=ctrl-r:toggle-sort --wrap-sign '"$'\t'"↳ ' --highlight-line ${FZF_CTRL_R_OPTS-} +m --read0") \
FZF_DEFAULT_OPTS_FILE='' $(__fzfcmd) --query "$READLINE_LINE"
) || return