-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(cellbuf): add common sequence decoding utilities
This abstracts the decoding of Select Graphic Rendition (SGR) escape sequences and hyperlink escape sequences from the cellbuf package. This will allow other packages to use these utilities without having to duplicate the code.
- Loading branch information
1 parent
62850e9
commit 4755a29
Showing
1 changed file
with
126 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
package cellbuf | ||
|
||
import ( | ||
"bytes" | ||
|
||
"github.com/charmbracelet/x/ansi" | ||
) | ||
|
||
// DecodeStyle decodes a Select Graphic Rendition (SGR) escape sequences from a | ||
// list of parameters. | ||
func DecodeStyle(params []ansi.Parameter, pen *Style) { | ||
if len(params) == 0 { | ||
pen.Reset() | ||
return | ||
} | ||
|
||
for i := 0; i < len(params); i++ { | ||
r := params[i] | ||
param, hasMore := r.Param(0), r.HasMore() // Are there more subparameters i.e. separated by ":"? | ||
switch param { | ||
case 0: // Reset | ||
pen.Reset() | ||
case 1: // Bold | ||
pen.Bold(true) | ||
case 2: // Dim/Faint | ||
pen.Faint(true) | ||
case 3: // Italic | ||
pen.Italic(true) | ||
case 4: // Underline | ||
if hasMore { // Only accept subparameters i.e. separated by ":" | ||
nextParam := params[i+1].Param(0) | ||
switch nextParam { | ||
case 0, 1, 2, 3, 4, 5: | ||
i++ | ||
switch nextParam { | ||
case 0: // No Underline | ||
pen.UnderlineStyle(NoUnderline) | ||
case 1: // Single Underline | ||
pen.UnderlineStyle(SingleUnderline) | ||
case 2: // Double Underline | ||
pen.UnderlineStyle(DoubleUnderline) | ||
case 3: // Curly Underline | ||
pen.UnderlineStyle(CurlyUnderline) | ||
case 4: // Dotted Underline | ||
pen.UnderlineStyle(DottedUnderline) | ||
case 5: // Dashed Underline | ||
pen.UnderlineStyle(DashedUnderline) | ||
} | ||
} | ||
} else { | ||
// Single Underline | ||
pen.Underline(true) | ||
} | ||
case 5: // Slow Blink | ||
pen.SlowBlink(true) | ||
case 6: // Rapid Blink | ||
pen.RapidBlink(true) | ||
case 7: // Reverse | ||
pen.Reverse(true) | ||
case 8: // Conceal | ||
pen.Conceal(true) | ||
case 9: // Crossed-out/Strikethrough | ||
pen.Strikethrough(true) | ||
case 22: // Normal Intensity (not bold or faint) | ||
pen.Bold(false).Faint(false) | ||
case 23: // Not italic, not Fraktur | ||
pen.Italic(false) | ||
case 24: // Not underlined | ||
pen.Underline(false) | ||
case 25: // Blink off | ||
pen.SlowBlink(false).RapidBlink(false) | ||
case 27: // Positive (not reverse) | ||
pen.Reverse(false) | ||
case 28: // Reveal | ||
pen.Conceal(false) | ||
case 29: // Not crossed out | ||
pen.Strikethrough(false) | ||
case 30, 31, 32, 33, 34, 35, 36, 37: // Set foreground | ||
pen.Foreground(ansi.Black + ansi.BasicColor(param-30)) //nolint:gosec | ||
case 38: // Set foreground 256 or truecolor | ||
n, c := ansi.DecodeColor(params[i:]) | ||
if n > 0 { | ||
pen.Foreground(c) | ||
i += n - 1 | ||
} | ||
case 39: // Default foreground | ||
pen.Foreground(nil) | ||
case 40, 41, 42, 43, 44, 45, 46, 47: // Set background | ||
pen.Background(ansi.Black + ansi.BasicColor(param-40)) //nolint:gosec | ||
case 48: // Set background 256 or truecolor | ||
n, c := ansi.DecodeColor(params[i:]) | ||
if n > 0 { | ||
pen.Background(c) | ||
i += n - 1 | ||
} | ||
case 49: // Default Background | ||
pen.Background(nil) | ||
case 58: // Set underline color | ||
n, c := ansi.DecodeColor(params[i:]) | ||
if n > 0 { | ||
pen.UnderlineColor(c) | ||
i += n - 1 | ||
} | ||
case 59: // Default underline color | ||
pen.UnderlineColor(nil) | ||
case 90, 91, 92, 93, 94, 95, 96, 97: // Set bright foreground | ||
pen.Foreground(ansi.BrightBlack + ansi.BasicColor(param-90)) //nolint:gosec | ||
case 100, 101, 102, 103, 104, 105, 106, 107: // Set bright background | ||
pen.Background(ansi.BrightBlack + ansi.BasicColor(param-100)) //nolint:gosec | ||
} | ||
} | ||
} | ||
|
||
// DecodeLine decodes a hyperlink escape sequence from a data buffer. | ||
func DecodeLink(p []byte, link *Link) { | ||
params := bytes.Split(p, []byte{';'}) | ||
if len(params) != 3 { | ||
return | ||
} | ||
for _, param := range bytes.Split(params[1], []byte{':'}) { | ||
if bytes.HasPrefix(param, []byte("id=")) { | ||
link.URLID = string(param) | ||
} | ||
} | ||
link.URL = string(params[2]) | ||
} |