blob: 7a603d7f761778187c078d222a6eb2659a388025 [file] [log] [blame]
Dan Willemsenb82471a2018-05-17 16:37:09 -07001// Copyright 2017 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package terminal
16
17import (
18 "bytes"
19 "io"
20 "os"
21 "syscall"
22 "unsafe"
23)
24
Colin Crossce525352019-06-08 18:58:00 -070025func isSmartTerminal(w io.Writer) bool {
Dan Willemsenb82471a2018-05-17 16:37:09 -070026 if f, ok := w.(*os.File); ok {
Mikhail Naganov9d424252019-07-02 09:51:42 -070027 if term, ok := os.LookupEnv("TERM"); ok && term == "dumb" {
28 return false
29 }
Dan Willemsenb82471a2018-05-17 16:37:09 -070030 var termios syscall.Termios
31 _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, f.Fd(),
32 ioctlGetTermios, uintptr(unsafe.Pointer(&termios)),
33 0, 0, 0)
34 return err == 0
Colin Crossdde49cb2019-06-08 21:59:42 -070035 } else if _, ok := w.(*fakeSmartTerminal); ok {
36 return true
Dan Willemsenb82471a2018-05-17 16:37:09 -070037 }
38 return false
39}
40
Colin Cross3dac80e2019-06-11 11:19:06 -070041func termSize(w io.Writer) (width int, height int, ok bool) {
Dan Willemsenb82471a2018-05-17 16:37:09 -070042 if f, ok := w.(*os.File); ok {
43 var winsize struct {
44 ws_row, ws_column uint16
45 ws_xpixel, ws_ypixel uint16
46 }
47 _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, f.Fd(),
48 syscall.TIOCGWINSZ, uintptr(unsafe.Pointer(&winsize)),
49 0, 0, 0)
Colin Cross3dac80e2019-06-11 11:19:06 -070050 return int(winsize.ws_column), int(winsize.ws_row), err == 0
Colin Crossdde49cb2019-06-08 21:59:42 -070051 } else if f, ok := w.(*fakeSmartTerminal); ok {
Colin Cross3dac80e2019-06-11 11:19:06 -070052 return f.termWidth, f.termHeight, true
Dan Willemsenb82471a2018-05-17 16:37:09 -070053 }
Colin Cross3dac80e2019-06-11 11:19:06 -070054 return 0, 0, false
Dan Willemsenb82471a2018-05-17 16:37:09 -070055}
56
57// stripAnsiEscapes strips ANSI control codes from a byte array in place.
58func stripAnsiEscapes(input []byte) []byte {
59 // read represents the remaining part of input that needs to be processed.
60 read := input
61 // write represents where we should be writing in input.
62 // It will share the same backing store as input so that we make our modifications
63 // in place.
64 write := input
65
66 // advance will copy count bytes from read to write and advance those slices
67 advance := func(write, read []byte, count int) ([]byte, []byte) {
68 copy(write, read[:count])
69 return write[count:], read[count:]
70 }
71
72 for {
73 // Find the next escape sequence
74 i := bytes.IndexByte(read, 0x1b)
75 // If it isn't found, or if there isn't room for <ESC>[, finish
76 if i == -1 || i+1 >= len(read) {
77 copy(write, read)
78 break
79 }
80
81 // Not a CSI code, continue searching
82 if read[i+1] != '[' {
83 write, read = advance(write, read, i+1)
84 continue
85 }
86
87 // Found a CSI code, advance up to the <ESC>
88 write, read = advance(write, read, i)
89
90 // Find the end of the CSI code
91 i = bytes.IndexFunc(read, func(r rune) bool {
92 return (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z')
93 })
94 if i == -1 {
95 // We didn't find the end of the code, just remove the rest
96 i = len(read) - 1
97 }
98
99 // Strip off the end marker too
100 i = i + 1
101
102 // Skip the reader forward and reduce final length by that amount
103 read = read[i:]
104 input = input[:len(input)-i]
105 }
106
107 return input
108}
Colin Crossdde49cb2019-06-08 21:59:42 -0700109
110type fakeSmartTerminal struct {
111 bytes.Buffer
Colin Cross3dac80e2019-06-11 11:19:06 -0700112 termWidth, termHeight int
Colin Crossdde49cb2019-06-08 21:59:42 -0700113}