garybernhardt / selecta

A fuzzy text selector for files and anything else you need to select. Use it from vim, from the command line, or anywhere you can run a shell command.
MIT License
1.34k stars 81 forks source link

fish-shell: selecta doesn't work in subshell #94

Open timbertson opened 9 years ago

timbertson commented 9 years ago

I haven't dug into this too hard yet, I will probably try and get strace on it if nobody knows why this isn't working:

$ echo -e '1\n2\n3' | selecta
# ui appears; I select "2"
2

$ set -x RESULT (echo -e '1\n2\n3' | selecta)
# nothing happens; next prompt immediately shown

# just to show that this is how you normally set something from a subshell in fish:
$ set -x RESULT (echo -e '1\n2\n3')
$ echo $RESULT
1 2 3

I'm guessing it's failing to get /dev/tty from within the subshell for some reason?

garybernhardt commented 9 years ago

That seems like a reasonable guess, though Selecta should print an error to stderr if it can't get a TTY.

rschmitt commented 9 years ago

Actually, here's the problem:

gsj@the-brick ~> set -x RESULT (cat .zshrc | hs)
gsj@the-brick ~> jobs
Job Group   State   Command
2   74396   stopped cat .zshrc | hs
rschmitt commented 9 years ago

No no no, HERE's the problem:

In fish, (foo) means $(foo) or foo.

Fish doesn't even have subshells, according to a quick google search. Mystery solved!

timbertson commented 9 years ago

I believe it's not the same as a bash subshell, but it's still a sub-pipeline:

$ set x (echo -e '1\n2\n3' | grep 2)
$ echo $x
2

Whatever you want to call it, I don't see why selecta shouldn't work in place of grep.

I think your jobs thought is much more likely to be the culprit. Not sure how that happens, though.

timbertson commented 9 years ago

Or, maybe I just shouldn't have called it a "subshell" in the issue - it's equivalent to $(...) in bash, in which selecta works fine.

rschmitt commented 9 years ago

My best guess is that selecta somehow starts up in a background process group, and it receives SIGTTIN or SIGTTOU when it tries to access the terminal.

timbertson commented 9 years ago

OK, I've straced it which may help a little. Doing a diff, it looks like it's to do with the stty process - but maybe that was already obvious.

Here are the strace logs from a subpipeline (inside brackets) vs a top-level pipeline (which works). Both are just from the execv on stty onwards:

https://gist.github.com/gfxmonk/57c7e37d61baf0c48c86

Looks a lot like stty just doesn't do anything, but I have no idea how it works, or why it might decide not to do its thing...

garybernhardt commented 8 years ago

That gist seems to have disappeared, @timbertson. However, it seems like stty must do something in fish; otherwise most tools with complex UIs would break. I haven't used fish myself and don't want to dive into a whole new shell to diagnose this, but I'm happy to provide a bit of support if someone else wants to look deeper.

timbertson commented 8 years ago

Apologies, looks like it moved to https://gist.github.com/timbertson/57c7e37d61baf0c48c86 when I renamed myself on github (gists don't redirect)

timbertson commented 8 years ago

stty must do something in fish; otherwise most tools with complex UIs would break

I suspect that tools which (a) have complex terminal UIs and (b) are used inside a shell pipeline are rare - I can't think of any others aside from selecta that I'd use.

Maybe I'll ping the fish mailing list and see if anyone knows of ways in which sub-commands differ from top-level commands in terms of interacting with the TTY.

garybernhardt commented 8 years ago

I did a bit of googling and, as it turns out, fish just ignores stty entirely. stty is certainly a mess of legacy badness, but that seems a bit strong! See this thread where ridiculousfish says that stty "doesn't do anything in fish". There's been no resolution there, so I guess it's still an open problem.

I assume that other interactive tools (vim, emacs, etc.) work properly because they use the underlying C functions, rather than stty.

timbertson commented 7 years ago

I happened to come across this again today with another program, and since I understand it more now, I thought I'd summarize here:

As mentioned in https://github.com/fish-shell/fish-shell/issues/1949, fish runs process substitutions in a background process group, which does cause selecta to receive SIGTTOU when it tries to control the terminal (fish isn't lying - fd 0 is a tty, you're just not allowed to mess with it). It's no fault of stty, using the underlying system calls has the same issue.

A workaround is to run selecta more awkwardly so that it's a foreground process - e.g:

echo -e '1\n2\n3' | selecta | read --local result; echo "You picked: $result"

This might be a bit more robust if selecta supported null-terminating its result - then you could read --null which would not be confused by whitespace.

Also, it would be great if selecta could handle SIGTTOU and quit with a relevant message about not being able to modify the TTY. That way the error would become much more google-able instead of the process being mysteriously suspended :)