goterminalcommand-line-interfacettyterminal-color

How to Detect If Current Terminal Supports 16-Color or 256-Color in Go?


We got many popular packages in Go to render colorized text in terminal, like fatih/color, gookit/color, lucasb-eyer/go-colorful.

However I'm facing a problem that --- apart from seeing with my own eyes, how to detect if current terminal supports 16-Color or 256-Color programmatically in Go (even on Windows)?


Solution

  • As mentioned in "Determine whether the current Linux console supports 256 colours?" (and that is on Linux, the same portability issue would exist on Windows)

    As an example of non-portable option, you could use curses (on Linux), as discussed here and implemented in curses.go:

    Looking at tput colors and tigetnum('colors') (which return numbers like 1, 8, 256, or greater) are more along the lines of feature testing, which is less hacky and more future-proof.

    func Init(theme *ColorTheme, black bool, mouse bool) {
        {
            in, err := os.OpenFile("/dev/tty", syscall.O_RDONLY, 0)
            if err != nil {
                panic("Failed to open /dev/tty")
            }
            _in = in
            // Break STDIN
            // syscall.Dup2(int(in.Fd()), int(os.Stdin.Fd()))
        }
    
        C.setlocale(C.LC_ALL, C.CString(""))
        _screen = C.c_newterm()
        if _screen == nil {
            fmt.Println("Invalid $TERM: " + os.Getenv("TERM"))
            os.Exit(2)
        }
        C.set_term(_screen)
        if mouse {
            C.mousemask(C.ALL_MOUSE_EVENTS, nil)
        }
        C.noecho()
        C.raw() // stty dsusp undef
    
        if theme != nil {
            C.start_color()
            var baseTheme *ColorTheme
            if C.tigetnum(C.CString("colors")) >= 256 {
                baseTheme = Dark256
            } else {
                baseTheme = Default16
            }
            initPairs(baseTheme, theme, black)
            _color = attrColored
        } else {
            _color = attrMono
        }
    }