Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Underline Styles & Colors #114

Open
wants to merge 2 commits into
base: ref-color
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 30 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,13 @@ s.CrossOut()
s.Underline()
s.Overline()

// Underline styles
s.Underline(output.Color("#ff0000"))
s.Undercurl(output.Color("11"))
s.Underdouble()
s.Underdot(output.Color("216"))
s.Underdash()

// Reverse swaps current fore- & background colors
s.Reverse()

Expand Down Expand Up @@ -316,28 +323,32 @@ termenv.DisableBracketedPaste()
<details>
<summary>Click to show feature matrix</summary>

| Terminal | Query Color Scheme | Query Cursor Position | Set Window Title | Change Cursor Color | Change Default Foreground Setting | Change Default Background Setting | Bracketed Paste | Extended Mouse (SGR) | Pixels Mouse (SGR-Pixels) |
| ---------------- | :----------------: | :-------------------: | :--------------: | :-----------------: | :-------------------------------: | :-------------------------------: | :-------------: | :------------------: | :-----------------------: |
| alacritty | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| foot | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| kitty | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Konsole | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ |
| rxvt | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
| urxvt | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| screen | ⛔[^mux] | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ |
| st | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| tmux | ⛔[^mux] | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| vte-based[^vte] | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ |
| wezterm | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| xterm | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ |
| Linux Console | ❌ | ✅ | ⛔ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Apple Terminal | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ |
| iTerm | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ |
| Windows cmd | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
| Windows Terminal | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| Terminal | Colored & Styled Underlines | Query Color Scheme | Query Cursor Position | Set Window Title | Change Cursor Color | Change Default Foreground Setting | Change Default Background Setting | Bracketed Paste | Extended Mouse (SGR) | Pixels Mouse (SGR-Pixels) |
| ---------------- | :-------------------------: | :----------------: | :-------------------: | :--------------: | :-----------------: | :-------------------------------: | :-------------------------------: | :-------------: | :------------------: | :-----------------------: |
| alacritty | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| foot | ❌[^foot] | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| kitty | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Konsole | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ |
| rxvt | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
| urxvt | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| screen | ❌ | ⛔[^mux] | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ |
| st | ✅[^st] | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| tmux | ✅ | ⛔[^mux] | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| vte-based[^vte] | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ |
| wezterm | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| xterm | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ |
| Linux Console | ❌ | ❌ | ✅ | ⛔ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
| Apple Terminal | ❌ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ |
| iTerm | ✅[^iterm] | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ |
| Windows cmd | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
| Windows Terminal | ❌[^winterm] | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |

[^vte]: This covers all vte-based terminals, including Gnome Terminal, guake, Pantheon Terminal, Terminator, Tilix, XFCE Terminal.
[^mux]: Unavailable as multiplexers (like tmux or screen) can be connected to multiple terminals (with different color settings) at the same time.
[^foot]: https://codeberg.org/dnkl/foot/issues/828
[^st]: Underline styles & colors available using this patch https://st.suckless.org/patches/undercurl/
[^iterm]: Supported in iTerm2 v3.5 https://gitlab.com/gnachman/iterm2/-/issues/6382
[^winterm]: Refer to https://github.com/microsoft/terminal/issues/7228

You can help improve this list! Check out [how to](ansi_compat.md) and open an issue or pull request.

Expand Down
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