Skip to content

Commit

Permalink
Refine ForegroundFunc style option
Browse files Browse the repository at this point in the history
Refine new style option `ForegroundFunc` by finialising the function signature.

Fix wrong counting logic for new lines.

Add test cases for new style.
  • Loading branch information
HeavyWombat committed Feb 7, 2021
1 parent b8642b4 commit 2da738f
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 39 deletions.
30 changes: 18 additions & 12 deletions convenience.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,29 +147,35 @@ func Foreground(color colorful.Color) StyleOption {
}

// ForegroundFunc uses the provided function to set an individual foreground
// color for each part of the text, based on the position in the text. The
// function is given a float in the range between 0 and 1, normalized using the
// longest row/line in the string. Each row is handled separately.
func ForegroundFunc(f func(float64) colorful.Color) StyleOption {
// color for each part of the text, which can be based on the position (x, y)
// or the content (rune) in the text.
func ForegroundFunc(f func(int, int, rune) *colorful.Color) StyleOption {
return StyleOption{
postProcess: func(s *String, flags map[string]struct{}) {
var maxLineLength = float64(s.lineLength())
_, blendColors := flags["blendColors"]

var x, y int
for i, c := range *s {
if c.Symbol == '\n' {
x = 0
y++
continue
}

color := f(float64(x) / maxLineLength)
r, g, b := color.RGB255()
if color := f(x, y, c.Symbol); color != nil {
r, g, b := color.RGB255()
if blendColors {
if fgColor := ((*s)[i].Settings >> 8 & 0xFFFFFF); fgColor != 0 {
r, g, b = blend(r, g, b, fgColor)
}
}

(*s)[i].Settings &= 0xFFFFFFFF000000FF
(*s)[i].Settings |= 1
(*s)[i].Settings |= uint64(r) << 8
(*s)[i].Settings |= uint64(g) << 16
(*s)[i].Settings |= uint64(b) << 24
(*s)[i].Settings &= 0xFFFFFFFF000000FF
(*s)[i].Settings |= 1
(*s)[i].Settings |= uint64(r) << 8
(*s)[i].Settings |= uint64(g) << 16
(*s)[i].Settings |= uint64(b) << 24
}

x++
}
Expand Down
49 changes: 49 additions & 0 deletions convenience_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,5 +165,54 @@ var _ = Describe("convenience functions", func() {
BeEquivalentTo("\x1b[38;2;255;0;0mtext with \x1b[38;2;145;174;136mcolored parts\x1b[38;2;255;0;0m.\x1b[0m"),
)
})

It("should set a conditional foreground color based on the respective content", func() {
Expect(Style(
"foobar\nfOObAr",
ForegroundFunc(func(_, _ int, r rune) *colorful.Color {
switch r {
case 'o':
return &Green

case 'a':
return &Red
}

return nil
})),
).To(Equal("f\x1b[38;2;0;128;0moo\x1b[0mb\x1b[38;2;255;0;0ma\x1b[0mr\nfOObAr"))
})

It("should set a conditional foreground color based on the position in the content", func() {
Expect(Style(
"foobar\nfOObAr",
ForegroundFunc(func(x, _ int, _ rune) *colorful.Color {
switch x {
case 1, 2:
return &Green

case 4:
return &Red
}

return nil
})),
).To(Equal("f\x1b[38;2;0;128;0moo\x1b[0mb\x1b[38;2;255;0;0ma\x1b[0mr\nf\x1b[38;2;0;128;0mOO\x1b[0mb\x1b[38;2;255;0;0mA\x1b[0mr"))
})

It("should set a conditional foreground color by blending it with the current color", func() {
Expect(Style(
Sprintf("Lime{foobar}"),
Blend(),
ForegroundFunc(func(_, _ int, r rune) *colorful.Color {
switch r {
case 'o':
return &Red
}

return nil
})),
).To(Equal("\x1b[38;2;0;255;0mf\x1b[38;2;145;174;136moo\x1b[38;2;0;255;0mbar\x1b[0m"))
})
})
})
27 changes: 0 additions & 27 deletions model.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,6 @@

package bunt

import (
"strings"
"unicode/utf8"
)

// String is a string with color information
type String []ColoredRune

Expand All @@ -50,25 +45,3 @@ type ColoredRune struct {
func (s *String) Substring(from, to int) {
*s = (*s)[from:to]
}

func (s *String) rawString() string {
var runes = make([]rune, len(*s))
for i, c := range *s {
runes[i] = c.Symbol
}

return string(runes)
}

func (s *String) lineLength() int {
var lines = strings.Split(s.rawString(), "\n")
var max = 0

for _, line := range lines {
if len := utf8.RuneCountInString(line); len > max {
max = len
}
}

return max
}

0 comments on commit 2da738f

Please sign in to comment.