OSDN Git Service

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