junegunn / fzf

:cherry_blossom: A command-line fuzzy finder
https://junegunn.github.io/fzf/
MIT License
62.23k stars 2.35k forks source link

Bash Completion Wrapper #2473

Open neerajbadlani opened 3 years ago

neerajbadlani commented 3 years ago

Info

Problem / Steps to reproduce

I have lots of git aliases which i find sometimes hard to remember . I do have git bash autocompletion , but i'd like to integrate it with fzf .

Checked : https://github.com/junegunn/fzf#custom-fuzzy-completion

And wrote something similar : image

But it doesnt seem to work . Any pointers ?

Thanks

rayiik commented 3 years ago

are you just looking to have a list of your aliases printed select one and insert it to the command line?

neerajbadlani commented 3 years ago

So using git bash completion , when i do this :

[master:.configfiles] git <TAB><TAB>
Display all 183 possibilities? (y or n)

Above 183 are the aliases configured on my system . Instead of just putting them on screen , I want aliases to be available using fzf .

Lets say I now select log subcommand , I want options printed by bash completion to be available using fzf .

[master:.configfiles] git log <TAB> <TAB>
FETCH_HEAD      HEAD            ORIG_HEAD       master          origin/HEAD     origin/master
rayiik commented 3 years ago

Have you added it to bash completion ? End of the script should contain something like

Complete -F _custom_completion -o bashdefault -o default _custom_completion

However since your completeing the second word you need to modify your git completion file or import your function to it or is there no space after git

neerajbadlani commented 3 years ago

Yeah i have it . [ -n "$BASH" ] && complete -F _fzf_complete_doge -o default -o bashdefault doge

rayiik commented 3 years ago

which would work if you were calling completion for git-alias [tab] but since your calling git [alias] [tab] the definition is actually found in the git completion and defined as the first parameter the _fzf_complete_doge would only effect the if the first word matches but because we are matching the second word you need to modify the git completion instead of defining your own and insert that function withing the original git completion. some lines ton consider from the git completion file

 #If you use complex aliases of form '!f() { ... }; f', you can use the null
# command ':' as the first command in the function body to declare the desired
# completion style.  For example '!f() { : git commit ; ... }; f' will
# tell the completion to use commit completion.  This also works with aliases
# of form "!sh -c '...'".  For example, "!sh -c ': git commit ; ... '".

however theres 3500 lines of code in the git completion file and at least 4 functions that would need to be modified. theres an easier way to achieve what your looking for using READLINE_LINE create a file with a list of your alias's

cat ~/.bash_alias | sed 's/alias//' | awk -F'=' '{print $1}' >> ~/aliaslist

this right here should do it for you

#!/bin/bash
_fline () {
echo "$(tput setaf 2) $(printf "%${FZF_PREVIEW_COLUMNS}s" " "  | tr " " "-") $(tput sgr0)"
unset
}
_varset () {
    _rlvar="$READLINE_LINE"
}
_fzcom () {
fzf  \
--ansi \
--preview="{ echo ${_rlvar} {+} 2>/dev/null; fline; \
tput sgr0; cat $HOME/alias-list | \
 rg  --no-filename \
-e {+} -e {} 2>/dev/null; } " \
--preview-window=right:65:wrap \
--info=default \
--bind='ctrl-a:preview-page-up' \
--bind='ctrl-s:preview-page-down' \
--bind='ctrl-u:half-page-up+refresh-preview' \
--bind='ctrl-d:half-page-down+refresh-preview' \
--bind='alt-u:page-up+refresh-preview' \
--bind='alt-h:backward-char+refresh-preview' \
--bind='alt-l:forward-char+refresh-preview' \
--bind='alt-d:page-down+refresh-preview' \
--bind='alt-2:toggle-search+replace-query' \
--bind="f9:preview:rg '({q}|{})' $HOME/alias-list --passthru"
}
alias-complete () {
_varset "$@"
[[ ! -f "$HOME"/alias-list ]] && \
cat "$HOME"/.bash_aliases | awk '/^alias/{print}' | sed 's/alias//;/^$/d;s/^\s//;/^\#/d' | awk -F'=' '{print $1}' >> "$HOME"/.bash_aliases
_choice="$(cat "$HOME"/alias-list | _fzcom)"
READLINE_LINE="$READLINE_LINE $(tr '\n' ' ' <<<"${_choice}")"
if [[ -n "$READLINE_LINE" ]]; then
  printf '%s '"$READLINE_LINE" | \
    tr \\n \\s;
   READLINE_POINT=0x7fffffff; else
   READLINE_POINT=0x7fffffff
fi
}
bind -m emacs-standard '"\er": redraw-current-line' 
bind -m vi-command '"\C-z": emacs-editing-mode'
bind -m vi-insert '"\C-z": emacs-editing-mode' 
bind -m emacs-standard '"\C-z": vi-editing-mode' 
bind -m emacs -x '"\C-g":alias-complete'
bind -m vi-insert -x '"\C-g":alias-complete'

** changed preview command from "$HOME"/alias-list to "$HOME"/.bash_aliases that way in your preview you can view the full alias as rg will match your currently highlighted line (or alias) that way you can see flags and whatnot

rayiik commented 3 years ago

control-g will pull a list of your aliases in fzf and let you paste them after the command save and source is all

neerajbadlani commented 3 years ago

Thanks , But above seems difficult to follow .

However I found exactly what I am looking for in https://asciinema.org/a/293849 . This one supports zsh . There is one for bash too : https://github.com/lincheney/fzf-tab-completion/issues/38 , however its not working at the moment .

rayiik commented 3 years ago

hey sorry i should have explained i was just throwing together something as a proof of concept. this is not fzf completion this essentially a fzf-snippit manager (that happens to take your ~/.bash_alias strip any line that doesn't start with 'alias' and strips everything after = and copies it to a new file called alias-list) the function then saves the current line into a variable populates the list with your alias-list you select an option then it redraws the line with "original line" "$selection" without hitting return so you can supply values after the binding can be altered to anything, and there is some stuff in there that isn't necessary (i stole parts from my other scripts to throw it together).
tput are terminal color commands fline is just a function that prints a line of --------- that equal the width of your preview window (useful for separating multiple data streams) so the first line of the preview window was the original command you were typing when you executed the binding + your line selection (so you can get a visual of what your building) then a line then your .bash_alias file. so main function we test if alias-list exists if not it creates it. i can add another test to see if it contains the same number of lines (alias wise) as .bash_alias to verify all aliases are there. Then we define the choice which invokes fzf we set READLINE_LINE variable to its original value with the addition of our choice and strip the new line character from it so it doesn't execute