diff --git a/go.mod b/go.mod index cb0882aa..3c57e794 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 github.com/google/uuid v1.6.0 github.com/itchyny/gojq v0.12.19 - github.com/mattn/go-colorable v0.1.15 + github.com/mattn/go-colorable v0.1.16 github.com/mattn/go-isatty v0.0.24 github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d github.com/microsoft/azure-devops-go-api/azuredevops/v7 v7.1.0 diff --git a/go.sum b/go.sum index a934701c..262b7033 100644 --- a/go.sum +++ b/go.sum @@ -90,6 +90,8 @@ github.com/lucasb-eyer/go-colorful v1.4.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.15 h1:+u9SLTRGnXv73cEsnsmoZBom+dMU88B2M0aDcWy0/jY= github.com/mattn/go-colorable v0.1.15/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-colorable v0.1.16 h1:+2YjeAe7xP1OQbZW1jERPWWCDLlNqFNCvjiqGiAt84A= +github.com/mattn/go-colorable v0.1.16/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.24 h1:tGZZoVgT/KiqK1c8ocVLeDS8BSWMRd47J3Lbz7vsReI= github.com/mattn/go-isatty v0.0.24/go.mod h1:nMCL3Zebbrt45jsMDgnfIwz6ydEQApk5oEI3HqDio6A= diff --git a/vendor/github.com/mattn/go-colorable/colorable_windows.go b/vendor/github.com/mattn/go-colorable/colorable_windows.go index 426a409c..2e1f1ab1 100644 --- a/vendor/github.com/mattn/go-colorable/colorable_windows.go +++ b/vendor/github.com/mattn/go-colorable/colorable_windows.go @@ -5,16 +5,15 @@ package colorable import ( "bytes" - syscall "golang.org/x/sys/windows" "io" - "math" "os" "strconv" "strings" "sync" + stdsyscall "syscall" "unsafe" - "github.com/mattn/go-isatty" + syscall "golang.org/x/sys/windows" ) const ( @@ -52,6 +51,12 @@ type coord struct { y short } +// param packs the two signed 16-bit coordinates into the DWORD passed by value +// to console APIs, without reading past the four-byte coord on 64-bit Windows. +func (c coord) param() uintptr { + return uintptr(uint16(c.x)) | uintptr(uint16(c.y))<<16 +} + type smallRect struct { left short top short @@ -105,14 +110,15 @@ func NewColorable(file *os.File) io.Writer { panic("nil passed instead of *os.File to NewColorable()") } - if isatty.IsTerminal(file.Fd()) { - var mode uint32 - if r, _, _ := procGetConsoleMode.Call(file.Fd(), uintptr(unsafe.Pointer(&mode))); r != 0 && mode&cENABLE_VIRTUAL_TERMINAL_PROCESSING != 0 { + fd := file.Fd() + var mode uint32 + if err := syscall.GetConsoleMode(syscall.Handle(fd), &mode); err == nil { + if mode&cENABLE_VIRTUAL_TERMINAL_PROCESSING != 0 { return file } var csbi consoleScreenBufferInfo - handle := syscall.Handle(file.Fd()) - procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + handle := syscall.Handle(fd) + stdsyscall.SyscallN(procGetConsoleScreenBufferInfo.Addr(), uintptr(handle), uintptr(unsafe.Pointer(&csbi))) return &writer{out: file, handle: handle, oldattr: csbi.attributes, curattr: csbi.attributes, oldpos: coord{0, 0}} } return file @@ -128,302 +134,31 @@ func NewColorableStderr() io.Writer { return NewColorable(os.Stderr) } -var color256 = map[int]int{ - 0: 0x000000, - 1: 0x800000, - 2: 0x008000, - 3: 0x808000, - 4: 0x000080, - 5: 0x800080, - 6: 0x008080, - 7: 0xc0c0c0, - 8: 0x808080, - 9: 0xff0000, - 10: 0x00ff00, - 11: 0xffff00, - 12: 0x0000ff, - 13: 0xff00ff, - 14: 0x00ffff, - 15: 0xffffff, - 16: 0x000000, - 17: 0x00005f, - 18: 0x000087, - 19: 0x0000af, - 20: 0x0000d7, - 21: 0x0000ff, - 22: 0x005f00, - 23: 0x005f5f, - 24: 0x005f87, - 25: 0x005faf, - 26: 0x005fd7, - 27: 0x005fff, - 28: 0x008700, - 29: 0x00875f, - 30: 0x008787, - 31: 0x0087af, - 32: 0x0087d7, - 33: 0x0087ff, - 34: 0x00af00, - 35: 0x00af5f, - 36: 0x00af87, - 37: 0x00afaf, - 38: 0x00afd7, - 39: 0x00afff, - 40: 0x00d700, - 41: 0x00d75f, - 42: 0x00d787, - 43: 0x00d7af, - 44: 0x00d7d7, - 45: 0x00d7ff, - 46: 0x00ff00, - 47: 0x00ff5f, - 48: 0x00ff87, - 49: 0x00ffaf, - 50: 0x00ffd7, - 51: 0x00ffff, - 52: 0x5f0000, - 53: 0x5f005f, - 54: 0x5f0087, - 55: 0x5f00af, - 56: 0x5f00d7, - 57: 0x5f00ff, - 58: 0x5f5f00, - 59: 0x5f5f5f, - 60: 0x5f5f87, - 61: 0x5f5faf, - 62: 0x5f5fd7, - 63: 0x5f5fff, - 64: 0x5f8700, - 65: 0x5f875f, - 66: 0x5f8787, - 67: 0x5f87af, - 68: 0x5f87d7, - 69: 0x5f87ff, - 70: 0x5faf00, - 71: 0x5faf5f, - 72: 0x5faf87, - 73: 0x5fafaf, - 74: 0x5fafd7, - 75: 0x5fafff, - 76: 0x5fd700, - 77: 0x5fd75f, - 78: 0x5fd787, - 79: 0x5fd7af, - 80: 0x5fd7d7, - 81: 0x5fd7ff, - 82: 0x5fff00, - 83: 0x5fff5f, - 84: 0x5fff87, - 85: 0x5fffaf, - 86: 0x5fffd7, - 87: 0x5fffff, - 88: 0x870000, - 89: 0x87005f, - 90: 0x870087, - 91: 0x8700af, - 92: 0x8700d7, - 93: 0x8700ff, - 94: 0x875f00, - 95: 0x875f5f, - 96: 0x875f87, - 97: 0x875faf, - 98: 0x875fd7, - 99: 0x875fff, - 100: 0x878700, - 101: 0x87875f, - 102: 0x878787, - 103: 0x8787af, - 104: 0x8787d7, - 105: 0x8787ff, - 106: 0x87af00, - 107: 0x87af5f, - 108: 0x87af87, - 109: 0x87afaf, - 110: 0x87afd7, - 111: 0x87afff, - 112: 0x87d700, - 113: 0x87d75f, - 114: 0x87d787, - 115: 0x87d7af, - 116: 0x87d7d7, - 117: 0x87d7ff, - 118: 0x87ff00, - 119: 0x87ff5f, - 120: 0x87ff87, - 121: 0x87ffaf, - 122: 0x87ffd7, - 123: 0x87ffff, - 124: 0xaf0000, - 125: 0xaf005f, - 126: 0xaf0087, - 127: 0xaf00af, - 128: 0xaf00d7, - 129: 0xaf00ff, - 130: 0xaf5f00, - 131: 0xaf5f5f, - 132: 0xaf5f87, - 133: 0xaf5faf, - 134: 0xaf5fd7, - 135: 0xaf5fff, - 136: 0xaf8700, - 137: 0xaf875f, - 138: 0xaf8787, - 139: 0xaf87af, - 140: 0xaf87d7, - 141: 0xaf87ff, - 142: 0xafaf00, - 143: 0xafaf5f, - 144: 0xafaf87, - 145: 0xafafaf, - 146: 0xafafd7, - 147: 0xafafff, - 148: 0xafd700, - 149: 0xafd75f, - 150: 0xafd787, - 151: 0xafd7af, - 152: 0xafd7d7, - 153: 0xafd7ff, - 154: 0xafff00, - 155: 0xafff5f, - 156: 0xafff87, - 157: 0xafffaf, - 158: 0xafffd7, - 159: 0xafffff, - 160: 0xd70000, - 161: 0xd7005f, - 162: 0xd70087, - 163: 0xd700af, - 164: 0xd700d7, - 165: 0xd700ff, - 166: 0xd75f00, - 167: 0xd75f5f, - 168: 0xd75f87, - 169: 0xd75faf, - 170: 0xd75fd7, - 171: 0xd75fff, - 172: 0xd78700, - 173: 0xd7875f, - 174: 0xd78787, - 175: 0xd787af, - 176: 0xd787d7, - 177: 0xd787ff, - 178: 0xd7af00, - 179: 0xd7af5f, - 180: 0xd7af87, - 181: 0xd7afaf, - 182: 0xd7afd7, - 183: 0xd7afff, - 184: 0xd7d700, - 185: 0xd7d75f, - 186: 0xd7d787, - 187: 0xd7d7af, - 188: 0xd7d7d7, - 189: 0xd7d7ff, - 190: 0xd7ff00, - 191: 0xd7ff5f, - 192: 0xd7ff87, - 193: 0xd7ffaf, - 194: 0xd7ffd7, - 195: 0xd7ffff, - 196: 0xff0000, - 197: 0xff005f, - 198: 0xff0087, - 199: 0xff00af, - 200: 0xff00d7, - 201: 0xff00ff, - 202: 0xff5f00, - 203: 0xff5f5f, - 204: 0xff5f87, - 205: 0xff5faf, - 206: 0xff5fd7, - 207: 0xff5fff, - 208: 0xff8700, - 209: 0xff875f, - 210: 0xff8787, - 211: 0xff87af, - 212: 0xff87d7, - 213: 0xff87ff, - 214: 0xffaf00, - 215: 0xffaf5f, - 216: 0xffaf87, - 217: 0xffafaf, - 218: 0xffafd7, - 219: 0xffafff, - 220: 0xffd700, - 221: 0xffd75f, - 222: 0xffd787, - 223: 0xffd7af, - 224: 0xffd7d7, - 225: 0xffd7ff, - 226: 0xffff00, - 227: 0xffff5f, - 228: 0xffff87, - 229: 0xffffaf, - 230: 0xffffd7, - 231: 0xffffff, - 232: 0x080808, - 233: 0x121212, - 234: 0x1c1c1c, - 235: 0x262626, - 236: 0x303030, - 237: 0x3a3a3a, - 238: 0x444444, - 239: 0x4e4e4e, - 240: 0x585858, - 241: 0x626262, - 242: 0x6c6c6c, - 243: 0x767676, - 244: 0x808080, - 245: 0x8a8a8a, - 246: 0x949494, - 247: 0x9e9e9e, - 248: 0xa8a8a8, - 249: 0xb2b2b2, - 250: 0xbcbcbc, - 251: 0xc6c6c6, - 252: 0xd0d0d0, - 253: 0xdadada, - 254: 0xe4e4e4, - 255: 0xeeeeee, -} - // `\033]0;TITLESTR\007` -func doTitleSequence(er *bytes.Reader) error { - var c byte - var err error - - c, err = er.ReadByte() - if err != nil { - return err +func doTitleSequence(data []byte) (int, error) { + if len(data) == 0 { + return 0, io.EOF } - if c != '0' && c != '2' { - return nil + if data[0] != '0' && data[0] != '2' { + return 1, nil } - c, err = er.ReadByte() - if err != nil { - return err + if len(data) < 2 { + return 1, io.EOF } - if c != ';' { - return nil + if data[1] != ';' { + return 2, nil } - title := make([]byte, 0, 80) - for { - c, err = er.ReadByte() - if err != nil { - return err - } - if c == 0x07 || c == '\n' { - break - } - title = append(title, c) + end := bytes.IndexAny(data[2:], "\a\n") + if end < 0 { + return len(data), io.EOF } - if len(title) > 0 { - title8, err := syscall.UTF16PtrFromString(string(title)) + if end > 0 { + title, err := syscall.UTF16PtrFromString(string(data[2 : 2+end])) if err == nil { - procSetConsoleTitle.Call(uintptr(unsafe.Pointer(title8))) + stdsyscall.SyscallN(procSetConsoleTitle.Addr(), uintptr(unsafe.Pointer(title))) } } - return nil + return end + 3, nil } // returns Atoi(s) unless s == "" in which case it returns def @@ -434,45 +169,58 @@ func atoiWithDefault(s string, def int) (int, error) { return strconv.Atoi(s) } +// splitParameters uses caller-provided storage for the usual short ANSI +// parameter lists, while still accepting arbitrarily long lists. +func splitParameters(s string, storage []string) []string { + n := strings.Count(s, ";") + 1 + if n > cap(storage) { + storage = make([]string, n) + } else { + storage = storage[:n] + } + for i := 0; i < n-1; i++ { + end := strings.IndexByte(s, ';') + storage[i] = s[:end] + s = s[end+1:] + } + storage[n-1] = s + return storage +} + // Write writes data on console func (w *writer) Write(data []byte) (n int, err error) { w.mutex.Lock() defer w.mutex.Unlock() - var csbi consoleScreenBufferInfo if w.rest.Len() == 0 && bytes.IndexByte(data, 0x1b) == -1 { w.out.Write(data) return len(data), nil } + var csbi consoleScreenBufferInfo handle := w.handle - var er *bytes.Reader + input := data if w.rest.Len() > 0 { - var rest bytes.Buffer - w.rest.WriteTo(&rest) + w.rest.Write(data) + input = w.rest.Bytes() w.rest.Reset() - rest.Write(data) - er = bytes.NewReader(rest.Bytes()) - } else { - er = bytes.NewReader(data) } - var plaintext bytes.Buffer + er := bytes.NewReader(input) loop: - for { - c1, err := er.ReadByte() - if err != nil { - plaintext.WriteTo(w.out) + for er.Len() > 0 { + remaining := input[len(input)-er.Len():] + escape := bytes.IndexByte(remaining, 0x1b) + if escape < 0 { + w.out.Write(remaining) break loop } - if c1 != 0x1b { - plaintext.WriteByte(c1) - continue - } - _, err = plaintext.WriteTo(w.out) - if err != nil { - break loop + if escape > 0 { + if n, err := w.out.Write(remaining[:escape]); err != nil || n != escape { + break loop + } } + er.Seek(int64(escape+1), io.SeekCurrent) c2, err := er.ReadByte() if err != nil { break loop @@ -482,26 +230,24 @@ loop: case '>': continue case ']': - w.rest.WriteByte(c1) - w.rest.WriteByte(c2) - er.WriteTo(&w.rest) - if bytes.IndexByte(w.rest.Bytes(), 0x07) == -1 { + if bytes.IndexByte(remaining[escape+2:], 0x07) == -1 { + w.rest.Write(remaining[escape:]) break loop } - er = bytes.NewReader(w.rest.Bytes()[2:]) - err := doTitleSequence(er) + consumed, err := doTitleSequence(remaining[escape+2:]) + er.Seek(int64(consumed), io.SeekCurrent) if err != nil { + w.rest.Write(remaining[escape:]) break loop } - w.rest.Reset() continue // https://github.com/mattn/go-colorable/issues/27 case '7': - procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + stdsyscall.SyscallN(procGetConsoleScreenBufferInfo.Addr(), uintptr(handle), uintptr(unsafe.Pointer(&csbi))) w.oldpos = csbi.cursorPosition continue case '8': - procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&w.oldpos))) + stdsyscall.SyscallN(procSetConsoleCursorPosition.Addr(), uintptr(handle), w.oldpos.param()) continue case 0x5b: // execute part after switch @@ -509,102 +255,103 @@ loop: continue } - w.rest.WriteByte(c1) - w.rest.WriteByte(c2) - er.WriteTo(&w.rest) - - var buf bytes.Buffer + // Keep complete sequences in the input slice. Only an unfinished + // sequence needs to be copied and retained for the next Write. + params := remaining[escape+2:] + var buf []byte var m byte - for i, c := range w.rest.Bytes()[2:] { + for i, c := range params { if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' { m = c - er = bytes.NewReader(w.rest.Bytes()[2+i+1:]) - w.rest.Reset() + buf = params[:i] + er.Seek(int64(i+1), io.SeekCurrent) break } - buf.WriteByte(c) } if m == 0 { + w.rest.Write(remaining[escape:]) break loop } switch m { case 'A': - n, err = atoiWithDefault(buf.String(), 1) + n, err = atoiWithDefault(string(buf), 1) if err != nil { continue } - procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + stdsyscall.SyscallN(procGetConsoleScreenBufferInfo.Addr(), uintptr(handle), uintptr(unsafe.Pointer(&csbi))) csbi.cursorPosition.y -= short(n) - procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + stdsyscall.SyscallN(procSetConsoleCursorPosition.Addr(), uintptr(handle), csbi.cursorPosition.param()) case 'B': - n, err = atoiWithDefault(buf.String(), 1) + n, err = atoiWithDefault(string(buf), 1) if err != nil { continue } - procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + stdsyscall.SyscallN(procGetConsoleScreenBufferInfo.Addr(), uintptr(handle), uintptr(unsafe.Pointer(&csbi))) csbi.cursorPosition.y += short(n) - procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + stdsyscall.SyscallN(procSetConsoleCursorPosition.Addr(), uintptr(handle), csbi.cursorPosition.param()) case 'C': - n, err = atoiWithDefault(buf.String(), 1) + n, err = atoiWithDefault(string(buf), 1) if err != nil { continue } - procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + stdsyscall.SyscallN(procGetConsoleScreenBufferInfo.Addr(), uintptr(handle), uintptr(unsafe.Pointer(&csbi))) csbi.cursorPosition.x += short(n) - procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + stdsyscall.SyscallN(procSetConsoleCursorPosition.Addr(), uintptr(handle), csbi.cursorPosition.param()) case 'D': - n, err = atoiWithDefault(buf.String(), 1) + n, err = atoiWithDefault(string(buf), 1) if err != nil { continue } - procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + stdsyscall.SyscallN(procGetConsoleScreenBufferInfo.Addr(), uintptr(handle), uintptr(unsafe.Pointer(&csbi))) csbi.cursorPosition.x -= short(n) if csbi.cursorPosition.x < 0 { csbi.cursorPosition.x = 0 } - procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + stdsyscall.SyscallN(procSetConsoleCursorPosition.Addr(), uintptr(handle), csbi.cursorPosition.param()) case 'E': - n, err = atoiWithDefault(buf.String(), 1) + n, err = atoiWithDefault(string(buf), 1) if err != nil { continue } - procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + stdsyscall.SyscallN(procGetConsoleScreenBufferInfo.Addr(), uintptr(handle), uintptr(unsafe.Pointer(&csbi))) csbi.cursorPosition.x = 0 csbi.cursorPosition.y += short(n) - procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + stdsyscall.SyscallN(procSetConsoleCursorPosition.Addr(), uintptr(handle), csbi.cursorPosition.param()) case 'F': - n, err = atoiWithDefault(buf.String(), 1) + n, err = atoiWithDefault(string(buf), 1) if err != nil { continue } - procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + stdsyscall.SyscallN(procGetConsoleScreenBufferInfo.Addr(), uintptr(handle), uintptr(unsafe.Pointer(&csbi))) csbi.cursorPosition.x = 0 csbi.cursorPosition.y -= short(n) - procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + stdsyscall.SyscallN(procSetConsoleCursorPosition.Addr(), uintptr(handle), csbi.cursorPosition.param()) case 'G': - n, err = strconv.Atoi(buf.String()) + n, err = strconv.Atoi(string(buf)) if err != nil { continue } if n < 1 { n = 1 } - procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + stdsyscall.SyscallN(procGetConsoleScreenBufferInfo.Addr(), uintptr(handle), uintptr(unsafe.Pointer(&csbi))) csbi.cursorPosition.x = short(n - 1) - procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + stdsyscall.SyscallN(procSetConsoleCursorPosition.Addr(), uintptr(handle), csbi.cursorPosition.param()) case 'H', 'f': - procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) - if buf.Len() > 0 { - token := strings.Split(buf.String(), ";") + if len(buf) > 0 { + var storage [8]string + token := splitParameters(string(buf), storage[:]) switch len(token) { case 1: n1, err := strconv.Atoi(token[0]) if err != nil { continue } + stdsyscall.SyscallN(procGetConsoleScreenBufferInfo.Addr(), uintptr(handle), uintptr(unsafe.Pointer(&csbi))) csbi.cursorPosition.y = short(n1 - 1) case 2: + // Both coordinates are absolute; no console query is needed. n1, err := strconv.Atoi(token[0]) if err != nil { continue @@ -615,22 +362,25 @@ loop: } csbi.cursorPosition.x = short(n2 - 1) csbi.cursorPosition.y = short(n1 - 1) + default: + stdsyscall.SyscallN(procGetConsoleScreenBufferInfo.Addr(), uintptr(handle), uintptr(unsafe.Pointer(&csbi))) } } else { + stdsyscall.SyscallN(procGetConsoleScreenBufferInfo.Addr(), uintptr(handle), uintptr(unsafe.Pointer(&csbi))) csbi.cursorPosition.y = 0 } - procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) + stdsyscall.SyscallN(procSetConsoleCursorPosition.Addr(), uintptr(handle), csbi.cursorPosition.param()) case 'J': n := 0 - if buf.Len() > 0 { - n, err = strconv.Atoi(buf.String()) + if len(buf) > 0 { + n, err = strconv.Atoi(string(buf)) if err != nil { continue } } var count, written dword var cursor coord - procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + stdsyscall.SyscallN(procGetConsoleScreenBufferInfo.Addr(), uintptr(handle), uintptr(unsafe.Pointer(&csbi))) switch n { case 0: cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y} @@ -642,17 +392,17 @@ loop: cursor = coord{x: csbi.window.left, y: csbi.window.top} count = dword(csbi.size.x) - dword(csbi.cursorPosition.x) + dword(csbi.size.y-csbi.cursorPosition.y)*dword(csbi.size.x) } - procFillConsoleOutputCharacter.Call(uintptr(handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) - procFillConsoleOutputAttribute.Call(uintptr(handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) + stdsyscall.SyscallN(procFillConsoleOutputCharacter.Addr(), uintptr(handle), uintptr(' '), uintptr(count), cursor.param(), uintptr(unsafe.Pointer(&written))) + stdsyscall.SyscallN(procFillConsoleOutputAttribute.Addr(), uintptr(handle), uintptr(csbi.attributes), uintptr(count), cursor.param(), uintptr(unsafe.Pointer(&written))) case 'K': n := 0 - if buf.Len() > 0 { - n, err = strconv.Atoi(buf.String()) + if len(buf) > 0 { + n, err = strconv.Atoi(string(buf)) if err != nil { continue } } - procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + stdsyscall.SyscallN(procGetConsoleScreenBufferInfo.Addr(), uintptr(handle), uintptr(unsafe.Pointer(&csbi))) var cursor coord var count, written dword switch n { @@ -666,31 +416,34 @@ loop: cursor = coord{x: csbi.window.left, y: csbi.cursorPosition.y} count = dword(csbi.size.x) } - procFillConsoleOutputCharacter.Call(uintptr(handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) - procFillConsoleOutputAttribute.Call(uintptr(handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) + stdsyscall.SyscallN(procFillConsoleOutputCharacter.Addr(), uintptr(handle), uintptr(' '), uintptr(count), cursor.param(), uintptr(unsafe.Pointer(&written))) + stdsyscall.SyscallN(procFillConsoleOutputAttribute.Addr(), uintptr(handle), uintptr(csbi.attributes), uintptr(count), cursor.param(), uintptr(unsafe.Pointer(&written))) case 'X': n := 0 - if buf.Len() > 0 { - n, err = strconv.Atoi(buf.String()) + if len(buf) > 0 { + n, err = strconv.Atoi(string(buf)) if err != nil { continue } } - procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + stdsyscall.SyscallN(procGetConsoleScreenBufferInfo.Addr(), uintptr(handle), uintptr(unsafe.Pointer(&csbi))) var cursor coord var written dword cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y} - procFillConsoleOutputCharacter.Call(uintptr(handle), uintptr(' '), uintptr(n), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) - procFillConsoleOutputAttribute.Call(uintptr(handle), uintptr(csbi.attributes), uintptr(n), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) + stdsyscall.SyscallN(procFillConsoleOutputCharacter.Addr(), uintptr(handle), uintptr(' '), uintptr(n), cursor.param(), uintptr(unsafe.Pointer(&written))) + stdsyscall.SyscallN(procFillConsoleOutputAttribute.Addr(), uintptr(handle), uintptr(csbi.attributes), uintptr(n), cursor.param(), uintptr(unsafe.Pointer(&written))) case 'm': attr := w.curattr - cs := buf.String() + cs := string(buf) if cs == "" { - procSetConsoleTextAttribute.Call(uintptr(handle), uintptr(w.oldattr)) - w.curattr = w.oldattr + if w.curattr != w.oldattr { + stdsyscall.SyscallN(procSetConsoleTextAttribute.Addr(), uintptr(handle), uintptr(w.oldattr)) + w.curattr = w.oldattr + } continue } - token := strings.Split(cs, ";") + var storage [8]string + token := splitParameters(cs, storage[:]) for i := 0; i < len(token); i++ { ns := token[i] if n, err = strconv.Atoi(ns); err == nil { @@ -724,9 +477,7 @@ loop: case n == 38: // set foreground color. if i < len(token)-2 && (token[i+1] == "5" || token[i+1] == "05") { if n256, err := strconv.Atoi(token[i+2]); err == nil { - if n256foreAttr == nil { - n256setup() - } + attr &= backgroundMask attr |= n256foreAttr[n256%len(n256foreAttr)] i += 2 @@ -766,11 +517,9 @@ loop: case n == 48: // set background color. if i < len(token)-2 && token[i+1] == "5" { if n256, err := strconv.Atoi(token[i+2]); err == nil { - if n256backAttr == nil { - n256setup() - } + attr &= foregroundMask - attr |= n256backAttr[n256%len(n256backAttr)] + attr |= (n256foreAttr[n256%len(n256foreAttr)] << 4) i += 2 } } else if len(token) == 5 && token[i+1] == "2" { @@ -822,233 +571,73 @@ loop: } } if attr != w.curattr { - procSetConsoleTextAttribute.Call(uintptr(handle), uintptr(attr)) + stdsyscall.SyscallN(procSetConsoleTextAttribute.Addr(), uintptr(handle), uintptr(attr)) w.curattr = attr } case 'h': var ci consoleCursorInfo - cs := buf.String() + cs := string(buf) if cs == "5>" { - procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) + stdsyscall.SyscallN(procGetConsoleCursorInfo.Addr(), uintptr(handle), uintptr(unsafe.Pointer(&ci))) ci.visible = 0 - procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) + stdsyscall.SyscallN(procSetConsoleCursorInfo.Addr(), uintptr(handle), uintptr(unsafe.Pointer(&ci))) } else if cs == "?25" { - procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) + stdsyscall.SyscallN(procGetConsoleCursorInfo.Addr(), uintptr(handle), uintptr(unsafe.Pointer(&ci))) ci.visible = 1 - procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) + stdsyscall.SyscallN(procSetConsoleCursorInfo.Addr(), uintptr(handle), uintptr(unsafe.Pointer(&ci))) } else if cs == "?1049" { if w.althandle == 0 { - h, _, _ := procCreateConsoleScreenBuffer.Call(uintptr(genericRead|genericWrite), 0, 0, uintptr(consoleTextmodeBuffer), 0, 0) + h, _, _ := stdsyscall.SyscallN(procCreateConsoleScreenBuffer.Addr(), uintptr(genericRead|genericWrite), 0, 0, uintptr(consoleTextmodeBuffer), 0, 0) w.althandle = syscall.Handle(h) if w.althandle != 0 { handle = w.althandle - procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + stdsyscall.SyscallN(procGetConsoleScreenBufferInfo.Addr(), uintptr(handle), uintptr(unsafe.Pointer(&csbi))) w.curattr = csbi.attributes } } } case 'l': var ci consoleCursorInfo - cs := buf.String() + cs := string(buf) if cs == "5>" { - procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) + stdsyscall.SyscallN(procGetConsoleCursorInfo.Addr(), uintptr(handle), uintptr(unsafe.Pointer(&ci))) ci.visible = 1 - procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) + stdsyscall.SyscallN(procSetConsoleCursorInfo.Addr(), uintptr(handle), uintptr(unsafe.Pointer(&ci))) } else if cs == "?25" { - procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) + stdsyscall.SyscallN(procGetConsoleCursorInfo.Addr(), uintptr(handle), uintptr(unsafe.Pointer(&ci))) ci.visible = 0 - procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) + stdsyscall.SyscallN(procSetConsoleCursorInfo.Addr(), uintptr(handle), uintptr(unsafe.Pointer(&ci))) } else if cs == "?1049" { if w.althandle != 0 { syscall.CloseHandle(w.althandle) w.althandle = 0 handle = w.handle - procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + stdsyscall.SyscallN(procGetConsoleScreenBufferInfo.Addr(), uintptr(handle), uintptr(unsafe.Pointer(&csbi))) w.curattr = csbi.attributes } } case 's': - procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) + stdsyscall.SyscallN(procGetConsoleScreenBufferInfo.Addr(), uintptr(handle), uintptr(unsafe.Pointer(&csbi))) w.oldpos = csbi.cursorPosition case 'u': - procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&w.oldpos))) + stdsyscall.SyscallN(procSetConsoleCursorPosition.Addr(), uintptr(handle), w.oldpos.param()) } } return len(data), nil } -type consoleColor struct { - rgb int - red bool - green bool - blue bool - intensity bool -} - -func (c consoleColor) foregroundAttr() (attr word) { - if c.red { - attr |= foregroundRed - } - if c.green { - attr |= foregroundGreen - } - if c.blue { - attr |= foregroundBlue - } - if c.intensity { - attr |= foregroundIntensity - } - return -} - -func (c consoleColor) backgroundAttr() (attr word) { - if c.red { - attr |= backgroundRed - } - if c.green { - attr |= backgroundGreen - } - if c.blue { - attr |= backgroundBlue - } - if c.intensity { - attr |= backgroundIntensity - } - return -} - -var color16 = []consoleColor{ - {0x000000, false, false, false, false}, - {0x000080, false, false, true, false}, - {0x008000, false, true, false, false}, - {0x008080, false, true, true, false}, - {0x800000, true, false, false, false}, - {0x800080, true, false, true, false}, - {0x808000, true, true, false, false}, - {0xc0c0c0, true, true, true, false}, - {0x808080, false, false, false, true}, - {0x0000ff, false, false, true, true}, - {0x00ff00, false, true, false, true}, - {0x00ffff, false, true, true, true}, - {0xff0000, true, false, false, true}, - {0xff00ff, true, false, true, true}, - {0xffff00, true, true, false, true}, - {0xffffff, true, true, true, true}, -} - -type hsv struct { - h, s, v float32 -} - -func (a hsv) dist(b hsv) float32 { - dh := a.h - b.h - switch { - case dh > 0.5: - dh = 1 - dh - case dh < -0.5: - dh = -1 - dh - } - ds := a.s - b.s - dv := a.v - b.v - return float32(math.Sqrt(float64(dh*dh + ds*ds + dv*dv))) -} - -func toHSV(rgb int) hsv { - r, g, b := float32((rgb&0xFF0000)>>16)/256.0, - float32((rgb&0x00FF00)>>8)/256.0, - float32(rgb&0x0000FF)/256.0 - min, max := minmax3f(r, g, b) - h := max - min - if h > 0 { - if max == r { - h = (g - b) / h - if h < 0 { - h += 6 - } - } else if max == g { - h = 2 + (b-r)/h - } else { - h = 4 + (r-g)/h - } - } - h /= 6.0 - s := max - min - if max != 0 { - s /= max - } - v := max - return hsv{h: h, s: s, v: v} -} - -type hsvTable []hsv - -func toHSVTable(rgbTable []consoleColor) hsvTable { - t := make(hsvTable, len(rgbTable)) - for i, c := range rgbTable { - t[i] = toHSV(c.rgb) - } - return t -} - -func (t hsvTable) find(rgb int) consoleColor { - hsv := toHSV(rgb) - n := 7 - l := float32(5.0) - for i, p := range t { - d := hsv.dist(p) - if d < l { - l, n = d, i - } - } - return color16[n] -} - -func minmax3f(a, b, c float32) (min, max float32) { - if a < b { - if b < c { - return a, c - } else if a < c { - return a, b - } else { - return c, b - } - } else { - if a < c { - return b, c - } else if b < c { - return b, a - } else { - return c, a - } - } -} - -var n256foreAttr []word -var n256backAttr []word - -func n256setup() { - n256foreAttr = make([]word, 256) - n256backAttr = make([]word, 256) - t := toHSVTable(color16) - for i, rgb := range color256 { - c := t.find(rgb) - n256foreAttr[i] = c.foregroundAttr() - n256backAttr[i] = c.backgroundAttr() - } -} - // EnableColorsStdout enable colors if possible. func EnableColorsStdout(enabled *bool) func() { var mode uint32 h := os.Stdout.Fd() - if r, _, _ := procGetConsoleMode.Call(h, uintptr(unsafe.Pointer(&mode))); r != 0 { - if r, _, _ = procSetConsoleMode.Call(h, uintptr(mode|cENABLE_VIRTUAL_TERMINAL_PROCESSING)); r != 0 { + if r, _, _ := stdsyscall.SyscallN(procGetConsoleMode.Addr(), h, uintptr(unsafe.Pointer(&mode))); r != 0 { + if r, _, _ = stdsyscall.SyscallN(procSetConsoleMode.Addr(), h, uintptr(mode|cENABLE_VIRTUAL_TERMINAL_PROCESSING)); r != 0 { if enabled != nil { *enabled = true } return func() { - procSetConsoleMode.Call(h, uintptr(mode)) + stdsyscall.SyscallN(procSetConsoleMode.Addr(), h, uintptr(mode)) } } } diff --git a/vendor/github.com/mattn/go-colorable/colorable_windows_palette.go b/vendor/github.com/mattn/go-colorable/colorable_windows_palette.go new file mode 100644 index 00000000..349b0a82 --- /dev/null +++ b/vendor/github.com/mattn/go-colorable/colorable_windows_palette.go @@ -0,0 +1,25 @@ +//go:build windows && !appengine +// +build windows,!appengine + +package colorable + +// n256foreAttr maps the xterm palette to the nearest Windows console color. +// TestWindowsPalette verifies every entry against the HSV conversion. +var n256foreAttr = [256]word{ + 0x00, 0x04, 0x02, 0x06, 0x01, 0x05, 0x03, 0x07, 0x08, 0x0c, 0x0a, 0x0e, 0x09, 0x0d, 0x0b, 0x0f, + 0x00, 0x01, 0x01, 0x01, 0x09, 0x09, 0x02, 0x03, 0x03, 0x03, 0x09, 0x09, 0x02, 0x03, 0x03, 0x03, + 0x0b, 0x0b, 0x02, 0x03, 0x03, 0x03, 0x0b, 0x0b, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0a, 0x0a, + 0x0b, 0x0b, 0x0b, 0x0b, 0x04, 0x05, 0x05, 0x05, 0x09, 0x09, 0x06, 0x08, 0x08, 0x07, 0x09, 0x09, + 0x06, 0x08, 0x08, 0x01, 0x09, 0x09, 0x06, 0x07, 0x02, 0x03, 0x0b, 0x09, 0x0a, 0x0a, 0x0a, 0x0b, + 0x0b, 0x0b, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x04, 0x05, 0x05, 0x05, 0x0d, 0x0d, 0x06, 0x08, + 0x08, 0x07, 0x09, 0x09, 0x06, 0x08, 0x08, 0x07, 0x07, 0x09, 0x06, 0x07, 0x07, 0x07, 0x07, 0x09, + 0x0e, 0x0a, 0x07, 0x07, 0x07, 0x0b, 0x0e, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x04, 0x05, 0x05, 0x05, + 0x0d, 0x0d, 0x06, 0x07, 0x07, 0x07, 0x0d, 0x09, 0x06, 0x07, 0x07, 0x07, 0x07, 0x09, 0x06, 0x07, + 0x07, 0x07, 0x07, 0x0f, 0x0e, 0x0e, 0x07, 0x07, 0x07, 0x0f, 0x0e, 0x0a, 0x0a, 0x0f, 0x0f, 0x0f, + 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0e, 0x0c, 0x07, 0x07, + 0x07, 0x0f, 0x0e, 0x0e, 0x07, 0x07, 0x07, 0x0f, 0x0e, 0x0e, 0x07, 0x07, 0x07, 0x0f, 0x0e, 0x0e, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, + 0x0e, 0x0c, 0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x0c, 0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x0f, 0x0f, +} diff --git a/vendor/github.com/mattn/go-colorable/noncolorable.go b/vendor/github.com/mattn/go-colorable/noncolorable.go index 05d6f74b..4ddd5a7c 100644 --- a/vendor/github.com/mattn/go-colorable/noncolorable.go +++ b/vendor/github.com/mattn/go-colorable/noncolorable.go @@ -17,36 +17,30 @@ func NewNonColorable(w io.Writer) io.Writer { // Write writes data on console func (w *NonColorable) Write(data []byte) (n int, err error) { - er := bytes.NewReader(data) - var plaintext bytes.Buffer -loop: - for { - c1, err := er.ReadByte() - if err != nil { - plaintext.WriteTo(w.out) - break loop + for offset := 0; offset < len(data); { + escape := bytes.IndexByte(data[offset:], 0x1b) + if escape < 0 { + w.out.Write(data[offset:]) + break } - if c1 != 0x1b { - plaintext.WriteByte(c1) - continue - } - _, err = plaintext.WriteTo(w.out) - if err != nil { - break loop + if escape > 0 { + if n, err := w.out.Write(data[offset : offset+escape]); err != nil || n != escape { + break + } } - c2, err := er.ReadByte() - if err != nil { - break loop + offset += escape + 1 + if offset == len(data) { + break } + c2 := data[offset] + offset++ if c2 != 0x5b { continue } - for { - c, err := er.ReadByte() - if err != nil { - break loop - } + for offset < len(data) { + c := data[offset] + offset++ if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' { break } diff --git a/vendor/modules.txt b/vendor/modules.txt index c81c8d7b..b5b0da5b 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -134,7 +134,7 @@ github.com/kballard/go-shellquote # github.com/lucasb-eyer/go-colorful v1.4.0 ## explicit; go 1.12 github.com/lucasb-eyer/go-colorful -# github.com/mattn/go-colorable v0.1.15 +# github.com/mattn/go-colorable v0.1.16 ## explicit; go 1.18 github.com/mattn/go-colorable # github.com/mattn/go-isatty v0.0.24