color.go

 1package terminfo
 2
 3import (
 4	"os"
 5	"strconv"
 6	"strings"
 7)
 8
 9// ColorLevel is the color level supported by a terminal.
10type ColorLevel uint
11
12// ColorLevel values.
13const (
14	ColorLevelNone ColorLevel = iota
15	ColorLevelBasic
16	ColorLevelHundreds
17	ColorLevelMillions
18)
19
20// String satisfies the Stringer interface.
21func (c ColorLevel) String() string {
22	switch c {
23	case ColorLevelBasic:
24		return "basic"
25	case ColorLevelHundreds:
26		return "hundreds"
27	case ColorLevelMillions:
28		return "millions"
29	}
30	return "none"
31}
32
33// ChromaFormatterName returns the github.com/alecthomas/chroma compatible
34// formatter name for the color level.
35func (c ColorLevel) ChromaFormatterName() string {
36	switch c {
37	case ColorLevelBasic:
38		return "terminal"
39	case ColorLevelHundreds:
40		return "terminal256"
41	case ColorLevelMillions:
42		return "terminal16m"
43	}
44	return "noop"
45}
46
47// ColorLevelFromEnv returns the color level COLORTERM, FORCE_COLOR,
48// TERM_PROGRAM, or determined from the TERM environment variable.
49func ColorLevelFromEnv() (ColorLevel, error) {
50	// check for overriding environment variables
51	colorTerm, termProg, forceColor := os.Getenv("COLORTERM"), os.Getenv("TERM_PROGRAM"), os.Getenv("FORCE_COLOR")
52	switch {
53	case strings.Contains(colorTerm, "truecolor") || strings.Contains(colorTerm, "24bit") || termProg == "Hyper":
54		return ColorLevelMillions, nil
55	case colorTerm != "" || forceColor != "":
56		return ColorLevelBasic, nil
57	case termProg == "Apple_Terminal":
58		return ColorLevelHundreds, nil
59	case termProg == "iTerm.app":
60		ver := os.Getenv("TERM_PROGRAM_VERSION")
61		if ver == "" {
62			return ColorLevelHundreds, nil
63		}
64		i, err := strconv.Atoi(strings.Split(ver, ".")[0])
65		if err != nil {
66			return ColorLevelNone, ErrInvalidTermProgramVersion
67		}
68		if i == 3 {
69			return ColorLevelMillions, nil
70		}
71		return ColorLevelHundreds, nil
72	}
73	// otherwise determine from TERM's max_colors capability
74	if term := os.Getenv("TERM"); term != "" {
75		ti, err := Load(term)
76		if err != nil {
77			return ColorLevelNone, err
78		}
79		v, ok := ti.Nums[MaxColors]
80		switch {
81		case !ok || v <= 16:
82			return ColorLevelNone, nil
83		case ok && v >= 256:
84			return ColorLevelHundreds, nil
85		}
86	}
87	return ColorLevelBasic, nil
88}