Path: blob/main/vendor/github.com/chzyer/readline/ansi_windows.go
2875 views
// +build windows12package readline34import (5"bufio"6"io"7"strconv"8"strings"9"sync"10"unicode/utf8"11"unsafe"12)1314const (15_ = uint16(0)16COLOR_FBLUE = 0x000117COLOR_FGREEN = 0x000218COLOR_FRED = 0x000419COLOR_FINTENSITY = 0x00082021COLOR_BBLUE = 0x001022COLOR_BGREEN = 0x002023COLOR_BRED = 0x004024COLOR_BINTENSITY = 0x00802526COMMON_LVB_UNDERSCORE = 0x800027COMMON_LVB_BOLD = 0x000728)2930var ColorTableFg = []word{310, // 30: Black32COLOR_FRED, // 31: Red33COLOR_FGREEN, // 32: Green34COLOR_FRED | COLOR_FGREEN, // 33: Yellow35COLOR_FBLUE, // 34: Blue36COLOR_FRED | COLOR_FBLUE, // 35: Magenta37COLOR_FGREEN | COLOR_FBLUE, // 36: Cyan38COLOR_FRED | COLOR_FBLUE | COLOR_FGREEN, // 37: White39}4041var ColorTableBg = []word{420, // 40: Black43COLOR_BRED, // 41: Red44COLOR_BGREEN, // 42: Green45COLOR_BRED | COLOR_BGREEN, // 43: Yellow46COLOR_BBLUE, // 44: Blue47COLOR_BRED | COLOR_BBLUE, // 45: Magenta48COLOR_BGREEN | COLOR_BBLUE, // 46: Cyan49COLOR_BRED | COLOR_BBLUE | COLOR_BGREEN, // 47: White50}5152type ANSIWriter struct {53target io.Writer54wg sync.WaitGroup55ctx *ANSIWriterCtx56sync.Mutex57}5859func NewANSIWriter(w io.Writer) *ANSIWriter {60a := &ANSIWriter{61target: w,62ctx: NewANSIWriterCtx(w),63}64return a65}6667func (a *ANSIWriter) Close() error {68a.wg.Wait()69return nil70}7172type ANSIWriterCtx struct {73isEsc bool74isEscSeq bool75arg []string76target *bufio.Writer77wantFlush bool78}7980func NewANSIWriterCtx(target io.Writer) *ANSIWriterCtx {81return &ANSIWriterCtx{82target: bufio.NewWriter(target),83}84}8586func (a *ANSIWriterCtx) Flush() {87a.target.Flush()88}8990func (a *ANSIWriterCtx) process(r rune) bool {91if a.wantFlush {92if r == 0 || r == CharEsc {93a.wantFlush = false94a.target.Flush()95}96}97if a.isEscSeq {98a.isEscSeq = a.ioloopEscSeq(a.target, r, &a.arg)99return true100}101102switch r {103case CharEsc:104a.isEsc = true105case '[':106if a.isEsc {107a.arg = nil108a.isEscSeq = true109a.isEsc = false110break111}112fallthrough113default:114a.target.WriteRune(r)115a.wantFlush = true116}117return true118}119120func (a *ANSIWriterCtx) ioloopEscSeq(w *bufio.Writer, r rune, argptr *[]string) bool {121arg := *argptr122var err error123124if r >= 'A' && r <= 'D' {125count := short(GetInt(arg, 1))126info, err := GetConsoleScreenBufferInfo()127if err != nil {128return false129}130switch r {131case 'A': // up132info.dwCursorPosition.y -= count133case 'B': // down134info.dwCursorPosition.y += count135case 'C': // right136info.dwCursorPosition.x += count137case 'D': // left138info.dwCursorPosition.x -= count139}140SetConsoleCursorPosition(&info.dwCursorPosition)141return false142}143144switch r {145case 'J':146killLines()147case 'K':148eraseLine()149case 'm':150color := word(0)151for _, item := range arg {152var c int153c, err = strconv.Atoi(item)154if err != nil {155w.WriteString("[" + strings.Join(arg, ";") + "m")156break157}158if c >= 30 && c < 40 {159color ^= COLOR_FINTENSITY160color |= ColorTableFg[c-30]161} else if c >= 40 && c < 50 {162color ^= COLOR_BINTENSITY163color |= ColorTableBg[c-40]164} else if c == 4 {165color |= COMMON_LVB_UNDERSCORE | ColorTableFg[7]166} else if c == 1 {167color |= COMMON_LVB_BOLD | COLOR_FINTENSITY168} else { // unknown code treat as reset169color = ColorTableFg[7]170}171}172if err != nil {173break174}175kernel.SetConsoleTextAttribute(stdout, uintptr(color))176case '\007': // set title177case ';':178if len(arg) == 0 || arg[len(arg)-1] != "" {179arg = append(arg, "")180*argptr = arg181}182return true183default:184if len(arg) == 0 {185arg = append(arg, "")186}187arg[len(arg)-1] += string(r)188*argptr = arg189return true190}191*argptr = nil192return false193}194195func (a *ANSIWriter) Write(b []byte) (int, error) {196a.Lock()197defer a.Unlock()198199off := 0200for len(b) > off {201r, size := utf8.DecodeRune(b[off:])202if size == 0 {203return off, io.ErrShortWrite204}205off += size206a.ctx.process(r)207}208a.ctx.Flush()209return off, nil210}211212func killLines() error {213sbi, err := GetConsoleScreenBufferInfo()214if err != nil {215return err216}217218size := (sbi.dwCursorPosition.y - sbi.dwSize.y) * sbi.dwSize.x219size += sbi.dwCursorPosition.x220221var written int222kernel.FillConsoleOutputAttribute(stdout, uintptr(ColorTableFg[7]),223uintptr(size),224sbi.dwCursorPosition.ptr(),225uintptr(unsafe.Pointer(&written)),226)227return kernel.FillConsoleOutputCharacterW(stdout, uintptr(' '),228uintptr(size),229sbi.dwCursorPosition.ptr(),230uintptr(unsafe.Pointer(&written)),231)232}233234func eraseLine() error {235sbi, err := GetConsoleScreenBufferInfo()236if err != nil {237return err238}239240size := sbi.dwSize.x241sbi.dwCursorPosition.x = 0242var written int243return kernel.FillConsoleOutputCharacterW(stdout, uintptr(' '),244uintptr(size),245sbi.dwCursorPosition.ptr(),246uintptr(unsafe.Pointer(&written)),247)248}249250251