Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use terminfo instead of hardcoding a list of terminals #25

Closed
vincentbernat opened this issue Sep 5, 2020 · 9 comments
Closed

Use terminfo instead of hardcoding a list of terminals #25

vincentbernat opened this issue Sep 5, 2020 · 9 comments
Assignees
Labels
enhancement question

Comments

@vincentbernat
Copy link

@vincentbernat vincentbernat commented Sep 5, 2020

Hey!

You should use terminfo instead of relying on the terminal name in TERM. This can provide you the number of colors supported. Otherwise, you are missing a lot of terminals supporting colors, like rxvt or screen. In Go, it seems https://github.com/xo/terminfo can do that. It also seems to handle some edge cases for terminals not using the correct TERM. It also handles the special case of true color which was not available through terminfo until recently and is able to fallback to COLORTERM (but it should be using Tc if available).

@inhere inhere self-assigned this Sep 6, 2020
inhere added a commit that referenced this issue Sep 12, 2020
@Delta456
Copy link

@Delta456 Delta456 commented Nov 30, 2020

Please use this instead of hardcore logic 🙏

@Delta456
Copy link

@Delta456 Delta456 commented Nov 30, 2020

Also WSL has true color support.

@inhere inhere added the question label Dec 3, 2020
@Delta456
Copy link

@Delta456 Delta456 commented Dec 3, 2020

Here's how I did it https://github.com/Delta456/box-cli-maker/blob/dev/util.go, see detectTerminalColor function

@inhere
Copy link
Member

@inhere inhere commented Dec 3, 2020

ok, thanks

@inhere inhere added the enhancement label Dec 4, 2020
@Delta456
Copy link

@Delta456 Delta456 commented Dec 4, 2020

I found this from https://www.github.com/chalk/supports-color/tree/master/index.js

  // Windows 10 build 10586 is the first Windows release that supports 256 colors.
        // Windows 10 build 14931 is the first release that supports 16m/TrueColor

@inhere
Copy link
Member

@inhere inhere commented Apr 6, 2021

hi @vincentbernat @Delta456

Thanks you.

I refer xo/terminfo.detectColorLevelFromEnv and https://github.com/Delta456/box-cli-maker, rewrite the detect method: detectTermColorLevel()

code please see https://github.com/gookit/color/blob/master/detect_env.go

@Delta456
Copy link

@Delta456 Delta456 commented Apr 6, 2021

@inhere Amazing! Would appreciate if you could also add my repo as reference in the REAMDE.md.

@Delta456
Copy link

@Delta456 Delta456 commented Apr 6, 2021

Also I believe you could had imported my module and used it instead of making one.

@inhere
Copy link
Member

@inhere inhere commented Apr 6, 2021

hi @Delta456

Your module also has some problems, please see my detection code

color/detect_env.go

Lines 31 to 156 in 1459bf6

func detectTermColorLevel() (level terminfo.ColorLevel, needVTP bool) {
var err error
// on windows WSL:
// - runtime.GOOS == "Linux"
// - support true-color
// env:
// WSL_DISTRO_NAME=Debian
if val := os.Getenv("WSL_DISTRO_NAME"); val != "" {
// detect WSL as it has True Color support
if detectWSL() {
debugf("True Color support on WSL environment")
return terminfo.ColorLevelMillions, false
}
}
isWin := runtime.GOOS == "windows"
// TERM=screen
termVal := os.Getenv("TERM")
// on `screen` not support True-color
if termVal != "screen" {
// On JetBrains Terminal
// - support true-color
// TERMINAL_EMULATOR=JetBrains-JediTerm
val := os.Getenv("TERMINAL_EMULATOR")
if val == "JetBrains-JediTerm" {
debugf("True Color support on JetBrains-JediTerm, is win: %v", isWin)
return terminfo.ColorLevelMillions, isWin
}
}
// level, err = terminfo.ColorLevelFromEnv()
level, err = detectColorLevelFromEnv(termVal)
// fmt.Println(level.String(), err)
// debugf("color level by terminfo.ColorLevelFromEnv(): %s", level)
if err != nil {
// if on windows OS
if isWin {
debugf("fallback1 check special term color on windows")
level, needVTP = detectSpecialTermColor()
} else {
saveInternalError(err)
}
return
}
// enable VTP as it has True Color support
if level == terminfo.ColorLevelNone && isWin {
debugf("fallback2 check special term color on windows")
level, needVTP = detectSpecialTermColor()
}
return
}
// detectColorFromEnv returns the color level COLORTERM, FORCE_COLOR,
// TERM_PROGRAM, or determined from the TERM environment variable.
//
// refer the terminfo.ColorLevelFromEnv()
func detectColorLevelFromEnv(termVal string) (terminfo.ColorLevel, error) {
// on TERM=screen: not support true-color
// termVal := os.Getenv("TERM")
// check for overriding environment variables
colorTerm, termProg, forceColor := os.Getenv("COLORTERM"), os.Getenv("TERM_PROGRAM"), os.Getenv("FORCE_COLOR")
switch {
case strings.Contains(colorTerm, "truecolor") || strings.Contains(colorTerm, "24bit") || termProg == "Hyper":
if termVal == "screen" { // on TERM=screen: not support true-color
return terminfo.ColorLevelHundreds, nil
}
return terminfo.ColorLevelMillions, nil
case colorTerm != "" || forceColor != "":
return terminfo.ColorLevelBasic, nil
case termProg == "Apple_Terminal":
return terminfo.ColorLevelHundreds, nil
case termProg == "Terminus":
if termVal == "screen" { // on TERM=screen: not support true-color
return terminfo.ColorLevelHundreds, nil
}
return terminfo.ColorLevelMillions, nil
case termProg == "iTerm.app":
if termVal == "screen" { // on TERM=screen: not support true-color
return terminfo.ColorLevelHundreds, nil
}
// check version
ver := os.Getenv("TERM_PROGRAM_VERSION")
if ver == "" {
return terminfo.ColorLevelHundreds, nil
}
i, err := strconv.Atoi(strings.Split(ver, ".")[0])
if err != nil {
return terminfo.ColorLevelNone, terminfo.ErrInvalidTermProgramVersion
}
if i == 3 {
return terminfo.ColorLevelMillions, nil
}
return terminfo.ColorLevelHundreds, nil
}
// otherwise determine from TERM's max_colors capability
if termVal != "" {
ti, err := terminfo.Load(termVal)
if err != nil {
return terminfo.ColorLevelNone, err
}
// on TERM=screen:
// - support 256, not support true-color. test on macOS
if termVal == "screen" {
return terminfo.ColorLevelHundreds, nil
}
v, ok := ti.Nums[terminfo.MaxColors]
switch {
case !ok || v <= 16:
return terminfo.ColorLevelNone, nil
case ok && v >= 256:
return terminfo.ColorLevelHundreds, nil
}
return terminfo.ColorLevelBasic, nil
}
// Not TERM env value. default return none level
return terminfo.ColorLevelNone, nil
// return terminfo.ColorLevelBasic, nil
}

And my package as the base package, can not rely on your application package in reverse. :)

@inhere inhere closed this as completed Apr 18, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement question
Projects
None yet
Development

No branches or pull requests

3 participants