fatih / color

Color package for Go (golang)
https://pkg.go.dev/github.com/fatih/color
MIT License
7.17k stars 610 forks source link

output auto-alignment #160

Closed Ran-Xing closed 1 year ago

Ran-Xing commented 2 years ago

Excuse me, can I do it to define two colors at the same time, the left is the command and the right is the result

func Notice(noticeTXT, resultTXT string) {
    color.New(color.FgBlue).PrintfFunc()(" %-15v", noticeTXT)
    color.New(color.FgGreen).PrintfFunc()(" %-15v\n", resultTXT)
}
func main(){
    Notice("whoami:", "root")
}
image

Different results lead to inconsistent length and partial output cannot be aligned

kellypleahy commented 2 years ago

@Ran-Xing this looks like it might be an issue with your code, not the library. -15v means "left aligned in space of 15". Since your second line has more than 15 chars on the LHS, it is not aligned as expected. This is a function of the way the underlying formatter works rather than the library, I think ("which docker-compose:" is more than 15 chars so it doesn't fit an overflows the space).

winey-dev commented 2 years ago

hi @kellypleahy i also had a similar issue. this code ..

func Grade(grade string) string {
    var c *color.Color
    switch grade {
    case "minor":
        c = color.New(color.BgYellow)
    case "major":
        c = color.New(color.BgMagenta)
    case "critical":
        c = color.New(color.BgRed)
    case "cleared":
        c = color.New(color.BgGreen).Add(color.FgHiWhite)
    case "warning":
        c = color.New(color.BgBlue)
    case "indeterminate":
        c = color.New(color.BgCyan)
    case "mask":
        c = color.New(color.FgHiWhite)
    }

    if c == nil {
        return " "
    }
    return c.Sprintf("%s", grade)
}

func main() {
    strs := []string{
        "minor",
        "major",
        "critical",
        "cleared",
        "warning",
        "indeterminate",
        "mask",
    }

    for _, str := range strs {
        fmt.Printf("[%-2d] : [%-32s] [%s]\n", len(Grade(str)), Grade(str), "2022-07-01 10:10:10.000")
    }
    return
}

this code run

image

this same code runs, but green occupies space differently.

kellypleahy commented 2 years ago

@yiaw unfortunately, I think your issue is related to a bigger "problem" with the design of the library.

I suspect if you look, the printf formatting of -32s is taking into the count of the chars in the escape sequences that are added to the string. As such, you aren't really printing the whole string, but rather printing a subset of it (after the chars have been stripped). As a result, I think the lengths get changed. I don't have the time right now to confirm this, but I hoped that posting something might be helpful to someone trying to debug this.

If you look at your stuff above, I think you can see that the length of the strings that are not "cleared" are length of the text + 9. However, for "cleared" it is length of the text + 12. Those extra 3 characters correspond to what you are "losing" on the right hand side of your buffer once the line gets stripped by the library. Basically, the sprintf in the library prints your string "with escape sequences" fitted to 32 chars, and then it drops the escape sequences. If the sequences are the same length, you might not notice, so long as you don't have any strings longer than 32 chars. However, if you use different length sequences, you notice the difference.

I think the issue is related to #157 and they are both caused by a similar design issue - that is that the strings are manipulated by writing stuff before and after them when doing format, but that affects the length of the stuff passed to format.

that said, I think your issue might be alleviated if you printed the line in pieces, printing the colored bit separately from the non-colored bits. That is less than ideal, but should work.

winey-dev commented 2 years ago

Thanks for the reply @kellypleahy

so , i solved it like below.

func Grade(grade string) string {
    var c *color.Color
    switch grade {
    case "minor":
        c = color.New(color.BgYellow)
    case "major":
        c = color.New(color.BgMagenta)
    case "critical":
        c = color.New(color.BgRed)
    case "cleared":
        c = color.New(color.BgGreen)
    case "warning":
        c = color.New(color.BgBlue)
    case "indeterminate":
        c = color.New(color.BgCyan)
    case "mask":
        c = color.New(color.FgHiWhite)
    }

    if c == nil {
        return " "
    }

    return c.Sprintf("%s", grade)
}

remove green colors removed "Add()" method. so i want print format

image

Ran-Xing commented 1 year ago

The users and developers of this warehouse are the best I have ever seen, thank you