...

Source file src/github.com/muesli/termenv/termenv_windows.go

Documentation: github.com/muesli/termenv

     1  //go:build windows
     2  // +build windows
     3  
     4  package termenv
     5  
     6  import (
     7  	"fmt"
     8  	"strconv"
     9  
    10  	"golang.org/x/sys/windows"
    11  )
    12  
    13  func (o *Output) ColorProfile() Profile {
    14  	if !o.isTTY() {
    15  		return Ascii
    16  	}
    17  
    18  	if o.environ.Getenv("ConEmuANSI") == "ON" {
    19  		return TrueColor
    20  	}
    21  
    22  	winVersion, _, buildNumber := windows.RtlGetNtVersionNumbers()
    23  	if buildNumber < 10586 || winVersion < 10 {
    24  		// No ANSI support before Windows 10 build 10586.
    25  		if o.environ.Getenv("ANSICON") != "" {
    26  			conVersion := o.environ.Getenv("ANSICON_VER")
    27  			cv, err := strconv.ParseInt(conVersion, 10, 64)
    28  			if err != nil || cv < 181 {
    29  				// No 8 bit color support before v1.81 release.
    30  				return ANSI
    31  			}
    32  
    33  			return ANSI256
    34  		}
    35  
    36  		return Ascii
    37  	}
    38  	if buildNumber < 14931 {
    39  		// No true color support before build 14931.
    40  		return ANSI256
    41  	}
    42  
    43  	return TrueColor
    44  }
    45  
    46  func (o Output) foregroundColor() Color {
    47  	// default gray
    48  	return ANSIColor(7)
    49  }
    50  
    51  func (o Output) backgroundColor() Color {
    52  	// default black
    53  	return ANSIColor(0)
    54  }
    55  
    56  // EnableWindowsANSIConsole enables virtual terminal processing on Windows
    57  // platforms. This allows the use of ANSI escape sequences in Windows console
    58  // applications. Ensure this gets called before anything gets rendered with
    59  // termenv.
    60  //
    61  // Returns the original console mode and an error if one occurred.
    62  func EnableWindowsANSIConsole() (uint32, error) {
    63  	handle, err := windows.GetStdHandle(windows.STD_OUTPUT_HANDLE)
    64  	if err != nil {
    65  		return 0, err
    66  	}
    67  
    68  	var mode uint32
    69  	err = windows.GetConsoleMode(handle, &mode)
    70  	if err != nil {
    71  		return 0, err
    72  	}
    73  
    74  	// See https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences
    75  	if mode&windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING != windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING {
    76  		vtpmode := mode | windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING
    77  		if err := windows.SetConsoleMode(handle, vtpmode); err != nil {
    78  			return 0, err
    79  		}
    80  	}
    81  
    82  	return mode, nil
    83  }
    84  
    85  // RestoreWindowsConsole restores the console mode to a previous state.
    86  func RestoreWindowsConsole(mode uint32) error {
    87  	handle, err := windows.GetStdHandle(windows.STD_OUTPUT_HANDLE)
    88  	if err != nil {
    89  		return err
    90  	}
    91  
    92  	return windows.SetConsoleMode(handle, mode)
    93  }
    94  
    95  // EnableVirtualTerminalProcessing enables virtual terminal processing on
    96  // Windows for o and returns a function that restores o to its previous state.
    97  // On non-Windows platforms, or if o does not refer to a terminal, then it
    98  // returns a non-nil no-op function and no error.
    99  func EnableVirtualTerminalProcessing(o *Output) (restoreFunc func() error, err error) {
   100  	// There is nothing to restore until we set the console mode.
   101  	restoreFunc = func() error {
   102  		return nil
   103  	}
   104  
   105  	// If o is not a tty, then there is nothing to do.
   106  	tty := o.TTY()
   107  	if tty == nil {
   108  		return
   109  	}
   110  
   111  	// Get the current console mode. If there is an error, assume that o is not
   112  	// a terminal, discard the error, and return.
   113  	var mode uint32
   114  	if err2 := windows.GetConsoleMode(windows.Handle(tty.Fd()), &mode); err2 != nil {
   115  		return
   116  	}
   117  
   118  	// If virtual terminal processing is already set, then there is nothing to
   119  	// do and nothing to restore.
   120  	if mode&windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING == windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING {
   121  		return
   122  	}
   123  
   124  	// Enable virtual terminal processing. See
   125  	// https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences
   126  	if err2 := windows.SetConsoleMode(windows.Handle(tty.Fd()), mode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING); err2 != nil {
   127  		err = fmt.Errorf("windows.SetConsoleMode: %w", err2)
   128  		return
   129  	}
   130  
   131  	// Set the restore function. We maintain a reference to the tty in the
   132  	// closure (rather than just its handle) to ensure that the tty is not
   133  	// closed by a finalizer.
   134  	restoreFunc = func() error {
   135  		return windows.SetConsoleMode(windows.Handle(tty.Fd()), mode)
   136  	}
   137  
   138  	return
   139  }
   140  

View as plain text