github.com/sijibomii/docker@v0.0.0-20231230191044-5cf6ca554647/pkg/term/windows/console.go (about)

     1  // +build windows
     2  
     3  package windows
     4  
     5  import (
     6  	"io"
     7  	"os"
     8  	"syscall"
     9  
    10  	"github.com/Azure/go-ansiterm/winterm"
    11  
    12  	ansiterm "github.com/Azure/go-ansiterm"
    13  	"github.com/Sirupsen/logrus"
    14  	"io/ioutil"
    15  )
    16  
    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  // GetHandleInfo returns file descriptor and bool indicating whether the file is a console.
    74  func GetHandleInfo(in interface{}) (uintptr, bool) {
    75  	switch t := in.(type) {
    76  	case *ansiReader:
    77  		return t.Fd(), true
    78  	case *ansiWriter:
    79  		return t.Fd(), true
    80  	}
    81  
    82  	var inFd uintptr
    83  	var isTerminal bool
    84  
    85  	if file, ok := in.(*os.File); ok {
    86  		inFd = file.Fd()
    87  		isTerminal = IsConsole(inFd)
    88  	}
    89  	return inFd, isTerminal
    90  }
    91  
    92  // IsConsole returns true if the given file descriptor is a Windows Console.
    93  // The code assumes that GetConsoleMode will return an error for file descriptors that are not a console.
    94  func IsConsole(fd uintptr) bool {
    95  	_, e := winterm.GetConsoleMode(fd)
    96  	return e == nil
    97  }