Switch remote deploy to vendored source builds
Move remote deployment to a vendored source bundle built on the target host via Docker so redeploys no longer require local cross-compilation or host Go installation. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
21
vendor/github.com/leaanthony/go-ansi-parser/LICENSE
generated
vendored
Normal file
21
vendor/github.com/leaanthony/go-ansi-parser/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-Present Lea Anthony
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
86
vendor/github.com/leaanthony/go-ansi-parser/README.md
generated
vendored
Normal file
86
vendor/github.com/leaanthony/go-ansi-parser/README.md
generated
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
|
||||
<p align="center" style="text-align: center">
|
||||
<img src="logo.png"><br/>
|
||||
</p>
|
||||
<p align="center">
|
||||
A library for parsing ANSI encoded strings<br/><br/>
|
||||
<a href="https://github.com/leaanthony/go-ansi-parser/blob/master/LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg"></a>
|
||||
<a href="https://goreportcard.com/report/github.com/leaanthony/go-ansi-parser"><img src="https://goreportcard.com/badge/github.com/leaanthony/go-ansi-parser"/></a>
|
||||
<a href="http://godoc.org/github.com/leaanthony/go-ansi-parser"><img src="https://img.shields.io/badge/godoc-reference-blue.svg"/></a>
|
||||
<a href="https://github.com/leaanthony/go-ansi-parser/issues"><img src="https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat" alt="CodeFactor" /></a>
|
||||
<a href="https://app.fossa.io/projects/git%2Bgithub.com%2Fleaanthony%2Fgo-ansi-parser?ref=badge_shield" alt="FOSSA Status"><img src="https://app.fossa.io/api/projects/git%2Bgithub.com%2Fleaanthony%2Fgo-ansi-parser.svg?type=shield"/></a>
|
||||
</p>
|
||||
|
||||
Go ANSI Parser converts strings with [ANSI escape codes](https://en.wikipedia.org/wiki/ANSI_escape_code)
|
||||
into a slice of structs that represent styled text. Features:
|
||||
|
||||
* Can parse ANSI 16, 256 and TrueColor
|
||||
* Supports all styles: Regular, Bold, Faint, Italic, Blinking, Inversed, Invisible, Underlined, Strikethrough
|
||||
* Provides RGB, Hex, HSL, ANSI ID and Name for parsed colours
|
||||
* Truncation - works with emojis and grapheme clusters
|
||||
* Length - works with emojis and grapheme clusters
|
||||
* Cleanse - removes the ansi escape codes
|
||||
* Configurable colour map for customisation
|
||||
* 100% Test Coverage
|
||||
|
||||
# Installation
|
||||
```shell
|
||||
go get github.com/leaanthony/go-ansi-parser
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Parse
|
||||
```go
|
||||
text, err := ansi.Parse("\u001b[1;31;40mHello World\033[0m")
|
||||
|
||||
// is the equivalent of...
|
||||
|
||||
text := []*ansi.StyledText{
|
||||
{
|
||||
Label: "Hello World",
|
||||
FgCol: &ansi.Col{
|
||||
Id: 9,
|
||||
Hex: "#ff0000",
|
||||
Rgb: &ansi.Rgb{ R: 255, G: 0, B: 0 },
|
||||
Hsl: &ansi.Hsl{ H: 0, S: 100, L: 50 },
|
||||
Name: "Red",
|
||||
},
|
||||
BgCol: &ansi.Col{
|
||||
Id: 0,
|
||||
Hex: "#000000",
|
||||
Rgb: &ansi.Rgb{0, 0, 0},
|
||||
Hsl: &ansi.Hsl{0, 0, 0},
|
||||
Name: "Black",
|
||||
},
|
||||
Style: 1,
|
||||
},
|
||||
}
|
||||
```
|
||||
### Truncating
|
||||
```go
|
||||
shorter, err := ansi.Truncate("\u001b[1;31;40mHello\033[0m \u001b[0;30mWorld!\033[0m", 8)
|
||||
|
||||
// is the equivalent of...
|
||||
|
||||
shorter := "\u001b[1;31;40mHello\033[0m \u001b[0;30mWo\033[0m"
|
||||
```
|
||||
### Cleanse
|
||||
```go
|
||||
cleaner, err := ansi.Cleanse("\u001b[1;31;40mHello\033[0m \u001b[0;30mWorld!\033[0m")
|
||||
|
||||
// is the equivalent of...
|
||||
|
||||
cleaner := "Hello World!"
|
||||
```
|
||||
### Length
|
||||
```go
|
||||
length, err := ansi.Length("\u001b[1;31;40mHello\033[0m \u001b[0;30mWorld!\033[0m")
|
||||
|
||||
// is the equivalent of...
|
||||
|
||||
length := 12
|
||||
|
||||
// Works with grapheme clusters and emoji
|
||||
length, err := ansi.Length("\u001b[1;31;40m👩🏽🔧😎\033[0m") // 2
|
||||
```
|
||||
557
vendor/github.com/leaanthony/go-ansi-parser/ansi.go
generated
vendored
Normal file
557
vendor/github.com/leaanthony/go-ansi-parser/ansi.go
generated
vendored
Normal file
@@ -0,0 +1,557 @@
|
||||
package ansi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/rivo/uniseg"
|
||||
)
|
||||
|
||||
// TextStyle is a type representing the
|
||||
// ansi text styles
|
||||
type TextStyle int
|
||||
|
||||
const (
|
||||
// Bold Style
|
||||
Bold TextStyle = 1 << 0
|
||||
// Faint Style
|
||||
Faint TextStyle = 1 << 1
|
||||
// Italic Style
|
||||
Italic TextStyle = 1 << 2
|
||||
// Blinking Style
|
||||
Blinking TextStyle = 1 << 3
|
||||
// Inversed Style
|
||||
Inversed TextStyle = 1 << 4
|
||||
// Invisible Style
|
||||
Invisible TextStyle = 1 << 5
|
||||
// Underlined Style
|
||||
Underlined TextStyle = 1 << 6
|
||||
// Strikethrough Style
|
||||
Strikethrough TextStyle = 1 << 7
|
||||
// Bright Style
|
||||
Bright TextStyle = 1 << 8
|
||||
)
|
||||
|
||||
type ColourMode int
|
||||
|
||||
const (
|
||||
Default ColourMode = 0
|
||||
TwoFiveSix ColourMode = 1
|
||||
TrueColour ColourMode = 2
|
||||
)
|
||||
|
||||
var invalid = fmt.Errorf("invalid ansi string")
|
||||
var missingTerminator = fmt.Errorf("missing escape terminator 'm'")
|
||||
var invalidTrueColorSequence = fmt.Errorf("invalid TrueColor sequence")
|
||||
var invalid256ColSequence = fmt.Errorf("invalid 256 colour sequence")
|
||||
|
||||
const (
|
||||
// Default colors uses foreground color codes [30-37].
|
||||
// See ColourMap and case for background colors.
|
||||
defaultForegroundColor = "37"
|
||||
defaultBackgroundColor = "30"
|
||||
)
|
||||
|
||||
// StyledText represents a single formatted string
|
||||
type StyledText struct {
|
||||
Label string
|
||||
FgCol *Col
|
||||
BgCol *Col
|
||||
Style TextStyle
|
||||
ColourMode ColourMode
|
||||
// Offset is the offset into the input string where the StyledText begins
|
||||
Offset int
|
||||
// Len is the length in bytes of the substring of the input text that
|
||||
// contains the styled text
|
||||
Len int
|
||||
}
|
||||
|
||||
func (s *StyledText) styleToParams() []string {
|
||||
var params []string
|
||||
if s.Bold() {
|
||||
params = append(params, "1")
|
||||
}
|
||||
if s.Faint() {
|
||||
params = append(params, "2")
|
||||
}
|
||||
if s.Italic() {
|
||||
params = append(params, "3")
|
||||
}
|
||||
if s.Underlined() {
|
||||
params = append(params, "4")
|
||||
}
|
||||
if s.Blinking() {
|
||||
params = append(params, "5")
|
||||
}
|
||||
if s.Inversed() {
|
||||
params = append(params, "7")
|
||||
}
|
||||
if s.Invisible() {
|
||||
params = append(params, "8")
|
||||
}
|
||||
if s.Strikethrough() {
|
||||
params = append(params, "9")
|
||||
}
|
||||
if s.FgCol != nil {
|
||||
// Do we have an ID?
|
||||
switch s.ColourMode {
|
||||
case Default:
|
||||
offset := 30
|
||||
id := s.FgCol.Id
|
||||
// Adjust when bold has been applied to the id
|
||||
if (s.Bold() || s.Bright()) && id > 7 && id < 16 {
|
||||
id -= 8
|
||||
}
|
||||
if s.Bright() {
|
||||
offset = 90
|
||||
}
|
||||
params = append(params, fmt.Sprintf("%d", id+offset))
|
||||
case TwoFiveSix:
|
||||
params = append(params, []string{"38", "5", fmt.Sprintf("%d", s.FgCol.Id)}...)
|
||||
case TrueColour:
|
||||
r := fmt.Sprintf("%d", s.FgCol.Rgb.R)
|
||||
g := fmt.Sprintf("%d", s.FgCol.Rgb.G)
|
||||
b := fmt.Sprintf("%d", s.FgCol.Rgb.B)
|
||||
params = append(params, []string{"38", "2", r, g, b}...)
|
||||
}
|
||||
}
|
||||
if s.BgCol != nil {
|
||||
// Do we have an ID?
|
||||
switch s.ColourMode {
|
||||
case Default:
|
||||
id := s.BgCol.Id
|
||||
offset := 40
|
||||
if s.Bright() {
|
||||
offset = 100
|
||||
}
|
||||
// Adjust when bold has been applied to the id
|
||||
if (s.Bold() || s.Bright()) && id > 7 && id < 16 {
|
||||
id -= 8
|
||||
}
|
||||
params = append(params, fmt.Sprintf("%d", id+offset))
|
||||
case TwoFiveSix:
|
||||
params = append(params, []string{"48", "5", fmt.Sprintf("%d", s.BgCol.Id)}...)
|
||||
case TrueColour:
|
||||
r := fmt.Sprintf("%d", s.BgCol.Rgb.R)
|
||||
g := fmt.Sprintf("%d", s.BgCol.Rgb.G)
|
||||
b := fmt.Sprintf("%d", s.BgCol.Rgb.B)
|
||||
params = append(params, []string{"48", "2", r, g, b}...)
|
||||
}
|
||||
}
|
||||
return params
|
||||
}
|
||||
|
||||
func (s *StyledText) String() string {
|
||||
params := strings.Join(s.styleToParams(), ";")
|
||||
return "\033[0;" + params + "m" + s.Label + "\033[0m"
|
||||
}
|
||||
|
||||
// Bold will return true if the text has a Bold style
|
||||
func (s *StyledText) Bold() bool {
|
||||
return s.Style&Bold == Bold
|
||||
}
|
||||
|
||||
// Faint will return true if the text has a Faint style
|
||||
func (s *StyledText) Faint() bool {
|
||||
return s.Style&Faint == Faint
|
||||
}
|
||||
|
||||
// Italic will return true if the text has an Italic style
|
||||
func (s *StyledText) Italic() bool {
|
||||
return s.Style&Italic == Italic
|
||||
}
|
||||
|
||||
// Blinking will return true if the text has a Blinking style
|
||||
func (s *StyledText) Blinking() bool {
|
||||
return s.Style&Blinking == Blinking
|
||||
}
|
||||
|
||||
// Inversed will return true if the text has an Inversed style
|
||||
func (s *StyledText) Inversed() bool {
|
||||
return s.Style&Inversed == Inversed
|
||||
}
|
||||
|
||||
// Invisible will return true if the text has an Invisible style
|
||||
func (s *StyledText) Invisible() bool {
|
||||
return s.Style&Invisible == Invisible
|
||||
}
|
||||
|
||||
// Underlined will return true if the text has an Underlined style
|
||||
func (s *StyledText) Underlined() bool {
|
||||
return s.Style&Underlined == Underlined
|
||||
}
|
||||
|
||||
// Strikethrough will return true if the text has a Strikethrough style
|
||||
func (s *StyledText) Strikethrough() bool {
|
||||
return s.Style&Strikethrough == Strikethrough
|
||||
}
|
||||
|
||||
// Bright will return true if the text has a Bright style
|
||||
func (s *StyledText) Bright() bool {
|
||||
return s.Style&Bright == Bright
|
||||
}
|
||||
|
||||
// ColourMap maps ansi identifiers to a colour
|
||||
var ColourMap = map[string]map[string]*Col{
|
||||
"Regular": {
|
||||
"30": Cols[0],
|
||||
"31": Cols[1],
|
||||
"32": Cols[2],
|
||||
"33": Cols[3],
|
||||
"34": Cols[4],
|
||||
"35": Cols[5],
|
||||
"36": Cols[6],
|
||||
"37": Cols[7],
|
||||
"90": Cols[8],
|
||||
"91": Cols[9],
|
||||
"92": Cols[10],
|
||||
"93": Cols[11],
|
||||
"94": Cols[12],
|
||||
"95": Cols[13],
|
||||
"96": Cols[14],
|
||||
"97": Cols[15],
|
||||
"100": Cols[8],
|
||||
"101": Cols[9],
|
||||
"102": Cols[10],
|
||||
"103": Cols[11],
|
||||
"104": Cols[12],
|
||||
"105": Cols[13],
|
||||
"106": Cols[14],
|
||||
"107": Cols[15],
|
||||
},
|
||||
"Bold": {
|
||||
"30": Cols[8],
|
||||
"31": Cols[9],
|
||||
"32": Cols[10],
|
||||
"33": Cols[11],
|
||||
"34": Cols[12],
|
||||
"35": Cols[13],
|
||||
"36": Cols[14],
|
||||
"37": Cols[15],
|
||||
"90": Cols[8],
|
||||
"91": Cols[9],
|
||||
"92": Cols[10],
|
||||
"93": Cols[11],
|
||||
"94": Cols[12],
|
||||
"95": Cols[13],
|
||||
"96": Cols[14],
|
||||
"97": Cols[15],
|
||||
"100": Cols[8],
|
||||
"101": Cols[9],
|
||||
"102": Cols[10],
|
||||
"103": Cols[11],
|
||||
"104": Cols[12],
|
||||
"105": Cols[13],
|
||||
"106": Cols[14],
|
||||
"107": Cols[15],
|
||||
},
|
||||
"Faint": {
|
||||
"30": Cols[0],
|
||||
"31": Cols[1],
|
||||
"32": Cols[2],
|
||||
"33": Cols[3],
|
||||
"34": Cols[4],
|
||||
"35": Cols[5],
|
||||
"36": Cols[6],
|
||||
"37": Cols[7],
|
||||
},
|
||||
}
|
||||
|
||||
// Parse will convert an ansi encoded string and return
|
||||
// a slice of StyledText structs that represent the text.
|
||||
// If parsing is unsuccessful, an error is returned.
|
||||
func Parse(input string, options ...ParseOption) ([]*StyledText, error) {
|
||||
var result []*StyledText
|
||||
index := 0
|
||||
offset := 0
|
||||
escapeCodeLen := 0
|
||||
var currentStyledText = &StyledText{}
|
||||
|
||||
if len(input) == 0 {
|
||||
return []*StyledText{currentStyledText}, nil
|
||||
}
|
||||
|
||||
for {
|
||||
// Read all chars to next escape code
|
||||
esc := strings.Index(input, "\033[")
|
||||
|
||||
// If no more esc chars, save what's left and return
|
||||
if esc == -1 {
|
||||
text := input[index:]
|
||||
if len(text) > 0 {
|
||||
currentStyledText.Label = text
|
||||
currentStyledText.Offset = offset
|
||||
currentStyledText.Len = len(text) + escapeCodeLen
|
||||
result = append(result, currentStyledText)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
label := input[:esc]
|
||||
if len(label) > 0 {
|
||||
currentStyledText.Label = label
|
||||
currentStyledText.Offset = offset
|
||||
currentStyledText.Len = len(label) + escapeCodeLen
|
||||
offset += currentStyledText.Len
|
||||
result = append(result, currentStyledText)
|
||||
currentStyledText = &StyledText{
|
||||
Label: "",
|
||||
FgCol: currentStyledText.FgCol,
|
||||
BgCol: currentStyledText.BgCol,
|
||||
Style: currentStyledText.Style,
|
||||
}
|
||||
escapeCodeLen = 0
|
||||
}
|
||||
input = input[esc:]
|
||||
// skip
|
||||
input = input[2:]
|
||||
|
||||
// Read in params
|
||||
endesc := strings.Index(input, "m")
|
||||
if endesc == -1 {
|
||||
return nil, missingTerminator
|
||||
}
|
||||
paramText := input[:endesc]
|
||||
input = input[endesc+1:]
|
||||
escapeCodeLen += 2 + endesc + 1
|
||||
params := strings.Split(paramText, ";")
|
||||
colourMap := ColourMap["Regular"]
|
||||
skip := 0
|
||||
for index, param := range params {
|
||||
if skip > 0 {
|
||||
skip--
|
||||
continue
|
||||
}
|
||||
param = stripLeadingZeros(param)
|
||||
switch param {
|
||||
case "0", "":
|
||||
colourMap = ColourMap["Regular"]
|
||||
currentStyledText.Style = 0
|
||||
currentStyledText.FgCol = nil
|
||||
currentStyledText.BgCol = nil
|
||||
case "1":
|
||||
// Bold
|
||||
colourMap = ColourMap["Bold"]
|
||||
currentStyledText.Style |= Bold
|
||||
case "2":
|
||||
// Dim/Feint
|
||||
colourMap = ColourMap["Faint"]
|
||||
currentStyledText.Style |= Faint
|
||||
case "3":
|
||||
// Italic
|
||||
currentStyledText.Style |= Italic
|
||||
case "4":
|
||||
// Underlined
|
||||
currentStyledText.Style |= Underlined
|
||||
case "5":
|
||||
// Blinking
|
||||
currentStyledText.Style |= Blinking
|
||||
case "7":
|
||||
// Inversed
|
||||
currentStyledText.Style |= Inversed
|
||||
case "8":
|
||||
// Invisible
|
||||
currentStyledText.Style |= Invisible
|
||||
case "9":
|
||||
// Strikethrough
|
||||
currentStyledText.Style |= Strikethrough
|
||||
case "30", "31", "32", "33", "34", "35", "36", "37":
|
||||
currentStyledText.FgCol = colourMap[param]
|
||||
case "90", "91", "92", "93", "94", "95", "96", "97":
|
||||
currentStyledText.FgCol = colourMap[param]
|
||||
currentStyledText.Style |= Bright
|
||||
case "100", "101", "102", "103", "104", "105", "106", "107":
|
||||
currentStyledText.BgCol = colourMap[param]
|
||||
currentStyledText.Style |= Bright
|
||||
case "40", "41", "42", "43", "44", "45", "46", "47":
|
||||
bgcol := "3" + param[1:] // Equivalent of -10
|
||||
currentStyledText.BgCol = colourMap[bgcol]
|
||||
case "38", "48":
|
||||
if len(params)-index < 3 {
|
||||
return nil, invalid
|
||||
}
|
||||
// 256 colours
|
||||
param1 := stripLeadingZeros(params[index+1])
|
||||
if param1 == "5" {
|
||||
skip = 2
|
||||
colIndexText := stripLeadingZeros(params[index+2])
|
||||
colIndex, err := strconv.Atoi(colIndexText)
|
||||
if err != nil {
|
||||
return nil, invalid256ColSequence
|
||||
}
|
||||
if colIndex < 0 || colIndex > 255 {
|
||||
return nil, invalid256ColSequence
|
||||
}
|
||||
currentStyledText.ColourMode = TwoFiveSix
|
||||
if param == "38" {
|
||||
currentStyledText.FgCol = Cols[colIndex]
|
||||
continue
|
||||
}
|
||||
currentStyledText.BgCol = Cols[colIndex]
|
||||
continue
|
||||
}
|
||||
// we must have 4 params left
|
||||
if len(params)-index < 5 {
|
||||
return nil, invalidTrueColorSequence
|
||||
}
|
||||
if param1 != "2" {
|
||||
return nil, invalidTrueColorSequence
|
||||
}
|
||||
var r, g, b uint8
|
||||
ri, err := strconv.Atoi(params[index+2])
|
||||
if err != nil {
|
||||
return nil, invalidTrueColorSequence
|
||||
}
|
||||
gi, err := strconv.Atoi(params[index+3])
|
||||
if err != nil {
|
||||
return nil, invalidTrueColorSequence
|
||||
}
|
||||
bi, err := strconv.Atoi(params[index+4])
|
||||
if err != nil {
|
||||
return nil, invalidTrueColorSequence
|
||||
}
|
||||
if bi > 255 || gi > 255 || ri > 255 {
|
||||
return nil, invalidTrueColorSequence
|
||||
}
|
||||
if bi < 0 || gi < 0 || ri < 0 {
|
||||
return nil, invalidTrueColorSequence
|
||||
}
|
||||
r = uint8(ri)
|
||||
g = uint8(gi)
|
||||
b = uint8(bi)
|
||||
skip = 4
|
||||
colvalue := fmt.Sprintf("#%02x%02x%02x", r, g, b)
|
||||
currentStyledText.ColourMode = TrueColour
|
||||
if param == "38" {
|
||||
currentStyledText.FgCol = &Col{Id: 256, Hex: colvalue, Rgb: Rgb{r, g, b}}
|
||||
continue
|
||||
}
|
||||
currentStyledText.BgCol = &Col{Id: 256, Hex: colvalue, Rgb: Rgb{r, g, b}}
|
||||
case "39":
|
||||
// Lookup for default foreground color.
|
||||
foregroundColor := colourMap[defaultForegroundColor]
|
||||
for _, option := range options {
|
||||
if option.ansiForegroundColor != "" {
|
||||
foregroundColor = colourMap[option.ansiForegroundColor]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Set selected foreground color.
|
||||
currentStyledText.FgCol = foregroundColor
|
||||
case "49":
|
||||
// Lookup for default background color.
|
||||
backgroundColor := colourMap[defaultBackgroundColor]
|
||||
for _, option := range options {
|
||||
if option.ansiBackgroundColor != "" {
|
||||
backgroundColor = colourMap[option.ansiBackgroundColor]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Set selected background color.
|
||||
currentStyledText.BgCol = backgroundColor
|
||||
default:
|
||||
// Unexpected codes may be ignored.
|
||||
unexpectedCodeIgnored := false
|
||||
for _, option := range options {
|
||||
if option.ignoreUnexpectedCode {
|
||||
unexpectedCodeIgnored = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !unexpectedCodeIgnored {
|
||||
return nil, invalid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func stripLeadingZeros(s string) string {
|
||||
if len(s) < 2 {
|
||||
return s
|
||||
}
|
||||
return strings.TrimLeft(s, "0")
|
||||
}
|
||||
|
||||
// HasEscapeCodes tests that input has escape codes.
|
||||
func HasEscapeCodes(input string) bool {
|
||||
return strings.IndexAny(input, "\033[") != -1
|
||||
}
|
||||
|
||||
// String builds an ANSI string for specified StyledText slice.
|
||||
func String(input []*StyledText) string {
|
||||
var result strings.Builder
|
||||
for _, text := range input {
|
||||
params := text.styleToParams()
|
||||
if len(params) == 0 {
|
||||
result.WriteString(text.Label)
|
||||
continue
|
||||
}
|
||||
result.WriteString(text.String())
|
||||
}
|
||||
return result.String()
|
||||
}
|
||||
|
||||
// Truncate truncates text to length but preserves control symbols in ANSI string.
|
||||
func Truncate(input string, maxChars int, options ...ParseOption) (string, error) {
|
||||
parsed, err := Parse(input, options...)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
charsLeft := maxChars
|
||||
var result []*StyledText
|
||||
for _, element := range parsed {
|
||||
userPerceivedChars := uniseg.GraphemeClusterCount(element.Label)
|
||||
if userPerceivedChars >= charsLeft {
|
||||
var newLabel []rune
|
||||
graphemes := uniseg.NewGraphemes(element.Label)
|
||||
for graphemes.Next() {
|
||||
newLabel = append(newLabel, graphemes.Runes()...)
|
||||
charsLeft--
|
||||
if charsLeft == 0 {
|
||||
element.Label = string(newLabel)
|
||||
result = append(result, element)
|
||||
return String(result), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
result = append(result, element)
|
||||
charsLeft -= userPerceivedChars
|
||||
}
|
||||
return String(result), nil
|
||||
}
|
||||
|
||||
// Cleanse removes ANSI control symbols from the string.
|
||||
func Cleanse(input string, options ...ParseOption) (string, error) {
|
||||
if input == "" {
|
||||
return "", nil
|
||||
}
|
||||
parsed, err := Parse(input, options...)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
var result strings.Builder
|
||||
for _, element := range parsed {
|
||||
result.WriteString(element.Label)
|
||||
}
|
||||
return result.String(), nil
|
||||
}
|
||||
|
||||
// Length calculates count of user-perceived characters in ANSI string.
|
||||
func Length(input string, options ...ParseOption) (int, error) {
|
||||
if input == "" {
|
||||
return 0, nil
|
||||
}
|
||||
parsed, err := Parse(input, options...)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
var result int
|
||||
for _, element := range parsed {
|
||||
userPerceivedChars := uniseg.GraphemeClusterCount(element.Label)
|
||||
result += userPerceivedChars
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
1823
vendor/github.com/leaanthony/go-ansi-parser/cols.go
generated
vendored
Normal file
1823
vendor/github.com/leaanthony/go-ansi-parser/cols.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
BIN
vendor/github.com/leaanthony/go-ansi-parser/logo.png
generated
vendored
Normal file
BIN
vendor/github.com/leaanthony/go-ansi-parser/logo.png
generated
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
25
vendor/github.com/leaanthony/go-ansi-parser/options.go
generated
vendored
Normal file
25
vendor/github.com/leaanthony/go-ansi-parser/options.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
package ansi
|
||||
|
||||
// ParseOption specifies parse option.
|
||||
type ParseOption struct {
|
||||
ignoreUnexpectedCode bool
|
||||
ansiForegroundColor string
|
||||
ansiBackgroundColor string
|
||||
}
|
||||
|
||||
// WithIgnoreInvalidCodes disables returning an error on invalid ANSI code.
|
||||
func WithIgnoreInvalidCodes() ParseOption {
|
||||
return ParseOption{ignoreUnexpectedCode: true}
|
||||
}
|
||||
|
||||
// WithDefaultForegroundColor specifies default foreground code (ANSI 39).
|
||||
// See ColourMap variable and foreground color codes 30-37.
|
||||
func WithDefaultForegroundColor(ansiColor string) ParseOption {
|
||||
return ParseOption{ansiForegroundColor: ansiColor}
|
||||
}
|
||||
|
||||
// WithDefaultBackgroundColor specifies default foreground code (ANSI 49).
|
||||
// See ColourMap variable and foreground color codes 30-37.
|
||||
func WithDefaultBackgroundColor(ansiColor string) ParseOption {
|
||||
return ParseOption{ansiBackgroundColor: ansiColor}
|
||||
}
|
||||
Reference in New Issue
Block a user