Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support FZF custom completion API #41

Merged
merged 1 commit into from
Feb 28, 2020
Merged

Support FZF custom completion API #41

merged 1 commit into from
Feb 28, 2020

Conversation

doubleloop
Copy link
Contributor

@doubleloop doubleloop commented Feb 21, 2020

API explained here, handy way of defining custom completions for particular commands.
Copied some functions from fzf completions.zsh to allow not sourcing it.

fzf-tab.zsh Outdated
echo "fzf-tmux -d${FZF_TMUX_HEIGHT:-40%}" || echo "fzf"
}

_fzf_feed_fifo() (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you copy functions over, give them a different name. Otherwise, when these functions get modified in fzf, the behavior of fzf-tab, and (worse!) of plain fzf will depend on the order in which files are sourced. It would be quite bad if fzf-tab affects the behavior of plan fzf.

@Aloxaf
Copy link
Owner

Aloxaf commented Feb 24, 2020

Thanks for your contribution.

But fzf-tab should be able to work together with fzf's completions.zsh, and its API is experimental. What's the advantage of supporting it?

@doubleloop
Copy link
Contributor Author

But fzf-tab should be able to work together with fzf's completions.zsh

I will try to fix this

What's the advantage of supporting it

The ability to customize for particular commands is really cool. Actually It does not have to be fzf API, could be anything thet allow user to use zsh sources by default but provide convenient way to define custom behavior for for particular commands. Still, FZF mechanism for customization is quite convenient and easy to use and if user already defined some custom _fzf_complete_<cmd> functions, it could be a benefit if FZF-tab recognize and use them (there could be some env variable like FZF_TAB_USE_FZF_CUSTOM_COMPLETIONS) .

@romkatv
Copy link
Contributor

romkatv commented Feb 24, 2020

The ability to customize for particular commands is really cool.

Doesn't Zsh have this feature out of the box? compdef _pids foo will complete command foo using completion function _pids. Instead of _pids you can use your own completion function.

@doubleloop
Copy link
Contributor Author

Doesn't Zsh have this feature out of the box?

True. On the other hand, providing some framework/helper function like _fzf_complete out of the box make customizations much easier to write.

Consider for example:

BLUE='\033[0;34m'
RED='\033[0;31m'
NC='\033[0m'

_foo() {
    for i in {1..40}; do
        echo -e "${BLUE}foo${NC} completion$i"
    done
}

_bar() {
    # this is some slower command
    sleep 1
    for i in {40..80}; do
        echo -e "${RED}bar${NC} completion$i"
    done
}

_fzf_complete_foobar() {
    _fzf_complete "--multi --ansi -n 2" "$@" < <(
        _foo
        _bar
    )
}
_fzf_complete_foobar_post() { awk '{print $2}'; }

How to easily write custom compdef function which:

  1. is asynchronous (does not delay showing completions untill bar is finished)
  2. is easy to specify if --multi vs --no-multi should be used (rm vs cd)
  3. is easy to provide some coloring/icons
  4. specify which part of sorce line should be used for fuzzy search (-n flag)

I do not know zsh completion mechanism well, so after few minutes of reading some docs I started with something like:

_foobar() {
    completions=(${(f)"$(_foo)"})
    compadd $completions
    completions=(${(f)"$(_bar)"})
    compadd $completions
}
compdef _foobar foobar

From what I understand, using compdef mechanism it is hard to controll multi/no-multi and coloring, also completion is synchronous.

@romkatv
Copy link
Contributor

romkatv commented Feb 24, 2020

I see. Streaming completions would definitely be useful.

@doubleloop
Copy link
Contributor Author

But fzf-tab should be able to work together with fzf's completions.zsh

I will try to fix this

works together wit fzf completions now

To enable, set FZF_TAB_USE_FZF_CUSTOM_COMPLETIONS=1

@Aloxaf
Copy link
Owner

Aloxaf commented Feb 25, 2020

I will try to fix this

Sorry I didn't make myself clear.
I mean, if I can get the support of fzf's custom completion API by sourcing completion.zsh, what's the advantage of supporting it in fzf-tab itself.

@doubleloop
Copy link
Contributor Author

doubleloop commented Feb 25, 2020

if I can get the support of fzf's custom completion API by sourcing completion.zsh, what's the advantage of supporting it in fzf-tab itself.

No need for separate completion trigger. Currently, when one define some custom completion, one has to explicitly use fzf trigger (**<tab>) to delegate it to completion.zsh while fzf-tab (<tab>) for everything else. One can change FZF_COMPLETION_TRIGGER or change the shortcut (described here), but still in result there are 2 separate triggers, which is (arguably) inconvenient. With this change one can use <tab>, so that if custom completion function is defined for particular command, it is used, otherwise fzf-tab completion is used. One still cen explicitly delegate to completion.zsh using FZF_COMPLETION_TRIGGER.

Edit:
The point of this change is not to support FZF api but to add any customization mechanism to fzf-tab. The FZF customization mechanism just seemed good enough to copy as is, but if we just change _fzf_complete function name and custom function naming convention, we will end up with fzf-tab own customization mechanism working analogous to fzf one.

@Aloxaf
Copy link
Owner

Aloxaf commented Feb 25, 2020

Sounds great. Please update README.md as well.

@doubleloop
Copy link
Contributor Author

doubleloop commented Feb 26, 2020

I cleaned up the PR and updated README.md.

After some thought, I decided that the best solution is not providing _fzf_complete helper function. Ability to hook custom functions is enough. How they will be used is up to user. Using _fzf_complete from completion.zsh is suggested in readme but if one do not want to source completion.zsh, one can define his own mechanism.

fzf-tab.zsh Outdated Show resolved Hide resolved
@Aloxaf Aloxaf merged commit 49702f7 into Aloxaf:master Feb 28, 2020
@@ -306,7 +308,24 @@ _fzf_tab_complete() {

zle -C _fzf_tab_complete complete-word _fzf_tab_complete

_fzf_tab_try_custom_completion() {
# do not steal fzf's completions
[[ $LBUFFER =~ ${(q)FZF_COMPLETION_TRIGGER-'**'}$ ]] && return 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I set FZF_COMPLETION_TRIGGER="" and bind fzf-completion to a separate key (Ctrl-T). This way I can use TAB for normal completions and Ctrl-T to complete file arguments with fzf. I find that pressing Ctrl-T to complete file arguments with fzf is more convenient than pressing *-*-TAB.

With this setup _fzf_tab_try_custom_completion always bails out early.

Does the check on the first line of _fzf_tab_try_custom_completion presuppose that _fzf_tab_orig_widget is fzf-completion (or some other widget that respects FZF_COMPLETION_TRIGGER)? I set _fzf_tab_orig_widget to expand-or-complete, so this check doesn't make much sense.

FWIW, I don't know what's the right thing to do here. I'm unsure how exactly I want completions to work. Just wanted to share that the current code is a bit odd and likely incorrect.

Copy link
Contributor Author

@doubleloop doubleloop Feb 28, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just checked for this configuration:

export FZF_COMPLETION_TRIGGER=""
bindkey '^T' fzf-completion
bindkey '^I' fzf-tab-complete

export fzf_default_completion=expand-or-complete
export _fzf_tab_orig_widget=expand-or-complete

If no custom completion function is defined, TAB triggers fzf-tab, ctrl-t triggers fzf.
If some custom completion function is defined, both TAB and ctrl-t triggers it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean it return 1 on the first if?

Yes.

If some custom completion function is defined, both TAB and ctrl-t triggers it.

Are you sure TAB triggers it? It doesn't for me. When I press TAB, _fzf_tab_try_custom_completion returns on the first line, so _fzf_complete_* is never called. Can you verify that _fzf_tab_orig_widget is indeed expand-or-complete in your setup?

Aloxaf added a commit that referenced this pull request Feb 28, 2020
@doubleloop doubleloop deleted the custom_completions branch November 21, 2021 23:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants