327e5ef601
This disables recently added ANSI emulation feature in certain Windows shells (like ConEmu) where ANSI output is emulated by default with builtin functionality in the shell. MSYS (mingw) runs in cmd.exe window and it doesn't support emulation. Cygwin doesn't even pass terminal handles to docker.exe as far as I can tell, stdin/stdout/stderr handles are behaving like non-TTY. Therefore not even including that in the check. Signed-off-by: Ahmet Alp Balkan <ahmetalpbalkan@gmail.com>
137 lines
4 KiB
Go
137 lines
4 KiB
Go
// +build windows
|
|
package term
|
|
|
|
import (
|
|
"io"
|
|
"os"
|
|
|
|
"github.com/docker/docker/pkg/term/winconsole"
|
|
)
|
|
|
|
// State holds the console mode for the terminal.
|
|
type State struct {
|
|
mode uint32
|
|
}
|
|
|
|
// Winsize is used for window size.
|
|
type Winsize struct {
|
|
Height uint16
|
|
Width uint16
|
|
x uint16
|
|
y uint16
|
|
}
|
|
|
|
// GetWinsize gets the window size of the given terminal
|
|
func GetWinsize(fd uintptr) (*Winsize, error) {
|
|
ws := &Winsize{}
|
|
var info *winconsole.CONSOLE_SCREEN_BUFFER_INFO
|
|
info, err := winconsole.GetConsoleScreenBufferInfo(fd)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ws.Width = uint16(info.Window.Right - info.Window.Left + 1)
|
|
ws.Height = uint16(info.Window.Bottom - info.Window.Top + 1)
|
|
|
|
ws.x = 0 // todo azlinux -- this is the pixel size of the Window, and not currently used by any caller
|
|
ws.y = 0
|
|
|
|
return ws, nil
|
|
}
|
|
|
|
// SetWinsize sets the terminal connected to the given file descriptor to a
|
|
// given size.
|
|
func SetWinsize(fd uintptr, ws *Winsize) error {
|
|
return nil
|
|
}
|
|
|
|
// IsTerminal returns true if the given file descriptor is a terminal.
|
|
func IsTerminal(fd uintptr) bool {
|
|
_, e := winconsole.GetConsoleMode(fd)
|
|
return e == nil
|
|
}
|
|
|
|
// RestoreTerminal restores the terminal connected to the given file descriptor to a
|
|
// previous state.
|
|
func RestoreTerminal(fd uintptr, state *State) error {
|
|
return winconsole.SetConsoleMode(fd, state.mode)
|
|
}
|
|
|
|
// SaveState saves the state of the given console
|
|
func SaveState(fd uintptr) (*State, error) {
|
|
mode, e := winconsole.GetConsoleMode(fd)
|
|
if e != nil {
|
|
return nil, e
|
|
}
|
|
return &State{mode}, nil
|
|
}
|
|
|
|
// DisableEcho disbales the echo for given file descriptor and returns previous state
|
|
// see http://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx for these flag settings
|
|
func DisableEcho(fd uintptr, state *State) error {
|
|
state.mode &^= (winconsole.ENABLE_ECHO_INPUT)
|
|
state.mode |= (winconsole.ENABLE_PROCESSED_INPUT | winconsole.ENABLE_LINE_INPUT)
|
|
return winconsole.SetConsoleMode(fd, state.mode)
|
|
}
|
|
|
|
// SetRawTerminal puts the terminal connected to the given file descriptor into raw
|
|
// mode and returns the previous state of the terminal so that it can be
|
|
// restored.
|
|
func SetRawTerminal(fd uintptr) (*State, error) {
|
|
oldState, err := MakeRaw(fd)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// TODO (azlinux): implement handling interrupt and restore state of terminal
|
|
return oldState, err
|
|
}
|
|
|
|
// MakeRaw puts the terminal connected to the given file descriptor into raw
|
|
// mode and returns the previous state of the terminal so that it can be
|
|
// restored.
|
|
func MakeRaw(fd uintptr) (*State, error) {
|
|
var state *State
|
|
state, err := SaveState(fd)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx
|
|
// All three input modes, along with processed output mode, are designed to work together.
|
|
// It is best to either enable or disable all of these modes as a group.
|
|
// When all are enabled, the application is said to be in "cooked" mode, which means that most of the processing is handled for the application.
|
|
// When all are disabled, the application is in "raw" mode, which means that input is unfiltered and any processing is left to the application.
|
|
state.mode = 0
|
|
err = winconsole.SetConsoleMode(fd, state.mode)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return state, nil
|
|
}
|
|
|
|
// GetFdInfo returns file descriptor and bool indicating whether the file is a terminal
|
|
func GetFdInfo(in interface{}) (uintptr, bool) {
|
|
return winconsole.GetHandleInfo(in)
|
|
}
|
|
|
|
func StdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
|
|
var shouldEmulateANSI bool
|
|
switch {
|
|
case os.Getenv("ConEmuANSI") == "ON":
|
|
// ConEmu shell, ansi emulated by default and ConEmu does an extensively
|
|
// good emulation.
|
|
shouldEmulateANSI = false
|
|
case os.Getenv("MSYSTEM") != "":
|
|
// MSYS (mingw) cannot fully emulate well and still shows escape characters
|
|
// mostly because it's still running on cmd.exe window.
|
|
shouldEmulateANSI = true
|
|
default:
|
|
shouldEmulateANSI = true
|
|
}
|
|
|
|
if shouldEmulateANSI {
|
|
return winconsole.StdStreams()
|
|
}
|
|
|
|
return os.Stdin, os.Stdout, os.Stderr
|
|
}
|