mirror of
https://github.com/junegunn/fzf.git
synced 2025-11-16 07:13:48 -05:00
[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:
committed by
Junegunn Choi
parent
ec521e47aa
commit
09194c24f2
@@ -39,6 +39,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_comprun() {
|
||||
if [[ "$(type -t _fzf_comprun 2>&1)" = function ]]; then
|
||||
_fzf_comprun "$@"
|
||||
@@ -364,7 +390,7 @@ _fzf_complete() {
|
||||
fi
|
||||
|
||||
local cur selected trigger cmd post
|
||||
post="$(caller 0 | command awk '{print $2}')_post"
|
||||
post="$(caller 0 | __fzf_exec_awk '{print $2}')_post"
|
||||
type -t "$post" > /dev/null 2>&1 || post='command cat'
|
||||
|
||||
trigger=${FZF_COMPLETION_TRIGGER-'**'}
|
||||
@@ -443,7 +469,7 @@ _fzf_proc_completion() {
|
||||
}
|
||||
|
||||
_fzf_proc_completion_post() {
|
||||
command awk '{print $2}'
|
||||
__fzf_exec_awk '{print $2}'
|
||||
}
|
||||
|
||||
# To use custom hostname lists, override __fzf_list_hosts.
|
||||
@@ -475,7 +501,7 @@ if ! declare -F __fzf_list_hosts > /dev/null; then
|
||||
shopt -u dotglob nocaseglob failglob
|
||||
shopt -s nullglob
|
||||
|
||||
command awk '
|
||||
__fzf_exec_awk '
|
||||
tolower($1) ~ /^host(name)?$/ {
|
||||
for (i = 2; i <= NF; i++)
|
||||
if ($i !~ /[*?%]/)
|
||||
@@ -484,7 +510,7 @@ if ! declare -F __fzf_list_hosts > /dev/null; then
|
||||
' ~/.ssh/config ~/.ssh/config.d/* /etc/ssh/ssh_config 2> /dev/null
|
||||
) \
|
||||
<(
|
||||
command awk -F ',' '
|
||||
__fzf_exec_awk -F ',' '
|
||||
match($0, /^[[a-z0-9.,:-]+/) {
|
||||
$0 = substr($0, 1, RLENGTH)
|
||||
gsub(/\[/, "")
|
||||
@@ -494,7 +520,7 @@ if ! declare -F __fzf_list_hosts > /dev/null; then
|
||||
' ~/.ssh/known_hosts 2> /dev/null
|
||||
) \
|
||||
<(
|
||||
command awk '
|
||||
__fzf_exec_awk '
|
||||
/^[[:blank:]]*(#|$)|0\.0\.0\.0/ { next }
|
||||
{
|
||||
sub(/#.*/, "")
|
||||
@@ -523,7 +549,7 @@ _fzf_complete_ssh() {
|
||||
*)
|
||||
local user=
|
||||
[[ "$2" =~ '@' ]] && user="${2%%@*}@"
|
||||
_fzf_complete +m -- "$@" < <(__fzf_list_hosts | command awk -v user="$user" '{print user $0}')
|
||||
_fzf_complete +m -- "$@" < <(__fzf_list_hosts | __fzf_exec_awk -v user="$user" '{print user $0}')
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
@@ -104,6 +104,32 @@ __fzf_defaults() {
|
||||
echo -E "${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_comprun() {
|
||||
if [[ "$(type _fzf_comprun 2>&1)" =~ function ]]; then
|
||||
_fzf_comprun "$@"
|
||||
@@ -253,7 +279,7 @@ if ! declare -f __fzf_list_hosts > /dev/null; then
|
||||
# when no matching is found.
|
||||
setopt GLOB NO_DOT_GLOB CASE_GLOB NO_NOMATCH NULL_GLOB
|
||||
|
||||
command awk '
|
||||
__fzf_exec_awk '
|
||||
tolower($1) ~ /^host(name)?$/ {
|
||||
for (i = 2; i <= NF; i++)
|
||||
if ($i !~ /[*?%]/)
|
||||
@@ -262,7 +288,7 @@ if ! declare -f __fzf_list_hosts > /dev/null; then
|
||||
' ~/.ssh/config ~/.ssh/config.d/* /etc/ssh/ssh_config 2> /dev/null
|
||||
) \
|
||||
<(
|
||||
command awk -F ',' '
|
||||
__fzf_exec_awk -F ',' '
|
||||
match($0, /^[[a-z0-9.,:-]+/) {
|
||||
$0 = substr($0, 1, RLENGTH)
|
||||
gsub(/\[/, "")
|
||||
@@ -272,7 +298,7 @@ if ! declare -f __fzf_list_hosts > /dev/null; then
|
||||
' ~/.ssh/known_hosts 2> /dev/null
|
||||
) \
|
||||
<(
|
||||
command awk '
|
||||
__fzf_exec_awk '
|
||||
/^[[:blank:]]*(#|$)|0\.0\.0\.0/ { next }
|
||||
{
|
||||
sub(/#.*/, "")
|
||||
@@ -300,7 +326,7 @@ _fzf_complete_ssh() {
|
||||
*)
|
||||
local user
|
||||
[[ $prefix =~ @ ]] && user="${prefix%%@*}@"
|
||||
_fzf_complete +m -- "$@" < <(__fzf_list_hosts | awk -v user="$user" '{print user $0}')
|
||||
_fzf_complete +m -- "$@" < <(__fzf_list_hosts | __fzf_exec_awk -v user="$user" '{print user $0}')
|
||||
;;
|
||||
esac
|
||||
}
|
||||
@@ -358,7 +384,7 @@ _fzf_complete_kill() {
|
||||
}
|
||||
|
||||
_fzf_complete_kill_post() {
|
||||
awk '{print $2}'
|
||||
__fzf_exec_awk '{print $2}'
|
||||
}
|
||||
|
||||
fzf-completion() {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -46,6 +46,32 @@ __fzf_defaults() {
|
||||
echo -E "${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" "$@"
|
||||
}
|
||||
|
||||
# CTRL-T - Paste the selected file path(s) into the command line
|
||||
__fzf_select() {
|
||||
setopt localoptions pipefail no_aliases 2> /dev/null
|
||||
@@ -117,13 +143,13 @@ fzf-history-widget() {
|
||||
FZF_DEFAULT_OPTS=$(__fzf_defaults "" "-n2..,.. --scheme=history --bind=ctrl-r:toggle-sort --wrap-sign '\t↳ ' --highlight-line ${FZF_CTRL_R_OPTS-} --query=${(qqq)LBUFFER} +m --read0") \
|
||||
FZF_DEFAULT_OPTS_FILE='' $(__fzfcmd))"
|
||||
else
|
||||
selected="$(fc -rl 1 | awk '{ cmd=$0; sub(/^[ \t]*[0-9]+\**[ \t]+/, "", cmd); if (!seen[cmd]++) print $0 }' |
|
||||
selected="$(fc -rl 1 | __fzf_exec_awk '{ cmd=$0; sub(/^[ \t]*[0-9]+\**[ \t]+/, "", cmd); if (!seen[cmd]++) print $0 }' |
|
||||
FZF_DEFAULT_OPTS=$(__fzf_defaults "" "-n2..,.. --scheme=history --bind=ctrl-r:toggle-sort --wrap-sign '\t↳ ' --highlight-line ${FZF_CTRL_R_OPTS-} --query=${(qqq)LBUFFER} +m") \
|
||||
FZF_DEFAULT_OPTS_FILE='' $(__fzfcmd))"
|
||||
fi
|
||||
local ret=$?
|
||||
if [ -n "$selected" ]; then
|
||||
if [[ $(awk '{print $1; exit}' <<< "$selected") =~ ^[1-9][0-9]* ]]; then
|
||||
if [[ $(__fzf_exec_awk '{print $1; exit}' <<< "$selected") =~ ^[1-9][0-9]* ]]; then
|
||||
zle vi-fetch-history -n $MATCH
|
||||
else # selected is a custom query, not from history
|
||||
LBUFFER="$selected"
|
||||
|
||||
Reference in New Issue
Block a user