Meta: reading file from stdin while still interacting with the terminal

20 views
Skip to first unread message

Tim Chase

unread,
Apr 19, 2020, 11:07:03 PM4/19/20
to v...@vim.org
I'm playing around with a curses program and would like it to behave
similarly to how vim lets me do

$ echo hello | vim -

where vim reads data from stdin but then interacts with the terminal
directrly. What magic is vim doing here?

For context, it's a dumb Python curses program, but if I try to pipe
data into it, it interprets the EOF on stdin and then complains
there's no input for the curses getch()/getkey() call.

It's not exactly vim-related other than "vim does what I want; what's
it doing under the hood?"

Thanks for any pointers you might send my way.

-tim


Eli the Bearded

unread,
Apr 20, 2020, 2:09:18 PM4/20/20
to Tim Chase, vim...@googlegroups.com
(Sent directly and to list; list moderator -- if any -- is welcome
to reject this.)

Tim Chase wrote:
> I'm playing around with a curses program and would like it to behave
> similarly to how vim lets me do
>
> $ echo hello | vim -
>
> where vim reads data from stdin but then interacts with the terminal
> directrly. What magic is vim doing here?

I don't know what vim is doing, but I suspect it works like password
prompts in pipelines, eg:

$ someprogram | ssh user@site "sh someotherprogram -"
user@site password:
$

Those read from STDERR to get keyboard input in the face of STDIN being
NOTATTY.

Elijah

Cameron Simpson

unread,
Apr 20, 2020, 6:20:53 PM4/20/20
to vim...@googlegroups.com, v...@vim.org, Tim Chase
On 19Apr2020 22:06, Tim Chase <v...@tim.thechases.com> wrote:
>I'm playing around with a curses program and would like it to behave
>similarly to how vim lets me do
>
> $ echo hello | vim -
>
>where vim reads data from stdin but then interacts with the terminal
>directrly. What magic is vim doing here?

Typically stdin, stdout and stderr are all os.dup()s of the terminal.

In the above vim's stdin will of course be the pipe but stdout and
stderr are still attached; it could dup one of them to stdin again and
proceed.

Or it might just open /dev/tty again after reading stdin if that isn't a
tty.

>For context, it's a dumb Python curses program, but if I try to pipe
>data into it, it interprets the EOF on stdin and then complains
>there's no input for the curses getch()/getkey() call.

Aye. The pipe is empty. Reach for the tty.

You _could_ close sys.stdin and reopen, but you might be better off just
using os.close(0) and then duping fd 1 to fd 0. I'd expect getch and
getkey to go direct to the file descriptor.

Cheers,
Cameron Simpson <c...@cskk.id.au>

Tim Chase

unread,
Apr 21, 2020, 3:14:50 PM4/21/20
to Cameron Simpson, vim...@googlegroups.com, v...@vim.org, Tim Chase
On 2020-04-21 08:20, Cameron Simpson wrote:
> On 19Apr2020 22:06, Tim Chase <v...@tim.thechases.com> wrote:
> >I'm playing around with a curses program and would like it to
> >behave similarly to how vim lets me do
> >
> > $ echo hello | vim -
> >
> >where vim reads data from stdin but then interacts with the
> >terminal directrly. What magic is vim doing here?
>
> Typically stdin, stdout and stderr are all os.dup()s of the
> terminal.
>
> In the above vim's stdin will of course be the pipe but stdout and
> stderr are still attached; it could dup one of them to stdin again
> and proceed.
>
> Or it might just open /dev/tty again after reading stdin if that
> isn't a tty.

Thanks, Cameron & Eli. I tried meandering through the vim source
and, while this is what it looked like it was doing (i.e., using
stderr for input), it made no sense to me. Now it makes more sense.

So now at least I have two possible courses of action (use stderr or
(re)open /dev/tty). Time to try and bludgeon curses into pulling its
input from some place other than stdin. Or possibly re-attaching
stdin to the stderr file descriptor.

Thanks again!

-tim




Reply all
Reply to author
Forward
0 new messages