func newAnsiWriter(nFile int) *ansiWriter { logFile := ioutil.Discard if isDebugEnv := os.Getenv(ansiterm.LogEnv); isDebugEnv == "1" { logFile, _ = os.Create("ansiReaderWriter.log") } logger = &logrus.Logger{ Out: logFile, Formatter: new(logrus.TextFormatter), Level: logrus.DebugLevel, } file, fd := winterm.GetStdFile(nFile) info, err := winterm.GetConsoleScreenBufferInfo(fd) if err != nil { return nil } parser := ansiterm.CreateParser("Ground", winterm.CreateWinEventHandler(fd, file)) logger.Infof("newAnsiWriter: parser %p", parser) aw := &ansiWriter{ file: file, fd: fd, infoReset: info, command: make([]byte, 0, ansiterm.ANSI_MAX_CMD_LENGTH), escapeSequence: []byte(ansiterm.KEY_ESC_CSI), parser: parser, } logger.Infof("newAnsiWriter: aw.parser %p", aw.parser) logger.Infof("newAnsiWriter: %v", aw) return aw }
// GetWinsize returns the window size based on the specified file descriptor. func GetWinsize(fd uintptr) (*Winsize, error) { info, err := winterm.GetConsoleScreenBufferInfo(fd) if err != nil { return nil, err } winsize := &Winsize{ Width: uint16(info.Window.Right - info.Window.Left + 1), Height: uint16(info.Window.Bottom - info.Window.Top + 1), x: 0, y: 0} // Note: GetWinsize is called frequently -- uncomment only for excessive details // logrus.Debugf("[windows] GetWinsize: Console(%v)", info.String()) // logrus.Debugf("[windows] GetWinsize: Width(%v), Height(%v), x(%v), y(%v)", winsize.Width, winsize.Height, winsize.x, winsize.y) return winsize, nil }
// SetWinsize tries to set the specified window size for the specified file descriptor. func SetWinsize(fd uintptr, ws *Winsize) error { // Ensure the requested dimensions are no larger than the maximum window size info, err := winterm.GetConsoleScreenBufferInfo(fd) if err != nil { return err } if ws.Width == 0 || ws.Height == 0 || ws.Width > uint16(info.MaximumWindowSize.X) || ws.Height > uint16(info.MaximumWindowSize.Y) { return fmt.Errorf("Illegal window size: (%v,%v) -- Maximum allow: (%v,%v)", ws.Width, ws.Height, info.MaximumWindowSize.X, info.MaximumWindowSize.Y) } // Narrow the sizes to that used by Windows width := winterm.SHORT(ws.Width) height := winterm.SHORT(ws.Height) // Set the dimensions while ensuring they remain within the bounds of the backing console buffer // -- Shrinking will always succeed. Growing may push the edges past the buffer boundary. When that occurs, // shift the upper left just enough to keep the new window within the buffer. rect := info.Window if width < rect.Right-rect.Left+1 { rect.Right = rect.Left + width - 1 } else if width > rect.Right-rect.Left+1 { rect.Right = rect.Left + width - 1 if rect.Right >= info.Size.X { rect.Left = info.Size.X - width rect.Right = info.Size.X - 1 } } if height < rect.Bottom-rect.Top+1 { rect.Bottom = rect.Top + height - 1 } else if height > rect.Bottom-rect.Top+1 { rect.Bottom = rect.Top + height - 1 if rect.Bottom >= info.Size.Y { rect.Top = info.Size.Y - height rect.Bottom = info.Size.Y - 1 } } logrus.Debugf("[windows] SetWinsize: Requested((%v,%v)) Actual(%v)", ws.Width, ws.Height, rect) return winterm.SetConsoleWindowInfo(fd, true, rect) }