sequence.go

  1package cellbuf
  2
  3import (
  4	"bytes"
  5	"image/color"
  6
  7	"github.com/charmbracelet/x/ansi"
  8)
  9
 10// ReadStyle reads a Select Graphic Rendition (SGR) escape sequences from a
 11// list of parameters.
 12func ReadStyle(params ansi.Params, pen *Style) {
 13	if len(params) == 0 {
 14		pen.Reset()
 15		return
 16	}
 17
 18	for i := 0; i < len(params); i++ {
 19		param, hasMore, _ := params.Param(i, 0)
 20		switch param {
 21		case 0: // Reset
 22			pen.Reset()
 23		case 1: // Bold
 24			pen.Bold(true)
 25		case 2: // Dim/Faint
 26			pen.Faint(true)
 27		case 3: // Italic
 28			pen.Italic(true)
 29		case 4: // Underline
 30			nextParam, _, ok := params.Param(i+1, 0)
 31			if hasMore && ok { // Only accept subparameters i.e. separated by ":"
 32				switch nextParam {
 33				case 0, 1, 2, 3, 4, 5:
 34					i++
 35					switch nextParam {
 36					case 0: // No Underline
 37						pen.UnderlineStyle(NoUnderline)
 38					case 1: // Single Underline
 39						pen.UnderlineStyle(SingleUnderline)
 40					case 2: // Double Underline
 41						pen.UnderlineStyle(DoubleUnderline)
 42					case 3: // Curly Underline
 43						pen.UnderlineStyle(CurlyUnderline)
 44					case 4: // Dotted Underline
 45						pen.UnderlineStyle(DottedUnderline)
 46					case 5: // Dashed Underline
 47						pen.UnderlineStyle(DashedUnderline)
 48					}
 49				}
 50			} else {
 51				// Single Underline
 52				pen.Underline(true)
 53			}
 54		case 5: // Slow Blink
 55			pen.SlowBlink(true)
 56		case 6: // Rapid Blink
 57			pen.RapidBlink(true)
 58		case 7: // Reverse
 59			pen.Reverse(true)
 60		case 8: // Conceal
 61			pen.Conceal(true)
 62		case 9: // Crossed-out/Strikethrough
 63			pen.Strikethrough(true)
 64		case 22: // Normal Intensity (not bold or faint)
 65			pen.Bold(false).Faint(false)
 66		case 23: // Not italic, not Fraktur
 67			pen.Italic(false)
 68		case 24: // Not underlined
 69			pen.Underline(false)
 70		case 25: // Blink off
 71			pen.SlowBlink(false).RapidBlink(false)
 72		case 27: // Positive (not reverse)
 73			pen.Reverse(false)
 74		case 28: // Reveal
 75			pen.Conceal(false)
 76		case 29: // Not crossed out
 77			pen.Strikethrough(false)
 78		case 30, 31, 32, 33, 34, 35, 36, 37: // Set foreground
 79			pen.Foreground(ansi.Black + ansi.BasicColor(param-30)) //nolint:gosec
 80		case 38: // Set foreground 256 or truecolor
 81			var c color.Color
 82			n := ReadStyleColor(params[i:], &c)
 83			if n > 0 {
 84				pen.Foreground(c)
 85				i += n - 1
 86			}
 87		case 39: // Default foreground
 88			pen.Foreground(nil)
 89		case 40, 41, 42, 43, 44, 45, 46, 47: // Set background
 90			pen.Background(ansi.Black + ansi.BasicColor(param-40)) //nolint:gosec
 91		case 48: // Set background 256 or truecolor
 92			var c color.Color
 93			n := ReadStyleColor(params[i:], &c)
 94			if n > 0 {
 95				pen.Background(c)
 96				i += n - 1
 97			}
 98		case 49: // Default Background
 99			pen.Background(nil)
100		case 58: // Set underline color
101			var c color.Color
102			n := ReadStyleColor(params[i:], &c)
103			if n > 0 {
104				pen.UnderlineColor(c)
105				i += n - 1
106			}
107		case 59: // Default underline color
108			pen.UnderlineColor(nil)
109		case 90, 91, 92, 93, 94, 95, 96, 97: // Set bright foreground
110			pen.Foreground(ansi.BrightBlack + ansi.BasicColor(param-90)) //nolint:gosec
111		case 100, 101, 102, 103, 104, 105, 106, 107: // Set bright background
112			pen.Background(ansi.BrightBlack + ansi.BasicColor(param-100)) //nolint:gosec
113		}
114	}
115}
116
117// ReadLink reads a hyperlink escape sequence from a data buffer.
118func ReadLink(p []byte, link *Link) {
119	params := bytes.Split(p, []byte{';'})
120	if len(params) != 3 {
121		return
122	}
123	link.Params = string(params[1])
124	link.URL = string(params[2])
125}
126
127// ReadStyleColor reads a color from a list of parameters.
128// See [ansi.ReadStyleColor] for more information.
129func ReadStyleColor(params ansi.Params, c *color.Color) int {
130	return ansi.ReadStyleColor(params, c)
131}