github.com/lazyboychen7/engine@v17.12.1-ce-rc2+incompatible/pkg/term/proxy.go (about) 1 package term 2 3 import ( 4 "io" 5 ) 6 7 // EscapeError is special error which returned by a TTY proxy reader's Read() 8 // method in case its detach escape sequence is read. 9 type EscapeError struct{} 10 11 func (EscapeError) Error() string { 12 return "read escape sequence" 13 } 14 15 // escapeProxy is used only for attaches with a TTY. It is used to proxy 16 // stdin keypresses from the underlying reader and look for the passed in 17 // escape key sequence to signal a detach. 18 type escapeProxy struct { 19 escapeKeys []byte 20 escapeKeyPos int 21 r io.Reader 22 } 23 24 // NewEscapeProxy returns a new TTY proxy reader which wraps the given reader 25 // and detects when the specified escape keys are read, in which case the Read 26 // method will return an error of type EscapeError. 27 func NewEscapeProxy(r io.Reader, escapeKeys []byte) io.Reader { 28 return &escapeProxy{ 29 escapeKeys: escapeKeys, 30 r: r, 31 } 32 } 33 34 func (r *escapeProxy) Read(buf []byte) (int, error) { 35 nr, err := r.r.Read(buf) 36 37 preserve := func() { 38 // this preserves the original key presses in the passed in buffer 39 nr += r.escapeKeyPos 40 preserve := make([]byte, 0, r.escapeKeyPos+len(buf)) 41 preserve = append(preserve, r.escapeKeys[:r.escapeKeyPos]...) 42 preserve = append(preserve, buf...) 43 r.escapeKeyPos = 0 44 copy(buf[0:nr], preserve) 45 } 46 47 if nr != 1 || err != nil { 48 if r.escapeKeyPos > 0 { 49 preserve() 50 } 51 return nr, err 52 } 53 54 if buf[0] != r.escapeKeys[r.escapeKeyPos] { 55 if r.escapeKeyPos > 0 { 56 preserve() 57 } 58 return nr, nil 59 } 60 61 if r.escapeKeyPos == len(r.escapeKeys)-1 { 62 return 0, EscapeError{} 63 } 64 65 // Looks like we've got an escape key, but we need to match again on the next 66 // read. 67 // Store the current escape key we found so we can look for the next one on 68 // the next read. 69 // Since this is an escape key, make sure we don't let the caller read it 70 // If later on we find that this is not the escape sequence, we'll add the 71 // keys back 72 r.escapeKeyPos++ 73 return nr - r.escapeKeyPos, nil 74 }