github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/lib/terminal/terminal.go (about)

     1  // Package terminal provides VT100 terminal codes and a windows
     2  // implementation of that.
     3  package terminal
     4  
     5  import (
     6  	"context"
     7  	"io"
     8  	"os"
     9  	"runtime"
    10  	"sync"
    11  
    12  	colorable "github.com/mattn/go-colorable"
    13  	"github.com/rclone/rclone/fs"
    14  )
    15  
    16  // VT100 codes
    17  const (
    18  	EraseLine         = "\x1b[2K"
    19  	MoveToStartOfLine = "\x1b[1G"
    20  	MoveUp            = "\x1b[1A"
    21  
    22  	Reset      = "\x1b[0m"
    23  	Bright     = "\x1b[1m"
    24  	Dim        = "\x1b[2m"
    25  	Underscore = "\x1b[4m"
    26  	Blink      = "\x1b[5m"
    27  	Reverse    = "\x1b[7m"
    28  	Hidden     = "\x1b[8m"
    29  
    30  	BlackFg   = "\x1b[30m"
    31  	RedFg     = "\x1b[31m"
    32  	GreenFg   = "\x1b[32m"
    33  	YellowFg  = "\x1b[33m"
    34  	BlueFg    = "\x1b[34m"
    35  	MagentaFg = "\x1b[35m"
    36  	CyanFg    = "\x1b[36m"
    37  	WhiteFg   = "\x1b[37m"
    38  
    39  	BlackBg   = "\x1b[40m"
    40  	RedBg     = "\x1b[41m"
    41  	GreenBg   = "\x1b[42m"
    42  	YellowBg  = "\x1b[43m"
    43  	BlueBg    = "\x1b[44m"
    44  	MagentaBg = "\x1b[45m"
    45  	CyanBg    = "\x1b[46m"
    46  	WhiteBg   = "\x1b[47m"
    47  
    48  	HiBlackFg   = "\x1b[90m"
    49  	HiRedFg     = "\x1b[91m"
    50  	HiGreenFg   = "\x1b[92m"
    51  	HiYellowFg  = "\x1b[93m"
    52  	HiBlueFg    = "\x1b[94m"
    53  	HiMagentaFg = "\x1b[95m"
    54  	HiCyanFg    = "\x1b[96m"
    55  	HiWhiteFg   = "\x1b[97m"
    56  
    57  	HiBlackBg   = "\x1b[100m"
    58  	HiRedBg     = "\x1b[101m"
    59  	HiGreenBg   = "\x1b[102m"
    60  	HiYellowBg  = "\x1b[103m"
    61  	HiBlueBg    = "\x1b[104m"
    62  	HiMagentaBg = "\x1b[105m"
    63  	HiCyanBg    = "\x1b[106m"
    64  	HiWhiteBg   = "\x1b[107m"
    65  
    66  	ChangeTitle = "\033]0;"
    67  	BEL         = "\007"
    68  )
    69  
    70  var (
    71  	// make sure that start is only called once
    72  	once sync.Once
    73  )
    74  
    75  // Start the terminal - must be called before use
    76  func Start() {
    77  	once.Do(func() {
    78  		ci := fs.GetConfig(context.Background())
    79  
    80  		f := os.Stdout
    81  		if !IsTerminal(int(f.Fd())) {
    82  			// If stdout is not a tty, remove escape codes EXCEPT if terminal color mode equals "ALWAYS"
    83  			if ci.TerminalColorMode == fs.TerminalColorModeAlways {
    84  				Out = colorable.NewColorable(f)
    85  			} else {
    86  				Out = colorable.NewNonColorable(f)
    87  			}
    88  		} else if runtime.GOOS == "windows" && os.Getenv("TERM") != "" {
    89  			// If TERM is set just use stdout
    90  			Out = f
    91  		} else if ci.TerminalColorMode == fs.TerminalColorModeNever {
    92  			Out = colorable.NewNonColorable(f)
    93  		} else {
    94  			Out = colorable.NewColorable(f)
    95  		}
    96  	})
    97  }
    98  
    99  // WriteString writes the string passed in to the terminal
   100  func WriteString(s string) {
   101  	Write([]byte(s))
   102  }
   103  
   104  // Out is an io.Writer which can be used to write to the terminal
   105  // e.g. for use with fmt.Fprintf(terminal.Out, "terminal fun: %d\n", n)
   106  var Out io.Writer
   107  
   108  // Write sends out to the VT100 terminal.
   109  // It will initialise the terminal if this is the first call.
   110  func Write(out []byte) {
   111  	Start()
   112  	_, _ = Out.Write(out)
   113  }
   114  
   115  // EnableColorsStdout enable colors if possible.
   116  // This enables virtual terminal processing on Windows 10 console,
   117  // adding native support for VT100 escape codes. When this terminal
   118  // package is used for output, the result is that the colorable library
   119  // don't have to decode the escapes and explicitly write text with color
   120  // formatting to the console using Windows API functions, but can simply
   121  // relay everything to stdout.
   122  func EnableColorsStdout() {
   123  	_ = colorable.EnableColorsStdout(nil)
   124  }