Skip to content

Commit

Permalink
Merge pull request #183 from cli/andyfeller/accessible-colors-chroma
Browse files Browse the repository at this point in the history
Ensure codeblocks use accessible colors
  • Loading branch information
andyfeller authored Feb 27, 2025
2 parents 607ac5b + 851d3c3 commit 0136321
Show file tree
Hide file tree
Showing 6 changed files with 216 additions and 37 deletions.
19 changes: 10 additions & 9 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,32 @@ go 1.21
require (
github.com/AlecAivazis/survey/v2 v2.3.7
github.com/MakeNowJust/heredoc v1.0.0
github.com/charmbracelet/glamour v0.8.0
github.com/charmbracelet/lipgloss v0.12.1
github.com/alecthomas/chroma/v2 v2.14.0
github.com/charmbracelet/lipgloss v1.0.0
github.com/cli/browser v1.3.0
github.com/cli/glamour v0.0.0-20250225134531-b1d96ed4a7e1
github.com/cli/safeexec v1.0.0
github.com/cli/shurcooL-graphql v0.0.4
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/henvic/httpretty v0.0.6
github.com/itchyny/gojq v0.12.15
github.com/leaanthony/go-ansi-parser v1.6.1
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d
github.com/muesli/reflow v0.3.0
github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a
github.com/stretchr/testify v1.7.0
github.com/thlib/go-timezone-local v0.0.0-20210907160436-ef149e42d28e
golang.org/x/sys v0.28.0
golang.org/x/term v0.27.0
golang.org/x/sys v0.30.0
golang.org/x/term v0.29.0
golang.org/x/text v0.21.0
gopkg.in/h2non/gock.v1 v1.1.2
gopkg.in/yaml.v3 v3.0.1
)

require (
github.com/alecthomas/chroma/v2 v2.14.0 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/aymerick/douceur v0.2.0 // indirect
github.com/charmbracelet/x/ansi v0.1.4 // indirect
github.com/charmbracelet/x/ansi v0.8.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dlclark/regexp2 v1.11.0 // indirect
github.com/gorilla/css v1.0.1 // indirect
Expand All @@ -40,12 +41,12 @@ require (
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/microcosm-cc/bluemonday v1.0.27 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/yuin/goldmark v1.7.4 // indirect
github.com/yuin/goldmark-emoji v1.0.3 // indirect
github.com/yuin/goldmark v1.7.8 // indirect
github.com/yuin/goldmark-emoji v1.0.4 // indirect
golang.org/x/net v0.33.0 // indirect
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
)
42 changes: 24 additions & 18 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,18 @@ github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWp
github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
github.com/charmbracelet/glamour v0.8.0 h1:tPrjL3aRcQbn++7t18wOpgLyl8wrOHUEDS7IZ68QtZs=
github.com/charmbracelet/glamour v0.8.0/go.mod h1:ViRgmKkf3u5S7uakt2czJ272WSg2ZenlYEZXT2x7Bjw=
github.com/charmbracelet/lipgloss v0.12.1 h1:/gmzszl+pedQpjCOH+wFkZr/N90Snz40J/NR7A0zQcs=
github.com/charmbracelet/lipgloss v0.12.1/go.mod h1:V2CiwIuhx9S1S1ZlADfOj9HmxeMAORuz5izHb0zGbB8=
github.com/charmbracelet/x/ansi v0.1.4 h1:IEU3D6+dWwPSgZ6HBH+v6oUuZ/nVawMiWj5831KfiLM=
github.com/charmbracelet/x/ansi v0.1.4/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
github.com/charmbracelet/x/exp/golden v0.0.0-20240715153702-9ba8adf781c4 h1:6KzMkQeAF56rggw2NZu1L+TH7j9+DM1/2Kmh7KUxg1I=
github.com/charmbracelet/x/exp/golden v0.0.0-20240715153702-9ba8adf781c4/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
github.com/charmbracelet/lipgloss v1.0.0 h1:O7VkGDvqEdGi93X+DeqsQ7PKHDgtQfF8j8/O2qFMQNg=
github.com/charmbracelet/lipgloss v1.0.0/go.mod h1:U5fy9Z+C38obMs+T+tJqst9VGzlOYGj4ri9reL3qUlo=
github.com/charmbracelet/x/ansi v0.8.0 h1:9GTq3xq9caJW8ZrBTe0LIe2fvfLR/bYXKTx2llXn7xE=
github.com/charmbracelet/x/ansi v0.8.0/go.mod h1:wdYl/ONOLHLIVmQaxbIYEC/cRKOQyjTkowiI4blgS9Q=
github.com/charmbracelet/x/exp/golden v0.0.0-20240806155701-69247e0abc2a h1:G99klV19u0QnhiizODirwVksQB91TJKV/UaTnACcG30=
github.com/charmbracelet/x/exp/golden v0.0.0-20240806155701-69247e0abc2a/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
github.com/cli/browser v1.3.0 h1:LejqCrpWr+1pRqmEPDGnTZOjsMe7sehifLynZJuqJpo=
github.com/cli/browser v1.3.0/go.mod h1:HH8s+fOAxjhQoBUAsKuPCbqUuxZDhQ2/aD+SzsEfBTk=
github.com/cli/glamour v0.0.0-20250220192152-8544502ccff9 h1:fPJNUzG+Au+pIfYx2c5QNngZ3KLj7xAzjutL6efy1x8=
github.com/cli/glamour v0.0.0-20250220192152-8544502ccff9/go.mod h1:bB4uNJ5F0+nzpGqwlhKEy7tD0PPL0SxNWEwZzG77vMg=
github.com/cli/glamour v0.0.0-20250225134531-b1d96ed4a7e1 h1:TrV+Bs2RKR/CeodJDRO6GXzIxT7PAOwbuxth8ACcucg=
github.com/cli/glamour v0.0.0-20250225134531-b1d96ed4a7e1/go.mod h1:bB4uNJ5F0+nzpGqwlhKEy7tD0PPL0SxNWEwZzG77vMg=
github.com/cli/safeexec v1.0.0 h1:0VngyaIyqACHdcMNWfo6+KdUYnqEr2Sg+bSP1pdF+dI=
github.com/cli/safeexec v1.0.0/go.mod h1:Z/D4tTN8Vs5gXYHDCbaM1S/anmEDnJb1iW0+EJ5zx3Q=
github.com/cli/shurcooL-graphql v0.0.4 h1:6MogPnQJLjKkaXPyGqPRXOI2qCsQdqNfUY1QSJu2GuY=
Expand Down Expand Up @@ -60,8 +62,12 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/leaanthony/go-ansi-parser v1.6.1 h1:xd8bzARK3dErqkPFtoF9F3/HgN8UQk0ed1YDKpEz01A=
github.com/leaanthony/go-ansi-parser v1.6.1/go.mod h1:+vva/2y4alzVmmIEpk9QDhA7vLC5zKDTRwfZGOp3IWU=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
Expand All @@ -70,8 +76,8 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
Expand All @@ -97,10 +103,10 @@ github.com/thlib/go-timezone-local v0.0.0-20210907160436-ef149e42d28e h1:Buzhfgf
github.com/thlib/go-timezone-local v0.0.0-20210907160436-ef149e42d28e/go.mod h1:/Tnicc6m/lsJE0irFMA0LfIwTBo4QP7A8IfyIv4zZKI=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg=
github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
github.com/yuin/goldmark-emoji v1.0.3 h1:aLRkLHOuBR2czCY4R8olwMjID+tENfhyFDMCRhbIQY4=
github.com/yuin/goldmark-emoji v1.0.3/go.mod h1:tTkZEbwu5wkPmgTcitqddVxY9osFZiavD+r4AzQrh1U=
github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic=
github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
github.com/yuin/goldmark-emoji v1.0.4 h1:vCwMkPZSNefSUnOW2ZKRUjBSD5Ok3W78IXhGxxAEF90=
github.com/yuin/goldmark-emoji v1.0.4/go.mod h1:tTkZEbwu5wkPmgTcitqddVxY9osFZiavD+r4AzQrh1U=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
Expand All @@ -120,12 +126,12 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
Expand Down
4 changes: 2 additions & 2 deletions pkg/markdown/accessibility.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package markdown
import (
"strconv"

"github.com/charmbracelet/glamour/ansi"
"github.com/charmbracelet/glamour/styles"
"github.com/cli/glamour/ansi"
"github.com/cli/glamour/styles"
)

type ANSIColorCode int
Expand Down
4 changes: 2 additions & 2 deletions pkg/markdown/accessibility_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package markdown
import (
"testing"

"github.com/charmbracelet/glamour/ansi"
"github.com/charmbracelet/glamour/styles"
"github.com/cli/glamour/ansi"
"github.com/cli/glamour/styles"
"github.com/stretchr/testify/assert"
)

Expand Down
7 changes: 5 additions & 2 deletions pkg/markdown/markdown.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"os"
"strings"

"github.com/charmbracelet/glamour"
"github.com/cli/glamour"
"github.com/cli/go-gh/v2/pkg/accessibility"
)

Expand Down Expand Up @@ -39,7 +39,10 @@ func WithTheme(theme string) glamour.TermRendererOption {
switch theme {
case "light", "dark":
if accessible {
return glamour.WithStyles(AccessibleStyleConfig(theme))
return glamour.WithOptions(
glamour.WithStyles(AccessibleStyleConfig(theme)),
glamour.WithChromaFormatter("terminal16"),
)
}
style = theme
default:
Expand Down
177 changes: 173 additions & 4 deletions pkg/markdown/markdown_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import (
"strings"
"testing"

"github.com/MakeNowJust/heredoc"
"github.com/alecthomas/chroma/v2/styles"
"github.com/cli/go-gh/v2/pkg/accessibility"
ansi "github.com/leaanthony/go-ansi-parser"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
Expand All @@ -21,12 +24,149 @@ const (
brightMagenta_4bitColorSeq = "\x1b[95;"
)

// Test_Render verifies that the proper ANSI color codes are applied to the rendered
// Test_RenderAccessible tests rendered markdown for accessibility concerns such as color mode / depth and other display attributes.
// It works by parsing the rendered markdown for ANSI escape sequences and checking their display attributes.
// Test scenarios allow multiple color mode / depths because `ansi.Parse()` considers `\x1b[0m` sequence as part of `ansi.Default`.
func Test_RenderAccessible(t *testing.T) {
goCodeBlock := heredoc.Docf(`
%[1]s%[1]s%[1]sgo
package main
import (
"fmt"
)
func main() {
fmt.Println("Hello, world!")
}
%[1]s%[1]s%[1]s
`, "`")

shellCodeBlock := heredoc.Docf(`
%[1]s%[1]s%[1]sshell
# list all repositories for a user
$ gh api graphql --paginate -f query='
query($endCursor: String) {
viewer {
repositories(first: 100, after: $endCursor) {
nodes { nameWithOwner }
pageInfo {
hasNextPage
endCursor
}
}
}
}
'
%[1]s%[1]s%[1]s
`)

tests := []struct {
name string
text string
theme string
accessible bool
wantColourModes []ansi.ColourMode
allowDimFaintText bool
}{
{
name: "when the light theme is selected, the Go codeblock renders using 8-bit colors",
text: goCodeBlock,
theme: "light",
wantColourModes: []ansi.ColourMode{ansi.Default, ansi.TwoFiveSix},
allowDimFaintText: true,
},
{
name: "when the dark theme is selected, the Go codeblock renders using 8-bit colors",
text: goCodeBlock,
theme: "dark",
wantColourModes: []ansi.ColourMode{ansi.Default, ansi.TwoFiveSix},
allowDimFaintText: true,
},
{
name: "when the accessible env var is set and the light theme is selected, the Go codeblock renders using 4-bit colors without dim/faint text",
text: goCodeBlock,
theme: "light",
accessible: true,
wantColourModes: []ansi.ColourMode{ansi.Default},
allowDimFaintText: false,
},
{
name: "when the accessible env var is set and the dark theme is selected, the Go codeblock renders using 4-bit colors without dim/faint text",
text: goCodeBlock,
theme: "dark",
accessible: true,
wantColourModes: []ansi.ColourMode{ansi.Default},
allowDimFaintText: false,
},
{
name: "when the light theme is selected, the Shell codeblock renders using 8-bit colors",
text: shellCodeBlock,
theme: "light",
wantColourModes: []ansi.ColourMode{ansi.Default, ansi.TwoFiveSix},
allowDimFaintText: true,
},
{
name: "when the dark theme is selected, the Shell codeblock renders using 8-bit colors",
text: shellCodeBlock,
theme: "dark",
wantColourModes: []ansi.ColourMode{ansi.Default, ansi.TwoFiveSix},
allowDimFaintText: true,
},
{
name: "when the accessible env var is set and the light theme is selected, the Shell codeblock renders using 4-bit colors without dim/faint text",
text: shellCodeBlock,
theme: "light",
accessible: true,
wantColourModes: []ansi.ColourMode{ansi.Default},
allowDimFaintText: false,
},
{
name: "when the accessible env var is set and the dark theme is selected, the Shell codeblock renders using 4-bit colors without dim/faint text",
text: shellCodeBlock,
theme: "dark",
accessible: true,
wantColourModes: []ansi.ColourMode{ansi.Default},
allowDimFaintText: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.accessible {
t.Setenv(accessibility.ACCESSIBILITY_ENV, "true")
}

out, err := Render(tt.text, WithTheme(tt.theme))
require.NoError(t, err)

// Parse and test ANSI escape sequences from rendered markdown for inaccessible display attributes
styledText, err := ansi.Parse(out)
require.NoError(t, err)

for _, st := range styledText {
require.Containsf(t, tt.wantColourModes, st.ColourMode, "Unexpected color mode detected in '%s' at %d", st, st.Offset)

if st.Faint() {
require.Truef(t, tt.allowDimFaintText, "Unexpected dim/faint text detected in '%s' at %d", st, st.Offset)
}
}
})
}
}

// Test_RenderColor verifies that the proper ANSI color codes are applied to the rendered
// markdown by examining the ANSI escape sequences in the output for the correct color
// match. For more information on ANSI color codes, see
// https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit
func Test_Render(t *testing.T) {
func Test_RenderColor(t *testing.T) {
t.Setenv("GLAMOUR_STYLE", "")

codeBlock := heredoc.Docf(`
%[1]s%[1]s%[1]sgo
fmt.Println("Hello, world!")
%[1]s%[1]s%[1]s
`, "`")

tests := []struct {
name string
text string
Expand Down Expand Up @@ -74,14 +214,43 @@ func Test_Render(t *testing.T) {
accessibleEnvVar: "true",
wantOut: fmt.Sprintf("%s1mh2", brightMagenta_4bitColorSeq),
},
{
name: "when the light theme is selected, the codeblock renders using 8-bit colors",
text: codeBlock,
theme: "light",
wantOut: "\x1b[0m\x1b[38;5;235mfmt\x1b[0m\x1b[38;5;210m.\x1b[0m\x1b[38;5;35mPrintln\x1b[0m\x1b[38;5;210m(\x1b[0m\x1b[38;5;95m\"Hello, world!\"\x1b[0m\x1b[38;5;210m)\x1b[0m",
},
{
name: "when the dark theme is selected, the codeblock renders using 8-bit colors",
text: codeBlock,
theme: "dark",
wantOut: "\x1b[0m\x1b[38;5;251mfmt\x1b[0m\x1b[38;5;187m.\x1b[0m\x1b[38;5;42mPrintln\x1b[0m\x1b[38;5;187m(\x1b[0m\x1b[38;5;173m\"Hello, world!\"\x1b[0m\x1b[38;5;187m)\x1b[0m",
},
{
name: "when the accessible env var is set and the light theme is selected, the codeblock renders using 4-bit colors",
text: codeBlock,
theme: "light",
accessibleEnvVar: "true",
wantOut: "\x1b[0m\x1b[30mfmt\x1b[0m\x1b[33m.\x1b[0m\x1b[36mPrintln\x1b[0m\x1b[33m(\x1b[0m\x1b[90m\"Hello, world!\"\x1b[0m\x1b[33m)\x1b[0m",
},
{
name: "when the accessible env var is set and the dark theme is selected, the codeblock renders using 4-bit colors",
text: codeBlock,
theme: "dark",
accessibleEnvVar: "true",
wantOut: "\x1b[0m\x1b[37mfmt\x1b[0m\x1b[37m.\x1b[0m\x1b[36mPrintln\x1b[0m\x1b[37m(\x1b[0m\x1b[33m\"Hello, world!\"\x1b[0m\x1b[37m)\x1b[0m",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Cleanup(func() {
// Chroma caches charm style used to render codeblocks, it must be unregistered to avoid previously used style being reused.
delete(styles.Registry, "charm")
})
t.Setenv(accessibility.ACCESSIBILITY_ENV, tt.accessibleEnvVar)

if tt.styleEnvVar != "" {
tmpDir := t.TempDir()
path := filepath.Join(tmpDir, fmt.Sprintf("%s.json", tt.styleEnvVar))
path := filepath.Join(t.TempDir(), fmt.Sprintf("%s.json", tt.styleEnvVar))
err := os.WriteFile(path, []byte(customGlamourStyle(t)), 0644)
if err != nil {
t.Fatal(err)
Expand Down

0 comments on commit 0136321

Please sign in to comment.