svent/sift

Exit code 1 and no results when run without `.` path indication in Neovim

Closed this issue · 4 comments

Hi,

I noticed a somewhat weird problem when running sift in Neovim. Initially I thought it's connected with vim-grepper so I opened an issue there.

Marco Hinz noticed that running sift in Neovim doesn't work even without vim-grepper when there's no search path indication.

Basically: :!sift -n foo yields shell returned 1 and no results. :!sift -n foo . works just fine. There is no problem with 'vanilla' Vim.

I tracked the issue to a4bc2b9 - sift built at this point yields the aforementioned error, e109c32 works ok.

My sift binaries were built with go version go1.5.1 linux/amd64 (git checkout COMMIT_ID; rm ./sift; go build).

mhinz commented

Neovim relies on libuv for running processes. Due to libuv's asynchronous nature, processes run "in the background" and after exiting their output can be read from a named pipe. And that's the "issue" in this case: https://github.com/svent/sift/blob/master/sift.go#L644-L648

For quick testing put the following into /tmp/test.go, switch to /tmp, and execute :!go run test.go in Vim and Neovim. The output won't be the same.

package main

import (
    "fmt"
    "os"
    "golang.org/x/crypto/ssh/terminal"
)

func main() {
    if terminal.IsTerminal(int(os.Stdin.Fd())) {
        fmt.Println("terminal")
    } else {
        fmt.Println("pipe")
    }
}

It can't be fixed in Neovim since it's because of libuv. Then again I'm not sure if there's a way to fix this in sift. Maybe people should just explicitly append the . on their own in this case. For those who don't, the behaviour will be confusing, though.

svent commented

@mhinz Thanks for the analysis!

While this somehow worked with an earlier version of sift, I still consider the improved terminal detection correct. Unfortunately, I also do not see a simple fix for this and somehow sift works as expected in this scenario.

I would expect that other grep alternatives have similar problems with this - although "terminal detection" is an intricate problem and they might handle it somehow different.

As I do not want to change existing behavior and other uses cases (CLI) are more important I fear this issue will not get solved at the moment.

mhinz commented

Okay, I fixed this in the plugin. Here a short summary of how to use Neovim:

:! and system() both use pipes. This is a result of Neovim's new client/server architecture where every UI is basically just a plugin that can be attached to an instance. It's a means to get consistent output across all attached UIs.

It prevents using interactive programs, though. E.g. git add -p. But for those cases there's another new Neovim feature: a real (opposed to what Emacs provides) built in terminal emulator that can be called with :term <optional command>. :te sift foo works as expected.

:term is basically built atop of jobstart() which my plugin uses. What I didn't know so far, you can simply tell it to allocate a pseudo terminal that the process connects to. Everything's working fine afterwards!

I still consider the improved terminal detection correct

I agree. :)

This issue can be closed.

svent commented

Thanks for your efforts - great to hear that you found a solution to this problem.