如何在 zsh 中使用 fzf 获得模糊 xdg-open?

如何在 zsh 中使用 fzf 获得模糊 xdg-open?

问题

我一直在尝试使用弗兹夫绑定快捷方式(最好是Ctrl+ o)以交互方式搜索文件并将其通过管道传输到xdg-openzsh 中。许多快捷方式已经成为fzf实用程序的一部分,只要您源文件位于fzf/shell/键绑定.zsh。在那里,您将找到用于绑定Ctrl+r模糊搜索命令历史记录和Ctrl+t模糊完成当前命令行的片段。这是 fzf 源代码中第一个快捷方式的样子:

# CTRL-R - Paste the selected command from history into the command line
fzf-history-widget() {
  local selected num
  setopt localoptions noglobsubst noposixbuiltins pipefail no_aliases 2> /dev/null
  selected=( $(fc -rl 1 | perl -ne 'print if !$seen{(/^\s*[0-9]+\**\s+(.*)/, $1)}++' |
    FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} $FZF_DEFAULT_OPTS -n2..,.. --tiebreak=index --bind=ctrl-r:toggle-sort,ctrl-z:ignore $FZF_CTRL_R_OPTS --query=${(qqq)LBUFFER} +m" $(__fzfcmd)) )
  local ret=$?
  if [ -n "$selected" ]; then
    num=$selected[1]
    if [ -n "$num" ]; then
      zle vi-fetch-history -n $num
    fi
  fi
  zle reset-prompt
  return $ret
}
zle     -N   fzf-history-widget
bindkey '^R' fzf-history-widget

当然,它的行为与我想要的行为有点不同,因为它将所选结果粘贴到命令行,而不是直接通过管道将其传递到命令。不过,下面的 bash 脚本恰恰具有我所期望的行为,并且运行它比我自己在解释它方面做得更好。

bind -x '"\C-o": file="$(fzf --height 40% --reverse)" && [ -f "$file" ] && xdg-open "$file"'

我也发现了这个鱼功能具有相同的行为,但 Fish 的语法与 zsh 和 bash 等 POSIX 兼容 shell 有很大不同,所以我不知道这有多大帮助。

那么,有谁知道将Ctrl+绑定o到交互式 fzf 搜索,并将其结果直接通过管道传输到xdg-openzsh 中?

提前致谢!


答案

这是我根据以下内容编写的工作脚本堆栈溢出答案。

fuzzy-xdg-open() {
  local output
  output=$(fzf --height 40% --reverse </dev/tty) && xdg-open ${(q-)output}
  zle reset-prompt
}

zle -N fuzzy-xdg-open
bindkey '^o' fuzzy-xdg-open

答案1

在 中zsh,您将按键或按键组合(使用bindkey)绑定到小部件,在行编辑器中执行特殊操作的小部件。

您可以使用内置函数定义自定义小部件zle

在该自定义小部件中,您可以运行任意命令,但您可能还需要考虑如何处理数字参数。

例如,如果用户输入Alt+ 3 Ctrl+ ,您是否要按照大多数小部件的惯例运行该命令三次?o

您还需要考虑是否应该在运行命令后重新绘制行编辑器缓冲区(到目前为止输入的内容)或提示符,或者在运行命令之前将其隐藏起来,以防您运行的命令碰巧向终端写入内容。此外,命令的退出状态是否应该确定小部件是否成功(例如导致视觉或听觉通知)。

如果您在小部件中运行的工具需要从用户获取输入,您还需要在 ZLE 重定向时恢复 tty 上的标准输入,/dev/null以防止它们扰乱行编辑器中的正常输入流。您需要确保您的命令使终端处于与它发现时相同的状态(这应该是 的情况fzf)。

例如,这可能是:

my-open-widget() {
  zle -I # invalidate current zle display
  local file ret=0
  repeat ${NUMERIC-1} {
    file="$(fzf --height 40% --reverse)" &&
      [ -f "$file" ] &&
      xdg-open "$file" ||
      ret=$?
  } < /dev/tty
  return $ret
}

zle -N my-open-widget
bindkey '^o' my-open-widget

要根据请求多次运行代码并在失败时返回失败,请预先使显示无效以确保该代码输出的内容(如果有)不会扰乱提示。

或者,您可能希望在一个实例失败时立即中止(替换|| ret=$?|| return)。或者,如果您知道代码不会弄乱显示并且更一般地不会与 tty 交互,请跳过zle -I.或者您可以忽略数字参数并无条件运行代码一次且仅一次,因此最终,它可以像将代码放入该小部件函数的主体中一样简单。

答案2

这种键绑定在原版中不能直接实现。但是,如果您安装插件zsh-edit,然后您可以使用以下内容:

bind '^O' 'file="$(fzf --height 40% --reverse)" && [ -f "$file" ] && xdg-open "$file"'

答案3

#!/bin/bash
xdg-open "$(rg --no-messages --files ~/Music ~/Series ~/Films ~/Documents ~/pdf \
    ~/Dropbox/calibre2 ~/Downloads \
    -g "!{*.srt,*.rar,*.txt,*.zip,*.nfo}" | rofi -threads 0 \
    -theme-str "#window { width: 900;}" \
    -dmenu -sort -sorting-method fzf -i -p "find")"

不完全相同,但我发现这个脚本组合 xdg-open + rofi 对于打开文件很有用。 (没有 zsh 依赖)。

来源:https://www.reddit.com/r/i3wm/comments/c17m5e/launcher_to_open_files_with_xdgopen_using_fzf/

相关内容