Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(643)

Delta Between Two Patch Sets: ssh/terminal/terminal.go

Issue 93010046: code review 93010046: ssh/terminal: handles interruptions in user-friendly manner
Left Patch Set: diff -r a3d6743eb586 https://code.google.com/p/go.crypto/ Created 9 years, 11 months ago
Right Patch Set: diff -r a3d6743eb586 https://code.google.com/p/go.crypto/ Created 9 years, 10 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | ssh/terminal/terminal_test.go » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 // Copyright 2011 The Go Authors. All rights reserved. 1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style 2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file. 3 // license that can be found in the LICENSE file.
4 4
5 package terminal 5 package terminal
6 6
7 import ( 7 import (
8 "fmt"
9 "io" 8 "io"
10 "sync" 9 "sync"
11 "unicode/utf8" 10 "unicode/utf8"
12 ) 11 )
13 12
14 // EscapeCodes contains escape sequences that can be written to the terminal in 13 // EscapeCodes contains escape sequences that can be written to the terminal in
15 // order to achieve different styles of text. 14 // order to achieve different styles of text.
16 type EscapeCodes struct { 15 type EscapeCodes struct {
17 // Foreground colors 16 // Foreground colors
18 Black, Red, Green, Yellow, Blue, Magenta, Cyan, White []byte 17 Black, Red, Green, Yellow, Blue, Magenta, Cyan, White []byte
(...skipping 11 matching lines...) Expand all
30 Magenta: []byte{keyEscape, '[', '3', '5', 'm'}, 29 Magenta: []byte{keyEscape, '[', '3', '5', 'm'},
31 Cyan: []byte{keyEscape, '[', '3', '6', 'm'}, 30 Cyan: []byte{keyEscape, '[', '3', '6', 'm'},
32 White: []byte{keyEscape, '[', '3', '7', 'm'}, 31 White: []byte{keyEscape, '[', '3', '7', 'm'},
33 32
34 Reset: []byte{keyEscape, '[', '0', 'm'}, 33 Reset: []byte{keyEscape, '[', '0', 'm'},
35 } 34 }
36 35
37 // Terminal contains the state for running a VT100 terminal that is capable of 36 // Terminal contains the state for running a VT100 terminal that is capable of
38 // reading lines of input. 37 // reading lines of input.
39 type Terminal struct { 38 type Terminal struct {
40 » // AutoCompleteCallback, if non-null, is called for each keypress with 39 » // AutoCompleteCallback, if non-nil, is called for each keypress with
41 // the full input line and the current position of the cursor (in 40 // 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 41 // bytes, as an index into |line|). If it returns ok=false, the key
43 // press is processed normally. Otherwise it returns a replacement line 42 // press is processed normally. Otherwise it returns a replacement line
44 // and the new cursor position. 43 // and the new cursor position.
45 AutoCompleteCallback func(line string, pos int, key rune) (newLine strin g, newPos int, ok bool) 44 AutoCompleteCallback func(line string, pos int, key rune) (newLine strin g, newPos int, ok bool)
45
46 // SignalHandler, if non-nil, is called when ^C or ^Z has been pressed.
47 // If it returns ok=false, the key processing is continued. Otherwise
48 // the given line and error will be returned from ReadLine.
49 SignalHandler func(key rune) (line string, err error, ok bool)
46 50
47 // Escape contains a pointer to the escape codes for this terminal. 51 // Escape contains a pointer to the escape codes for this terminal.
48 // It's always a valid pointer, although the escape codes themselves 52 // It's always a valid pointer, although the escape codes themselves
49 // may be empty if the terminal doesn't support them. 53 // may be empty if the terminal doesn't support them.
50 Escape *EscapeCodes 54 Escape *EscapeCodes
51 55
52 // lock protects the terminal and the state in this object from 56 // lock protects the terminal and the state in this object from
53 // concurrent processing of a key press and a Write() call. 57 // concurrent processing of a key press and a Write() call.
54 lock sync.Mutex 58 lock sync.Mutex
55 59
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after
205 } 209 }
206 210
207 var eraseUnderCursor = []rune{' ', keyEscape, '[', 'D'} 211 var eraseUnderCursor = []rune{' ', keyEscape, '[', 'D'}
208 var space = []rune{' '} 212 var space = []rune{' '}
209 213
210 func isPrintable(key rune) bool { 214 func isPrintable(key rune) bool {
211 isInSurrogateArea := key >= 0xd800 && key <= 0xdbff 215 isInSurrogateArea := key >= 0xd800 && key <= 0xdbff
212 return key >= 32 && !isInSurrogateArea 216 return key >= 32 && !isInSurrogateArea
213 } 217 }
214 218
219 func isSignal(key rune) bool {
220 return key == keyCtrlC || key == keyCtrlZ
221 }
222
215 // moveCursorToPos appends data to t.outBuf which will move the cursor to the 223 // moveCursorToPos appends data to t.outBuf which will move the cursor to the
216 // given, logical position in the text. 224 // given, logical position in the text.
217 func (t *Terminal) moveCursorToPos(pos int) { 225 func (t *Terminal) moveCursorToPos(pos int) {
218 if !t.echo { 226 if !t.echo {
219 return 227 return
220 } 228 }
221 229
222 x := len(t.prompt) + pos 230 x := len(t.prompt) + pos
223 y := x / t.termWidth 231 y := x / t.termWidth
224 x = x % t.termWidth 232 x = x % t.termWidth
(...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after
602 lineOk := false 610 lineOk := false
603 for !lineOk { 611 for !lineOk {
604 var key rune 612 var key rune
605 key, rest = bytesToKey(rest) 613 key, rest = bytesToKey(rest)
606 if key == utf8.RuneError { 614 if key == utf8.RuneError {
607 break 615 break
608 } 616 }
609 if key == keyCtrlD { 617 if key == keyCtrlD {
610 return "", io.EOF 618 return "", io.EOF
611 } 619 }
612 » » » if key == keyCtrlC { 620 » » » if isSignal(key) {
613 » » » » return "", fmt.Errorf("interrupted with SIGINT") 621 » » » » if t.SignalHandler != nil {
614 » » » } 622 » » » » » if line, err, ok := t.SignalHandler(key) ; ok {
615 » » » if key == keyCtrlZ { 623 » » » » » » return line, err
616 » » » » return "", fmt.Errorf("interrupted with SIGSTP") 624 » » » » » }
625 » » » » }
626 » » » » continue
617 } 627 }
618 line, lineOk = t.handleKey(key) 628 line, lineOk = t.handleKey(key)
619 } 629 }
620 if len(rest) > 0 { 630 if len(rest) > 0 {
621 n := copy(t.inBuf[:], rest) 631 n := copy(t.inBuf[:], rest)
622 t.remainder = t.inBuf[:n] 632 t.remainder = t.inBuf[:n]
623 } else { 633 } else {
624 t.remainder = nil 634 t.remainder = nil
625 } 635 }
626 t.c.Write(t.outBuf) 636 t.c.Write(t.outBuf)
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
699 func (s *stRingBuffer) NthPreviousEntry(n int) (value string, ok bool) { 709 func (s *stRingBuffer) NthPreviousEntry(n int) (value string, ok bool) {
700 if n >= s.size { 710 if n >= s.size {
701 return "", false 711 return "", false
702 } 712 }
703 index := s.head - n 713 index := s.head - n
704 if index < 0 { 714 if index < 0 {
705 index += s.max 715 index += s.max
706 } 716 }
707 return s.entries[index], true 717 return s.entries[index], true
708 } 718 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b