mirror of
https://github.com/walles/moar.git
synced 2024-10-26 13:00:40 +03:00
Compare commits
5 Commits
43f17ebe7b
...
f69e58d9b3
Author | SHA1 | Date | |
---|---|---|---|
|
f69e58d9b3 | ||
|
065b95a653 | ||
|
d9b3e16e00 | ||
|
ae0ae42241 | ||
|
2c9f16fa2a |
@ -511,6 +511,18 @@ func rawUpdateStyle(style twin.Style, escapeSequenceWithoutHeader string, number
|
||||
case 49:
|
||||
style = style.WithBackground(twin.ColorDefault)
|
||||
|
||||
case 58:
|
||||
var err error
|
||||
var color *twin.Color
|
||||
index, color, err = consumeCompositeColor(numbersBuffer, index-1)
|
||||
if err != nil {
|
||||
return style, numbersBuffer, fmt.Errorf("Underline: %w", err)
|
||||
}
|
||||
style = style.WithUnderlineColor(*color)
|
||||
|
||||
case 59:
|
||||
style = style.WithUnderlineColor(twin.ColorDefault)
|
||||
|
||||
// Bright foreground colors: see https://pkg.go.dev/github.com/gdamore/Color
|
||||
//
|
||||
// After testing vs less and cat on iTerm2 3.3.9 / macOS Catalina
|
||||
@ -573,9 +585,9 @@ func joinUints(ints []uint) string {
|
||||
// * A color value that can be applied to a style
|
||||
func consumeCompositeColor(numbers []uint, index int) (int, *twin.Color, error) {
|
||||
baseIndex := index
|
||||
if numbers[index] != 38 && numbers[index] != 48 {
|
||||
if numbers[index] != 38 && numbers[index] != 48 && numbers[index] != 58 {
|
||||
err := fmt.Errorf(
|
||||
"unknown start of color sequence <%d>, expected 38 (foreground) or 48 (background): <CSI %sm>",
|
||||
"unknown start of color sequence <%d>, expected 38 (foreground), 48 (background) or 58 (underline): <CSI %sm>",
|
||||
numbers[index],
|
||||
joinUints(numbers[baseIndex:]))
|
||||
return -1, nil, err
|
||||
|
@ -216,7 +216,7 @@ func TestConsumeCompositeColorBadPrefix(t *testing.T) {
|
||||
// 8 bit color
|
||||
// Example from: https://github.com/walles/moar/issues/14
|
||||
_, color, err := consumeCompositeColor([]uint{29}, 0)
|
||||
assert.Equal(t, err.Error(), "unknown start of color sequence <29>, expected 38 (foreground) or 48 (background): <CSI 29m>")
|
||||
assert.Equal(t, err.Error(), "unknown start of color sequence <29>, expected 38 (foreground), 48 (background) or 58 (underline): <CSI 29m>")
|
||||
assert.Assert(t, color == nil)
|
||||
}
|
||||
|
||||
|
1
sample-files/colored-underlines.txt
Normal file
1
sample-files/colored-underlines.txt
Normal file
@ -0,0 +1 @@
|
||||
[4m[58:5:196mRed underline[59m Default colored underline
|
@ -19,9 +19,10 @@ const (
|
||||
)
|
||||
|
||||
type Style struct {
|
||||
fg Color
|
||||
bg Color
|
||||
attrs AttrMask
|
||||
fg Color
|
||||
bg Color
|
||||
underlineColor Color
|
||||
attrs AttrMask
|
||||
|
||||
// This hyperlinkURL is a URL for in-terminal hyperlinks.
|
||||
//
|
||||
@ -37,8 +38,13 @@ type Style struct {
|
||||
var StyleDefault Style
|
||||
|
||||
func (style Style) String() string {
|
||||
undelineSuffix := ""
|
||||
if style.underlineColor != ColorDefault {
|
||||
undelineSuffix = fmt.Sprintf(" underlined with %v", style.underlineColor)
|
||||
}
|
||||
|
||||
if style.attrs == AttrNone {
|
||||
return fmt.Sprint(style.fg, " on ", style.bg)
|
||||
return fmt.Sprint(style.fg, " on ", style.bg, undelineSuffix)
|
||||
}
|
||||
|
||||
attrNames := make([]string, 0)
|
||||
@ -67,15 +73,16 @@ func (style Style) String() string {
|
||||
attrNames = append(attrNames, "\""+*style.hyperlinkURL+"\"")
|
||||
}
|
||||
|
||||
return fmt.Sprint(strings.Join(attrNames, " "), " ", style.fg, " on ", style.bg)
|
||||
return fmt.Sprint(strings.Join(attrNames, " "), " ", style.fg, " on ", style.bg, undelineSuffix)
|
||||
}
|
||||
|
||||
func (style Style) WithAttr(attr AttrMask) Style {
|
||||
result := Style{
|
||||
fg: style.fg,
|
||||
bg: style.bg,
|
||||
attrs: style.attrs | attr,
|
||||
hyperlinkURL: style.hyperlinkURL,
|
||||
fg: style.fg,
|
||||
bg: style.bg,
|
||||
underlineColor: style.underlineColor,
|
||||
attrs: style.attrs | attr,
|
||||
hyperlinkURL: style.hyperlinkURL,
|
||||
}
|
||||
|
||||
// Bold and dim are mutually exclusive
|
||||
@ -97,19 +104,21 @@ func (style Style) WithHyperlink(hyperlinkURL *string) Style {
|
||||
}
|
||||
|
||||
return Style{
|
||||
fg: style.fg,
|
||||
bg: style.bg,
|
||||
attrs: style.attrs,
|
||||
hyperlinkURL: hyperlinkURL,
|
||||
fg: style.fg,
|
||||
bg: style.bg,
|
||||
underlineColor: style.underlineColor,
|
||||
attrs: style.attrs,
|
||||
hyperlinkURL: hyperlinkURL,
|
||||
}
|
||||
}
|
||||
|
||||
func (style Style) WithoutAttr(attr AttrMask) Style {
|
||||
return Style{
|
||||
fg: style.fg,
|
||||
bg: style.bg,
|
||||
attrs: style.attrs & ^attr,
|
||||
hyperlinkURL: style.hyperlinkURL,
|
||||
fg: style.fg,
|
||||
bg: style.bg,
|
||||
underlineColor: style.underlineColor,
|
||||
attrs: style.attrs & ^attr,
|
||||
hyperlinkURL: style.hyperlinkURL,
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,19 +128,31 @@ func (attr AttrMask) has(attrs AttrMask) bool {
|
||||
|
||||
func (style Style) WithBackground(color Color) Style {
|
||||
return Style{
|
||||
fg: style.fg,
|
||||
bg: color,
|
||||
attrs: style.attrs,
|
||||
hyperlinkURL: style.hyperlinkURL,
|
||||
fg: style.fg,
|
||||
bg: color,
|
||||
underlineColor: style.underlineColor,
|
||||
attrs: style.attrs,
|
||||
hyperlinkURL: style.hyperlinkURL,
|
||||
}
|
||||
}
|
||||
|
||||
func (style Style) WithForeground(color Color) Style {
|
||||
return Style{
|
||||
fg: color,
|
||||
bg: style.bg,
|
||||
attrs: style.attrs,
|
||||
hyperlinkURL: style.hyperlinkURL,
|
||||
fg: color,
|
||||
bg: style.bg,
|
||||
underlineColor: style.underlineColor,
|
||||
attrs: style.attrs,
|
||||
hyperlinkURL: style.hyperlinkURL,
|
||||
}
|
||||
}
|
||||
|
||||
func (style Style) WithUnderlineColor(color Color) Style {
|
||||
return Style{
|
||||
fg: style.fg,
|
||||
bg: style.bg,
|
||||
underlineColor: color,
|
||||
attrs: style.attrs,
|
||||
hyperlinkURL: style.hyperlinkURL,
|
||||
}
|
||||
}
|
||||
|
||||
@ -159,6 +180,10 @@ func (current Style) RenderUpdateFrom(previous Style, terminalColorCount ColorCo
|
||||
builder.WriteString(current.bg.ansiString(colorTypeBackground, terminalColorCount))
|
||||
}
|
||||
|
||||
if current.underlineColor != previous.underlineColor {
|
||||
builder.WriteString(current.underlineColor.ansiString(colorTypeUnderline, terminalColorCount))
|
||||
}
|
||||
|
||||
// Handle AttrDim / AttrBold changes
|
||||
previousBoldDim := previous.attrs & (AttrBold | AttrDim)
|
||||
currentBoldDim := current.attrs & (AttrBold | AttrDim)
|
||||
|
Loading…
Reference in New Issue
Block a user