1package termenv
2
3import (
4	"errors"
5	"os"
6
7	"github.com/mattn/go-isatty"
8)
9
10var (
11	ErrStatusReport = errors.New("unable to retrieve status report")
12)
13
14type Profile int
15
16const (
17	CSI = "\x1b["
18
19	Ascii = Profile(iota)
20	ANSI
21	ANSI256
22	TrueColor
23)
24
25// ColorProfile returns the supported color profile:
26// Ascii, ANSI, ANSI256, or TrueColor.
27func ColorProfile() Profile {
28	if !isatty.IsTerminal(os.Stdout.Fd()) {
29		return Ascii
30	}
31
32	return colorProfile()
33}
34
35// ForegroundColor returns the terminal's default foreground color.
36func ForegroundColor() Color {
37	if !isatty.IsTerminal(os.Stdout.Fd()) {
38		return NoColor{}
39	}
40
41	return foregroundColor()
42}
43
44// BackgroundColor returns the terminal's default background color.
45func BackgroundColor() Color {
46	if !isatty.IsTerminal(os.Stdout.Fd()) {
47		return NoColor{}
48	}
49
50	return backgroundColor()
51}
52
53// HasDarkBackground returns whether terminal uses a dark-ish background.
54func HasDarkBackground() bool {
55	c := ConvertToRGB(BackgroundColor())
56	_, _, l := c.Hsl()
57	return l < 0.5
58}
59
60// EnvNoColor returns true if the environment variables explicitly disable color output
61// by setting NO_COLOR (https://no-color.org/)
62// or CLICOLOR/CLICOLOR_FORCE (https://bixense.com/clicolors/)
63// If NO_COLOR is set, this will return true, ignoring CLICOLOR/CLICOLOR_FORCE
64// If CLICOLOR=="0", it will be true only if CLICOLOR_FORCE is also "0" or is unset.
65func EnvNoColor() bool {
66	return os.Getenv("NO_COLOR") != "" || (os.Getenv("CLICOLOR") == "0" && !cliColorForced())
67}
68
69// EnvColorProfile returns the color profile based on environment variables set
70// Supports NO_COLOR (https://no-color.org/)
71// and CLICOLOR/CLICOLOR_FORCE (https://bixense.com/clicolors/)
72// If none of these environment variables are set, this behaves the same as ColorProfile()
73// It will return the Ascii color profile if EnvNoColor() returns true
74// If the terminal does not support any colors, but CLICOLOR_FORCE is set and not "0"
75// then the ANSI color profile will be returned.
76func EnvColorProfile() Profile {
77	if EnvNoColor() {
78		return Ascii
79	}
80	p := ColorProfile()
81	if cliColorForced() && p == Ascii {
82		return ANSI
83	}
84	return p
85}
86
87func cliColorForced() bool {
88	if forced := os.Getenv("CLICOLOR_FORCE"); forced != "" {
89		return forced != "0"
90	}
91	return false
92}
93