The openpty(3C) compatibility shim is not quite right in one critical respect: pushing a STREAMS module onto a tty device can have the side effect of making that device the process's controlling terminal. Using __I_PUSH_NOCTTY avoids that side effect. This was causing the nvim --embed child process to exit unexpectedly when :terminal was used.
Neovim presently does some partially incorrect and wholly ill-advised construction of a struct termios object from whole cloth when starting an interactive child process. This likely has a subtle impact even on Linux (I verified that it is not quite producing a default object there either, though the differences are less severe). The delta between our system default termios object and the one Neovim produces is:
-===== DEFAULT:
+===== FROM NEOVIM:
input flags (c_iflag):
- BRKINT Signal interrupt on break
ICRNL Map CR to NL on input
IXON Enable start/stop output control
- IMAXBEL Echo BEL on input line too long
output flags (c_oflag):
OPOST Post-process output
ONLCR Map NL to CR-NL on output
NLDLY: Select newline delays
NL0
CRDLY: Select carriage-return delays
CR0
TABDLY: Select horizontal tab delays or tab expansion
- TAB3
- XTABS
+ TAB0
BSDLY: Select backspace delays
BS0
VTDLY: Select vertical tab delays
VT0
FFDLY: Select form feed delays
FF0
control flags (c_cflag):
CREAD Enable receiver
- CRTSCTS Enable outbound hardware flow control
CBAUDEXT Bit to indicate output speed > B38400
+ CIBAUDEXT Bit to indicate input speed > B38400
CBAUD: Baud rate (with CEXTBAUD)
- B115200
+ B57600
CSIZE: Character size
CS8
local flags (c_lflag):
- ICANON Canonical input (erase/kill proc.)
TOSTOP Send SIGTTOU for background output
ECHOPRT Echo erase char as char erased
- FLUSHO Output is being flushed
control characters (c_cc):
for canonical mode:
VINTR 0x03 ( 3) ^C
VQUIT 0x1c ( 28)
VERASE 0x7f (127)
VKILL 0x15 ( 21) ^U
- VEOF 0x04 ( 4) ^D
+ VEOF 0x01 ( 1) ^A
VEOL 0x00 ( 0)
VEOL2 0x00 ( 0)
VSWTCH 0x00 ( 0)
VSTART 0x11 ( 17) ^Q
VSTOP 0x13 ( 19) ^S
VSUSP 0x1a ( 26) ^Z
- VDSUSP 0x19 ( 25) ^Y
+ VDSUSP 0x00 ( 0)
VREPRINT 0x12 ( 18) ^R
- VDISCARD 0x0f ( 15) ^O
+ VDISCARD 0x00 ( 0)
VWERASE 0x17 ( 23) ^W
VLNEXT 0x16 ( 22) ^V
- VSTATUS 0x14 ( 20) ^T
- VERASE2 0x08 ( 8) ^H
+ VSTATUS 0x00 ( 0)
+ VERASE2 0x00 ( 0)
for raw mode:
- VMIN 0x04 ( 4) ^D
+ VMIN 0x01 ( 1) ^A
VTIME 0x00 ( 0)
Of perhaps paramount importance is that the terminal is in raw mode, which is generally totally unexpected on a UNIX system, and followed closely behind that is an unusual value for VEOF, which happens to share a slot with VMIN which has been spuriously overridden. I have removed the overrides entirely so that we just use the system default settings. I'll be working up the energy to post that fix in particular upstream, as I do not believe it is ever correct to do what they're doing there.
With these fixes in place, an interactive :terminal works under Neovim, as does the fzf-lua plugin that is quite popular and which depends on running fzf in under a pty.
A few fixes for
:terminal
support in Neovim 0.10:__I_PUSH_NOCTTY
avoids that side effect. This was causing the nvim --embed child process to exit unexpectedly when:terminal
was used.Neovim presently does some partially incorrect and wholly ill-advised construction of a struct termios object from whole cloth when starting an interactive child process. This likely has a subtle impact even on Linux (I verified that it is not quite producing a default object there either, though the differences are less severe). The delta between our system default termios object and the one Neovim produces is:
Of perhaps paramount importance is that the terminal is in raw mode, which is generally totally unexpected on a UNIX system, and followed closely behind that is an unusual value for VEOF, which happens to share a slot with VMIN which has been spuriously overridden. I have removed the overrides entirely so that we just use the system default settings. I'll be working up the energy to post that fix in particular upstream, as I do not believe it is ever correct to do what they're doing there.
With these fixes in place, an interactive
:terminal
works under Neovim, as does the fzf-lua plugin that is quite popular and which depends on running fzf in under a pty.