mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-11-04 10:03:42 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			744 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			744 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// +build windows
 | 
						|
 | 
						|
package winterm
 | 
						|
 | 
						|
import (
 | 
						|
	"bytes"
 | 
						|
	"log"
 | 
						|
	"os"
 | 
						|
	"strconv"
 | 
						|
 | 
						|
	"github.com/Azure/go-ansiterm"
 | 
						|
)
 | 
						|
 | 
						|
type windowsAnsiEventHandler struct {
 | 
						|
	fd             uintptr
 | 
						|
	file           *os.File
 | 
						|
	infoReset      *CONSOLE_SCREEN_BUFFER_INFO
 | 
						|
	sr             scrollRegion
 | 
						|
	buffer         bytes.Buffer
 | 
						|
	attributes     uint16
 | 
						|
	inverted       bool
 | 
						|
	wrapNext       bool
 | 
						|
	drewMarginByte bool
 | 
						|
	originMode     bool
 | 
						|
	marginByte     byte
 | 
						|
	curInfo        *CONSOLE_SCREEN_BUFFER_INFO
 | 
						|
	curPos         COORD
 | 
						|
	logf           func(string, ...interface{})
 | 
						|
}
 | 
						|
 | 
						|
type Option func(*windowsAnsiEventHandler)
 | 
						|
 | 
						|
func WithLogf(f func(string, ...interface{})) Option {
 | 
						|
	return func(w *windowsAnsiEventHandler) {
 | 
						|
		w.logf = f
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func CreateWinEventHandler(fd uintptr, file *os.File, opts ...Option) ansiterm.AnsiEventHandler {
 | 
						|
	infoReset, err := GetConsoleScreenBufferInfo(fd)
 | 
						|
	if err != nil {
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
 | 
						|
	h := &windowsAnsiEventHandler{
 | 
						|
		fd:         fd,
 | 
						|
		file:       file,
 | 
						|
		infoReset:  infoReset,
 | 
						|
		attributes: infoReset.Attributes,
 | 
						|
	}
 | 
						|
	for _, o := range opts {
 | 
						|
		o(h)
 | 
						|
	}
 | 
						|
 | 
						|
	if isDebugEnv := os.Getenv(ansiterm.LogEnv); isDebugEnv == "1" {
 | 
						|
		logFile, _ := os.Create("winEventHandler.log")
 | 
						|
		logger := log.New(logFile, "", log.LstdFlags)
 | 
						|
		if h.logf != nil {
 | 
						|
			l := h.logf
 | 
						|
			h.logf = func(s string, v ...interface{}) {
 | 
						|
				l(s, v...)
 | 
						|
				logger.Printf(s, v...)
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			h.logf = logger.Printf
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if h.logf == nil {
 | 
						|
		h.logf = func(string, ...interface{}) {}
 | 
						|
	}
 | 
						|
 | 
						|
	return h
 | 
						|
}
 | 
						|
 | 
						|
type scrollRegion struct {
 | 
						|
	top    int16
 | 
						|
	bottom int16
 | 
						|
}
 | 
						|
 | 
						|
// simulateLF simulates a LF or CR+LF by scrolling if necessary to handle the
 | 
						|
// current cursor position and scroll region settings, in which case it returns
 | 
						|
// true. If no special handling is necessary, then it does nothing and returns
 | 
						|
// false.
 | 
						|
//
 | 
						|
// In the false case, the caller should ensure that a carriage return
 | 
						|
// and line feed are inserted or that the text is otherwise wrapped.
 | 
						|
func (h *windowsAnsiEventHandler) simulateLF(includeCR bool) (bool, error) {
 | 
						|
	if h.wrapNext {
 | 
						|
		if err := h.Flush(); err != nil {
 | 
						|
			return false, err
 | 
						|
		}
 | 
						|
		h.clearWrap()
 | 
						|
	}
 | 
						|
	pos, info, err := h.getCurrentInfo()
 | 
						|
	if err != nil {
 | 
						|
		return false, err
 | 
						|
	}
 | 
						|
	sr := h.effectiveSr(info.Window)
 | 
						|
	if pos.Y == sr.bottom {
 | 
						|
		// Scrolling is necessary. Let Windows automatically scroll if the scrolling region
 | 
						|
		// is the full window.
 | 
						|
		if sr.top == info.Window.Top && sr.bottom == info.Window.Bottom {
 | 
						|
			if includeCR {
 | 
						|
				pos.X = 0
 | 
						|
				h.updatePos(pos)
 | 
						|
			}
 | 
						|
			return false, nil
 | 
						|
		}
 | 
						|
 | 
						|
		// A custom scroll region is active. Scroll the window manually to simulate
 | 
						|
		// the LF.
 | 
						|
		if err := h.Flush(); err != nil {
 | 
						|
			return false, err
 | 
						|
		}
 | 
						|
		h.logf("Simulating LF inside scroll region")
 | 
						|
		if err := h.scrollUp(1); err != nil {
 | 
						|
			return false, err
 | 
						|
		}
 | 
						|
		if includeCR {
 | 
						|
			pos.X = 0
 | 
						|
			if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
 | 
						|
				return false, err
 | 
						|
			}
 | 
						|
		}
 | 
						|
		return true, nil
 | 
						|
 | 
						|
	} else if pos.Y < info.Window.Bottom {
 | 
						|
		// Let Windows handle the LF.
 | 
						|
		pos.Y++
 | 
						|
		if includeCR {
 | 
						|
			pos.X = 0
 | 
						|
		}
 | 
						|
		h.updatePos(pos)
 | 
						|
		return false, nil
 | 
						|
	} else {
 | 
						|
		// The cursor is at the bottom of the screen but outside the scroll
 | 
						|
		// region. Skip the LF.
 | 
						|
		h.logf("Simulating LF outside scroll region")
 | 
						|
		if includeCR {
 | 
						|
			if err := h.Flush(); err != nil {
 | 
						|
				return false, err
 | 
						|
			}
 | 
						|
			pos.X = 0
 | 
						|
			if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
 | 
						|
				return false, err
 | 
						|
			}
 | 
						|
		}
 | 
						|
		return true, nil
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// executeLF executes a LF without a CR.
 | 
						|
func (h *windowsAnsiEventHandler) executeLF() error {
 | 
						|
	handled, err := h.simulateLF(false)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	if !handled {
 | 
						|
		// Windows LF will reset the cursor column position. Write the LF
 | 
						|
		// and restore the cursor position.
 | 
						|
		pos, _, err := h.getCurrentInfo()
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		h.buffer.WriteByte(ansiterm.ANSI_LINE_FEED)
 | 
						|
		if pos.X != 0 {
 | 
						|
			if err := h.Flush(); err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
			h.logf("Resetting cursor position for LF without CR")
 | 
						|
			if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (h *windowsAnsiEventHandler) Print(b byte) error {
 | 
						|
	if h.wrapNext {
 | 
						|
		h.buffer.WriteByte(h.marginByte)
 | 
						|
		h.clearWrap()
 | 
						|
		if _, err := h.simulateLF(true); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
	pos, info, err := h.getCurrentInfo()
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	if pos.X == info.Size.X-1 {
 | 
						|
		h.wrapNext = true
 | 
						|
		h.marginByte = b
 | 
						|
	} else {
 | 
						|
		pos.X++
 | 
						|
		h.updatePos(pos)
 | 
						|
		h.buffer.WriteByte(b)
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (h *windowsAnsiEventHandler) Execute(b byte) error {
 | 
						|
	switch b {
 | 
						|
	case ansiterm.ANSI_TAB:
 | 
						|
		h.logf("Execute(TAB)")
 | 
						|
		// Move to the next tab stop, but preserve auto-wrap if already set.
 | 
						|
		if !h.wrapNext {
 | 
						|
			pos, info, err := h.getCurrentInfo()
 | 
						|
			if err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
			pos.X = (pos.X + 8) - pos.X%8
 | 
						|
			if pos.X >= info.Size.X {
 | 
						|
				pos.X = info.Size.X - 1
 | 
						|
			}
 | 
						|
			if err := h.Flush(); err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
			if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
		}
 | 
						|
		return nil
 | 
						|
 | 
						|
	case ansiterm.ANSI_BEL:
 | 
						|
		h.buffer.WriteByte(ansiterm.ANSI_BEL)
 | 
						|
		return nil
 | 
						|
 | 
						|
	case ansiterm.ANSI_BACKSPACE:
 | 
						|
		if h.wrapNext {
 | 
						|
			if err := h.Flush(); err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
			h.clearWrap()
 | 
						|
		}
 | 
						|
		pos, _, err := h.getCurrentInfo()
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		if pos.X > 0 {
 | 
						|
			pos.X--
 | 
						|
			h.updatePos(pos)
 | 
						|
			h.buffer.WriteByte(ansiterm.ANSI_BACKSPACE)
 | 
						|
		}
 | 
						|
		return nil
 | 
						|
 | 
						|
	case ansiterm.ANSI_VERTICAL_TAB, ansiterm.ANSI_FORM_FEED:
 | 
						|
		// Treat as true LF.
 | 
						|
		return h.executeLF()
 | 
						|
 | 
						|
	case ansiterm.ANSI_LINE_FEED:
 | 
						|
		// Simulate a CR and LF for now since there is no way in go-ansiterm
 | 
						|
		// to tell if the LF should include CR (and more things break when it's
 | 
						|
		// missing than when it's incorrectly added).
 | 
						|
		handled, err := h.simulateLF(true)
 | 
						|
		if handled || err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		return h.buffer.WriteByte(ansiterm.ANSI_LINE_FEED)
 | 
						|
 | 
						|
	case ansiterm.ANSI_CARRIAGE_RETURN:
 | 
						|
		if h.wrapNext {
 | 
						|
			if err := h.Flush(); err != nil {
 | 
						|
				return err
 | 
						|
			}
 | 
						|
			h.clearWrap()
 | 
						|
		}
 | 
						|
		pos, _, err := h.getCurrentInfo()
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		if pos.X != 0 {
 | 
						|
			pos.X = 0
 | 
						|
			h.updatePos(pos)
 | 
						|
			h.buffer.WriteByte(ansiterm.ANSI_CARRIAGE_RETURN)
 | 
						|
		}
 | 
						|
		return nil
 | 
						|
 | 
						|
	default:
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (h *windowsAnsiEventHandler) CUU(param int) error {
 | 
						|
	if err := h.Flush(); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	h.logf("CUU: [%v]", []string{strconv.Itoa(param)})
 | 
						|
	h.clearWrap()
 | 
						|
	return h.moveCursorVertical(-param)
 | 
						|
}
 | 
						|
 | 
						|
func (h *windowsAnsiEventHandler) CUD(param int) error {
 | 
						|
	if err := h.Flush(); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	h.logf("CUD: [%v]", []string{strconv.Itoa(param)})
 | 
						|
	h.clearWrap()
 | 
						|
	return h.moveCursorVertical(param)
 | 
						|
}
 | 
						|
 | 
						|
func (h *windowsAnsiEventHandler) CUF(param int) error {
 | 
						|
	if err := h.Flush(); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	h.logf("CUF: [%v]", []string{strconv.Itoa(param)})
 | 
						|
	h.clearWrap()
 | 
						|
	return h.moveCursorHorizontal(param)
 | 
						|
}
 | 
						|
 | 
						|
func (h *windowsAnsiEventHandler) CUB(param int) error {
 | 
						|
	if err := h.Flush(); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	h.logf("CUB: [%v]", []string{strconv.Itoa(param)})
 | 
						|
	h.clearWrap()
 | 
						|
	return h.moveCursorHorizontal(-param)
 | 
						|
}
 | 
						|
 | 
						|
func (h *windowsAnsiEventHandler) CNL(param int) error {
 | 
						|
	if err := h.Flush(); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	h.logf("CNL: [%v]", []string{strconv.Itoa(param)})
 | 
						|
	h.clearWrap()
 | 
						|
	return h.moveCursorLine(param)
 | 
						|
}
 | 
						|
 | 
						|
func (h *windowsAnsiEventHandler) CPL(param int) error {
 | 
						|
	if err := h.Flush(); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	h.logf("CPL: [%v]", []string{strconv.Itoa(param)})
 | 
						|
	h.clearWrap()
 | 
						|
	return h.moveCursorLine(-param)
 | 
						|
}
 | 
						|
 | 
						|
func (h *windowsAnsiEventHandler) CHA(param int) error {
 | 
						|
	if err := h.Flush(); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	h.logf("CHA: [%v]", []string{strconv.Itoa(param)})
 | 
						|
	h.clearWrap()
 | 
						|
	return h.moveCursorColumn(param)
 | 
						|
}
 | 
						|
 | 
						|
func (h *windowsAnsiEventHandler) VPA(param int) error {
 | 
						|
	if err := h.Flush(); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	h.logf("VPA: [[%d]]", param)
 | 
						|
	h.clearWrap()
 | 
						|
	info, err := GetConsoleScreenBufferInfo(h.fd)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	window := h.getCursorWindow(info)
 | 
						|
	position := info.CursorPosition
 | 
						|
	position.Y = window.Top + int16(param) - 1
 | 
						|
	return h.setCursorPosition(position, window)
 | 
						|
}
 | 
						|
 | 
						|
func (h *windowsAnsiEventHandler) CUP(row int, col int) error {
 | 
						|
	if err := h.Flush(); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	h.logf("CUP: [[%d %d]]", row, col)
 | 
						|
	h.clearWrap()
 | 
						|
	info, err := GetConsoleScreenBufferInfo(h.fd)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	window := h.getCursorWindow(info)
 | 
						|
	position := COORD{window.Left + int16(col) - 1, window.Top + int16(row) - 1}
 | 
						|
	return h.setCursorPosition(position, window)
 | 
						|
}
 | 
						|
 | 
						|
func (h *windowsAnsiEventHandler) HVP(row int, col int) error {
 | 
						|
	if err := h.Flush(); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	h.logf("HVP: [[%d %d]]", row, col)
 | 
						|
	h.clearWrap()
 | 
						|
	return h.CUP(row, col)
 | 
						|
}
 | 
						|
 | 
						|
func (h *windowsAnsiEventHandler) DECTCEM(visible bool) error {
 | 
						|
	if err := h.Flush(); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	h.logf("DECTCEM: [%v]", []string{strconv.FormatBool(visible)})
 | 
						|
	h.clearWrap()
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (h *windowsAnsiEventHandler) DECOM(enable bool) error {
 | 
						|
	if err := h.Flush(); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	h.logf("DECOM: [%v]", []string{strconv.FormatBool(enable)})
 | 
						|
	h.clearWrap()
 | 
						|
	h.originMode = enable
 | 
						|
	return h.CUP(1, 1)
 | 
						|
}
 | 
						|
 | 
						|
func (h *windowsAnsiEventHandler) DECCOLM(use132 bool) error {
 | 
						|
	if err := h.Flush(); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	h.logf("DECCOLM: [%v]", []string{strconv.FormatBool(use132)})
 | 
						|
	h.clearWrap()
 | 
						|
	if err := h.ED(2); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	info, err := GetConsoleScreenBufferInfo(h.fd)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	targetWidth := int16(80)
 | 
						|
	if use132 {
 | 
						|
		targetWidth = 132
 | 
						|
	}
 | 
						|
	if info.Size.X < targetWidth {
 | 
						|
		if err := SetConsoleScreenBufferSize(h.fd, COORD{targetWidth, info.Size.Y}); err != nil {
 | 
						|
			h.logf("set buffer failed: %v", err)
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
	window := info.Window
 | 
						|
	window.Left = 0
 | 
						|
	window.Right = targetWidth - 1
 | 
						|
	if err := SetConsoleWindowInfo(h.fd, true, window); err != nil {
 | 
						|
		h.logf("set window failed: %v", err)
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	if info.Size.X > targetWidth {
 | 
						|
		if err := SetConsoleScreenBufferSize(h.fd, COORD{targetWidth, info.Size.Y}); err != nil {
 | 
						|
			h.logf("set buffer failed: %v", err)
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return SetConsoleCursorPosition(h.fd, COORD{0, 0})
 | 
						|
}
 | 
						|
 | 
						|
func (h *windowsAnsiEventHandler) ED(param int) error {
 | 
						|
	if err := h.Flush(); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	h.logf("ED: [%v]", []string{strconv.Itoa(param)})
 | 
						|
	h.clearWrap()
 | 
						|
 | 
						|
	// [J  -- Erases from the cursor to the end of the screen, including the cursor position.
 | 
						|
	// [1J -- Erases from the beginning of the screen to the cursor, including the cursor position.
 | 
						|
	// [2J -- Erases the complete display. The cursor does not move.
 | 
						|
	// Notes:
 | 
						|
	// -- Clearing the entire buffer, versus just the Window, works best for Windows Consoles
 | 
						|
 | 
						|
	info, err := GetConsoleScreenBufferInfo(h.fd)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	var start COORD
 | 
						|
	var end COORD
 | 
						|
 | 
						|
	switch param {
 | 
						|
	case 0:
 | 
						|
		start = info.CursorPosition
 | 
						|
		end = COORD{info.Size.X - 1, info.Size.Y - 1}
 | 
						|
 | 
						|
	case 1:
 | 
						|
		start = COORD{0, 0}
 | 
						|
		end = info.CursorPosition
 | 
						|
 | 
						|
	case 2:
 | 
						|
		start = COORD{0, 0}
 | 
						|
		end = COORD{info.Size.X - 1, info.Size.Y - 1}
 | 
						|
	}
 | 
						|
 | 
						|
	err = h.clearRange(h.attributes, start, end)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	// If the whole buffer was cleared, move the window to the top while preserving
 | 
						|
	// the window-relative cursor position.
 | 
						|
	if param == 2 {
 | 
						|
		pos := info.CursorPosition
 | 
						|
		window := info.Window
 | 
						|
		pos.Y -= window.Top
 | 
						|
		window.Bottom -= window.Top
 | 
						|
		window.Top = 0
 | 
						|
		if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		if err := SetConsoleWindowInfo(h.fd, true, window); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (h *windowsAnsiEventHandler) EL(param int) error {
 | 
						|
	if err := h.Flush(); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	h.logf("EL: [%v]", strconv.Itoa(param))
 | 
						|
	h.clearWrap()
 | 
						|
 | 
						|
	// [K  -- Erases from the cursor to the end of the line, including the cursor position.
 | 
						|
	// [1K -- Erases from the beginning of the line to the cursor, including the cursor position.
 | 
						|
	// [2K -- Erases the complete line.
 | 
						|
 | 
						|
	info, err := GetConsoleScreenBufferInfo(h.fd)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	var start COORD
 | 
						|
	var end COORD
 | 
						|
 | 
						|
	switch param {
 | 
						|
	case 0:
 | 
						|
		start = info.CursorPosition
 | 
						|
		end = COORD{info.Size.X, info.CursorPosition.Y}
 | 
						|
 | 
						|
	case 1:
 | 
						|
		start = COORD{0, info.CursorPosition.Y}
 | 
						|
		end = info.CursorPosition
 | 
						|
 | 
						|
	case 2:
 | 
						|
		start = COORD{0, info.CursorPosition.Y}
 | 
						|
		end = COORD{info.Size.X, info.CursorPosition.Y}
 | 
						|
	}
 | 
						|
 | 
						|
	err = h.clearRange(h.attributes, start, end)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (h *windowsAnsiEventHandler) IL(param int) error {
 | 
						|
	if err := h.Flush(); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	h.logf("IL: [%v]", strconv.Itoa(param))
 | 
						|
	h.clearWrap()
 | 
						|
	return h.insertLines(param)
 | 
						|
}
 | 
						|
 | 
						|
func (h *windowsAnsiEventHandler) DL(param int) error {
 | 
						|
	if err := h.Flush(); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	h.logf("DL: [%v]", strconv.Itoa(param))
 | 
						|
	h.clearWrap()
 | 
						|
	return h.deleteLines(param)
 | 
						|
}
 | 
						|
 | 
						|
func (h *windowsAnsiEventHandler) ICH(param int) error {
 | 
						|
	if err := h.Flush(); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	h.logf("ICH: [%v]", strconv.Itoa(param))
 | 
						|
	h.clearWrap()
 | 
						|
	return h.insertCharacters(param)
 | 
						|
}
 | 
						|
 | 
						|
func (h *windowsAnsiEventHandler) DCH(param int) error {
 | 
						|
	if err := h.Flush(); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	h.logf("DCH: [%v]", strconv.Itoa(param))
 | 
						|
	h.clearWrap()
 | 
						|
	return h.deleteCharacters(param)
 | 
						|
}
 | 
						|
 | 
						|
func (h *windowsAnsiEventHandler) SGR(params []int) error {
 | 
						|
	if err := h.Flush(); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	strings := []string{}
 | 
						|
	for _, v := range params {
 | 
						|
		strings = append(strings, strconv.Itoa(v))
 | 
						|
	}
 | 
						|
 | 
						|
	h.logf("SGR: [%v]", strings)
 | 
						|
 | 
						|
	if len(params) <= 0 {
 | 
						|
		h.attributes = h.infoReset.Attributes
 | 
						|
		h.inverted = false
 | 
						|
	} else {
 | 
						|
		for _, attr := range params {
 | 
						|
 | 
						|
			if attr == ansiterm.ANSI_SGR_RESET {
 | 
						|
				h.attributes = h.infoReset.Attributes
 | 
						|
				h.inverted = false
 | 
						|
				continue
 | 
						|
			}
 | 
						|
 | 
						|
			h.attributes, h.inverted = collectAnsiIntoWindowsAttributes(h.attributes, h.inverted, h.infoReset.Attributes, int16(attr))
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	attributes := h.attributes
 | 
						|
	if h.inverted {
 | 
						|
		attributes = invertAttributes(attributes)
 | 
						|
	}
 | 
						|
	err := SetConsoleTextAttribute(h.fd, attributes)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (h *windowsAnsiEventHandler) SU(param int) error {
 | 
						|
	if err := h.Flush(); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	h.logf("SU: [%v]", []string{strconv.Itoa(param)})
 | 
						|
	h.clearWrap()
 | 
						|
	return h.scrollUp(param)
 | 
						|
}
 | 
						|
 | 
						|
func (h *windowsAnsiEventHandler) SD(param int) error {
 | 
						|
	if err := h.Flush(); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	h.logf("SD: [%v]", []string{strconv.Itoa(param)})
 | 
						|
	h.clearWrap()
 | 
						|
	return h.scrollDown(param)
 | 
						|
}
 | 
						|
 | 
						|
func (h *windowsAnsiEventHandler) DA(params []string) error {
 | 
						|
	h.logf("DA: [%v]", params)
 | 
						|
	// DA cannot be implemented because it must send data on the VT100 input stream,
 | 
						|
	// which is not available to go-ansiterm.
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (h *windowsAnsiEventHandler) DECSTBM(top int, bottom int) error {
 | 
						|
	if err := h.Flush(); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	h.logf("DECSTBM: [%d, %d]", top, bottom)
 | 
						|
 | 
						|
	// Windows is 0 indexed, Linux is 1 indexed
 | 
						|
	h.sr.top = int16(top - 1)
 | 
						|
	h.sr.bottom = int16(bottom - 1)
 | 
						|
 | 
						|
	// This command also moves the cursor to the origin.
 | 
						|
	h.clearWrap()
 | 
						|
	return h.CUP(1, 1)
 | 
						|
}
 | 
						|
 | 
						|
func (h *windowsAnsiEventHandler) RI() error {
 | 
						|
	if err := h.Flush(); err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	h.logf("RI: []")
 | 
						|
	h.clearWrap()
 | 
						|
 | 
						|
	info, err := GetConsoleScreenBufferInfo(h.fd)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	sr := h.effectiveSr(info.Window)
 | 
						|
	if info.CursorPosition.Y == sr.top {
 | 
						|
		return h.scrollDown(1)
 | 
						|
	}
 | 
						|
 | 
						|
	return h.moveCursorVertical(-1)
 | 
						|
}
 | 
						|
 | 
						|
func (h *windowsAnsiEventHandler) IND() error {
 | 
						|
	h.logf("IND: []")
 | 
						|
	return h.executeLF()
 | 
						|
}
 | 
						|
 | 
						|
func (h *windowsAnsiEventHandler) Flush() error {
 | 
						|
	h.curInfo = nil
 | 
						|
	if h.buffer.Len() > 0 {
 | 
						|
		h.logf("Flush: [%s]", h.buffer.Bytes())
 | 
						|
		if _, err := h.buffer.WriteTo(h.file); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if h.wrapNext && !h.drewMarginByte {
 | 
						|
		h.logf("Flush: drawing margin byte '%c'", h.marginByte)
 | 
						|
 | 
						|
		info, err := GetConsoleScreenBufferInfo(h.fd)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		charInfo := []CHAR_INFO{{UnicodeChar: uint16(h.marginByte), Attributes: info.Attributes}}
 | 
						|
		size := COORD{1, 1}
 | 
						|
		position := COORD{0, 0}
 | 
						|
		region := SMALL_RECT{Left: info.CursorPosition.X, Top: info.CursorPosition.Y, Right: info.CursorPosition.X, Bottom: info.CursorPosition.Y}
 | 
						|
		if err := WriteConsoleOutput(h.fd, charInfo, size, position, ®ion); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		h.drewMarginByte = true
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// cacheConsoleInfo ensures that the current console screen information has been queried
 | 
						|
// since the last call to Flush(). It must be called before accessing h.curInfo or h.curPos.
 | 
						|
func (h *windowsAnsiEventHandler) getCurrentInfo() (COORD, *CONSOLE_SCREEN_BUFFER_INFO, error) {
 | 
						|
	if h.curInfo == nil {
 | 
						|
		info, err := GetConsoleScreenBufferInfo(h.fd)
 | 
						|
		if err != nil {
 | 
						|
			return COORD{}, nil, err
 | 
						|
		}
 | 
						|
		h.curInfo = info
 | 
						|
		h.curPos = info.CursorPosition
 | 
						|
	}
 | 
						|
	return h.curPos, h.curInfo, nil
 | 
						|
}
 | 
						|
 | 
						|
func (h *windowsAnsiEventHandler) updatePos(pos COORD) {
 | 
						|
	if h.curInfo == nil {
 | 
						|
		panic("failed to call getCurrentInfo before calling updatePos")
 | 
						|
	}
 | 
						|
	h.curPos = pos
 | 
						|
}
 | 
						|
 | 
						|
// clearWrap clears the state where the cursor is in the margin
 | 
						|
// waiting for the next character before wrapping the line. This must
 | 
						|
// be done before most operations that act on the cursor.
 | 
						|
func (h *windowsAnsiEventHandler) clearWrap() {
 | 
						|
	h.wrapNext = false
 | 
						|
	h.drewMarginByte = false
 | 
						|
}
 |