charmbracelet / lipgloss

Style definitions for nice terminal layouts 👄
MIT License
8.03k stars 228 forks source link

Explicitly setting the color profile #33

Closed komalali closed 3 years ago

komalali commented 3 years ago

Curious how y'all test the lipgloss output. I'm currently running into issues where the terminal colors are sometimes rendered in tests and sometimes they are not, and it seems to be based on which directory I'm running go test from. Any ideas on how to handle this?

Screen Shot 2021-05-26 at 10 16 31 AM
muesli commented 3 years ago

It depends whether the string's contents get escaped or not: \x1b... is the escaped version of the string, so it doesn't get interpreted by the terminal. You could strings.ReplaceAll that byte sequence to something more human-readable like ESC.

komalali commented 3 years ago

Sweet, that should keep things consistent at least. Thanks!

komalali commented 3 years ago

Hmm... actually that doesn't seem to help. Even with the escape I still get different results for the string output depending on which directory I run go test from.

komalali commented 3 years ago

The function seems to return a different string based on where go test is run from. I'm totally stumped on how this could be happening. It does seem to respect the italics styling regardless of the directory of execution, but the lipgloss output string has none of the colors if I execute go test ./display but the colors are present in the string if I execute go test from the display directory.

Screen Shot 2021-05-26 at 11 15 36 AM
komalali commented 3 years ago

Ah interesting, if I execute go test . instead of just go test from the display directory I get the same result as running go test ./display from the parent directory

meowgorithm commented 3 years ago

@komalali Can you provide any sort of sample code to replicate the issue?

komalali commented 3 years ago

Indeed! Here's a minimum repro:

Code

repro.go

package main

import (
    "fmt"
    "github.com/charmbracelet/lipgloss"
)

var myStyle = lipgloss.NewStyle().Italic(true).Foreground(lipgloss.Color("205"))

func colorString(str string) string {
    return myStyle.Render(str)
}

func main() {
    fmt.Println(colorString("hello world"))
}

repro_test.go

package main

import (
    "strings"
    "testing"
)

func Test_colorString(t *testing.T) {
    tests := []struct {
        input string
        want string
    }{
        { "hello world", "ESC[3;38;5;205mhello worldESC[0m"},
    }
        for _, tt := range tests {
        t.Run(tt.input, func(t *testing.T) {
            got := colorString(tt.input)
            if got = strings.ReplaceAll(got, "\x1b", "ESC"); got != tt.want {
                t.Errorf("colorString() = %v, want %v", got, tt.want)
            }
        })
    }
}

Instructions

  1. Run go test - observe success
    ❯ go test  
    PASS
    ok      lipgloss-repro  0.164s
  2. Run go test . - observe failure
    ❯ go test .
    --- FAIL: Test_colorString (0.00s)
    --- FAIL: Test_colorString/hello_world (0.00s)
        repro_test.go:20: colorString() = ESC[3;mhello worldESC[0m, want ESC[3;38;5;205mhello worldESC[0m
    FAIL
    FAIL    lipgloss-repro  0.334s
    FAIL

Note: It is curious that the italic styling is preserved in either invocation, but the colors are not.

meowgorithm commented 3 years ago

How very odd this is. I'm seeing the same results but am quite baffled as to why they're occuring.

@muesli: note that I'm able to replicate the same behavior in termenv as well.

muesli commented 3 years ago

This is because the test outputs for entire packages get redirected, and aren't printing to stdout directly anymore. As such termenv detects that it's not rendering to a terminal and ColorProfile returns Ascii instead of an ANSI profile. As far as termenv is concerned, I would recommend simply using termenv.TrueColor as the color profile for your tests.

We will probably have to enhance lipgloss's API to enforce using different color profiles for such use-cases.

meowgorithm commented 3 years ago

That totally makes sense, and is easy enough to do.

meowgorithm commented 3 years ago

This is now in master and will be included in the next release.

@komalali, there's a test included which illustrates how you can use lipgloss.SetColorProfile in your own tests.

komalali commented 3 years ago

Awesome! Thanks for the quick response/turnaround.