Skip to content

Commit 337e381

Browse files
committed
fixes #606 Want ColorNone to preserve existing color(s)
While here, consolidate the use of the Fill() function from CellBuffer (eliminating redundant code).
1 parent 8041b8e commit 337e381

File tree

4 files changed

+87
-22
lines changed

4 files changed

+87
-22
lines changed

cell.go

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2022 The TCell Authors
1+
// Copyright 2023 The TCell Authors
22
//
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use file except in compliance with the License.
@@ -31,7 +31,7 @@ type cell struct {
3131
lock bool
3232
}
3333

34-
// CellBuffer represents a two dimensional array of character cells.
34+
// CellBuffer represents a two-dimensional array of character cells.
3535
// This is primarily intended for use by Screen implementors; it
3636
// contains much of the common code they need. To create one, just
3737
// declare a variable of its type; no explicit initialization is necessary.
@@ -44,7 +44,9 @@ type CellBuffer struct {
4444
}
4545

4646
// SetContent sets the contents (primary rune, combining runes,
47-
// and style) for a cell at a given location.
47+
// and style) for a cell at a given location. If the background or
48+
// foreground of the style is set to ColorNone, then the respective
49+
// color is left un changed.
4850
func (cb *CellBuffer) SetContent(x int, y int,
4951
mainc rune, combc []rune, style Style,
5052
) {
@@ -61,6 +63,12 @@ func (cb *CellBuffer) SetContent(x int, y int,
6163
c.width = runewidth.RuneWidth(mainc)
6264
}
6365
c.currMain = mainc
66+
if style.fg == ColorNone {
67+
style.fg = c.currStyle.fg
68+
}
69+
if style.bg == ColorNone {
70+
style.bg = c.currStyle.bg
71+
}
6472
c.currStyle = style
6573
}
6674
}
@@ -97,10 +105,9 @@ func (cb *CellBuffer) Invalidate() {
97105
}
98106
}
99107

100-
// Dirty checks if a character at the given location needs an
101-
// to be refreshed on the physical display. This returns true
102-
// if the cell content is different since the last time it was
103-
// marked clean.
108+
// Dirty checks if a character at the given location needs to be
109+
// refreshed on the physical display. This returns true if the cell
110+
// content is different since the last time it was marked clean.
104111
func (cb *CellBuffer) Dirty(x, y int) bool {
105112
if x >= 0 && y >= 0 && x < cb.w && y < cb.h {
106113
c := &cb.cells[(y*cb.w)+x]
@@ -204,12 +211,21 @@ func (cb *CellBuffer) Resize(w, h int) {
204211
// Fill fills the entire cell buffer array with the specified character
205212
// and style. Normally choose ' ' to clear the screen. This API doesn't
206213
// support combining characters, or characters with a width larger than one.
214+
// If either the foreground or background are ColorNone, then the respective
215+
// color is unchanged.
207216
func (cb *CellBuffer) Fill(r rune, style Style) {
208217
for i := range cb.cells {
209218
c := &cb.cells[i]
210219
c.currMain = r
211220
c.currComb = nil
212-
c.currStyle = style
221+
cs := style
222+
if cs.fg == ColorNone {
223+
cs.fg = c.currStyle.fg
224+
}
225+
if cs.bg == ColorNone {
226+
cs.bg = c.currStyle.bg
227+
}
228+
c.currStyle = cs
213229
c.width = 1
214230
}
215231
}
@@ -224,7 +240,7 @@ func init() {
224240
runewidth.DefaultCondition.EastAsianWidth = false
225241
}
226242

227-
// For performance reasons, we create a lookup table. However some users
243+
// For performance reasons, we create a lookup table. However, some users
228244
// might be more memory conscious. If that's you, set the TCELL_MINIMIZE
229245
// environment variable.
230246
if os.Getenv("TCELL_MINIMIZE") == "" {

color.go

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2020 The TCell Authors
1+
// Copyright 2023 The TCell Authors
22
//
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use file except in compliance with the License.
@@ -839,6 +839,11 @@ const (
839839
// ColorReset is used to indicate that the color should use the
840840
// vanilla terminal colors. (Basically go back to the defaults.)
841841
ColorReset = ColorSpecial | iota
842+
843+
// ColorNone indicates that we should not change the color from
844+
// whatever is already displayed. This can only be used in limited
845+
// circumstances.
846+
ColorNone
842847
)
843848

844849
// ColorNames holds the written names of colors. Useful to present a list of
@@ -1002,8 +1007,8 @@ func (c Color) IsRGB() bool {
10021007
return c&(ColorValid|ColorIsRGB) == (ColorValid | ColorIsRGB)
10031008
}
10041009

1005-
// CSS returns the CSS hex string ( #ABCDEF ) if valid
1006-
// if not a valid color returns empty string
1010+
// CSS returns the CSS hex string ( #ABCDEF ) if valid
1011+
// if not a valid color returns empty string
10071012
func (c Color) CSS() string {
10081013
if !c.Valid() {
10091014
return ""
@@ -1015,13 +1020,21 @@ func (c Color) CSS() string {
10151020
// W3C name if it has one or the CSS hex string '#ABCDEF'
10161021
func (c Color) String() string {
10171022
if !c.Valid() {
1023+
switch c {
1024+
case ColorNone:
1025+
return "none"
1026+
case ColorDefault:
1027+
return "default"
1028+
case ColorReset:
1029+
return "reset"
1030+
}
10181031
return ""
10191032
}
10201033
return c.Name(true)
10211034
}
10221035

10231036
// Name returns W3C name or an empty string if no arguments
1024-
// if passed true as an argument it will falls back to
1037+
// if passed true as an argument it will falls back to
10251038
// the CSS hex string if no W3C name found '#ABCDEF'
10261039
func (c Color) Name(css ...bool) string {
10271040
for name, hex := range ColorNames {

color_test.go

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2018 The TCell Authors
1+
// Copyright 2023 The TCell Authors
22
//
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use file except in compliance with the License.
@@ -46,7 +46,7 @@ func TestColorValues(t *testing.T) {
4646
}
4747

4848
func TestColorFitting(t *testing.T) {
49-
pal := []Color{}
49+
var pal []Color
5050
for i := 0; i < 255; i++ {
5151
pal = append(pal, PaletteColor(i))
5252
}
@@ -108,6 +108,17 @@ func TestColorNameLookup(t *testing.T) {
108108
t.Errorf("TrueColor did not match")
109109
}
110110
}
111+
112+
// these colors only have strings (for debugging), you cannot use them to create a color
113+
if ColorNone.String() != "none" {
114+
t.Errorf("ColorNone did not match")
115+
}
116+
if ColorReset.String() != "reset" {
117+
t.Errorf("ColorReset did not match")
118+
}
119+
if ColorDefault.String() != "default" {
120+
t.Errorf("ColorDefault did not match")
121+
}
111122
}
112123

113124
func TestColorRGB(t *testing.T) {
@@ -132,3 +143,34 @@ func TestFromImageColor(t *testing.T) {
132143
t.Errorf("%v is not 0x00FFFF", hex)
133144
}
134145
}
146+
147+
func TestColorNone(t *testing.T) {
148+
s := mkTestScreen(t, "")
149+
s.Init()
150+
s.SetSize(80, 24)
151+
st := StyleDefault.Foreground(ColorBlack).Background(ColorWhite)
152+
s.Fill(' ', st)
153+
if _, _, s1, _ := s.GetContent(0, 0); s1 != st {
154+
t.Errorf("Wrong style! fg %s bg %s", s1.fg.String(), s1.bg.String())
155+
}
156+
st2 := st.Foreground(ColorNone).Background(ColorNone)
157+
s.Fill('X', st2)
158+
if _, _, s1, _ := s.GetContent(0, 0); s1 != st {
159+
t.Errorf("Wrong style! fg %s bg %s", s1.fg.String(), s1.bg.String())
160+
}
161+
red := st.Foreground(ColorRed).Background(ColorNone)
162+
s.SetContent(1, 0, ' ', nil, red)
163+
if _, _, s1, _ := s.GetContent(1, 0); s1 != red.Background(st.bg) {
164+
t.Errorf("Wrong style! fg %s bg %s", s1.fg.String(), s1.bg.String())
165+
}
166+
if _, _, s1, _ := s.GetContent(0, 0); s1 != st {
167+
t.Errorf("Wrong style! fg %s bg %s", s1.fg.String(), s1.bg.String())
168+
}
169+
pink := st.Background(ColorPink).Foreground(ColorNone)
170+
s.SetContent(1, 0, ' ', nil, pink)
171+
combined := pink.Foreground(ColorRed)
172+
173+
if _, _, s1, _ := s.GetContent(1, 0); s1 != combined {
174+
t.Errorf("Wrong style! fg %s bg %s", s1.fg.String(), s1.bg.String())
175+
}
176+
}

screen.go

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -376,13 +376,7 @@ func (b *baseScreen) Clear() {
376376
func (b *baseScreen) Fill(r rune, style Style) {
377377
cb := b.GetCells()
378378
b.Lock()
379-
for i := range cb.cells {
380-
c := &cb.cells[i]
381-
c.currMain = r
382-
c.currComb = nil
383-
c.currStyle = style
384-
c.width = 1
385-
}
379+
cb.Fill(r, style)
386380
b.Unlock()
387381
}
388382

0 commit comments

Comments
 (0)