From 474860961114c9255db80be88abe7a089eca679f Mon Sep 17 00:00:00 2001 From: Jeffrey Morgan Date: Fri, 27 Oct 2023 20:01:48 -0700 Subject: [PATCH] Don't quit ioloop on `NUL` character (#940) * dont quit ioloop on 0 rune * check for closed channel * remove unused error on `Close()` --- readline/buffer.go | 26 +++++++++++++------------- readline/readline.go | 42 ++++++++++++++++++++---------------------- readline/term.go | 6 ++++-- readline/types.go | 1 + 4 files changed, 38 insertions(+), 37 deletions(-) diff --git a/readline/buffer.go b/readline/buffer.go index 1a75f139..8b680282 100644 --- a/readline/buffer.go +++ b/readline/buffer.go @@ -45,7 +45,7 @@ func (b *Buffer) MoveLeft() { if b.Pos%b.LineWidth == 0 { fmt.Printf(CursorUp + CursorBOL + cursorRightN(b.Width)) } else { - fmt.Printf(CursorLeft) + fmt.Print(CursorLeft) } b.Pos -= 1 } @@ -78,7 +78,7 @@ func (b *Buffer) MoveRight() { if b.Pos%b.LineWidth == 0 { fmt.Printf(CursorDown + CursorBOL + cursorRightN(b.PromptSize())) } else { - fmt.Printf(CursorRight) + fmt.Print(CursorRight) } } } @@ -104,7 +104,7 @@ func (b *Buffer) MoveToStart() { currLine := b.Pos / b.LineWidth if currLine > 0 { for cnt := 0; cnt < currLine; cnt++ { - fmt.Printf(CursorUp) + fmt.Print(CursorUp) } } fmt.Printf(CursorBOL + cursorRightN(b.PromptSize())) @@ -118,12 +118,12 @@ func (b *Buffer) MoveToEnd() { totalLines := b.Size() / b.LineWidth if currLine < totalLines { for cnt := 0; cnt < totalLines-currLine; cnt++ { - fmt.Printf(CursorDown) + fmt.Print(CursorDown) } remainder := b.Size() % b.LineWidth fmt.Printf(CursorBOL + cursorRightN(b.PromptSize()+remainder)) } else { - fmt.Printf(cursorRightN(b.Size() - b.Pos)) + fmt.Print(cursorRightN(b.Size() - b.Pos)) } b.Pos = b.Size() @@ -173,15 +173,15 @@ func (b *Buffer) drawRemaining() { if b.Pos > 0 { place = b.Pos % b.LineWidth } - fmt.Printf(CursorHide) + fmt.Print(CursorHide) // render the rest of the current line currLine := remainingText[:min(b.LineWidth-place, len(remainingText))] if len(currLine) > 0 { fmt.Printf(ClearToEOL + currLine) - fmt.Printf(cursorLeftN(len(currLine))) + fmt.Print(cursorLeftN(len(currLine))) } else { - fmt.Printf(ClearToEOL) + fmt.Print(ClearToEOL) } // render the other lines @@ -195,12 +195,12 @@ func (b *Buffer) drawRemaining() { } fmt.Printf("%c", c) } - fmt.Printf(ClearToEOL) - fmt.Printf(cursorUpN(totalLines)) + fmt.Print(ClearToEOL) + fmt.Print(cursorUpN(totalLines)) fmt.Printf(CursorBOL + cursorRightN(b.Width-len(currLine))) } - fmt.Printf(CursorShow) + fmt.Print(CursorShow) } func (b *Buffer) Remove() { @@ -305,12 +305,12 @@ func (b *Buffer) ClearScreen() { targetLine := currPos / b.LineWidth if targetLine > 0 { for cnt := 0; cnt < targetLine; cnt++ { - fmt.Printf(CursorDown) + fmt.Print(CursorDown) } } remainder := currPos % b.LineWidth if remainder > 0 { - fmt.Printf(cursorRightN(remainder)) + fmt.Print(cursorRightN(remainder)) } if currPos%b.LineWidth == 0 { fmt.Printf(CursorBOL + b.Prompt.AltPrompt) diff --git a/readline/readline.go b/readline/readline.go index 8a74727e..95b0ca18 100644 --- a/readline/readline.go +++ b/readline/readline.go @@ -5,7 +5,6 @@ import ( "fmt" "io" "os" - "sync" "syscall" ) @@ -18,8 +17,6 @@ type Prompt struct { } type Terminal struct { - m sync.Mutex - wg sync.WaitGroup outchan chan rune } @@ -52,7 +49,7 @@ func (i *Instance) Readline() (string, error) { if i.Prompt.UseAlt { prompt = i.Prompt.AltPrompt } - fmt.Printf(prompt) + fmt.Print(prompt) termios, err := SetRawMode(syscall.Stdin) if err != nil { @@ -78,13 +75,13 @@ func (i *Instance) Readline() (string, error) { fmt.Printf(ColorGrey + ph + fmt.Sprintf(CursorLeftN, len(ph)) + ColorDefault) } - r := i.Terminal.ReadRune() - if buf.IsEmpty() { - fmt.Printf(ClearToEOL) + r, err := i.Terminal.Read() + if err != nil { + return "", io.EOF } - if r == 0 { // io.EOF - break + if buf.IsEmpty() { + fmt.Print(ClearToEOL) } if escex { @@ -112,7 +109,11 @@ func (i *Instance) Readline() (string, error) { case CharBracketedPaste: var code string for cnt := 0; cnt < 3; cnt++ { - r = i.Terminal.ReadRune() + r, err = i.Terminal.Read() + if err != nil { + return "", io.EOF + } + code += string(r) } if code == CharBracketedPasteStart { @@ -149,6 +150,8 @@ func (i *Instance) Readline() (string, error) { } switch r { + case CharNull: + continue case CharEsc: esc = true case CharInterrupt: @@ -206,11 +209,10 @@ func (i *Instance) Readline() (string, error) { } } } - return "", nil } -func (i *Instance) Close() error { - return i.Terminal.Close() +func (i *Instance) Close() { + i.Terminal.Close() } func (i *Instance) HistoryEnable() { @@ -240,22 +242,18 @@ func (t *Terminal) ioloop() { break } t.outchan <- r - if r == 0 { // EOF - break - } } - } -func (t *Terminal) ReadRune() rune { +func (t *Terminal) Read() (rune, error) { r, ok := <-t.outchan if !ok { - return rune(0) + return 0, io.EOF } - return r + + return r, nil } -func (t *Terminal) Close() error { +func (t *Terminal) Close() { close(t.outchan) - return nil } diff --git a/readline/term.go b/readline/term.go index a2c35938..36517263 100644 --- a/readline/term.go +++ b/readline/term.go @@ -1,4 +1,6 @@ +//go:build aix || darwin || dragonfly || freebsd || (linux && !appengine) || netbsd || openbsd || os400 || solaris // +build aix darwin dragonfly freebsd linux,!appengine netbsd openbsd os400 solaris + package readline import ( @@ -30,6 +32,6 @@ func UnsetRawMode(fd int, termios *Termios) error { // IsTerminal returns true if the given file descriptor is a terminal. func IsTerminal(fd int) bool { - _, err := getTermios(fd) - return err == nil + _, err := getTermios(fd) + return err == nil } diff --git a/readline/types.go b/readline/types.go index f4b3d0c4..03fa526d 100644 --- a/readline/types.go +++ b/readline/types.go @@ -1,6 +1,7 @@ package readline const ( + CharNull = 0 CharLineStart = 1 CharBackward = 2 CharInterrupt = 3