cat / 012
clone

a spreadsheet for the terminal: lotus 1-2-3 looks, google sheets keys and formulas, one go binary

Test config, themes and the API key end to end

Dami committed c97c9c9
e2e builds 012 with -tags fakekeyring, whose credential store is a
file under XDG_CONFIG_HOME, and gives every session its own config
directory. New tests cover config warnings, the theme picker (preview,
Esc, saving, the next start), .env files not being read, set-key then
JEV, and the masked key prompt; golden screens show two dark schemes,
a light one with a menu open, a 61-column overlay, the theme picker,
the key prompt and a config warning.
commit
c97c9c9d05a0cca615b5584df6c4782c52144b1e
parent
7e2d997efe21c40a1aa5fc8717a73e805e928807
author
Dami <dami.etoile@gmail.com>
21 files changed, +452 -17
Ae2e/config_test.go111++++++++++++++++++++++++++++++
Me2e/harness_test.go30++++++++-
Me2e/jev_test.go2+-
Me2e/screenlist_test.go32+++++++++
Ae2e/testdata/screens/api-key-prompt.html30++++++++
Ae2e/testdata/screens/config-warning.html30++++++++
Me2e/testdata/screens/menu-settings.html14++--
Me2e/testdata/screens/palette-narrow.html2+-
Me2e/testdata/screens/palette-search-light.html2+-
Me2e/testdata/screens/palette-search.html2+-
Me2e/testdata/screens/palette-wide.html2+-
Me2e/testdata/screens/palette.html6+-
Ae2e/testdata/screens/theme-classic-narrow-menu.html16++++
Ae2e/testdata/screens/theme-classic.html30++++++++
Ae2e/testdata/screens/theme-dark.html30++++++++
Ae2e/testdata/screens/theme-light-menu.html30++++++++
Ae2e/testdata/screens/theme-picker.html30++++++++
Minternal/keyring/system_darwin.go2+
Ainternal/keyring/system_fake.go64+++++++++++++++++
Minternal/keyring/system_unix.go2+-
Minternal/keyring/system_windows.go2+
A e2e/config_test.go +111 -0
@@ -0,0 +1,111 @@
1+package e2e2+3+import (4+ "os"5+ "os/exec"6+ "path/filepath"7+ "strings"8+ "testing"9+)10+11+// Problems in the config file show on the context line; 012 starts12+// anyway, with defaults for what's wrong.13+func TestConfigWarnings(t *testing.T) {14+ s := startWith(t, options{config: "theme = Dracula\nbogus = 1\nchart-images = maybe\n"})15+ s.waitFor(`Config: config:2: unknown key "bogus" (and 1 more; run 012 config)`)16+ if !strings.Contains(s.html(), "background:#1e1f29") {17+ t.Error("the valid theme line was not applied")18+ }19+}20+21+// openTheme opens File > Settings > Theme.22+func openTheme(s *session) {23+ s.keys("<alt+f>", "<up>", "<up>", "<right>", "<down>")24+ s.waitFor("Pick a color theme")25+ s.keys("<enter>")26+ s.waitFor("─ Theme ─")27+}28+29+// The theme picker previews the highlighted theme, Esc restores the one30+// there was, and Enter keeps and saves it, so the next start has it.31+func TestThemePicker(t *testing.T) {32+ cfg := t.TempDir()33+ s := startWith(t, options{configDir: cfg})34+ openTheme(s)35+ s.keys("Dracula")36+ s.eventually("Dracula previewed", func() bool { return strings.Contains(s.html(), "background:#1e1f29") })37+ s.keys("<esc>")38+ s.eventually("the terminal theme restored", func() bool { return !strings.Contains(s.html(), "#1e1f29") })39+ s.waitFor("READY")40+41+ openTheme(s)42+ s.keys("Dracula", "<enter>")43+ s.waitFor("Theme Dracula, saved in")44+ data, err := os.ReadFile(filepath.Join(cfg, "012", "config"))45+ if err != nil || string(data) != "theme = Dracula\n" {46+ t.Errorf("config file %q %v", data, err)47+ }48+ s.keys("<ctrl+q>")49+ s.waitExit()50+51+ r := startWith(t, options{configDir: cfg})52+ r.eventually("Dracula at start", func() bool { return strings.Contains(r.html(), "background:#1e1f29") })53+}54+55+// A .env with the key next to the sheet is never read: JEV stays off,56+// and the context line says how to store the key instead.57+func TestDotEnvNotRead(t *testing.T) {58+ srv, requests := fakeTypeSafe(t)59+ dir := t.TempDir()60+ os.WriteFile(filepath.Join(dir, ".env"), []byte("TYPESAFE_API_KEY=test-key\nTYPESAFE_BASE_URL="+srv.URL+"\n"), 0o600)61+ s := startWith(t, options{dir: dir})62+ s.waitFor("012 no longer reads TYPESAFE_API_KEY from .env files")63+ s.keys(`=JEV.TEST("x", "Q")`, "<enter>", "<up>")64+ s.waitFor("JEV functions need an API key")65+ if n := requests.Load(); n != 0 {66+ t.Errorf("%d requests with a key from .env", n)67+ }68+}69+70+// 012 config set-key stores the key (here in the tests' stand-in for the71+// credential store); the next start finds it there and JEV works.72+func TestSetKeyThenJEV(t *testing.T) {73+ srv, requests := fakeTypeSafe(t)74+ cfg := t.TempDir()75+ cmd := exec.Command(binPath, "config", "set-key")76+ cmd.Env = append(os.Environ(), "XDG_CONFIG_HOME="+cfg, "TYPESAFE_API_KEY=")77+ cmd.Stdin = strings.NewReader("test-key\n")78+ out, err := cmd.CombinedOutput()79+ if err != nil || !strings.Contains(string(out), "Saved the JEV API key in the test credential store") || strings.Contains(string(out), "test-key") {80+ t.Fatalf("set-key: %v\n%s", err, out)81+ }82+ s := startWith(t, options{configDir: cfg, env: []string{"TYPESAFE_BASE_URL=" + srv.URL}})83+ s.keys(`=JEV.TEST("The box was crushed", "Is this a complaint?")`, "<enter>")84+ s.waitForLine(gridRow1, " 1 TRUE")85+ if requests.Load() != 1 {86+ t.Errorf("%d requests", requests.Load())87+ }88+}89+90+// File > Settings > JEV API key takes the key masked, stores it and turns91+// JEV on at once.92+func TestAPIKeyPrompt(t *testing.T) {93+ srv, _ := fakeTypeSafe(t)94+ cfg := t.TempDir()95+ s := startWith(t, options{configDir: cfg, env: []string{"TYPESAFE_BASE_URL=" + srv.URL}})96+ s.keys(`=JEV.TEST("The box was crushed", "Is this a complaint?")`, "<enter>")97+ s.keys("<alt+f>", "<up>", "<up>", "<right>", "<down>", "<down>")98+ s.waitFor("Store the TypeSafe API key")99+ s.keys("<enter>", "test-key")100+ s.waitFor("TypeSafe API key: ••••••••")101+ if strings.Contains(s.screen(), "test-key") {102+ t.Fatal("the key is on screen")103+ }104+ s.keys("<enter>")105+ s.waitFor("API key saved in the test credential store")106+ s.waitForLine(gridRow1, " 1 TRUE")107+ data, err := os.ReadFile(filepath.Join(cfg, "012", "test-credential-store"))108+ if err != nil || string(data) != "test-key" {109+ t.Errorf("stored %q %v", data, err)110+ }111+}
M e2e/harness_test.go +29 -1
@@ -27,7 +27,9 @@ func TestMain(m *testing.M) {
2727 panic(err)2828 }2929 binPath = filepath.Join(dir, "012")30- build := exec.Command("go", "build", "-o", binPath, "./cmd/012")30+ // fakekeyring swaps the OS credential store for a file under31+ // XDG_CONFIG_HOME, which every session points at a temporary directory.32+ build := exec.Command("go", "build", "-tags", "fakekeyring", "-o", binPath, "./cmd/012")3133 build.Dir = ".."3234 build.Env = append(os.Environ(), "CGO_ENABLED=0")3335 if out, err := build.CombinedOutput(); err != nil {
@@ -68,6 +70,11 @@ type options struct {
6870 light bool // use the light reference palette6971 env []string // extra environment, e.g. a fake JEV endpoint7072 jev bool // answer JEV functions with a fake service (screens)73+ // config is the session's config file. Every session has its own74+ // config directory (XDG_CONFIG_HOME), so the user's is never read;75+ // configDir shares one between sessions.76+ config string77+ configDir string7178 // graphics turns on the kitty graphics protocol, so charts become7279 // images; off by default, so screens show the text charts every7380 // terminal gets.
@@ -123,6 +130,7 @@ func startWith(t *testing.T, o options, args ...string) *session {
123130 // Tests never reach the real JEV service: the key is cleared unless a124131 // test points JEV at a fake server through o.env.125132 s.cmd.Env = append(os.Environ(), "TERM=xterm-256color", "COLORTERM=truecolor", "TYPESAFE_API_KEY=", "TYPESAFE_BASE_URL=")133+ s.cmd.Env = append(s.cmd.Env, configEnv(t, o)...)126134 s.cmd.Env = append(s.cmd.Env, o.env...)127135 s.pty, err = pty.StartWithSize(s.cmd, &pty.Winsize{Cols: s.cols, Rows: s.rows})128136 if err != nil {
@@ -456,3 +464,23 @@ var charKeys = func() map[rune]physKey {
456464 }457465 return m458466 }()467+468+// configEnv gives a session its own config directory, with o.config as469+// its config file, and turns off the telemetry and theme variables a470+// developer's shell may set.471+func configEnv(t *testing.T, o options) []string {472+ t.Helper()473+ dir := o.configDir474+ if dir == "" {475+ dir = t.TempDir()476+ }477+ if o.config != "" {478+ if err := os.MkdirAll(filepath.Join(dir, "012"), 0o700); err != nil {479+ t.Fatal(err)480+ }481+ if err := os.WriteFile(filepath.Join(dir, "012", "config"), []byte(o.config), 0o600); err != nil {482+ t.Fatal(err)483+ }484+ }485+ return []string{"XDG_CONFIG_HOME=" + dir, "O12_THEME=", "TYPESAFE_DEFAULT_MODEL="}486+}
M e2e/jev_test.go +1 -1
M e2e/screenlist_test.go +32 -0
@@ -238,6 +238,38 @@ var screens = []screen{
238238 s.keys("<alt+f>", "<up>", "<up>", "<right>")239239 s.waitFor("Compute money exactly")240240 }},241+ // Themes: color schemes draw bars and the screen in their own colors.242+ {name: "theme-classic", opts: options{config: "theme = 1-2-3 Classic\n"}, setup: func(s *session) {243+ budget(s)244+ s.keys("<up>", "<up>", "<up>", "<up>", "<shift+down>", "<shift+down>")245+ s.waitFor("Sum 2158.4")246+ }},247+ {name: "theme-classic-narrow-menu", opts: options{cols: 61, rows: 16, config: "theme = 1-2-3 Classic\n"}, setup: func(s *session) {248+ budget(s)249+ s.keys("<alt+f>", "<down>", "<down>", "<down>")250+ s.waitFor("Save the sheet")251+ }},252+ {name: "theme-dark", opts: options{config: "theme = TokyoNight\n"}, setup: formatted},253+ {name: "theme-light-menu", opts: options{light: true, config: "theme = light:Catppuccin Latte,dark:Catppuccin Mocha\n"}, setup: func(s *session) {254+ budget(s)255+ s.keys("<alt+f>", "<down>", "<down>", "<down>")256+ s.waitFor("Save the sheet")257+ }},258+ {name: "theme-picker", setup: func(s *session) {259+ budget(s)260+ openTheme(s)261+ s.keys("gruvbox")262+ s.waitFor("│ › gruvbox")263+ }},264+ {name: "api-key-prompt", setup: func(s *session) {265+ s.keys("<alt+f>", "<up>", "<up>", "<right>", "<down>", "<down>")266+ s.waitFor("Store the TypeSafe API key")267+ s.keys("<enter>", "ts-demo-0123456789")268+ s.waitFor("TypeSafe API key: ••••••••••••••••••")269+ }},270+ {name: "config-warning", opts: options{config: "theme = Nord\nbogus = 1\n"}, setup: func(s *session) {271+ s.waitFor(`unknown key "bogus"`)272+ }},241273 {name: "menu-freeze", setup: func(s *session) {242274 inventory(s)243275 s.keys("<alt+v>", "<right>", "<down>")
A e2e/testdata/screens/api-key-prompt.html +30 -0
@@ -0,0 +1,30 @@
1+<pre class="screen"> <span style="text-decoration:underline">F</span>ile <span style="text-decoration:underline">E</span>dit <span style="text-decoration:underline">V</span>iew <span style="text-decoration:underline">I</span>nsert F<span style="text-decoration:underline">o</span>rmat <span style="text-decoration:underline">D</span>ata <span style="text-decoration:underline">H</span>elp <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">KEY</span><span style="background:var(--vt-palette-6)"> </span>2+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">A1</span><span style="background:var(--vt-palette-8)"> </span>3+TypeSafe API key: •••••••••••••••••• <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Enter</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">save</span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Esc</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">cancel</span>4+<span style="background:var(--vt-palette-8)"> </span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">A</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">B</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">C</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">D</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">E</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">F</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">G</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">H</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">I</span><span style="background:var(--vt-palette-8)"> </span>5+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">1</span><span style="background:var(--vt-palette-6)"> </span>6+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">2</span><span style="background:var(--vt-palette-8)"> </span>7+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">3</span><span style="background:var(--vt-palette-8)"> </span>8+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">4</span><span style="background:var(--vt-palette-8)"> </span>9+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">5</span><span style="background:var(--vt-palette-8)"> </span>10+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">6</span><span style="background:var(--vt-palette-8)"> </span>11+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">7</span><span style="background:var(--vt-palette-8)"> </span>12+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">8</span><span style="background:var(--vt-palette-8)"> </span>13+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">9</span><span style="background:var(--vt-palette-8)"> </span>14+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">10</span><span style="background:var(--vt-palette-8)"> </span>15+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">11</span><span style="background:var(--vt-palette-8)"> </span>16+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">12</span><span style="background:var(--vt-palette-8)"> </span>17+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">13</span><span style="background:var(--vt-palette-8)"> </span>18+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">14</span><span style="background:var(--vt-palette-8)"> </span>19+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">15</span><span style="background:var(--vt-palette-8)"> </span>20+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">16</span><span style="background:var(--vt-palette-8)"> </span>21+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">17</span><span style="background:var(--vt-palette-8)"> </span>22+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">18</span><span style="background:var(--vt-palette-8)"> </span>23+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">19</span><span style="background:var(--vt-palette-8)"> </span>24+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">20</span><span style="background:var(--vt-palette-8)"> </span>25+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">21</span><span style="background:var(--vt-palette-8)"> </span>26+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">22</span><span style="background:var(--vt-palette-8)"> </span>27+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">23</span><span style="background:var(--vt-palette-8)"> </span>28+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">24</span><span style="background:var(--vt-palette-8)"> </span>29+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">25</span><span style="background:var(--vt-palette-8)"> </span>30+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">Sheet1</span><span style="background:var(--vt-palette-6)"> </span> <span style="color:var(--vt-palette-8)">+</span> <span style="color:var(--vt-palette-8)">│</span> untitled <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+K</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">search</span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+/</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">shortcuts</span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">F10</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">menu</span></pre>\ No newline at end of file
A e2e/testdata/screens/config-warning.html +30 -0
@@ -0,0 +1,30 @@
1+<pre class="screen"><span style="background:#424854"> </span><span style="color:#d8dee9;background:#424854;text-decoration:underline">F</span><span style="color:#d8dee9;background:#424854">ile</span><span style="background:#424854"> </span><span style="color:#d8dee9;background:#424854;text-decoration:underline">E</span><span style="color:#d8dee9;background:#424854">dit</span><span style="background:#424854"> </span><span style="color:#d8dee9;background:#424854;text-decoration:underline">V</span><span style="color:#d8dee9;background:#424854">iew</span><span style="background:#424854"> </span><span style="color:#d8dee9;background:#424854;text-decoration:underline">I</span><span style="color:#d8dee9;background:#424854">nsert</span><span style="background:#424854"> </span><span style="color:#d8dee9;background:#424854">F</span><span style="color:#d8dee9;background:#424854;text-decoration:underline">o</span><span style="color:#d8dee9;background:#424854">rmat</span><span style="background:#424854"> </span><span style="color:#d8dee9;background:#424854;text-decoration:underline">D</span><span style="color:#d8dee9;background:#424854">ata</span><span style="background:#424854"> </span><span style="color:#d8dee9;background:#424854;text-decoration:underline">H</span><span style="color:#d8dee9;background:#424854">elp</span><span style="background:#424854"> </span><span style="background:#88c0d0"> </span><span style="color:#3b4252;background:#88c0d0;font-weight:bold">READY</span><span style="background:#88c0d0"> </span>2+<span style="background:#4c566a"> </span><span style="color:#eceff4;background:#4c566a">A1</span><span style="background:#4c566a"> </span><span style="background:#2e3440"> </span>3+<span style="color:#ebcb8b;background:#2e3440">Config:</span><span style="background:#2e3440"> </span><span style="color:#ebcb8b;background:#2e3440">config:2:</span><span style="background:#2e3440"> </span><span style="color:#ebcb8b;background:#2e3440">unknown</span><span style="background:#2e3440"> </span><span style="color:#ebcb8b;background:#2e3440">key</span><span style="background:#2e3440"> </span><span style="color:#ebcb8b;background:#2e3440">&#34;bogus&#34;</span><span style="background:#2e3440"> </span>4+<span style="background:#4c566a"> </span><span style="background:#88c0d0"> </span><span style="color:#3b4252;background:#88c0d0;font-weight:bold">A</span><span style="background:#88c0d0"> </span><span style="background:#4c566a"> </span><span style="color:#eceff4;background:#4c566a">B</span><span style="background:#4c566a"> </span><span style="color:#eceff4;background:#4c566a">C</span><span style="background:#4c566a"> </span><span style="color:#eceff4;background:#4c566a">D</span><span style="background:#4c566a"> </span><span style="color:#eceff4;background:#4c566a">E</span><span style="background:#4c566a"> </span><span style="color:#eceff4;background:#4c566a">F</span><span style="background:#4c566a"> </span><span style="color:#eceff4;background:#4c566a">G</span><span style="background:#4c566a"> </span><span style="color:#eceff4;background:#4c566a">H</span><span style="background:#4c566a"> </span><span style="color:#eceff4;background:#4c566a">I</span><span style="background:#4c566a"> </span>5+<span style="background:#88c0d0"> </span><span style="color:#3b4252;background:#88c0d0;font-weight:bold">1</span><span style="background:#88c0d0"> </span><span style="background:#2e3440"> </span>6+<span style="background:#4c566a"> </span><span style="color:#eceff4;background:#4c566a">2</span><span style="background:#4c566a"> </span><span style="background:#2e3440"> </span>7+<span style="background:#4c566a"> </span><span style="color:#eceff4;background:#4c566a">3</span><span style="background:#4c566a"> </span><span style="background:#2e3440"> </span>8+<span style="background:#4c566a"> </span><span style="color:#eceff4;background:#4c566a">4</span><span style="background:#4c566a"> </span><span style="background:#2e3440"> </span>9+<span style="background:#4c566a"> </span><span style="color:#eceff4;background:#4c566a">5</span><span style="background:#4c566a"> </span><span style="background:#2e3440"> </span>10+<span style="background:#4c566a"> </span><span style="color:#eceff4;background:#4c566a">6</span><span style="background:#4c566a"> </span><span style="background:#2e3440"> </span>11+<span style="background:#4c566a"> </span><span style="color:#eceff4;background:#4c566a">7</span><span style="background:#4c566a"> </span><span style="background:#2e3440"> </span>12+<span style="background:#4c566a"> </span><span style="color:#eceff4;background:#4c566a">8</span><span style="background:#4c566a"> </span><span style="background:#2e3440"> </span>13+<span style="background:#4c566a"> </span><span style="color:#eceff4;background:#4c566a">9</span><span style="background:#4c566a"> </span><span style="background:#2e3440"> </span>14+<span style="background:#4c566a"> </span><span style="color:#eceff4;background:#4c566a">10</span><span style="background:#4c566a"> </span><span style="background:#2e3440"> </span>15+<span style="background:#4c566a"> </span><span style="color:#eceff4;background:#4c566a">11</span><span style="background:#4c566a"> </span><span style="background:#2e3440"> </span>16+<span style="background:#4c566a"> </span><span style="color:#eceff4;background:#4c566a">12</span><span style="background:#4c566a"> </span><span style="background:#2e3440"> </span>17+<span style="background:#4c566a"> </span><span style="color:#eceff4;background:#4c566a">13</span><span style="background:#4c566a"> </span><span style="background:#2e3440"> </span>18+<span style="background:#4c566a"> </span><span style="color:#eceff4;background:#4c566a">14</span><span style="background:#4c566a"> </span><span style="background:#2e3440"> </span>19+<span style="background:#4c566a"> </span><span style="color:#eceff4;background:#4c566a">15</span><span style="background:#4c566a"> </span><span style="background:#2e3440"> </span>20+<span style="background:#4c566a"> </span><span style="color:#eceff4;background:#4c566a">16</span><span style="background:#4c566a"> </span><span style="background:#2e3440"> </span>21+<span style="background:#4c566a"> </span><span style="color:#eceff4;background:#4c566a">17</span><span style="background:#4c566a"> </span><span style="background:#2e3440"> </span>22+<span style="background:#4c566a"> </span><span style="color:#eceff4;background:#4c566a">18</span><span style="background:#4c566a"> </span><span style="background:#2e3440"> </span>23+<span style="background:#4c566a"> </span><span style="color:#eceff4;background:#4c566a">19</span><span style="background:#4c566a"> </span><span style="background:#2e3440"> </span>24+<span style="background:#4c566a"> </span><span style="color:#eceff4;background:#4c566a">20</span><span style="background:#4c566a"> </span><span style="background:#2e3440"> </span>25+<span style="background:#4c566a"> </span><span style="color:#eceff4;background:#4c566a">21</span><span style="background:#4c566a"> </span><span style="background:#2e3440"> </span>26+<span style="background:#4c566a"> </span><span style="color:#eceff4;background:#4c566a">22</span><span style="background:#4c566a"> </span><span style="background:#2e3440"> </span>27+<span style="background:#4c566a"> </span><span style="color:#eceff4;background:#4c566a">23</span><span style="background:#4c566a"> </span><span style="background:#2e3440"> </span>28+<span style="background:#4c566a"> </span><span style="color:#eceff4;background:#4c566a">24</span><span style="background:#4c566a"> </span><span style="background:#2e3440"> </span>29+<span style="background:#4c566a"> </span><span style="color:#eceff4;background:#4c566a">25</span><span style="background:#4c566a"> </span><span style="background:#2e3440"> </span>30+<span style="background:#88c0d0"> </span><span style="color:#3b4252;background:#88c0d0;font-weight:bold">Sheet1</span><span style="background:#88c0d0"> </span><span style="background:#424854"> </span><span style="color:#747d8e;background:#424854">+</span><span style="background:#424854"> </span><span style="color:#747d8e;background:#424854">│</span><span style="background:#424854"> </span><span style="color:#d8dee9;background:#424854">untitled</span><span style="background:#424854"> </span><span style="background:#4c566a"> </span><span style="color:#eceff4;background:#4c566a">Ctrl+K</span><span style="background:#4c566a"> </span><span style="background:#424854"> </span><span style="color:#747d8e;background:#424854">search</span><span style="background:#424854"> </span><span style="background:#4c566a"> </span><span style="color:#eceff4;background:#4c566a">Ctrl+/</span><span style="background:#4c566a"> </span><span style="background:#424854"> </span><span style="color:#747d8e;background:#424854">shortcuts</span><span style="background:#424854"> </span><span style="background:#4c566a"> </span><span style="color:#eceff4;background:#4c566a">F10</span><span style="background:#4c566a"> </span><span style="background:#424854"> </span><span style="color:#747d8e;background:#424854">menu</span></pre>\ No newline at end of file
M e2e/testdata/screens/menu-settings.html +7 -7
@@ -9,13 +9,13 @@
99 <span style="color:var(--vt-palette-8)">│</span> Download › <span style="color:var(--vt-palette-8)">│</span>1010 <span style="color:var(--vt-palette-8)">├─────────────────────┤┌────────────────────────┐</span>1111 <span style="color:var(--vt-palette-8)">│</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">Settings</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">›</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-8)">││</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">Decimal</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">arithmetic</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">✓</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-8)">│</span>12-<span style="color:var(--vt-palette-8)">├─────────────────────┤└────────────────────────┘</span>13-<span style="color:var(--vt-palette-8)">│</span> Quit <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Q</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>14-<span style="color:var(--vt-palette-8)">└─────────────────────┘</span>15-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">11</span><span style="background:var(--vt-palette-8)"> </span>16-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">12</span><span style="background:var(--vt-palette-8)"> </span>17-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">13</span><span style="background:var(--vt-palette-8)"> </span>18-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">14</span><span style="background:var(--vt-palette-8)"> </span>12+<span style="color:var(--vt-palette-8)">├─────────────────────┤├────────────────────────┤</span>13+<span style="color:var(--vt-palette-8)">│</span> Quit <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Q</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">││</span> Theme <span style="color:var(--vt-palette-8)">│</span>14+<span style="color:var(--vt-palette-8)">└─────────────────────┘│</span> JEV API key <span style="color:var(--vt-palette-8)">│</span>15+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">11</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">├────────────────────────┤</span>16+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">12</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> Open config file <span style="color:var(--vt-palette-8)">│</span>17+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">13</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> Reload config <span style="color:var(--vt-palette-8)">│</span>18+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">14</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">└────────────────────────┘</span>1919 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">15</span><span style="background:var(--vt-palette-8)"> </span>2020 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">16</span><span style="background:var(--vt-palette-8)"> </span>2121 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">17</span><span style="background:var(--vt-palette-8)"> </span>
M e2e/testdata/screens/palette-narrow.html +1 -1
@@ -12,5 +12,5 @@
1212 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">Ask</span> <span style="color:var(--vt-palette-8)">JEV</span> <span style="color:var(--vt-palette-8)">again</span> <span style="color:var(--vt-palette-8)">Data</span> <span style="color:var(--vt-palette-8)">│</span>1313 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-3);font-weight:bold">S</span>ort r<span style="color:var(--vt-palette-3);font-weight:bold">a</span>nge <span style="color:var(--vt-palette-8)">Data</span> <span style="color:var(--vt-palette-8)">›</span> <span style="color:var(--vt-palette-8)">Sor…</span> <span style="color:var(--vt-palette-8)">│</span>1414 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">Select</span> <span style="color:var(--vt-palette-8)">chart</span> <span style="color:var(--vt-palette-8)">│</span>15-<span style="color:var(--vt-palette-8)">└──────────────────────────────────────────────</span> <span style="color:var(--vt-palette-8)">24</span> <span style="color:var(--vt-palette-8)">of</span> <span style="color:var(--vt-palette-8)">100</span> <span style="color:var(--vt-palette-8)">─┘</span>15+<span style="color:var(--vt-palette-8)">└──────────────────────────────────────────────</span> <span style="color:var(--vt-palette-8)">24</span> <span style="color:var(--vt-palette-8)">of</span> <span style="color:var(--vt-palette-8)">104</span> <span style="color:var(--vt-palette-8)">─┘</span>1616 Save the sheet u… <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Up/Down</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">move</span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Enter</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">run</span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Esc</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">close</span></pre>\ No newline at end of file
M e2e/testdata/screens/palette-search-light.html +1 -1
@@ -14,7 +14,7 @@
1414 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">10</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> Insert <span style="color:var(--vt-palette-4);font-weight:bold">col</span>umns right <span style="color:var(--vt-palette-0)">Insert</span> <span style="color:var(--vt-palette-8)">│</span>1515 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">11</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> Delete rows or <span style="color:var(--vt-palette-4);font-weight:bold">col</span>umns <span style="color:var(--vt-palette-0)">Edit</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+Alt+-</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span>1616 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">12</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> Insert rows or <span style="color:var(--vt-palette-4);font-weight:bold">col</span>umns <span style="color:var(--vt-palette-0)">Insert</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+Alt+=</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span>17-<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">13</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">└──────────────────────────────────────────────────────</span> <span style="color:var(--vt-palette-0)">15</span> <span style="color:var(--vt-palette-0)">of</span> <span style="color:var(--vt-palette-0)">100</span> <span style="color:var(--vt-palette-8)">─┘</span>17+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">13</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">└──────────────────────────────────────────────────────</span> <span style="color:var(--vt-palette-0)">17</span> <span style="color:var(--vt-palette-0)">of</span> <span style="color:var(--vt-palette-0)">104</span> <span style="color:var(--vt-palette-8)">─┘</span>1818 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">14</span><span style="background:var(--vt-palette-7)"> </span>1919 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">15</span><span style="background:var(--vt-palette-7)"> </span>2020 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">16</span><span style="background:var(--vt-palette-7)"> </span>
M e2e/testdata/screens/palette-search.html +1 -1
@@ -14,7 +14,7 @@
1414 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">10</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> Insert <span style="color:var(--vt-palette-3);font-weight:bold">col</span>umns right <span style="color:var(--vt-palette-8)">Insert</span> <span style="color:var(--vt-palette-8)">│</span>1515 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">11</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> Delete rows or <span style="color:var(--vt-palette-3);font-weight:bold">col</span>umns <span style="color:var(--vt-palette-8)">Edit</span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Alt+-</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>1616 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">12</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> Insert rows or <span style="color:var(--vt-palette-3);font-weight:bold">col</span>umns <span style="color:var(--vt-palette-8)">Insert</span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Alt+=</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>17-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">13</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">└──────────────────────────────────────────────────────</span> <span style="color:var(--vt-palette-8)">15</span> <span style="color:var(--vt-palette-8)">of</span> <span style="color:var(--vt-palette-8)">100</span> <span style="color:var(--vt-palette-8)">─┘</span>17+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">13</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">└──────────────────────────────────────────────────────</span> <span style="color:var(--vt-palette-8)">17</span> <span style="color:var(--vt-palette-8)">of</span> <span style="color:var(--vt-palette-8)">104</span> <span style="color:var(--vt-palette-8)">─┘</span>1818 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">14</span><span style="background:var(--vt-palette-8)"> </span>1919 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">15</span><span style="background:var(--vt-palette-8)"> </span>2020 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">16</span><span style="background:var(--vt-palette-8)"> </span>
M e2e/testdata/screens/palette-wide.html +1 -1
@@ -14,7 +14,7 @@
1414 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">10</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> In<span style="color:var(--vt-palette-3);font-weight:bold">se</span>rt rows be<span style="color:var(--vt-palette-3);font-weight:bold">l</span>ow <span style="color:var(--vt-palette-8)">Insert</span> <span style="color:var(--vt-palette-8)">│</span>1515 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">11</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> Re<span style="color:var(--vt-palette-3);font-weight:bold">se</span>t co<span style="color:var(--vt-palette-3);font-weight:bold">l</span>umn width <span style="color:var(--vt-palette-8)">Format</span> <span style="color:var(--vt-palette-8)">│</span>1616 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">12</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> In<span style="color:var(--vt-palette-3);font-weight:bold">se</span>rt co<span style="color:var(--vt-palette-3);font-weight:bold">l</span>umns right <span style="color:var(--vt-palette-8)">Insert</span> <span style="color:var(--vt-palette-8)">│</span>17-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">13</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">└──────────────────────────────────────────────────────</span> <span style="color:var(--vt-palette-8)">21</span> <span style="color:var(--vt-palette-8)">of</span> <span style="color:var(--vt-palette-8)">100</span> <span style="color:var(--vt-palette-8)">─┘</span>17+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">13</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">└──────────────────────────────────────────────────────</span> <span style="color:var(--vt-palette-8)">21</span> <span style="color:var(--vt-palette-8)">of</span> <span style="color:var(--vt-palette-8)">104</span> <span style="color:var(--vt-palette-8)">─┘</span>1818 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">14</span><span style="background:var(--vt-palette-8)"> </span>1919 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">15</span><span style="background:var(--vt-palette-8)"> </span>2020 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">16</span><span style="background:var(--vt-palette-8)"> </span>
M e2e/testdata/screens/palette.html +3 -3
@@ -12,9 +12,9 @@
1212 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">8</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> Download as XLSX <span style="color:var(--vt-palette-8)">File</span> <span style="color:var(--vt-palette-8)">›</span> <span style="color:var(--vt-palette-8)">Download</span> <span style="color:var(--vt-palette-8)">│</span>1313 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">9</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> Download as SQLite <span style="color:var(--vt-palette-8)">File</span> <span style="color:var(--vt-palette-8)">›</span> <span style="color:var(--vt-palette-8)">Download</span> <span style="color:var(--vt-palette-8)">│</span>1414 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">10</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> Decimal arithmetic <span style="color:var(--vt-palette-8)">File</span> <span style="color:var(--vt-palette-8)">›</span> <span style="color:var(--vt-palette-8)">Settings</span> <span style="color:var(--vt-palette-8)">│</span>15-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">11</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> Quit <span style="color:var(--vt-palette-8)">File</span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Q</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>16-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">12</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> Undo <span style="color:var(--vt-palette-8)">Edit</span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Z</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>17-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">13</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">└─────────────────────────────────────────────────────</span> <span style="color:var(--vt-palette-8)">100</span> <span style="color:var(--vt-palette-8)">of</span> <span style="color:var(--vt-palette-8)">100</span> <span style="color:var(--vt-palette-8)">─┘</span>15+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">11</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> Theme <span style="color:var(--vt-palette-8)">File</span> <span style="color:var(--vt-palette-8)">›</span> <span style="color:var(--vt-palette-8)">Settings</span> <span style="color:var(--vt-palette-8)">│</span>16+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">12</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> JEV API key <span style="color:var(--vt-palette-8)">File</span> <span style="color:var(--vt-palette-8)">›</span> <span style="color:var(--vt-palette-8)">Settings</span> <span style="color:var(--vt-palette-8)">│</span>17+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">13</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">└─────────────────────────────────────────────────────</span> <span style="color:var(--vt-palette-8)">104</span> <span style="color:var(--vt-palette-8)">of</span> <span style="color:var(--vt-palette-8)">104</span> <span style="color:var(--vt-palette-8)">─┘</span>1818 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">14</span><span style="background:var(--vt-palette-8)"> </span>1919 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">15</span><span style="background:var(--vt-palette-8)"> </span>2020 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">16</span><span style="background:var(--vt-palette-8)"> </span>
A e2e/testdata/screens/theme-classic-narrow-menu.html +16 -0
@@ -0,0 +1,16 @@
1+<pre class="screen"><span style="background:#00aaaa"> </span><span style="color:#000000;background:#00aaaa;text-decoration:underline">F</span><span style="color:#000000;background:#00aaaa">ile</span><span style="background:#00aaaa"> </span><span style="background:#1f1fb4"> </span><span style="color:#ffffff;background:#1f1fb4;text-decoration:underline">E</span><span style="color:#ffffff;background:#1f1fb4">dit</span><span style="background:#1f1fb4"> </span><span style="color:#ffffff;background:#1f1fb4;text-decoration:underline">V</span><span style="color:#ffffff;background:#1f1fb4">iew</span><span style="background:#1f1fb4"> </span><span style="color:#ffffff;background:#1f1fb4;text-decoration:underline">I</span><span style="color:#ffffff;background:#1f1fb4">nsert</span><span style="background:#1f1fb4"> </span><span style="color:#ffffff;background:#1f1fb4">F</span><span style="color:#ffffff;background:#1f1fb4;text-decoration:underline">o</span><span style="color:#ffffff;background:#1f1fb4">rmat</span><span style="background:#1f1fb4"> </span><span style="color:#ffffff;background:#1f1fb4;text-decoration:underline">D</span><span style="color:#ffffff;background:#1f1fb4">ata</span><span style="background:#1f1fb4"> </span><span style="color:#ffffff;background:#1f1fb4;text-decoration:underline">H</span><span style="color:#ffffff;background:#1f1fb4">elp</span><span style="background:#1f1fb4"> </span><span style="background:#00aaaa"> </span><span style="color:#000000;background:#00aaaa;font-weight:bold">MENU</span><span style="background:#00aaaa"> </span>2+<span style="color:#787878;background:#0000aa">┌─────────────────────┐</span><span style="background:#0000aa"> </span>3+<span style="color:#787878;background:#0000aa">│</span><span style="background:#0000aa"> </span><span style="color:#ffffff;background:#0000aa">New</span><span style="background:#0000aa"> </span><span style="color:#787878;background:#0000aa">│</span><span style="background:#0000aa"> </span>4+<span style="color:#787878;background:#0000aa">│</span><span style="background:#0000aa"> </span><span style="color:#ffffff;background:#0000aa">Open</span><span style="background:#0000aa"> </span><span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">Ctrl+O</span><span style="background:#555555"> </span><span style="background:#0000aa"> </span><span style="color:#787878;background:#0000aa">│</span><span style="background:#00aaaa"> </span><span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">C</span><span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">D</span><span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">E</span><span style="background:#555555"> </span>5+<span style="color:#787878;background:#0000aa">│</span><span style="background:#0000aa"> </span><span style="color:#ffffff;background:#0000aa">Import</span><span style="background:#0000aa"> </span><span style="color:#787878;background:#0000aa">│</span><span style="background:#0000aa"> </span><span style="color:#ffffff;background:#0000aa">2026</span><span style="background:#0000aa"> </span>6+<span style="color:#787878;background:#0000aa">├─────────────────────┤</span><span style="background:#0000aa"> </span>7+<span style="color:#787878;background:#0000aa">│</span><span style="background:#00aaaa"> </span><span style="color:#000000;background:#00aaaa">Save</span><span style="background:#00aaaa"> </span><span style="color:#000000;background:#00aaaa">Ctrl+S</span><span style="background:#00aaaa"> </span><span style="color:#787878;background:#0000aa">│</span><span style="color:#ffffff;background:#0000aa">50</span><span style="background:#0000aa"> </span>8+<span style="color:#787878;background:#0000aa">│</span><span style="background:#0000aa"> </span><span style="color:#ffffff;background:#0000aa">Save</span><span style="background:#0000aa"> </span><span style="color:#ffffff;background:#0000aa">as</span><span style="background:#0000aa"> </span><span style="color:#787878;background:#0000aa">│</span><span style="color:#ffffff;background:#0000aa">.4</span><span style="background:#0000aa"> </span>9+<span style="color:#787878;background:#0000aa">│</span><span style="background:#0000aa"> </span><span style="color:#ffffff;background:#0000aa">Download</span><span style="background:#0000aa"> </span><span style="color:#ffffff;background:#0000aa">›</span><span style="background:#0000aa"> </span><span style="color:#787878;background:#0000aa">│</span><span style="color:#ffffff;background:#0000aa">96</span><span style="background:#0000aa"> </span>10+<span style="color:#787878;background:#0000aa">├─────────────────────┤</span><span style="color:#d47f7f;background:#0000aa;text-decoration:underline wavy #aa0000">!</span><span style="background:#0000aa"> </span>11+<span style="color:#787878;background:#0000aa">│</span><span style="background:#0000aa"> </span><span style="color:#ffffff;background:#0000aa">Settings</span><span style="background:#0000aa"> </span><span style="color:#ffffff;background:#0000aa">›</span><span style="background:#0000aa"> </span><span style="color:#787878;background:#0000aa">│</span><span style="color:#000000;background:#00aaaa">.4</span><span style="background:#00aaaa"> </span><span style="background:#0000aa"> </span>12+<span style="color:#787878;background:#0000aa">├─────────────────────┤</span><span style="background:#0000aa"> </span>13+<span style="color:#787878;background:#0000aa">│</span><span style="background:#0000aa"> </span><span style="color:#ffffff;background:#0000aa">Quit</span><span style="background:#0000aa"> </span><span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">Ctrl+Q</span><span style="background:#555555"> </span><span style="background:#0000aa"> </span><span style="color:#787878;background:#0000aa">│</span><span style="background:#0000aa"> </span>14+<span style="color:#787878;background:#0000aa">└─────────────────────┘</span><span style="background:#0000aa"> </span>15+<span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">11</span><span style="background:#555555"> </span><span style="background:#0000aa"> </span>16+<span style="color:#ffffff;background:#1f1fb4">Save</span><span style="background:#1f1fb4"> </span><span style="color:#ffffff;background:#1f1fb4">the</span><span style="background:#1f1fb4"> </span><span style="color:#ffffff;background:#1f1fb4">sheet</span><span style="background:#1f1fb4"> </span><span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">Arrows</span><span style="background:#555555"> </span><span style="background:#1f1fb4"> </span><span style="color:#787878;background:#1f1fb4">move</span><span style="background:#1f1fb4"> </span><span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">Enter</span><span style="background:#555555"> </span><span style="background:#1f1fb4"> </span><span style="color:#787878;background:#1f1fb4">choose</span><span style="background:#1f1fb4"> </span><span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">Esc</span><span style="background:#555555"> </span><span style="background:#1f1fb4"> </span><span style="color:#787878;background:#1f1fb4">close</span></pre>\ No newline at end of file
A e2e/testdata/screens/theme-classic.html +30 -0
@@ -0,0 +1,30 @@
1+<pre class="screen"><span style="background:#1f1fb4"> </span><span style="color:#ffffff;background:#1f1fb4;text-decoration:underline">F</span><span style="color:#ffffff;background:#1f1fb4">ile</span><span style="background:#1f1fb4"> </span><span style="color:#ffffff;background:#1f1fb4;text-decoration:underline">E</span><span style="color:#ffffff;background:#1f1fb4">dit</span><span style="background:#1f1fb4"> </span><span style="color:#ffffff;background:#1f1fb4;text-decoration:underline">V</span><span style="color:#ffffff;background:#1f1fb4">iew</span><span style="background:#1f1fb4"> </span><span style="color:#ffffff;background:#1f1fb4;text-decoration:underline">I</span><span style="color:#ffffff;background:#1f1fb4">nsert</span><span style="background:#1f1fb4"> </span><span style="color:#ffffff;background:#1f1fb4">F</span><span style="color:#ffffff;background:#1f1fb4;text-decoration:underline">o</span><span style="color:#ffffff;background:#1f1fb4">rmat</span><span style="background:#1f1fb4"> </span><span style="color:#ffffff;background:#1f1fb4;text-decoration:underline">D</span><span style="color:#ffffff;background:#1f1fb4">ata</span><span style="background:#1f1fb4"> </span><span style="color:#ffffff;background:#1f1fb4;text-decoration:underline">H</span><span style="color:#ffffff;background:#1f1fb4">elp</span><span style="background:#1f1fb4"> </span><span style="background:#00aaaa"> </span><span style="color:#000000;background:#00aaaa;font-weight:bold">READY</span><span style="background:#00aaaa"> </span>2+<span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">B3:B5</span><span style="background:#555555"> </span><span style="background:#0000aa"> </span><span style="color:#ffffff;background:#0000aa">1450</span><span style="background:#0000aa"> </span>3+<span style="background:#0000aa"> </span>4+<span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">A</span><span style="background:#555555"> </span><span style="background:#00aaaa"> </span><span style="color:#000000;background:#00aaaa;font-weight:bold">B</span><span style="background:#00aaaa"> </span><span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">C</span><span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">D</span><span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">E</span><span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">F</span><span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">G</span><span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">H</span><span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">I</span><span style="background:#555555"> </span>5+<span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">1</span><span style="background:#555555"> </span><span style="background:#0000aa"> </span><span style="color:#ffffff;background:#0000aa">Household</span><span style="background:#0000aa"> </span><span style="color:#ffffff;background:#0000aa">budget</span><span style="background:#0000aa"> </span><span style="color:#ffffff;background:#0000aa">2026</span><span style="background:#0000aa"> </span>6+<span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">2</span><span style="background:#555555"> </span><span style="background:#0000aa"> </span>7+<span style="background:#00aaaa"> </span><span style="color:#000000;background:#00aaaa;font-weight:bold">3</span><span style="background:#00aaaa"> </span><span style="background:#0000aa"> </span><span style="color:#ffffff;background:#0000aa">Rent</span><span style="background:#0000aa"> </span><span style="background:#00aaaa"> </span><span style="color:#000000;background:#00aaaa">1450</span><span style="background:#00aaaa"> </span><span style="background:#0000aa"> </span>8+<span style="background:#00aaaa"> </span><span style="color:#0000aa;background:#00aaaa">4</span><span style="background:#00aaaa"> </span><span style="background:#0000aa"> </span><span style="color:#ffffff;background:#0000aa">Groceries</span><span style="background:#00aaaa"> </span><span style="color:#0000aa;background:#00aaaa">612.4</span><span style="background:#00aaaa"> </span><span style="background:#0000aa"> </span>9+<span style="background:#00aaaa"> </span><span style="color:#0000aa;background:#00aaaa">5</span><span style="background:#00aaaa"> </span><span style="background:#0000aa"> </span><span style="color:#ffffff;background:#0000aa">Transit</span><span style="background:#0000aa"> </span><span style="background:#00aaaa"> </span><span style="color:#0000aa;background:#00aaaa">96</span><span style="background:#00aaaa"> </span><span style="background:#0000aa"> </span>10+<span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">6</span><span style="background:#555555"> </span><span style="background:#0000aa"> </span><span style="color:#ffffff;background:#0000aa">Savings</span><span style="background:#0000aa"> </span><span style="color:#ffffff;background:#0000aa">r</span><span style="background:#0000aa"> </span><span style="color:#d47f7f;background:#0000aa;text-decoration:underline wavy #aa0000">#DIV/0!</span><span style="background:#0000aa"> </span>11+<span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">7</span><span style="background:#555555"> </span><span style="background:#0000aa"> </span><span style="color:#ffffff;background:#0000aa">Total</span><span style="background:#0000aa"> </span><span style="color:#ffffff;background:#0000aa">2158.4</span><span style="background:#0000aa"> </span>12+<span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">8</span><span style="background:#555555"> </span><span style="background:#0000aa"> </span>13+<span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">9</span><span style="background:#555555"> </span><span style="background:#0000aa"> </span>14+<span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">10</span><span style="background:#555555"> </span><span style="background:#0000aa"> </span>15+<span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">11</span><span style="background:#555555"> </span><span style="background:#0000aa"> </span>16+<span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">12</span><span style="background:#555555"> </span><span style="background:#0000aa"> </span>17+<span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">13</span><span style="background:#555555"> </span><span style="background:#0000aa"> </span>18+<span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">14</span><span style="background:#555555"> </span><span style="background:#0000aa"> </span>19+<span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">15</span><span style="background:#555555"> </span><span style="background:#0000aa"> </span>20+<span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">16</span><span style="background:#555555"> </span><span style="background:#0000aa"> </span>21+<span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">17</span><span style="background:#555555"> </span><span style="background:#0000aa"> </span>22+<span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">18</span><span style="background:#555555"> </span><span style="background:#0000aa"> </span>23+<span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">19</span><span style="background:#555555"> </span><span style="background:#0000aa"> </span>24+<span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">20</span><span style="background:#555555"> </span><span style="background:#0000aa"> </span>25+<span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">21</span><span style="background:#555555"> </span><span style="background:#0000aa"> </span>26+<span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">22</span><span style="background:#555555"> </span><span style="background:#0000aa"> </span>27+<span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">23</span><span style="background:#555555"> </span><span style="background:#0000aa"> </span>28+<span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">24</span><span style="background:#555555"> </span><span style="background:#0000aa"> </span>29+<span style="background:#555555"> </span><span style="color:#ffffff;background:#555555">25</span><span style="background:#555555"> </span><span style="background:#0000aa"> </span>30+<span style="background:#00aaaa"> </span><span style="color:#000000;background:#00aaaa;font-weight:bold">Sheet1</span><span style="background:#00aaaa"> </span><span style="background:#1f1fb4"> </span><span style="color:#787878;background:#1f1fb4">+</span><span style="background:#1f1fb4"> </span><span style="color:#787878;background:#1f1fb4">│</span><span style="background:#1f1fb4"> </span><span style="color:#ffffff;background:#1f1fb4">untitled</span><span style="background:#1f1fb4"> </span><span style="color:#787878;background:#1f1fb4">modified</span><span style="background:#1f1fb4"> </span><span style="color:#ffffff;background:#1f1fb4;font-weight:bold">B3:B5</span><span style="background:#1f1fb4"> </span><span style="color:#787878;background:#1f1fb4">Sum</span><span style="background:#1f1fb4"> </span><span style="color:#ffffff;background:#1f1fb4">2158.4</span><span style="background:#1f1fb4"> </span><span style="color:#787878;background:#1f1fb4">Avg</span><span style="background:#1f1fb4"> </span><span style="color:#ffffff;background:#1f1fb4">719.47</span><span style="background:#1f1fb4"> </span><span style="color:#787878;background:#1f1fb4">Count</span><span style="background:#1f1fb4"> </span><span style="color:#ffffff;background:#1f1fb4">3</span></pre>\ No newline at end of file
A e2e/testdata/screens/theme-dark.html +30 -0
@@ -0,0 +1,30 @@
1+<pre class="screen"><span style="background:#262631"> </span><span style="color:#888ca5;background:#262631;text-decoration:underline">F</span><span style="color:#888ca5;background:#262631">ile</span><span style="background:#262631"> </span><span style="color:#888ca5;background:#262631;text-decoration:underline">E</span><span style="color:#888ca5;background:#262631">dit</span><span style="background:#262631"> </span><span style="color:#888ca5;background:#262631;text-decoration:underline">V</span><span style="color:#888ca5;background:#262631">iew</span><span style="background:#262631"> </span><span style="color:#888ca5;background:#262631;text-decoration:underline">I</span><span style="color:#888ca5;background:#262631">nsert</span><span style="background:#262631"> </span><span style="color:#888ca5;background:#262631">F</span><span style="color:#888ca5;background:#262631;text-decoration:underline">o</span><span style="color:#888ca5;background:#262631">rmat</span><span style="background:#262631"> </span><span style="color:#888ca5;background:#262631;text-decoration:underline">D</span><span style="color:#888ca5;background:#262631">ata</span><span style="background:#262631"> </span><span style="color:#888ca5;background:#262631;text-decoration:underline">H</span><span style="color:#888ca5;background:#262631">elp</span><span style="background:#262631"> </span><span style="background:#7dcfff"> </span><span style="color:#363b54;background:#7dcfff;font-weight:bold">READY</span><span style="background:#7dcfff"> </span>2+<span style="background:#363b54"> </span><span style="color:#acb0d0;background:#363b54">A7:D7</span><span style="background:#363b54"> </span><span style="background:#16161e"> </span><span style="color:#7a7e9a;background:#16161e">Total</span><span style="background:#16161e"> </span>3+<span style="color:#7a7e9a;background:#16161e">Bold</span><span style="background:#16161e"> </span><span style="color:#7a7e9a;background:#16161e">on</span><span style="background:#16161e"> </span><span style="color:#7a7e9a;background:#16161e">for</span><span style="background:#16161e"> </span><span style="color:#7a7e9a;background:#16161e">A7:D7</span><span style="background:#16161e"> </span>4+<span style="background:#363b54"> </span><span style="background:#7dcfff"> </span><span style="color:#363b54;background:#7dcfff;font-weight:bold">A</span><span style="background:#7dcfff"> </span><span style="background:#7aa2f7"> </span><span style="color:#343951;background:#7aa2f7">B</span><span style="background:#7aa2f7"> </span><span style="color:#343951;background:#7aa2f7">C</span><span style="background:#7aa2f7"> </span><span style="color:#343951;background:#7aa2f7">D</span><span style="background:#7aa2f7"> </span><span style="background:#363b54"> </span><span style="color:#acb0d0;background:#363b54">E</span><span style="background:#363b54"> </span><span style="color:#acb0d0;background:#363b54">F</span><span style="background:#363b54"> </span><span style="color:#acb0d0;background:#363b54">G</span><span style="background:#363b54"> </span><span style="color:#acb0d0;background:#363b54">H</span><span style="background:#363b54"> </span><span style="color:#acb0d0;background:#363b54">I</span><span style="background:#363b54"> </span>5+<span style="background:#363b54"> </span><span style="color:#acb0d0;background:#363b54">1</span><span style="background:#363b54"> </span><span style="background:#16161e"> </span><span style="color:#7a7e9a;background:#16161e;font-weight:bold">Bills</span><span style="background:#16161e"> </span><span style="color:#7a7e9a;background:#16161e;font-weight:bold">for</span><span style="background:#16161e"> </span><span style="color:#7a7e9a;background:#16161e;font-weight:bold">October</span><span style="background:#16161e"> </span>6+<span style="background:#363b54"> </span><span style="color:#acb0d0;background:#363b54">2</span><span style="background:#363b54"> </span><span style="background:#16161e"> </span><span style="color:#7a7e9a;background:#16161e;font-weight:bold">Item</span><span style="background:#16161e"> </span><span style="color:#7a7e9a;background:#16161e;font-weight:bold">Due</span><span style="background:#16161e"> </span><span style="color:#7a7e9a;background:#16161e;font-weight:bold">Amount</span><span style="background:#16161e"> </span><span style="color:#7a7e9a;background:#16161e;font-weight:bold">Share</span><span style="background:#16161e"> </span>7+<span style="background:#363b54"> </span><span style="color:#acb0d0;background:#363b54">3</span><span style="background:#363b54"> </span><span style="background:#16161e"> </span><span style="color:#7a7e9a;background:#16161e">Rent</span><span style="background:#16161e"> </span><span style="color:#7a7e9a;background:#16161e">10/1/2026</span><span style="background:#16161e"> </span><span style="color:#7a7e9a;background:#16161e">$1,450.00</span><span style="background:#16161e"> </span><span style="color:#7a7e9a;background:#16161e">65.96%</span><span style="background:#16161e"> </span>8+<span style="background:#363b54"> </span><span style="color:#acb0d0;background:#363b54">4</span><span style="background:#363b54"> </span><span style="background:#16161e"> </span><span style="color:#7a7e9a;background:#16161e">Food</span><span style="background:#16161e"> </span><span style="color:#7a7e9a;background:#16161e">9/28/2026</span><span style="background:#16161e"> </span><span style="color:#7a7e9a;background:#16161e">$612.40</span><span style="background:#16161e"> </span><span style="color:#7a7e9a;background:#16161e">27.86%</span><span style="background:#16161e"> </span>9+<span style="background:#363b54"> </span><span style="color:#acb0d0;background:#363b54">5</span><span style="background:#363b54"> </span><span style="background:#16161e"> </span><span style="color:#7a7e9a;background:#16161e">Transit</span><span style="background:#16161e"> </span><span style="color:#7a7e9a;background:#16161e">9/30/2026</span><span style="background:#16161e"> </span><span style="color:#7a7e9a;background:#16161e">$96.00</span><span style="background:#16161e"> </span><span style="color:#7a7e9a;background:#16161e">4.37%</span><span style="background:#16161e"> </span>10+<span style="background:#363b54"> </span><span style="color:#acb0d0;background:#363b54">6</span><span style="background:#363b54"> </span><span style="background:#16161e"> </span><span style="color:#7a7e9a;background:#16161e;text-decoration:line-through">Gym</span><span style="background:#16161e"> </span><span style="color:#7a7e9a;background:#16161e;text-decoration:line-through">10/5/2026</span><span style="background:#16161e"> </span><span style="color:#7a7e9a;background:#16161e;text-decoration:line-through">$40.00</span><span style="background:#16161e"> </span><span style="color:#7a7e9a;background:#16161e;text-decoration:line-through">1.82%</span><span style="background:#16161e"> </span>11+<span style="background:#7dcfff"> </span><span style="color:#363b54;background:#7dcfff;font-weight:bold">7</span><span style="background:#7dcfff"> </span><span style="color:#363b54;background:#7dcfff;font-weight:bold">Total</span><span style="background:#7dcfff"> </span><span style="background:#7aa2f7"> </span><span style="color:#343951;background:#7aa2f7;font-weight:bold">$2,198.40</span><span style="background:#7aa2f7"> </span><span style="color:#343951;background:#7aa2f7;font-weight:bold">100.00%</span><span style="background:#7aa2f7"> </span><span style="background:#16161e"> </span>12+<span style="background:#363b54"> </span><span style="color:#acb0d0;background:#363b54">8</span><span style="background:#363b54"> </span><span style="background:#16161e"> </span>13+<span style="background:#363b54"> </span><span style="color:#acb0d0;background:#363b54">9</span><span style="background:#363b54"> </span><span style="background:#16161e"> </span><span style="color:#7a7e9a;background:#16161e;font-style:italic">Gym</span><span style="background:#16161e"> </span><span style="color:#7a7e9a;background:#16161e;font-style:italic">cancelled</span><span style="background:#16161e"> </span><span style="color:#7a7e9a;background:#16161e;font-style:italic">from</span><span style="background:#16161e"> </span><span style="color:#7a7e9a;background:#16161e;font-style:italic">November</span><span style="background:#16161e"> </span>14+<span style="background:#363b54"> </span><span style="color:#acb0d0;background:#363b54">10</span><span style="background:#363b54"> </span><span style="background:#16161e"> </span>15+<span style="background:#363b54"> </span><span style="color:#acb0d0;background:#363b54">11</span><span style="background:#363b54"> </span><span style="background:#16161e"> </span>16+<span style="background:#363b54"> </span><span style="color:#acb0d0;background:#363b54">12</span><span style="background:#363b54"> </span><span style="background:#16161e"> </span>17+<span style="background:#363b54"> </span><span style="color:#acb0d0;background:#363b54">13</span><span style="background:#363b54"> </span><span style="background:#16161e"> </span>18+<span style="background:#363b54"> </span><span style="color:#acb0d0;background:#363b54">14</span><span style="background:#363b54"> </span><span style="background:#16161e"> </span>19+<span style="background:#363b54"> </span><span style="color:#acb0d0;background:#363b54">15</span><span style="background:#363b54"> </span><span style="background:#16161e"> </span>20+<span style="background:#363b54"> </span><span style="color:#acb0d0;background:#363b54">16</span><span style="background:#363b54"> </span><span style="background:#16161e"> </span>21+<span style="background:#363b54"> </span><span style="color:#acb0d0;background:#363b54">17</span><span style="background:#363b54"> </span><span style="background:#16161e"> </span>22+<span style="background:#363b54"> </span><span style="color:#acb0d0;background:#363b54">18</span><span style="background:#363b54"> </span><span style="background:#16161e"> </span>23+<span style="background:#363b54"> </span><span style="color:#acb0d0;background:#363b54">19</span><span style="background:#363b54"> </span><span style="background:#16161e"> </span>24+<span style="background:#363b54"> </span><span style="color:#acb0d0;background:#363b54">20</span><span style="background:#363b54"> </span><span style="background:#16161e"> </span>25+<span style="background:#363b54"> </span><span style="color:#acb0d0;background:#363b54">21</span><span style="background:#363b54"> </span><span style="background:#16161e"> </span>26+<span style="background:#363b54"> </span><span style="color:#acb0d0;background:#363b54">22</span><span style="background:#363b54"> </span><span style="background:#16161e"> </span>27+<span style="background:#363b54"> </span><span style="color:#acb0d0;background:#363b54">23</span><span style="background:#363b54"> </span><span style="background:#16161e"> </span>28+<span style="background:#363b54"> </span><span style="color:#acb0d0;background:#363b54">24</span><span style="background:#363b54"> </span><span style="background:#16161e"> </span>29+<span style="background:#363b54"> </span><span style="color:#acb0d0;background:#363b54">25</span><span style="background:#363b54"> </span><span style="background:#16161e"> </span>30+<span style="background:#7dcfff"> </span><span style="color:#363b54;background:#7dcfff;font-weight:bold">Sheet1</span><span style="background:#7dcfff"> </span><span style="background:#262631"> </span><span style="color:#5d627c;background:#262631">+</span><span style="background:#262631"> </span><span style="color:#5d627c;background:#262631">│</span><span style="background:#262631"> </span><span style="color:#888ca5;background:#262631">untitled</span><span style="background:#262631"> </span><span style="color:#5d627c;background:#262631">modified</span><span style="background:#262631"> </span><span style="color:#888ca5;background:#262631;font-weight:bold">A7:D7</span><span style="background:#262631"> </span><span style="color:#5d627c;background:#262631">Sum</span><span style="background:#262631"> </span><span style="color:#888ca5;background:#262631">2199.4</span><span style="background:#262631"> </span><span style="color:#5d627c;background:#262631">Avg</span><span style="background:#262631"> </span><span style="color:#888ca5;background:#262631">1099.7</span><span style="background:#262631"> </span><span style="color:#5d627c;background:#262631">Count</span><span style="background:#262631"> </span><span style="color:#888ca5;background:#262631">3</span></pre>\ No newline at end of file
A e2e/testdata/screens/theme-light-menu.html +30 -0
@@ -0,0 +1,30 @@
1+<pre class="screen"><span style="background:#179299"> </span><span style="color:#1c1c24;background:#179299;text-decoration:underline">F</span><span style="color:#1c1c24;background:#179299">ile</span><span style="background:#179299"> </span><span style="background:#dadde4"> </span><span style="color:#4c4f69;background:#dadde4;text-decoration:underline">E</span><span style="color:#4c4f69;background:#dadde4">dit</span><span style="background:#dadde4"> </span><span style="color:#4c4f69;background:#dadde4;text-decoration:underline">V</span><span style="color:#4c4f69;background:#dadde4">iew</span><span style="background:#dadde4"> </span><span style="color:#4c4f69;background:#dadde4;text-decoration:underline">I</span><span style="color:#4c4f69;background:#dadde4">nsert</span><span style="background:#dadde4"> </span><span style="color:#4c4f69;background:#dadde4">F</span><span style="color:#4c4f69;background:#dadde4;text-decoration:underline">o</span><span style="color:#4c4f69;background:#dadde4">rmat</span><span style="background:#dadde4"> </span><span style="color:#4c4f69;background:#dadde4;text-decoration:underline">D</span><span style="color:#4c4f69;background:#dadde4">ata</span><span style="background:#dadde4"> </span><span style="color:#4c4f69;background:#dadde4;text-decoration:underline">H</span><span style="color:#4c4f69;background:#dadde4">elp</span><span style="background:#dadde4"> </span><span style="background:#179299"> </span><span style="color:#1c1c24;background:#179299;font-weight:bold">MENU</span><span style="background:#179299"> </span>2+<span style="color:#6c6f85;background:#eff1f5">┌─────────────────────┐</span><span style="background:#eff1f5"> </span>3+<span style="color:#6c6f85;background:#eff1f5">│</span><span style="background:#eff1f5"> </span><span style="color:#4c4f69;background:#eff1f5">New</span><span style="background:#eff1f5"> </span><span style="color:#6c6f85;background:#eff1f5">│</span><span style="background:#eff1f5"> </span>4+<span style="color:#6c6f85;background:#eff1f5">│</span><span style="background:#eff1f5"> </span><span style="color:#4c4f69;background:#eff1f5">Open</span><span style="background:#eff1f5"> </span><span style="background:#acb0be"> </span><span style="color:#414354;background:#acb0be">Ctrl+O</span><span style="background:#acb0be"> </span><span style="background:#eff1f5"> </span><span style="color:#6c6f85;background:#eff1f5">│</span><span style="background:#179299"> </span><span style="background:#acb0be"> </span><span style="color:#414354;background:#acb0be">C</span><span style="background:#acb0be"> </span><span style="color:#414354;background:#acb0be">D</span><span style="background:#acb0be"> </span><span style="color:#414354;background:#acb0be">E</span><span style="background:#acb0be"> </span><span style="color:#414354;background:#acb0be">F</span><span style="background:#acb0be"> </span><span style="color:#414354;background:#acb0be">G</span><span style="background:#acb0be"> </span><span style="color:#414354;background:#acb0be">H</span><span style="background:#acb0be"> </span><span style="color:#414354;background:#acb0be">I</span><span style="background:#acb0be"> </span>5+<span style="color:#6c6f85;background:#eff1f5">│</span><span style="background:#eff1f5"> </span><span style="color:#4c4f69;background:#eff1f5">Import</span><span style="background:#eff1f5"> </span><span style="color:#6c6f85;background:#eff1f5">│</span><span style="background:#eff1f5"> </span><span style="color:#4c4f69;background:#eff1f5">2026</span><span style="background:#eff1f5"> </span>6+<span style="color:#6c6f85;background:#eff1f5">├─────────────────────┤</span><span style="background:#eff1f5"> </span>7+<span style="color:#6c6f85;background:#eff1f5">│</span><span style="background:#179299"> </span><span style="color:#1c1c24;background:#179299">Save</span><span style="background:#179299"> </span><span style="color:#1c1c24;background:#179299">Ctrl+S</span><span style="background:#179299"> </span><span style="color:#6c6f85;background:#eff1f5">│</span><span style="color:#4c4f69;background:#eff1f5">50</span><span style="background:#eff1f5"> </span>8+<span style="color:#6c6f85;background:#eff1f5">│</span><span style="background:#eff1f5"> </span><span style="color:#4c4f69;background:#eff1f5">Save</span><span style="background:#eff1f5"> </span><span style="color:#4c4f69;background:#eff1f5">as</span><span style="background:#eff1f5"> </span><span style="color:#6c6f85;background:#eff1f5">│</span><span style="color:#4c4f69;background:#eff1f5">.4</span><span style="background:#eff1f5"> </span>9+<span style="color:#6c6f85;background:#eff1f5">│</span><span style="background:#eff1f5"> </span><span style="color:#4c4f69;background:#eff1f5">Download</span><span style="background:#eff1f5"> </span><span style="color:#4c4f69;background:#eff1f5">›</span><span style="background:#eff1f5"> </span><span style="color:#6c6f85;background:#eff1f5">│</span><span style="color:#4c4f69;background:#eff1f5">96</span><span style="background:#eff1f5"> </span>10+<span style="color:#6c6f85;background:#eff1f5">├─────────────────────┤</span><span style="color:#d20f39;background:#eff1f5;text-decoration:underline wavy #d20f39">!</span><span style="background:#eff1f5"> </span>11+<span style="color:#6c6f85;background:#eff1f5">│</span><span style="background:#eff1f5"> </span><span style="color:#4c4f69;background:#eff1f5">Settings</span><span style="background:#eff1f5"> </span><span style="color:#4c4f69;background:#eff1f5">›</span><span style="background:#eff1f5"> </span><span style="color:#6c6f85;background:#eff1f5">│</span><span style="color:#1c1c24;background:#179299">.4</span><span style="background:#179299"> </span><span style="background:#eff1f5"> </span>12+<span style="color:#6c6f85;background:#eff1f5">├─────────────────────┤</span><span style="background:#eff1f5"> </span>13+<span style="color:#6c6f85;background:#eff1f5">│</span><span style="background:#eff1f5"> </span><span style="color:#4c4f69;background:#eff1f5">Quit</span><span style="background:#eff1f5"> </span><span style="background:#acb0be"> </span><span style="color:#414354;background:#acb0be">Ctrl+Q</span><span style="background:#acb0be"> </span><span style="background:#eff1f5"> </span><span style="color:#6c6f85;background:#eff1f5">│</span><span style="background:#eff1f5"> </span>14+<span style="color:#6c6f85;background:#eff1f5">└─────────────────────┘</span><span style="background:#eff1f5"> </span>15+<span style="background:#acb0be"> </span><span style="color:#414354;background:#acb0be">11</span><span style="background:#acb0be"> </span><span style="background:#eff1f5"> </span>16+<span style="background:#acb0be"> </span><span style="color:#414354;background:#acb0be">12</span><span style="background:#acb0be"> </span><span style="background:#eff1f5"> </span>17+<span style="background:#acb0be"> </span><span style="color:#414354;background:#acb0be">13</span><span style="background:#acb0be"> </span><span style="background:#eff1f5"> </span>18+<span style="background:#acb0be"> </span><span style="color:#414354;background:#acb0be">14</span><span style="background:#acb0be"> </span><span style="background:#eff1f5"> </span>19+<span style="background:#acb0be"> </span><span style="color:#414354;background:#acb0be">15</span><span style="background:#acb0be"> </span><span style="background:#eff1f5"> </span>20+<span style="background:#acb0be"> </span><span style="color:#414354;background:#acb0be">16</span><span style="background:#acb0be"> </span><span style="background:#eff1f5"> </span>21+<span style="background:#acb0be"> </span><span style="color:#414354;background:#acb0be">17</span><span style="background:#acb0be"> </span><span style="background:#eff1f5"> </span>22+<span style="background:#acb0be"> </span><span style="color:#414354;background:#acb0be">18</span><span style="background:#acb0be"> </span><span style="background:#eff1f5"> </span>23+<span style="background:#acb0be"> </span><span style="color:#414354;background:#acb0be">19</span><span style="background:#acb0be"> </span><span style="background:#eff1f5"> </span>24+<span style="background:#acb0be"> </span><span style="color:#414354;background:#acb0be">20</span><span style="background:#acb0be"> </span><span style="background:#eff1f5"> </span>25+<span style="background:#acb0be"> </span><span style="color:#414354;background:#acb0be">21</span><span style="background:#acb0be"> </span><span style="background:#eff1f5"> </span>26+<span style="background:#acb0be"> </span><span style="color:#414354;background:#acb0be">22</span><span style="background:#acb0be"> </span><span style="background:#eff1f5"> </span>27+<span style="background:#acb0be"> </span><span style="color:#414354;background:#acb0be">23</span><span style="background:#acb0be"> </span><span style="background:#eff1f5"> </span>28+<span style="background:#acb0be"> </span><span style="color:#414354;background:#acb0be">24</span><span style="background:#acb0be"> </span><span style="background:#eff1f5"> </span>29+<span style="background:#acb0be"> </span><span style="color:#414354;background:#acb0be">25</span><span style="background:#acb0be"> </span><span style="background:#eff1f5"> </span>30+<span style="color:#4c4f69;background:#dadde4">Save</span><span style="background:#dadde4"> </span><span style="color:#4c4f69;background:#dadde4">the</span><span style="background:#dadde4"> </span><span style="color:#4c4f69;background:#dadde4">sheet</span><span style="background:#dadde4"> </span><span style="background:#acb0be"> </span><span style="color:#414354;background:#acb0be">Arrows</span><span style="background:#acb0be"> </span><span style="background:#dadde4"> </span><span style="color:#5c5f77;background:#dadde4">move</span><span style="background:#dadde4"> </span><span style="background:#acb0be"> </span><span style="color:#414354;background:#acb0be">Enter</span><span style="background:#acb0be"> </span><span style="background:#dadde4"> </span><span style="color:#5c5f77;background:#dadde4">choose</span><span style="background:#dadde4"> </span><span style="background:#acb0be"> </span><span style="color:#414354;background:#acb0be">Esc</span><span style="background:#acb0be"> </span><span style="background:#dadde4"> </span><span style="color:#5c5f77;background:#dadde4">close</span></pre>\ No newline at end of file
A e2e/testdata/screens/theme-picker.html +30 -0
@@ -0,0 +1,30 @@
1+<pre class="screen"><span style="background:#3f3d39"> </span><span style="color:#ebdbb2;background:#3f3d39;text-decoration:underline">F</span><span style="color:#ebdbb2;background:#3f3d39">ile</span><span style="background:#3f3d39"> </span><span style="color:#ebdbb2;background:#3f3d39;text-decoration:underline">E</span><span style="color:#ebdbb2;background:#3f3d39">dit</span><span style="background:#3f3d39"> </span><span style="color:#ebdbb2;background:#3f3d39;text-decoration:underline">V</span><span style="color:#ebdbb2;background:#3f3d39">iew</span><span style="background:#3f3d39"> </span><span style="color:#ebdbb2;background:#3f3d39;text-decoration:underline">I</span><span style="color:#ebdbb2;background:#3f3d39">nsert</span><span style="background:#3f3d39"> </span><span style="color:#ebdbb2;background:#3f3d39">F</span><span style="color:#ebdbb2;background:#3f3d39;text-decoration:underline">o</span><span style="color:#ebdbb2;background:#3f3d39">rmat</span><span style="background:#3f3d39"> </span><span style="color:#ebdbb2;background:#3f3d39;text-decoration:underline">D</span><span style="color:#ebdbb2;background:#3f3d39">ata</span><span style="background:#3f3d39"> </span><span style="color:#ebdbb2;background:#3f3d39;text-decoration:underline">H</span><span style="color:#ebdbb2;background:#3f3d39">elp</span><span style="background:#3f3d39"> </span><span style="background:#689d6a"> </span><span style="color:#282828;background:#689d6a;font-weight:bold">MENU</span><span style="background:#689d6a"> </span>2+<span style="background:#928374"> </span><span style="color:#211e19;background:#928374">B7</span><span style="background:#928374"> </span><span style="background:#282828"> </span><span style="color:#ebdbb2;background:#282828">=SUM(B</span><span style="color:#928374;background:#282828">┌─</span><span style="background:#282828"> </span><span style="color:#ebdbb2;background:#282828;font-weight:bold">Theme</span><span style="background:#282828"> </span><span style="color:#928374;background:#282828">──────────────────────────────────────────────────────┐</span><span style="background:#282828"> </span>3+<span style="background:#282828"> </span><span style="color:#928374;background:#282828">│</span><span style="background:#282828"> </span><span style="color:#ebdbb2;background:#282828;font-weight:bold">›</span><span style="background:#282828"> </span><span style="color:#ebdbb2;background:#282828">gruvbox</span><span style="background:#282828"> </span><span style="color:#928374;background:#282828">│</span><span style="background:#282828"> </span>4+<span style="background:#928374"> </span><span style="color:#211e19;background:#928374">A</span><span style="background:#928374"> </span><span style="background:#689d6a"> </span><span style="color:#928374;background:#282828">├──────────────────────────────────────────────────────────────┤</span><span style="background:#928374"> </span><span style="color:#211e19;background:#928374">I</span><span style="background:#928374"> </span>5+<span style="background:#928374"> </span><span style="color:#211e19;background:#928374">1</span><span style="background:#928374"> </span><span style="background:#282828"> </span><span style="color:#ebdbb2;background:#282828">Household</span><span style="background:#282828"> </span><span style="color:#ebdbb2;background:#282828">b</span><span style="color:#928374;background:#282828">│</span><span style="background:#689d6a"> </span><span style="color:#282828;background:#689d6a;font-weight:bold;text-decoration:underline">Gruvbox</span><span style="color:#282828;background:#689d6a">Dark</span><span style="background:#689d6a"> </span><span style="color:#282828;background:#689d6a">dark</span><span style="background:#689d6a"> </span><span style="color:#928374;background:#282828">│</span><span style="background:#282828"> </span>6+<span style="background:#928374"> </span><span style="color:#211e19;background:#928374">2</span><span style="background:#928374"> </span><span style="background:#282828"> </span><span style="color:#928374;background:#282828">│</span><span style="background:#282828"> </span><span style="color:#d79921;background:#282828;font-weight:bold">Gruvbox</span><span style="background:#282828"> </span><span style="color:#ebdbb2;background:#282828">Light</span><span style="background:#282828"> </span><span style="color:#928374;background:#282828">light</span><span style="background:#282828"> </span><span style="color:#928374;background:#282828">│</span><span style="background:#282828"> </span>7+<span style="background:#928374"> </span><span style="color:#211e19;background:#928374">3</span><span style="background:#928374"> </span><span style="background:#282828"> </span><span style="color:#ebdbb2;background:#282828">Rent</span><span style="background:#282828"> </span><span style="color:#928374;background:#282828">│</span><span style="background:#282828"> </span><span style="color:#d79921;background:#282828;font-weight:bold">Gruvbox</span><span style="color:#ebdbb2;background:#282828">DarkHard</span><span style="background:#282828"> </span><span style="color:#928374;background:#282828">dark</span><span style="background:#282828"> </span><span style="color:#928374;background:#282828">│</span><span style="background:#282828"> </span>8+<span style="background:#928374"> </span><span style="color:#211e19;background:#928374">4</span><span style="background:#928374"> </span><span style="background:#282828"> </span><span style="color:#ebdbb2;background:#282828">Groceries</span><span style="background:#282828"> </span><span style="color:#928374;background:#282828">└───────────────────────────────────────────────────</span><span style="background:#282828"> </span><span style="color:#928374;background:#282828">3</span><span style="background:#282828"> </span><span style="color:#928374;background:#282828">of</span><span style="background:#282828"> </span><span style="color:#928374;background:#282828">350</span><span style="background:#282828"> </span><span style="color:#928374;background:#282828">─┘</span><span style="background:#282828"> </span>9+<span style="background:#928374"> </span><span style="color:#211e19;background:#928374">5</span><span style="background:#928374"> </span><span style="background:#282828"> </span><span style="color:#ebdbb2;background:#282828">Transit</span><span style="background:#282828"> </span><span style="color:#ebdbb2;background:#282828">96</span><span style="background:#282828"> </span>10+<span style="background:#928374"> </span><span style="color:#211e19;background:#928374">6</span><span style="background:#928374"> </span><span style="background:#282828"> </span><span style="color:#ebdbb2;background:#282828">Savings</span><span style="background:#282828"> </span><span style="color:#ebdbb2;background:#282828">r</span><span style="background:#282828"> </span><span style="color:#d9705a;background:#282828;text-decoration:underline wavy #cc241d">#DIV/0!</span><span style="background:#282828"> </span>11+<span style="background:#689d6a"> </span><span style="color:#282828;background:#689d6a;font-weight:bold">7</span><span style="background:#689d6a"> </span><span style="background:#282828"> </span><span style="color:#ebdbb2;background:#282828">Total</span><span style="background:#282828"> </span><span style="background:#689d6a"> </span><span style="color:#282828;background:#689d6a">2158.4</span><span style="background:#689d6a"> </span><span style="background:#282828"> </span>12+<span style="background:#928374"> </span><span style="color:#211e19;background:#928374">8</span><span style="background:#928374"> </span><span style="background:#282828"> </span>13+<span style="background:#928374"> </span><span style="color:#211e19;background:#928374">9</span><span style="background:#928374"> </span><span style="background:#282828"> </span>14+<span style="background:#928374"> </span><span style="color:#211e19;background:#928374">10</span><span style="background:#928374"> </span><span style="background:#282828"> </span>15+<span style="background:#928374"> </span><span style="color:#211e19;background:#928374">11</span><span style="background:#928374"> </span><span style="background:#282828"> </span>16+<span style="background:#928374"> </span><span style="color:#211e19;background:#928374">12</span><span style="background:#928374"> </span><span style="background:#282828"> </span>17+<span style="background:#928374"> </span><span style="color:#211e19;background:#928374">13</span><span style="background:#928374"> </span><span style="background:#282828"> </span>18+<span style="background:#928374"> </span><span style="color:#211e19;background:#928374">14</span><span style="background:#928374"> </span><span style="background:#282828"> </span>19+<span style="background:#928374"> </span><span style="color:#211e19;background:#928374">15</span><span style="background:#928374"> </span><span style="background:#282828"> </span>20+<span style="background:#928374"> </span><span style="color:#211e19;background:#928374">16</span><span style="background:#928374"> </span><span style="background:#282828"> </span>21+<span style="background:#928374"> </span><span style="color:#211e19;background:#928374">17</span><span style="background:#928374"> </span><span style="background:#282828"> </span>22+<span style="background:#928374"> </span><span style="color:#211e19;background:#928374">18</span><span style="background:#928374"> </span><span style="background:#282828"> </span>23+<span style="background:#928374"> </span><span style="color:#211e19;background:#928374">19</span><span style="background:#928374"> </span><span style="background:#282828"> </span>24+<span style="background:#928374"> </span><span style="color:#211e19;background:#928374">20</span><span style="background:#928374"> </span><span style="background:#282828"> </span>25+<span style="background:#928374"> </span><span style="color:#211e19;background:#928374">21</span><span style="background:#928374"> </span><span style="background:#282828"> </span>26+<span style="background:#928374"> </span><span style="color:#211e19;background:#928374">22</span><span style="background:#928374"> </span><span style="background:#282828"> </span>27+<span style="background:#928374"> </span><span style="color:#211e19;background:#928374">23</span><span style="background:#928374"> </span><span style="background:#282828"> </span>28+<span style="background:#928374"> </span><span style="color:#211e19;background:#928374">24</span><span style="background:#928374"> </span><span style="background:#282828"> </span>29+<span style="background:#928374"> </span><span style="color:#211e19;background:#928374">25</span><span style="background:#928374"> </span><span style="background:#282828"> </span>30+<span style="color:#ebdbb2;background:#3f3d39">A</span><span style="background:#3f3d39"> </span><span style="color:#ebdbb2;background:#3f3d39">dark</span><span style="background:#3f3d39"> </span><span style="color:#ebdbb2;background:#3f3d39">color</span><span style="background:#3f3d39"> </span><span style="color:#ebdbb2;background:#3f3d39">scheme,</span><span style="background:#3f3d39"> </span><span style="color:#ebdbb2;background:#3f3d39">drawn</span><span style="background:#3f3d39"> </span><span style="color:#ebdbb2;background:#3f3d39">in</span><span style="background:#3f3d39"> </span><span style="color:#ebdbb2;background:#3f3d39">its</span><span style="background:#3f3d39"> </span><span style="color:#ebdbb2;background:#3f3d39">own</span><span style="background:#3f3d39"> </span><span style="color:#ebdbb2;background:#3f3d39">colors</span><span style="background:#3f3d39"> </span><span style="color:#ebdbb2;background:#3f3d39">with</span><span style="background:#3f3d39"> </span><span style="color:#ebdbb2;background:#3f3d39">solid…</span><span style="background:#3f3d39"> </span><span style="background:#928374"> </span><span style="color:#211e19;background:#928374">Up/Down</span><span style="background:#928374"> </span><span style="background:#3f3d39"> </span><span style="color:#928374;background:#3f3d39">move</span><span style="background:#3f3d39"> </span><span style="background:#928374"> </span><span style="color:#211e19;background:#928374">Enter</span><span style="background:#928374"> </span><span style="background:#3f3d39"> </span><span style="color:#928374;background:#3f3d39">keep</span><span style="background:#3f3d39"> </span><span style="background:#928374"> </span><span style="color:#211e19;background:#928374">Esc</span><span style="background:#928374"> </span><span style="background:#3f3d39"> </span><span style="color:#928374;background:#3f3d39">close</span></pre>\ No newline at end of file
M internal/keyring/system_darwin.go +2 -0
A internal/keyring/system_fake.go +64 -0
@@ -0,0 +1,64 @@
1+//go:build fakekeyring2+3+package keyring4+5+import (6+ "context"7+ "errors"8+ "os"9+ "path/filepath"10+ "strings"11+)12+13+// System, in binaries built with -tags fakekeyring (the e2e tests), is a14+// file in $XDG_CONFIG_HOME/012, which the tests point at a temporary15+// directory, so they never reach a real credential store.16+func System() Store { return fileStore{} }17+18+type fileStore struct{}19+20+func (fileStore) path() (string, error) {21+ x := os.Getenv("XDG_CONFIG_HOME")22+ if x == "" {23+ return "", errors.New("the test credential store needs XDG_CONFIG_HOME")24+ }25+ return filepath.Join(x, "012", "test-credential-store"), nil26+}27+28+func (fileStore) Name() string { return "test credential store" }29+30+func (f fileStore) Get(context.Context) (string, error) {31+ p, err := f.path()32+ if err != nil {33+ return "", err34+ }35+ b, err := os.ReadFile(p)36+ if errors.Is(err, os.ErrNotExist) {37+ return "", ErrNotFound38+ }39+ return strings.TrimSpace(string(b)), err40+}41+42+func (f fileStore) Set(_ context.Context, secret string) error {43+ p, err := f.path()44+ if err != nil {45+ return err46+ }47+ if err := os.MkdirAll(filepath.Dir(p), 0o700); err != nil {48+ return err49+ }50+ return os.WriteFile(p, []byte(secret), 0o600)51+}52+53+func (f fileStore) Delete(context.Context) error {54+ p, err := f.path()55+ if err != nil {56+ return err57+ }58+ if err := os.Remove(p); errors.Is(err, os.ErrNotExist) {59+ return ErrNotFound60+ } else if err != nil {61+ return err62+ }63+ return nil64+}
M internal/keyring/system_unix.go +1 -1
M internal/keyring/system_windows.go +2 -0