小部件只能在ZLE处于活动状态时调用。

24

我已经快一个月处理这个问题了,感到很沮丧。非常感谢任何帮助。

我正在尝试为我的takenote命令编写一个小部件。该小部件的目的是将~/notes文件夹中的所有markdown文件提供给fzf,以便用户可以选择其中一个并开始编辑它。 当用户输入takenote并按下<tab>键时,我希望小部件运行。

这是_takenote.zsh小部件定义:

#compdef takenote
local file=$( find -L "$HOME/notes/" -print 2> /dev/null | fzf-tmux +m )
zle reset-prompt
compadd $file
return 1

很不幸,由于zle reset-prompt的存在,上述代码无法正常工作,如果我将其删除,结果会变成这样:

选择前

在选择文件后,结果会变成:

选择后

正如您所看到的那样,这将破坏提示符和命令本身。 在调用compadd之前,我需要执行zle reset-prompt,但这只能在我将函数绑定到按键时才起作用,否则我将会得到以下错误:

ZLE处于非活动状态时无法调用小部件


2
到目前为止有什么进展吗?如果你成功了,我会使用这个解决方案。 - animaacija
不好意思!已经过了很长时间,我还是没有找到解决方案。但我真的很想知道答案。也许你可以给这个问题点个赞? - ExistMe
@animaacija,我尝试了一下,但似乎需要更多的努力。我可以给你一个指针,可能会有所帮助。这是为 vim 做的,你可能能够适应它到你的环境中。请参见 https://github.com/junegunn/fzf/issues/227 - Tarun Lalwani
@ExistMe,又是第三个赏金任务了:-)。你有机会看一下我发布的链接吗? - Tarun Lalwani
@tarun-lalwani 谢谢,我花了一天时间尝试你建议的链接,但没有成功 :) 这有多复杂啊,我感觉自己对 zle 和它的状态一无所知。我认为这主要是一个 zle widget 的问题,而不是 fzf - ExistMe
3个回答

6
我最终找到了解决这个问题的方法。虽然我对这种策略并不满意,因为它不是完全包含在小部件本身中,但它确实有效。解决方案涉及在调用fzf-completion后捕获它并调用zle reset-prompt
要注册陷阱,请将以下代码段添加到您的.zshrc文件中(请参见 Zsh菜单完成会导致zle重置提示后出现问题):
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
}

_takenote小部件:

#compdef takenote
local file=$( find -L "$HOME/notes/" -print 2> /dev/null | fzf-tmux +m )
compadd $file
return 0

附注:我仍然希望将陷阱移动到小部件内部,并避免在初始化脚本(.zshrc)中注册它


4
我尝试使用 bindkey 命令来让 vim 打开 fzf 选中的文件时,遇到了相同的错误。结果发现我需要在 function1 中打开文件,然后有一个 function2 调用 function1,最后调用 reset-prompt 命令来避免出现“widgets can only be called when ZLE is active”的错误提示。像你说的那样,这真的很 令人沮丧,我花了近一天的时间才找到解决办法!
示例代码:
## 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


这个问题现在已经很老了,但我仍然对更好的解决方案感兴趣。据我所记,当使用bindkey绑定到一个键组合时,只需要使用zle reset-prompt就足够了。真正的痛点是当你想要将其与标签补全一起使用时。我找不到任何替代方法,只能使用TRAPALRM方法。 - ExistMe

3

太好了!你终于在4年后找到了正确的答案 :) 非常感谢你的分享和提及来源。干杯! - ExistMe
1
我只是发布了这条消息,因为两年前你曾经评论说你仍然对更好的解决方案感兴趣;) 也是,确实花了一些时间;) - zrf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接