From fd5a52a5d8b7d9e40debc473d5799bfafb8c60db Mon Sep 17 00:00:00 2001 From: Derek Che Date: Thu, 18 Dec 2014 21:22:47 -0800 Subject: [PATCH] ssh/terminal: fix SetSize when nothing on current line SetSize has a problem may cause the following ReadPassword setting temporary prompt not working, when changing width the current SetSize will call clearAndRepaintLinePlusNPrevious which would print an old prompt whatever the current line has, causing a following ReadPassword with temporary prompt not printing the different prompt. When running code like this, the nt.SetSize prints a "> " as prompt then the temporary "Password: " prompt would never show up. ```go oldState, err := terminal.MakeRaw(int(os.Stdin.Fd())) width, height, _ = terminal.GetSize(int(os.Stdin.Fd())) nt := terminal.NewTerminal(os.Stdin, "> ") nt.SetSize(width, height) password, err = nt.ReadPassword("Password: ") ``` the new test cases is to test SetSize with different terminal sizes, either shrinking or expanding, a following ReadPassword should get the correct temporary prompt. Change-Id: I33d13b2c732997c0c88670d53545b8c0048b94b6 Reviewed-on: https://go-review.googlesource.com/1861 Reviewed-by: Adam Langley --- terminal.go | 4 ++++ terminal_test.go | 26 ++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/terminal.go b/terminal.go index 965f0cf..741eeb1 100644 --- a/terminal.go +++ b/terminal.go @@ -789,6 +789,10 @@ func (t *Terminal) SetSize(width, height int) error { // If the width didn't change then nothing else needs to be // done. return nil + case len(t.line) == 0 && t.cursorX == 0 && t.cursorY == 0: + // If there is nothing on current line and no prompt printed, + // just do nothing + return nil case width < oldWidth: // Some terminals (e.g. xterm) will truncate lines that were // too long when shinking. Others, (e.g. gnome-terminal) will diff --git a/terminal_test.go b/terminal_test.go index 6579801..a663fe4 100644 --- a/terminal_test.go +++ b/terminal_test.go @@ -241,3 +241,29 @@ func TestPasswordNotSaved(t *testing.T) { t.Fatalf("password was saved in history") } } + +var setSizeTests = []struct { + width, height int +}{ + {40, 13}, + {80, 24}, + {132, 43}, +} + +func TestTerminalSetSize(t *testing.T) { + for _, setSize := range setSizeTests { + c := &MockTerminal{ + toSend: []byte("password\r\x1b[A\r"), + bytesPerRead: 1, + } + ss := NewTerminal(c, "> ") + ss.SetSize(setSize.width, setSize.height) + pw, _ := ss.ReadPassword("Password: ") + if pw != "password" { + t.Fatalf("failed to read password, got %s", pw) + } + if string(c.received) != "Password: \r\n" { + t.Errorf("failed to set the temporary prompt expected %q, got %q", "Password: ", c.received) + } + } +}