Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions lib/-ftb-generate-complist
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,9 @@ fi

(( same_word )) && tcandidates[2,-1]=()

# sort and remove sort group or other index
# sort and remove the duplicate group index before the displayed description.
# Keep the leading index so group reloads do not have to use presentation colors
# as group identity. The first field is hidden by fzf's --nth setting.
zstyle -T ":completion:$_ftb_curcontext" sort
if (( $? != 1 )); then
if (( colorful )); then
Expand All @@ -99,7 +101,15 @@ if (( $? != 1 )); then
tcandidates=("${(@o)tcandidates}")
fi
fi
typeset -gUa _ftb_complist=("${(@)tcandidates//[0-9]#$bs}")
local candidate group_id
local -a indexed_candidates
for candidate in "${(@)tcandidates}"; do
group_id=${candidate%%$bs*}
candidate=${candidate//[0-9]#$bs}
[[ $group_id == <-> ]] && candidate=$group_id$bs$candidate
indexed_candidates+=$candidate
done
typeset -gUa _ftb_complist=("${(@)indexed_candidates}")

# hide needless group
if (( $#_ftb_groups )); then
Expand Down
51 changes: 30 additions & 21 deletions lib/ftb-switch-group
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,30 @@ local pid=$1 header_lines=$2 active_group_style=$3 tmp_dir=$4 offset=$5

# read completion list
local -a list=(${(f)mapfile[$tmp_dir/completions.$pid]})
local -a groups=(${(f)mapfile[$tmp_dir/groups.$pid]})
local bs=$'\b'

# --- group marker detection (fzf-tab groups) ---------------------------------
# When groups exist, fzf-tab prefixes each entry with a group SGR like $'\e[94m'.
# When no groups exist (often file lists), entries may start with $'\e[0m'
# (reset for LS_COLORS). Treat that as "no groups".
local -Ua group_sgr_prefixes
# Each grouped entry starts with its numeric group id and a backspace. This
# field is hidden by fzf, but remains stable when group colors are identical.
local -Ua group_ids
if (( $#list > 10000 && $+commands[grep] )); then
group_sgr_prefixes=(${(f)"$(print -l -- ${list:$header_lines} | command grep -a -o $'^\x1b\\[[0-9;]*m')"})
group_ids=(${(f)"$(print -l -- ${list:$header_lines} | command grep -a -o $'^[0-9][0-9]*\b')"})
group_ids=("${(@)group_ids%$bs}")
else
group_sgr_prefixes=(${(M)${list:$header_lines}#$'\x1b['[0-9;]#*m})
fi

# if the only marker is reset, there are no real groups
if (( $#group_sgr_prefixes == 1 )) && [[ $group_sgr_prefixes[1] == $'\e[0m' ]]; then
group_sgr_prefixes=()
local item
for item in "${(@)list:$header_lines}"; do
[[ $item == (#b)(<->)$bs* ]] && group_ids+=$match[1]
done
fi

# calculate and persist current group index
# the index starts from 2, because switching from "all" to "group 1" looks weird
local current=2
if (( $#group_sgr_prefixes > 0 )) && [[ -f $tmp_dir/current-group.$pid ]]; then
if (( $#group_ids > 0 )) && [[ -f $tmp_dir/current-group.$pid ]]; then
current=$(( $(<$tmp_dir/current-group.$pid) + offset ))
fi
(( current > $#group_sgr_prefixes )) && current=1
(( current == 0 )) && current=$#group_sgr_prefixes
(( current > $#group_ids )) && current=1
(( current == 0 )) && current=$#group_ids
echo $current > $tmp_dir/current-group.$pid

# configure style of active header
Expand All @@ -45,17 +44,27 @@ case $active_group_style in
(*) sgr_on=$'\x1b[1m'; sgr_off=$'\x1b[22m' ;; # fallback
esac

# The ANSI SGR code that marks every line in the currently selected group.
local current_prefix=$group_sgr_prefixes[current]
# The hidden marker on every line in the selected group, and its label.
local current_marker='' current_group=''
if (( $#group_ids )); then
current_marker=$group_ids[current]$bs
current_group=$groups[$group_ids[current]]
fi

# print headers
if (( header_lines != 0 )); then
# Apply style only to the group label (excluding trailing spaces), then disable it
print -l ${${(S)list[1,header_lines]/(#b)($current_prefix*)($'\x1b[00m')/${match[1]/%(#b)( #)/$sgr_off$match}$match[2]}/$current_prefix/$current_prefix$sgr_on}
# Apply style only to the exact group label, excluding its padding.
local header
for header in "${(@)list[1,header_lines]}"; do
if [[ -n $current_group && $current_group != __hide__* ]]; then
header=${header/(#b)($'\x1b['[0-9;]#m)(${(b)current_group})( #)($'\x1b[00m')/$match[1]$sgr_on$match[2]$sgr_off$match[3]$match[4]}
fi
print -r -- $header
done
fi

if (( $#list > 10000 && $+commands[grep] )); then
print -l -- ${list:$header_lines} | command grep -a -F -- "${group_sgr_prefixes[current]}"
print -l -- ${list:$header_lines} | command grep -a -- "^$current_marker"
else
print -l -- ${(M)${list:$header_lines}:#${group_sgr_prefixes[current]}*}
print -l -- ${(M)${list:$header_lines}:#${current_marker}*}
fi
64 changes: 63 additions & 1 deletion test/fzftab.ztst
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,69 @@
>C1:{package }
>C1:{openpgp-keys-gentoo-release}
>C1:{-MERGING-pnpm-bin}

() {
emulate -L zsh -o extended_glob
local bs=$'\b'
local _ftb_curcontext=identical-colors
local -Ua _ftb_groups=('group one' 'group two')
local -a _ftb_compcap=(
$'alpha\2<\x00>\x00group\x001\x00word\x00alpha'
$'beta\2<\x00>\x00group\x002\x00word\x00beta'
)
local -a _ftb_group_colors=($'\e[0m')
-ftb-zstyle() {
zstyle $1 ":fzf-tab:$_ftb_curcontext" ${@:2}
}
zstyle ':fzf-tab:identical-colors' group-colors $'\e[0m' $'\e[0m'
. $ZTST_srcdir/../lib/-ftb-generate-complist
zstyle -d ':fzf-tab:identical-colors' group-colors
local -a first_fields=("${(@0)_ftb_complist[1]}")
local -a second_fields=("${(@0)_ftb_complist[2]}")
[[ $first_fields[1] == 1${bs}* && $first_fields[2] == alpha ]] &&
[[ $second_fields[1] == 2${bs}* && $second_fields[2] == beta ]]
}
0:completion list retains hidden group identity with identical colors

() {
emulate -L zsh
local tmp_dir=$ZTST_tmp/identical-group-colors
local pid=$$
local bs=$'\b'
mkdir -p $tmp_dir
print -rl -- \
$'\e[0mgroup one \e[00m\e[0mgroup two\e[00m' \
1${bs}$'\e[0m·alpha\0alpha\0' \
2${bs}$'\e[0m·beta\0beta\0' \
> $tmp_dir/completions.$pid
print -rl -- 'group one' 'group two' > $tmp_dir/groups.$pid
local -a switched=("${(@f)$(
$commands[zsh] -f $ZTST_srcdir/../lib/ftb-switch-group $pid 1 bold $tmp_dir 0
)}")
(( $#switched == 2 )) &&
[[ $switched[1] == $'\e[0mgroup one \e[00m\e[0m\e[1mgroup two\e[22m\e[00m' ]] &&
[[ $switched[2] == 2${bs}$'\e[0m·beta\0beta\0' ]]
}
0:group switching uses hidden identity when colors are identical

() {
emulate -L zsh
local tmp_dir=$ZTST_tmp/ungrouped-reset-colors
local pid=$$
mkdir -p $tmp_dir
print -rl -- \
$'\e[0m·alpha\0alpha\0' \
$'\e[0m·beta\0beta\0' \
> $tmp_dir/completions.$pid
: > $tmp_dir/groups.$pid
local -a switched=("${(@f)$(
$commands[zsh] -f $ZTST_srcdir/../lib/ftb-switch-group $pid 0 none $tmp_dir 0
)}")
(( $#switched == 2 )) &&
[[ $switched[1] == $'\e[0m·alpha\0alpha\0' ]] &&
[[ $switched[2] == $'\e[0m·beta\0beta\0' ]]
}
0:group switching preserves an ungrouped reset-colored list
%clean

zmodload -ui zsh/zpty