Вызов fzf из nim не показывает fzfs TUI

Я пытаюсь перенести небольшой скрипт на python в nim. Ядро - это вызов fzf:

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

Насколько я понимаю фзф открытый /dev/tty чтобы взаимодействовать с пользователем и использует stdin/stdout для связи с вызывающей его программой. Соответствующий код NIM:

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

Но в моей версии NIM FZF TUI не появляется. Но ввод в терминал читается, потому что на основании моего ввода выбран правильный пункт.

Я понятия не имею, почему это может иметь место. Я думал, может быть, Ним создает PTY с startProcess но /proc/sys/kernel/pty/nr не увеличивается, так что я думаю, что это не так. Я попытался скомпилировать с -d:useFork потому что.. ну не знаю, почему это должно это исправить, и это не так. Насколько я понимаю, fzf/terminal/tty на самом деле не должно быть чего-то такого, что nim мог бы сделать, чтобы fzf не мог писать в /dev/tty, Или, может быть, python делает что-то, о чем я не знаю, что fzf вызывает его TUI?

Поэтому мой вопрос заключается в том, как убедить fzf показать свой TUI из nim (и почему / как он этого не делает).

1 ответ

Решение

В качестве правильного ответа я нашел вариант poParentStreams в osproc модуль. Его можно использовать для запуска 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 указал в комментариях, что fzf открывает /dev/tty чтобы показать TUI, не нарушая поток stdin / stdout. Я не совсем уверен, почему это не работает в 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")
Другие вопросы по тегам