Use the terminal's own background color
The panes used palette color 0, which color themes such as Catppuccin set to a grey lighter than their background: everything looked washed out and grey text almost disappeared (seen in Ghostty on macOS). The startup probe now also asks for the background color (OSC 11), and with 24-bit color and a dark background that color is used. The probe always runs at startup, so a later switch to real images in the Config view never has to ask the terminal while the screen owns it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019reK4DUGYqDUjniWYJvwUW
This commit is contained in:
@@ -2,6 +2,10 @@
|
||||
|
||||
## Unreleased
|
||||
|
||||
- **The terminal's own background:** the panes used color 0 of the terminal's palette ("black"),
|
||||
which many color themes set to a grey lighter than their background (e.g. Catppuccin), so the
|
||||
whole program looked washed out and grey text almost disappeared. The terminal is now asked for
|
||||
its background color at startup and that is used (with 24-bit color and a dark background).
|
||||
- **Smooth scrolling on huge terminals:** while an arrow key is held, the poster waits until the
|
||||
selection rests (120 ms). Every poster rewrites all of its cells, which on a terminal zoomed far
|
||||
out was more output per step than the terminal could draw, so moving through a list lagged.
|
||||
|
||||
@@ -64,7 +64,7 @@ Notes:
|
||||
- Global speed / pause state in the status bar. Pause/resume and delete a SABnzbd job.
|
||||
- **Status bar / help:** the bottom bar lists the keys that work in the current view or panel; the top right shows the connection state of each service; `F9` opens the full key reference.
|
||||
- **Posters:** the detail panes show the poster at the top right; the head (title, facts, path) and the plot are one text that flows along the poster's left side and continues at full width below it (text is wrapped by arr-tui itself, with a narrower width for the first lines); on panes too small for the poster, the text simply uses the full width. Two ways to draw the poster, chosen by `ui.cover_style`:
|
||||
- **Real images** (`kitty`, and `auto` in kitty/Ghostty): the Kitty graphics protocol with Unicode placeholders. The poster (kept up to 640 px tall) is uploaded as PNG (`a=t,f=100,q=2`, 4096-byte base64 chunks) and placed virtually with the cell footprint (`a=p,U=1,c=,r=`) right away. Every footprint (crop and cell size) is its own image id, placed once and never changed: Ghostty kept showing the old, small placement when the size of an existing one was changed, so a new size uploads under a new id and deletes the old one. The poster is shown by writing U+10EEEE placeholder characters whose combining marks give row and column (the 297-entry table from the protocol) and whose foreground color is the image id. Since it is ordinary text, popups, dialogs and view changes cover it correctly and tcell's diffing keeps it in place. The footprint uses the real cell size in pixels (the window's pixel size divided by its cell count, rounded down to whole pixels so padding around the grid does not skew it; all images are deleted whenever the window or cell size changes, block characters stand in while the size keeps changing, and real images are uploaded afresh once it has been stable for 300 ms, because uploading and placing for every intermediate size of a window drag raced with the terminal's own resizing) and a box whose shape is within 3% of the poster's; the remaining sliver is cropped from the poster's edges before upload (one upload per size, the previous one is deleted), because the terminal letterboxes an image that does not fit its box exactly. As a second safeguard the placeholder cells use the panes' background color, so anything the picture does not cover blends in (without it the terminal's own, slightly different, default background showed as grey bars beside the poster). Writes to the terminal go through the screen's tty on the UI goroutine, so they cannot interleave with drawing. Requires 24-bit color; otherwise, and inside tmux/screen, the block fallback is used. Terminals are recognised from `TERM`/`TERM_PROGRAM`/`KITTY_WINDOW_ID`/`GHOSTTY_RESOURCES_DIR`, and then asked before the screen starts (a Kitty graphics query followed by a device-attributes request, 300 ms timeout): only a terminal that answers the query gets real images, also with `cover_style: kitty`, because a terminal without the protocol prints the commands as text. The Log says which way posters are drawn. With `ARR_TUI_DEBUG_GFX=1` the Log (F7) lists every window size, the cell shape, every upload (poster size, crop, cells) and every change of what is drawn (image id, position, cells); with a path (`ARR_TUI_DEBUG_GFX=/tmp/arr-gfx.log`) the same lines also go to that file with millisecond timestamps, so they can be read without leaving the view that shows the problem. The go-termimg library was looked at and not used: its placeholder support is marked experimental, its diacritic table does not match the protocol's, and it writes images straight to the terminal instead of through the screen.
|
||||
- **Real images** (`kitty`, and `auto` in kitty/Ghostty): the Kitty graphics protocol with Unicode placeholders. The poster (kept up to 640 px tall) is uploaded as PNG (`a=t,f=100,q=2`, 4096-byte base64 chunks) and placed virtually with the cell footprint (`a=p,U=1,c=,r=`) right away. Every footprint (crop and cell size) is its own image id, placed once and never changed: Ghostty kept showing the old, small placement when the size of an existing one was changed, so a new size uploads under a new id and deletes the old one. The poster is shown by writing U+10EEEE placeholder characters whose combining marks give row and column (the 297-entry table from the protocol) and whose foreground color is the image id. Since it is ordinary text, popups, dialogs and view changes cover it correctly and tcell's diffing keeps it in place. The footprint uses the real cell size in pixels (the window's pixel size divided by its cell count, rounded down to whole pixels so padding around the grid does not skew it; all images are deleted whenever the window or cell size changes, block characters stand in while the size keeps changing, and real images are uploaded afresh once it has been stable for 300 ms, because uploading and placing for every intermediate size of a window drag raced with the terminal's own resizing) and a box whose shape is within 3% of the poster's; the remaining sliver is cropped from the poster's edges before upload (one upload per size, the previous one is deleted), because the terminal letterboxes an image that does not fit its box exactly. As a second safeguard the placeholder cells use the panes' background color, so anything the picture does not cover blends in (without it the terminal's own, slightly different, default background showed as grey bars beside the poster). Writes to the terminal go through the screen's tty on the UI goroutine, so they cannot interleave with drawing. Requires 24-bit color; otherwise, and inside tmux/screen, the block fallback is used. Terminals are recognised from `TERM`/`TERM_PROGRAM`/`KITTY_WINDOW_ID`/`GHOSTTY_RESOURCES_DIR`, and then asked before the screen starts (a Kitty graphics query and a background-color query followed by a device-attributes request, 300 ms timeout, waiting with select(2) because a read deadline does not work on a terminal device on macOS): only a terminal that answers the query gets real images, also with `cover_style: kitty`, because a terminal without the protocol prints the commands as text. The Log says which way posters are drawn. With `ARR_TUI_DEBUG_GFX=1` the Log (F7) lists every window size, the cell shape, every upload (poster size, crop, cells) and every change of what is drawn (image id, position, cells); with a path (`ARR_TUI_DEBUG_GFX=/tmp/arr-gfx.log`) the same lines also go to that file with millisecond timestamps, so they can be read without leaving the view that shows the problem. The go-termimg library was looked at and not used: its placeholder support is marked experimental, its diacritic table does not match the protocol's, and it writes images straight to the terminal instead of through the screen.
|
||||
- **Block characters** (`quadrant`, `sextant`, `cells`, and the fallback): every cell shows several pixels in the best two-color split (`quadrant`: 2×2 pixels, glyphs from the Block Elements range every font has; `sextant`: 2×3 pixels, sharper, glyphs from Symbols for Legacy Computing; `cells`: 1 pixel per cell drawn as background color only, because macOS Terminal draws block elements from the font with the halves off the cell's middle). `auto` picks cells in macOS Terminal (`TERM_PROGRAM=Apple_Terminal`), sextants on kitty, WezTerm, foot and Ghostty, and on other terminals (not on macOS, whose terminals do not use fontconfig's fonts) when fontconfig lists a font with the sextant characters (`fc-list :charset=1fb00`, about 20 ms at startup; terminals draw glyphs their font lacks from fallback fonts; skipped over SSH because the installed fonts are the remote machine's), and quadrants otherwise.
|
||||
Posters are JPEG, PNG, GIF or WebP (Radarr and Sonarr keep whatever bytes the provider sent under a `.jpg` name, which can be WebP), decoded and downscaled in the process; for any other format the Log says what the data looked like (e.g. AVIF, an HTML error page, or its first bytes). Library items fetch `/MediaCover/<id>/poster-250.jpg` from their Radarr/Sonarr instance with the API key (then the original `poster.jpg`; an instance that answers 200 with an HTML page, i.e. wants a login for `/MediaCover`, is also tried with the key as the `apikey` query parameter; and if the instance has no usable copy, the provider's `remoteUrl`, fetched without credentials); search results fall back to the provider's `remoteUrl` (fetched without credentials). Posters are cached in memory (the terminal's copies are deleted when the cache is dropped and on exit), failed downloads are not retried for two minutes and are written to the Log (F7) with the reason, and the poster shrinks or disappears when the pane is too short. `ui.covers: false` disables it.
|
||||
- **Calendar view (F5):** a two-week window (starting today, moved a week at a time with `[`/`]`, `t` returns to today) with the library's movie releases and airing episodes, grouped by day. Radarr `GET /calendar` supplies the cinema, digital and physical release dates (taken as written: midnight UTC means that calendar day) and Sonarr `GET /calendar?includeSeries=true` the episodes with their air time (shown in local time). Unmonitored items are included with `u`. A movie appears once per release date in the window. Each entry shows type, title, episode or release kind and status (downloaded / missing / upcoming); the detail pane shows poster and plot; `Enter`/`i` starts the release search and `s` an automatic search.
|
||||
@@ -103,6 +103,8 @@ Layout sketch (Library view; the other views follow the same frame):
|
||||
|
||||
Popups for action feedback appear in the bottom right and fade away; the Log view (F7) keeps the history.
|
||||
|
||||
Colors: the panes' background is the terminal's own background color (asked with OSC 11 at startup) when the terminal has 24-bit color and a dark background; otherwise tview's default, palette color 0. Color themes often make color 0 a grey lighter than their background (Catppuccin: `#45475a` on `#1e1e2e`), on which grey text almost disappears. Light backgrounds keep color 0 because the text colors are made for dark ones.
|
||||
|
||||
tview primitives: `Pages` (views and stacked overlays), `Flex` (layout), `InputField` (search), `List`/`Table` (results, queues, library), `TextView` (details, log), `Form` (add dialog), `Modal` (confirmations). Popups are drawn by a wrapper around the root primitive.
|
||||
|
||||
Keybindings (the status bar shows the ones that apply to the current view):
|
||||
|
||||
@@ -100,6 +100,9 @@ type overlay struct {
|
||||
|
||||
// New builds the application shell: a tab bar, one page per view and a status bar.
|
||||
func New(cfg *config.Config) *App {
|
||||
// Ask the terminal before the screen takes it over and before any widget
|
||||
// copies the default background.
|
||||
ownBackground := useTerminalBackground(terminalAnswers(), os.Getenv)
|
||||
a := &App{
|
||||
app: tview.NewApplication(),
|
||||
tabs: tview.NewTextView().SetDynamicColors(true),
|
||||
@@ -136,6 +139,9 @@ func New(cfg *config.Config) *App {
|
||||
if a.covers {
|
||||
a.logs.add(levelInfo, coverNote)
|
||||
}
|
||||
if ownBackground {
|
||||
a.logs.add(levelInfo, "Background: the terminal's own color")
|
||||
}
|
||||
sabClient := sabnzbd.NewClient(cfg.SABnzbd.URL, cfg.SABnzbd.APIKey)
|
||||
a.sab = sabClient
|
||||
a.probes = []probe{
|
||||
|
||||
+4
-12
@@ -15,7 +15,6 @@ import (
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
@@ -198,17 +197,10 @@ func resolveCovers(setting string, env func(string) string) (blocks coverStyle,
|
||||
return coverStyleFor(setting, env), false
|
||||
}
|
||||
|
||||
var (
|
||||
kittyProbeOnce sync.Once
|
||||
kittyProbeResult bool
|
||||
)
|
||||
|
||||
// kittyGraphicsSupported asks the terminal once (see probeKittyGraphics) and
|
||||
// remembers the answer. It is a variable so tests can replace it.
|
||||
var kittyGraphicsSupported = func() bool {
|
||||
kittyProbeOnce.Do(func() { kittyProbeResult = probeKittyGraphics(300 * time.Millisecond) })
|
||||
return kittyProbeResult
|
||||
}
|
||||
// kittyGraphicsSupported reports whether the terminal confirmed the Kitty
|
||||
// graphics protocol when it was asked at startup (see probeTerminal). It is a
|
||||
// variable so tests can replace it.
|
||||
var kittyGraphicsSupported = func() bool { return terminalAnswers().graphics }
|
||||
|
||||
// flatPixelError is the squared RGB distance per pixel below which a cell is
|
||||
// drawn flat: smooth areas and noise should not turn into patterns.
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
)
|
||||
|
||||
// TestMain keeps the tests from asking the real terminal about graphics
|
||||
// support (the probe writes to and reads from /dev/tty).
|
||||
// support and its colors (the probe writes to and reads from /dev/tty).
|
||||
func TestMain(m *testing.M) {
|
||||
kittyGraphicsSupported = func() bool { return false }
|
||||
terminalAnswers = func() terminalInfo { return terminalInfo{} }
|
||||
os.Exit(m.Run())
|
||||
}
|
||||
|
||||
@@ -4,5 +4,6 @@ package ui
|
||||
|
||||
import "time"
|
||||
|
||||
// probeKittyGraphics is not implemented here; the block characters are used.
|
||||
func probeKittyGraphics(time.Duration) bool { return false }
|
||||
// probeTerminal is not implemented here: block characters and the default
|
||||
// colors are used.
|
||||
func probeTerminal(time.Duration) terminalInfo { return terminalInfo{} }
|
||||
|
||||
+16
-18
@@ -12,28 +12,28 @@ import (
|
||||
"golang.org/x/term"
|
||||
)
|
||||
|
||||
// probeKittyGraphics asks the terminal whether it understands the Kitty
|
||||
// graphics protocol: a tiny query image (which a capable terminal answers with
|
||||
// "OK" and does not show) followed by a Primary Device Attributes request,
|
||||
// which every terminal answers. If the DA answer arrives without a graphics
|
||||
// answer before it, the protocol is not supported. Runs before the screen is
|
||||
// set up, on the controlling terminal.
|
||||
func probeKittyGraphics(timeout time.Duration) bool {
|
||||
// probeTerminal asks the terminal two things: whether it understands the Kitty
|
||||
// graphics protocol (a tiny query image, which a capable terminal answers with
|
||||
// "OK" and does not show) and its background color (OSC 11). A Primary Device
|
||||
// Attributes request follows, which every terminal answers, and answers come
|
||||
// in order: once the DA answer is in, whatever was not answered before it is
|
||||
// not supported. Runs before the screen is set up, on the controlling terminal.
|
||||
func probeTerminal(timeout time.Duration) (info terminalInfo) {
|
||||
tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0)
|
||||
if err != nil {
|
||||
return false
|
||||
return info
|
||||
}
|
||||
defer tty.Close()
|
||||
fd := int(tty.Fd())
|
||||
state, err := term.MakeRaw(fd)
|
||||
if err != nil {
|
||||
return false
|
||||
return info
|
||||
}
|
||||
defer term.Restore(fd, state)
|
||||
|
||||
const query = "\x1b_Gi=31,s=1,v=1,a=q,t=d,f=24;AAAA\x1b\\" + "\x1b[c"
|
||||
const query = "\x1b_Gi=31,s=1,v=1,a=q,t=d,f=24;AAAA\x1b\\" + "\x1b]11;?\x1b\\" + "\x1b[c"
|
||||
if _, err := tty.WriteString(query); err != nil {
|
||||
return false
|
||||
return info
|
||||
}
|
||||
// A terminal that does not know APC sequences may print the query; erase it.
|
||||
defer tty.WriteString("\r\x1b[2K")
|
||||
@@ -47,7 +47,7 @@ func probeKittyGraphics(timeout time.Duration) bool {
|
||||
for {
|
||||
left := time.Until(deadline)
|
||||
if left <= 0 {
|
||||
return false // no answer in time: assume no support
|
||||
break // no complete answer in time: keep what arrived
|
||||
}
|
||||
var fds unix.FdSet
|
||||
fds.Set(fd)
|
||||
@@ -57,7 +57,7 @@ func probeKittyGraphics(timeout time.Duration) bool {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
return false
|
||||
break
|
||||
}
|
||||
if n == 0 {
|
||||
continue // timed out; the loop ends above
|
||||
@@ -67,14 +67,12 @@ func probeKittyGraphics(timeout time.Duration) bool {
|
||||
continue
|
||||
}
|
||||
if err != nil || n <= 0 {
|
||||
return false
|
||||
break
|
||||
}
|
||||
got = append(got, buf[:n]...)
|
||||
if bytes.Contains(got, []byte("_Gi=31;OK")) {
|
||||
return true
|
||||
}
|
||||
if da := bytes.Index(got, []byte("\x1b[?")); da >= 0 && bytes.IndexByte(got[da:], 'c') >= 0 {
|
||||
return false // device attributes answered, graphics query not
|
||||
break // device attributes answered: everything else came before
|
||||
}
|
||||
}
|
||||
return parseTerminalAnswers(got)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"image/color"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
"github.com/rivo/tview"
|
||||
)
|
||||
|
||||
// terminalInfo is what the terminal said about itself at startup.
|
||||
type terminalInfo struct {
|
||||
graphics bool // the Kitty graphics protocol is supported
|
||||
bg color.RGBA // its background color, if hasBG
|
||||
hasBG bool
|
||||
}
|
||||
|
||||
var (
|
||||
terminalOnce sync.Once
|
||||
terminalResult terminalInfo
|
||||
)
|
||||
|
||||
// terminalAnswers asks the terminal once (see probeTerminal) and remembers the
|
||||
// answers. The first call must happen before the screen is set up, which owns
|
||||
// the terminal afterwards; New makes it. It is a variable so tests can replace it.
|
||||
var terminalAnswers = func() terminalInfo {
|
||||
terminalOnce.Do(func() { terminalResult = probeTerminal(300 * time.Millisecond) })
|
||||
return terminalResult
|
||||
}
|
||||
|
||||
// parseTerminalAnswers reads the answers to probeTerminal's questions.
|
||||
func parseTerminalAnswers(got []byte) (info terminalInfo) {
|
||||
info.graphics = bytes.Contains(got, []byte("_Gi=31;OK"))
|
||||
// OSC 11 answer: ESC ] 11 ; rgb:RRRR/GGGG/BBBB, ended by ST or BEL. Each
|
||||
// component has 1 to 4 hex digits.
|
||||
if i := bytes.Index(got, []byte("\x1b]11;rgb:")); i >= 0 {
|
||||
rest := got[i+len("\x1b]11;rgb:"):]
|
||||
if end := bytes.IndexAny(rest, "\x1b\a"); end >= 0 {
|
||||
rest = rest[:end]
|
||||
}
|
||||
if parts := strings.Split(string(rest), "/"); len(parts) == 3 {
|
||||
var c [3]uint8
|
||||
ok := true
|
||||
for j, p := range parts {
|
||||
v, err := strconv.ParseUint(p, 16, 16)
|
||||
if err != nil || len(p) < 1 || len(p) > 4 {
|
||||
ok = false
|
||||
break
|
||||
}
|
||||
c[j] = uint8(v * 255 / (1<<(4*len(p)) - 1))
|
||||
}
|
||||
if ok {
|
||||
info.bg, info.hasBG = color.RGBA{c[0], c[1], c[2], 255}, true
|
||||
}
|
||||
}
|
||||
}
|
||||
return info
|
||||
}
|
||||
|
||||
// useTerminalBackground makes the terminal's own background color the
|
||||
// background of every pane, instead of color 0 of the palette ("black"), which
|
||||
// color themes often set to a grey that differs from their background (and
|
||||
// on which grey text almost disappears). Only for dark backgrounds: the text
|
||||
// colors are made for those. Needs true color, else the exact color cannot be
|
||||
// drawn. Must run before any widget is created, they copy the style. It
|
||||
// reports whether it changed anything.
|
||||
func useTerminalBackground(info terminalInfo, env func(string) string) bool {
|
||||
if !info.hasBG || !hasTrueColor(env) || luminance(info.bg) > 0.4 {
|
||||
return false
|
||||
}
|
||||
tview.Styles.PrimitiveBackgroundColor = tcell.NewRGBColor(int32(info.bg.R), int32(info.bg.G), int32(info.bg.B))
|
||||
return true
|
||||
}
|
||||
|
||||
// hasTrueColor reports whether the terminal says it draws 24-bit colors.
|
||||
func hasTrueColor(env func(string) string) bool {
|
||||
switch strings.ToLower(env("COLORTERM")) {
|
||||
case "truecolor", "24bit":
|
||||
return true
|
||||
}
|
||||
return strings.HasSuffix(env("TERM"), "-direct")
|
||||
}
|
||||
|
||||
// luminance is the relative brightness of c, from 0 (black) to 1 (white).
|
||||
func luminance(c color.RGBA) float64 {
|
||||
return (0.2126*float64(c.R) + 0.7152*float64(c.G) + 0.0722*float64(c.B)) / 255
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"testing"
|
||||
|
||||
"github.com/gdamore/tcell/v2"
|
||||
"github.com/rivo/tview"
|
||||
)
|
||||
|
||||
func TestParseTerminalAnswers(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
got string
|
||||
graphics bool
|
||||
bg color.RGBA
|
||||
hasBG bool
|
||||
}{
|
||||
{"ghostty", "\x1b_Gi=31;OK\x1b\\\x1b]11;rgb:1e1e/1e1e/2e2e\x1b\\\x1b[?62;22c", true, color.RGBA{30, 30, 46, 255}, true},
|
||||
{"bel and two digits", "\x1b]11;rgb:ff/80/00\a\x1b[?1;2c", false, color.RGBA{255, 128, 0, 255}, true},
|
||||
{"one digit", "\x1b]11;rgb:f/0/8\x1b\\\x1b[?6c", false, color.RGBA{255, 0, 136, 255}, true},
|
||||
{"only device attributes", "\x1b[?1;2c", false, color.RGBA{}, false},
|
||||
{"garbage", "\x1b]11;rgb:zz/00/00\x1b\\\x1b[?6c", false, color.RGBA{}, false},
|
||||
{"nothing", "", false, color.RGBA{}, false},
|
||||
} {
|
||||
info := parseTerminalAnswers([]byte(tc.got))
|
||||
if info.graphics != tc.graphics || info.hasBG != tc.hasBG || info.bg != tc.bg {
|
||||
t.Errorf("%s: %+v", tc.name, info)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUseTerminalBackground(t *testing.T) {
|
||||
defer func(old tcell.Color) { tview.Styles.PrimitiveBackgroundColor = old }(tview.Styles.PrimitiveBackgroundColor)
|
||||
env := func(m map[string]string) func(string) string { return func(k string) string { return m[k] } }
|
||||
dark := terminalInfo{bg: color.RGBA{30, 30, 46, 255}, hasBG: true}
|
||||
light := terminalInfo{bg: color.RGBA{239, 241, 245, 255}, hasBG: true}
|
||||
truecolor := env(map[string]string{"COLORTERM": "truecolor"})
|
||||
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
info terminalInfo
|
||||
env func(string) string
|
||||
want bool
|
||||
}{
|
||||
{"dark background, true color", dark, truecolor, true},
|
||||
{"no true color", dark, env(map[string]string{"TERM": "xterm-256color"}), false},
|
||||
{"light background keeps the default", light, truecolor, false},
|
||||
{"no answer", terminalInfo{}, truecolor, false},
|
||||
} {
|
||||
tview.Styles.PrimitiveBackgroundColor = tcell.ColorBlack
|
||||
if got := useTerminalBackground(tc.info, tc.env); got != tc.want {
|
||||
t.Errorf("%s: %v", tc.name, got)
|
||||
}
|
||||
want := tcell.ColorBlack
|
||||
if tc.want {
|
||||
want = tcell.NewRGBColor(30, 30, 46)
|
||||
}
|
||||
if tview.Styles.PrimitiveBackgroundColor != want {
|
||||
t.Errorf("%s: background %v", tc.name, tview.Styles.PrimitiveBackgroundColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user