mirror of
https://github.com/golang/term.git
synced 2026-02-09 12:16:05 +03:00
x/crypto/ssh/terminal: replace \n with \r\n.
18e6eb769a made MakeRaw match C's behaviour. This included clearing the
OPOST flag, which means that one now needs to write \r\n for a newline,
otherwise the cursor doesn't move back to the beginning and the terminal
prints a staircase.
(Dear god, we're still emulating line printers.)
This change causes the terminal package to do the required
transformation.
Fixes golang/go#17364.
Change-Id: Ida15d3cf701a21eaa59161ab61b3ed4dee2ded46
Reviewed-on: https://go-review.googlesource.com/33902
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
42
terminal.go
42
terminal.go
@@ -132,8 +132,11 @@ const (
|
||||
keyPasteEnd
|
||||
)
|
||||
|
||||
var pasteStart = []byte{keyEscape, '[', '2', '0', '0', '~'}
|
||||
var pasteEnd = []byte{keyEscape, '[', '2', '0', '1', '~'}
|
||||
var (
|
||||
crlf = []byte{'\r', '\n'}
|
||||
pasteStart = []byte{keyEscape, '[', '2', '0', '0', '~'}
|
||||
pasteEnd = []byte{keyEscape, '[', '2', '0', '1', '~'}
|
||||
)
|
||||
|
||||
// bytesToKey tries to parse a key sequence from b. If successful, it returns
|
||||
// the key and the remainder of the input. Otherwise it returns utf8.RuneError.
|
||||
@@ -333,7 +336,7 @@ func (t *Terminal) advanceCursor(places int) {
|
||||
// So, if we are stopping at the end of a line, we
|
||||
// need to write a newline so that our cursor can be
|
||||
// advanced to the next line.
|
||||
t.outBuf = append(t.outBuf, '\n')
|
||||
t.outBuf = append(t.outBuf, '\r', '\n')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -593,6 +596,35 @@ func (t *Terminal) writeLine(line []rune) {
|
||||
}
|
||||
}
|
||||
|
||||
// writeWithCRLF writes buf to w but replaces all occurances of \n with \r\n.
|
||||
func writeWithCRLF(w io.Writer, buf []byte) (n int, err error) {
|
||||
for len(buf) > 0 {
|
||||
i := bytes.IndexByte(buf, '\n')
|
||||
todo := len(buf)
|
||||
if i >= 0 {
|
||||
todo = i
|
||||
}
|
||||
|
||||
var nn int
|
||||
nn, err = w.Write(buf[:todo])
|
||||
n += nn
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
buf = buf[todo:]
|
||||
|
||||
if i >= 0 {
|
||||
if _, err = w.Write(crlf); err != nil {
|
||||
return n, err
|
||||
}
|
||||
n += 1
|
||||
buf = buf[1:]
|
||||
}
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (t *Terminal) Write(buf []byte) (n int, err error) {
|
||||
t.lock.Lock()
|
||||
defer t.lock.Unlock()
|
||||
@@ -600,7 +632,7 @@ func (t *Terminal) Write(buf []byte) (n int, err error) {
|
||||
if t.cursorX == 0 && t.cursorY == 0 {
|
||||
// This is the easy case: there's nothing on the screen that we
|
||||
// have to move out of the way.
|
||||
return t.c.Write(buf)
|
||||
return writeWithCRLF(t.c, buf)
|
||||
}
|
||||
|
||||
// We have a prompt and possibly user input on the screen. We
|
||||
@@ -620,7 +652,7 @@ func (t *Terminal) Write(buf []byte) (n int, err error) {
|
||||
}
|
||||
t.outBuf = t.outBuf[:0]
|
||||
|
||||
if n, err = t.c.Write(buf); err != nil {
|
||||
if n, err = writeWithCRLF(t.c, buf); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
package terminal
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"os"
|
||||
"testing"
|
||||
@@ -289,3 +290,17 @@ func TestMakeRawState(t *testing.T) {
|
||||
t.Errorf("states do not match; was %v, expected %v", raw, st)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOutputNewlines(t *testing.T) {
|
||||
// \n should be changed to \r\n in terminal output.
|
||||
buf := new(bytes.Buffer)
|
||||
term := NewTerminal(buf, ">")
|
||||
|
||||
term.Write([]byte("1\n2\n"))
|
||||
output := string(buf.Bytes())
|
||||
const expected = "1\r\n2\r\n"
|
||||
|
||||
if output != expected {
|
||||
t.Errorf("incorrect output: was %q, expected %q", output, expected)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user