forked from toolshed/abra
build: go 1.24
We were running behind and there were quite some deprecations to update. This was mostly in the upstream copy/pasta package but seems quite minimal.
This commit is contained in:
508
vendor/github.com/charmbracelet/x/cellbuf/cell.go
generated
vendored
Normal file
508
vendor/github.com/charmbracelet/x/cellbuf/cell.go
generated
vendored
Normal file
@ -0,0 +1,508 @@
|
||||
package cellbuf
|
||||
|
||||
import (
|
||||
"github.com/charmbracelet/x/ansi"
|
||||
)
|
||||
|
||||
var (
|
||||
// BlankCell is a cell with a single space, width of 1, and no style or link.
|
||||
BlankCell = Cell{Rune: ' ', Width: 1}
|
||||
|
||||
// EmptyCell is just an empty cell used for comparisons and as a placeholder
|
||||
// for wide cells.
|
||||
EmptyCell = Cell{}
|
||||
)
|
||||
|
||||
// Cell represents a single cell in the terminal screen.
|
||||
type Cell struct {
|
||||
// The style of the cell. Nil style means no style. Zero value prints a
|
||||
// reset sequence.
|
||||
Style Style
|
||||
|
||||
// Link is the hyperlink of the cell.
|
||||
Link Link
|
||||
|
||||
// Comb is the combining runes of the cell. This is nil if the cell is a
|
||||
// single rune or if it's a zero width cell that is part of a wider cell.
|
||||
Comb []rune
|
||||
|
||||
// Width is the mono-space width of the grapheme cluster.
|
||||
Width int
|
||||
|
||||
// Rune is the main rune of the cell. This is zero if the cell is part of a
|
||||
// wider cell.
|
||||
Rune rune
|
||||
}
|
||||
|
||||
// Append appends runes to the cell without changing the width. This is useful
|
||||
// when we want to use the cell to store escape sequences or other runes that
|
||||
// don't affect the width of the cell.
|
||||
func (c *Cell) Append(r ...rune) {
|
||||
for i, r := range r {
|
||||
if i == 0 && c.Rune == 0 {
|
||||
c.Rune = r
|
||||
continue
|
||||
}
|
||||
c.Comb = append(c.Comb, r)
|
||||
}
|
||||
}
|
||||
|
||||
// String returns the string content of the cell excluding any styles, links,
|
||||
// and escape sequences.
|
||||
func (c Cell) String() string {
|
||||
if c.Rune == 0 {
|
||||
return ""
|
||||
}
|
||||
if len(c.Comb) == 0 {
|
||||
return string(c.Rune)
|
||||
}
|
||||
return string(append([]rune{c.Rune}, c.Comb...))
|
||||
}
|
||||
|
||||
// Equal returns whether the cell is equal to the other cell.
|
||||
func (c *Cell) Equal(o *Cell) bool {
|
||||
return o != nil &&
|
||||
c.Width == o.Width &&
|
||||
c.Rune == o.Rune &&
|
||||
runesEqual(c.Comb, o.Comb) &&
|
||||
c.Style.Equal(&o.Style) &&
|
||||
c.Link.Equal(&o.Link)
|
||||
}
|
||||
|
||||
// Empty returns whether the cell is an empty cell. An empty cell is a cell
|
||||
// with a width of 0, a rune of 0, and no combining runes.
|
||||
func (c Cell) Empty() bool {
|
||||
return c.Width == 0 &&
|
||||
c.Rune == 0 &&
|
||||
len(c.Comb) == 0
|
||||
}
|
||||
|
||||
// Reset resets the cell to the default state zero value.
|
||||
func (c *Cell) Reset() {
|
||||
c.Rune = 0
|
||||
c.Comb = nil
|
||||
c.Width = 0
|
||||
c.Style.Reset()
|
||||
c.Link.Reset()
|
||||
}
|
||||
|
||||
// Clear returns whether the cell consists of only attributes that don't
|
||||
// affect appearance of a space character.
|
||||
func (c *Cell) Clear() bool {
|
||||
return c.Rune == ' ' && len(c.Comb) == 0 && c.Width == 1 && c.Style.Clear() && c.Link.Empty()
|
||||
}
|
||||
|
||||
// Clone returns a copy of the cell.
|
||||
func (c *Cell) Clone() (n *Cell) {
|
||||
n = new(Cell)
|
||||
*n = *c
|
||||
return
|
||||
}
|
||||
|
||||
// Blank makes the cell a blank cell by setting the rune to a space, comb to
|
||||
// nil, and the width to 1.
|
||||
func (c *Cell) Blank() *Cell {
|
||||
c.Rune = ' '
|
||||
c.Comb = nil
|
||||
c.Width = 1
|
||||
return c
|
||||
}
|
||||
|
||||
// Link represents a hyperlink in the terminal screen.
|
||||
type Link struct {
|
||||
URL string
|
||||
Params string
|
||||
}
|
||||
|
||||
// String returns a string representation of the hyperlink.
|
||||
func (h Link) String() string {
|
||||
return h.URL
|
||||
}
|
||||
|
||||
// Reset resets the hyperlink to the default state zero value.
|
||||
func (h *Link) Reset() {
|
||||
h.URL = ""
|
||||
h.Params = ""
|
||||
}
|
||||
|
||||
// Equal returns whether the hyperlink is equal to the other hyperlink.
|
||||
func (h *Link) Equal(o *Link) bool {
|
||||
return o != nil && h.URL == o.URL && h.Params == o.Params
|
||||
}
|
||||
|
||||
// Empty returns whether the hyperlink is empty.
|
||||
func (h Link) Empty() bool {
|
||||
return h.URL == "" && h.Params == ""
|
||||
}
|
||||
|
||||
// AttrMask is a bitmask for text attributes that can change the look of text.
|
||||
// These attributes can be combined to create different styles.
|
||||
type AttrMask uint8
|
||||
|
||||
// These are the available text attributes that can be combined to create
|
||||
// different styles.
|
||||
const (
|
||||
BoldAttr AttrMask = 1 << iota
|
||||
FaintAttr
|
||||
ItalicAttr
|
||||
SlowBlinkAttr
|
||||
RapidBlinkAttr
|
||||
ReverseAttr
|
||||
ConcealAttr
|
||||
StrikethroughAttr
|
||||
|
||||
ResetAttr AttrMask = 0
|
||||
)
|
||||
|
||||
// Contains returns whether the attribute mask contains the attribute.
|
||||
func (a AttrMask) Contains(attr AttrMask) bool {
|
||||
return a&attr == attr
|
||||
}
|
||||
|
||||
// UnderlineStyle is the style of underline to use for text.
|
||||
type UnderlineStyle = ansi.UnderlineStyle
|
||||
|
||||
// These are the available underline styles.
|
||||
const (
|
||||
NoUnderline = ansi.NoUnderlineStyle
|
||||
SingleUnderline = ansi.SingleUnderlineStyle
|
||||
DoubleUnderline = ansi.DoubleUnderlineStyle
|
||||
CurlyUnderline = ansi.CurlyUnderlineStyle
|
||||
DottedUnderline = ansi.DottedUnderlineStyle
|
||||
DashedUnderline = ansi.DashedUnderlineStyle
|
||||
)
|
||||
|
||||
// Style represents the Style of a cell.
|
||||
type Style struct {
|
||||
Fg ansi.Color
|
||||
Bg ansi.Color
|
||||
Ul ansi.Color
|
||||
Attrs AttrMask
|
||||
UlStyle UnderlineStyle
|
||||
}
|
||||
|
||||
// Sequence returns the ANSI sequence that sets the style.
|
||||
func (s Style) Sequence() string {
|
||||
if s.Empty() {
|
||||
return ansi.ResetStyle
|
||||
}
|
||||
|
||||
var b ansi.Style
|
||||
|
||||
if s.Attrs != 0 {
|
||||
if s.Attrs&BoldAttr != 0 {
|
||||
b = b.Bold()
|
||||
}
|
||||
if s.Attrs&FaintAttr != 0 {
|
||||
b = b.Faint()
|
||||
}
|
||||
if s.Attrs&ItalicAttr != 0 {
|
||||
b = b.Italic()
|
||||
}
|
||||
if s.Attrs&SlowBlinkAttr != 0 {
|
||||
b = b.SlowBlink()
|
||||
}
|
||||
if s.Attrs&RapidBlinkAttr != 0 {
|
||||
b = b.RapidBlink()
|
||||
}
|
||||
if s.Attrs&ReverseAttr != 0 {
|
||||
b = b.Reverse()
|
||||
}
|
||||
if s.Attrs&ConcealAttr != 0 {
|
||||
b = b.Conceal()
|
||||
}
|
||||
if s.Attrs&StrikethroughAttr != 0 {
|
||||
b = b.Strikethrough()
|
||||
}
|
||||
}
|
||||
if s.UlStyle != NoUnderline {
|
||||
switch s.UlStyle {
|
||||
case SingleUnderline:
|
||||
b = b.Underline()
|
||||
case DoubleUnderline:
|
||||
b = b.DoubleUnderline()
|
||||
case CurlyUnderline:
|
||||
b = b.CurlyUnderline()
|
||||
case DottedUnderline:
|
||||
b = b.DottedUnderline()
|
||||
case DashedUnderline:
|
||||
b = b.DashedUnderline()
|
||||
}
|
||||
}
|
||||
if s.Fg != nil {
|
||||
b = b.ForegroundColor(s.Fg)
|
||||
}
|
||||
if s.Bg != nil {
|
||||
b = b.BackgroundColor(s.Bg)
|
||||
}
|
||||
if s.Ul != nil {
|
||||
b = b.UnderlineColor(s.Ul)
|
||||
}
|
||||
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// DiffSequence returns the ANSI sequence that sets the style as a diff from
|
||||
// another style.
|
||||
func (s Style) DiffSequence(o Style) string {
|
||||
if o.Empty() {
|
||||
return s.Sequence()
|
||||
}
|
||||
|
||||
var b ansi.Style
|
||||
|
||||
if !colorEqual(s.Fg, o.Fg) {
|
||||
b = b.ForegroundColor(s.Fg)
|
||||
}
|
||||
|
||||
if !colorEqual(s.Bg, o.Bg) {
|
||||
b = b.BackgroundColor(s.Bg)
|
||||
}
|
||||
|
||||
if !colorEqual(s.Ul, o.Ul) {
|
||||
b = b.UnderlineColor(s.Ul)
|
||||
}
|
||||
|
||||
var (
|
||||
noBlink bool
|
||||
isNormal bool
|
||||
)
|
||||
|
||||
if s.Attrs != o.Attrs {
|
||||
if s.Attrs&BoldAttr != o.Attrs&BoldAttr {
|
||||
if s.Attrs&BoldAttr != 0 {
|
||||
b = b.Bold()
|
||||
} else if !isNormal {
|
||||
isNormal = true
|
||||
b = b.NormalIntensity()
|
||||
}
|
||||
}
|
||||
if s.Attrs&FaintAttr != o.Attrs&FaintAttr {
|
||||
if s.Attrs&FaintAttr != 0 {
|
||||
b = b.Faint()
|
||||
} else if !isNormal {
|
||||
b = b.NormalIntensity()
|
||||
}
|
||||
}
|
||||
if s.Attrs&ItalicAttr != o.Attrs&ItalicAttr {
|
||||
if s.Attrs&ItalicAttr != 0 {
|
||||
b = b.Italic()
|
||||
} else {
|
||||
b = b.NoItalic()
|
||||
}
|
||||
}
|
||||
if s.Attrs&SlowBlinkAttr != o.Attrs&SlowBlinkAttr {
|
||||
if s.Attrs&SlowBlinkAttr != 0 {
|
||||
b = b.SlowBlink()
|
||||
} else if !noBlink {
|
||||
noBlink = true
|
||||
b = b.NoBlink()
|
||||
}
|
||||
}
|
||||
if s.Attrs&RapidBlinkAttr != o.Attrs&RapidBlinkAttr {
|
||||
if s.Attrs&RapidBlinkAttr != 0 {
|
||||
b = b.RapidBlink()
|
||||
} else if !noBlink {
|
||||
b = b.NoBlink()
|
||||
}
|
||||
}
|
||||
if s.Attrs&ReverseAttr != o.Attrs&ReverseAttr {
|
||||
if s.Attrs&ReverseAttr != 0 {
|
||||
b = b.Reverse()
|
||||
} else {
|
||||
b = b.NoReverse()
|
||||
}
|
||||
}
|
||||
if s.Attrs&ConcealAttr != o.Attrs&ConcealAttr {
|
||||
if s.Attrs&ConcealAttr != 0 {
|
||||
b = b.Conceal()
|
||||
} else {
|
||||
b = b.NoConceal()
|
||||
}
|
||||
}
|
||||
if s.Attrs&StrikethroughAttr != o.Attrs&StrikethroughAttr {
|
||||
if s.Attrs&StrikethroughAttr != 0 {
|
||||
b = b.Strikethrough()
|
||||
} else {
|
||||
b = b.NoStrikethrough()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if s.UlStyle != o.UlStyle {
|
||||
b = b.UnderlineStyle(s.UlStyle)
|
||||
}
|
||||
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// Equal returns true if the style is equal to the other style.
|
||||
func (s *Style) Equal(o *Style) bool {
|
||||
return s.Attrs == o.Attrs &&
|
||||
s.UlStyle == o.UlStyle &&
|
||||
colorEqual(s.Fg, o.Fg) &&
|
||||
colorEqual(s.Bg, o.Bg) &&
|
||||
colorEqual(s.Ul, o.Ul)
|
||||
}
|
||||
|
||||
func colorEqual(c, o ansi.Color) bool {
|
||||
if c == nil && o == nil {
|
||||
return true
|
||||
}
|
||||
if c == nil || o == nil {
|
||||
return false
|
||||
}
|
||||
cr, cg, cb, ca := c.RGBA()
|
||||
or, og, ob, oa := o.RGBA()
|
||||
return cr == or && cg == og && cb == ob && ca == oa
|
||||
}
|
||||
|
||||
// Bold sets the bold attribute.
|
||||
func (s *Style) Bold(v bool) *Style {
|
||||
if v {
|
||||
s.Attrs |= BoldAttr
|
||||
} else {
|
||||
s.Attrs &^= BoldAttr
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Faint sets the faint attribute.
|
||||
func (s *Style) Faint(v bool) *Style {
|
||||
if v {
|
||||
s.Attrs |= FaintAttr
|
||||
} else {
|
||||
s.Attrs &^= FaintAttr
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Italic sets the italic attribute.
|
||||
func (s *Style) Italic(v bool) *Style {
|
||||
if v {
|
||||
s.Attrs |= ItalicAttr
|
||||
} else {
|
||||
s.Attrs &^= ItalicAttr
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// SlowBlink sets the slow blink attribute.
|
||||
func (s *Style) SlowBlink(v bool) *Style {
|
||||
if v {
|
||||
s.Attrs |= SlowBlinkAttr
|
||||
} else {
|
||||
s.Attrs &^= SlowBlinkAttr
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// RapidBlink sets the rapid blink attribute.
|
||||
func (s *Style) RapidBlink(v bool) *Style {
|
||||
if v {
|
||||
s.Attrs |= RapidBlinkAttr
|
||||
} else {
|
||||
s.Attrs &^= RapidBlinkAttr
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Reverse sets the reverse attribute.
|
||||
func (s *Style) Reverse(v bool) *Style {
|
||||
if v {
|
||||
s.Attrs |= ReverseAttr
|
||||
} else {
|
||||
s.Attrs &^= ReverseAttr
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Conceal sets the conceal attribute.
|
||||
func (s *Style) Conceal(v bool) *Style {
|
||||
if v {
|
||||
s.Attrs |= ConcealAttr
|
||||
} else {
|
||||
s.Attrs &^= ConcealAttr
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Strikethrough sets the strikethrough attribute.
|
||||
func (s *Style) Strikethrough(v bool) *Style {
|
||||
if v {
|
||||
s.Attrs |= StrikethroughAttr
|
||||
} else {
|
||||
s.Attrs &^= StrikethroughAttr
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// UnderlineStyle sets the underline style.
|
||||
func (s *Style) UnderlineStyle(style UnderlineStyle) *Style {
|
||||
s.UlStyle = style
|
||||
return s
|
||||
}
|
||||
|
||||
// Underline sets the underline attribute.
|
||||
// This is a syntactic sugar for [UnderlineStyle].
|
||||
func (s *Style) Underline(v bool) *Style {
|
||||
if v {
|
||||
return s.UnderlineStyle(SingleUnderline)
|
||||
}
|
||||
return s.UnderlineStyle(NoUnderline)
|
||||
}
|
||||
|
||||
// Foreground sets the foreground color.
|
||||
func (s *Style) Foreground(c ansi.Color) *Style {
|
||||
s.Fg = c
|
||||
return s
|
||||
}
|
||||
|
||||
// Background sets the background color.
|
||||
func (s *Style) Background(c ansi.Color) *Style {
|
||||
s.Bg = c
|
||||
return s
|
||||
}
|
||||
|
||||
// UnderlineColor sets the underline color.
|
||||
func (s *Style) UnderlineColor(c ansi.Color) *Style {
|
||||
s.Ul = c
|
||||
return s
|
||||
}
|
||||
|
||||
// Reset resets the style to default.
|
||||
func (s *Style) Reset() *Style {
|
||||
s.Fg = nil
|
||||
s.Bg = nil
|
||||
s.Ul = nil
|
||||
s.Attrs = ResetAttr
|
||||
s.UlStyle = NoUnderline
|
||||
return s
|
||||
}
|
||||
|
||||
// Empty returns true if the style is empty.
|
||||
func (s *Style) Empty() bool {
|
||||
return s.Fg == nil && s.Bg == nil && s.Ul == nil && s.Attrs == ResetAttr && s.UlStyle == NoUnderline
|
||||
}
|
||||
|
||||
// Clear returns whether the style consists of only attributes that don't
|
||||
// affect appearance of a space character.
|
||||
func (s *Style) Clear() bool {
|
||||
return s.UlStyle == NoUnderline &&
|
||||
s.Attrs&^(BoldAttr|FaintAttr|ItalicAttr|SlowBlinkAttr|RapidBlinkAttr) == 0 &&
|
||||
s.Fg == nil &&
|
||||
s.Bg == nil &&
|
||||
s.Ul == nil
|
||||
}
|
||||
|
||||
func runesEqual(a, b []rune) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
for i, r := range a {
|
||||
if r != b[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
Reference in New Issue
Block a user