jhawthorn/fzy

[UX] Show in readme how to replace bash history search with fzy

SoftwareApe opened this issue · 6 comments

The killer feature that convinced me to use fzf was searching for files (shown in readme), but also ctrl+R bash history search and git branch search.

https://github.com/junegunn/fzf#key-bindings-for-command-line

It would be nice if fzy could provide similar functionality. Or at least point out how to add these in the readme. This might also attract more people.

For fzf you only need this in your ~/.bashrc

[ -f ~/.fzf.bash ] && source ~/.fzf.bash
casr commented

There are some examples in the wiki but they're for ZSH. Perhaps as a starting point, you could contribute to the wiki first by adapting how fzf binds to Bash?

https://github.com/jhawthorn/fzy/wiki#zsh-insert-fuzzy-found-paths-directly-into-the-shell-command-line

So I found this https://unix.stackexchange.com/a/523619.

If I add

# Replicate fuzzy file finding
alias fzf='find . -type f | fzy'
# Replicate Ctrl+r history search
alias fzhist="HISTTIMEFORMAT= history | cut -f4- -d' ' | fzy"
bind '"\C-r":" \C-e\C-u\C-y\ey\C-u$(fzhist)\e\C-e\er\e^"'

I can get a history search going, but the sorting is "off". We'd need to somehow not only sort by distance of the match but also recency, not sure how to do this. I think that's what they do with the fzf_history command, which I didn't have the time to check.

casr commented

I think fzy algorithm is agnostic to input sort order (i.e. recent) unlike fzf. It gives its ordering based on how each match scores.

Hm, ok the usefulness is then quite limited for history search, since recency is kind of important here. Usually you want the command that happened 10 or 100 calls ago much more likely than 1000 or 10000 calls ago.

arkq commented

Recently I've also created a simple snippet for Bash history reverse search (lines shown in a reversed order with duplicates removed). Simply add it to .bashrc:

bind -x '"\C-r": __history_fuzzy_search'
__history_fuzzy_search() {
	READLINE_LINE=$(
		HISTTIMEFORMAT=
		history | sort -rn \
			| awk '{ $1="" ; if (!x[$0]++) print substr($0,2) }' \
			| fzy -q "$READLINE_LINE")
	READLINE_POINT=0x7FFFFFFF
}

Trying to do a simple launcher that would use data from '.bash_history' and 'compgen -c', example

unset arr;arr=();arr+=($( { tail -1000 ~/.bash_history & compgen -c } | fzy )) && "${arr[@]}"

but if the match is not found it will force me to select one anyway, any clues how to work around that? (basically I'd like to preserve user input when no matches are found. )
Can I say: If score is lower than 2, then just passthrough user input?

Example recording of unwanted behavior:
https://asciinema.org/a/t2qi5Vv8580eTBRSHoKZioJyF