Custom sort weights
Closed this issue · 3 comments
- I have read through the manual page (
man fzf
) - I have the latest version of fzf
- I have searched through the existing issues
Info
- OS
- Linux
- Mac OS X
- Windows
- Etc.
- Shell
- bash
- zsh
- fish
Problem
I have a fzf
script that searches through config files in ~/.config
and /etc
. Most of the time I want something from .config
, but I want to keep etc in there for other cases. So what I'd like to do is some way to assign a weight by matching a substring so the config files are preferred - currently it matches awkward paths in /etc far to often. That could also be useful for cases such as #78.
An idea would be something like fd . -t f --full-path ~/.config /etc | fzf --weight /etc=-5
- which would reduce the weight of paths matching that string (the number is arbitrary, I haven't had a look at the algorithms), or even having a simple config file that can be specified to support more complicated cases.
Making the matching/sorting algorithm configurable is not something I want to do. You might want to preprocess the input so that the more important items are listed first and start fzf with --tiebreak=index
.
In case someone else is interested, here my solution - it is a shell function for config editing, and it caches the last 9 selecions so they are immediately up for selection:
conf() {
conf_cache="$XDG_CACHE_HOME/conf"
conf_tmp="${conf_cache}.tmp"
conf_extra="$XDG_CONFIG_HOME/conf-extra"
touch "$conf_cache"
# | xargs file | grep text | cut -d':' -f1 # this would filter out non-text files, but it's ridiculously slow
result="$({ cat $conf_cache $conf_extra; fd --type file --hidden --maxdepth 1 . ~; fd --type file . --full-path $XDG_CONFIG_HOME /etc } | awk '!a[$0]++' | fzf -1 -0 --tiebreak=end,length --preview 'bat --color=always --style=numbers --line-range :200 {}')"
test "$result" && ((echo "$result" | cat - "$conf_cache" | head -9 >"$conf_tmp" && mv "$conf_tmp" "$conf_cache") & $EDITOR "$result")
}
@xerus2000 I further streamlined the code into a dash script:
#!/bin/dash
echo() {
printf -- "%s\n" "$*"
}
mru_count=30
if test -z "$context" ; then
echo "$0: You need to provide a context" >&2
exit 1
fi
conf_dir="$HOME/.cache/fzf_mru"
mkdir -p "$conf_dir"
conf_cache="$conf_dir/${context}"
touch "$conf_cache"
conf_tmp="${conf_cache}.tmp"
# Removing duplicate lines: seen is an associative-array that Awk will pass every line of the file to. If a line isn't in the array then seen[$0] will evaluate to false. (The name 'seen' does not matter.)
result="$(cat "$conf_cache" - | awk '!seen[$0]++' | fzf --tiebreak=index "$@")" || return $?
if test -n "$result" ; then
echo "$result" | cat - "$conf_cache" | awk '!seen[$0]++' | head -n "$mru_count" > "$conf_tmp" && mv "$conf_tmp" "$conf_cache"
echo "$result"
else
return 1
fi
Usage:
cat choices | context=some_context fzf_mru.sh
The latest version of this script can be found here.