console.go 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. // +build windows
  2. package windows
  3. import (
  4. "io"
  5. "os"
  6. "syscall"
  7. "github.com/Azure/go-ansiterm/winterm"
  8. ansiterm "github.com/Azure/go-ansiterm"
  9. "github.com/Sirupsen/logrus"
  10. "io/ioutil"
  11. )
  12. // ConEmuStreams returns prepared versions of console streams,
  13. // for proper use in ConEmu terminal.
  14. // The ConEmu terminal emulates ANSI on output streams well by default.
  15. func ConEmuStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
  16. if IsConsole(os.Stdin.Fd()) {
  17. stdIn = newAnsiReader(syscall.STD_INPUT_HANDLE)
  18. } else {
  19. stdIn = os.Stdin
  20. }
  21. stdOut = os.Stdout
  22. stdErr = os.Stderr
  23. // WARNING (BEGIN): sourced from newAnsiWriter
  24. logFile := ioutil.Discard
  25. if isDebugEnv := os.Getenv(ansiterm.LogEnv); isDebugEnv == "1" {
  26. logFile, _ = os.Create("ansiReaderWriter.log")
  27. }
  28. logger = &logrus.Logger{
  29. Out: logFile,
  30. Formatter: new(logrus.TextFormatter),
  31. Level: logrus.DebugLevel,
  32. }
  33. // WARNING (END): sourced from newAnsiWriter
  34. return stdIn, stdOut, stdErr
  35. }
  36. // ConsoleStreams returns a wrapped version for each standard stream referencing a console,
  37. // that handles ANSI character sequences.
  38. func ConsoleStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
  39. if IsConsole(os.Stdin.Fd()) {
  40. stdIn = newAnsiReader(syscall.STD_INPUT_HANDLE)
  41. } else {
  42. stdIn = os.Stdin
  43. }
  44. if IsConsole(os.Stdout.Fd()) {
  45. stdOut = newAnsiWriter(syscall.STD_OUTPUT_HANDLE)
  46. } else {
  47. stdOut = os.Stdout
  48. }
  49. if IsConsole(os.Stderr.Fd()) {
  50. stdErr = newAnsiWriter(syscall.STD_ERROR_HANDLE)
  51. } else {
  52. stdErr = os.Stderr
  53. }
  54. return stdIn, stdOut, stdErr
  55. }
  56. // GetHandleInfo returns file descriptor and bool indicating whether the file is a console.
  57. func GetHandleInfo(in interface{}) (uintptr, bool) {
  58. switch t := in.(type) {
  59. case *ansiReader:
  60. return t.Fd(), true
  61. case *ansiWriter:
  62. return t.Fd(), true
  63. }
  64. var inFd uintptr
  65. var isTerminal bool
  66. if file, ok := in.(*os.File); ok {
  67. inFd = file.Fd()
  68. isTerminal = IsConsole(inFd)
  69. }
  70. return inFd, isTerminal
  71. }
  72. // IsConsole returns true if the given file descriptor is a Windows Console.
  73. // The code assumes that GetConsoleMode will return an error for file descriptors that are not a console.
  74. func IsConsole(fd uintptr) bool {
  75. _, e := winterm.GetConsoleMode(fd)
  76. return e == nil
  77. }