Skip to content

Commit

Permalink
feat(style): add underline style and color support
Browse files Browse the repository at this point in the history
Add support to CSI 4:x and CSI 58 escape sequences

Ref: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR
Ref: https://sw.kovidgoyal.net/kitty/underlines/
  • Loading branch information
aymanbagabas committed Mar 3, 2023
1 parent 97711a2 commit d960f27
Show file tree
Hide file tree
Showing 8 changed files with 151 additions and 34 deletions.
2 changes: 2 additions & 0 deletions color.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ const (
ForegroudSeq = "38"
// Background sequence code.
BackgroundSeq = "48"
// Underline color sequence code.
UnderColorSeq = "58"
)

// Foreground and Background sequence codes
Expand Down
79 changes: 69 additions & 10 deletions style.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,20 @@ import (

// Sequence definitions.
const (
ResetSeq = "0"
BoldSeq = "1"
FaintSeq = "2"
ItalicSeq = "3"
UnderlineSeq = "4"
BlinkSeq = "5"
ReverseSeq = "7"
CrossOutSeq = "9"
OverlineSeq = "53"
ResetSeq = "0"
BoldSeq = "1"
FaintSeq = "2"
ItalicSeq = "3"
UnderlineSeq = "4" // also 4:1
UnderdoubleSeq = "4:2"
UndercurlSeq = "4:3"
UnderdotSeq = "4:4"
UnderdashSeq = "4:5"
BlinkSeq = "5"
ReverseSeq = "7"
CrossOutSeq = "9"
OverlineSeq = "53"
UndercolorSeq = "58"
)

// Style is a string that various rendering styles can be applied to.
Expand Down Expand Up @@ -106,9 +111,63 @@ func (t Style) Italic() Style {
return t
}

func undercolorSeq(c Color) []string {
var seqs []string
switch v := c.(type) {
case NoColor:
return seqs
case ANSIColor:
// ANSIColor(s) are their own sequences.
// Underline colors don't support ANSI color sequences.
// Convert them into ANSI256
c = ANSI256Color(v.Color)
}
seqs = append(seqs, UndercolorSeq, c.Sequence())
return seqs
}

// Underline enables underline rendering.
func (t Style) Underline() Style {
func (t Style) Underline(c ...Color) Style {
t.styles = append(t.styles, UnderlineSeq)
if len(c) > 0 {
t.styles = append(t.styles, undercolorSeq(c[0])...)
}
return t
}

// Underdouble enables double underline rendering.
func (t Style) Underdouble(c ...Color) Style {
t.styles = append(t.styles, UnderdoubleSeq)
if len(c) > 0 {
t.styles = append(t.styles, undercolorSeq(c[0])...)
}
return t
}

// Undercurl enables curly underline rendering.
func (t Style) Undercurl(c ...Color) Style {
t.styles = append(t.styles, UndercurlSeq)
if len(c) > 0 {
t.styles = append(t.styles, undercolorSeq(c[0])...)
}
return t
}

// Underdot enables dotted underline rendering.
func (t Style) Underdot(c ...Color) Style {
t.styles = append(t.styles, UnderdotSeq)
if len(c) > 0 {
t.styles = append(t.styles, undercolorSeq(c[0])...)
}
return t
}

// Underdash enables dashed underline rendering.
func (t Style) Underdash(c ...Color) Style {
t.styles = append(t.styles, UnderdashSeq)
if len(c) > 0 {
t.styles = append(t.styles, undercolorSeq(c[0])...)
}
return t
}

Expand Down
64 changes: 45 additions & 19 deletions templatehelper.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,29 @@ func TemplateFuncs(p Profile) template.FuncMap {

return s.String()
},
"Bold": styleFunc(p, Style.Bold),
"Faint": styleFunc(p, Style.Faint),
"Italic": styleFunc(p, Style.Italic),
"Underline": styleFunc(p, Style.Underline),
"Overline": styleFunc(p, Style.Overline),
"Blink": styleFunc(p, Style.Blink),
"Reverse": styleFunc(p, Style.Reverse),
"CrossOut": styleFunc(p, Style.CrossOut),
"Bold": styleFunc(p, Style.Bold),
"Faint": styleFunc(p, Style.Faint),
"Italic": styleFunc(p, Style.Italic),
"Overline": styleFunc(p, Style.Overline),
"Blink": styleFunc(p, Style.Blink),
"Reverse": styleFunc(p, Style.Reverse),
"CrossOut": styleFunc(p, Style.CrossOut),
"Underline": styleUnderline(p, Style.Underline),
"Underdouble": styleUnderline(p, Style.Underdouble),
"Undercurl": styleUnderline(p, Style.Undercurl),
"Underdot": styleUnderline(p, Style.Underdot),
"Underdash": styleUnderline(p, Style.Underdash),
}
}

func styleUnderline(p Profile, f func(Style, ...Color) Style) func(...interface{}) string {
return func(values ...interface{}) string {
if len(values) == 2 {
s := p.String(values[1].(string))
return f(s, p.Color(values[0].(string))).String()
}
s := p.String(values[0].(string))
return f(s).String()
}
}

Expand All @@ -64,17 +79,21 @@ func styleFunc(p Profile, f func(Style) Style) func(...interface{}) string {
}

var noopTemplateFuncs = template.FuncMap{
"Color": noColorFunc,
"Foreground": noColorFunc,
"Background": noColorFunc,
"Bold": noStyleFunc,
"Faint": noStyleFunc,
"Italic": noStyleFunc,
"Underline": noStyleFunc,
"Overline": noStyleFunc,
"Blink": noStyleFunc,
"Reverse": noStyleFunc,
"CrossOut": noStyleFunc,
"Color": noColorFunc,
"Foreground": noColorFunc,
"Background": noColorFunc,
"Bold": noStyleFunc,
"Faint": noStyleFunc,
"Italic": noStyleFunc,
"Overline": noStyleFunc,
"Blink": noStyleFunc,
"Reverse": noStyleFunc,
"CrossOut": noStyleFunc,
"Underline": noUnderline,
"Underdouble": noUnderline,
"Undercurl": noUnderline,
"Underdot": noUnderline,
"Underdash": noUnderline,
}

func noColorFunc(values ...interface{}) string {
Expand All @@ -84,3 +103,10 @@ func noColorFunc(values ...interface{}) string {
func noStyleFunc(values ...interface{}) string {
return values[0].(string)
}

func noUnderline(values ...interface{}) string {
if len(values) == 2 {
return values[1].(string)
}
return values[0].(string)
}
8 changes: 7 additions & 1 deletion testdata/templatehelper.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@ Plain
{{ Faint "Faint" }}
{{ Italic "Italic" }}
{{ Underline "Underline" }}
{{ Underline "#ff0000" "Red Underline" }}
{{ Underdouble "Double Underline" }}
{{ Undercurl "Undercurl" }}
{{ Undercurl "#00ff00" "Green Undercurl" }}
{{ Underdot "Dotted Underline" }}
{{ Underdash "Dashed Underline" }}
{{ Overline "Overline" }}
{{ Blink "Blink" }}
{{ Reverse "Reverse" }}
{{ CrossOut "CrossOut" }}
{{ CrossOut "CrossOut" }}
8 changes: 7 additions & 1 deletion testdata/templatehelper_ansi.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@ Plain
Faint
Italic
Underline
Red Underline
[4:2mDouble Underline
[4:3mUndercurl
[4:3;58;5;10mGreen Undercurl
[4:4mDotted Underline
[4:5mDashed Underline
Overline
Blink
Reverse
CrossOut
CrossOut
8 changes: 7 additions & 1 deletion testdata/templatehelper_ansi256.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@ Plain
Faint
Italic
Underline
Red Underline
[4:2mDouble Underline
[4:3mUndercurl
[4:3;58;5;46mGreen Undercurl
[4:4mDotted Underline
[4:5mDashed Underline
Overline
Blink
Reverse
CrossOut
CrossOut
8 changes: 7 additions & 1 deletion testdata/templatehelper_ascii.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@ Bold
Faint
Italic
Underline
Red Underline
Double Underline
Undercurl
Green Undercurl
Dotted Underline
Dashed Underline
Overline
Blink
Reverse
CrossOut
CrossOut
8 changes: 7 additions & 1 deletion testdata/templatehelper_truecolor.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@ Plain
Faint
Italic
Underline
Red Underline
[4:2mDouble Underline
[4:3mUndercurl
[4:3;58;2;0;255;0mGreen Undercurl
[4:4mDotted Underline
[4:5mDashed Underline
Overline
Blink
Reverse
CrossOut
CrossOut

0 comments on commit d960f27

Please sign in to comment.