handle race condition while setting raw mode in windows (#2509)
This commit is contained in:
parent
9241a29336
commit
42e77e2a69
5 changed files with 38 additions and 15 deletions
|
@ -32,6 +32,8 @@ func (p *Prompt) placeholder() string {
|
||||||
|
|
||||||
type Terminal struct {
|
type Terminal struct {
|
||||||
outchan chan rune
|
outchan chan rune
|
||||||
|
rawmode bool
|
||||||
|
termios any
|
||||||
}
|
}
|
||||||
|
|
||||||
type Instance struct {
|
type Instance struct {
|
||||||
|
@ -60,6 +62,16 @@ func New(prompt Prompt) (*Instance, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Instance) Readline() (string, error) {
|
func (i *Instance) Readline() (string, error) {
|
||||||
|
if !i.Terminal.rawmode {
|
||||||
|
fd := int(syscall.Stdin)
|
||||||
|
termios, err := SetRawMode(fd)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
i.Terminal.rawmode = true
|
||||||
|
i.Terminal.termios = termios
|
||||||
|
}
|
||||||
|
|
||||||
prompt := i.Prompt.prompt()
|
prompt := i.Prompt.prompt()
|
||||||
if i.Pasting {
|
if i.Pasting {
|
||||||
// force alt prompt when pasting
|
// force alt prompt when pasting
|
||||||
|
@ -67,13 +79,12 @@ func (i *Instance) Readline() (string, error) {
|
||||||
}
|
}
|
||||||
fmt.Print(prompt)
|
fmt.Print(prompt)
|
||||||
|
|
||||||
|
defer func() {
|
||||||
fd := int(syscall.Stdin)
|
fd := int(syscall.Stdin)
|
||||||
termios, err := SetRawMode(fd)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
// nolint: errcheck
|
// nolint: errcheck
|
||||||
defer UnsetRawMode(fd, termios)
|
UnsetRawMode(fd, i.Terminal.termios)
|
||||||
|
i.Terminal.rawmode = false
|
||||||
|
}()
|
||||||
|
|
||||||
buf, _ := NewBuffer(i.Prompt)
|
buf, _ := NewBuffer(i.Prompt)
|
||||||
|
|
||||||
|
@ -205,7 +216,8 @@ func (i *Instance) Readline() (string, error) {
|
||||||
case CharCtrlW:
|
case CharCtrlW:
|
||||||
buf.DeleteWord()
|
buf.DeleteWord()
|
||||||
case CharCtrlZ:
|
case CharCtrlZ:
|
||||||
return handleCharCtrlZ(fd, termios)
|
fd := int(syscall.Stdin)
|
||||||
|
return handleCharCtrlZ(fd, i.Terminal.termios)
|
||||||
case CharEnter:
|
case CharEnter:
|
||||||
output := buf.String()
|
output := buf.String()
|
||||||
if output != "" {
|
if output != "" {
|
||||||
|
@ -236,8 +248,16 @@ func (i *Instance) HistoryDisable() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTerminal() (*Terminal, error) {
|
func NewTerminal() (*Terminal, error) {
|
||||||
|
fd := int(syscall.Stdin)
|
||||||
|
termios, err := SetRawMode(fd)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
t := &Terminal{
|
t := &Terminal{
|
||||||
outchan: make(chan rune),
|
outchan: make(chan rune),
|
||||||
|
rawmode: true,
|
||||||
|
termios: termios,
|
||||||
}
|
}
|
||||||
|
|
||||||
go t.ioloop()
|
go t.ioloop()
|
||||||
|
|
|
@ -6,8 +6,9 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
func handleCharCtrlZ(fd int, termios *Termios) (string, error) {
|
func handleCharCtrlZ(fd int, termios any) (string, error) {
|
||||||
if err := UnsetRawMode(fd, termios); err != nil {
|
t := termios.(*Termios)
|
||||||
|
if err := UnsetRawMode(fd, t); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package readline
|
package readline
|
||||||
|
|
||||||
func handleCharCtrlZ(fd int, state *State) (string, error) {
|
func handleCharCtrlZ(fd int, state any) (string, error) {
|
||||||
// not supported
|
// not supported
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,8 +25,9 @@ func SetRawMode(fd int) (*Termios, error) {
|
||||||
return termios, setTermios(fd, &newTermios)
|
return termios, setTermios(fd, &newTermios)
|
||||||
}
|
}
|
||||||
|
|
||||||
func UnsetRawMode(fd int, termios *Termios) error {
|
func UnsetRawMode(fd int, termios any) error {
|
||||||
return setTermios(fd, termios)
|
t := termios.(*Termios)
|
||||||
|
return setTermios(fd, t)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsTerminal returns true if the given file descriptor is a terminal.
|
// IsTerminal returns true if the given file descriptor is a terminal.
|
||||||
|
|
|
@ -56,7 +56,8 @@ func SetRawMode(fd int) (*State, error) {
|
||||||
return &State{st}, nil
|
return &State{st}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func UnsetRawMode(fd int, state *State) error {
|
func UnsetRawMode(fd int, state any) error {
|
||||||
_, _, err := syscall.SyscallN(procSetConsoleMode.Addr(), uintptr(fd), uintptr(state.mode), 0)
|
s := state.(*State)
|
||||||
|
_, _, err := syscall.SyscallN(procSetConsoleMode.Addr(), uintptr(fd), uintptr(s.mode), 0)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue