Code refactoring for bpa operator
[icn.git] / cmd / bpa-operator / vendor / golang.org / x / crypto / ssh / terminal / terminal.go
1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package terminal
6
7 import (
8         "bytes"
9         "io"
10         "strconv"
11         "sync"
12         "unicode/utf8"
13 )
14
15 // EscapeCodes contains escape sequences that can be written to the terminal in
16 // order to achieve different styles of text.
17 type EscapeCodes struct {
18         // Foreground colors
19         Black, Red, Green, Yellow, Blue, Magenta, Cyan, White []byte
20
21         // Reset all attributes
22         Reset []byte
23 }
24
25 var vt100EscapeCodes = EscapeCodes{
26         Black:   []byte{keyEscape, '[', '3', '0', 'm'},
27         Red:     []byte{keyEscape, '[', '3', '1', 'm'},
28         Green:   []byte{keyEscape, '[', '3', '2', 'm'},
29         Yellow:  []byte{keyEscape, '[', '3', '3', 'm'},
30         Blue:    []byte{keyEscape, '[', '3', '4', 'm'},
31         Magenta: []byte{keyEscape, '[', '3', '5', 'm'},
32         Cyan:    []byte{keyEscape, '[', '3', '6', 'm'},
33         White:   []byte{keyEscape, '[', '3', '7', 'm'},
34
35         Reset: []byte{keyEscape, '[', '0', 'm'},
36 }
37
38 // Terminal contains the state for running a VT100 terminal that is capable of
39 // reading lines of input.
40 type Terminal struct {
41         // AutoCompleteCallback, if non-null, is called for each keypress with
42         // the full input line and the current position of the cursor (in
43         // bytes, as an index into |line|). If it returns ok=false, the key
44         // press is processed normally. Otherwise it returns a replacement line
45         // and the new cursor position.
46         AutoCompleteCallback func(line string, pos int, key rune) (newLine string, newPos int, ok bool)
47
48         // Escape contains a pointer to the escape codes for this terminal.
49         // It's always a valid pointer, although the escape codes themselves
50         // may be empty if the terminal doesn't support them.
51         Escape *EscapeCodes
52
53         // lock protects the terminal and the state in this object from
54         // concurrent processing of a key press and a Write() call.
55         lock sync.Mutex
56
57         c      io.ReadWriter
58         prompt []rune
59
60         // line is the current line being entered.
61         line []rune
62         // pos is the logical position of the cursor in line
63         pos int
64         // echo is true if local echo is enabled
65         echo bool
66         // pasteActive is true iff there is a bracketed paste operation in
67         // progress.
68         pasteActive bool
69
70         // cursorX contains the current X value of the cursor where the left
71         // edge is 0. cursorY contains the row number where the first row of
72         // the current line is 0.
73         cursorX, cursorY int
74         // maxLine is the greatest value of cursorY so far.
75         maxLine int
76
77         termWidth, termHeight int
78
79         // outBuf contains the terminal data to be sent.
80         outBuf []byte
81         // remainder contains the remainder of any partial key sequences after
82         // a read. It aliases into inBuf.
83         remainder []byte
84         inBuf     [256]byte
85
86         // history contains previously entered commands so that they can be
87         // accessed with the up and down keys.
88         history stRingBuffer
89         // historyIndex stores the currently accessed history entry, where zero
90         // means the immediately previous entry.
91         historyIndex int
92         // When navigating up and down the history it's possible to return to
93         // the incomplete, initial line. That value is stored in
94         // historyPending.
95         historyPending string
96 }
97
98 // NewTerminal runs a VT100 terminal on the given ReadWriter. If the ReadWriter is
99 // a local terminal, that terminal must first have been put into raw mode.
100 // prompt is a string that is written at the start of each input line (i.e.
101 // "> ").
102 func NewTerminal(c io.ReadWriter, prompt string) *Terminal {
103         return &Terminal{
104                 Escape:       &vt100EscapeCodes,
105                 c:            c,
106                 prompt:       []rune(prompt),
107                 termWidth:    80,
108                 termHeight:   24,
109                 echo:         true,
110                 historyIndex: -1,
111         }
112 }
113
114 const (
115         keyCtrlD     = 4
116         keyCtrlU     = 21
117         keyEnter     = '\r'
118         keyEscape    = 27
119         keyBackspace = 127
120         keyUnknown   = 0xd800 /* UTF-16 surrogate area */ + iota
121         keyUp
122         keyDown
123         keyLeft
124         keyRight
125         keyAltLeft
126         keyAltRight
127         keyHome
128         keyEnd
129         keyDeleteWord
130         keyDeleteLine
131         keyClearScreen
132         keyPasteStart
133         keyPasteEnd
134 )
135
136 var (
137         crlf       = []byte{'\r', '\n'}
138         pasteStart = []byte{keyEscape, '[', '2', '0', '0', '~'}
139         pasteEnd   = []byte{keyEscape, '[', '2', '0', '1', '~'}
140 )
141
142 // bytesToKey tries to parse a key sequence from b. If successful, it returns
143 // the key and the remainder of the input. Otherwise it returns utf8.RuneError.
144 func bytesToKey(b []byte, pasteActive bool) (rune, []byte) {
145         if len(b) == 0 {
146                 return utf8.RuneError, nil
147         }
148
149         if !pasteActive {
150                 switch b[0] {
151                 case 1: // ^A
152                         return keyHome, b[1:]
153                 case 5: // ^E
154                         return keyEnd, b[1:]
155                 case 8: // ^H
156                         return keyBackspace, b[1:]
157                 case 11: // ^K
158                         return keyDeleteLine, b[1:]
159                 case 12: // ^L
160                         return keyClearScreen, b[1:]
161                 case 23: // ^W
162                         return keyDeleteWord, b[1:]
163                 case 14: // ^N
164                         return keyDown, b[1:]
165                 case 16: // ^P
166                         return keyUp, b[1:]
167                 }
168         }
169
170         if b[0] != keyEscape {
171                 if !utf8.FullRune(b) {
172                         return utf8.RuneError, b
173                 }
174                 r, l := utf8.DecodeRune(b)
175                 return r, b[l:]
176         }
177
178         if !pasteActive && len(b) >= 3 && b[0] == keyEscape && b[1] == '[' {
179                 switch b[2] {
180                 case 'A':
181                         return keyUp, b[3:]
182                 case 'B':
183                         return keyDown, b[3:]
184                 case 'C':
185                         return keyRight, b[3:]
186                 case 'D':
187                         return keyLeft, b[3:]
188                 case 'H':
189                         return keyHome, b[3:]
190                 case 'F':
191                         return keyEnd, b[3:]
192                 }
193         }
194
195         if !pasteActive && len(b) >= 6 && b[0] == keyEscape && b[1] == '[' && b[2] == '1' && b[3] == ';' && b[4] == '3' {
196                 switch b[5] {
197                 case 'C':
198                         return keyAltRight, b[6:]
199                 case 'D':
200                         return keyAltLeft, b[6:]
201                 }
202         }
203
204         if !pasteActive && len(b) >= 6 && bytes.Equal(b[:6], pasteStart) {
205                 return keyPasteStart, b[6:]
206         }
207
208         if pasteActive && len(b) >= 6 && bytes.Equal(b[:6], pasteEnd) {
209                 return keyPasteEnd, b[6:]
210         }
211
212         // If we get here then we have a key that we don't recognise, or a
213         // partial sequence. It's not clear how one should find the end of a
214         // sequence without knowing them all, but it seems that [a-zA-Z~] only
215         // appears at the end of a sequence.
216         for i, c := range b[0:] {
217                 if c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '~' {
218                         return keyUnknown, b[i+1:]
219                 }
220         }
221
222         return utf8.RuneError, b
223 }
224
225 // queue appends data to the end of t.outBuf
226 func (t *Terminal) queue(data []rune) {
227         t.outBuf = append(t.outBuf, []byte(string(data))...)
228 }
229
230 var eraseUnderCursor = []rune{' ', keyEscape, '[', 'D'}
231 var space = []rune{' '}
232
233 func isPrintable(key rune) bool {
234         isInSurrogateArea := key >= 0xd800 && key <= 0xdbff
235         return key >= 32 && !isInSurrogateArea
236 }
237
238 // moveCursorToPos appends data to t.outBuf which will move the cursor to the
239 // given, logical position in the text.
240 func (t *Terminal) moveCursorToPos(pos int) {
241         if !t.echo {
242                 return
243         }
244
245         x := visualLength(t.prompt) + pos
246         y := x / t.termWidth
247         x = x % t.termWidth
248
249         up := 0
250         if y < t.cursorY {
251                 up = t.cursorY - y
252         }
253
254         down := 0
255         if y > t.cursorY {
256                 down = y - t.cursorY
257         }
258
259         left := 0
260         if x < t.cursorX {
261                 left = t.cursorX - x
262         }
263
264         right := 0
265         if x > t.cursorX {
266                 right = x - t.cursorX
267         }
268
269         t.cursorX = x
270         t.cursorY = y
271         t.move(up, down, left, right)
272 }
273
274 func (t *Terminal) move(up, down, left, right int) {
275         m := []rune{}
276
277         // 1 unit up can be expressed as ^[[A or ^[A
278         // 5 units up can be expressed as ^[[5A
279
280         if up == 1 {
281                 m = append(m, keyEscape, '[', 'A')
282         } else if up > 1 {
283                 m = append(m, keyEscape, '[')
284                 m = append(m, []rune(strconv.Itoa(up))...)
285                 m = append(m, 'A')
286         }
287
288         if down == 1 {
289                 m = append(m, keyEscape, '[', 'B')
290         } else if down > 1 {
291                 m = append(m, keyEscape, '[')
292                 m = append(m, []rune(strconv.Itoa(down))...)
293                 m = append(m, 'B')
294         }
295
296         if right == 1 {
297                 m = append(m, keyEscape, '[', 'C')
298         } else if right > 1 {
299                 m = append(m, keyEscape, '[')
300                 m = append(m, []rune(strconv.Itoa(right))...)
301                 m = append(m, 'C')
302         }
303
304         if left == 1 {
305                 m = append(m, keyEscape, '[', 'D')
306         } else if left > 1 {
307                 m = append(m, keyEscape, '[')
308                 m = append(m, []rune(strconv.Itoa(left))...)
309                 m = append(m, 'D')
310         }
311
312         t.queue(m)
313 }
314
315 func (t *Terminal) clearLineToRight() {
316         op := []rune{keyEscape, '[', 'K'}
317         t.queue(op)
318 }
319
320 const maxLineLength = 4096
321
322 func (t *Terminal) setLine(newLine []rune, newPos int) {
323         if t.echo {
324                 t.moveCursorToPos(0)
325                 t.writeLine(newLine)
326                 for i := len(newLine); i < len(t.line); i++ {
327                         t.writeLine(space)
328                 }
329                 t.moveCursorToPos(newPos)
330         }
331         t.line = newLine
332         t.pos = newPos
333 }
334
335 func (t *Terminal) advanceCursor(places int) {
336         t.cursorX += places
337         t.cursorY += t.cursorX / t.termWidth
338         if t.cursorY > t.maxLine {
339                 t.maxLine = t.cursorY
340         }
341         t.cursorX = t.cursorX % t.termWidth
342
343         if places > 0 && t.cursorX == 0 {
344                 // Normally terminals will advance the current position
345                 // when writing a character. But that doesn't happen
346                 // for the last character in a line. However, when
347                 // writing a character (except a new line) that causes
348                 // a line wrap, the position will be advanced two
349                 // places.
350                 //
351                 // So, if we are stopping at the end of a line, we
352                 // need to write a newline so that our cursor can be
353                 // advanced to the next line.
354                 t.outBuf = append(t.outBuf, '\r', '\n')
355         }
356 }
357
358 func (t *Terminal) eraseNPreviousChars(n int) {
359         if n == 0 {
360                 return
361         }
362
363         if t.pos < n {
364                 n = t.pos
365         }
366         t.pos -= n
367         t.moveCursorToPos(t.pos)
368
369         copy(t.line[t.pos:], t.line[n+t.pos:])
370         t.line = t.line[:len(t.line)-n]
371         if t.echo {
372                 t.writeLine(t.line[t.pos:])
373                 for i := 0; i < n; i++ {
374                         t.queue(space)
375                 }
376                 t.advanceCursor(n)
377                 t.moveCursorToPos(t.pos)
378         }
379 }
380
381 // countToLeftWord returns then number of characters from the cursor to the
382 // start of the previous word.
383 func (t *Terminal) countToLeftWord() int {
384         if t.pos == 0 {
385                 return 0
386         }
387
388         pos := t.pos - 1
389         for pos > 0 {
390                 if t.line[pos] != ' ' {
391                         break
392                 }
393                 pos--
394         }
395         for pos > 0 {
396                 if t.line[pos] == ' ' {
397                         pos++
398                         break
399                 }
400                 pos--
401         }
402
403         return t.pos - pos
404 }
405
406 // countToRightWord returns then number of characters from the cursor to the
407 // start of the next word.
408 func (t *Terminal) countToRightWord() int {
409         pos := t.pos
410         for pos < len(t.line) {
411                 if t.line[pos] == ' ' {
412                         break
413                 }
414                 pos++
415         }
416         for pos < len(t.line) {
417                 if t.line[pos] != ' ' {
418                         break
419                 }
420                 pos++
421         }
422         return pos - t.pos
423 }
424
425 // visualLength returns the number of visible glyphs in s.
426 func visualLength(runes []rune) int {
427         inEscapeSeq := false
428         length := 0
429
430         for _, r := range runes {
431                 switch {
432                 case inEscapeSeq:
433                         if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') {
434                                 inEscapeSeq = false
435                         }
436                 case r == '\x1b':
437                         inEscapeSeq = true
438                 default:
439                         length++
440                 }
441         }
442
443         return length
444 }
445
446 // handleKey processes the given key and, optionally, returns a line of text
447 // that the user has entered.
448 func (t *Terminal) handleKey(key rune) (line string, ok bool) {
449         if t.pasteActive && key != keyEnter {
450                 t.addKeyToLine(key)
451                 return
452         }
453
454         switch key {
455         case keyBackspace:
456                 if t.pos == 0 {
457                         return
458                 }
459                 t.eraseNPreviousChars(1)
460         case keyAltLeft:
461                 // move left by a word.
462                 t.pos -= t.countToLeftWord()
463                 t.moveCursorToPos(t.pos)
464         case keyAltRight:
465                 // move right by a word.
466                 t.pos += t.countToRightWord()
467                 t.moveCursorToPos(t.pos)
468         case keyLeft:
469                 if t.pos == 0 {
470                         return
471                 }
472                 t.pos--
473                 t.moveCursorToPos(t.pos)
474         case keyRight:
475                 if t.pos == len(t.line) {
476                         return
477                 }
478                 t.pos++
479                 t.moveCursorToPos(t.pos)
480         case keyHome:
481                 if t.pos == 0 {
482                         return
483                 }
484                 t.pos = 0
485                 t.moveCursorToPos(t.pos)
486         case keyEnd:
487                 if t.pos == len(t.line) {
488                         return
489                 }
490                 t.pos = len(t.line)
491                 t.moveCursorToPos(t.pos)
492         case keyUp:
493                 entry, ok := t.history.NthPreviousEntry(t.historyIndex + 1)
494                 if !ok {
495                         return "", false
496                 }
497                 if t.historyIndex == -1 {
498                         t.historyPending = string(t.line)
499                 }
500                 t.historyIndex++
501                 runes := []rune(entry)
502                 t.setLine(runes, len(runes))
503         case keyDown:
504                 switch t.historyIndex {
505                 case -1:
506                         return
507                 case 0:
508                         runes := []rune(t.historyPending)
509                         t.setLine(runes, len(runes))
510                         t.historyIndex--
511                 default:
512                         entry, ok := t.history.NthPreviousEntry(t.historyIndex - 1)
513                         if ok {
514                                 t.historyIndex--
515                                 runes := []rune(entry)
516                                 t.setLine(runes, len(runes))
517                         }
518                 }
519         case keyEnter:
520                 t.moveCursorToPos(len(t.line))
521                 t.queue([]rune("\r\n"))
522                 line = string(t.line)
523                 ok = true
524                 t.line = t.line[:0]
525                 t.pos = 0
526                 t.cursorX = 0
527                 t.cursorY = 0
528                 t.maxLine = 0
529         case keyDeleteWord:
530                 // Delete zero or more spaces and then one or more characters.
531                 t.eraseNPreviousChars(t.countToLeftWord())
532         case keyDeleteLine:
533                 // Delete everything from the current cursor position to the
534                 // end of line.
535                 for i := t.pos; i < len(t.line); i++ {
536                         t.queue(space)
537                         t.advanceCursor(1)
538                 }
539                 t.line = t.line[:t.pos]
540                 t.moveCursorToPos(t.pos)
541         case keyCtrlD:
542                 // Erase the character under the current position.
543                 // The EOF case when the line is empty is handled in
544                 // readLine().
545                 if t.pos < len(t.line) {
546                         t.pos++
547                         t.eraseNPreviousChars(1)
548                 }
549         case keyCtrlU:
550                 t.eraseNPreviousChars(t.pos)
551         case keyClearScreen:
552                 // Erases the screen and moves the cursor to the home position.
553                 t.queue([]rune("\x1b[2J\x1b[H"))
554                 t.queue(t.prompt)
555                 t.cursorX, t.cursorY = 0, 0
556                 t.advanceCursor(visualLength(t.prompt))
557                 t.setLine(t.line, t.pos)
558         default:
559                 if t.AutoCompleteCallback != nil {
560                         prefix := string(t.line[:t.pos])
561                         suffix := string(t.line[t.pos:])
562
563                         t.lock.Unlock()
564                         newLine, newPos, completeOk := t.AutoCompleteCallback(prefix+suffix, len(prefix), key)
565                         t.lock.Lock()
566
567                         if completeOk {
568                                 t.setLine([]rune(newLine), utf8.RuneCount([]byte(newLine)[:newPos]))
569                                 return
570                         }
571                 }
572                 if !isPrintable(key) {
573                         return
574                 }
575                 if len(t.line) == maxLineLength {
576                         return
577                 }
578                 t.addKeyToLine(key)
579         }
580         return
581 }
582
583 // addKeyToLine inserts the given key at the current position in the current
584 // line.
585 func (t *Terminal) addKeyToLine(key rune) {
586         if len(t.line) == cap(t.line) {
587                 newLine := make([]rune, len(t.line), 2*(1+len(t.line)))
588                 copy(newLine, t.line)
589                 t.line = newLine
590         }
591         t.line = t.line[:len(t.line)+1]
592         copy(t.line[t.pos+1:], t.line[t.pos:])
593         t.line[t.pos] = key
594         if t.echo {
595                 t.writeLine(t.line[t.pos:])
596         }
597         t.pos++
598         t.moveCursorToPos(t.pos)
599 }
600
601 func (t *Terminal) writeLine(line []rune) {
602         for len(line) != 0 {
603                 remainingOnLine := t.termWidth - t.cursorX
604                 todo := len(line)
605                 if todo > remainingOnLine {
606                         todo = remainingOnLine
607                 }
608                 t.queue(line[:todo])
609                 t.advanceCursor(visualLength(line[:todo]))
610                 line = line[todo:]
611         }
612 }
613
614 // writeWithCRLF writes buf to w but replaces all occurrences of \n with \r\n.
615 func writeWithCRLF(w io.Writer, buf []byte) (n int, err error) {
616         for len(buf) > 0 {
617                 i := bytes.IndexByte(buf, '\n')
618                 todo := len(buf)
619                 if i >= 0 {
620                         todo = i
621                 }
622
623                 var nn int
624                 nn, err = w.Write(buf[:todo])
625                 n += nn
626                 if err != nil {
627                         return n, err
628                 }
629                 buf = buf[todo:]
630
631                 if i >= 0 {
632                         if _, err = w.Write(crlf); err != nil {
633                                 return n, err
634                         }
635                         n++
636                         buf = buf[1:]
637                 }
638         }
639
640         return n, nil
641 }
642
643 func (t *Terminal) Write(buf []byte) (n int, err error) {
644         t.lock.Lock()
645         defer t.lock.Unlock()
646
647         if t.cursorX == 0 && t.cursorY == 0 {
648                 // This is the easy case: there's nothing on the screen that we
649                 // have to move out of the way.
650                 return writeWithCRLF(t.c, buf)
651         }
652
653         // We have a prompt and possibly user input on the screen. We
654         // have to clear it first.
655         t.move(0 /* up */, 0 /* down */, t.cursorX /* left */, 0 /* right */)
656         t.cursorX = 0
657         t.clearLineToRight()
658
659         for t.cursorY > 0 {
660                 t.move(1 /* up */, 0, 0, 0)
661                 t.cursorY--
662                 t.clearLineToRight()
663         }
664
665         if _, err = t.c.Write(t.outBuf); err != nil {
666                 return
667         }
668         t.outBuf = t.outBuf[:0]
669
670         if n, err = writeWithCRLF(t.c, buf); err != nil {
671                 return
672         }
673
674         t.writeLine(t.prompt)
675         if t.echo {
676                 t.writeLine(t.line)
677         }
678
679         t.moveCursorToPos(t.pos)
680
681         if _, err = t.c.Write(t.outBuf); err != nil {
682                 return
683         }
684         t.outBuf = t.outBuf[:0]
685         return
686 }
687
688 // ReadPassword temporarily changes the prompt and reads a password, without
689 // echo, from the terminal.
690 func (t *Terminal) ReadPassword(prompt string) (line string, err error) {
691         t.lock.Lock()
692         defer t.lock.Unlock()
693
694         oldPrompt := t.prompt
695         t.prompt = []rune(prompt)
696         t.echo = false
697
698         line, err = t.readLine()
699
700         t.prompt = oldPrompt
701         t.echo = true
702
703         return
704 }
705
706 // ReadLine returns a line of input from the terminal.
707 func (t *Terminal) ReadLine() (line string, err error) {
708         t.lock.Lock()
709         defer t.lock.Unlock()
710
711         return t.readLine()
712 }
713
714 func (t *Terminal) readLine() (line string, err error) {
715         // t.lock must be held at this point
716
717         if t.cursorX == 0 && t.cursorY == 0 {
718                 t.writeLine(t.prompt)
719                 t.c.Write(t.outBuf)
720                 t.outBuf = t.outBuf[:0]
721         }
722
723         lineIsPasted := t.pasteActive
724
725         for {
726                 rest := t.remainder
727                 lineOk := false
728                 for !lineOk {
729                         var key rune
730                         key, rest = bytesToKey(rest, t.pasteActive)
731                         if key == utf8.RuneError {
732                                 break
733                         }
734                         if !t.pasteActive {
735                                 if key == keyCtrlD {
736                                         if len(t.line) == 0 {
737                                                 return "", io.EOF
738                                         }
739                                 }
740                                 if key == keyPasteStart {
741                                         t.pasteActive = true
742                                         if len(t.line) == 0 {
743                                                 lineIsPasted = true
744                                         }
745                                         continue
746                                 }
747                         } else if key == keyPasteEnd {
748                                 t.pasteActive = false
749                                 continue
750                         }
751                         if !t.pasteActive {
752                                 lineIsPasted = false
753                         }
754                         line, lineOk = t.handleKey(key)
755                 }
756                 if len(rest) > 0 {
757                         n := copy(t.inBuf[:], rest)
758                         t.remainder = t.inBuf[:n]
759                 } else {
760                         t.remainder = nil
761                 }
762                 t.c.Write(t.outBuf)
763                 t.outBuf = t.outBuf[:0]
764                 if lineOk {
765                         if t.echo {
766                                 t.historyIndex = -1
767                                 t.history.Add(line)
768                         }
769                         if lineIsPasted {
770                                 err = ErrPasteIndicator
771                         }
772                         return
773                 }
774
775                 // t.remainder is a slice at the beginning of t.inBuf
776                 // containing a partial key sequence
777                 readBuf := t.inBuf[len(t.remainder):]
778                 var n int
779
780                 t.lock.Unlock()
781                 n, err = t.c.Read(readBuf)
782                 t.lock.Lock()
783
784                 if err != nil {
785                         return
786                 }
787
788                 t.remainder = t.inBuf[:n+len(t.remainder)]
789         }
790 }
791
792 // SetPrompt sets the prompt to be used when reading subsequent lines.
793 func (t *Terminal) SetPrompt(prompt string) {
794         t.lock.Lock()
795         defer t.lock.Unlock()
796
797         t.prompt = []rune(prompt)
798 }
799
800 func (t *Terminal) clearAndRepaintLinePlusNPrevious(numPrevLines int) {
801         // Move cursor to column zero at the start of the line.
802         t.move(t.cursorY, 0, t.cursorX, 0)
803         t.cursorX, t.cursorY = 0, 0
804         t.clearLineToRight()
805         for t.cursorY < numPrevLines {
806                 // Move down a line
807                 t.move(0, 1, 0, 0)
808                 t.cursorY++
809                 t.clearLineToRight()
810         }
811         // Move back to beginning.
812         t.move(t.cursorY, 0, 0, 0)
813         t.cursorX, t.cursorY = 0, 0
814
815         t.queue(t.prompt)
816         t.advanceCursor(visualLength(t.prompt))
817         t.writeLine(t.line)
818         t.moveCursorToPos(t.pos)
819 }
820
821 func (t *Terminal) SetSize(width, height int) error {
822         t.lock.Lock()
823         defer t.lock.Unlock()
824
825         if width == 0 {
826                 width = 1
827         }
828
829         oldWidth := t.termWidth
830         t.termWidth, t.termHeight = width, height
831
832         switch {
833         case width == oldWidth:
834                 // If the width didn't change then nothing else needs to be
835                 // done.
836                 return nil
837         case len(t.line) == 0 && t.cursorX == 0 && t.cursorY == 0:
838                 // If there is nothing on current line and no prompt printed,
839                 // just do nothing
840                 return nil
841         case width < oldWidth:
842                 // Some terminals (e.g. xterm) will truncate lines that were
843                 // too long when shinking. Others, (e.g. gnome-terminal) will
844                 // attempt to wrap them. For the former, repainting t.maxLine
845                 // works great, but that behaviour goes badly wrong in the case
846                 // of the latter because they have doubled every full line.
847
848                 // We assume that we are working on a terminal that wraps lines
849                 // and adjust the cursor position based on every previous line
850                 // wrapping and turning into two. This causes the prompt on
851                 // xterms to move upwards, which isn't great, but it avoids a
852                 // huge mess with gnome-terminal.
853                 if t.cursorX >= t.termWidth {
854                         t.cursorX = t.termWidth - 1
855                 }
856                 t.cursorY *= 2
857                 t.clearAndRepaintLinePlusNPrevious(t.maxLine * 2)
858         case width > oldWidth:
859                 // If the terminal expands then our position calculations will
860                 // be wrong in the future because we think the cursor is
861                 // |t.pos| chars into the string, but there will be a gap at
862                 // the end of any wrapped line.
863                 //
864                 // But the position will actually be correct until we move, so
865                 // we can move back to the beginning and repaint everything.
866                 t.clearAndRepaintLinePlusNPrevious(t.maxLine)
867         }
868
869         _, err := t.c.Write(t.outBuf)
870         t.outBuf = t.outBuf[:0]
871         return err
872 }
873
874 type pasteIndicatorError struct{}
875
876 func (pasteIndicatorError) Error() string {
877         return "terminal: ErrPasteIndicator not correctly handled"
878 }
879
880 // ErrPasteIndicator may be returned from ReadLine as the error, in addition
881 // to valid line data. It indicates that bracketed paste mode is enabled and
882 // that the returned line consists only of pasted data. Programs may wish to
883 // interpret pasted data more literally than typed data.
884 var ErrPasteIndicator = pasteIndicatorError{}
885
886 // SetBracketedPasteMode requests that the terminal bracket paste operations
887 // with markers. Not all terminals support this but, if it is supported, then
888 // enabling this mode will stop any autocomplete callback from running due to
889 // pastes. Additionally, any lines that are completely pasted will be returned
890 // from ReadLine with the error set to ErrPasteIndicator.
891 func (t *Terminal) SetBracketedPasteMode(on bool) {
892         if on {
893                 io.WriteString(t.c, "\x1b[?2004h")
894         } else {
895                 io.WriteString(t.c, "\x1b[?2004l")
896         }
897 }
898
899 // stRingBuffer is a ring buffer of strings.
900 type stRingBuffer struct {
901         // entries contains max elements.
902         entries []string
903         max     int
904         // head contains the index of the element most recently added to the ring.
905         head int
906         // size contains the number of elements in the ring.
907         size int
908 }
909
910 func (s *stRingBuffer) Add(a string) {
911         if s.entries == nil {
912                 const defaultNumEntries = 100
913                 s.entries = make([]string, defaultNumEntries)
914                 s.max = defaultNumEntries
915         }
916
917         s.head = (s.head + 1) % s.max
918         s.entries[s.head] = a
919         if s.size < s.max {
920                 s.size++
921         }
922 }
923
924 // NthPreviousEntry returns the value passed to the nth previous call to Add.
925 // If n is zero then the immediately prior value is returned, if one, then the
926 // next most recent, and so on. If such an element doesn't exist then ok is
927 // false.
928 func (s *stRingBuffer) NthPreviousEntry(n int) (value string, ok bool) {
929         if n >= s.size {
930                 return "", false
931         }
932         index := s.head - n
933         if index < 0 {
934                 index += s.max
935         }
936         return s.entries[index], true
937 }
938
939 // readPasswordLine reads from reader until it finds \n or io.EOF.
940 // The slice returned does not include the \n.
941 // readPasswordLine also ignores any \r it finds.
942 func readPasswordLine(reader io.Reader) ([]byte, error) {
943         var buf [1]byte
944         var ret []byte
945
946         for {
947                 n, err := reader.Read(buf[:])
948                 if n > 0 {
949                         switch buf[0] {
950                         case '\n':
951                                 return ret, nil
952                         case '\r':
953                                 // remove \r from passwords on Windows
954                         default:
955                                 ret = append(ret, buf[0])
956                         }
957                         continue
958                 }
959                 if err != nil {
960                         if err == io.EOF && len(ret) > 0 {
961                                 return ret, nil
962                         }
963                         return ret, err
964                 }
965         }
966 }