Manually specify the closing SGR for a span
This commit is contained in:
parent
6590be84a2
commit
de9edb6ff5
@ -329,7 +329,7 @@ func SGRFromCSI(csi string) (ans SGR) {
|
||||
|
||||
type Span struct {
|
||||
Offset, Size int // in bytes
|
||||
SGR SGR
|
||||
opening_sgr, closing_sgr SGR
|
||||
}
|
||||
|
||||
func NewSpan(offset, size int) *Span {
|
||||
@ -354,102 +354,93 @@ func (self *ColorVal) Set(val any) {
|
||||
}
|
||||
|
||||
func (self *Span) SetForeground(val any) *Span {
|
||||
self.SGR.Foreground.Set(val)
|
||||
self.opening_sgr.Foreground.Set(val)
|
||||
return self
|
||||
}
|
||||
|
||||
func (self *Span) SetBackground(val any) *Span {
|
||||
self.SGR.Background.Set(val)
|
||||
self.opening_sgr.Background.Set(val)
|
||||
return self
|
||||
}
|
||||
|
||||
func (self *Span) SetUnderlineColor(val any) *Span {
|
||||
self.SGR.Underline_color.Set(val)
|
||||
self.opening_sgr.Underline_color.Set(val)
|
||||
return self
|
||||
}
|
||||
|
||||
func (self *Span) SetItalic(val bool) *Span {
|
||||
self.SGR.Italic.Set(val)
|
||||
self.opening_sgr.Italic.Set(val)
|
||||
return self
|
||||
}
|
||||
|
||||
func (self *Span) SetBold(val bool) *Span {
|
||||
self.SGR.Bold.Set(val)
|
||||
self.opening_sgr.Bold.Set(val)
|
||||
return self
|
||||
}
|
||||
func (self *Span) SetReverse(val bool) *Span {
|
||||
self.SGR.Reverse.Set(val)
|
||||
self.opening_sgr.Reverse.Set(val)
|
||||
return self
|
||||
}
|
||||
func (self *Span) SetDim(val bool) *Span {
|
||||
self.SGR.Dim.Set(val)
|
||||
self.opening_sgr.Dim.Set(val)
|
||||
return self
|
||||
}
|
||||
func (self *Span) SetStrikethrough(val bool) *Span {
|
||||
self.SGR.Strikethrough.Set(val)
|
||||
self.opening_sgr.Strikethrough.Set(val)
|
||||
return self
|
||||
}
|
||||
func (self *Span) SetUnderlineStyle(val UnderlineStyle) *Span {
|
||||
self.SGR.Underline_style.Is_set = true
|
||||
self.SGR.Underline_style.Val = val
|
||||
self.opening_sgr.Underline_style.Is_set = true
|
||||
self.opening_sgr.Underline_style.Val = val
|
||||
return self
|
||||
}
|
||||
|
||||
type defaulting_val interface {
|
||||
DefaultCSI() string
|
||||
func (self *Span) SetClosingForeground(val any) *Span {
|
||||
self.closing_sgr.Foreground.Set(val)
|
||||
return self
|
||||
}
|
||||
|
||||
func append_default_csi(x defaulting_val, ans []byte) []byte {
|
||||
val := x.DefaultCSI()
|
||||
if val != "" {
|
||||
ans = append(ans, val...)
|
||||
ans = append(ans, ';')
|
||||
}
|
||||
return ans
|
||||
func (self *Span) SetClosingBackground(val any) *Span {
|
||||
self.closing_sgr.Background.Set(val)
|
||||
return self
|
||||
}
|
||||
|
||||
func (self *Span) ClosingCSI() string {
|
||||
ans := make([]byte, 0, 16)
|
||||
w := func(x string) {
|
||||
if x != "" {
|
||||
ans = append(append(ans, x...), ';')
|
||||
func (self *Span) SetClosingUnderlineColor(val any) *Span {
|
||||
self.closing_sgr.Underline_color.Set(val)
|
||||
return self
|
||||
}
|
||||
|
||||
func (self *Span) SetClosingItalic(val bool) *Span {
|
||||
self.closing_sgr.Italic.Set(val)
|
||||
return self
|
||||
}
|
||||
if self.SGR.Bold.Is_set {
|
||||
w(self.SGR.Bold.AsCSI("1", "221"))
|
||||
|
||||
func (self *Span) SetClosingBold(val bool) *Span {
|
||||
self.closing_sgr.Bold.Set(val)
|
||||
return self
|
||||
}
|
||||
if self.SGR.Dim.Is_set {
|
||||
w(self.SGR.Dim.AsCSI("2", "222"))
|
||||
func (self *Span) SetClosingReverse(val bool) *Span {
|
||||
self.closing_sgr.Reverse.Set(val)
|
||||
return self
|
||||
}
|
||||
if self.SGR.Italic.Is_set {
|
||||
w(self.SGR.Italic.AsCSI("3", "23"))
|
||||
func (self *Span) SetClosingDim(val bool) *Span {
|
||||
self.closing_sgr.Dim.Set(val)
|
||||
return self
|
||||
}
|
||||
if self.SGR.Reverse.Is_set {
|
||||
w(self.SGR.Reverse.AsCSI("7", "27"))
|
||||
func (self *Span) SetClosingStrikethrough(val bool) *Span {
|
||||
self.closing_sgr.Strikethrough.Set(val)
|
||||
return self
|
||||
}
|
||||
if self.SGR.Strikethrough.Is_set {
|
||||
w(self.SGR.Strikethrough.AsCSI("9", "29"))
|
||||
}
|
||||
wc := func(cval ColorVal, base int) {
|
||||
if cval.Is_set {
|
||||
cval.Is_default = true
|
||||
w(cval.AsCSI(base))
|
||||
}
|
||||
}
|
||||
wc(self.SGR.Foreground, 30)
|
||||
wc(self.SGR.Background, 40)
|
||||
wc(self.SGR.Underline_color, 50)
|
||||
if len(ans) > 0 {
|
||||
ans = ans[:len(ans)-1]
|
||||
ans = append(ans, 'm')
|
||||
}
|
||||
return utils.UnsafeBytesToString(ans)
|
||||
func (self *Span) SetClosingUnderlineStyle(val UnderlineStyle) *Span {
|
||||
self.closing_sgr.Underline_style.Is_set = true
|
||||
self.opening_sgr.Underline_style.Val = val
|
||||
return self
|
||||
}
|
||||
|
||||
// Insert formatting into text at the specified offsets, overriding any existing formatting, and restoring
|
||||
// existing formatting after the replaced sections.
|
||||
func InsertFormatting(text string, spans ...*Span) string {
|
||||
spans = utils.Filter(spans, func(s *Span) bool { return !s.SGR.IsEmpty() })
|
||||
spans = utils.Filter(spans, func(s *Span) bool { return !s.opening_sgr.IsEmpty() })
|
||||
if len(spans) == 0 {
|
||||
return text
|
||||
}
|
||||
@ -470,7 +461,7 @@ func InsertFormatting(text string, spans ...*Span) string {
|
||||
in_span = spans[0]
|
||||
spans = spans[1:]
|
||||
if in_span.Size > 0 {
|
||||
write_csi(in_span.SGR.AsCSI())
|
||||
write_csi(in_span.opening_sgr.AsCSI())
|
||||
} else {
|
||||
in_span = nil
|
||||
}
|
||||
@ -478,7 +469,7 @@ func InsertFormatting(text string, spans ...*Span) string {
|
||||
}
|
||||
|
||||
close_span := func() {
|
||||
write_csi(in_span.ClosingCSI())
|
||||
write_csi(in_span.closing_sgr.AsCSI())
|
||||
write_csi(overall_sgr_state.AsCSI())
|
||||
in_span = nil
|
||||
}
|
||||
@ -515,7 +506,7 @@ func InsertFormatting(text string, spans ...*Span) string {
|
||||
if in_span == nil {
|
||||
write_csi(csi)
|
||||
} else {
|
||||
sgr.ApplyMask(in_span.SGR)
|
||||
sgr.ApplyMask(in_span.opening_sgr)
|
||||
csi := sgr.AsCSI()
|
||||
write_csi(csi)
|
||||
}
|
||||
|
||||
@ -21,16 +21,16 @@ func TestInsertFormatting(t *testing.T) {
|
||||
test(
|
||||
"\x1b[44m abcd \x1b[49m",
|
||||
"\x1b[44m a\x1b[33;41mbc\x1b[39;49m\x1b[44md \x1b[49m",
|
||||
NewSpan(2, 2).SetForeground(3).SetBackground(1),
|
||||
NewSpan(2, 2).SetForeground(3).SetBackground(1).SetClosingForeground(nil).SetClosingBackground(nil),
|
||||
)
|
||||
test(
|
||||
"abcd",
|
||||
"a\x1b[92mbcd\x1b[39m",
|
||||
NewSpan(1, 11).SetForeground(10),
|
||||
NewSpan(1, 11).SetForeground(10).SetClosingForeground(nil),
|
||||
)
|
||||
test(
|
||||
"AB\x1b[1mC\x1b[221mDE",
|
||||
"A\x1b[37mB\x1b[1mC\x1b[221mDE\x1b[39m\x1b[221m",
|
||||
NewSpan(1, 11).SetForeground(7),
|
||||
NewSpan(1, 11).SetForeground(7).SetClosingForeground(nil),
|
||||
)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user