rclone/lib/terminal/terminal.go
2023-03-24 20:40:52 +00:00

124 lines
3 KiB
Go

// Package terminal provides VT100 terminal codes and a windows
// implementation of that.
package terminal
import (
"context"
"io"
"os"
"runtime"
"sync"
colorable "github.com/mattn/go-colorable"
"github.com/rclone/rclone/fs"
)
// VT100 codes
const (
EraseLine = "\x1b[2K"
MoveToStartOfLine = "\x1b[1G"
MoveUp = "\x1b[1A"
Reset = "\x1b[0m"
Bright = "\x1b[1m"
Dim = "\x1b[2m"
Underscore = "\x1b[4m"
Blink = "\x1b[5m"
Reverse = "\x1b[7m"
Hidden = "\x1b[8m"
BlackFg = "\x1b[30m"
RedFg = "\x1b[31m"
GreenFg = "\x1b[32m"
YellowFg = "\x1b[33m"
BlueFg = "\x1b[34m"
MagentaFg = "\x1b[35m"
CyanFg = "\x1b[36m"
WhiteFg = "\x1b[37m"
BlackBg = "\x1b[40m"
RedBg = "\x1b[41m"
GreenBg = "\x1b[42m"
YellowBg = "\x1b[43m"
BlueBg = "\x1b[44m"
MagentaBg = "\x1b[45m"
CyanBg = "\x1b[46m"
WhiteBg = "\x1b[47m"
HiBlackFg = "\x1b[90m"
HiRedFg = "\x1b[91m"
HiGreenFg = "\x1b[92m"
HiYellowFg = "\x1b[93m"
HiBlueFg = "\x1b[94m"
HiMagentaFg = "\x1b[95m"
HiCyanFg = "\x1b[96m"
HiWhiteFg = "\x1b[97m"
HiBlackBg = "\x1b[100m"
HiRedBg = "\x1b[101m"
HiGreenBg = "\x1b[102m"
HiYellowBg = "\x1b[103m"
HiBlueBg = "\x1b[104m"
HiMagentaBg = "\x1b[105m"
HiCyanBg = "\x1b[106m"
HiWhiteBg = "\x1b[107m"
ChangeTitle = "\033]0;"
BEL = "\007"
)
var (
// make sure that start is only called once
once sync.Once
)
// Start the terminal - must be called before use
func Start() {
once.Do(func() {
ci := fs.GetConfig(context.Background())
f := os.Stdout
if !IsTerminal(int(f.Fd())) {
// If stdout is not a tty, remove escape codes EXCEPT if terminal color mode equals "ALWAYS"
if ci.TerminalColorMode == fs.TerminalColorModeAlways {
Out = colorable.NewColorable(f)
} else {
Out = colorable.NewNonColorable(f)
}
} else if runtime.GOOS == "windows" && os.Getenv("TERM") != "" {
// If TERM is set just use stdout
Out = f
} else if ci.TerminalColorMode == fs.TerminalColorModeNever {
Out = colorable.NewNonColorable(f)
} else {
Out = colorable.NewColorable(f)
}
})
}
// WriteString writes the string passed in to the terminal
func WriteString(s string) {
Write([]byte(s))
}
// Out is an io.Writer which can be used to write to the terminal
// e.g. for use with fmt.Fprintf(terminal.Out, "terminal fun: %d\n", n)
var Out io.Writer
// Write sends out to the VT100 terminal.
// It will initialise the terminal if this is the first call.
func Write(out []byte) {
Start()
_, _ = Out.Write(out)
}
// EnableColorsStdout enable colors if possible.
// This enables virtual terminal processing on Windows 10 console,
// adding native support for VT100 escape codes. When this terminal
// package is used for output, the result is that the colorable library
// don't have to decode the escapes and explicitly write text with color
// formatting to the console using Windows API functions, but can simply
// relay everything to stdout.
func EnableColorsStdout() {
_ = colorable.EnableColorsStdout(nil)
}