Always enable VT output emulation when starting the process so that
non-attaching commands can still output VT codes.
Also remove the version block for using the native console and just rely
on supported flags being present.
Signed-off-by: John Starks <jostarks@microsoft.com>
| ... | ... |
@@ -47,8 +47,10 @@ type DockerCli struct {
|
| 47 | 47 |
isTerminalOut bool |
| 48 | 48 |
// client is the http client that performs all API operations |
| 49 | 49 |
client client.APIClient |
| 50 |
- // state holds the terminal state |
|
| 51 |
- state *term.State |
|
| 50 |
+ // state holds the terminal input state |
|
| 51 |
+ inState *term.State |
|
| 52 |
+ // outState holds the terminal output state |
|
| 53 |
+ outState *term.State |
|
| 52 | 54 |
} |
| 53 | 55 |
|
| 54 | 56 |
// Initialize calls the init function that will setup the configuration for the client |
| ... | ... |
@@ -124,19 +126,31 @@ func (cli *DockerCli) ImagesFormat() string {
|
| 124 | 124 |
} |
| 125 | 125 |
|
| 126 | 126 |
func (cli *DockerCli) setRawTerminal() error {
|
| 127 |
- if cli.isTerminalIn && os.Getenv("NORAW") == "" {
|
|
| 128 |
- state, err := term.SetRawTerminal(cli.inFd) |
|
| 129 |
- if err != nil {
|
|
| 130 |
- return err |
|
| 127 |
+ if os.Getenv("NORAW") == "" {
|
|
| 128 |
+ if cli.isTerminalIn {
|
|
| 129 |
+ state, err := term.SetRawTerminal(cli.inFd) |
|
| 130 |
+ if err != nil {
|
|
| 131 |
+ return err |
|
| 132 |
+ } |
|
| 133 |
+ cli.inState = state |
|
| 134 |
+ } |
|
| 135 |
+ if cli.isTerminalOut {
|
|
| 136 |
+ state, err := term.SetRawTerminalOutput(cli.outFd) |
|
| 137 |
+ if err != nil {
|
|
| 138 |
+ return err |
|
| 139 |
+ } |
|
| 140 |
+ cli.outState = state |
|
| 131 | 141 |
} |
| 132 |
- cli.state = state |
|
| 133 | 142 |
} |
| 134 | 143 |
return nil |
| 135 | 144 |
} |
| 136 | 145 |
|
| 137 | 146 |
func (cli *DockerCli) restoreTerminal(in io.Closer) error {
|
| 138 |
- if cli.state != nil {
|
|
| 139 |
- term.RestoreTerminal(cli.inFd, cli.state) |
|
| 147 |
+ if cli.inState != nil {
|
|
| 148 |
+ term.RestoreTerminal(cli.inFd, cli.inState) |
|
| 149 |
+ } |
|
| 150 |
+ if cli.outState != nil {
|
|
| 151 |
+ term.RestoreTerminal(cli.outFd, cli.outState) |
|
| 140 | 152 |
} |
| 141 | 153 |
// WARNING: DO NOT REMOVE THE OS CHECK !!! |
| 142 | 154 |
// For some reason this Close call blocks on darwin.. |
| ... | ... |
@@ -88,7 +88,8 @@ func DisableEcho(fd uintptr, state *State) error {
|
| 88 | 88 |
} |
| 89 | 89 |
|
| 90 | 90 |
// SetRawTerminal puts the terminal connected to the given file descriptor into |
| 91 |
-// raw mode and returns the previous state. |
|
| 91 |
+// raw mode and returns the previous state. On UNIX, this puts both the input |
|
| 92 |
+// and output into raw mode. On Windows, it only puts the input into raw mode. |
|
| 92 | 93 |
func SetRawTerminal(fd uintptr) (*State, error) {
|
| 93 | 94 |
oldState, err := MakeRaw(fd) |
| 94 | 95 |
if err != nil {
|
| ... | ... |
@@ -98,6 +99,13 @@ func SetRawTerminal(fd uintptr) (*State, error) {
|
| 98 | 98 |
return oldState, err |
| 99 | 99 |
} |
| 100 | 100 |
|
| 101 |
+// SetRawTerminalOutput puts the output of terminal connected to the given file |
|
| 102 |
+// descriptor into raw mode. On UNIX, this does nothing and returns nil for the |
|
| 103 |
+// state. On Windows, it disables LF -> CRLF translation. |
|
| 104 |
+func SetRawTerminalOutput(fd uintptr) (*State, error) {
|
|
| 105 |
+ return nil, nil |
|
| 106 |
+} |
|
| 107 |
+ |
|
| 101 | 108 |
func handleInterrupt(fd uintptr, state *State) {
|
| 102 | 109 |
sigchan := make(chan os.Signal, 1) |
| 103 | 110 |
signal.Notify(sigchan, os.Interrupt) |
| ... | ... |
@@ -9,14 +9,12 @@ import ( |
| 9 | 9 |
"syscall" |
| 10 | 10 |
|
| 11 | 11 |
"github.com/Azure/go-ansiterm/winterm" |
| 12 |
- "github.com/docker/docker/pkg/system" |
|
| 13 | 12 |
"github.com/docker/docker/pkg/term/windows" |
| 14 | 13 |
) |
| 15 | 14 |
|
| 16 | 15 |
// State holds the console mode for the terminal. |
| 17 | 16 |
type State struct {
|
| 18 |
- inMode, outMode uint32 |
|
| 19 |
- inHandle, outHandle syscall.Handle |
|
| 17 |
+ mode uint32 |
|
| 20 | 18 |
} |
| 21 | 19 |
|
| 22 | 20 |
// Winsize is used for window size. |
| ... | ... |
@@ -32,143 +30,70 @@ const ( |
| 32 | 32 |
disableNewlineAutoReturn = 0x0008 |
| 33 | 33 |
) |
| 34 | 34 |
|
| 35 |
-// usingNativeConsole is true if we are using the Windows native console |
|
| 36 |
-var usingNativeConsole bool |
|
| 35 |
+// vtInputSupported is true if enableVirtualTerminalInput is supported by the console |
|
| 36 |
+var vtInputSupported bool |
|
| 37 | 37 |
|
| 38 | 38 |
// StdStreams returns the standard streams (stdin, stdout, stedrr). |
| 39 | 39 |
func StdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
|
| 40 |
- switch {
|
|
| 41 |
- case os.Getenv("ConEmuANSI") == "ON":
|
|
| 42 |
- // The ConEmu terminal emulates ANSI on output streams well. |
|
| 43 |
- return windows.ConEmuStreams() |
|
| 44 |
- case os.Getenv("MSYSTEM") != "":
|
|
| 45 |
- // MSYS (mingw) does not emulate ANSI well. |
|
| 46 |
- return windows.ConsoleStreams() |
|
| 47 |
- default: |
|
| 48 |
- if useNativeConsole() {
|
|
| 49 |
- usingNativeConsole = true |
|
| 50 |
- return os.Stdin, os.Stdout, os.Stderr |
|
| 40 |
+ // Turn on VT handling on all std handles, if possible. This might |
|
| 41 |
+ // fail, in which case we will fall back to terminal emulation. |
|
| 42 |
+ var emulateStdin, emulateStdout, emulateStderr bool |
|
| 43 |
+ fd := os.Stdin.Fd() |
|
| 44 |
+ if mode, err := winterm.GetConsoleMode(fd); err == nil {
|
|
| 45 |
+ // Validate that enableVirtualTerminalInput is supported, but do not set it. |
|
| 46 |
+ if err = winterm.SetConsoleMode(fd, mode|enableVirtualTerminalInput); err != nil {
|
|
| 47 |
+ emulateStdin = true |
|
| 48 |
+ } else {
|
|
| 49 |
+ winterm.SetConsoleMode(fd, mode) |
|
| 50 |
+ vtInputSupported = true |
|
| 51 | 51 |
} |
| 52 |
- return windows.ConsoleStreams() |
|
| 53 |
- } |
|
| 54 |
-} |
|
| 55 |
- |
|
| 56 |
-// useNativeConsole determines if the docker client should use the built-in |
|
| 57 |
-// console which supports ANSI emulation, or fall-back to the golang emulator |
|
| 58 |
-// (github.com/azure/go-ansiterm). |
|
| 59 |
-func useNativeConsole() bool {
|
|
| 60 |
- osv := system.GetOSVersion() |
|
| 61 |
- |
|
| 62 |
- // Native console is not available before major version 10 |
|
| 63 |
- if osv.MajorVersion < 10 {
|
|
| 64 |
- return false |
|
| 65 |
- } |
|
| 66 |
- |
|
| 67 |
- // Get the console modes. If this fails, we can't use the native console |
|
| 68 |
- state, err := getNativeConsole() |
|
| 69 |
- if err != nil {
|
|
| 70 |
- return false |
|
| 71 | 52 |
} |
| 72 | 53 |
|
| 73 |
- // Probe the console to see if it can be enabled. |
|
| 74 |
- if nil != probeNativeConsole(state) {
|
|
| 75 |
- return false |
|
| 76 |
- } |
|
| 77 |
- |
|
| 78 |
- // Environment variable override |
|
| 79 |
- if e := os.Getenv("USE_NATIVE_CONSOLE"); e != "" {
|
|
| 80 |
- if e == "1" {
|
|
| 81 |
- return true |
|
| 54 |
+ fd = os.Stdout.Fd() |
|
| 55 |
+ if mode, err := winterm.GetConsoleMode(fd); err == nil {
|
|
| 56 |
+ // Validate disableNewlineAutoReturn is supported, but do not set it. |
|
| 57 |
+ if err = winterm.SetConsoleMode(fd, mode|enableVirtualTerminalProcessing|disableNewlineAutoReturn); err != nil {
|
|
| 58 |
+ emulateStdout = true |
|
| 59 |
+ } else {
|
|
| 60 |
+ winterm.SetConsoleMode(fd, mode|enableVirtualTerminalProcessing) |
|
| 82 | 61 |
} |
| 83 |
- return false |
|
| 84 |
- } |
|
| 85 |
- |
|
| 86 |
- // Must have a post-TP5 RS1 build of Windows Server 2016/Windows 10 for |
|
| 87 |
- // the native console to be usable. |
|
| 88 |
- if osv.Build < 14350 {
|
|
| 89 |
- return false |
|
| 90 | 62 |
} |
| 91 | 63 |
|
| 92 |
- return true |
|
| 93 |
-} |
|
| 94 |
- |
|
| 95 |
-// getNativeConsole returns the console modes ('state') for the native Windows console
|
|
| 96 |
-func getNativeConsole() (State, error) {
|
|
| 97 |
- var ( |
|
| 98 |
- err error |
|
| 99 |
- state State |
|
| 100 |
- ) |
|
| 101 |
- |
|
| 102 |
- // Get the handle to stdout |
|
| 103 |
- if state.outHandle, err = syscall.GetStdHandle(syscall.STD_OUTPUT_HANDLE); err != nil {
|
|
| 104 |
- return state, err |
|
| 105 |
- } |
|
| 106 |
- |
|
| 107 |
- // Get the console mode from the consoles stdout handle |
|
| 108 |
- if err = syscall.GetConsoleMode(state.outHandle, &state.outMode); err != nil {
|
|
| 109 |
- return state, err |
|
| 64 |
+ fd = os.Stderr.Fd() |
|
| 65 |
+ if mode, err := winterm.GetConsoleMode(fd); err == nil {
|
|
| 66 |
+ // Validate disableNewlineAutoReturn is supported, but do not set it. |
|
| 67 |
+ if err = winterm.SetConsoleMode(fd, mode|enableVirtualTerminalProcessing|disableNewlineAutoReturn); err != nil {
|
|
| 68 |
+ emulateStderr = true |
|
| 69 |
+ } else {
|
|
| 70 |
+ winterm.SetConsoleMode(fd, mode|enableVirtualTerminalProcessing) |
|
| 71 |
+ } |
|
| 110 | 72 |
} |
| 111 | 73 |
|
| 112 |
- // Get the handle to stdin |
|
| 113 |
- if state.inHandle, err = syscall.GetStdHandle(syscall.STD_INPUT_HANDLE); err != nil {
|
|
| 114 |
- return state, err |
|
| 74 |
+ if os.Getenv("ConEmuANSI") == "ON" {
|
|
| 75 |
+ // The ConEmu terminal emulates ANSI on output streams well. |
|
| 76 |
+ emulateStdout = false |
|
| 77 |
+ emulateStderr = false |
|
| 115 | 78 |
} |
| 116 | 79 |
|
| 117 |
- // Get the console mode from the consoles stdin handle |
|
| 118 |
- if err = syscall.GetConsoleMode(state.inHandle, &state.inMode); err != nil {
|
|
| 119 |
- return state, err |
|
| 80 |
+ if emulateStdin {
|
|
| 81 |
+ stdIn = windows.NewAnsiReader(syscall.STD_INPUT_HANDLE) |
|
| 82 |
+ } else {
|
|
| 83 |
+ stdIn = os.Stdin |
|
| 120 | 84 |
} |
| 121 | 85 |
|
| 122 |
- return state, nil |
|
| 123 |
-} |
|
| 124 |
- |
|
| 125 |
-// probeNativeConsole probes the console to determine if native can be supported, |
|
| 126 |
-func probeNativeConsole(state State) error {
|
|
| 127 |
- if err := winterm.SetConsoleMode(uintptr(state.outHandle), state.outMode|enableVirtualTerminalProcessing); err != nil {
|
|
| 128 |
- return err |
|
| 86 |
+ if emulateStdout {
|
|
| 87 |
+ stdOut = windows.NewAnsiWriter(syscall.STD_OUTPUT_HANDLE) |
|
| 88 |
+ } else {
|
|
| 89 |
+ stdOut = os.Stdout |
|
| 129 | 90 |
} |
| 130 |
- defer winterm.SetConsoleMode(uintptr(state.outHandle), state.outMode) |
|
| 131 | 91 |
|
| 132 |
- if err := winterm.SetConsoleMode(uintptr(state.inHandle), state.inMode|enableVirtualTerminalInput); err != nil {
|
|
| 133 |
- return err |
|
| 92 |
+ if emulateStderr {
|
|
| 93 |
+ stdErr = windows.NewAnsiWriter(syscall.STD_ERROR_HANDLE) |
|
| 94 |
+ } else {
|
|
| 95 |
+ stdErr = os.Stderr |
|
| 134 | 96 |
} |
| 135 |
- defer winterm.SetConsoleMode(uintptr(state.inHandle), state.inMode) |
|
| 136 | 97 |
|
| 137 |
- return nil |
|
| 138 |
-} |
|
| 139 |
- |
|
| 140 |
-// enableNativeConsole turns on native console mode |
|
| 141 |
-func enableNativeConsole(state State) error {
|
|
| 142 |
- // First attempt both enableVirtualTerminalProcessing and disableNewlineAutoReturn |
|
| 143 |
- if err := winterm.SetConsoleMode(uintptr(state.outHandle), |
|
| 144 |
- state.outMode|(enableVirtualTerminalProcessing|disableNewlineAutoReturn)); err != nil {
|
|
| 145 |
- |
|
| 146 |
- // That may fail, so fallback to trying just enableVirtualTerminalProcessing |
|
| 147 |
- if err := winterm.SetConsoleMode(uintptr(state.outHandle), state.outMode|enableVirtualTerminalProcessing); err != nil {
|
|
| 148 |
- return err |
|
| 149 |
- } |
|
| 150 |
- } |
|
| 151 |
- |
|
| 152 |
- if err := winterm.SetConsoleMode(uintptr(state.inHandle), state.inMode|enableVirtualTerminalInput); err != nil {
|
|
| 153 |
- winterm.SetConsoleMode(uintptr(state.outHandle), state.outMode) // restore out if we can |
|
| 154 |
- return err |
|
| 155 |
- } |
|
| 156 |
- |
|
| 157 |
- return nil |
|
| 158 |
-} |
|
| 159 |
- |
|
| 160 |
-// disableNativeConsole turns off native console mode |
|
| 161 |
-func disableNativeConsole(state *State) error {
|
|
| 162 |
- // Try and restore both in an out before error checking. |
|
| 163 |
- errout := winterm.SetConsoleMode(uintptr(state.outHandle), state.outMode) |
|
| 164 |
- errin := winterm.SetConsoleMode(uintptr(state.inHandle), state.inMode) |
|
| 165 |
- if errout != nil {
|
|
| 166 |
- return errout |
|
| 167 |
- } |
|
| 168 |
- if errin != nil {
|
|
| 169 |
- return errin |
|
| 170 |
- } |
|
| 171 |
- return nil |
|
| 98 |
+ return |
|
| 172 | 99 |
} |
| 173 | 100 |
|
| 174 | 101 |
// GetFdInfo returns the file descriptor for an os.File and indicates whether the file represents a terminal. |
| ... | ... |
@@ -199,34 +124,23 @@ func IsTerminal(fd uintptr) bool {
|
| 199 | 199 |
// RestoreTerminal restores the terminal connected to the given file descriptor |
| 200 | 200 |
// to a previous state. |
| 201 | 201 |
func RestoreTerminal(fd uintptr, state *State) error {
|
| 202 |
- if usingNativeConsole {
|
|
| 203 |
- return disableNativeConsole(state) |
|
| 204 |
- } |
|
| 205 |
- return winterm.SetConsoleMode(fd, state.outMode) |
|
| 202 |
+ return winterm.SetConsoleMode(fd, state.mode) |
|
| 206 | 203 |
} |
| 207 | 204 |
|
| 208 | 205 |
// SaveState saves the state of the terminal connected to the given file descriptor. |
| 209 | 206 |
func SaveState(fd uintptr) (*State, error) {
|
| 210 |
- if usingNativeConsole {
|
|
| 211 |
- state, err := getNativeConsole() |
|
| 212 |
- if err != nil {
|
|
| 213 |
- return nil, err |
|
| 214 |
- } |
|
| 215 |
- return &state, nil |
|
| 216 |
- } |
|
| 217 |
- |
|
| 218 | 207 |
mode, e := winterm.GetConsoleMode(fd) |
| 219 | 208 |
if e != nil {
|
| 220 | 209 |
return nil, e |
| 221 | 210 |
} |
| 222 | 211 |
|
| 223 |
- return &State{outMode: mode}, nil
|
|
| 212 |
+ return &State{mode: mode}, nil
|
|
| 224 | 213 |
} |
| 225 | 214 |
|
| 226 | 215 |
// DisableEcho disables echo for the terminal connected to the given file descriptor. |
| 227 | 216 |
// -- See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx |
| 228 | 217 |
func DisableEcho(fd uintptr, state *State) error {
|
| 229 |
- mode := state.inMode |
|
| 218 |
+ mode := state.mode |
|
| 230 | 219 |
mode &^= winterm.ENABLE_ECHO_INPUT |
| 231 | 220 |
mode |= winterm.ENABLE_PROCESSED_INPUT | winterm.ENABLE_LINE_INPUT |
| 232 | 221 |
err := winterm.SetConsoleMode(fd, mode) |
| ... | ... |
@@ -239,8 +153,9 @@ func DisableEcho(fd uintptr, state *State) error {
|
| 239 | 239 |
return nil |
| 240 | 240 |
} |
| 241 | 241 |
|
| 242 |
-// SetRawTerminal puts the terminal connected to the given file descriptor into raw |
|
| 243 |
-// mode and returns the previous state. |
|
| 242 |
+// SetRawTerminal puts the terminal connected to the given file descriptor into |
|
| 243 |
+// raw mode and returns the previous state. On UNIX, this puts both the input |
|
| 244 |
+// and output into raw mode. On Windows, it only puts the input into raw mode. |
|
| 244 | 245 |
func SetRawTerminal(fd uintptr) (*State, error) {
|
| 245 | 246 |
state, err := MakeRaw(fd) |
| 246 | 247 |
if err != nil {
|
| ... | ... |
@@ -252,6 +167,21 @@ func SetRawTerminal(fd uintptr) (*State, error) {
|
| 252 | 252 |
return state, err |
| 253 | 253 |
} |
| 254 | 254 |
|
| 255 |
+// SetRawTerminalOutput puts the output of terminal connected to the given file |
|
| 256 |
+// descriptor into raw mode. On UNIX, this does nothing and returns nil for the |
|
| 257 |
+// state. On Windows, it disables LF -> CRLF translation. |
|
| 258 |
+func SetRawTerminalOutput(fd uintptr) (*State, error) {
|
|
| 259 |
+ state, err := SaveState(fd) |
|
| 260 |
+ if err != nil {
|
|
| 261 |
+ return nil, err |
|
| 262 |
+ } |
|
| 263 |
+ |
|
| 264 |
+ // Ignore failures, since disableNewlineAutoReturn might not be supported on this |
|
| 265 |
+ // version of Windows. |
|
| 266 |
+ winterm.SetConsoleMode(fd, state.mode|disableNewlineAutoReturn) |
|
| 267 |
+ return state, err |
|
| 268 |
+} |
|
| 269 |
+ |
|
| 255 | 270 |
// MakeRaw puts the terminal (Windows Console) connected to the given file descriptor into raw |
| 256 | 271 |
// mode and returns the previous state of the terminal so that it can be restored. |
| 257 | 272 |
func MakeRaw(fd uintptr) (*State, error) {
|
| ... | ... |
@@ -260,13 +190,7 @@ func MakeRaw(fd uintptr) (*State, error) {
|
| 260 | 260 |
return nil, err |
| 261 | 261 |
} |
| 262 | 262 |
|
| 263 |
- mode := state.inMode |
|
| 264 |
- if usingNativeConsole {
|
|
| 265 |
- if err := enableNativeConsole(*state); err != nil {
|
|
| 266 |
- return nil, err |
|
| 267 |
- } |
|
| 268 |
- mode |= enableVirtualTerminalInput |
|
| 269 |
- } |
|
| 263 |
+ mode := state.mode |
|
| 270 | 264 |
|
| 271 | 265 |
// See |
| 272 | 266 |
// -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx |
| ... | ... |
@@ -283,6 +207,9 @@ func MakeRaw(fd uintptr) (*State, error) {
|
| 283 | 283 |
mode |= winterm.ENABLE_EXTENDED_FLAGS |
| 284 | 284 |
mode |= winterm.ENABLE_INSERT_MODE |
| 285 | 285 |
mode |= winterm.ENABLE_QUICK_EDIT_MODE |
| 286 |
+ if vtInputSupported {
|
|
| 287 |
+ mode |= enableVirtualTerminalInput |
|
| 288 |
+ } |
|
| 286 | 289 |
|
| 287 | 290 |
err = winterm.SetConsoleMode(fd, mode) |
| 288 | 291 |
if err != nil {
|
| ... | ... |
@@ -6,6 +6,7 @@ import ( |
| 6 | 6 |
"bytes" |
| 7 | 7 |
"errors" |
| 8 | 8 |
"fmt" |
| 9 |
+ "io" |
|
| 9 | 10 |
"os" |
| 10 | 11 |
"strings" |
| 11 | 12 |
"unsafe" |
| ... | ... |
@@ -27,7 +28,9 @@ type ansiReader struct {
|
| 27 | 27 |
command []byte |
| 28 | 28 |
} |
| 29 | 29 |
|
| 30 |
-func newAnsiReader(nFile int) *ansiReader {
|
|
| 30 |
+// NewAnsiReader returns an io.ReadCloser that provides VT100 terminal emulation on top of a |
|
| 31 |
+// Windows console input handle. |
|
| 32 |
+func NewAnsiReader(nFile int) io.ReadCloser {
|
|
| 31 | 33 |
initLogger() |
| 32 | 34 |
file, fd := winterm.GetStdFile(nFile) |
| 33 | 35 |
return &ansiReader{
|
| ... | ... |
@@ -3,6 +3,7 @@ |
| 3 | 3 |
package windows |
| 4 | 4 |
|
| 5 | 5 |
import ( |
| 6 |
+ "io" |
|
| 6 | 7 |
"os" |
| 7 | 8 |
|
| 8 | 9 |
ansiterm "github.com/Azure/go-ansiterm" |
| ... | ... |
@@ -20,7 +21,9 @@ type ansiWriter struct {
|
| 20 | 20 |
parser *ansiterm.AnsiParser |
| 21 | 21 |
} |
| 22 | 22 |
|
| 23 |
-func newAnsiWriter(nFile int) *ansiWriter {
|
|
| 23 |
+// NewAnsiWriter returns an io.Writer that provides VT100 terminal emulation on top of a |
|
| 24 |
+// Windows console output handle. |
|
| 25 |
+func NewAnsiWriter(nFile int) io.Writer {
|
|
| 24 | 26 |
initLogger() |
| 25 | 27 |
file, fd := winterm.GetStdFile(nFile) |
| 26 | 28 |
info, err := winterm.GetConsoleScreenBufferInfo(fd) |
| ... | ... |
@@ -3,73 +3,11 @@ |
| 3 | 3 |
package windows |
| 4 | 4 |
|
| 5 | 5 |
import ( |
| 6 |
- "io" |
|
| 7 | 6 |
"os" |
| 8 |
- "syscall" |
|
| 9 | 7 |
|
| 10 | 8 |
"github.com/Azure/go-ansiterm/winterm" |
| 11 |
- |
|
| 12 |
- ansiterm "github.com/Azure/go-ansiterm" |
|
| 13 |
- "github.com/Sirupsen/logrus" |
|
| 14 |
- "io/ioutil" |
|
| 15 | 9 |
) |
| 16 | 10 |
|
| 17 |
-// ConEmuStreams returns prepared versions of console streams, |
|
| 18 |
-// for proper use in ConEmu terminal. |
|
| 19 |
-// The ConEmu terminal emulates ANSI on output streams well by default. |
|
| 20 |
-func ConEmuStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
|
|
| 21 |
- if IsConsole(os.Stdin.Fd()) {
|
|
| 22 |
- stdIn = newAnsiReader(syscall.STD_INPUT_HANDLE) |
|
| 23 |
- } else {
|
|
| 24 |
- stdIn = os.Stdin |
|
| 25 |
- } |
|
| 26 |
- |
|
| 27 |
- stdOut = os.Stdout |
|
| 28 |
- stdErr = os.Stderr |
|
| 29 |
- |
|
| 30 |
- // WARNING (BEGIN): sourced from newAnsiWriter |
|
| 31 |
- |
|
| 32 |
- logFile := ioutil.Discard |
|
| 33 |
- |
|
| 34 |
- if isDebugEnv := os.Getenv(ansiterm.LogEnv); isDebugEnv == "1" {
|
|
| 35 |
- logFile, _ = os.Create("ansiReaderWriter.log")
|
|
| 36 |
- } |
|
| 37 |
- |
|
| 38 |
- logger = &logrus.Logger{
|
|
| 39 |
- Out: logFile, |
|
| 40 |
- Formatter: new(logrus.TextFormatter), |
|
| 41 |
- Level: logrus.DebugLevel, |
|
| 42 |
- } |
|
| 43 |
- |
|
| 44 |
- // WARNING (END): sourced from newAnsiWriter |
|
| 45 |
- |
|
| 46 |
- return stdIn, stdOut, stdErr |
|
| 47 |
-} |
|
| 48 |
- |
|
| 49 |
-// ConsoleStreams returns a wrapped version for each standard stream referencing a console, |
|
| 50 |
-// that handles ANSI character sequences. |
|
| 51 |
-func ConsoleStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
|
|
| 52 |
- if IsConsole(os.Stdin.Fd()) {
|
|
| 53 |
- stdIn = newAnsiReader(syscall.STD_INPUT_HANDLE) |
|
| 54 |
- } else {
|
|
| 55 |
- stdIn = os.Stdin |
|
| 56 |
- } |
|
| 57 |
- |
|
| 58 |
- if IsConsole(os.Stdout.Fd()) {
|
|
| 59 |
- stdOut = newAnsiWriter(syscall.STD_OUTPUT_HANDLE) |
|
| 60 |
- } else {
|
|
| 61 |
- stdOut = os.Stdout |
|
| 62 |
- } |
|
| 63 |
- |
|
| 64 |
- if IsConsole(os.Stderr.Fd()) {
|
|
| 65 |
- stdErr = newAnsiWriter(syscall.STD_ERROR_HANDLE) |
|
| 66 |
- } else {
|
|
| 67 |
- stdErr = os.Stderr |
|
| 68 |
- } |
|
| 69 |
- |
|
| 70 |
- return stdIn, stdOut, stdErr |
|
| 71 |
-} |
|
| 72 |
- |
|
| 73 | 11 |
// GetHandleInfo returns file descriptor and bool indicating whether the file is a console. |
| 74 | 12 |
func GetHandleInfo(in interface{}) (uintptr, bool) {
|
| 75 | 13 |
switch t := in.(type) {
|