Get the process output from an interactive terminal job - aka, modern system()


Some background. Skip to the end if you’d rather cut to the chase.

I am trying to integrate fzy with neovim. Fzy is a command line fuzzy finder that can be integrated with editors. The project provides some vimscript to do so.

function! FzyCommand(choice_command, vim_command)
    let output = system(a:choice_command . " | fzy ")
  catch /Vim:Interrupt/
    " Swallow errors from ^C, allow redraw! below
  if v:shell_error == 0 && !empty(output)
    exec a:vim_command . ' ' . output

nnoremap <leader>e :call FzyCommand("find . -type f", ":e")<cr>
nnoremap <leader>v :call FzyCommand("find . -type f", ":vs")<cr>
nnoremap <leader>s :call FzyCommand("find . -type f", ":sp")<cr>

However, this approach uses system(), which in neovim is no longer suitable for interactive commands, by design.

I thought, no problem, I’ll just use termopen() to run fzy, which works great, but I’m struggling with finding a reliable way to capture the command’s final output. Ideally, I’d want to store the output - the selected file - in a variable, similar to how the snippet does, above.

Is there a function or event I’m missing? I tried on_exit, but that just gives me job_id and exit status, not the output itself. It feels like there’s something fundamental about terminal control I don’t understand.

Thanks so much!

EDIT I guess really what |'m asking is: how do I open a terminal running a commend, then store stdout for that command in a Neovim variable?

I figured it out! Found this person’s dotfiles implementation of something similar: shell.lua « fzy « lua « nvim « config - dotfiles - My *nix dotfiles

Their solution is to use on_exit and save the output to a temporary file using vim.fn.tempname(). There might be a better solution than this, but this works better than piping the output of fzy to nvr.