【问题标题】:Calling fzf from nim doesn't show fzfs TUI从 nim 调用 fzf 不显示 fzfs TUI
【发布时间】:2018-08-20 14:24:01
【问题描述】:

我正在尝试将我的一个小型 python 脚本移植到 nim。核心是对 fzf 的调用:

fzf = subprocess.Popen(["fzf"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
stdout, stderr = fzf.communicate(some_data)

据我了解 fzf open /dev/tty 与用户进行交互并使用 stdin/stdout 与调用它的程序进行通信。对应的nim代码:

var p = startProcess(path_to_fzf)
var stream = p.inputStream()
stream.write(some_data)
stream.flush()

但在我的 nim 版本中,fzf TUI 没有出现。但是会读取终端的输入,因为根据我的输入选择了正确的项目。

我不知道为什么会这样。我想也许 nim 用startProcess 创建了一个 PTY,但/proc/sys/kernel/pty/nr 并没有增加,所以我认为情况并非如此。我尝试使用-d:useFork 进行编译,因为.. 不知道为什么要修复它,但它没有。据我了解,fzf/terminal/tty 不应该让 nim 真正阻止 fzf 写入/dev/tty。或者也许 python 做了一些我不知道的事情,触发 fzf 显示它的 TUI?

所以我的问题是如何说服 fzf 从 nim 显示其 TUI(以及为什么/如何还没有)。

【问题讨论】:

  • 那个python程序的第二行不是将sys.stdout设置为fzf进程吗?如果没有其他程序,很难说。基本上,TUI 所做的是分别从标准输入和标准输出(可能还有标准错误)读取和写入。当你将它作为一个进程运行时,这些只是 Nim 中的流。因此,为了让 TUI 显示,您必须将 fzf 的标准输出重定向到程序的标准输出,并允许它从标准输入获取输入。

标签: python tty nim-lang fzf


【解决方案1】:

作为正确答案,我在osproc 模块中找到了选项poParentStreams。可以像这样使用它来启动 TUI:

import osproc

let process = startProcess("htop", options = {poParentStreams, poUsePath})
let eCode = process.waitForExit()
if eCode == 0:
  echo "htop completed successfully"
else:
  echo "htop aborted with error code: " & $eCode

@syntonym 在 cmets 中指出 fzf 打开 /dev/tty 是为了在不中断 stdin/stdout 流程的情况下显示 TUI。我不完全确定为什么这在 Nim 中不起作用,但解决方案当然是将结果写入命名管道并从中读出,如下所示:

import osproc
import posix
import streams

discard mkfifo("/tmp/fzfoutput", 0o644)
let process = startProcess("echo \"hello\nworld\" | fzf > /tmp/fzfoutput", options = {poUsePath, poEvalCommand, poParentStreams})
var f: File
discard f.open("/tmp/fzfoutput")
echo "Output of fzf:" & f.readLine()
let eCode = process.waitForExit()
if eCode == 0:
  echo "fzf completed successfully"
else:
  echo "fzf aborted with error code: " & $eCode
discard execCmd("rm /tmp/fzfoutput")

【讨论】:

  • 通常程序读写 stdin/stdout 以与用户进行通信,但 fzf 使用了一个聪明的技巧:它打开始终是终端的 /dev/tty(而不是可能看不到的 stdin/stdout由用户,就像这里的情况一样)。这样 fzf 可以在管道中使用,例如find . -name '*.mp3' | fzf | xargs vlc。但我不知道为什么它不适用于我的 nim 代码,python 代码可以正常工作。
  • 更新了我的答案以展示如何实现这一目标。不完全确定为什么它在 Nim 中的工作方式与在 Python 中不同,但这应该可以。
  • 不知何故这不是我所希望的,但如果它有效的话。如果有人知道为什么“正常的 nim 版本”不起作用,我会等一两天,但如果没有人出现,我会接受你的回答。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多