// HandleOutputCommand interpretes the Ansi commands and then makes appropriate Win32 calls func (term *WindowsTerminal) HandleOutputCommand(handle uintptr, command []byte) (n int, err error) { // always consider all the bytes in command, processed n = len(command) parsedCommand := parseAnsiCommand(command) logrus.Debugf("[windows] HandleOutputCommand: %v", parsedCommand) // console settings changes need to happen in atomic way term.outMutex.Lock() defer term.outMutex.Unlock() switch parsedCommand.Command { case "m": // [Value;...;Valuem // Set Graphics Mode: // Calls the graphics functions specified by the following values. // These specified functions remain active until the next occurrence of this escape sequence. // Graphics mode changes the colors and attributes of text (such as bold and underline) displayed on the screen. screenBufferInfo, err := GetConsoleScreenBufferInfo(handle) if err != nil { return n, err } flag := screenBufferInfo.Attributes for _, e := range parsedCommand.Parameters { value, _ := strconv.ParseInt(e, 10, 16) // base 10, 16 bit if value == ANSI_ATTR_RESET { flag = term.screenBufferInfo.Attributes // reset } else { flag, err = getWindowsTextAttributeForAnsiValue(flag, term.screenBufferInfo.Attributes, int16(value)) if err != nil { return n, err } } } if err := setConsoleTextAttribute(handle, flag); err != nil { return n, err } case "H", "f": // [line;columnH // [line;columnf // Moves the cursor to the specified position (coordinates). // If you do not specify a position, the cursor moves to the home position at the upper-left corner of the screen (line 0, column 0). screenBufferInfo, err := GetConsoleScreenBufferInfo(handle) if err != nil { return n, err } line, err := parseInt16OrDefault(parsedCommand.getParam(0), 1) if err != nil { return n, err } if line > int16(screenBufferInfo.Window.Bottom) { line = int16(screenBufferInfo.Window.Bottom) + 1 } column, err := parseInt16OrDefault(parsedCommand.getParam(1), 1) if err != nil { return n, err } if column > int16(screenBufferInfo.Window.Right) { column = int16(screenBufferInfo.Window.Right) + 1 } // The numbers are not 0 based, but 1 based logrus.Debugf("[windows] HandleOutputCommmand: Moving cursor to (%v,%v)", column-1, line-1) if err := setConsoleCursorPosition(handle, false, column-1, line-1); err != nil { return n, err } case "A": // [valueA // Moves the cursor up by the specified number of lines without changing columns. // If the cursor is already on the top line, ignores this sequence. value, err := parseInt16OrDefault(parsedCommand.getParam(0), 1) if err != nil { return len(command), err } if err := setConsoleCursorPosition(handle, true, 0, -value); err != nil { return n, err } case "B": // [valueB // Moves the cursor down by the specified number of lines without changing columns. // If the cursor is already on the bottom line, ignores this sequence. value, err := parseInt16OrDefault(parsedCommand.getParam(0), 1) if err != nil { return n, err } if err := setConsoleCursorPosition(handle, true, 0, value); err != nil { return n, err } case "C": // [valueC // Moves the cursor forward by the specified number of columns without changing lines. // If the cursor is already in the rightmost column, ignores this sequence. value, err := parseInt16OrDefault(parsedCommand.getParam(0), 1) if err != nil { return n, err } if err := setConsoleCursorPosition(handle, true, value, 0); err != nil { return n, err } case "D": // [valueD // Moves the cursor back by the specified number of columns without changing lines. // If the cursor is already in the leftmost column, ignores this sequence. value, err := parseInt16OrDefault(parsedCommand.getParam(0), 1) if err != nil { return n, err } if err := setConsoleCursorPosition(handle, true, -value, 0); err != nil { return n, err } case "J": // [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. // Clears the screen and moves the cursor to the home position (line 0, column 0). value, err := parseInt16OrDefault(parsedCommand.getParam(0), 0) if err != nil { return n, err } var start COORD var cursor COORD var end COORD screenBufferInfo, err := GetConsoleScreenBufferInfo(handle) if err != nil { return n, err } switch value { case 0: start = screenBufferInfo.CursorPosition // end of the buffer end.X = screenBufferInfo.Size.X - 1 end.Y = screenBufferInfo.Size.Y - 1 // cursor cursor = screenBufferInfo.CursorPosition case 1: // start of the screen start.X = 0 start.Y = 0 // end of the screen end = screenBufferInfo.CursorPosition // cursor cursor = screenBufferInfo.CursorPosition case 2: // start of the screen start.X = 0 start.Y = 0 // end of the buffer end.X = screenBufferInfo.Size.X - 1 end.Y = screenBufferInfo.Size.Y - 1 // cursor cursor.X = 0 cursor.Y = 0 } if _, err := clearDisplayRange(uintptr(handle), term.screenBufferInfo.Attributes, start, end); err != nil { return n, err } // remember the the cursor position is 1 based if err := setConsoleCursorPosition(handle, false, int16(cursor.X), int16(cursor.Y)); err != nil { return n, err } case "K": // [K // Clears all characters from the cursor position to the end of the line (including the character at the cursor position). // [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. value, err := parseInt16OrDefault(parsedCommand.getParam(0), 0) var start COORD var cursor COORD var end COORD screenBufferInfo, err := GetConsoleScreenBufferInfo(uintptr(handle)) if err != nil { return n, err } switch value { case 0: // start is where cursor is start = screenBufferInfo.CursorPosition // end of line end.X = screenBufferInfo.Size.X - 1 end.Y = screenBufferInfo.CursorPosition.Y // cursor remains the same cursor = screenBufferInfo.CursorPosition case 1: // beginning of line start.X = 0 start.Y = screenBufferInfo.CursorPosition.Y // until cursor end = screenBufferInfo.CursorPosition // cursor remains the same cursor = screenBufferInfo.CursorPosition case 2: // start of the line start.X = 0 start.Y = screenBufferInfo.CursorPosition.Y - 1 // end of the line end.X = screenBufferInfo.Size.X - 1 end.Y = screenBufferInfo.CursorPosition.Y - 1 // cursor cursor.X = 0 cursor.Y = screenBufferInfo.CursorPosition.Y - 1 } if _, err := clearDisplayRange(uintptr(handle), term.screenBufferInfo.Attributes, start, end); err != nil { return n, err } // remember the the cursor position is 1 based if err := setConsoleCursorPosition(uintptr(handle), false, int16(cursor.X), int16(cursor.Y)); err != nil { return n, err } case "l": for _, value := range parsedCommand.Parameters { switch value { case "?25", "25": SetCursorVisible(uintptr(handle), BOOL(0)) case "?1049", "1049": // TODO (azlinux): Restore terminal case "?1", "1": // If the DECCKM function is reset, then the arrow keys send ANSI cursor sequences to the host. term.inputEscapeSequence = []byte(KEY_ESC_CSI) } } case "h": for _, value := range parsedCommand.Parameters { switch value { case "?25", "25": SetCursorVisible(uintptr(handle), BOOL(1)) case "?1049", "1049": // TODO (azlinux): Save terminal case "?1", "1": // If the DECCKM function is set, then the arrow keys send application sequences to the host. // DECCKM (default off): When set, the cursor keys send an ESC O prefix, rather than ESC [. term.inputEscapeSequence = []byte(KEY_ESC_O) } } case "]": /* TODO (azlinux): Linux Console Private CSI Sequences The following sequences are neither ECMA-48 nor native VT102. They are native to the Linux console driver. Colors are in SGR parameters: 0 = black, 1 = red, 2 = green, 3 = brown, 4 = blue, 5 = magenta, 6 = cyan, 7 = white. ESC [ 1 ; n ] Set color n as the underline color ESC [ 2 ; n ] Set color n as the dim color ESC [ 8 ] Make the current color pair the default attributes. ESC [ 9 ; n ] Set screen blank timeout to n minutes. ESC [ 10 ; n ] Set bell frequency in Hz. ESC [ 11 ; n ] Set bell duration in msec. ESC [ 12 ; n ] Bring specified console to the front. ESC [ 13 ] Unblank the screen. ESC [ 14 ; n ] Set the VESA powerdown interval in minutes. */ } return n, nil }
// SetWinsize sets the size of the given terminal connected to the passed file descriptor. func SetWinsize(fd uintptr, ws *Winsize) error { // TODO(azlinux): Implement SetWinsize logrus.Debugf("[windows] SetWinsize: WARNING -- Unsupported method invoked") return nil }