I have been dealing with this problem for almost a month now, and I feel frustrated, Any help would be greatly appreciated.
I am trying to write a widget for my takenote
command. The purpose of the widget is to feed all the markdown files in ~/notes
folder into fzf
so that the user can select one of them and starts editing it. After the user types takenote
and presses <tab>
I expect the widget to run.
Here is the _takenote.zsh
widget definition:
#compdef takenote
local file=$( find -L "$HOME/notes/" -print 2> /dev/null | fzf-tmux +m )
zle reset-prompt
compadd $file
return 1
Unfortunately, the above code doesn't work because of zle reset-prompt
, if I remove it then the result would be like this:
And after selecting the file it would turn into:
Which as you see will corrupt the prompt and the command itself. It appears to me that what I need to do is do a zle reset-prompt
before calling compadd
but this can only work when I bind the function to a key otherwise, I will get the following error:
widgets can only be called when ZLE is active
I finally found a workaround for the issue. Although I am not satisfied with the strategy since it is not self contained in the widget itself, but it works. The solution involves trapping fzf-completion
after it is invoked and calling zle reset-prompt
.
For registering the trap add the following snippet to your .zshrc
file (see Zsh menu completion causes problems after zle reset-prompt ):
TMOUT=1
TRAPALRM() {
if [[ "$WIDGET" =~ ^(complete-word|fzf-completion)$ ]]; then
# limit the reset-prompt functionality to the `takenote` script
if [[ "$LBUFFER" == "takenote "* ]]; then
zle reset-prompt
fi
fi
}
The _takenote
widget:
#compdef takenote
local file=$( find -L "$HOME/notes/" -print 2> /dev/null | fzf-tmux +m )
compadd $file
return 0
ps: I would still love to move the trap inside the widget, and avoid registering it in the init script ( .zshrc
)
I was getting the same error when trying to use bindkey
for a widget to use vim to open the fzf
selected file. Turns out I have to open the file in function1
and then have a function2
calling function1 and then reset-prompt
to avoid this widgets can only be called when ZLE is active
error. Like you said, it is really frustrating and took me almost a day to figure out!
Example code:
## use rg to get file list
export FZF_DEFAULT_COMMAND='rg --files --hidden'
## file open (function1)
__my-fo() (
setopt localoptions pipefail no_aliases 2> /dev/null
local file=$(eval "${FZF_DEFAULT_COMMAND}" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse $FZF_DEFAULT_OPTS --preview 'bat --color=always --line-range :500 {}'" $(__fzfcmd) -m "$@" | while read item; do
echo -n "${(q)item}"
done)
local ret=$?
if [[ -n $file ]]; then
$EDITOR $file
fi
return $ret
)
## define zsh widget(function2)
__my-fo-widget(){
__my-fo
local ret=$?
zle reset-prompt
return $ret
}
zle -N __my-fo-widget
bindkey ^p __my-fo-widget
After two days, I finally managed to find a hint on how to achieve it thanks to the excellent fzf-tab-completion project:
https://github.com/lincheney/fzf-tab-completion/blob/master/zsh/fzf-zsh-completion.sh#L102
So actually, all that you need to do is:
#compdef takenote
local file=$( find -L "$HOME/notes/" -print 2> /dev/null | fzf-tmux +m )
compadd $file
TRAPEXIT() {
zle reset-prompt
}
return 0
And it finally works. Cheers!
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.