cat / 012
clone

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

Merge main into the formats track

Dami committed df62969
Reconciles number formats, styles and the function library with the
undo history, clipboard, find, mouse and shell work on main. Formatting
goes through the history's place/change paths, the copy marker layers
on styled cells, format commands appear in the Format menu, and the
e2e scripts account for menu letters that now match several items.
Adds a golden of the Format > Number submenu.
commit
df62969218f07dfd6af3aae1eb519bac7bff4fe8
parent
b4f3e8533868cd9c89d3cd2bcc4a9eace9887ac2
parent
ac12201a300f1e479b73aa75944db9adc0607895
author
Dami <dami.etoile@gmail.com>
98 files changed, +7823 -1345
M.gitignore1+
MREADME.md16+-
Mdocs/UX.md39++-
Me2e/app_test.go134++++++-
Ae2e/clipboard_test.go59+++
Me2e/harness_test.go58+++-
Ae2e/mouse_test.go99++++++
Me2e/render_test.go26+-
Me2e/screens_test.go109++++++-
Ae2e/shell_test.go81+++++
Ae2e/testdata/screens/about.html30++
Me2e/testdata/screens/budget-light.html58++--
Me2e/testdata/screens/budget.html58++--
Me2e/testdata/screens/column-select.html58++--
Ae2e/testdata/screens/context-menu-column-light.html30++
Ae2e/testdata/screens/context-menu-column.html30++
Ae2e/testdata/screens/context-menu.html30++
Ae2e/testdata/screens/copy-marker-light.html30++
Ae2e/testdata/screens/copy-marker-selected-light.html30++
Ae2e/testdata/screens/copy-marker-selected.html30++
Ae2e/testdata/screens/copy-marker.html30++
Me2e/testdata/screens/edit-error.html60++--
Me2e/testdata/screens/entry-formula.html60++--
Me2e/testdata/screens/error-goto.html58++--
Me2e/testdata/screens/formats-light.html60++--
Me2e/testdata/screens/formats-narrow.html32+-
Me2e/testdata/screens/formats.html60++--
Ae2e/testdata/screens/functions-light.html30++
Ae2e/testdata/screens/functions.html30++
Me2e/testdata/screens/help-light.html60++--
Ae2e/testdata/screens/help-narrow.html16+
Ae2e/testdata/screens/help-wide.html45+++
Me2e/testdata/screens/help.html60++--
Ae2e/testdata/screens/hover-resize-handle.html30++
Ae2e/testdata/screens/menu-format-number-light.html30++
Ae2e/testdata/screens/menu-format-number.html30++
Ae2e/testdata/screens/menu-light.html30++
Ae2e/testdata/screens/menu-narrow.html16+
Me2e/testdata/screens/menu.html60++--
Ae2e/testdata/screens/narrow-copy.html16+
Me2e/testdata/screens/narrow.html30+-
Ae2e/testdata/screens/palette-narrow.html16+
Ae2e/testdata/screens/palette-search-light.html30++
Ae2e/testdata/screens/palette-search.html30++
Ae2e/testdata/screens/palette-wide.html30++
Ae2e/testdata/screens/palette.html30++
Me2e/testdata/screens/point-range-light.html60++--
Me2e/testdata/screens/point-range.html60++--
Me2e/testdata/screens/prompt-width.html60++--
Me2e/testdata/screens/quit-confirm-light.html60++--
Me2e/testdata/screens/quit-confirm.html60++--
Me2e/testdata/screens/ready-empty.html58++--
Ae2e/testdata/screens/resizing-column-light.html30++
Ae2e/testdata/screens/resizing-column.html30++
Me2e/testdata/screens/selection-stats-light.html58++--
Me2e/testdata/screens/selection-stats.html58++--
Ae2e/testdata/screens/undo-note.html30++
Mgo.mod1+
Mgo.sum4+
Minternal/sheet/addr.go50++-
Minternal/sheet/eval.go8+
Ainternal/sheet/find.go139++++++++
Ainternal/sheet/find_test.go126+++++++
Minternal/sheet/history.go222+++++++++++-
Ainternal/sheet/history_test.go147++++++++
Ainternal/sheet/merge_undo_test.go40++
Ainternal/sheet/ops.go317++++++++++++++++++
Minternal/sheet/parse.go64+++-
Ainternal/sheet/print.go100++++++
Ainternal/sheet/refs.go196+++++++++++
Ainternal/sheet/refs_test.go365++++++++++++++++++++
Minternal/sheet/sheet.go7+-
Minternal/sheet/sheet_test.go2+-
Ainternal/ui/clipboard.go223+++++++++++++
Minternal/ui/commands.go64++-
Ainternal/ui/context.go87+++++
Ainternal/ui/context_test.go107++++++
Ainternal/ui/dialog.go106++++++
Ainternal/ui/edit.go294++++++++++++++++
Ainternal/ui/edit_test.go311+++++++++++++++++
Minternal/ui/entry.go35+-
Minternal/ui/format_test.go19+-
Ainternal/ui/help.go295+++++++++++++++++
Ainternal/ui/help_test.go124+++++++
Minternal/ui/menu.go159+--------
Ainternal/ui/menubar.go535++++++++++++++++++++++++++++++
Minternal/ui/model.go110+++++-
Minternal/ui/model_test.go109++----
Ainternal/ui/mouse.go397++++++++++++++++++++++
Ainternal/ui/mouse_test.go147++++++++
Ainternal/ui/overlay.go217++++++++++++
Ainternal/ui/palette.go347+++++++++++++++++++
Ainternal/ui/palette_test.go164+++++++++
Ainternal/ui/panel.go241++++++++++++++
Minternal/ui/selection.go124+-------
Ainternal/ui/shell_test.go302+++++++++++++++++
Minternal/ui/theme.go49++-
Minternal/ui/view.go265+-------------
M .gitignore +1 -0
M README.md +15 -1
@@ -23,15 +23,29 @@ Inside the grid, one23 works like Google Sheets.
2323 | Click a header, Ctrl+Space, Shift+Space | Select whole columns or rows |2424 | Ctrl+A | Select the data, then everything |2525 | Del / Backspace | Clear the selection (formatting stays) |26+| Ctrl+Z, Ctrl+Y or Ctrl+Shift+Z | Undo, redo |27+| Ctrl+C, Ctrl+X, Ctrl+V | Copy, cut, paste; references adjust as in Sheets, and copies also go to the system clipboard |28+| Ctrl+Shift+V | Paste values only |29+| Paste from the terminal | Tab-separated or multi-line text fills a block of cells |30+| Ctrl+D, Ctrl+R | Fill down, fill right |31+| Ctrl+Alt+= / Ctrl+Alt+- | Insert rows above / delete the selected rows (columns when whole columns are selected) |32+| Ctrl+Enter while typing | Enter the same entry in every selected cell |33+| F4 while typing a formula | Cycle the reference at the caret through A1, $A$1, A$1, $A1 |2634 | Ctrl+Shift+1 ... 6 | Number, time, date, currency, percent, scientific format |2735 | Ctrl+B, Ctrl+I, Ctrl+U, Alt+Shift+5 | Bold, italic, underline, strikethrough |2836 | Ctrl+Shift+L / E / R | Align left, center, right |2937 | Ctrl+\ | Clear formatting |3038 | Ctrl+S, Ctrl+O, Ctrl+Q | Save, open, quit |3139 | Ctrl+G or F5 | Go to a cell |32-| F10 | Menu |40+| Alt+F, Alt+E, Alt+V, Alt+I, Alt+O, Alt+H, F10, click a title | Open a menu (arrows move, Enter runs, Esc closes) |41+| Ctrl+K, Alt+/, Ctrl+Shift+P | Search the menus: find and run any command |42+| Right-click, Shift+F10 | Cell, column or row menu |3343 | F1 or Ctrl+/ | Keyboard shortcuts |3444 45+The top three lines are the menu bar and mode indicator, the formula bar46+(name box, then the cell's contents or the entry being typed) and the47+context line (prompts, key hints, formula errors).48+3549 ## Layout3650 3751 ```
M docs/UX.md +29 -10
@@ -13,18 +13,31 @@ follow-up task.
1313 1-2-3 disagree, Sheets wins. 1-2-3 lives on as the visual identity:1414 the control panel doubling as the formula bar, the mode indicator, the1515 crisp character grid.16-2. **Everything is discoverable.** Every action is a registered command16+2. **Familiar, but native to the terminal.** Sheets tells us which jobs17+ users expect to get done and which keys they reach for, not what the18+ screen must look like. This is a Bubble Tea program: prefer patterns19+ that feel at home in a terminal when they serve the same need as well20+ or better. Bars and prompts on the context line or status line over21+ floating dialogs, incremental search that highlights as you type,22+ toggles shown as key chips, pickers in the style of fzf or lazygit, and23+ no fake GUI chrome (drop shadows, faux buttons) unless it earns its24+ place. Overlays are fine when content genuinely needs room (menus,25+ long lists), and they stay keyboard-first.26+3. **Everything is discoverable.** Every action is a registered command1727 (`internal/ui/commands.go`) with a title and one-line description. It is1828 reachable from the menu where Sheets would put it, from key bindings in19- `keymap`, and from help (generated from the registry). When the command20- palette lands, it lists every registered command with its keys.21-3. **The screen always says what's going on.** The mode indicator is always22- correct. The third panel line tells the user what keys do in any23- non-READY state. Prompts live on the second panel line.24-4. **Never lose work.** Destructive actions warn when there are unsaved29+ `keymap`, and from help (generated from the registry). The command30+ palette lists every registered command with its keys.31+4. **The screen always says what's going on.** The mode indicator is always32+ correct. The control panel is the menu bar (with the mode indicator),33+ the formula bar, and the context line, which holds prompts, small34+ confirmations and the keys that apply in any non-READY state. While a35+ menu, the palette or the shortcuts are open, the status line says what36+ the highlighted item does and which keys apply.37+5. **Never lose work.** Destructive actions warn when there are unsaved2538 changes and are undoable once undo exists. Errors are specific2639 ("expected , or )" with the cursor on the spot), never generic.27-5. **Esc backs out one level; Enter confirms.** Everywhere, no exceptions.40+6. **Esc backs out one level; Enter confirms.** Everywhere, no exceptions.2841 2942 ## Visual rules3043
@@ -39,8 +52,14 @@ follow-up task.
3952 `modified`, `#DIV/0!`, `Circular reference`).4053 - Numbers right-aligned, text left, booleans and errors centered, one4154 column of padding, text overflowing into empty neighbors: as Sheets.42- Headers centered. Menu items separated by two spaces. Keys shown as43- `F2`, `Ctrl+Z`, `Del` (see `keyLabel`).55+ Headers centered. Menu bar titles separated by two spaces. Keys shown56+ as `F2`, `Ctrl+Z`, `Del` (see `keyLabel`), drawn as key chips57+ (`chip`) in hints, menus, the palette and the shortcuts.58+- Menus, the palette and the shortcuts are overlays: boxes framed with59+ light box-drawing lines (`frame`), composited over the grid without60+ moving it, with a title in the top border and a position or count in61+ the bottom one. Small questions (quit with unsaved changes) go on the62+ context line as a choice bar, not in a box.4463 - The active cell is always distinct from the rest of a selection, and4564 the headers of selected rows and columns are highlighted.4665 - Layout works from 60x16 up to very wide terminals. Nothing jumps
M e2e/app_test.go +111 -23
@@ -10,8 +10,44 @@ import (
1010 ghostty "go.mitchellh.com/libghostty"1111 )1212 13-// Screen layout: panel lines 0-2, column header 3, grid row 1 on line 4.14-const gridRow1 = 413+// Screen layout: menu bar 0, formula bar 1 (an 11-wide name box and a14+// space, then the contents), context line 2, column header 3, grid row 115+// on line 4.16+const (17+ barLine = 118+ barX = 1219+ contextLine = 220+ gridRow1 = 421+)22+23+// waitForBar waits for the formula bar to show name in the name box and24+// text after it.25+func (s *session) waitForBar(name, text string) {26+ s.t.Helper()27+ s.eventually(fmt.Sprintf("formula bar %s %q", name, text), func() bool {28+ l := s.line(barLine) + strings.Repeat(" ", barX)29+ return strings.TrimSpace(l[:barX]) == name && strings.TrimRight(l[barX:], " ") == text30+ })31+}32+33+// waitForName waits for the name box to show name.34+func (s *session) waitForName(name string) {35+ s.t.Helper()36+ s.eventually(fmt.Sprintf("name box %s", name), func() bool {37+ l := s.line(barLine)38+ return strings.TrimSpace(l[:min(barX, len(l))]) == name39+ })40+}41+42+// waitForEntry waits for the formula bar to show text, whatever the name43+// box says; used while typing.44+func (s *session) waitForEntry(text string) {45+ s.t.Helper()46+ s.eventually(fmt.Sprintf("formula bar %q", text), func() bool {47+ l := s.line(barLine)48+ return len(l) >= barX && l[barX:] == text49+ })50+}1551 1652 // numRow is how a grid row of numbers in default-width (10) columns looks:1753 // a 6-wide row header, then each number right-aligned with one column of
@@ -28,7 +64,7 @@ func TestFormulaRecalc(t *testing.T) {
2864 s := start(t, "")2965 s.keys("10", "<enter>", "20", "<enter>", "=SUM(A1:A2)", "<enter>")3066 s.keys("<up>")31- s.waitFor("A3 =SUM(A1:A2)")67+ s.waitForBar("A3", "=SUM(A1:A2)")3268 s.waitForLine(gridRow1+2, numRow(3, "30"))3369 3470 // Changing a precedent recalculates the total on screen.
@@ -40,11 +76,11 @@ func TestPointModeBuildsFormula(t *testing.T) {
4076 s := start(t, "")4177 s.keys("4", "<tab>", "6", "<tab>", "=", "<left>", "<left>")4278 s.waitFor("POINT")43- s.waitForLine(1, "=A1")79+ s.waitForBar("C1", "=A1")4480 s.keys("*", "<left>", "<enter>")4581 // Enter after a run of Tabs returns to the starting column, as in Sheets.4682 s.keys("<up>", "<right>", "<right>")47- s.waitFor("C1 =A1*B1")83+ s.waitForBar("C1", "=A1*B1")4884 s.waitForLine(gridRow1, numRow(1, "4", "6", "24"))4985 }5086
@@ -76,19 +112,10 @@ func TestInvalidFormulaCursor(t *testing.T) {
76112 // The real terminal cursor sits on the edit line at the error.77113 s.eventually("cursor at end of edit line", func() bool {78114 x, y := s.cursor()79- return x == len("=SUM(A1") && y == 1115+ return x == barX+len("=SUM(A1") && y == barLine80116 })81117 }82118 83-func TestMenuSetsColumnWidth(t *testing.T) {84- s := start(t, "")85- s.keys("<f10>")86- s.waitFor("File Edit Format")87- s.keys("f", "<enter>", "c", "20", "<enter>")88- s.waitFor("READY")89- s.eventually("wider column A", func() bool { return strings.HasPrefix(s.line(3), strings.Repeat(" ", 6)+strings.Repeat(" ", 9)+"A") })90-}91-92119 func TestSaveQuitReopen(t *testing.T) {93120 dir := t.TempDir()94121 s := start(t, dir)
@@ -113,14 +140,6 @@ func TestSaveQuitReopen(t *testing.T) {
113140 }114141 }115142 116-func TestQuitAsksAboutUnsavedChanges(t *testing.T) {117- s := start(t, "")118- s.keys("1", "<enter>", "<ctrl+q>")119- s.waitFor("Cancel Quit without saving")120- s.keys("<esc>", "<esc>")121- s.waitFor("READY")122-}123-124143 func TestResizeShowsMoreColumns(t *testing.T) {125144 s := start(t, "")126145 s.waitFor(" I")
@@ -131,6 +150,75 @@ func TestResizeShowsMoreColumns(t *testing.T) {
131150 s.eventually("column N after resize", func() bool { return strings.Contains(s.line(3), " N") })132151 }133152 153+func TestCopyPasteAdjustsReferences(t *testing.T) {154+ s := start(t, "")155+ clip := s.watchClipboard()156+ s.keys("2", "<tab>", "=A1*10", "<enter>", "3", "<enter>", "<ctrl+home>", "<right>", "<ctrl+c>")157+ s.waitFor("Copied B1")158+ s.eventually("system clipboard", func() bool { return clip.get() == "20" })159+ s.keys("<down>", "<ctrl+v>")160+ s.waitFor("Pasted 1 cell at B2")161+ s.waitForBar("B2", "=A2*10")162+ s.waitForLine(gridRow1+1, numRow(2, "3", "30"))163+164+ // Esc clears the marker; the paste stays.165+ s.keys("<esc>")166+ s.eventually("marker cleared", func() bool { return !strings.Contains(s.line(2), "Copied") })167+168+ // Cut and paste moves the cell and the formula that uses it follows.169+ s.keys("<ctrl+home>", "<ctrl+x>", "<down>", "<down>", "<down>", "<ctrl+v>")170+ s.waitFor("Moved A1 to A4")171+ s.keys("<ctrl+home>", "<right>")172+ s.waitForBar("B1", "=A4*10")173+ s.waitForLine(gridRow1+3, numRow(4, "2"))174+}175+176+func TestUndoRedo(t *testing.T) {177+ s := start(t, "")178+ s.keys("10", "<enter>", "=A1+1", "<enter>", "<up>", "<up>", "<shift+down>", "<delete>")179+ s.waitForLine(gridRow1, " 1")180+ s.keys("<ctrl+z>")181+ s.waitFor("Undid: clear A1:A2")182+ s.waitForLine(gridRow1+1, numRow(2, "11"))183+ s.keys("<ctrl+y>")184+ s.waitFor("Redid: clear A1:A2")185+ s.waitForLine(gridRow1+1, " 2")186+ s.keys("<ctrl+shift+z>")187+ s.waitFor("Nothing to redo")188+}189+190+func TestInsertRowRewritesFormulas(t *testing.T) {191+ s := start(t, "")192+ s.keys("1", "<enter>", "2", "<enter>", "=SUM(A1:A2)", "<enter>")193+ s.keys("<up>", "<up>", "<shift+space>", "<ctrl+alt+=>")194+ s.waitForLine(gridRow1+3, numRow(4, "3"))195+ s.keys("<down>", "<down>")196+ s.waitForBar("A4", "=SUM(A1:A3)")197+ s.keys("<up>", "<up>", "5", "<enter>")198+ s.waitForLine(gridRow1+3, numRow(4, "8"))199+ s.keys("<ctrl+z>", "<ctrl+z>")200+ s.waitFor("Undid: insert 1 row")201+ s.waitForLine(gridRow1+2, numRow(3, "3"))202+}203+204+func TestPasteTSVFillsCells(t *testing.T) {205+ s := start(t, "")206+ s.paste("Item\tCost\nRent\t1450\nFood\t=B2/2\n")207+ s.waitFor("Pasted 6 cells at A1:B3")208+ s.waitForLine(gridRow1+2, " 3 Food 725")209+}210+211+func TestFillAndAbsoluteReferences(t *testing.T) {212+ s := start(t, "")213+ s.keys("2", "<enter>", "3", "<enter>", "4", "<enter>", "<ctrl+home>", "<right>")214+ s.keys("=A1*A1", "<left>", "<left>", "<f4>")215+ s.waitForEntry("=A1*$A$1")216+ s.keys("<enter>", "<up>", "<shift+down>", "<shift+down>", "<ctrl+d>")217+ s.waitForLine(gridRow1+2, numRow(3, "4", "8"))218+ s.keys("<right>", "<shift+down>", "=B1+1", "<ctrl+enter>")219+ s.waitForLine(gridRow1+1, numRow(2, "3", "6", "7"))220+}221+134222 // Click handling is covered by the unit tests; this checks the program135223 // actually turned on mouse reporting in the terminal.136224 func TestMouseTrackingEnabled(t *testing.T) {
A e2e/clipboard_test.go +59 -0
M e2e/harness_test.go +57 -1
@@ -53,6 +53,8 @@ type session struct {
5353 vt *ghostty.Terminal5454 enc *ghostty.KeyEncoder5555 ev *ghostty.KeyEvent56+ menc *ghostty.MouseEncoder57+ mev *ghostty.MouseEvent5658 cols uint165759 rows uint165860
@@ -90,6 +92,12 @@ func startWith(t *testing.T, o options, args ...string) *session {
9092 if s.enc, err = ghostty.NewKeyEncoder(); err != nil {9193 t.Fatal(err)9294 }95+ if s.menc, err = ghostty.NewMouseEncoder(); err != nil {96+ t.Fatal(err)97+ }98+ if s.mev, err = ghostty.NewMouseEvent(); err != nil {99+ t.Fatal(err)100+ }93101 if s.ev, err = ghostty.NewKeyEvent(); err != nil {94102 t.Fatal(err)95103 }
@@ -108,7 +116,7 @@ func startWith(t *testing.T, o options, args ...string) *session {
108116 s.pty.Write(append([]byte(nil), data...))109117 })110118 s.vt.SetEffectSize(func(*ghostty.Terminal) (ghostty.SizeReportSize, bool) {111- return ghostty.SizeReportSize{Columns: s.cols, Rows: s.rows, CellWidth: 8, CellHeight: 16}, true119+ return ghostty.SizeReportSize{Columns: s.cols, Rows: s.rows, CellWidth: cellW, CellHeight: cellH}, true112120 })113121 114122 go func() {
@@ -134,6 +142,8 @@ func startWith(t *testing.T, o options, args ...string) *session {
134142 s.pty.Close()135143 <-s.exited136144 s.ev.Close()145+ s.mev.Close()146+ s.menc.Close()137147 s.enc.Close()138148 s.vt.Close()139149 })
@@ -290,6 +300,52 @@ func (s *session) press(key ghostty.Key, mods ghostty.Mods, text string, unshift
290300 time.Sleep(5 * time.Millisecond)291301 }292302 303+// Cell size in pixels, as reported to the program and used to place mouse304+// events.305+const cellW, cellH = 8, 16306+307+// mouse sends a mouse event at cell x, y, encoded by libghostty for the308+// tracking mode and format the program turned on. MouseButtonUnknown means309+// no button, e.g. plain motion.310+func (s *session) mouse(action ghostty.MouseAction, button ghostty.MouseButton, x, y int, mods ghostty.Mods) {311+ s.t.Helper()312+ s.mu.Lock()313+ s.menc.SetOptFromTerminal(s.vt)314+ s.menc.SetOptSize(ghostty.MouseEncoderSize{315+ ScreenWidth: uint32(s.cols) * cellW, ScreenHeight: uint32(s.rows) * cellH,316+ CellWidth: cellW, CellHeight: cellH,317+ })318+ s.mev.SetAction(action)319+ if button == ghostty.MouseButtonUnknown {320+ s.mev.ClearButton()321+ } else {322+ s.mev.SetButton(button)323+ }324+ s.mev.SetMods(mods)325+ // Motion with a button held is a drag.326+ s.menc.SetOptAnyButtonPressed(action == ghostty.MouseActionMotion && button != ghostty.MouseButtonUnknown)327+ s.mev.SetPosition(ghostty.MousePosition{X: float32(x*cellW + cellW/2), Y: float32(y*cellH + cellH/2)})328+ data, err := s.menc.Encode(s.mev)329+ s.mu.Unlock()330+ if err != nil {331+ s.t.Fatalf("encoding mouse event: %v", err)332+ }333+ if len(data) == 0 {334+ s.t.Fatalf("mouse event at %d,%d not reported; is mouse tracking on?", x, y)335+ }336+ if _, err := s.pty.Write(data); err != nil {337+ s.t.Fatal(err)338+ }339+ time.Sleep(5 * time.Millisecond)340+}341+342+// click presses and releases a mouse button over cell x, y.343+func (s *session) click(button ghostty.MouseButton, x, y int) {344+ s.t.Helper()345+ s.mouse(ghostty.MouseActionPress, button, x, y, 0)346+ s.mouse(ghostty.MouseActionRelease, button, x, y, 0)347+}348+293349 // resize changes both the virtual terminal and the pty, which sends the294350 // program SIGWINCH.295351 func (s *session) resize(cols, rows uint16) {
A e2e/mouse_test.go +99 -0
@@ -0,0 +1,99 @@
1+package e2e2+3+import (4+ "strings"5+ "testing"6+7+ ghostty "go.mitchellh.com/libghostty"8+)9+10+// leftClick presses and releases the left button at a screen cell, with11+// modifiers.12+func (s *session) leftClick(col, row int, mods ghostty.Mods) {13+ s.mouse(ghostty.MouseActionPress, ghostty.MouseButtonLeft, col, row, mods)14+ s.mouse(ghostty.MouseActionRelease, ghostty.MouseButtonLeft, col, row, mods)15+}16+17+// drag presses at one cell, moves through the path and releases at the end.18+func (s *session) drag(path ...[2]int) {19+ first, last := path[0], path[len(path)-1]20+ s.mouse(ghostty.MouseActionPress, ghostty.MouseButtonLeft, first[0], first[1], 0)21+ for _, p := range path[1:] {22+ s.mouse(ghostty.MouseActionMotion, ghostty.MouseButtonLeft, p[0], p[1], 0)23+ }24+ s.mouse(ghostty.MouseActionRelease, ghostty.MouseButtonLeft, last[0], last[1], 0)25+}26+27+// wheel scrolls at a cell; up is button 4, down is button 5.28+func (s *session) wheel(col, row, clicks int) {29+ button := ghostty.MouseButtonFive30+ if clicks < 0 {31+ button, clicks = ghostty.MouseButtonFour, -clicks32+ }33+ for range clicks {34+ s.mouse(ghostty.MouseActionPress, button, col, row, 0)35+ }36+}37+38+// Screen x of a cell in column c with default widths and no scrolling.39+func colX(c int) int { return 6 + c*10 + 2 }40+41+func TestMouseClickDragAndShiftClick(t *testing.T) {42+ s := start(t, "")43+ s.leftClick(colX(1), gridRow1+2, 0)44+ s.waitForName("B3")45+ s.drag([2]int{colX(0), gridRow1}, [2]int{colX(1), gridRow1 + 1}, [2]int{colX(2), gridRow1 + 2})46+ s.eventually("drag selection", func() bool { return strings.Contains(s.line(29), "A1:C3") })47+ s.leftClick(colX(3), gridRow1+4, ghostty.ModShift)48+ s.eventually("shift+click extends", func() bool { return strings.Contains(s.line(29), "A1:D5") })49+50+ // The app asked the terminal to pass Shift+click through.51+ s.mu.Lock()52+ raw := string(s.raw)53+ s.mu.Unlock()54+ if !strings.Contains(raw, "\x1b[>1s") {55+ t.Error("XTSHIFTESCAPE not requested")56+ }57+}58+59+func TestMouseClickWhileTypingAndFormulaReference(t *testing.T) {60+ s := start(t, "")61+ s.keys("40", "<enter>", "2", "<enter>", "=")62+ s.leftClick(colX(0), gridRow1, 0)63+ s.waitForEntry("=A1")64+ s.keys("+")65+ s.leftClick(colX(0), gridRow1+1, 0)66+ s.waitForEntry("=A1+A2")67+ s.keys("<enter>")68+ s.waitForLine(gridRow1+2, numRow(3, "42"))69+70+ // Clicking another cell while typing plain text accepts it there.71+ s.keys("note")72+ s.leftClick(colX(2), gridRow1, 0)73+ s.waitForName("C1")74+ s.waitForLine(gridRow1+3, " 4 note")75+}76+77+func TestMouseResizeAndWheel(t *testing.T) {78+ s := start(t, "")79+ border := 6 + 10 - 180+ s.drag([2]int{border, 3}, [2]int{border + 4, 3}, [2]int{border + 8, 3})81+ s.eventually("column A wider", func() bool {82+ return strings.HasPrefix(s.line(3), strings.Repeat(" ", 6)+strings.Repeat(" ", 8)+"A")83+ })84+ s.wheel(colX(2), gridRow1+5, 4)85+ s.waitForLine(gridRow1, " 13")86+ // The active cell didn't move; arrowing to A2 scrolls just enough to87+ // show it again.88+ s.keys("<down>")89+ s.waitForLine(gridRow1, " 2")90+}91+92+func TestMouseDoubleClickEdits(t *testing.T) {93+ s := start(t, "")94+ s.keys("hello", "<enter>")95+ s.leftClick(colX(0), gridRow1, 0)96+ s.leftClick(colX(0), gridRow1, 0)97+ s.waitFor("EDIT")98+ s.waitForEntry("hello")99+}
M e2e/render_test.go +18 -8
@@ -64,7 +64,7 @@ func renderHTML(vt *ghostty.Terminal) (string, error) {
6464 }6565 css := ""6666 if st, err := ref.Style(); err == nil && !st.IsDefault() {67- css = styleCSS(st)67+ css = styleCSS(st, strings.TrimSpace(text) == "")6868 }6969 // Cells erased with a background color hold just that color.7070 switch tag, _ := cell.ContentTag(); tag {
@@ -88,29 +88,39 @@ func renderHTML(vt *ghostty.Terminal) (string, error) {
8888 return `<pre class="screen">` + strings.TrimRight(b.String(), "\n") + "</pre>", nil8989 }9090 91-func styleCSS(st *ghostty.Style) string {91+// styleCSS converts a cell style to CSS. For blank cells only what shows92+// is kept (background, lines), so snapshots don't depend on whether the93+// renderer wrote spaces or erased cells.94+func styleCSS(st *ghostty.Style, blank bool) string {9295 fg, bg := cssColor(st.FgColor(), ""), cssColor(st.BgColor(), "")9396 if st.Inverse() {9497 fg, bg = cmp.Or(bg, "var(--bg)"), cmp.Or(fg, "var(--fg)")9598 }9699 var parts []string97- if fg != "" {100+ if fg != "" && !blank {98101 parts = append(parts, "color:"+fg)99102 }100103 if bg != "" {101104 parts = append(parts, "background:"+bg)102105 }103- if st.Bold() {106+ if st.Bold() && !blank {104107 parts = append(parts, "font-weight:bold")105108 }106- if st.Italic() {109+ if st.Italic() && !blank {107110 parts = append(parts, "font-style:italic")108111 }109- if st.Faint() {112+ if st.Faint() && !blank {110113 parts = append(parts, "opacity:.6")111114 }112- if st.Underline() != 0 {113- parts = append(parts, "text-decoration:underline")115+ if u := st.Underline(); u != ghostty.UnderlineNone {116+ line := map[ghostty.SGRUnderline]string{117+ ghostty.UnderlineDouble: " double", ghostty.UnderlineCurly: " wavy",118+ ghostty.UnderlineDotted: " dotted", ghostty.UnderlineDashed: " dashed",119+ }[u]120+ if c := cssColor(st.UnderlineColor(), ""); c != "" {121+ line += " " + c122+ }123+ parts = append(parts, "text-decoration:underline"+line)114124 }115125 if st.Strikethrough() {116126 parts = append(parts, "text-decoration:line-through")
M e2e/screens_test.go +102 -7
@@ -9,6 +9,8 @@ import (
99 "strings"1010 "testing"1111 "time"12+13+ ghostty "go.mitchellh.com/libghostty"1214 )1315 1416 var update = flag.Bool("update", false, "rewrite golden screens in testdata/screens")
@@ -32,7 +34,7 @@ func budget(s *session) {
3234 s.keys("Savings rate", "<tab>", "=B3/0", "<enter>")3335 s.keys("Total", "<tab>", "=SUM(B3:B5)", "<enter>")3436 s.keys("<up>", "<right>")35- s.waitFor("B7 =SUM(B3:B5)")37+ s.waitForBar("B7", "=SUM(B3:B5)")3638 }3739 3840 // formatted types a bill schedule with dates, currency and percentages,
@@ -90,17 +92,69 @@ var screens = []screen{
9092 }},9193 {name: "menu", setup: func(s *session) {9294 budget(s)93- s.keys("<f10>")94- s.waitFor("File Edit Format")95+ s.keys("<alt+f>", "<down>", "<down>")96+ s.waitFor("Save the sheet")97+ }},98+ {name: "palette", setup: func(s *session) {99+ budget(s)100+ s.keys("<ctrl+k>")101+ s.waitFor("Search the menus")102+ }},103+ {name: "palette-search", setup: func(s *session) {104+ budget(s)105+ s.keys("<alt+/>", "col")106+ s.waitFor("│ › col")107+ }},108+ {name: "palette-narrow", opts: options{cols: 60, rows: 16}, setup: func(s *session) {109+ budget(s)110+ s.keys("<ctrl+k>", "sa")111+ s.waitFor("│ › sa")112+ }},113+ {name: "context-menu", setup: func(s *session) {114+ budget(s)115+ s.click(ghostty.MouseButtonRight, 6+10+4, 4+3)116+ s.waitFor("│ Clear")117+ }},118+ {name: "context-menu-column", setup: func(s *session) {119+ budget(s)120+ s.click(ghostty.MouseButtonRight, 6+10+4, 3)121+ s.waitFor("│ Resize column")122+ }},123+ {name: "menu-narrow", opts: options{cols: 60, rows: 16}, setup: func(s *session) {124+ budget(s)125+ s.keys("<alt+h>")126+ s.waitFor("│ About one23")127+ }},128+ {name: "functions", setup: func(s *session) {129+ budget(s)130+ s.keys("<alt+h>", "f", "if")131+ s.waitFor("│ › if")132+ }},133+ {name: "about", setup: func(s *session) {134+ s.keys("<alt+h>", "a")135+ s.waitFor("Google Sheets keys")136+ }},137+ {name: "help-narrow", opts: options{cols: 60, rows: 16}, setup: func(s *session) {138+ s.keys("<f1>")139+ s.waitFor("Keyboard shortcuts")140+ }},141+ {name: "palette-wide", opts: options{cols: 200, rows: 30}, setup: func(s *session) {142+ budget(s)143+ s.keys("<ctrl+k>", "sel")144+ s.waitFor("│ › sel")145+ }},146+ {name: "help-wide", opts: options{cols: 200, rows: 45}, setup: func(s *session) {147+ s.keys("<f1>")148+ s.waitFor("Keyboard shortcuts")95149 }},96150 {name: "quit-confirm", setup: func(s *session) {97151 budget(s)98- s.keys("<ctrl+q>", "<right>")152+ s.keys("<ctrl+q>")99153 s.waitFor("unsaved changes")100154 }},101155 {name: "prompt-width", setup: func(s *session) {102156 budget(s)103- s.keys("<ctrl+home>", "<f10>", "f", "<enter>", "c", "<right>", "<right>", "<right>")157+ s.keys("<ctrl+home>", "<alt+o>", "c", "<enter>", "<right>", "<right>", "<right>")104158 s.waitFor("Column width (1-240): 13")105159 }},106160 {name: "error-goto", setup: func(s *session) {
@@ -112,14 +166,50 @@ var screens = []screen{
112166 s.waitFor("HELP")113167 }},114168 {name: "narrow", opts: options{cols: 60, rows: 16}, setup: budget},169+ {name: "hover-resize-handle", setup: func(s *session) {170+ budget(s)171+ s.mouse(ghostty.MouseActionMotion, ghostty.MouseButtonUnknown, 6+10-1, 3, 0)172+ s.waitFor("▐")173+ }},174+ {name: "resizing-column", setup: func(s *session) {175+ budget(s)176+ s.mouse(ghostty.MouseActionPress, ghostty.MouseButtonLeft, 6+10-1, 3, 0)177+ s.mouse(ghostty.MouseActionMotion, ghostty.MouseButtonLeft, 6+10+5, 3, 0)178+ s.waitFor("Column A width 16")179+ }},180+ {name: "copy-marker", setup: func(s *session) {181+ budget(s)182+ s.keys("<up>", "<up>", "<up>", "<up>", "<shift+down>", "<shift+down>", "<ctrl+c>", "<right>", "<up>")183+ s.waitFor("Copied B3:B5")184+ }},185+ {name: "copy-marker-selected", setup: func(s *session) {186+ budget(s)187+ s.keys("<left>", "<up>", "<up>", "<up>", "<up>", "<shift+down>", "<shift+down>", "<shift+right>", "<ctrl+x>")188+ s.waitFor("Cut A3:B5")189+ }},190+ {name: "undo-note", setup: func(s *session) {191+ budget(s)192+ s.keys("<up>", "<shift+up>", "<delete>", "<ctrl+z>")193+ s.waitFor("Undid: clear B5:B6")194+ }},195+ {name: "narrow-copy", opts: options{cols: 60, rows: 16}, setup: func(s *session) {196+ budget(s)197+ s.keys("<ctrl+c>", "<down>")198+ s.waitFor("Copied B7")199+ }},115200 {name: "formats", setup: formatted},201+ {name: "menu-format-number", setup: func(s *session) {202+ formatted(s)203+ s.keys("<alt+o>", "<right>")204+ s.waitFor("Currency rounded")205+ }},116206 {name: "formats-narrow", opts: options{cols: 60, rows: 16}, setup: formatted},117207 }118208 119209 // Key screens are also recorded on a light terminal, where the app picks120210 // its light theme from the reported background color.121211 func init() {122- for _, name := range []string{"budget", "point-range", "selection-stats", "quit-confirm", "help", "formats"} {212+ for _, name := range []string{"budget", "point-range", "selection-stats", "menu", "palette-search", "context-menu-column", "functions", "quit-confirm", "help", "resizing-column", "copy-marker", "copy-marker-selected", "formats", "menu-format-number"} {123213 for _, sc := range screens {124214 if sc.name == name {125215 sc.name += "-light"
@@ -195,6 +285,7 @@ h2{font:500 13px ui-monospace,monospace;color:#aaa;margin:0 0 8px}
195285 .term{display:inline-block;padding:14px 16px;border-radius:10px;box-shadow:0 8px 30px #0008}196286 .screen{margin:0;font:13px/1.3 "JetBrains Mono","SF Mono",Menlo,monospace;color:var(--fg)}197287 .grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(820px,1fr));gap:8px 24px}288+.wide{grid-column:1/-1}198289 `)199290 for _, p := range []struct {200291 class string
@@ -213,7 +304,11 @@ h2{font:500 13px ui-monospace,monospace;color:#aaa;margin:0 0 8px}
213304 if err != nil {214305 return err215306 }216- fmt.Fprintf(&b, "<section id=%q><h2>%s</h2><div>", sc.name, html.EscapeString(sc.name))307+ wide := ""308+ if sc.opts.cols > 120 {309+ wide = " class=wide" // spans the whole gallery row310+ }311+ fmt.Fprintf(&b, "<section id=%q%s><h2>%s</h2><div>", sc.name, wide, html.EscapeString(sc.name))217312 th := "dark"218313 if sc.opts.light {219314 th = "light"
A e2e/shell_test.go +81 -0
@@ -0,0 +1,81 @@
1+package e2e2+3+import (4+ "os"5+ "path/filepath"6+ "strings"7+ "testing"8+9+ ghostty "go.mitchellh.com/libghostty"10+)11+12+// The app shell: menu bar, dropdowns, context menus, the command palette13+// and the context-line confirmations.14+15+func TestAltFOpensFileMenuAndSaves(t *testing.T) {16+ dir := t.TempDir()17+ s := start(t, dir)18+ s.keys("42", "<enter>", "<alt+f>")19+ s.waitFor("│ Save as")20+ s.waitFor("MENU")21+ // "s" highlights Save (Save as also starts with s); Enter runs it.22+ s.keys("s", "<enter>")23+ s.waitFor("Save as: SHEET1.o23")24+ s.keys("<enter>")25+ s.eventually("saved file", func() bool {26+ _, err := os.Stat(filepath.Join(dir, "SHEET1.o23"))27+ return err == nil28+ })29+ s.waitFor("READY")30+}31+32+func TestMenuSetsColumnWidth(t *testing.T) {33+ s := start(t, "")34+ s.keys("<alt+o>", "c", "<enter>", "20", "<enter>")35+ s.waitFor("READY")36+ s.eventually("wider column A", func() bool { return strings.HasPrefix(s.line(3), strings.Repeat(" ", 6)+strings.Repeat(" ", 9)+"A") })37+}38+39+func TestPaletteSearchAndRun(t *testing.T) {40+ s := start(t, "")41+ s.keys("<ctrl+k>")42+ s.waitFor("Search the menus")43+ s.keys("goto")44+ s.waitFor("│ › goto")45+ s.keys("<enter>")46+ s.waitFor("Go to: A1")47+ s.keys("C5", "<enter>")48+ s.waitForBar("C5", "")49+}50+51+func TestRightClickColumnMenu(t *testing.T) {52+ s := start(t, "")53+ // Right-click column C's header: it selects the column and opens the54+ // column menu under the mouse.55+ x := 6 + 2*10 + 456+ s.click(ghostty.MouseButtonRight, x, 3)57+ s.waitFor("│ Resize column")58+ s.waitFor("C1:C8192")59+ s.keys("<esc>")60+ s.waitFor("READY")61+62+ // Clicking an item runs it.63+ s.click(ghostty.MouseButtonRight, x, 3)64+ s.waitFor("│ Resize column")65+ for y, l := range strings.Split(s.screen(), "\n") {66+ if strings.Contains(l, "│ Resize column") {67+ s.click(ghostty.MouseButtonLeft, x+3, y)68+ }69+ }70+ s.waitFor("Column width (1-240): 10")71+}72+73+func TestQuitAsksAboutUnsavedChanges(t *testing.T) {74+ s := start(t, "")75+ s.keys("1", "<enter>", "<ctrl+q>")76+ s.waitFor("You have unsaved changes.")77+ s.keys("<esc>")78+ s.waitFor("READY")79+ s.keys("<ctrl+q>", "d")80+ s.waitExit()81+}
A e2e/testdata/screens/about.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">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">MENU</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+one23 devel: Lotus 1-2-3 looks, Google Sheets keys. <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> Close4+<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+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
M e2e/testdata/screens/budget-light.html +29 -29
@@ -1,30 +1,30 @@
1-<pre class="screen"><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> B7 </span> =SUM(B3:B5) <span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> READY</span><span style="background:var(--vt-palette-6)"> </span>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">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">READY</span><span style="background:var(--vt-palette-6)"> </span>2+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">B7</span><span style="background:var(--vt-palette-7)"> </span> =SUM(B3:B5)23 3-4-<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> A </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> B </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> C D E F G H I </span>5-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 1 </span> Household budget 20266-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 2 </span>7-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 3 </span> Rent 14508-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 4 </span> Groceries 612.49-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 5 </span> Transit 9610-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 6 </span> Savings r<span style="color:var(--vt-palette-1)"> #DIV/0! </span>11-<span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> 7 </span> Total <span style="color:var(--vt-palette-0);background:var(--vt-palette-6)"> 2158.4 </span>12-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 8 </span>13-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 9 </span>14-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 10 </span>15-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 11 </span>16-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 12 </span>17-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 13 </span>18-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 14 </span>19-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 15 </span>20-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 16 </span>21-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 17 </span>22-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 18 </span>23-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 19 </span>24-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 20 </span>25-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 21 </span>26-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 22 </span>27-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 23 </span>28-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 24 </span>29-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 25 </span>30-untitled<span style="color:var(--vt-palette-0)"> modified</span> <span style="font-weight:bold">F1</span> <span style="color:var(--vt-palette-0)">help </span><span style="font-weight:bold">F10</span> <span style="color:var(--vt-palette-0)">menu </span><span style="font-weight:bold">Ctrl+Q</span> <span style="color:var(--vt-palette-0)">quit</span></pre>\ No newline at end of file4+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">A</span><span style="background:var(--vt-palette-7)"> </span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">B</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">C</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">D</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">E</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">F</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">G</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">H</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">I</span><span style="background:var(--vt-palette-7)"> </span>5+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1</span><span style="background:var(--vt-palette-7)"> </span> Household budget 20266+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">2</span><span style="background:var(--vt-palette-7)"> </span>7+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">3</span><span style="background:var(--vt-palette-7)"> </span> Rent 14508+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">4</span><span style="background:var(--vt-palette-7)"> </span> Groceries 612.49+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">5</span><span style="background:var(--vt-palette-7)"> </span> Transit 9610+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">6</span><span style="background:var(--vt-palette-7)"> </span> Savings r <span style="color:var(--vt-palette-1)">#DIV/0!</span>11+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">7</span><span style="background:var(--vt-palette-6)"> </span> Total <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">2158.4</span><span style="background:var(--vt-palette-6)"> </span>12+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">8</span><span style="background:var(--vt-palette-7)"> </span>13+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">9</span><span style="background:var(--vt-palette-7)"> </span>14+<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>15+<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>16+<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>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>18+<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>19+<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>20+<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>21+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">17</span><span style="background:var(--vt-palette-7)"> </span>22+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">18</span><span style="background:var(--vt-palette-7)"> </span>23+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">19</span><span style="background:var(--vt-palette-7)"> </span>24+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">20</span><span style="background:var(--vt-palette-7)"> </span>25+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">21</span><span style="background:var(--vt-palette-7)"> </span>26+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">22</span><span style="background:var(--vt-palette-7)"> </span>27+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">23</span><span style="background:var(--vt-palette-7)"> </span>28+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">24</span><span style="background:var(--vt-palette-7)"> </span>29+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">25</span><span style="background:var(--vt-palette-7)"> </span>30+untitled <span style="color:var(--vt-palette-0)">modified</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+K</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">search</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+/</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">shortcuts</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">F10</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">menu</span></pre>\ No newline at end of file
M e2e/testdata/screens/budget.html +29 -29
@@ -1,30 +1,30 @@
1-<pre class="screen"><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> B7 </span> =SUM(B3:B5) <span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> READY</span><span style="background:var(--vt-palette-6)"> </span>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">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">READY</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)">B7</span><span style="background:var(--vt-palette-8)"> </span> =SUM(B3:B5)23 3-4-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> A </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> B </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> C D E F G H I </span>5-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 1 </span> Household budget 20266-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 2 </span>7-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 3 </span> Rent 14508-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 4 </span> Groceries 612.49-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 5 </span> Transit 9610-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 6 </span> Savings r<span style="color:var(--vt-palette-1)"> #DIV/0! </span>11-<span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> 7 </span> Total <span style="color:var(--vt-palette-0);background:var(--vt-palette-6)"> 2158.4 </span>12-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 8 </span>13-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 9 </span>14-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 10 </span>15-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 11 </span>16-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 12 </span>17-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 13 </span>18-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 14 </span>19-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 15 </span>20-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 16 </span>21-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 17 </span>22-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 18 </span>23-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 19 </span>24-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 20 </span>25-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 21 </span>26-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 22 </span>27-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 23 </span>28-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 24 </span>29-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 25 </span>30-untitled<span style="color:var(--vt-palette-8)"> modified</span> <span style="font-weight:bold">F1</span> <span style="color:var(--vt-palette-8)">help </span><span style="font-weight:bold">F10</span> <span style="color:var(--vt-palette-8)">menu </span><span style="font-weight:bold">Ctrl+Q</span> <span style="color:var(--vt-palette-8)">quit</span></pre>\ No newline at end of file4+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">A</span><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">B</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)">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-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1</span><span style="background:var(--vt-palette-8)"> </span> Household budget 20266+<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> Rent 14508+<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> Groceries 612.49+<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> Transit 9610+<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> Savings r <span style="color:var(--vt-palette-1)">#DIV/0!</span>11+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">7</span><span style="background:var(--vt-palette-6)"> </span> Total <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">2158.4</span><span style="background:var(--vt-palette-6)"> </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+untitled <span style="color:var(--vt-palette-8)">modified</span> <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
M e2e/testdata/screens/column-select.html +29 -29
@@ -1,30 +1,30 @@
1-<pre class="screen"><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> B7 </span> =SUM(B3:B5) <span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> READY</span><span style="background:var(--vt-palette-6)"> </span>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">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">READY</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)">B1:B8192</span><span style="background:var(--vt-palette-8)"> </span> =SUM(B3:B5)23 3-4-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> A </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> B </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> C D E F G H I </span>5-<span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> 1 </span> Household<span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> budget 20</span>266-<span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> 2 </span> <span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> </span>7-<span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> 3 </span> Rent <span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> 1450 </span>8-<span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> 4 </span> Groceries<span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> 612.4 </span>9-<span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> 5 </span> Transit <span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> 96 </span>10-<span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> 6 </span> Savings r<span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> #DIV/0! </span>11-<span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> 7 </span> Total <span style="color:var(--vt-palette-0);background:var(--vt-palette-6)"> 2158.4 </span>12-<span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> 8 </span> <span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> </span>13-<span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> 9 </span> <span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> </span>14-<span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> 10 </span> <span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> </span>15-<span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> 11 </span> <span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> </span>16-<span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> 12 </span> <span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> </span>17-<span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> 13 </span> <span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> </span>18-<span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> 14 </span> <span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> </span>19-<span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> 15 </span> <span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> </span>20-<span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> 16 </span> <span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> </span>21-<span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> 17 </span> <span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> </span>22-<span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> 18 </span> <span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> </span>23-<span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> 19 </span> <span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> </span>24-<span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> 20 </span> <span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> </span>25-<span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> 21 </span> <span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> </span>26-<span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> 22 </span> <span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> </span>27-<span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> 23 </span> <span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> </span>28-<span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> 24 </span> <span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> </span>29-<span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> 25 </span> <span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> </span>30-untitled<span style="color:var(--vt-palette-8)"> modified</span> <span style="font-weight:bold">B1:B8192</span> <span style="color:var(--vt-palette-8)">Sum </span>4316.8 <span style="color:var(--vt-palette-8)">Avg </span>1079.2 <span style="color:var(--vt-palette-8)">Count </span>5</pre>\ No newline at end of file4+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">A</span><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">B</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)">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-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">1</span><span style="background:var(--vt-palette-4)"> </span> Household<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">budget</span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">20</span>266+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">2</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>7+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">3</span><span style="background:var(--vt-palette-4)"> </span> Rent <span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">1450</span><span style="background:var(--vt-palette-4)"> </span>8+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">4</span><span style="background:var(--vt-palette-4)"> </span> Groceries<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">612.4</span><span style="background:var(--vt-palette-4)"> </span>9+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">5</span><span style="background:var(--vt-palette-4)"> </span> Transit <span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">96</span><span style="background:var(--vt-palette-4)"> </span>10+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">6</span><span style="background:var(--vt-palette-4)"> </span> Savings r<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">#DIV/0!</span><span style="background:var(--vt-palette-4)"> </span>11+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">7</span><span style="background:var(--vt-palette-6)"> </span> Total <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">2158.4</span><span style="background:var(--vt-palette-6)"> </span>12+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">8</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>13+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">9</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>14+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">10</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>15+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">11</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>16+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">12</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>17+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">13</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>18+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">14</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>19+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">15</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>20+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">16</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>21+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">17</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>22+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">18</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>23+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">19</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>24+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">20</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>25+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">21</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>26+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">22</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>27+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">23</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>28+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">24</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>29+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">25</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>30+untitled <span style="color:var(--vt-palette-8)">modified</span> <span style="font-weight:bold">B1:B8192</span> <span style="color:var(--vt-palette-8)">Sum</span> 4316.8 <span style="color:var(--vt-palette-8)">Avg</span> 1079.2 <span style="color:var(--vt-palette-8)">Count</span> 5</pre>\ No newline at end of file
A e2e/testdata/screens/context-menu-column-light.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">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">MENU</span><span style="background:var(--vt-palette-6)"> </span>2+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">B1:B8192</span><span style="background:var(--vt-palette-7)"> </span>3+4+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">A</span><span style="background:var(--vt-palette-7)"> </span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">B</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">C</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">D</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">E</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">F</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">G</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">H</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">I</span><span style="background:var(--vt-palette-7)"> </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> Household<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">bud</span><span style="color:var(--vt-palette-8)">┌────────────────────────────────┐</span>6+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">2</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </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)">Cut</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">Ctrl+X</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-8)">│</span>7+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">3</span><span style="background:var(--vt-palette-4)"> </span> Rent <span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-8)">│</span> Copy <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+C</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span>8+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">4</span><span style="background:var(--vt-palette-4)"> </span> Groceries<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-8)">│</span> Paste <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+V</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span>9+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">5</span><span style="background:var(--vt-palette-4)"> </span> Transit <span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-8)">├────────────────────────────────┤</span>10+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">6</span><span style="background:var(--vt-palette-4)"> </span> Savings r<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">#DI</span><span style="color:var(--vt-palette-8)">│</span> Insert column left <span style="color:var(--vt-palette-8)">│</span>11+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">7</span><span style="background:var(--vt-palette-4)"> </span> Total <span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">2</span><span style="color:var(--vt-palette-8)">│</span> Insert column right <span style="color:var(--vt-palette-8)">│</span>12+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">8</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-8)">├────────────────────────────────┤</span>13+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">9</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-8)">│</span> Delete column <span style="color:var(--vt-palette-8)">│</span>14+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">10</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-8)">│</span> Clear <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Del</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span>15+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">11</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-8)">├────────────────────────────────┤</span>16+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">12</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-8)">│</span> Resize column <span style="color:var(--vt-palette-8)">│</span>17+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">13</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-8)">│</span> Reset column width <span style="color:var(--vt-palette-8)">│</span>18+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">14</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-8)">└────────────────────────────────┘</span>19+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">15</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>20+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">16</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>21+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">17</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>22+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">18</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>23+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">19</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>24+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">20</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>25+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">21</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>26+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">22</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>27+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">23</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>28+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">24</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>29+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">25</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>30+Cut the selection, to move it where you paste <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Up/Down</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">move</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Enter</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">choose</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Esc</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">close</span></pre>\ No newline at end of file
A e2e/testdata/screens/context-menu-column.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">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">MENU</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)">B1:B8192</span><span style="background:var(--vt-palette-8)"> </span>3+4+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">A</span><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">B</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)">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> Household<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">bud</span><span style="color:var(--vt-palette-8)">┌────────────────────────────────┐</span>6+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">2</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </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)">Cut</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">Ctrl+X</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-8)">│</span>7+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">3</span><span style="background:var(--vt-palette-4)"> </span> Rent <span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-8)">│</span> Copy <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+C</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>8+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">4</span><span style="background:var(--vt-palette-4)"> </span> Groceries<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-8)">│</span> Paste <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+V</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>9+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">5</span><span style="background:var(--vt-palette-4)"> </span> Transit <span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-8)">├────────────────────────────────┤</span>10+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">6</span><span style="background:var(--vt-palette-4)"> </span> Savings r<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">#DI</span><span style="color:var(--vt-palette-8)">│</span> Insert column left <span style="color:var(--vt-palette-8)">│</span>11+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">7</span><span style="background:var(--vt-palette-4)"> </span> Total <span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">2</span><span style="color:var(--vt-palette-8)">│</span> Insert column right <span style="color:var(--vt-palette-8)">│</span>12+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">8</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-8)">├────────────────────────────────┤</span>13+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">9</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-8)">│</span> Delete column <span style="color:var(--vt-palette-8)">│</span>14+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">10</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-8)">│</span> Clear <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Del</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>15+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">11</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-8)">├────────────────────────────────┤</span>16+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">12</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-8)">│</span> Resize column <span style="color:var(--vt-palette-8)">│</span>17+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">13</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-8)">│</span> Reset column width <span style="color:var(--vt-palette-8)">│</span>18+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">14</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-8)">└────────────────────────────────┘</span>19+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">15</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>20+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">16</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>21+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">17</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>22+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">18</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>23+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">19</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>24+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">20</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>25+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">21</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>26+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">22</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>27+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">23</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>28+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">24</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>29+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">25</span><span style="background:var(--vt-palette-4)"> </span> <span style="background:var(--vt-palette-4)"> </span>30+Cut the selection, to move it where you paste <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)">choose</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
A e2e/testdata/screens/context-menu.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">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">MENU</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)">B4</span><span style="background:var(--vt-palette-8)"> </span> 612.43+4+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">A</span><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">B</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)">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-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1</span><span style="background:var(--vt-palette-8)"> </span> Household budget 20266+<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> Rent 14508+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">4</span><span style="background:var(--vt-palette-6)"> </span> Groceries<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">612.4</span><span style="background:var(--vt-palette-6)"> </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> Transit <span style="color: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> Savings r <span style="color:var(--vt-palette-1)">#DI</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)">Cut</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">Ctrl+X</span><span style="background:var(--vt-palette-6)"> </span><span style="color: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> Total 2<span style="color:var(--vt-palette-8)">│</span> Copy <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+C</span><span style="background:var(--vt-palette-8)"> </span> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> Paste <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+V</span><span style="background:var(--vt-palette-8)"> </span> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> Paste values only <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Shift+V</span><span style="background:var(--vt-palette-8)"> </span> <span style="color: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> <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> Insert row above <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> Insert row below <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> Insert column left <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> Insert column right <span style="color: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> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> Delete row <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> Delete column <span style="color: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> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> Clear <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Del</span><span style="background:var(--vt-palette-8)"> </span> <span style="color: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> <span style="color: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+Cut the selection, to move it where you paste <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)">choose</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
A e2e/testdata/screens/copy-marker-light.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">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">READY</span><span style="background:var(--vt-palette-6)"> </span>2+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">C2</span><span style="background:var(--vt-palette-7)"> </span>3+Copied B3:B5 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+V</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">paste</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+Shift+V</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">paste</span> <span style="color:var(--vt-palette-0)">values</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Esc</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">clear</span>4+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">A</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">B</span><span style="background:var(--vt-palette-7)"> </span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">C</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">D</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">E</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">F</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">G</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">H</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">I</span><span style="background:var(--vt-palette-7)"> </span>5+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1</span><span style="background:var(--vt-palette-7)"> </span> Household budget 20266+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">2</span><span style="background:var(--vt-palette-6)"> </span> <span style="background:var(--vt-palette-6)"> </span>7+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">3</span><span style="background:var(--vt-palette-7)"> </span> Rent <span style="text-decoration:underline"> </span><span style="color:var(--vt-palette-5);text-decoration:underline dashed">1450</span><span style="text-decoration:underline"> </span>8+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">4</span><span style="background:var(--vt-palette-7)"> </span> Groceries<span style="text-decoration:underline"> </span><span style="color:var(--vt-palette-5);text-decoration:underline dashed">612.4</span><span style="text-decoration:underline"> </span>9+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">5</span><span style="background:var(--vt-palette-7)"> </span> Transit <span style="text-decoration:underline"> </span><span style="color:var(--vt-palette-5);text-decoration:underline dashed">96</span><span style="text-decoration:underline"> </span>10+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">6</span><span style="background:var(--vt-palette-7)"> </span> Savings r <span style="color:var(--vt-palette-1)">#DIV/0!</span>11+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">7</span><span style="background:var(--vt-palette-7)"> </span> Total 2158.412+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">8</span><span style="background:var(--vt-palette-7)"> </span>13+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">9</span><span style="background:var(--vt-palette-7)"> </span>14+<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>15+<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>16+<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>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>18+<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>19+<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>20+<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>21+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">17</span><span style="background:var(--vt-palette-7)"> </span>22+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">18</span><span style="background:var(--vt-palette-7)"> </span>23+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">19</span><span style="background:var(--vt-palette-7)"> </span>24+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">20</span><span style="background:var(--vt-palette-7)"> </span>25+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">21</span><span style="background:var(--vt-palette-7)"> </span>26+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">22</span><span style="background:var(--vt-palette-7)"> </span>27+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">23</span><span style="background:var(--vt-palette-7)"> </span>28+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">24</span><span style="background:var(--vt-palette-7)"> </span>29+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">25</span><span style="background:var(--vt-palette-7)"> </span>30+untitled <span style="color:var(--vt-palette-0)">modified</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+K</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">search</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+/</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">shortcuts</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">F10</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">menu</span></pre>\ No newline at end of file
A e2e/testdata/screens/copy-marker-selected-light.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">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">READY</span><span style="background:var(--vt-palette-6)"> </span>2+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">A3:B5</span><span style="background:var(--vt-palette-7)"> </span> Rent3+Cut A3:B5 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+V</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">move</span> <span style="color:var(--vt-palette-0)">here</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Esc</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">cancel</span>4+<span style="background:var(--vt-palette-7)"> </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-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">B</span><span style="background:var(--vt-palette-4)"> </span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">C</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">D</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">E</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">F</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">G</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">H</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">I</span><span style="background:var(--vt-palette-7)"> </span>5+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1</span><span style="background:var(--vt-palette-7)"> </span> Household budget 20266+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">2</span><span style="background:var(--vt-palette-7)"> </span>7+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">3</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-6);text-decoration:underline"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);text-decoration:underline dashed">Rent</span><span style="background:var(--vt-palette-6);text-decoration:underline"> </span><span style="background:var(--vt-palette-4);text-decoration:underline"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4);text-decoration:underline dashed">1450</span><span style="background:var(--vt-palette-4);text-decoration:underline"> </span>8+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">4</span><span style="background:var(--vt-palette-4)"> </span><span style="background:var(--vt-palette-4);text-decoration:underline"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4);text-decoration:underline dashed">Groceries</span><span style="background:var(--vt-palette-4);text-decoration:underline"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4);text-decoration:underline dashed">612.4</span><span style="background:var(--vt-palette-4);text-decoration:underline"> </span>9+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">5</span><span style="background:var(--vt-palette-4)"> </span><span style="background:var(--vt-palette-4);text-decoration:underline"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4);text-decoration:underline dashed">Transit</span><span style="background:var(--vt-palette-4);text-decoration:underline"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4);text-decoration:underline dashed">96</span><span style="background:var(--vt-palette-4);text-decoration:underline"> </span>10+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">6</span><span style="background:var(--vt-palette-7)"> </span> Savings r <span style="color:var(--vt-palette-1)">#DIV/0!</span>11+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">7</span><span style="background:var(--vt-palette-7)"> </span> Total 2158.412+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">8</span><span style="background:var(--vt-palette-7)"> </span>13+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">9</span><span style="background:var(--vt-palette-7)"> </span>14+<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>15+<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>16+<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>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>18+<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>19+<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>20+<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>21+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">17</span><span style="background:var(--vt-palette-7)"> </span>22+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">18</span><span style="background:var(--vt-palette-7)"> </span>23+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">19</span><span style="background:var(--vt-palette-7)"> </span>24+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">20</span><span style="background:var(--vt-palette-7)"> </span>25+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">21</span><span style="background:var(--vt-palette-7)"> </span>26+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">22</span><span style="background:var(--vt-palette-7)"> </span>27+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">23</span><span style="background:var(--vt-palette-7)"> </span>28+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">24</span><span style="background:var(--vt-palette-7)"> </span>29+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">25</span><span style="background:var(--vt-palette-7)"> </span>30+untitled <span style="color:var(--vt-palette-0)">modified</span> <span style="font-weight:bold">A3:B5</span> <span style="color:var(--vt-palette-0)">Sum</span> 2158.4 <span style="color:var(--vt-palette-0)">Avg</span> 719.47 <span style="color:var(--vt-palette-0)">Count</span> 6</pre>\ No newline at end of file
A e2e/testdata/screens/copy-marker-selected.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">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">READY</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)">A3:B5</span><span style="background:var(--vt-palette-8)"> </span> Rent3+Cut A3:B5 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+V</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">move</span> <span style="color:var(--vt-palette-8)">here</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-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">B</span><span style="background:var(--vt-palette-4)"> </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-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1</span><span style="background:var(--vt-palette-8)"> </span> Household budget 20266+<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-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">3</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-6);text-decoration:underline"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);text-decoration:underline dashed">Rent</span><span style="background:var(--vt-palette-6);text-decoration:underline"> </span><span style="background:var(--vt-palette-4);text-decoration:underline"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4);text-decoration:underline dashed">1450</span><span style="background:var(--vt-palette-4);text-decoration:underline"> </span>8+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">4</span><span style="background:var(--vt-palette-4)"> </span><span style="background:var(--vt-palette-4);text-decoration:underline"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4);text-decoration:underline dashed">Groceries</span><span style="background:var(--vt-palette-4);text-decoration:underline"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4);text-decoration:underline dashed">612.4</span><span style="background:var(--vt-palette-4);text-decoration:underline"> </span>9+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">5</span><span style="background:var(--vt-palette-4)"> </span><span style="background:var(--vt-palette-4);text-decoration:underline"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4);text-decoration:underline dashed">Transit</span><span style="background:var(--vt-palette-4);text-decoration:underline"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4);text-decoration:underline dashed">96</span><span style="background:var(--vt-palette-4);text-decoration:underline"> </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> Savings r <span style="color:var(--vt-palette-1)">#DIV/0!</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> Total 2158.412+<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+untitled <span style="color:var(--vt-palette-8)">modified</span> <span style="font-weight:bold">A3:B5</span> <span style="color:var(--vt-palette-8)">Sum</span> 2158.4 <span style="color:var(--vt-palette-8)">Avg</span> 719.47 <span style="color:var(--vt-palette-8)">Count</span> 6</pre>\ No newline at end of file
A e2e/testdata/screens/copy-marker.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">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">READY</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)">C2</span><span style="background:var(--vt-palette-8)"> </span>3+Copied B3:B5 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+V</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">paste</span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Shift+V</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">paste</span> <span style="color:var(--vt-palette-8)">values</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)">clear</span>4+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">A</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="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">C</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)">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-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1</span><span style="background:var(--vt-palette-8)"> </span> Household budget 20266+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">2</span><span style="background:var(--vt-palette-6)"> </span> <span style="background:var(--vt-palette-6)"> </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> Rent <span style="text-decoration:underline"> </span><span style="color:var(--vt-palette-5);text-decoration:underline dashed">1450</span><span style="text-decoration:underline"> </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> Groceries<span style="text-decoration:underline"> </span><span style="color:var(--vt-palette-5);text-decoration:underline dashed">612.4</span><span style="text-decoration:underline"> </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> Transit <span style="text-decoration:underline"> </span><span style="color:var(--vt-palette-5);text-decoration:underline dashed">96</span><span style="text-decoration:underline"> </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> Savings r <span style="color:var(--vt-palette-1)">#DIV/0!</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> Total 2158.412+<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+untitled <span style="color:var(--vt-palette-8)">modified</span> <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
M e2e/testdata/screens/edit-error.html +30 -30
@@ -1,30 +1,30 @@
1-<pre class="screen"><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> A1 </span> <span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> EDIT</span><span style="background:var(--vt-palette-6)"> </span>2-=SUM(A13-<span style="color:var(--vt-palette-3)">Expected , or ) in SUM</span>4-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> A </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> B C D E F G H I </span>5-<span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> 1 </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)"> =SUM(A1 </span>6-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 2 </span>7-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 3 </span>8-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 4 </span>9-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 5 </span>10-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 6 </span>11-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 7 </span>12-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 8 </span>13-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 9 </span>14-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 10 </span>15-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 11 </span>16-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 12 </span>17-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 13 </span>18-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 14 </span>19-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 15 </span>20-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 16 </span>21-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 17 </span>22-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 18 </span>23-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 19 </span>24-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 20 </span>25-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 21 </span>26-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 22 </span>27-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 23 </span>28-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 24 </span>29-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 25 </span>30-untitled <span style="font-weight:bold">F1</span> <span style="color:var(--vt-palette-8)">help </span><span style="font-weight:bold">F10</span> <span style="color:var(--vt-palette-8)">menu </span><span style="font-weight:bold">Ctrl+Q</span> <span style="color:var(--vt-palette-8)">quit</span></pre>\ No newline at end of file1+<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">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">EDIT</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> =SUM(A13+<span style="color:var(--vt-palette-3)">Expected</span> <span style="color:var(--vt-palette-3)">,</span> <span style="color:var(--vt-palette-3)">or</span> <span style="color:var(--vt-palette-3)">)</span> <span style="color:var(--vt-palette-3)">in</span> <span style="color:var(--vt-palette-3)">SUM</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><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">=SUM(A1</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+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
M e2e/testdata/screens/entry-formula.html +30 -30
@@ -1,30 +1,30 @@
1-<pre class="screen"><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> B8 </span> <span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> ENTER</span><span style="background:var(--vt-palette-6)"> </span>2-=B7*123-<span style="font-weight:bold">Enter</span> <span style="color:var(--vt-palette-8)">accept </span><span style="font-weight:bold">Tab</span> <span style="color:var(--vt-palette-8)">accept and go right </span><span style="font-weight:bold">Arrows after an operator</span> <span style="color:var(--vt-palette-8)">pick cells </span><span style="font-weight:bold">Esc</span> <span style="color:var(--vt-palette-8)">cancel</span>4-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> A </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> B </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> C D E F G H I </span>5-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 1 </span> Household budget 20266-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 2 </span>7-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 3 </span> Rent 14508-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 4 </span> Groceries 612.49-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 5 </span> Transit 9610-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 6 </span> Savings r<span style="color:var(--vt-palette-1)"> #DIV/0! </span>11-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 7 </span> Total 2158.412-<span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> 8 </span> <span style="color:var(--vt-palette-0);background:var(--vt-palette-6)"> =B7*12 </span>13-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 9 </span>14-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 10 </span>15-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 11 </span>16-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 12 </span>17-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 13 </span>18-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 14 </span>19-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 15 </span>20-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 16 </span>21-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 17 </span>22-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 18 </span>23-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 19 </span>24-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 20 </span>25-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 21 </span>26-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 22 </span>27-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 23 </span>28-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 24 </span>29-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 25 </span>30-untitled<span style="color:var(--vt-palette-8)"> modified</span> <span style="font-weight:bold">F1</span> <span style="color:var(--vt-palette-8)">help </span><span style="font-weight:bold">F10</span> <span style="color:var(--vt-palette-8)">menu </span><span style="font-weight:bold">Ctrl+Q</span> <span style="color:var(--vt-palette-8)">quit</span></pre>\ No newline at end of file1+<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">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">ENTER</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)">B8</span><span style="background:var(--vt-palette-8)"> </span> =B7*123+<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)">accept</span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Tab</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">accept</span> <span style="color:var(--vt-palette-8)">and</span> <span style="color:var(--vt-palette-8)">go</span> <span style="color:var(--vt-palette-8)">right</span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Arrows</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">pick</span> <span style="color:var(--vt-palette-8)">cells</span> <span style="color:var(--vt-palette-8)">after</span> <span style="color:var(--vt-palette-8)">an</span> <span style="color:var(--vt-palette-8)">operator</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="color:var(--vt-palette-15);background:var(--vt-palette-8)">A</span><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">B</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)">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-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1</span><span style="background:var(--vt-palette-8)"> </span> Household budget 20266+<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> Rent 14508+<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> Groceries 612.49+<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> Transit 9610+<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> Savings r <span style="color:var(--vt-palette-1)">#DIV/0!</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> Total 2158.412+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">8</span><span style="background:var(--vt-palette-6)"> </span> <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">=B7*12</span><span style="background:var(--vt-palette-6)"> </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+untitled <span style="color:var(--vt-palette-8)">modified</span> <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
M e2e/testdata/screens/error-goto.html +29 -29
@@ -1,30 +1,30 @@
1-<pre class="screen"><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> A1 </span> <span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> ERROR</span><span style="background:var(--vt-palette-6)"> </span>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">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">ERROR</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>23 3-4-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> A </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> B C D E F G H I </span>5-<span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> 1 </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)"> </span>6-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 2 </span>7-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 3 </span>8-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 4 </span>9-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 5 </span>10-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 6 </span>11-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 7 </span>12-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 8 </span>13-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 9 </span>14-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 10 </span>15-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 11 </span>16-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 12 </span>17-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 13 </span>18-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 14 </span>19-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 15 </span>20-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 16 </span>21-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 17 </span>22-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 18 </span>23-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 19 </span>24-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 20 </span>25-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 21 </span>26-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 22 </span>27-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 23 </span>28-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 24 </span>29-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 25 </span>30-<span style="color:var(--vt-palette-9);font-weight:bold">Not a cell address: nope</span><span style="color:var(--vt-palette-8)"> press any key</span></pre>\ No newline at end of file4+<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="color:var(--vt-palette-9);font-weight:bold">Not</span> <span style="color:var(--vt-palette-9);font-weight:bold">a</span> <span style="color:var(--vt-palette-9);font-weight:bold">cell</span> <span style="color:var(--vt-palette-9);font-weight:bold">address:</span> <span style="color:var(--vt-palette-9);font-weight:bold">nope</span> <span style="color:var(--vt-palette-8)">press</span> <span style="color:var(--vt-palette-8)">any</span> <span style="color:var(--vt-palette-8)">key</span></pre>\ No newline at end of file
M e2e/testdata/screens/formats-light.html +30 -30
@@ -1,30 +1,30 @@
1-<pre class="screen"><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> A7 </span> Total <span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> READY</span><span style="background:var(--vt-palette-6)"> </span>2-3-<span style="color:var(--vt-palette-0)">Bold on for A7:D7</span>4-<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> A </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)"> B C D </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> E F G H I </span>5-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 1 </span> <span style="font-weight:bold">Bills for October</span>6-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 2 </span> <span style="font-weight:bold">Item</span> <span style="font-weight:bold">Due</span> <span style="font-weight:bold">Amount</span> <span style="font-weight:bold">Share</span>7-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 3 </span> Rent 10/1/2026 $1,450.00 65.96%8-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 4 </span> Food 9/28/2026 $612.40 27.86%9-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 5 </span> Transit 9/30/2026 $96.00 4.37%10-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 6 </span> <span style="text-decoration:line-through">Gym</span> <span style="text-decoration:line-through">10/5/2026</span> <span style="text-decoration:line-through">$40.00</span> <span style="text-decoration:line-through">1.82%</span>11-<span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> 7 </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">Total</span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4);font-weight:bold">$2,198.40</span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4);font-weight:bold">100.00%</span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)"> </span>12-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 8 </span>13-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 9 </span> <span style="font-style:italic">Gym cancelled from November</span>14-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 10 </span>15-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 11 </span>16-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 12 </span>17-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 13 </span>18-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 14 </span>19-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 15 </span>20-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 16 </span>21-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 17 </span>22-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 18 </span>23-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 19 </span>24-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 20 </span>25-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 21 </span>26-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 22 </span>27-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 23 </span>28-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 24 </span>29-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 25 </span>30-untitled<span style="color:var(--vt-palette-0)"> modified</span> <span style="font-weight:bold">A7:D7</span> <span style="color:var(--vt-palette-0)">Sum </span>2199.4 <span style="color:var(--vt-palette-0)">Avg </span>1099.7 <span style="color:var(--vt-palette-0)">Count </span>3</pre>\ No newline at end of file1+<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">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">READY</span><span style="background:var(--vt-palette-6)"> </span>2+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">A7:D7</span><span style="background:var(--vt-palette-7)"> </span> Total3+Bold on for A7:D74+<span style="background:var(--vt-palette-7)"> </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-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">B</span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">C</span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">D</span><span style="background:var(--vt-palette-4)"> </span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">E</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">F</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">G</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">H</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">I</span><span style="background:var(--vt-palette-7)"> </span>5+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1</span><span style="background:var(--vt-palette-7)"> </span> <span style="font-weight:bold">Bills</span> <span style="font-weight:bold">for</span> <span style="font-weight:bold">October</span>6+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">2</span><span style="background:var(--vt-palette-7)"> </span> <span style="font-weight:bold">Item</span> <span style="font-weight:bold">Due</span> <span style="font-weight:bold">Amount</span> <span style="font-weight:bold">Share</span>7+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">3</span><span style="background:var(--vt-palette-7)"> </span> Rent 10/1/2026 $1,450.00 65.96%8+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">4</span><span style="background:var(--vt-palette-7)"> </span> Food 9/28/2026 $612.40 27.86%9+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">5</span><span style="background:var(--vt-palette-7)"> </span> Transit 9/30/2026 $96.00 4.37%10+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">6</span><span style="background:var(--vt-palette-7)"> </span> <span style="text-decoration:line-through">Gym</span> <span style="text-decoration:line-through">10/5/2026</span> <span style="text-decoration:line-through">$40.00</span> <span style="text-decoration:line-through">1.82%</span>11+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">7</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">Total</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4);font-weight:bold">$2,198.40</span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4);font-weight:bold">100.00%</span><span style="background:var(--vt-palette-4)"> </span>12+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">8</span><span style="background:var(--vt-palette-7)"> </span>13+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">9</span><span style="background:var(--vt-palette-7)"> </span> <span style="font-style:italic">Gym</span> <span style="font-style:italic">cancelled</span> <span style="font-style:italic">from</span> <span style="font-style:italic">November</span>14+<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>15+<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>16+<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>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>18+<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>19+<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>20+<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>21+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">17</span><span style="background:var(--vt-palette-7)"> </span>22+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">18</span><span style="background:var(--vt-palette-7)"> </span>23+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">19</span><span style="background:var(--vt-palette-7)"> </span>24+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">20</span><span style="background:var(--vt-palette-7)"> </span>25+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">21</span><span style="background:var(--vt-palette-7)"> </span>26+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">22</span><span style="background:var(--vt-palette-7)"> </span>27+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">23</span><span style="background:var(--vt-palette-7)"> </span>28+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">24</span><span style="background:var(--vt-palette-7)"> </span>29+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">25</span><span style="background:var(--vt-palette-7)"> </span>30+untitled <span style="color:var(--vt-palette-0)">modified</span> <span style="font-weight:bold">A7:D7</span> <span style="color:var(--vt-palette-0)">Sum</span> 2199.4 <span style="color:var(--vt-palette-0)">Avg</span> 1099.7 <span style="color:var(--vt-palette-0)">Count</span> 3</pre>\ No newline at end of file
M e2e/testdata/screens/formats-narrow.html +16 -16
@@ -1,16 +1,16 @@
1-<pre class="screen"><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> A7 </span> Total <span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> READY</span><span style="background:var(--vt-palette-6)"> </span>2-3-<span style="color:var(--vt-palette-8)">Bold on for A7:D7</span>4-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> A </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> B C D </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> E </span>5-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 1 </span> <span style="font-weight:bold">Bills for October</span>6-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 2 </span> <span style="font-weight:bold">Item</span> <span style="font-weight:bold">Due</span> <span style="font-weight:bold">Amount</span> <span style="font-weight:bold">Share</span>7-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 3 </span> Rent 10/1/2026 $1,450.00 65.96%8-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 4 </span> Food 9/28/2026 $612.40 27.86%9-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 5 </span> Transit 9/30/2026 $96.00 4.37%10-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 6 </span> <span style="text-decoration:line-through">Gym</span> <span style="text-decoration:line-through">10/5/2026</span> <span style="text-decoration:line-through">$40.00</span> <span style="text-decoration:line-through">1.82%</span>11-<span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> 7 </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">Total</span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4);font-weight:bold">$2,198.40</span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4);font-weight:bold">100.00%</span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> </span>12-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 8 </span>13-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 9 </span> <span style="font-style:italic">Gym cancelled from November</span>14-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 10 </span>15-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 11 </span>16-untitled<span style="color:var(--vt-palette-8)"> modified</span> <span style="font-weight:bold">A7:D7</span> <span style="color:var(--vt-palette-8)">Sum </span>2199.4 <span style="color:var(--vt-palette-8)">Avg </span>1099.7 <span style="color:var(--vt-palette-8)">Count </span>3</pre>\ No newline at end of file1+<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">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">READY</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)">A7:D7</span><span style="background:var(--vt-palette-8)"> </span> Total3+Bold on for A7:D74+<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-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">B</span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">C</span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">D</span><span style="background:var(--vt-palette-4)"> </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>5+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1</span><span style="background:var(--vt-palette-8)"> </span> <span style="font-weight:bold">Bills</span> <span style="font-weight:bold">for</span> <span style="font-weight:bold">October</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> <span style="font-weight:bold">Item</span> <span style="font-weight:bold">Due</span> <span style="font-weight:bold">Amount</span> <span style="font-weight:bold">Share</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> Rent 10/1/2026 $1,450.00 65.96%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> Food 9/28/2026 $612.40 27.86%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> Transit 9/30/2026 $96.00 4.37%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> <span style="text-decoration:line-through">Gym</span> <span style="text-decoration:line-through">10/5/2026</span> <span style="text-decoration:line-through">$40.00</span> <span style="text-decoration:line-through">1.82%</span>11+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">7</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">Total</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4);font-weight:bold">$2,198.40</span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4);font-weight:bold">100.00%</span><span style="background:var(--vt-palette-4)"> </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> <span style="font-style:italic">Gym</span> <span style="font-style:italic">cancelled</span> <span style="font-style:italic">from</span> <span style="font-style:italic">November</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+untitled <span style="color:var(--vt-palette-8)">modified</span> <span style="font-weight:bold">A7:D7</span> <span style="color:var(--vt-palette-8)">Sum</span> 2199.4 <span style="color:var(--vt-palette-8)">Avg</span> 1099.7 <span style="color:var(--vt-palette-8)">Count</span> 3</pre>\ No newline at end of file
M e2e/testdata/screens/formats.html +30 -30
@@ -1,30 +1,30 @@
1-<pre class="screen"><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> A7 </span> Total <span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> READY</span><span style="background:var(--vt-palette-6)"> </span>2-3-<span style="color:var(--vt-palette-8)">Bold on for A7:D7</span>4-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> A </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> B C D </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> E F G H I </span>5-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 1 </span> <span style="font-weight:bold">Bills for October</span>6-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 2 </span> <span style="font-weight:bold">Item</span> <span style="font-weight:bold">Due</span> <span style="font-weight:bold">Amount</span> <span style="font-weight:bold">Share</span>7-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 3 </span> Rent 10/1/2026 $1,450.00 65.96%8-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 4 </span> Food 9/28/2026 $612.40 27.86%9-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 5 </span> Transit 9/30/2026 $96.00 4.37%10-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 6 </span> <span style="text-decoration:line-through">Gym</span> <span style="text-decoration:line-through">10/5/2026</span> <span style="text-decoration:line-through">$40.00</span> <span style="text-decoration:line-through">1.82%</span>11-<span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> 7 </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">Total</span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4);font-weight:bold">$2,198.40</span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4);font-weight:bold">100.00%</span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> </span>12-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 8 </span>13-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 9 </span> <span style="font-style:italic">Gym cancelled from November</span>14-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 10 </span>15-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 11 </span>16-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 12 </span>17-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 13 </span>18-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 14 </span>19-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 15 </span>20-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 16 </span>21-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 17 </span>22-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 18 </span>23-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 19 </span>24-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 20 </span>25-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 21 </span>26-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 22 </span>27-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 23 </span>28-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 24 </span>29-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 25 </span>30-untitled<span style="color:var(--vt-palette-8)"> modified</span> <span style="font-weight:bold">A7:D7</span> <span style="color:var(--vt-palette-8)">Sum </span>2199.4 <span style="color:var(--vt-palette-8)">Avg </span>1099.7 <span style="color:var(--vt-palette-8)">Count </span>3</pre>\ No newline at end of file1+<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">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">READY</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)">A7:D7</span><span style="background:var(--vt-palette-8)"> </span> Total3+Bold on for A7:D74+<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-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">B</span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">C</span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">D</span><span style="background:var(--vt-palette-4)"> </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-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1</span><span style="background:var(--vt-palette-8)"> </span> <span style="font-weight:bold">Bills</span> <span style="font-weight:bold">for</span> <span style="font-weight:bold">October</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> <span style="font-weight:bold">Item</span> <span style="font-weight:bold">Due</span> <span style="font-weight:bold">Amount</span> <span style="font-weight:bold">Share</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> Rent 10/1/2026 $1,450.00 65.96%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> Food 9/28/2026 $612.40 27.86%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> Transit 9/30/2026 $96.00 4.37%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> <span style="text-decoration:line-through">Gym</span> <span style="text-decoration:line-through">10/5/2026</span> <span style="text-decoration:line-through">$40.00</span> <span style="text-decoration:line-through">1.82%</span>11+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">7</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">Total</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4);font-weight:bold">$2,198.40</span><span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4);font-weight:bold">100.00%</span><span style="background:var(--vt-palette-4)"> </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> <span style="font-style:italic">Gym</span> <span style="font-style:italic">cancelled</span> <span style="font-style:italic">from</span> <span style="font-style:italic">November</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+untitled <span style="color:var(--vt-palette-8)">modified</span> <span style="font-weight:bold">A7:D7</span> <span style="color:var(--vt-palette-8)">Sum</span> 2199.4 <span style="color:var(--vt-palette-8)">Avg</span> 1099.7 <span style="color:var(--vt-palette-8)">Count</span> 3</pre>\ No newline at end of file
A e2e/testdata/screens/functions-light.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">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">MENU</span><span style="background:var(--vt-palette-6)"> </span>2+<span style="color:var(--vt-palette-8)">┌─</span> <span style="font-weight:bold">Functions</span> <span style="color:var(--vt-palette-8)">──────────────────────────────────────────────────────────────────────────────────────┐</span>3+<span style="color:var(--vt-palette-8)">│</span> <span style="font-weight:bold">›</span> if <span style="color:var(--vt-palette-8)">│</span>4+<span style="color:var(--vt-palette-8)">├──────────────────────────────────────────────────────────────────────────────────────────────────┤</span>5+<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);font-weight:bold;text-decoration:underline">IF</span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">(condition,</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">value_if_true,</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">[value_if_false])</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">Choose</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">a</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">value</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">by</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">a</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">condition</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-8)">│</span>6+<span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-4);font-weight:bold">IF</span>S(condition1, value1, [condition2, value2, ...]) <span style="color:var(--vt-palette-0)">The</span> <span style="color:var(--vt-palette-0)">value</span> <span style="color:var(--vt-palette-0)">of</span> <span style="color:var(--vt-palette-0)">the</span> <span style="color:var(--vt-palette-0)">first</span> <span style="color:var(--vt-palette-0)">true</span> <span style="color:var(--vt-palette-0)">condi…</span> <span style="color:var(--vt-palette-8)">│</span>7+<span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-4);font-weight:bold">IF</span>NA(value, value_if_na) <span style="color:var(--vt-palette-0)">A</span> <span style="color:var(--vt-palette-0)">fallback</span> <span style="color:var(--vt-palette-0)">when</span> <span style="color:var(--vt-palette-0)">a</span> <span style="color:var(--vt-palette-0)">value</span> <span style="color:var(--vt-palette-0)">is</span> <span style="color:var(--vt-palette-0)">#N/A</span> <span style="color:var(--vt-palette-8)">│</span>8+<span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-4);font-weight:bold">IF</span>ERROR(value, [value_if_error]) <span style="color:var(--vt-palette-0)">A</span> <span style="color:var(--vt-palette-0)">fallback</span> <span style="color:var(--vt-palette-0)">when</span> <span style="color:var(--vt-palette-0)">a</span> <span style="color:var(--vt-palette-0)">value</span> <span style="color:var(--vt-palette-0)">is</span> <span style="color:var(--vt-palette-0)">an</span> <span style="color:var(--vt-palette-0)">err…</span> <span style="color:var(--vt-palette-8)">│</span>9+<span style="color:var(--vt-palette-8)">│</span> SUM<span style="color:var(--vt-palette-4);font-weight:bold">IF</span>(range, criterion, [sum_range]) <span style="color:var(--vt-palette-0)">Sum</span> <span style="color:var(--vt-palette-0)">of</span> <span style="color:var(--vt-palette-0)">the</span> <span style="color:var(--vt-palette-0)">cells</span> <span style="color:var(--vt-palette-0)">that</span> <span style="color:var(--vt-palette-0)">meet</span> <span style="color:var(--vt-palette-0)">a</span> <span style="color:var(--vt-palette-0)">cond…</span> <span style="color:var(--vt-palette-8)">│</span>10+<span style="color:var(--vt-palette-8)">│</span> SUM<span style="color:var(--vt-palette-4);font-weight:bold">IF</span>S(sum_range, criteria_range1, criterion1, [criteria_… <span style="color:var(--vt-palette-0)">Sum</span> <span style="color:var(--vt-palette-0)">of</span> <span style="color:var(--vt-palette-0)">the</span> <span style="color:var(--vt-palette-0)">cells</span> <span style="color:var(--vt-palette-0)">that</span> <span style="color:var(--vt-palette-0)">meet</span> <span style="color:var(--vt-palette-0)">every</span> <span style="color:var(--vt-palette-0)">…</span> <span style="color:var(--vt-palette-8)">│</span>11+<span style="color:var(--vt-palette-8)">│</span> COUNT<span style="color:var(--vt-palette-4);font-weight:bold">IF</span>(range, criterion) <span style="color:var(--vt-palette-0)">Count</span> <span style="color:var(--vt-palette-0)">of</span> <span style="color:var(--vt-palette-0)">the</span> <span style="color:var(--vt-palette-0)">cells</span> <span style="color:var(--vt-palette-0)">that</span> <span style="color:var(--vt-palette-0)">meet</span> <span style="color:var(--vt-palette-0)">a</span> <span style="color:var(--vt-palette-0)">co…</span> <span style="color:var(--vt-palette-8)">│</span>12+<span style="color:var(--vt-palette-8)">│</span> DATED<span style="color:var(--vt-palette-4);font-weight:bold">IF</span>(start_date, end_date, unit) <span style="color:var(--vt-palette-0)">Time</span> <span style="color:var(--vt-palette-0)">between</span> <span style="color:var(--vt-palette-0)">dates</span> <span style="color:var(--vt-palette-0)">in</span> <span style="color:var(--vt-palette-0)">&#34;Y&#34;,</span> <span style="color:var(--vt-palette-0)">&#34;M&#34;,</span> <span style="color:var(--vt-palette-0)">&#34;…</span> <span style="color:var(--vt-palette-8)">│</span>13+<span style="color:var(--vt-palette-8)">│</span> COUNT<span style="color:var(--vt-palette-4);font-weight:bold">IF</span>S(criteria_range1, criterion1, [criteria_range2, c… <span style="color:var(--vt-palette-0)">Count</span> <span style="color:var(--vt-palette-0)">of</span> <span style="color:var(--vt-palette-0)">the</span> <span style="color:var(--vt-palette-0)">cells</span> <span style="color:var(--vt-palette-0)">that</span> <span style="color:var(--vt-palette-0)">meet</span> <span style="color:var(--vt-palette-0)">ever…</span> <span style="color:var(--vt-palette-8)">│</span>14+<span style="color:var(--vt-palette-8)">│</span> AVERAGE<span style="color:var(--vt-palette-4);font-weight:bold">IF</span>(criteria_range, criterion, [average_range]) <span style="color:var(--vt-palette-0)">Average</span> <span style="color:var(--vt-palette-0)">of</span> <span style="color:var(--vt-palette-0)">the</span> <span style="color:var(--vt-palette-0)">cells</span> <span style="color:var(--vt-palette-0)">that</span> <span style="color:var(--vt-palette-0)">meet</span> <span style="color:var(--vt-palette-0)">a</span> <span style="color:var(--vt-palette-0)">…</span> <span style="color:var(--vt-palette-8)">│</span>15+<span style="color:var(--vt-palette-8)">│</span> AVERAGE<span style="color:var(--vt-palette-4);font-weight:bold">IF</span>S(average_range, criteria_range1, criterion1, [c… <span style="color:var(--vt-palette-0)">Average</span> <span style="color:var(--vt-palette-0)">of</span> <span style="color:var(--vt-palette-0)">the</span> <span style="color:var(--vt-palette-0)">cells</span> <span style="color:var(--vt-palette-0)">that</span> <span style="color:var(--vt-palette-0)">meet</span> <span style="color:var(--vt-palette-0)">ev…</span> <span style="color:var(--vt-palette-8)">│</span>16+<span style="color:var(--vt-palette-8)">│</span> ISLOGICAL(value) <span style="color:var(--vt-palette-0)">TRUE</span> <span style="color:var(--vt-palette-4);font-weight:bold">i</span><span style="color:var(--vt-palette-0)">f</span> <span style="color:var(--vt-palette-0)">a</span> <span style="color:var(--vt-palette-0)">value</span> <span style="color:var(--vt-palette-0)">is</span> <span style="color:var(--vt-palette-0)">TRUE</span> <span style="color:var(--vt-palette-0)">or</span> <span style="color:var(--vt-palette-4);font-weight:bold">F</span><span style="color:var(--vt-palette-0)">ALSE</span> <span style="color:var(--vt-palette-8)">│</span>17+<span style="color:var(--vt-palette-8)">└──────────────────────────────────────────────────────────────────────────────────────</span> <span style="color:var(--vt-palette-0)">62</span> <span style="color:var(--vt-palette-0)">of</span> <span style="color:var(--vt-palette-0)">115</span> <span style="color:var(--vt-palette-8)">─┘</span>18+<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>19+<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>20+<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>21+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">17</span><span style="background:var(--vt-palette-7)"> </span>22+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">18</span><span style="background:var(--vt-palette-7)"> </span>23+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">19</span><span style="background:var(--vt-palette-7)"> </span>24+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">20</span><span style="background:var(--vt-palette-7)"> </span>25+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">21</span><span style="background:var(--vt-palette-7)"> </span>26+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">22</span><span style="background:var(--vt-palette-7)"> </span>27+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">23</span><span style="background:var(--vt-palette-7)"> </span>28+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">24</span><span style="background:var(--vt-palette-7)"> </span>29+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">25</span><span style="background:var(--vt-palette-7)"> </span>30+Choose a value by a condition <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Up/Down</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">move</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Enter</span><span style="background:var(--vt-palette-7)"> </span> <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)">Esc</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">close</span></pre>\ No newline at end of file
A e2e/testdata/screens/functions.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">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">MENU</span><span style="background:var(--vt-palette-6)"> </span>2+<span style="color:var(--vt-palette-8)">┌─</span> <span style="font-weight:bold">Functions</span> <span style="color:var(--vt-palette-8)">──────────────────────────────────────────────────────────────────────────────────────┐</span>3+<span style="color:var(--vt-palette-8)">│</span> <span style="font-weight:bold">›</span> if <span style="color:var(--vt-palette-8)">│</span>4+<span style="color:var(--vt-palette-8)">├──────────────────────────────────────────────────────────────────────────────────────────────────┤</span>5+<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);font-weight:bold;text-decoration:underline">IF</span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">(condition,</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">value_if_true,</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">[value_if_false])</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">Choose</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">a</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">value</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">by</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">a</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">condition</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-8)">│</span>6+<span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-3);font-weight:bold">IF</span>S(condition1, value1, [condition2, value2, ...]) <span style="color:var(--vt-palette-8)">The</span> <span style="color:var(--vt-palette-8)">value</span> <span style="color:var(--vt-palette-8)">of</span> <span style="color:var(--vt-palette-8)">the</span> <span style="color:var(--vt-palette-8)">first</span> <span style="color:var(--vt-palette-8)">true</span> <span style="color:var(--vt-palette-8)">condi…</span> <span style="color:var(--vt-palette-8)">│</span>7+<span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-3);font-weight:bold">IF</span>NA(value, value_if_na) <span style="color:var(--vt-palette-8)">A</span> <span style="color:var(--vt-palette-8)">fallback</span> <span style="color:var(--vt-palette-8)">when</span> <span style="color:var(--vt-palette-8)">a</span> <span style="color:var(--vt-palette-8)">value</span> <span style="color:var(--vt-palette-8)">is</span> <span style="color:var(--vt-palette-8)">#N/A</span> <span style="color:var(--vt-palette-8)">│</span>8+<span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-3);font-weight:bold">IF</span>ERROR(value, [value_if_error]) <span style="color:var(--vt-palette-8)">A</span> <span style="color:var(--vt-palette-8)">fallback</span> <span style="color:var(--vt-palette-8)">when</span> <span style="color:var(--vt-palette-8)">a</span> <span style="color:var(--vt-palette-8)">value</span> <span style="color:var(--vt-palette-8)">is</span> <span style="color:var(--vt-palette-8)">an</span> <span style="color:var(--vt-palette-8)">err…</span> <span style="color:var(--vt-palette-8)">│</span>9+<span style="color:var(--vt-palette-8)">│</span> SUM<span style="color:var(--vt-palette-3);font-weight:bold">IF</span>(range, criterion, [sum_range]) <span style="color:var(--vt-palette-8)">Sum</span> <span style="color:var(--vt-palette-8)">of</span> <span style="color:var(--vt-palette-8)">the</span> <span style="color:var(--vt-palette-8)">cells</span> <span style="color:var(--vt-palette-8)">that</span> <span style="color:var(--vt-palette-8)">meet</span> <span style="color:var(--vt-palette-8)">a</span> <span style="color:var(--vt-palette-8)">cond…</span> <span style="color:var(--vt-palette-8)">│</span>10+<span style="color:var(--vt-palette-8)">│</span> SUM<span style="color:var(--vt-palette-3);font-weight:bold">IF</span>S(sum_range, criteria_range1, criterion1, [criteria_… <span style="color:var(--vt-palette-8)">Sum</span> <span style="color:var(--vt-palette-8)">of</span> <span style="color:var(--vt-palette-8)">the</span> <span style="color:var(--vt-palette-8)">cells</span> <span style="color:var(--vt-palette-8)">that</span> <span style="color:var(--vt-palette-8)">meet</span> <span style="color:var(--vt-palette-8)">every</span> <span style="color:var(--vt-palette-8)">…</span> <span style="color:var(--vt-palette-8)">│</span>11+<span style="color:var(--vt-palette-8)">│</span> COUNT<span style="color:var(--vt-palette-3);font-weight:bold">IF</span>(range, criterion) <span style="color:var(--vt-palette-8)">Count</span> <span style="color:var(--vt-palette-8)">of</span> <span style="color:var(--vt-palette-8)">the</span> <span style="color:var(--vt-palette-8)">cells</span> <span style="color:var(--vt-palette-8)">that</span> <span style="color:var(--vt-palette-8)">meet</span> <span style="color:var(--vt-palette-8)">a</span> <span style="color:var(--vt-palette-8)">co…</span> <span style="color:var(--vt-palette-8)">│</span>12+<span style="color:var(--vt-palette-8)">│</span> DATED<span style="color:var(--vt-palette-3);font-weight:bold">IF</span>(start_date, end_date, unit) <span style="color:var(--vt-palette-8)">Time</span> <span style="color:var(--vt-palette-8)">between</span> <span style="color:var(--vt-palette-8)">dates</span> <span style="color:var(--vt-palette-8)">in</span> <span style="color:var(--vt-palette-8)">&#34;Y&#34;,</span> <span style="color:var(--vt-palette-8)">&#34;M&#34;,</span> <span style="color:var(--vt-palette-8)">&#34;…</span> <span style="color:var(--vt-palette-8)">│</span>13+<span style="color:var(--vt-palette-8)">│</span> COUNT<span style="color:var(--vt-palette-3);font-weight:bold">IF</span>S(criteria_range1, criterion1, [criteria_range2, c… <span style="color:var(--vt-palette-8)">Count</span> <span style="color:var(--vt-palette-8)">of</span> <span style="color:var(--vt-palette-8)">the</span> <span style="color:var(--vt-palette-8)">cells</span> <span style="color:var(--vt-palette-8)">that</span> <span style="color:var(--vt-palette-8)">meet</span> <span style="color:var(--vt-palette-8)">ever…</span> <span style="color:var(--vt-palette-8)">│</span>14+<span style="color:var(--vt-palette-8)">│</span> AVERAGE<span style="color:var(--vt-palette-3);font-weight:bold">IF</span>(criteria_range, criterion, [average_range]) <span style="color:var(--vt-palette-8)">Average</span> <span style="color:var(--vt-palette-8)">of</span> <span style="color:var(--vt-palette-8)">the</span> <span style="color:var(--vt-palette-8)">cells</span> <span style="color:var(--vt-palette-8)">that</span> <span style="color:var(--vt-palette-8)">meet</span> <span style="color:var(--vt-palette-8)">a</span> <span style="color:var(--vt-palette-8)">…</span> <span style="color:var(--vt-palette-8)">│</span>15+<span style="color:var(--vt-palette-8)">│</span> AVERAGE<span style="color:var(--vt-palette-3);font-weight:bold">IF</span>S(average_range, criteria_range1, criterion1, [c… <span style="color:var(--vt-palette-8)">Average</span> <span style="color:var(--vt-palette-8)">of</span> <span style="color:var(--vt-palette-8)">the</span> <span style="color:var(--vt-palette-8)">cells</span> <span style="color:var(--vt-palette-8)">that</span> <span style="color:var(--vt-palette-8)">meet</span> <span style="color:var(--vt-palette-8)">ev…</span> <span style="color:var(--vt-palette-8)">│</span>16+<span style="color:var(--vt-palette-8)">│</span> ISLOGICAL(value) <span style="color:var(--vt-palette-8)">TRUE</span> <span style="color:var(--vt-palette-3);font-weight:bold">i</span><span style="color:var(--vt-palette-8)">f</span> <span style="color:var(--vt-palette-8)">a</span> <span style="color:var(--vt-palette-8)">value</span> <span style="color:var(--vt-palette-8)">is</span> <span style="color:var(--vt-palette-8)">TRUE</span> <span style="color:var(--vt-palette-8)">or</span> <span style="color:var(--vt-palette-3);font-weight:bold">F</span><span style="color:var(--vt-palette-8)">ALSE</span> <span style="color:var(--vt-palette-8)">│</span>17+<span style="color:var(--vt-palette-8)">└──────────────────────────────────────────────────────────────────────────────────────</span> <span style="color:var(--vt-palette-8)">62</span> <span style="color:var(--vt-palette-8)">of</span> <span style="color:var(--vt-palette-8)">115</span> <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>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+Choose a value by a condition <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)">insert</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/help-light.html +30 -30
@@ -1,30 +1,30 @@
1-<pre class="screen"><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> HELP </span> Keyboard shortcuts <span style="color:var(--vt-palette-0)">(press any key to return)</span>2-3- Arrows Move Shift+arrows Select4- Ctrl+arrows Jump to the edge of the data (add Shift to select)5- Tab / Shift+Tab Right / left PgUp / PgDn Screen up / down6- Home / Ctrl+Home Column A / A1 Ctrl+End Last used cell7- Mouse Click, drag or Shift+click to select; click headers8- for whole columns or rows; double-click to edit9-10- Ctrl+B Make text bold, or plain again11- Ctrl+Shift+E Center horizontally12- Backspace / Del Clear the contents of the selected cells13- Ctrl+\ Reset number formats and text styles, keeping contents14- Ctrl+Shift+4 Currency: $1,000.1215- Ctrl+Shift+3 Date: 9/26/202616- Esc Collapse the selection to the active cell17- Enter / F2 Edit the active cell&#39;s contents18- Ctrl+G / F5 Move to a cell address19- Ctrl+I Make text italic, or upright again20- Ctrl+Shift+L Align to the left21- F10 Open the menu22- Ctrl+Shift+1 Number with thousands separators: 1,000.1223- Ctrl+O Open a sheet, replacing this one24- Ctrl+Shift+5 Percent: 10.12%25- Ctrl+Q Close one2326- Ctrl+Shift+R Align to the right27- Ctrl+S Save the sheet28- Ctrl+Shift+6 Scientific notation: 1.01E+0329- Ctrl+A Select the data, then the whole sheet30- Ctrl+Space Select the whole columns of the selection</pre>\ No newline at end of file1+<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">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">HELP</span><span style="background:var(--vt-palette-6)"> </span>2+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">A1</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">┌─</span> <span style="font-weight:bold">Keyboard</span> <span style="font-weight:bold">shortcuts</span> <span style="color:var(--vt-palette-8)">──────────────────────────────────────────────────┐</span>3+ <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span>4+<span style="background:var(--vt-palette-7)"> </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="color:var(--vt-palette-8)">│</span> <span style="font-weight:bold">Moving</span> <span style="font-weight:bold">around</span> <span style="color:var(--vt-palette-8)">│</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">I</span><span style="background:var(--vt-palette-7)"> </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><span style="color:var(--vt-palette-8)">│</span> Move <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Arrows</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span>6+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">2</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> Jump to the edge of the data <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+arrows</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span>7+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">3</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> Right, left <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Tab</span><span style="background:var(--vt-palette-7)"> </span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Shift+Tab</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span>8+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">4</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> Screen up, down <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">PgUp</span><span style="background:var(--vt-palette-7)"> </span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">PgDn</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span>9+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">5</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> Screen left, right <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Alt+PgUp</span><span style="background:var(--vt-palette-7)"> </span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Alt+PgDn</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span>10+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">6</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> Column A, cell A1 <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Home</span><span style="background:var(--vt-palette-7)"> </span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+Home</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span>11+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">7</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> Last used cell <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+End</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span>12+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">8</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> Go to <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+G</span><span style="background:var(--vt-palette-7)"> </span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">F5</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span>13+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">9</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span>14+<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> <span style="font-weight:bold">Selecting</span> <span style="color:var(--vt-palette-8)">│</span>15+<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> Extend the selection <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Shift+arrows</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span>16+<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> Extend to the edge of the data <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+Shift+arrows</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> Select by dragging or Shift+click <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Mouse</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span>18+<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> <span style="color:var(--vt-palette-8)">│</span> Deselect <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Esc</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span>19+<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> <span style="color:var(--vt-palette-8)">│</span> Select all <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+A</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span>20+<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> <span style="color:var(--vt-palette-8)">│</span> Select columns <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+Space</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span>21+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">17</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> Select rows <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Shift+Space</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span>22+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">18</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span>23+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">19</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="font-weight:bold">Entering</span> <span style="font-weight:bold">data</span> <span style="color:var(--vt-palette-8)">│</span>24+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">20</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> Replace the cell; = starts a formula <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Type</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span>25+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">21</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> Accept and move down, right <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Enter</span><span style="background:var(--vt-palette-7)"> </span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Tab</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span>26+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">22</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> Pick cells for a formula <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Arrows</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span>27+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">23</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> Cancel the entry <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Esc</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span>28+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">24</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">└──────────────────────────────────────────────────────────</span> <span style="color:var(--vt-palette-0)">1-25</span> <span style="color:var(--vt-palette-0)">of</span> <span style="color:var(--vt-palette-0)">69</span> <span style="color:var(--vt-palette-8)">─┘</span>29+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">25</span><span style="background:var(--vt-palette-7)"> </span>30+ <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Up/Down</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">scroll</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Esc</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">close</span></pre>\ No newline at end of file
A e2e/testdata/screens/help-narrow.html +16 -0
@@ -0,0 +1,16 @@
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">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">HELP</span><span style="background:var(--vt-palette-6)"> </span>2+<span style="color:var(--vt-palette-8)">┌─</span> <span style="font-weight:bold">Keyboard</span> <span style="font-weight:bold">shortcuts</span> <span style="color:var(--vt-palette-8)">────────────────────────────────────┐</span>3+<span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span>4+<span style="color:var(--vt-palette-8)">│</span> <span style="font-weight:bold">Moving</span> <span style="font-weight:bold">around</span> <span style="color:var(--vt-palette-8)">│</span>5+<span style="color:var(--vt-palette-8)">│</span> Move <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Arrows</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>6+<span style="color:var(--vt-palette-8)">│</span> Jump to the edge of t… <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+arrows</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>7+<span style="color:var(--vt-palette-8)">│</span> Right, left <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Tab</span><span style="background:var(--vt-palette-8)"> </span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Shift+Tab</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>8+<span style="color:var(--vt-palette-8)">│</span> Screen up, down <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">PgUp</span><span style="background:var(--vt-palette-8)"> </span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">PgDn</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>9+<span style="color:var(--vt-palette-8)">│</span> Screen left, right <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Alt+PgUp</span><span style="background:var(--vt-palette-8)"> </span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Alt+PgDn</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>10+<span style="color:var(--vt-palette-8)">│</span> Column A, cell A1 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Home</span><span style="background:var(--vt-palette-8)"> </span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Home</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>11+<span style="color:var(--vt-palette-8)">│</span> Last used cell <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+End</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>12+<span style="color:var(--vt-palette-8)">│</span> Go to <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+G</span><span style="background:var(--vt-palette-8)"> </span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">F5</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>13+<span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</span>14+<span style="color:var(--vt-palette-8)">└────────────────────────────────────────────</span> <span style="color:var(--vt-palette-8)">1-11</span> <span style="color:var(--vt-palette-8)">of</span> <span style="color:var(--vt-palette-8)">69</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>16+ <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)">scroll</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
A e2e/testdata/screens/help-wide.html +45 -0
@@ -0,0 +1,45 @@
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">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">HELP</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+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-8)">┌─</span> <span style="font-weight:bold">Keyboard</span> <span style="font-weight:bold">shortcuts</span> <span style="color:var(--vt-palette-8)">───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">R</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">S</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> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</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> <span style="color:var(--vt-palette-8)">│</span> <span style="font-weight:bold">Moving</span> <span style="font-weight:bold">around</span> <span style="font-weight:bold">File</span> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> Move <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Arrows</span><span style="background:var(--vt-palette-8)"> </span> Open <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+O</span><span style="background:var(--vt-palette-8)"> </span> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> Jump to the edge of the data <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+arrows</span><span style="background:var(--vt-palette-8)"> </span> Save <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+S</span><span style="background:var(--vt-palette-8)"> </span> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> Right, left <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Tab</span><span style="background:var(--vt-palette-8)"> </span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Shift+Tab</span><span style="background: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>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> <span style="color:var(--vt-palette-8)">│</span> Screen up, down <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">PgUp</span><span style="background:var(--vt-palette-8)"> </span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">PgDn</span><span style="background:var(--vt-palette-8)"> </span> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> Screen left, right <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Alt+PgUp</span><span style="background:var(--vt-palette-8)"> </span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Alt+PgDn</span><span style="background:var(--vt-palette-8)"> </span> <span style="font-weight:bold">Edit</span> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> Column A, cell A1 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Home</span><span style="background:var(--vt-palette-8)"> </span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Home</span><span style="background:var(--vt-palette-8)"> </span> Undo <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>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> <span style="color:var(--vt-palette-8)">│</span> Last used cell <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+End</span><span style="background:var(--vt-palette-8)"> </span> Redo <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Shift+Z</span><span style="background:var(--vt-palette-8)"> </span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Y</span><span style="background:var(--vt-palette-8)"> </span> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> Go to <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+G</span><span style="background:var(--vt-palette-8)"> </span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">F5</span><span style="background:var(--vt-palette-8)"> </span> Cut <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+X</span><span style="background:var(--vt-palette-8)"> </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> Copy <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+C</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> <span style="font-weight:bold">Selecting</span> Paste <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+V</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> Extend the selection <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Shift+arrows</span><span style="background:var(--vt-palette-8)"> </span> Paste values only <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Shift+V</span><span style="background:var(--vt-palette-8)"> </span> <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> Extend to the edge of the data <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Shift+arrows</span><span style="background:var(--vt-palette-8)"> </span> Fill down <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+D</span><span style="background:var(--vt-palette-8)"> </span> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> Select by dragging or Shift+click <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Mouse</span><span style="background:var(--vt-palette-8)"> </span> Fill right <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+R</span><span style="background:var(--vt-palette-8)"> </span> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> Deselect <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> Clear <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Del</span><span style="background:var(--vt-palette-8)"> </span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Backspace</span><span style="background:var(--vt-palette-8)"> </span> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> Select all <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+A</span><span style="background:var(--vt-palette-8)"> </span> Delete rows or columns <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>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> <span style="color:var(--vt-palette-8)">│</span> Select columns <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Space</span><span style="background:var(--vt-palette-8)"> </span> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> Select rows <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Shift+Space</span><span style="background:var(--vt-palette-8)"> </span> <span style="font-weight:bold">Insert</span> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> Insert rows or columns <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>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> <span style="color:var(--vt-palette-8)">│</span> <span style="font-weight:bold">Entering</span> <span style="font-weight:bold">data</span> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> Replace the cell; = starts a formula <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Type</span><span style="background:var(--vt-palette-8)"> </span> <span style="font-weight:bold">Format</span> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> Accept and move down, right <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="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Tab</span><span style="background:var(--vt-palette-8)"> </span> Number <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Shift+1</span><span style="background:var(--vt-palette-8)"> </span> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> Pick cells for a formula <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Arrows</span><span style="background:var(--vt-palette-8)"> </span> Percent <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Shift+5</span><span style="background:var(--vt-palette-8)"> </span> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> Cancel the entry <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> Scientific <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Shift+6</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>30+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">26</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> Edit cell <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">F2</span><span style="background:var(--vt-palette-8)"> </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> Currency <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Shift+4</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>31+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">27</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> Date <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Shift+3</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>32+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">28</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="font-weight:bold">Menus</span> <span style="font-weight:bold">and</span> <span style="font-weight:bold">search</span> Time <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Shift+2</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>33+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">29</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> Open a menu by its underlined letter <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Alt+letter</span><span style="background:var(--vt-palette-8)"> </span> Bold <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+B</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>34+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">30</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> Search the menus <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="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Shift+P</span><span style="background:var(--vt-palette-8)"> </span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Alt+/</span><span style="background:var(--vt-palette-8)"> </span> Italic <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+I</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>35+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">31</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> Menu <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> Underline <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+U</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>36+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">32</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> Cell menu <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Shift+F10</span><span style="background:var(--vt-palette-8)"> </span> Strikethrough <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Alt+Shift+5</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>37+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">33</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> Keyboard shortcuts <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="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">F1</span><span style="background:var(--vt-palette-8)"> </span> Left <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Shift+L</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>38+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">34</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> Center <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Shift+E</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>39+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">35</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> Right <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Shift+R</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>40+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">36</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> Clear formatting <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)">│</span>41+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">37</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">└────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘</span>42+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">38</span><span style="background:var(--vt-palette-8)"> </span>43+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">39</span><span style="background:var(--vt-palette-8)"> </span>44+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">40</span><span style="background:var(--vt-palette-8)"> </span>45+ <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)">scroll</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/help.html +30 -30
@@ -1,30 +1,30 @@
1-<pre class="screen"><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> HELP </span> Keyboard shortcuts <span style="color:var(--vt-palette-8)">(press any key to return)</span>2-3- Arrows Move Shift+arrows Select4- Ctrl+arrows Jump to the edge of the data (add Shift to select)5- Tab / Shift+Tab Right / left PgUp / PgDn Screen up / down6- Home / Ctrl+Home Column A / A1 Ctrl+End Last used cell7- Mouse Click, drag or Shift+click to select; click headers8- for whole columns or rows; double-click to edit9-10- Ctrl+B Make text bold, or plain again11- Ctrl+Shift+E Center horizontally12- Backspace / Del Clear the contents of the selected cells13- Ctrl+\ Reset number formats and text styles, keeping contents14- Ctrl+Shift+4 Currency: $1,000.1215- Ctrl+Shift+3 Date: 9/26/202616- Esc Collapse the selection to the active cell17- Enter / F2 Edit the active cell&#39;s contents18- Ctrl+G / F5 Move to a cell address19- Ctrl+I Make text italic, or upright again20- Ctrl+Shift+L Align to the left21- F10 Open the menu22- Ctrl+Shift+1 Number with thousands separators: 1,000.1223- Ctrl+O Open a sheet, replacing this one24- Ctrl+Shift+5 Percent: 10.12%25- Ctrl+Q Close one2326- Ctrl+Shift+R Align to the right27- Ctrl+S Save the sheet28- Ctrl+Shift+6 Scientific notation: 1.01E+0329- Ctrl+A Select the data, then the whole sheet30- Ctrl+Space Select the whole columns of the selection</pre>\ No newline at end of file1+<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">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">HELP</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> <span style="color:var(--vt-palette-8)">┌─</span> <span style="font-weight:bold">Keyboard</span> <span style="font-weight:bold">shortcuts</span> <span style="color:var(--vt-palette-8)">──────────────────────────────────────────────────┐</span>3+ <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-8)">│</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="color:var(--vt-palette-8)">│</span> <span style="font-weight:bold">Moving</span> <span style="font-weight:bold">around</span> <span style="color:var(--vt-palette-8)">│</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><span style="color:var(--vt-palette-8)">│</span> Move <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Arrows</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</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> <span style="color:var(--vt-palette-8)">│</span> Jump to the edge of the data <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+arrows</span><span style="background:var(--vt-palette-8)"> </span> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> Right, left <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Tab</span><span style="background:var(--vt-palette-8)"> </span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Shift+Tab</span><span style="background:var(--vt-palette-8)"> </span> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> Screen up, down <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">PgUp</span><span style="background:var(--vt-palette-8)"> </span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">PgDn</span><span style="background:var(--vt-palette-8)"> </span> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> Screen left, right <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Alt+PgUp</span><span style="background:var(--vt-palette-8)"> </span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Alt+PgDn</span><span style="background:var(--vt-palette-8)"> </span> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> Column A, cell A1 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Home</span><span style="background:var(--vt-palette-8)"> </span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Home</span><span style="background:var(--vt-palette-8)"> </span> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> Last used cell <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+End</span><span style="background:var(--vt-palette-8)"> </span> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> Go to <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+G</span><span style="background:var(--vt-palette-8)"> </span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">F5</span><span style="background:var(--vt-palette-8)"> </span> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> <span style="font-weight:bold">Selecting</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> Extend the selection <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Shift+arrows</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> Extend to the edge of the data <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Shift+arrows</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> Select by dragging or Shift+click <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Mouse</span><span style="background:var(--vt-palette-8)"> </span> <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> Deselect <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)">│</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> <span style="color:var(--vt-palette-8)">│</span> Select all <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+A</span><span style="background:var(--vt-palette-8)"> </span> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> Select columns <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Space</span><span style="background:var(--vt-palette-8)"> </span> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> Select rows <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Shift+Space</span><span style="background:var(--vt-palette-8)"> </span> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> <span style="font-weight:bold">Entering</span> <span style="font-weight:bold">data</span> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> Replace the cell; = starts a formula <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Type</span><span style="background:var(--vt-palette-8)"> </span> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> Accept and move down, right <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="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Tab</span><span style="background:var(--vt-palette-8)"> </span> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> Pick cells for a formula <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Arrows</span><span style="background:var(--vt-palette-8)"> </span> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> Cancel the entry <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)">│</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> <span style="color:var(--vt-palette-8)">└──────────────────────────────────────────────────────────</span> <span style="color:var(--vt-palette-8)">1-25</span> <span style="color:var(--vt-palette-8)">of</span> <span style="color:var(--vt-palette-8)">69</span> <span style="color: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-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)">scroll</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
A e2e/testdata/screens/hover-resize-handle.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">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">READY</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)">B7</span><span style="background:var(--vt-palette-8)"> </span> =SUM(B3:B5)3+4+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-6);background:var(--vt-palette-8);font-weight:bold">A</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-6);background:var(--vt-palette-8);font-weight:bold">▐</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">B</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)">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-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1</span><span style="background:var(--vt-palette-8)"> </span> Household budget 20266+<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> Rent 14508+<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> Groceries 612.49+<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> Transit 9610+<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> Savings r <span style="color:var(--vt-palette-1)">#DIV/0!</span>11+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">7</span><span style="background:var(--vt-palette-6)"> </span> Total <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">2158.4</span><span style="background:var(--vt-palette-6)"> </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+untitled <span style="color:var(--vt-palette-8)">modified</span> <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/menu-format-number-light.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 <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">F</span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);text-decoration:underline">o</span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">rmat</span><span style="background:var(--vt-palette-6)"> </span> <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">MENU</span><span style="background:var(--vt-palette-6)"> </span>2+<span style="color:var(--vt-palette-8)">┌───────────────────────────────────┐────────────────────────────────┐</span>3+<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)">Automatic</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)">›</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-8)">│</span>4+<span style="color:var(--vt-palette-8)">│</span> Plain text <span style="color:var(--vt-palette-8)">│</span>decimal places <span style="color:var(--vt-palette-8)">│</span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">G</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">H</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">I</span><span style="background:var(--vt-palette-7)"> </span>5+<span style="color:var(--vt-palette-8)">├───────────────────────────────────┤</span>decimal places <span style="color:var(--vt-palette-8)">│</span>6+<span style="color:var(--vt-palette-8)">│</span> Number <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+Shift+1</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│────────────────────────────────┤</span>7+<span style="color:var(--vt-palette-8)">│</span> Percent <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+Shift+5</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+B</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span>8+<span style="color:var(--vt-palette-8)">│</span> Scientific <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+Shift+6</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+I</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span>9+<span style="color:var(--vt-palette-8)">├───────────────────────────────────┤</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+U</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span>10+<span style="color:var(--vt-palette-8)">│</span> Accounting <span style="color:var(--vt-palette-8)">│</span>ough <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Alt+Shift+5</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span>11+<span style="color:var(--vt-palette-8)">│</span> Financial <span style="color:var(--vt-palette-8)">│────────────────────────────────┤</span>12+<span style="color:var(--vt-palette-8)">│</span> Currency <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+Shift+4</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span>t <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+Shift+L</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span>13+<span style="color:var(--vt-palette-8)">│</span> Currency rounded <span style="color:var(--vt-palette-8)">│</span>ter <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+Shift+E</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span>14+<span style="color:var(--vt-palette-8)">├───────────────────────────────────┤</span>ht <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+Shift+R</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span>15+<span style="color:var(--vt-palette-8)">│</span> Date <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+Shift+3</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│────────────────────────────────┤</span>16+<span style="color:var(--vt-palette-8)">│</span> Time <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+Shift+2</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span>dth <span style="color:var(--vt-palette-8)">│</span>17+<span style="color:var(--vt-palette-8)">│</span> Date time <span style="color:var(--vt-palette-8)">│</span>umn width <span style="color:var(--vt-palette-8)">│</span>18+<span style="color:var(--vt-palette-8)">│</span> Duration <span style="color:var(--vt-palette-8)">│────────────────────────────────┤</span>19+<span style="color:var(--vt-palette-8)">└───────────────────────────────────┘</span>matting <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+\</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span>20+<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> <span style="color:var(--vt-palette-8)">└──────────────────────────────────────────┘</span>21+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">17</span><span style="background:var(--vt-palette-7)"> </span>22+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">18</span><span style="background:var(--vt-palette-7)"> </span>23+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">19</span><span style="background:var(--vt-palette-7)"> </span>24+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">20</span><span style="background:var(--vt-palette-7)"> </span>25+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">21</span><span style="background:var(--vt-palette-7)"> </span>26+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">22</span><span style="background:var(--vt-palette-7)"> </span>27+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">23</span><span style="background:var(--vt-palette-7)"> </span>28+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">24</span><span style="background:var(--vt-palette-7)"> </span>29+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">25</span><span style="background:var(--vt-palette-7)"> </span>30+Show numbers as typed, or as formulas infer <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Arrows</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">move</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Enter</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">choose</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Esc</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">close</span></pre>\ No newline at end of file
A e2e/testdata/screens/menu-format-number.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 <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">F</span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);text-decoration:underline">o</span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">rmat</span><span style="background:var(--vt-palette-6)"> </span> <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">MENU</span><span style="background:var(--vt-palette-6)"> </span>2+<span style="color:var(--vt-palette-8)">┌───────────────────────────────────┐────────────────────────────────┐</span>3+<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)">Automatic</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)">›</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-8)">│</span>4+<span style="color:var(--vt-palette-8)">│</span> Plain text <span style="color:var(--vt-palette-8)">│</span>decimal places <span style="color: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="color:var(--vt-palette-8)">├───────────────────────────────────┤</span>decimal places <span style="color:var(--vt-palette-8)">│</span>6+<span style="color:var(--vt-palette-8)">│</span> Number <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Shift+1</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│────────────────────────────────┤</span>7+<span style="color:var(--vt-palette-8)">│</span> Percent <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Shift+5</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+B</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>8+<span style="color:var(--vt-palette-8)">│</span> Scientific <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Shift+6</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+I</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>9+<span style="color:var(--vt-palette-8)">├───────────────────────────────────┤</span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+U</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>10+<span style="color:var(--vt-palette-8)">│</span> Accounting <span style="color:var(--vt-palette-8)">│</span>ough <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Alt+Shift+5</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>11+<span style="color:var(--vt-palette-8)">│</span> Financial <span style="color:var(--vt-palette-8)">│────────────────────────────────┤</span>12+<span style="color:var(--vt-palette-8)">│</span> Currency <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Shift+4</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>t <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Shift+L</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>13+<span style="color:var(--vt-palette-8)">│</span> Currency rounded <span style="color:var(--vt-palette-8)">│</span>ter <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Shift+E</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>ht <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Shift+R</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>15+<span style="color:var(--vt-palette-8)">│</span> Date <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Shift+3</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│────────────────────────────────┤</span>16+<span style="color:var(--vt-palette-8)">│</span> Time <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Shift+2</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>dth <span style="color:var(--vt-palette-8)">│</span>17+<span style="color:var(--vt-palette-8)">│</span> Date time <span style="color:var(--vt-palette-8)">│</span>umn width <span style="color:var(--vt-palette-8)">│</span>18+<span style="color:var(--vt-palette-8)">│</span> Duration <span style="color:var(--vt-palette-8)">│────────────────────────────────┤</span>19+<span style="color:var(--vt-palette-8)">└───────────────────────────────────┘</span>matting <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)">│</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> <span style="color: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+Show numbers as typed, or as formulas infer <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Arrows</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)">choose</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
A e2e/testdata/screens/menu-light.html +30 -0
@@ -0,0 +1,30 @@
1+<pre class="screen"><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);text-decoration:underline">F</span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">ile</span><span style="background:var(--vt-palette-6)"> </span> <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">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">MENU</span><span style="background:var(--vt-palette-6)"> </span>2+<span style="color:var(--vt-palette-8)">┌────────────────────┐</span>)3+<span style="color:var(--vt-palette-8)">│</span> New <span style="color:var(--vt-palette-8)">│</span>4+<span style="color:var(--vt-palette-8)">│</span> Open <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+O</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">C</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">D</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">E</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">F</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">G</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">H</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">I</span><span style="background:var(--vt-palette-7)"> </span>5+<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)">Save</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">Ctrl+S</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-8)">│</span>t 20266+<span style="color:var(--vt-palette-8)">│</span> Save as <span style="color:var(--vt-palette-8)">│</span>7+<span style="color:var(--vt-palette-8)">├────────────────────┤</span>4508+<span style="color:var(--vt-palette-8)">│</span> Quit <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+Q</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span>2.49+<span style="color:var(--vt-palette-8)">└────────────────────┘</span> 9610+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">6</span><span style="background:var(--vt-palette-7)"> </span> Savings r <span style="color:var(--vt-palette-1)">#DIV/0!</span>11+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">7</span><span style="background:var(--vt-palette-6)"> </span> Total <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">2158.4</span><span style="background:var(--vt-palette-6)"> </span>12+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">8</span><span style="background:var(--vt-palette-7)"> </span>13+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">9</span><span style="background:var(--vt-palette-7)"> </span>14+<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>15+<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>16+<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>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>18+<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>19+<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>20+<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>21+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">17</span><span style="background:var(--vt-palette-7)"> </span>22+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">18</span><span style="background:var(--vt-palette-7)"> </span>23+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">19</span><span style="background:var(--vt-palette-7)"> </span>24+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">20</span><span style="background:var(--vt-palette-7)"> </span>25+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">21</span><span style="background:var(--vt-palette-7)"> </span>26+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">22</span><span style="background:var(--vt-palette-7)"> </span>27+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">23</span><span style="background:var(--vt-palette-7)"> </span>28+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">24</span><span style="background:var(--vt-palette-7)"> </span>29+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">25</span><span style="background:var(--vt-palette-7)"> </span>30+Save the sheet <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Arrows</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">move</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Enter</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">choose</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Esc</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">close</span></pre>\ No newline at end of file
A e2e/testdata/screens/menu-narrow.html +16 -0
@@ -0,0 +1,16 @@
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="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);text-decoration:underline">H</span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">elp</span><span style="background:var(--vt-palette-6)"> </span> <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">MENU</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)">B7</span><span style="background:var(--vt-palette-8)"> </span> =SUM(B3:B5) <span style="color:var(--vt-palette-8)">┌───────────────────────────────┐</span>3+ <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)">Search</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">the</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">menus</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">Ctrl+K</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-8)">│</span>4+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">A</span><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">B</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-8)">│</span> Keyboard shortcuts <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)">│</span>5+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1</span><span style="background:var(--vt-palette-8)"> </span> Household budget 202<span style="color:var(--vt-palette-8)">│</span> Function list <span style="color:var(--vt-palette-8)">│</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> <span style="color: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> Rent 1450 <span style="color:var(--vt-palette-8)">│</span> About one23 <span style="color: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> Groceries 612.4 <span style="color: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> Transit 9610+<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> Savings r <span style="color:var(--vt-palette-1)">#DIV/0!</span>11+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">7</span><span style="background:var(--vt-palette-6)"> </span> Total <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">2158.4</span><span style="background:var(--vt-palette-6)"> </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+Find and run a… <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Arrows</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)">choose</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/menu.html +30 -30
@@ -1,30 +1,30 @@
1-<pre class="screen"><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> B7 </span> =SUM(B3:B5) <span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> MENU</span><span style="background:var(--vt-palette-6)"> </span>2-<span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">File</span> Edit Format3-New Open Save As Quit4-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> A </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> B </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> C D E F G H I </span>5-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 1 </span> Household budget 20266-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 2 </span>7-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 3 </span> Rent 14508-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 4 </span> Groceries 612.49-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 5 </span> Transit 9610-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 6 </span> Savings r<span style="color:var(--vt-palette-1)"> #DIV/0! </span>11-<span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> 7 </span> Total <span style="color:var(--vt-palette-0);background:var(--vt-palette-6)"> 2158.4 </span>12-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 8 </span>13-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 9 </span>14-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 10 </span>15-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 11 </span>16-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 12 </span>17-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 13 </span>18-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 14 </span>19-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 15 </span>20-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 16 </span>21-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 17 </span>22-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 18 </span>23-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 19 </span>24-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 20 </span>25-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 21 </span>26-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 22 </span>27-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 23 </span>28-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 24 </span>29-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 25 </span>30-untitled<span style="color:var(--vt-palette-8)"> modified</span> <span style="font-weight:bold">F1</span> <span style="color:var(--vt-palette-8)">help </span><span style="font-weight:bold">F10</span> <span style="color:var(--vt-palette-8)">menu </span><span style="font-weight:bold">Ctrl+Q</span> <span style="color:var(--vt-palette-8)">quit</span></pre>\ No newline at end of file1+<pre class="screen"><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);text-decoration:underline">F</span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">ile</span><span style="background:var(--vt-palette-6)"> </span> <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">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">MENU</span><span style="background:var(--vt-palette-6)"> </span>2+<span style="color:var(--vt-palette-8)">┌────────────────────┐</span>)3+<span style="color:var(--vt-palette-8)">│</span> New <span style="color:var(--vt-palette-8)">│</span>4+<span style="color:var(--vt-palette-8)">│</span> Open <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+O</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</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)">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="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)">Save</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">Ctrl+S</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-8)">│</span>t 20266+<span style="color:var(--vt-palette-8)">│</span> Save as <span style="color:var(--vt-palette-8)">│</span>7+<span style="color:var(--vt-palette-8)">├────────────────────┤</span>4508+<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>2.49+<span style="color:var(--vt-palette-8)">└────────────────────┘</span> 9610+<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> Savings r <span style="color:var(--vt-palette-1)">#DIV/0!</span>11+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">7</span><span style="background:var(--vt-palette-6)"> </span> Total <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">2158.4</span><span style="background:var(--vt-palette-6)"> </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+Save the sheet <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Arrows</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)">choose</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
A e2e/testdata/screens/narrow-copy.html +16 -0
@@ -0,0 +1,16 @@
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">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">READY</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)">B8</span><span style="background:var(--vt-palette-8)"> </span>3+Copied B7 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+V</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">paste</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)">clear</span>4+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">A</span><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">B</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)">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>5+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1</span><span style="background:var(--vt-palette-8)"> </span> Household budget 20266+<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> Rent 14508+<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> Groceries 612.49+<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> Transit 9610+<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> Savings r <span style="color:var(--vt-palette-1)">#DIV/0!</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> Total <span style="text-decoration:underline"> </span><span style="color:var(--vt-palette-5);text-decoration:underline dashed">2158.4</span><span style="text-decoration:underline"> </span>12+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">8</span><span style="background:var(--vt-palette-6)"> </span> <span style="background:var(--vt-palette-6)"> </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+untitled <span style="color:var(--vt-palette-8)">modified</span> <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></pre>\ No newline at end of file
M e2e/testdata/screens/narrow.html +15 -15
@@ -1,16 +1,16 @@
1-<pre class="screen"><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> B7 </span> =SUM(B3:B5) <span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> READY</span><span style="background:var(--vt-palette-6)"> </span>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">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">READY</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)">B7</span><span style="background:var(--vt-palette-8)"> </span> =SUM(B3:B5)23 3-4-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> A </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> B </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> C D E </span>5-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 1 </span> Household budget 20266-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 2 </span>7-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 3 </span> Rent 14508-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 4 </span> Groceries 612.49-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 5 </span> Transit 9610-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 6 </span> Savings r<span style="color:var(--vt-palette-1)"> #DIV/0! </span>11-<span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> 7 </span> Total <span style="color:var(--vt-palette-0);background:var(--vt-palette-6)"> 2158.4 </span>12-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 8 </span>13-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 9 </span>14-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 10 </span>15-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 11 </span>16-untitled<span style="color:var(--vt-palette-8)"> modified</span> <span style="font-weight:bold">F1</span> <span style="color:var(--vt-palette-8)">help </span><span style="font-weight:bold">F10</span> <span style="color:var(--vt-palette-8)">menu </span><span style="font-weight:bold">Ctrl+Q</span> <span style="color:var(--vt-palette-8)">quit</span></pre>\ No newline at end of file4+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">A</span><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">B</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)">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>5+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1</span><span style="background:var(--vt-palette-8)"> </span> Household budget 20266+<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> Rent 14508+<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> Groceries 612.49+<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> Transit 9610+<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> Savings r <span style="color:var(--vt-palette-1)">#DIV/0!</span>11+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">7</span><span style="background:var(--vt-palette-6)"> </span> Total <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">2158.4</span><span style="background:var(--vt-palette-6)"> </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+untitled <span style="color:var(--vt-palette-8)">modified</span> <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></pre>\ No newline at end of file
A e2e/testdata/screens/palette-narrow.html +16 -0
@@ -0,0 +1,16 @@
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">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">MENU</span><span style="background:var(--vt-palette-6)"> </span>2+<span style="color:var(--vt-palette-8)">┌─</span> <span style="font-weight:bold">Search</span> <span style="font-weight:bold">the</span> <span style="font-weight:bold">menus</span> <span style="color:var(--vt-palette-8)">───────────────────────────────────────┐</span>3+<span style="color:var(--vt-palette-8)">│</span> <span style="font-weight:bold">›</span> sa <span style="color:var(--vt-palette-8)">│</span>4+<span style="color:var(--vt-palette-8)">├──────────────────────────────────────────────────────────┤</span>5+<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);font-weight:bold;text-decoration:underline">S</span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">ave</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold;text-decoration:underline">a</span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">s</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">File</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-8)">│</span>6+<span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-3);font-weight:bold">S</span>elect <span style="color:var(--vt-palette-3);font-weight:bold">a</span>ll <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+A</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>7+<span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-3);font-weight:bold">Sa</span>ve <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+S</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>8+<span style="color:var(--vt-palette-8)">│</span> In<span style="color:var(--vt-palette-3);font-weight:bold">s</span>ert rows <span style="color:var(--vt-palette-3);font-weight:bold">a</span>bove <span style="color:var(--vt-palette-8)">Insert</span> <span style="color:var(--vt-palette-8)">│</span>9+<span style="color:var(--vt-palette-8)">│</span> Pa<span style="color:var(--vt-palette-3);font-weight:bold">s</span>te v<span style="color:var(--vt-palette-3);font-weight:bold">a</span>lues only <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+Shift+V</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>10+<span style="color:var(--vt-palette-8)">│</span> Increa<span style="color:var(--vt-palette-3);font-weight:bold">s</span>e decim<span style="color:var(--vt-palette-3);font-weight:bold">a</span>l places <span style="color:var(--vt-palette-8)">Format</span> <span style="color:var(--vt-palette-8)">│</span>11+<span style="color:var(--vt-palette-8)">│</span> Decrea<span style="color:var(--vt-palette-3);font-weight:bold">s</span>e decim<span style="color:var(--vt-palette-3);font-weight:bold">a</span>l places <span style="color:var(--vt-palette-8)">Format</span> <span style="color:var(--vt-palette-8)">│</span>12+<span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-3);font-weight:bold">S</span>trikethrough <span style="color:var(--vt-palette-8)">Form</span><span style="color:var(--vt-palette-3);font-weight:bold">a</span><span style="color:var(--vt-palette-8)">t</span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Alt+Shift+5</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">│</span>13+<span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-3);font-weight:bold">S</span>cientific <span style="color:var(--vt-palette-8)">Form</span><span style="color:var(--vt-palette-3);font-weight:bold">a</span><span style="color:var(--vt-palette-8)">t</span> <span style="color:var(--vt-palette-8)">›</span> <span style="color:var(--vt-palette-8)">Number</span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Shift+6</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> Re<span style="color:var(--vt-palette-3);font-weight:bold">s</span>et column width <span style="color:var(--vt-palette-8)">Form</span><span style="color:var(--vt-palette-3);font-weight:bold">a</span><span style="color:var(--vt-palette-8)">t</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)">10</span> <span style="color:var(--vt-palette-8)">of</span> <span style="color:var(--vt-palette-8)">58</span> <span style="color:var(--vt-palette-8)">─┘</span>16+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
A e2e/testdata/screens/palette-search-light.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">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">MENU</span><span style="background:var(--vt-palette-6)"> </span>2+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">B7</span><span style="background:var(--vt-palette-7)"> </span> =SUM(B3<span style="color:var(--vt-palette-8)">┌─</span> <span style="font-weight:bold">Search</span> <span style="font-weight:bold">the</span> <span style="font-weight:bold">menus</span> <span style="color:var(--vt-palette-8)">─────────────────────────────────────────┐</span>3+ <span style="color:var(--vt-palette-8)">│</span> <span style="font-weight:bold">›</span> col <span style="color:var(--vt-palette-8)">│</span>4+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">A</span><span style="background:var(--vt-palette-7)"> </span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-8)">├────────────────────────────────────────────────────────────┤</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">I</span><span style="background:var(--vt-palette-7)"> </span>5+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1</span><span style="background:var(--vt-palette-7)"> </span> Household bu<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);font-weight:bold;text-decoration:underline">Col</span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">umn</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">width</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">Format</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-8)">│</span>6+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">2</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> Delete <span style="color:var(--vt-palette-4);font-weight:bold">col</span>umns <span style="color:var(--vt-palette-0)">Edit</span> <span style="color:var(--vt-palette-8)">│</span>7+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">3</span><span style="background:var(--vt-palette-7)"> </span> Rent <span style="color:var(--vt-palette-8)">│</span> Insert <span style="color:var(--vt-palette-4);font-weight:bold">co</span>lumns <span style="color:var(--vt-palette-4);font-weight:bold">l</span>eft <span style="color:var(--vt-palette-0)">Insert</span> <span style="color:var(--vt-palette-8)">│</span>8+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">4</span><span style="background:var(--vt-palette-7)"> </span> Groceries <span style="color:var(--vt-palette-8)">│</span> Select <span style="color:var(--vt-palette-4);font-weight:bold">col</span>umns <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+Space</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span>9+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">5</span><span style="background:var(--vt-palette-7)"> </span> Transit <span style="color:var(--vt-palette-8)">│</span> Reset <span style="color:var(--vt-palette-4);font-weight:bold">col</span>umn width <span style="color:var(--vt-palette-0)">Format</span> <span style="color:var(--vt-palette-8)">│</span>10+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">6</span><span style="background:var(--vt-palette-7)"> </span> Savings r <span style="color:var(--vt-palette-1)">#D</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>11+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">7</span><span style="background:var(--vt-palette-6)"> </span> Total <span style="background:var(--vt-palette-6)"> </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>12+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">8</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>13+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">9</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-8)">│</span> Fun<span style="color:var(--vt-palette-4);font-weight:bold">c</span>ti<span style="color:var(--vt-palette-4);font-weight:bold">o</span>n <span style="color:var(--vt-palette-4);font-weight:bold">l</span>ist <span style="color:var(--vt-palette-0)">Help</span> <span style="color:var(--vt-palette-8)">│</span>14+<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> <span style="color:var(--vt-palette-0)">9</span> <span style="color:var(--vt-palette-0)">of</span> <span style="color:var(--vt-palette-0)">58</span> <span style="color:var(--vt-palette-8)">─┘</span>15+<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>16+<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>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>18+<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>19+<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>20+<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>21+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">17</span><span style="background:var(--vt-palette-7)"> </span>22+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">18</span><span style="background:var(--vt-palette-7)"> </span>23+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">19</span><span style="background:var(--vt-palette-7)"> </span>24+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">20</span><span style="background:var(--vt-palette-7)"> </span>25+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">21</span><span style="background:var(--vt-palette-7)"> </span>26+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">22</span><span style="background:var(--vt-palette-7)"> </span>27+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">23</span><span style="background:var(--vt-palette-7)"> </span>28+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">24</span><span style="background:var(--vt-palette-7)"> </span>29+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">25</span><span style="background:var(--vt-palette-7)"> </span>30+Set the width of the selected columns <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Up/Down</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">move</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Enter</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">run</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Esc</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">close</span></pre>\ No newline at end of file
A e2e/testdata/screens/palette-search.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">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">MENU</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)">B7</span><span style="background:var(--vt-palette-8)"> </span> =SUM(B3<span style="color:var(--vt-palette-8)">┌─</span> <span style="font-weight:bold">Search</span> <span style="font-weight:bold">the</span> <span style="font-weight:bold">menus</span> <span style="color:var(--vt-palette-8)">─────────────────────────────────────────┐</span>3+ <span style="color:var(--vt-palette-8)">│</span> <span style="font-weight:bold">›</span> col <span style="color:var(--vt-palette-8)">│</span>4+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">A</span><span style="background:var(--vt-palette-8)"> </span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-8)">├────────────────────────────────────────────────────────────┤</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-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1</span><span style="background:var(--vt-palette-8)"> </span> Household bu<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);font-weight:bold;text-decoration:underline">Col</span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">umn</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">width</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">Format</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-8)">│</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> <span style="color:var(--vt-palette-8)">│</span> Delete <span style="color:var(--vt-palette-3);font-weight:bold">col</span>umns <span style="color:var(--vt-palette-8)">Edit</span> <span style="color: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> Rent <span style="color:var(--vt-palette-8)">│</span> Insert <span style="color:var(--vt-palette-3);font-weight:bold">co</span>lumns <span style="color:var(--vt-palette-3);font-weight:bold">l</span>eft <span style="color:var(--vt-palette-8)">Insert</span> <span style="color: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> Groceries <span style="color:var(--vt-palette-8)">│</span> Select <span style="color:var(--vt-palette-3);font-weight:bold">col</span>umns <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Space</span><span style="background:var(--vt-palette-8)"> </span> <span style="color: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> Transit <span style="color:var(--vt-palette-8)">│</span> Reset <span style="color:var(--vt-palette-3);font-weight:bold">col</span>umn width <span style="color:var(--vt-palette-8)">Format</span> <span style="color: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> Savings r <span style="color:var(--vt-palette-1)">#D</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>11+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">7</span><span style="background:var(--vt-palette-6)"> </span> Total <span style="background:var(--vt-palette-6)"> </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>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> <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>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> <span style="color:var(--vt-palette-8)">│</span> Fun<span style="color:var(--vt-palette-3);font-weight:bold">c</span>ti<span style="color:var(--vt-palette-3);font-weight:bold">o</span>n <span style="color:var(--vt-palette-3);font-weight:bold">l</span>ist <span style="color:var(--vt-palette-8)">Help</span> <span style="color: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> <span style="color:var(--vt-palette-8)">└──────────────────────────────────────────────────</span> <span style="color:var(--vt-palette-8)">9</span> <span style="color:var(--vt-palette-8)">of</span> <span style="color:var(--vt-palette-8)">58</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>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+Set the width of the selected columns <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
A e2e/testdata/screens/palette-wide.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">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">MENU</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)">B7</span><span style="background:var(--vt-palette-8)"> </span> =SUM(B3:B5) <span style="color:var(--vt-palette-8)">┌─</span> <span style="font-weight:bold">Search</span> <span style="font-weight:bold">the</span> <span style="font-weight:bold">menus</span> <span style="color:var(--vt-palette-8)">─────────────────────────────────────────┐</span>3+ <span style="color:var(--vt-palette-8)">│</span> <span style="font-weight:bold">›</span> sel <span style="color:var(--vt-palette-8)">│</span>4+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">A</span><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">B</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)">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-8)">├────────────────────────────────────────────────────────────┤</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">N</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">O</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">P</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Q</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">R</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">S</span><span style="background:var(--vt-palette-8)"> </span>5+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1</span><span style="background:var(--vt-palette-8)"> </span> Household budget 2026 <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);font-weight:bold;text-decoration:underline">Sel</span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">ect</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">all</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">Edit</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">Ctrl+A</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-8)">│</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> <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-3);font-weight:bold">Sel</span>ect rows <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Shift+Space</span><span style="background:var(--vt-palette-8)"> </span> <span style="color: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> Rent 1450 <span style="color:var(--vt-palette-8)">│</span> <span style="color:var(--vt-palette-3);font-weight:bold">Sel</span>ect columns <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Ctrl+Space</span><span style="background:var(--vt-palette-8)"> </span> <span style="color: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> Groceries 612.4 <span style="color:var(--vt-palette-8)">│</span> De<span style="color:var(--vt-palette-3);font-weight:bold">sel</span>ect <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)">│</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> Transit 96 <span style="color:var(--vt-palette-8)">│</span> In<span style="color:var(--vt-palette-3);font-weight:bold">se</span>rt columns <span style="color:var(--vt-palette-3);font-weight:bold">l</span>eft <span style="color:var(--vt-palette-8)">Insert</span> <span style="color: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> Savings r <span style="color:var(--vt-palette-1)">#DIV/0!</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>11+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">7</span><span style="background:var(--vt-palette-6)"> </span> Total <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">2158.4</span><span style="background:var(--vt-palette-6)"> </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>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> <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>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> <span style="color:var(--vt-palette-8)">│</span> Pa<span style="color:var(--vt-palette-3);font-weight:bold">s</span>t<span style="color:var(--vt-palette-3);font-weight:bold">e</span> va<span style="color:var(--vt-palette-3);font-weight:bold">l</span>ues only <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+Shift+V</span><span style="background:var(--vt-palette-8)"> </span> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> In<span style="color:var(--vt-palette-3);font-weight:bold">se</span>rt rows or co<span style="color:var(--vt-palette-3);font-weight:bold">l</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>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> Increa<span style="color:var(--vt-palette-3);font-weight:bold">se</span> decima<span style="color:var(--vt-palette-3);font-weight:bold">l</span> places <span style="color:var(--vt-palette-8)">Format</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> Decrea<span style="color:var(--vt-palette-3);font-weight:bold">se</span> decima<span style="color:var(--vt-palette-3);font-weight:bold">l</span> places <span style="color:var(--vt-palette-8)">Format</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)">58</span> <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>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+Select the data, then the whole sheet <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
A e2e/testdata/screens/palette.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">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">MENU</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)">B7</span><span style="background:var(--vt-palette-8)"> </span> =SUM(B3<span style="color:var(--vt-palette-8)">┌─</span> <span style="font-weight:bold">Search</span> <span style="font-weight:bold">the</span> <span style="font-weight:bold">menus</span> <span style="color:var(--vt-palette-8)">─────────────────────────────────────────┐</span>3+ <span style="color:var(--vt-palette-8)">│</span> <span style="font-weight:bold">›</span> <span style="color:var(--vt-palette-8)">Type</span> <span style="color:var(--vt-palette-8)">a</span> <span style="color:var(--vt-palette-8)">command,</span> <span style="color:var(--vt-palette-8)">e.g.</span> <span style="color:var(--vt-palette-8)">save</span> <span style="color:var(--vt-palette-8)">or</span> <span style="color:var(--vt-palette-8)">width</span> <span style="color:var(--vt-palette-8)">│</span>4+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">A</span><span style="background:var(--vt-palette-8)"> </span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-8)">├────────────────────────────────────────────────────────────┤</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-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1</span><span style="background:var(--vt-palette-8)"> </span> Household bu<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)">New</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">File</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-8)">│</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> <span style="color:var(--vt-palette-8)">│</span> Open <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+O</span><span style="background:var(--vt-palette-8)"> </span> <span style="color: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> Rent <span style="color:var(--vt-palette-8)">│</span> Save <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+S</span><span style="background:var(--vt-palette-8)"> </span> <span style="color: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> Groceries <span style="color:var(--vt-palette-8)">│</span> Save as <span style="color:var(--vt-palette-8)">File</span> <span style="color: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> Transit <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>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> Savings r <span style="color:var(--vt-palette-1)">#D</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>11+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">7</span><span style="background:var(--vt-palette-6)"> </span> Total <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-8)">│</span> Redo <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+Shift+Z</span><span style="background:var(--vt-palette-8)"> </span> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> Cut <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+X</span><span style="background:var(--vt-palette-8)"> </span> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> Copy <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+C</span><span style="background:var(--vt-palette-8)"> </span> <span style="color: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> <span style="color:var(--vt-palette-8)">│</span> Paste <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+V</span><span style="background:var(--vt-palette-8)"> </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> Paste values only <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+Shift+V</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> Fill down <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+D</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)">58</span> <span style="color:var(--vt-palette-8)">of</span> <span style="color:var(--vt-palette-8)">58</span> <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>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+Start a new, empty sheet <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/point-range-light.html +30 -30
@@ -1,30 +1,30 @@
1-<pre class="screen"><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> C7 </span> <span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> POINT</span><span style="background:var(--vt-palette-6)"> </span>2-=AVERAGE(<span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">B3:B5</span>3-<span style="font-weight:bold">Arrows</span> <span style="color:var(--vt-palette-0)">pick a cell </span><span style="font-weight:bold">Shift+arrows</span> <span style="color:var(--vt-palette-0)">pick a range </span><span style="font-weight:bold">Enter</span> <span style="color:var(--vt-palette-0)">accept </span><span style="font-weight:bold">Esc</span> <span style="color:var(--vt-palette-0)">back</span>4-<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> A </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> B </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> C D E F G H I </span>5-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 1 </span> Household budget 20266-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 2 </span>7-<span style="color:var(--vt-palette-15);background:var(--vt-palette-4)"> 3 </span> Rent <span style="color:var(--vt-palette-15);background:var(--vt-palette-4)"> 1450 </span>8-<span style="color:var(--vt-palette-15);background:var(--vt-palette-4)"> 4 </span> Groceries<span style="color:var(--vt-palette-15);background:var(--vt-palette-4)"> 612.4 </span>9-<span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> 5 </span> Transit <span style="color:var(--vt-palette-0);background:var(--vt-palette-6)"> 96 </span>10-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 6 </span> Savings r<span style="color:var(--vt-palette-1)"> #DIV/0! </span>11-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 7 </span> Total 2158.412-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 8 </span>13-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 9 </span>14-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 10 </span>15-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 11 </span>16-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 12 </span>17-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 13 </span>18-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 14 </span>19-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 15 </span>20-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 16 </span>21-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 17 </span>22-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 18 </span>23-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 19 </span>24-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 20 </span>25-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 21 </span>26-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 22 </span>27-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 23 </span>28-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 24 </span>29-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 25 </span>30-untitled<span style="color:var(--vt-palette-0)"> modified</span> <span style="font-weight:bold">F1</span> <span style="color:var(--vt-palette-0)">help </span><span style="font-weight:bold">F10</span> <span style="color:var(--vt-palette-0)">menu </span><span style="font-weight:bold">Ctrl+Q</span> <span style="color:var(--vt-palette-0)">quit</span></pre>\ No newline at end of file1+<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">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">POINT</span><span style="background:var(--vt-palette-6)"> </span>2+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">C7</span><span style="background:var(--vt-palette-7)"> </span> =AVERAGE(<span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">B3:B5</span>3+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Arrows</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">pick</span> <span style="color:var(--vt-palette-0)">a</span> <span style="color:var(--vt-palette-0)">cell</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Shift+arrows</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">pick</span> <span style="color:var(--vt-palette-0)">a</span> <span style="color:var(--vt-palette-0)">range</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Enter</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">accept</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Esc</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">back</span>4+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">A</span><span style="background:var(--vt-palette-7)"> </span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">B</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">C</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">D</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">E</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">F</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">G</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">H</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">I</span><span style="background:var(--vt-palette-7)"> </span>5+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1</span><span style="background:var(--vt-palette-7)"> </span> Household budget 20266+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">2</span><span style="background:var(--vt-palette-7)"> </span>7+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">3</span><span style="background:var(--vt-palette-4)"> </span> Rent <span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">1450</span><span style="background:var(--vt-palette-4)"> </span>8+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">4</span><span style="background:var(--vt-palette-4)"> </span> Groceries<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">612.4</span><span style="background:var(--vt-palette-4)"> </span>9+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">5</span><span style="background:var(--vt-palette-6)"> </span> Transit <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">96</span><span style="background:var(--vt-palette-6)"> </span>10+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">6</span><span style="background:var(--vt-palette-7)"> </span> Savings r <span style="color:var(--vt-palette-1)">#DIV/0!</span>11+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">7</span><span style="background:var(--vt-palette-7)"> </span> Total 2158.412+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">8</span><span style="background:var(--vt-palette-7)"> </span>13+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">9</span><span style="background:var(--vt-palette-7)"> </span>14+<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>15+<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>16+<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>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>18+<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>19+<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>20+<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>21+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">17</span><span style="background:var(--vt-palette-7)"> </span>22+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">18</span><span style="background:var(--vt-palette-7)"> </span>23+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">19</span><span style="background:var(--vt-palette-7)"> </span>24+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">20</span><span style="background:var(--vt-palette-7)"> </span>25+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">21</span><span style="background:var(--vt-palette-7)"> </span>26+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">22</span><span style="background:var(--vt-palette-7)"> </span>27+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">23</span><span style="background:var(--vt-palette-7)"> </span>28+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">24</span><span style="background:var(--vt-palette-7)"> </span>29+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">25</span><span style="background:var(--vt-palette-7)"> </span>30+untitled <span style="color:var(--vt-palette-0)">modified</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+K</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">search</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+/</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">shortcuts</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">F10</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">menu</span></pre>\ No newline at end of file
M e2e/testdata/screens/point-range.html +30 -30
@@ -1,30 +1,30 @@
1-<pre class="screen"><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> C7 </span> <span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> POINT</span><span style="background:var(--vt-palette-6)"> </span>2-=AVERAGE(<span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">B3:B5</span>3-<span style="font-weight:bold">Arrows</span> <span style="color:var(--vt-palette-8)">pick a cell </span><span style="font-weight:bold">Shift+arrows</span> <span style="color:var(--vt-palette-8)">pick a range </span><span style="font-weight:bold">Enter</span> <span style="color:var(--vt-palette-8)">accept </span><span style="font-weight:bold">Esc</span> <span style="color:var(--vt-palette-8)">back</span>4-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> A </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> B </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> C D E F G H I </span>5-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 1 </span> Household budget 20266-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 2 </span>7-<span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> 3 </span> Rent <span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> 1450 </span>8-<span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> 4 </span> Groceries<span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> 612.4 </span>9-<span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> 5 </span> Transit <span style="color:var(--vt-palette-0);background:var(--vt-palette-6)"> 96 </span>10-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 6 </span> Savings r<span style="color:var(--vt-palette-1)"> #DIV/0! </span>11-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 7 </span> Total 2158.412-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 8 </span>13-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 9 </span>14-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 10 </span>15-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 11 </span>16-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 12 </span>17-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 13 </span>18-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 14 </span>19-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 15 </span>20-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 16 </span>21-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 17 </span>22-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 18 </span>23-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 19 </span>24-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 20 </span>25-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 21 </span>26-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 22 </span>27-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 23 </span>28-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 24 </span>29-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 25 </span>30-untitled<span style="color:var(--vt-palette-8)"> modified</span> <span style="font-weight:bold">F1</span> <span style="color:var(--vt-palette-8)">help </span><span style="font-weight:bold">F10</span> <span style="color:var(--vt-palette-8)">menu </span><span style="font-weight:bold">Ctrl+Q</span> <span style="color:var(--vt-palette-8)">quit</span></pre>\ No newline at end of file1+<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">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">POINT</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)">C7</span><span style="background:var(--vt-palette-8)"> </span> =AVERAGE(<span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">B3:B5</span>3+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Arrows</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">pick</span> <span style="color:var(--vt-palette-8)">a</span> <span style="color:var(--vt-palette-8)">cell</span> <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Shift+arrows</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">pick</span> <span style="color:var(--vt-palette-8)">a</span> <span style="color:var(--vt-palette-8)">range</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)">accept</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)">back</span>4+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">A</span><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">B</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)">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-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1</span><span style="background:var(--vt-palette-8)"> </span> Household budget 20266+<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-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">3</span><span style="background:var(--vt-palette-4)"> </span> Rent <span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">1450</span><span style="background:var(--vt-palette-4)"> </span>8+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">4</span><span style="background:var(--vt-palette-4)"> </span> Groceries<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">612.4</span><span style="background:var(--vt-palette-4)"> </span>9+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">5</span><span style="background:var(--vt-palette-6)"> </span> Transit <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">96</span><span style="background:var(--vt-palette-6)"> </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> Savings r <span style="color:var(--vt-palette-1)">#DIV/0!</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> Total 2158.412+<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+untitled <span style="color:var(--vt-palette-8)">modified</span> <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
M e2e/testdata/screens/prompt-width.html +30 -30
@@ -1,30 +1,30 @@
1-<pre class="screen"><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> A1 </span> Household budget 2026 <span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> WIDTH</span><span style="background:var(--vt-palette-6)"> </span>2-Column width (1-240): 133-<span style="font-weight:bold">Left/Right</span> <span style="color:var(--vt-palette-8)">adjust </span><span style="font-weight:bold">Enter</span> <span style="color:var(--vt-palette-8)">apply </span><span style="font-weight:bold">Esc</span> <span style="color:var(--vt-palette-8)">cancel</span>4-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> A </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> B C D E F G H I </span>5-<span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> 1 </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)"> Household bu</span>dget 20266-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 2 </span>7-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 3 </span> Rent 14508-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 4 </span> Groceries 612.49-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 5 </span> Transit 9610-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 6 </span> Savings rate<span style="color:var(--vt-palette-1)"> #DIV/0! </span>11-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 7 </span> Total 2158.412-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 8 </span>13-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 9 </span>14-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 10 </span>15-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 11 </span>16-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 12 </span>17-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 13 </span>18-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 14 </span>19-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 15 </span>20-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 16 </span>21-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 17 </span>22-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 18 </span>23-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 19 </span>24-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 20 </span>25-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 21 </span>26-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 22 </span>27-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 23 </span>28-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 24 </span>29-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 25 </span>30-untitled<span style="color:var(--vt-palette-8)"> modified</span> <span style="font-weight:bold">F1</span> <span style="color:var(--vt-palette-8)">help </span><span style="font-weight:bold">F10</span> <span style="color:var(--vt-palette-8)">menu </span><span style="font-weight:bold">Ctrl+Q</span> <span style="color:var(--vt-palette-8)">quit</span></pre>\ No newline at end of file1+<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">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">WIDTH</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> Household budget 20263+Column width (1-240): 13 <span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">Left/Right</span><span style="background:var(--vt-palette-8)"> </span> <span style="color:var(--vt-palette-8)">adjust</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)">apply</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><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">Household</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">bu</span>dget 20266+<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> Rent 14508+<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> Groceries 612.49+<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> Transit 9610+<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> Savings rate <span style="color:var(--vt-palette-1)">#DIV/0!</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> Total 2158.412+<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+untitled <span style="color:var(--vt-palette-8)">modified</span> <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
M e2e/testdata/screens/quit-confirm-light.html +30 -30
@@ -1,30 +1,30 @@
1-<pre class="screen"><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> B7 </span> =SUM(B3:B5) <span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> MENU</span><span style="background:var(--vt-palette-6)"> </span>2-Cancel <span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">Quit without saving</span>3-You have unsaved changes. Close one23 anyway?4-<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> A </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> B </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> C D E F G H I </span>5-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 1 </span> Household budget 20266-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 2 </span>7-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 3 </span> Rent 14508-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 4 </span> Groceries 612.49-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 5 </span> Transit 9610-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 6 </span> Savings r<span style="color:var(--vt-palette-1)"> #DIV/0! </span>11-<span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> 7 </span> Total <span style="color:var(--vt-palette-0);background:var(--vt-palette-6)"> 2158.4 </span>12-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 8 </span>13-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 9 </span>14-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 10 </span>15-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 11 </span>16-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 12 </span>17-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 13 </span>18-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 14 </span>19-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 15 </span>20-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 16 </span>21-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 17 </span>22-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 18 </span>23-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 19 </span>24-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 20 </span>25-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 21 </span>26-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 22 </span>27-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 23 </span>28-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 24 </span>29-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 25 </span>30-untitled<span style="color:var(--vt-palette-0)"> modified</span> <span style="font-weight:bold">F1</span> <span style="color:var(--vt-palette-0)">help </span><span style="font-weight:bold">F10</span> <span style="color:var(--vt-palette-0)">menu </span><span style="font-weight:bold">Ctrl+Q</span> <span style="color:var(--vt-palette-0)">quit</span></pre>\ No newline at end of file1+<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">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">MENU</span><span style="background:var(--vt-palette-6)"> </span>2+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">B7</span><span style="background:var(--vt-palette-7)"> </span> =SUM(B3:B5)3+<span style="color:var(--vt-palette-3)">You</span> <span style="color:var(--vt-palette-3)">have</span> <span style="color:var(--vt-palette-3)">unsaved</span> <span style="color:var(--vt-palette-3)">changes.</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Enter</span><span style="background:var(--vt-palette-7)"> </span> Save and quit <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">D</span><span style="background:var(--vt-palette-7)"> </span> Discard <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Esc</span><span style="background:var(--vt-palette-7)"> </span> Cancel4+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">A</span><span style="background:var(--vt-palette-7)"> </span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">B</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">C</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">D</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">E</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">F</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">G</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">H</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">I</span><span style="background:var(--vt-palette-7)"> </span>5+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1</span><span style="background:var(--vt-palette-7)"> </span> Household budget 20266+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">2</span><span style="background:var(--vt-palette-7)"> </span>7+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">3</span><span style="background:var(--vt-palette-7)"> </span> Rent 14508+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">4</span><span style="background:var(--vt-palette-7)"> </span> Groceries 612.49+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">5</span><span style="background:var(--vt-palette-7)"> </span> Transit 9610+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">6</span><span style="background:var(--vt-palette-7)"> </span> Savings r <span style="color:var(--vt-palette-1)">#DIV/0!</span>11+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">7</span><span style="background:var(--vt-palette-6)"> </span> Total <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">2158.4</span><span style="background:var(--vt-palette-6)"> </span>12+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">8</span><span style="background:var(--vt-palette-7)"> </span>13+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">9</span><span style="background:var(--vt-palette-7)"> </span>14+<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>15+<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>16+<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>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>18+<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>19+<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>20+<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>21+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">17</span><span style="background:var(--vt-palette-7)"> </span>22+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">18</span><span style="background:var(--vt-palette-7)"> </span>23+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">19</span><span style="background:var(--vt-palette-7)"> </span>24+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">20</span><span style="background:var(--vt-palette-7)"> </span>25+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">21</span><span style="background:var(--vt-palette-7)"> </span>26+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">22</span><span style="background:var(--vt-palette-7)"> </span>27+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">23</span><span style="background:var(--vt-palette-7)"> </span>28+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">24</span><span style="background:var(--vt-palette-7)"> </span>29+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">25</span><span style="background:var(--vt-palette-7)"> </span>30+untitled <span style="color:var(--vt-palette-0)">modified</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+K</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">search</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+/</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">shortcuts</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">F10</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">menu</span></pre>\ No newline at end of file
M e2e/testdata/screens/quit-confirm.html +30 -30
@@ -1,30 +1,30 @@
1-<pre class="screen"><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> B7 </span> =SUM(B3:B5) <span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> MENU</span><span style="background:var(--vt-palette-6)"> </span>2-Cancel <span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">Quit without saving</span>3-You have unsaved changes. Close one23 anyway?4-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> A </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> B </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> C D E F G H I </span>5-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 1 </span> Household budget 20266-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 2 </span>7-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 3 </span> Rent 14508-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 4 </span> Groceries 612.49-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 5 </span> Transit 9610-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 6 </span> Savings r<span style="color:var(--vt-palette-1)"> #DIV/0! </span>11-<span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> 7 </span> Total <span style="color:var(--vt-palette-0);background:var(--vt-palette-6)"> 2158.4 </span>12-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 8 </span>13-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 9 </span>14-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 10 </span>15-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 11 </span>16-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 12 </span>17-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 13 </span>18-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 14 </span>19-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 15 </span>20-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 16 </span>21-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 17 </span>22-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 18 </span>23-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 19 </span>24-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 20 </span>25-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 21 </span>26-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 22 </span>27-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 23 </span>28-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 24 </span>29-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 25 </span>30-untitled<span style="color:var(--vt-palette-8)"> modified</span> <span style="font-weight:bold">F1</span> <span style="color:var(--vt-palette-8)">help </span><span style="font-weight:bold">F10</span> <span style="color:var(--vt-palette-8)">menu </span><span style="font-weight:bold">Ctrl+Q</span> <span style="color:var(--vt-palette-8)">quit</span></pre>\ No newline at end of file1+<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">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">MENU</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)">B7</span><span style="background:var(--vt-palette-8)"> </span> =SUM(B3:B5)3+<span style="color:var(--vt-palette-3)">You</span> <span style="color:var(--vt-palette-3)">have</span> <span style="color:var(--vt-palette-3)">unsaved</span> <span style="color:var(--vt-palette-3)">changes.</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> Save and quit <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> Discard <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> Cancel4+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">A</span><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">B</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)">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-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1</span><span style="background:var(--vt-palette-8)"> </span> Household budget 20266+<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> Rent 14508+<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> Groceries 612.49+<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> Transit 9610+<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> Savings r <span style="color:var(--vt-palette-1)">#DIV/0!</span>11+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">7</span><span style="background:var(--vt-palette-6)"> </span> Total <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">2158.4</span><span style="background:var(--vt-palette-6)"> </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+untitled <span style="color:var(--vt-palette-8)">modified</span> <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
M e2e/testdata/screens/ready-empty.html +29 -29
@@ -1,30 +1,30 @@
1-<pre class="screen"><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> A1 </span> <span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> READY</span><span style="background:var(--vt-palette-6)"> </span>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">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">READY</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>23 3-4-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> A </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> B C D E F G H I </span>5-<span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> 1 </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)"> </span>6-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 2 </span>7-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 3 </span>8-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 4 </span>9-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 5 </span>10-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 6 </span>11-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 7 </span>12-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 8 </span>13-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 9 </span>14-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 10 </span>15-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 11 </span>16-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 12 </span>17-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 13 </span>18-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 14 </span>19-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 15 </span>20-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 16 </span>21-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 17 </span>22-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 18 </span>23-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 19 </span>24-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 20 </span>25-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 21 </span>26-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 22 </span>27-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 23 </span>28-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 24 </span>29-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 25 </span>30-untitled <span style="font-weight:bold">F1</span> <span style="color:var(--vt-palette-8)">help </span><span style="font-weight:bold">F10</span> <span style="color:var(--vt-palette-8)">menu </span><span style="font-weight:bold">Ctrl+Q</span> <span style="color:var(--vt-palette-8)">quit</span></pre>\ No newline at end of file4+<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+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/resizing-column-light.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">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">READY</span><span style="background:var(--vt-palette-6)"> </span>2+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">B7</span><span style="background:var(--vt-palette-7)"> </span> =SUM(B3:B5)3+<span style="font-weight:bold">Column</span> <span style="font-weight:bold">A</span> <span style="color:var(--vt-palette-0)">width</span> 16 <span style="color:var(--vt-palette-0)">double-click</span> <span style="color:var(--vt-palette-0)">the</span> <span style="color:var(--vt-palette-0)">border</span> <span style="color:var(--vt-palette-0)">to</span> <span style="color:var(--vt-palette-0)">fit</span>4+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">A</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-6);background:var(--vt-palette-7);font-weight:bold">▐</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">B</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">C</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">D</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">E</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">F</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">G</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">H</span><span style="background:var(--vt-palette-7)"> </span>5+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1</span><span style="background:var(--vt-palette-7)"> </span> Household budget 20266+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">2</span><span style="background:var(--vt-palette-7)"> </span>7+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">3</span><span style="background:var(--vt-palette-7)"> </span> Rent 14508+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">4</span><span style="background:var(--vt-palette-7)"> </span> Groceries 612.49+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">5</span><span style="background:var(--vt-palette-7)"> </span> Transit 9610+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">6</span><span style="background:var(--vt-palette-7)"> </span> Savings rate <span style="color:var(--vt-palette-1)">#DIV/0!</span>11+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">7</span><span style="background:var(--vt-palette-6)"> </span> Total <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">2158.4</span><span style="background:var(--vt-palette-6)"> </span>12+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">8</span><span style="background:var(--vt-palette-7)"> </span>13+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">9</span><span style="background:var(--vt-palette-7)"> </span>14+<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>15+<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>16+<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>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>18+<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>19+<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>20+<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>21+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">17</span><span style="background:var(--vt-palette-7)"> </span>22+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">18</span><span style="background:var(--vt-palette-7)"> </span>23+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">19</span><span style="background:var(--vt-palette-7)"> </span>24+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">20</span><span style="background:var(--vt-palette-7)"> </span>25+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">21</span><span style="background:var(--vt-palette-7)"> </span>26+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">22</span><span style="background:var(--vt-palette-7)"> </span>27+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">23</span><span style="background:var(--vt-palette-7)"> </span>28+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">24</span><span style="background:var(--vt-palette-7)"> </span>29+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">25</span><span style="background:var(--vt-palette-7)"> </span>30+untitled <span style="color:var(--vt-palette-0)">modified</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+K</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">search</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">Ctrl+/</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">shortcuts</span> <span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">F10</span><span style="background:var(--vt-palette-7)"> </span> <span style="color:var(--vt-palette-0)">menu</span></pre>\ No newline at end of file
A e2e/testdata/screens/resizing-column.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">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">READY</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)">B7</span><span style="background:var(--vt-palette-8)"> </span> =SUM(B3:B5)3+<span style="font-weight:bold">Column</span> <span style="font-weight:bold">A</span> <span style="color:var(--vt-palette-8)">width</span> 16 <span style="color:var(--vt-palette-8)">double-click</span> <span style="color:var(--vt-palette-8)">the</span> <span style="color:var(--vt-palette-8)">border</span> <span style="color:var(--vt-palette-8)">to</span> <span style="color:var(--vt-palette-8)">fit</span>4+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">A</span><span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-6);background:var(--vt-palette-8);font-weight:bold">▐</span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">B</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)">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>5+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1</span><span style="background:var(--vt-palette-8)"> </span> Household budget 20266+<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> Rent 14508+<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> Groceries 612.49+<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> Transit 9610+<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> Savings rate <span style="color:var(--vt-palette-1)">#DIV/0!</span>11+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">7</span><span style="background:var(--vt-palette-6)"> </span> Total <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">2158.4</span><span style="background:var(--vt-palette-6)"> </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+untitled <span style="color:var(--vt-palette-8)">modified</span> <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
M e2e/testdata/screens/selection-stats-light.html +29 -29
@@ -1,30 +1,30 @@
1-<pre class="screen"><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> B3 </span> 1450 <span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> READY</span><span style="background:var(--vt-palette-6)"> </span>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">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">READY</span><span style="background:var(--vt-palette-6)"> </span>2+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">B3:B5</span><span style="background:var(--vt-palette-7)"> </span> 145023 3-4-<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> A </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> B </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> C D E F G H I </span>5-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 1 </span> Household budget 20266-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 2 </span>7-<span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> 3 </span> Rent <span style="color:var(--vt-palette-0);background:var(--vt-palette-6)"> 1450 </span>8-<span style="color:var(--vt-palette-15);background:var(--vt-palette-4)"> 4 </span> Groceries<span style="color:var(--vt-palette-15);background:var(--vt-palette-4)"> 612.4 </span>9-<span style="color:var(--vt-palette-15);background:var(--vt-palette-4)"> 5 </span> Transit <span style="color:var(--vt-palette-15);background:var(--vt-palette-4)"> 96 </span>10-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 6 </span> Savings r<span style="color:var(--vt-palette-1)"> #DIV/0! </span>11-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 7 </span> Total 2158.412-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 8 </span>13-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 9 </span>14-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 10 </span>15-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 11 </span>16-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 12 </span>17-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 13 </span>18-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 14 </span>19-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 15 </span>20-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 16 </span>21-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 17 </span>22-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 18 </span>23-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 19 </span>24-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 20 </span>25-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 21 </span>26-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 22 </span>27-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 23 </span>28-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 24 </span>29-<span style="color:var(--vt-palette-0);background:var(--vt-palette-7)"> 25 </span>30-untitled<span style="color:var(--vt-palette-0)"> modified</span> <span style="font-weight:bold">B3:B5</span> <span style="color:var(--vt-palette-0)">Sum </span>2158.4 <span style="color:var(--vt-palette-0)">Avg </span>719.47 <span style="color:var(--vt-palette-0)">Count </span>3</pre>\ No newline at end of file4+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">A</span><span style="background:var(--vt-palette-7)"> </span><span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">B</span><span style="background:var(--vt-palette-6)"> </span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">C</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">D</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">E</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">F</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">G</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">H</span><span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">I</span><span style="background:var(--vt-palette-7)"> </span>5+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">1</span><span style="background:var(--vt-palette-7)"> </span> Household budget 20266+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">2</span><span style="background:var(--vt-palette-7)"> </span>7+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">3</span><span style="background:var(--vt-palette-6)"> </span> Rent <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">1450</span><span style="background:var(--vt-palette-6)"> </span>8+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">4</span><span style="background:var(--vt-palette-4)"> </span> Groceries<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">612.4</span><span style="background:var(--vt-palette-4)"> </span>9+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">5</span><span style="background:var(--vt-palette-4)"> </span> Transit <span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-4)">96</span><span style="background:var(--vt-palette-4)"> </span>10+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">6</span><span style="background:var(--vt-palette-7)"> </span> Savings r <span style="color:var(--vt-palette-1)">#DIV/0!</span>11+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">7</span><span style="background:var(--vt-palette-7)"> </span> Total 2158.412+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">8</span><span style="background:var(--vt-palette-7)"> </span>13+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">9</span><span style="background:var(--vt-palette-7)"> </span>14+<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>15+<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>16+<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>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>18+<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>19+<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>20+<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>21+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">17</span><span style="background:var(--vt-palette-7)"> </span>22+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">18</span><span style="background:var(--vt-palette-7)"> </span>23+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">19</span><span style="background:var(--vt-palette-7)"> </span>24+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">20</span><span style="background:var(--vt-palette-7)"> </span>25+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">21</span><span style="background:var(--vt-palette-7)"> </span>26+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">22</span><span style="background:var(--vt-palette-7)"> </span>27+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">23</span><span style="background:var(--vt-palette-7)"> </span>28+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">24</span><span style="background:var(--vt-palette-7)"> </span>29+<span style="background:var(--vt-palette-7)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-7)">25</span><span style="background:var(--vt-palette-7)"> </span>30+untitled <span style="color:var(--vt-palette-0)">modified</span> <span style="font-weight:bold">B3:B5</span> <span style="color:var(--vt-palette-0)">Sum</span> 2158.4 <span style="color:var(--vt-palette-0)">Avg</span> 719.47 <span style="color:var(--vt-palette-0)">Count</span> 3</pre>\ No newline at end of file
M e2e/testdata/screens/selection-stats.html +29 -29
@@ -1,30 +1,30 @@
1-<pre class="screen"><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> B3 </span> 1450 <span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> READY</span><span style="background:var(--vt-palette-6)"> </span>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">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">READY</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)">B3:B5</span><span style="background:var(--vt-palette-8)"> </span> 145023 3-4-<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> A </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> B </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> C D E F G H I </span>5-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 1 </span> Household budget 20266-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 2 </span>7-<span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold"> 3 </span> Rent <span style="color:var(--vt-palette-0);background:var(--vt-palette-6)"> 1450 </span>8-<span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> 4 </span> Groceries<span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> 612.4 </span>9-<span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> 5 </span> Transit <span style="color:var(--vt-palette-0);background:var(--vt-palette-4)"> 96 </span>10-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 6 </span> Savings r<span style="color:var(--vt-palette-1)"> #DIV/0! </span>11-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 7 </span> Total 2158.412-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 8 </span>13-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 9 </span>14-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 10 </span>15-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 11 </span>16-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 12 </span>17-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 13 </span>18-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 14 </span>19-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 15 </span>20-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 16 </span>21-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 17 </span>22-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 18 </span>23-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 19 </span>24-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 20 </span>25-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 21 </span>26-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 22 </span>27-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 23 </span>28-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 24 </span>29-<span style="color:var(--vt-palette-15);background:var(--vt-palette-8)"> 25 </span>30-untitled<span style="color:var(--vt-palette-8)"> modified</span> <span style="font-weight:bold">B3:B5</span> <span style="color:var(--vt-palette-8)">Sum </span>2158.4 <span style="color:var(--vt-palette-8)">Avg </span>719.47 <span style="color:var(--vt-palette-8)">Count </span>3</pre>\ No newline at end of file4+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">A</span><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">B</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)">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-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1</span><span style="background:var(--vt-palette-8)"> </span> Household budget 20266+<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-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">3</span><span style="background:var(--vt-palette-6)"> </span> Rent <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">1450</span><span style="background:var(--vt-palette-6)"> </span>8+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">4</span><span style="background:var(--vt-palette-4)"> </span> Groceries<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">612.4</span><span style="background:var(--vt-palette-4)"> </span>9+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">5</span><span style="background:var(--vt-palette-4)"> </span> Transit <span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">96</span><span style="background:var(--vt-palette-4)"> </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> Savings r <span style="color:var(--vt-palette-1)">#DIV/0!</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> Total 2158.412+<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+untitled <span style="color:var(--vt-palette-8)">modified</span> <span style="font-weight:bold">B3:B5</span> <span style="color:var(--vt-palette-8)">Sum</span> 2158.4 <span style="color:var(--vt-palette-8)">Avg</span> 719.47 <span style="color:var(--vt-palette-8)">Count</span> 3</pre>\ No newline at end of file
A e2e/testdata/screens/undo-note.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">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">READY</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)">B5:B6</span><span style="background:var(--vt-palette-8)"> </span> 963+Undid: clear B5:B64+<span style="background:var(--vt-palette-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">A</span><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">B</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)">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-8)"> </span><span style="color:var(--vt-palette-15);background:var(--vt-palette-8)">1</span><span style="background:var(--vt-palette-8)"> </span> Household budget 20266+<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> Rent 14508+<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> Groceries 612.49+<span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6);font-weight:bold">5</span><span style="background:var(--vt-palette-6)"> </span> Transit <span style="background:var(--vt-palette-6)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-6)">96</span><span style="background:var(--vt-palette-6)"> </span>10+<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">6</span><span style="background:var(--vt-palette-4)"> </span> Savings r<span style="background:var(--vt-palette-4)"> </span><span style="color:var(--vt-palette-0);background:var(--vt-palette-4)">#DIV/0!</span><span style="background:var(--vt-palette-4)"> </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> Total 2158.412+<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+untitled <span style="color:var(--vt-palette-8)">modified</span> <span style="font-weight:bold">B5:B6</span> <span style="color:var(--vt-palette-8)">Sum</span> 96 <span style="color:var(--vt-palette-8)">Avg</span> 96 <span style="color:var(--vt-palette-8)">Count</span> 2</pre>\ No newline at end of file
M go.mod +1 -0
M go.sum +4 -0
@@ -22,6 +22,8 @@ github.com/clipperhouse/displaywidth v0.11.0 h1:lBc6kY44VFw+TDx4I8opi/EtL9m20WSE
2222 github.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0=2323 github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk=2424 github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=25+github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=26+github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=2527 github.com/lucasb-eyer/go-colorful v1.4.1 h1:1EO+WB73+EH8EVbzlrG3KLAfEypQWVHIBqlTf+2hNss=2628 github.com/lucasb-eyer/go-colorful v1.4.1/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=2729 github.com/mattn/go-runewidth v0.0.24 h1:cpokDiIn0MGnhdHwuWnJBITySJ20QyNGnY2kR/ay2DU=
@@ -30,6 +32,8 @@ github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELU
3032 github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=3133 github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=3234 github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=35+github.com/sahilm/fuzzy v0.1.3 h1:juByESSS32nVD81vr6tHmKmA/8zde7gE+x5CLxrzXPU=36+github.com/sahilm/fuzzy v0.1.3/go.mod h1:au6//VbVSqu6DFrkL2CfjlJ5iURpNCPeE+1GwY3XsT8=3337 github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=3438 github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=3539 golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
M internal/sheet/addr.go +43 -7
@@ -53,21 +53,57 @@ func ParseCol(s string) (int, bool) {
5353 // ParseAddr parses an A1-style reference. Absolute markers ($A$1) are5454 // accepted and ignored.5555 func ParseAddr(s string) (Addr, bool) {56- s = strings.ReplaceAll(s, "$", "")56+ a, _, ok := parseRef(s)57+ return a, ok58+}59+60+// absFlags records which parts of a reference are absolute ($A$1). Copying61+// a formula shifts only the relative parts.62+type absFlags uint863+64+const (65+ absCol absFlags = 1 << iota66+ absRow67+)68+69+// parseRef parses a reference written as A1, $A1, A$1 or $A$1.70+func parseRef(s string) (Addr, absFlags, bool) {71+ var abs absFlags72+ if rest, ok := strings.CutPrefix(s, "$"); ok {73+ s, abs = rest, absCol74+ }5775 i := 05876 for i < len(s) && isLetter(s[i]) {5977 i++6078 }6179 col, ok := ParseCol(s[:i])62- if !ok || i == len(s) {63- return Addr{}, false80+ if !ok {81+ return Addr{}, 0, false82+ }83+ digits := s[i:]84+ if rest, ok := strings.CutPrefix(digits, "$"); ok {85+ digits, abs = rest, abs|absRow6486 }65- row, err := strconv.Atoi(s[i:])66- if err != nil || s[i] == '+' || s[i] == '-' {67- return Addr{}, false87+ if digits == "" || strings.ContainsFunc(digits, func(r rune) bool { return r < '0' || r > '9' }) {88+ return Addr{}, 0, false6889 }90+ row, err := strconv.Atoi(digits)6991 a := Addr{Col: col, Row: row - 1}70- return a, a.Valid()92+ return a, abs, err == nil && a.Valid()93+}94+95+// refString writes a with its absolute markers, e.g. $A1.96+func refString(a Addr, abs absFlags) string {97+ var b strings.Builder98+ if abs&absCol != 0 {99+ b.WriteByte('$')100+ }101+ b.WriteString(ColName(a.Col))102+ if abs&absRow != 0 {103+ b.WriteByte('$')104+ }105+ b.WriteString(strconv.Itoa(a.Row + 1))106+ return b.String()71107 }72108 73109 // Rect is an inclusive rectangular range of cells.
M internal/sheet/eval.go +8 -0
A internal/sheet/find.go +139 -0
@@ -0,0 +1,139 @@
1+package sheet2+3+import (4+ "regexp"5+ "strings"6+)7+8+// FindOptions mirror Google Sheets' Find and replace dialog.9+type FindOptions struct {10+ MatchCase bool11+ WholeCell bool // the whole cell must match, not just part of it12+ Regex bool // the query is a regular expression; replacements may use $113+ InFormulas bool // search formula text instead of formula results14+ Within *Rect // limit the search to a range; nil searches the sheet15+}16+17+// finder is a compiled query.18+type finder struct {19+ re *regexp.Regexp20+ o FindOptions21+}22+23+func newFinder(query string, o FindOptions) (*finder, error) {24+ pat := query25+ if !o.Regex {26+ pat = regexp.QuoteMeta(query)27+ }28+ if o.WholeCell {29+ pat = "^(?:" + pat + ")$"30+ }31+ if !o.MatchCase {32+ pat = "(?i)" + pat33+ }34+ re, err := regexp.Compile(pat)35+ if err != nil {36+ return nil, err37+ }38+ return &finder{re: re, o: o}, nil39+}40+41+// text is what the search looks at in a cell: formula text when searching42+// within formulas, otherwise what the cell shows.43+func (f *finder) text(c *Cell) string {44+ if c.IsFormula() && f.o.InFormulas {45+ return c.Input46+ }47+ if c.IsFormula() {48+ return c.Value.String()49+ }50+ return strings.TrimPrefix(c.Input, "'")51+}52+53+// Find returns the cells matching query in reading order: row by row,54+// left to right.55+func (s *Sheet) Find(query string, o FindOptions) ([]Addr, error) {56+ if query == "" {57+ return nil, nil58+ }59+ f, err := newFinder(query, o)60+ if err != nil {61+ return nil, err62+ }63+ var out []Addr64+ for _, a := range s.Addrs() {65+ if o.Within != nil && !o.Within.Contains(a) {66+ continue67+ }68+ if f.re.MatchString(f.text(s.cells[a])) {69+ out = append(out, a)70+ }71+ }72+ return out, nil73+}74+75+// Replace replaces matches of query in the cell at a and reports whether76+// the cell changed. Formula cells are only changed when searching within77+// formulas, as in Sheets. A replacement that turns a formula invalid is78+// returned as an error and leaves the cell unchanged.79+func (s *Sheet) Replace(a Addr, query, repl string, o FindOptions) (bool, error) {80+ f, err := newFinder(query, o)81+ if err != nil {82+ return false, err83+ }84+ return s.replace(a, f, repl)85+}86+87+func (s *Sheet) replace(a Addr, f *finder, repl string) (bool, error) {88+ c := s.cells[a]89+ if c == nil || (c.IsFormula() && !f.o.InFormulas) {90+ return false, nil91+ }92+ old := f.text(c)93+ if !f.re.MatchString(old) {94+ return false, nil95+ }96+ if !f.o.Regex {97+ repl = strings.ReplaceAll(repl, "$", "$$")98+ }99+ next := f.re.ReplaceAllString(old, repl)100+ if strings.HasPrefix(c.Input, "'") && !c.IsFormula() {101+ next = "'" + next // keep text forced as text102+ }103+ if next == c.Input {104+ return false, nil105+ }106+ return true, s.Set(a, next)107+}108+109+// ReplaceAll replaces every match and returns how many cells changed. It110+// stops at the first cell whose replacement is an invalid formula.111+func (s *Sheet) ReplaceAll(query, repl string, o FindOptions) (int, error) {112+ cells, err := s.Find(query, o)113+ if err != nil {114+ return 0, err115+ }116+ f, err := newFinder(query, o)117+ if err != nil {118+ return 0, err119+ }120+ n := 0121+ var focus Rect122+ if len(cells) > 0 {123+ focus = NewRect(cells[0], cells[len(cells)-1])124+ }125+ // One undo step for the whole replacement.126+ err = s.Batch(Change{Label: "replace all", Focus: focus}, func() error {127+ for _, a := range cells {128+ changed, err := s.replace(a, f, repl)129+ if err != nil {130+ return err131+ }132+ if changed {133+ n++134+ }135+ }136+ return nil137+ })138+ return n, err139+}
A internal/sheet/find_test.go +126 -0
@@ -0,0 +1,126 @@
1+package sheet2+3+import (4+ "slices"5+ "testing"6+)7+8+func findSheet() *Sheet {9+ s := New()10+ for a, in := range map[string]string{11+ "A1": "Rent", "B1": "1450",12+ "A2": "rental car", "B2": "=B1*2",13+ "A3": "'2900", "B3": "=SUM(B1:B2)",14+ "C1": "Rent", "C2": "Total rent: $5",15+ } {16+ s.Set(at(a), in)17+ }18+ return s19+}20+21+func names(as []Addr) []string {22+ out := make([]string, len(as))23+ for i, a := range as {24+ out[i] = a.String()25+ }26+ return out27+}28+29+func TestFind(t *testing.T) {30+ s := findSheet()31+ b1b2 := NewRect(at("B1"), at("B2"))32+ tests := []struct {33+ query string34+ o FindOptions35+ want []string36+ }{37+ {"rent", FindOptions{}, []string{"A1", "C1", "A2", "C2"}}, // reading order38+ {"Rent", FindOptions{MatchCase: true}, []string{"A1", "C1"}},39+ {"rent", FindOptions{WholeCell: true}, []string{"A1", "C1"}},40+ {"2900", FindOptions{}, []string{"B2", "A3"}}, // formula results and forced text41+ {"B1", FindOptions{}, nil}, // formula text isn't searched by default42+ {"B1", FindOptions{InFormulas: true}, []string{"B2", "B3"}},43+ {`^r\w+`, FindOptions{Regex: true}, []string{"A1", "C1", "A2"}},44+ {"$5", FindOptions{}, []string{"C2"}}, // plain queries are literal45+ {"1450", FindOptions{Within: &b1b2}, []string{"B1"}},46+ {"", FindOptions{}, nil},47+ }48+ for _, tt := range tests {49+ got, err := s.Find(tt.query, tt.o)50+ if err != nil {51+ t.Errorf("Find(%q): %v", tt.query, err)52+ continue53+ }54+ if !slices.Equal(names(got), tt.want) {55+ t.Errorf("Find(%q, %+v) = %v, want %v", tt.query, tt.o, names(got), tt.want)56+ }57+ }58+ if _, err := s.Find("(", FindOptions{Regex: true}); err == nil {59+ t.Error("invalid regex accepted")60+ }61+}62+63+func TestReplace(t *testing.T) {64+ s := findSheet()65+ n, err := s.ReplaceAll("rent", "Lease", FindOptions{})66+ if err != nil || n != 4 {67+ t.Fatalf("ReplaceAll = %d, %v", n, err)68+ }69+ for a, want := range map[string]string{"A1": "Lease", "A2": "Leaseal car", "C2": "Total Lease: $5"} {70+ if got := s.Cell(at(a)).Input; got != want {71+ t.Errorf("%s = %q, want %q", a, got, want)72+ }73+ }74+75+ // Formulas only change when searching within them, and keep working.76+ if n, _ := s.ReplaceAll("B1", "A9", FindOptions{}); n != 0 {77+ t.Errorf("replaced %d formula results", n)78+ }79+ s.Set(at("A9"), "10")80+ if n, _ := s.ReplaceAll("B1", "A9", FindOptions{InFormulas: true}); n != 2 {81+ t.Errorf("replaced %d formulas", n)82+ }83+ if got := s.Value(at("B2")).Num; got != 20 {84+ t.Errorf("B2 = %v after rewriting its reference", got)85+ }86+87+ // Regex groups; forced text stays text; literal $ in plain mode.88+ s.Set(at("D1"), "2026-09-26")89+ s.Replace(at("D1"), `(\d+)-(\d+)-(\d+)`, "$3/$2/$1", FindOptions{Regex: true})90+ if got := s.Cell(at("D1")).Input; got != "26/09/2026" {91+ t.Errorf("regex replace = %q", got)92+ }93+ s.Replace(at("A3"), "2900", "3000", FindOptions{})94+ if c := s.Cell(at("A3")); c.Input != "'3000" || c.Value.Kind != Text {95+ t.Errorf("forced text = %+v", c)96+ }97+ s.Set(at("C1"), "Rent due")98+ s.Replace(at("C1"), "Rent", "$1", FindOptions{})99+ if got := s.Cell(at("C1")).Input; got != "$1 due" {100+ t.Errorf("plain replacement = %q, want a literal $1", got)101+ }102+103+ // A replacement that breaks a formula is an error and changes nothing.104+ s.Set(at("E1"), "=SUM(B1:B2)")105+ if _, err := s.Replace(at("E1"), ")", "", FindOptions{InFormulas: true}); err == nil {106+ t.Error("broken formula accepted")107+ }108+ if got := s.Cell(at("E1")).Input; got != "=SUM(B1:B2)" {109+ t.Errorf("E1 changed to %q", got)110+ }111+}112+113+func TestReplaceAllIsOneUndoStep(t *testing.T) {114+ s := findSheet()115+ if n, err := s.ReplaceAll("rent", "Lease", FindOptions{}); n != 4 || err != nil {116+ t.Fatalf("ReplaceAll = %d, %v", n, err)117+ }118+ if _, ok := s.Undo(); !ok {119+ t.Fatal("nothing to undo")120+ }121+ for a, want := range map[string]string{"A1": "Rent", "A2": "rental car", "C1": "Rent", "C2": "Total rent: $5"} {122+ if got := s.Cell(at(a)).Input; got != want {123+ t.Errorf("%s = %q after undo, want %q", a, got, want)124+ }125+ }126+}
M internal/sheet/history.go +196 -26
@@ -1,63 +1,233 @@
11 package sheet22 3-// This file is a stand-in for the undo history on main4-// (internal/sheet/history.go there), with the same change, record, clone,5-// Batch and ClearHistory but no undo. Every mutation in this branch goes6-// through change and place as it does on main, so formatting changes7-// become undo steps once merged. When merging, take main's version of8-// this file.3+// MaxUndo is how many steps of undo history a sheet keeps.4+const MaxUndo = 10095 6+// History is a command log of before-images. Each step records, for every7+// cell and column width it touched, the state before the step; undoing8+// swaps those back in and records the state it replaced as the redo step.9+//10+// Steps snapshot whole cells (a shallow copy of the struct), so fields11+// added to Cell later are covered without changes here. That relies on12+// one rule: a stored *Cell is never modified in place except for its13+// computed Value. To change a cell, build a new one and store it with14+// place.1015 type history struct {11- depth int // nesting of change calls12- dirty []Addr // cells changed in the open step16+ undo, redo []*step17+ open *step // the step being built; nil outside change18+ depth int // nesting of change calls19+ dirty []Addr20+ lastID int21+ // mergeWidths lets the next width-only step join the top one, so a22+ // live preview of a column width and its final value (or its23+ // cancellation) are one step. Seal ends the run.24+ mergeWidths bool1325 }1426 15-// Change describes a step: what it did, in lower case for use in a16-// sentence ("format B3:B5 as currency"), and the range it affected.27+type step struct {28+ id int29+ label string // what the step did, e.g. "clear B3:B5"30+ focus Rect // what the UI selects when the step is undone or redone31+ cells map[Addr]*Cell // before the step; nil for blank32+ widths map[int]int // before the step; 0 for the default width33+}34+35+func (st *step) empty() bool { return len(st.cells) == 0 && len(st.widths) == 0 }36+37+func (c *Cell) clone() *Cell {38+ if c == nil {39+ return nil40+ }41+ cp := *c42+ return &cp43+}44+45+// Change describes an undo step: what it did, in lower case for use in a46+// sentence ("clear B3:B5"), and the range it affected.1747 type Change struct {1848 Label string1949 Focus Rect2050 }2151 22-// Batch runs fn as a single step, recalculating once at the end. Batches23-// nest; inner ones join the outermost.52+// Batch runs fn as a single undo step: everything it changes is undone53+// together, and formulas are recalculated once at the end. Batches nest;54+// inner ones join the outermost.2455 func (s *Sheet) Batch(c Change, fn func() error) error {2556 var err error2657 s.change(c.Label, c.Focus, func() { err = fn() })2758 return err2859 }2960 30-// change runs fn and, on the way out of the outermost call, recalculates31-// what changed.32-func (s *Sheet) change(_ string, _ Rect, fn func()) {61+// change opens a step (unless one is open), runs fn, and on the way out62+// of the outermost call recalculates what changed and pushes the step.63+func (s *Sheet) change(label string, focus Rect, fn func()) {3364 h := &s.hist65+ if h.depth == 0 {66+ h.open = &step{label: label, focus: focus, cells: map[Addr]*Cell{}, widths: map[int]int{}}67+ }3468 h.depth++3569 defer func() {3670 h.depth--3771 if h.depth > 0 {3872 return3973 }40- dirty := h.dirty41- h.dirty = nil74+ st, dirty := h.open, h.dirty75+ h.open, h.dirty = nil, nil4276 s.recalc(dirty)77+ s.push(st)4378 }()4479 fn()4580 }4681 47-// record notes that the cell at a is about to change.82+// record saves the cell at a before its first change in the open step.4883 func (s *Sheet) record(a Addr) {49- if s.hist.depth > 0 {50- s.hist.dirty = append(s.hist.dirty, a)84+ st := s.hist.open85+ if st == nil {86+ return87+ }88+ if _, seen := st.cells[a]; !seen {89+ st.cells[a] = s.cells[a].clone()5190 }91+ s.hist.dirty = append(s.hist.dirty, a)5292 }5393 54-func (c *Cell) clone() *Cell {55- if c == nil {94+// recordWidth saves column c's width before its first change in the open95+// step.96+func (s *Sheet) recordWidth(c int) {97+ st := s.hist.open98+ if st == nil {99+ return100+ }101+ if _, seen := st.widths[c]; !seen {102+ st.widths[c] = s.widths[c]103+ }104+}105+106+// push adds a finished step to the undo stack and clears redo, dropping107+// no-op changes.108+func (s *Sheet) push(st *step) {109+ h := &s.hist110+ for c, w := range st.widths {111+ if s.widths[c] == w {112+ delete(st.widths, c)113+ }114+ }115+ for a, c := range st.cells {116+ if c == nil && s.cells[a] == nil {117+ delete(st.cells, a)118+ }119+ }120+ if st.empty() {121+ return122+ }123+ h.redo = nil124+ h.lastID++125+ widthOnly := len(st.cells) == 0126+ if top := h.top(); widthOnly && h.mergeWidths && top != nil && len(top.cells) == 0 {127+ for c, w := range st.widths {128+ if _, ok := top.widths[c]; !ok {129+ top.widths[c] = w130+ }131+ }132+ for c, w := range top.widths {133+ if s.widths[c] == w {134+ delete(top.widths, c)135+ }136+ }137+ top.id, top.focus = h.lastID, union(top.focus, st.focus)138+ if top.empty() {139+ h.undo = h.undo[:len(h.undo)-1]140+ }141+ return142+ }143+ st.id = h.lastID144+ h.undo = append(h.undo, st)145+ if len(h.undo) > MaxUndo {146+ h.undo = h.undo[len(h.undo)-MaxUndo:]147+ }148+ h.mergeWidths = widthOnly149+}150+151+func (h *history) top() *step {152+ if len(h.undo) == 0 {56153 return nil57154 }58- cp := *c59- return &cp155+ return h.undo[len(h.undo)-1]156+}157+158+// Seal ends a run of column width changes, so the next one starts a new159+// undo step. The UI calls it between user actions.160+func (s *Sheet) Seal() { s.hist.mergeWidths = false }161+162+// Undo reverts the last step and describes it.163+func (s *Sheet) Undo() (Change, bool) {164+ return s.swap(&s.hist.undo, &s.hist.redo)165+}166+167+// Redo reapplies the last undone step and describes it.168+func (s *Sheet) Redo() (Change, bool) {169+ return s.swap(&s.hist.redo, &s.hist.undo)170+}171+172+// CanUndo and CanRedo report whether there is a step to undo or redo.173+func (s *Sheet) CanUndo() bool { return len(s.hist.undo) > 0 }174+func (s *Sheet) CanRedo() bool { return len(s.hist.redo) > 0 }175+176+// StateID identifies the sheet's contents in its undo history: undoing177+// back to a saved state returns the ID it had when saved, so the UI can178+// tell whether there are unsaved changes.179+func (s *Sheet) StateID() int {180+ if top := s.hist.top(); top != nil {181+ return top.id182+ }183+ return 0184+}185+186+// swap pops a step from one stack, restores its before-image, and pushes187+// the state it replaced onto the other stack.188+func (s *Sheet) swap(from, to *[]*step) (Change, bool) {189+ if len(*from) == 0 || s.hist.open != nil {190+ return Change{}, false191+ }192+ st := (*from)[len(*from)-1]193+ *from = (*from)[:len(*from)-1]194+ // The inverse keeps the step's ID: on the redo stack, an ID names the195+ // state the step leads back to.196+ inv := &step{id: st.id, label: st.label, focus: st.focus, cells: make(map[Addr]*Cell, len(st.cells)), widths: map[int]int{}}197+ changed := make([]Addr, 0, len(st.cells))198+ for a, c := range st.cells {199+ inv.cells[a] = s.cells[a].clone()200+ s.place(a, c.clone())201+ changed = append(changed, a)202+ }203+ for c, w := range st.widths {204+ inv.widths[c] = s.widths[c]205+ s.setWidth(c, w)206+ }207+ s.recalc(changed)208+ *to = append(*to, inv)209+ s.hist.mergeWidths = false210+ return Change{st.label, st.focus}, true211+}212+213+// ClearHistory forgets all undo and redo steps.214+func (s *Sheet) ClearHistory() {215+ s.hist = history{}216+}217+218+// colRect is the range covering whole columns from..to.219+func colRect(from, to int) Rect {220+ return Rect{Addr{Col: from}, Addr{Col: to, Row: MaxRows - 1}}60221 }61222 62-// ClearHistory forgets all steps.63-func (s *Sheet) ClearHistory() { s.hist = history{} }223+// rowRect is the range covering whole rows from..to.224+func rowRect(from, to int) Rect {225+ return Rect{Addr{Row: from}, Addr{Col: MaxCols - 1, Row: to}}226+}227+228+func union(a, b Rect) Rect {229+ return Rect{230+ From: Addr{Col: min(a.From.Col, b.From.Col), Row: min(a.From.Row, b.From.Row)},231+ To: Addr{Col: max(a.To.Col, b.To.Col), Row: max(a.To.Row, b.To.Row)},232+ }233+}
A internal/sheet/history_test.go +147 -0
@@ -0,0 +1,147 @@
1+package sheet2+3+import (4+ "reflect"5+ "strings"6+ "testing"7+)8+9+// sheetOf builds a sheet from cell inputs, without undo history.10+func sheetOf(t *testing.T, cells map[string]string) *Sheet {11+ t.Helper()12+ s := New()13+ for a, in := range cells {14+ if err := s.put(at(a), in); err != nil {15+ t.Fatalf("%s: %v", a, err)16+ }17+ }18+ s.RecalcAll()19+ return s20+}21+22+// inputs returns every cell's input by address.23+func inputs(s *Sheet) map[string]string {24+ out := map[string]string{}25+ for a, c := range s.cells {26+ out[a.String()] = c.Input27+ }28+ return out29+}30+31+func TestUndoRedo(t *testing.T) {32+ s := New()33+ s.Set(at("A1"), "1")34+ s.Set(at("A2"), "=A1*10")35+ s.Set(at("A1"), "2")36+ s.EraseRange(NewRect(at("A1"), at("A2")))37+ if s.Len() != 0 || s.StateID() != 4 {38+ t.Fatalf("len %d state %d", s.Len(), s.StateID())39+ }40+ c, ok := s.Undo()41+ if !ok || c != (Change{"clear A1:A2", NewRect(at("A1"), at("A2"))}) || s.Value(at("A2")).Num != 20 {42+ t.Fatalf("undo erase: %v %v A2=%+v", c, ok, s.Value(at("A2")))43+ }44+ s.Undo()45+ if s.Value(at("A2")).Num != 10 || s.StateID() != 2 {46+ t.Errorf("undo set: A2=%+v state %d", s.Value(at("A2")), s.StateID())47+ }48+ s.Redo()49+ if s.Value(at("A2")).Num != 20 || s.StateID() != 3 {50+ t.Errorf("redo: A2=%+v state %d", s.Value(at("A2")), s.StateID())51+ }52+ // A new change drops the redo stack.53+ s.Set(at("B1"), "x")54+ if s.CanRedo() {55+ t.Error("redo survived a new change")56+ }57+ for s.CanUndo() {58+ s.Undo()59+ }60+ if s.Len() != 0 || s.StateID() != 0 {61+ t.Errorf("undo all: %v", inputs(s))62+ }63+ // A parse error changes nothing and adds no step.64+ s.Set(at("A1"), "=1+")65+ if s.CanUndo() {66+ t.Error("failed Set added a step")67+ }68+}69+70+func TestUndoKeepsWholeCells(t *testing.T) {71+ s := New()72+ s.Set(at("A1"), "=1+1")73+ orig := s.Cell(at("A1"))74+ s.Set(at("A1"), "x")75+ s.Undo()76+ got := s.Cell(at("A1"))77+ if got == orig || !reflect.DeepEqual(*got, *orig) {78+ t.Errorf("restored %+v, want a copy of %+v", got, orig)79+ }80+}81+82+func TestBatchGroupsAndHistoryCap(t *testing.T) {83+ s := New()84+ s.Batch(Change{"type", NewRect(at("A1"), at("A3"))}, func() error {85+ for i := range 3 {86+ s.Set(Addr{Row: i}, "1")87+ }88+ s.SetColWidth(0, 20)89+ return nil90+ })91+ s.Undo()92+ if s.Len() != 0 || s.ColWidth(0) != DefaultWidth || s.CanUndo() {93+ t.Errorf("batch undo left %v width %d", inputs(s), s.ColWidth(0))94+ }95+ for i := range MaxUndo + 10 {96+ s.Set(at("A1"), strings.Repeat("x", i+1))97+ }98+ n := 099+ for s.CanUndo() {100+ s.Undo()101+ n++102+ }103+ if n != MaxUndo || inputs(s)["A1"] != strings.Repeat("x", 10) {104+ t.Errorf("undid %d steps, A1 %q", n, inputs(s)["A1"])105+ }106+}107+108+func TestWidthPreviewMerges(t *testing.T) {109+ s := New()110+ s.Set(at("A1"), "1")111+ // A live preview over two columns, then the final value: one step.112+ for w := 11; w <= 13; w++ {113+ s.SetColWidth(0, w)114+ s.SetColWidth(1, w)115+ }116+ s.Undo()117+ if s.ColWidth(0) != DefaultWidth || s.ColWidth(1) != DefaultWidth || s.Len() != 1 {118+ t.Errorf("widths %d %d len %d", s.ColWidth(0), s.ColWidth(1), s.Len())119+ }120+ // A preview that is cancelled leaves no step at all.121+ s.Redo()122+ id := s.StateID()123+ s.Seal()124+ s.SetColWidth(0, 20)125+ s.SetColWidth(0, 13)126+ if s.StateID() != id {127+ t.Errorf("cancelled preview left a step")128+ }129+ // Separate actions are separate steps.130+ s.Seal()131+ s.SetColWidth(2, 5)132+ s.Seal()133+ s.SetColWidth(3, 5)134+ s.Undo()135+ if s.ColWidth(2) != 5 || s.ColWidth(3) != DefaultWidth {136+ t.Errorf("sealed width changes merged")137+ }138+}139+140+func TestLoadIsNotUndoable(t *testing.T) {141+ s := sheetOf(t, map[string]string{"A1": "1"})142+ s.SetColWidth(0, 12)143+ s.RecalcAll()144+ if s.CanUndo() || s.StateID() != 0 {145+ t.Error("RecalcAll kept history")146+ }147+}
A internal/sheet/merge_undo_test.go +40 -0
A internal/sheet/ops.go +317 -0
@@ -0,0 +1,317 @@
1+package sheet2+3+import (4+ "errors"5+ "fmt"6+ "strconv"7+)8+9+// Errors returned by operations that would lose data or don't fit.10+var (11+ ErrPushedOff = errors.New("There's data at the edge of the sheet that would be pushed off")12+ ErrPasteEdge = errors.New("The paste doesn't fit: it would go past the edge of the sheet")13+ ErrFillTooBig = errors.New("The selection is too large to fill")14+)15+16+// maxFill caps how many cells a paste or fill writes at once, so an17+// accidental whole-sheet selection can't stall the program.18+const maxFill = 1 << 2019+20+// remap moves every stored cell with cell (dropping those it rejects) and21+// rewrites every formula with rw, as one undo step.22+func (s *Sheet) remap(label string, focus Rect, cell func(Addr) (Addr, bool), rw refRewrite) {23+ next := make(map[Addr]*Cell, len(s.cells))24+ for a, c := range s.cells {25+ if to, ok := cell(a); ok {26+ next[to] = c.rewritten(rw)27+ }28+ }29+ s.change(label, focus, func() {30+ for a, c := range s.cells {31+ if next[a] != c {32+ s.place(a, next[a])33+ }34+ }35+ for a, c := range next {36+ if s.cells[a] != c {37+ s.place(a, c)38+ }39+ }40+ })41+}42+43+// InsertRows inserts n blank rows before row at, shifting the rows below44+// down and adjusting every reference to them.45+func (s *Sheet) InsertRows(at, n int) error {46+ return s.insert(true, at, n)47+}48+49+// InsertCols inserts n blank columns before column at.50+func (s *Sheet) InsertCols(at, n int) error {51+ return s.insert(false, at, n)52+}53+54+// DeleteRows deletes n rows starting at row at. References to deleted55+// cells become #REF!; ranges that lose some of their rows shrink.56+func (s *Sheet) DeleteRows(at, n int) {57+ s.restructure(true, span{at, -n, MaxRows})58+}59+60+// DeleteCols deletes n columns starting at column at.61+func (s *Sheet) DeleteCols(at, n int) {62+ s.restructure(false, span{at, -n, MaxCols})63+}64+65+func (s *Sheet) insert(rows bool, at, n int) error {66+ size := MaxCols67+ if rows {68+ size = MaxRows69+ }70+ for a := range s.cells {71+ line := a.Col72+ if rows {73+ line = a.Row74+ }75+ if line >= at && line >= size-n {76+ return ErrPushedOff77+ }78+ }79+ s.restructure(rows, span{at, n, size})80+ return nil81+}82+83+func (s *Sheet) restructure(rows bool, sp span) {84+ cell, rng := axisRewrite(rows, sp)85+ last := sp.at + abs(sp.n) - 186+ focus := colRect(sp.at, min(last, MaxCols-1))87+ if rows {88+ focus = rowRect(sp.at, min(last, MaxRows-1))89+ }90+ verb, noun := "insert", "column"91+ if sp.n < 0 {92+ verb = "delete"93+ }94+ if rows {95+ noun = "row"96+ }97+ label := fmt.Sprintf("%s %d %s", verb, abs(sp.n), noun)98+ if abs(sp.n) > 1 {99+ label += "s"100+ }101+ s.change(label, focus, func() {102+ s.remap(label, focus, cell, relocate(cell, rng))103+ if !rows {104+ s.shiftWidths(sp)105+ }106+ })107+}108+109+// shiftWidths moves column widths along with inserted or deleted columns.110+func (s *Sheet) shiftWidths(sp span) {111+ next := map[int]int{}112+ for c, w := range s.widths {113+ if to, ok := sp.point(c); ok {114+ next[to] = w115+ }116+ }117+ for c := range s.widths {118+ if _, ok := next[c]; !ok {119+ s.setWidth(c, 0)120+ }121+ }122+ for c, w := range next {123+ if s.widths[c] != w {124+ s.setWidth(c, w)125+ }126+ }127+}128+129+// Move moves the cells in src so its top-left corner lands on to, as130+// cut and paste does in Sheets. Formulas anywhere that referred to the131+// moved cells follow them; references to cells the move overwrote become132+// #REF!. It returns the destination range.133+func (s *Sheet) Move(src Rect, to Addr) (Rect, error) {134+ dc, dr := to.Col-src.From.Col, to.Row-src.From.Row135+ dst := Rect{to, Addr{Col: src.To.Col + dc, Row: src.To.Row + dr}}136+ if !dst.To.Valid() {137+ return Rect{}, ErrPasteEdge138+ }139+ shift := func(a Addr) Addr { return Addr{Col: a.Col + dc, Row: a.Row + dr} }140+ cell := func(a Addr) (Addr, bool) {141+ switch {142+ case src.Contains(a):143+ return shift(a), true144+ case dst.Contains(a):145+ return a, false146+ }147+ return a, true148+ }149+ rng := func(r Rect) (Rect, bool) {150+ if src.Contains(r.From) && src.Contains(r.To) {151+ return Rect{shift(r.From), shift(r.To)}, true152+ }153+ return r, true154+ }155+ s.remap("move "+src.String()+" to "+dst.String(), dst, cell, relocate(cell, rng))156+ return dst, nil157+}158+159+// Clip is a copied range: snapshots of its cells taken at copy time.160+type Clip struct {161+ Src Rect162+ cells map[Addr]*Cell // by offset from Src.From163+}164+165+// Copy snapshots the cells in r for pasting.166+func (s *Sheet) Copy(r Rect) *Clip {167+ c := &Clip{Src: r, cells: map[Addr]*Cell{}}168+ for _, a := range s.cellsIn(r) {169+ c.cells[Addr{Col: a.Col - r.From.Col, Row: a.Row - r.From.Row}] = s.cells[a].clone()170+ }171+ return c172+}173+174+// Size returns the clip's width and height in cells.175+func (c *Clip) Size() (cols, rows int) {176+ return c.Src.To.Col - c.Src.From.Col + 1, c.Src.To.Row - c.Src.From.Row + 1177+}178+179+// Text returns the clip's values as displayed in General format, row by180+// row, for the system clipboard.181+func (c *Clip) Text() [][]string {182+ cols, rows := c.Size()183+ out := make([][]string, rows)184+ for r := range out {185+ out[r] = make([]string, cols)186+ for col := range out[r] {187+ if cell := c.cells[Addr{Col: col, Row: r}]; cell != nil {188+ out[r][col] = cell.Value.String()189+ }190+ }191+ }192+ return out193+}194+195+// Paste writes the clip into dst and returns the range written. Formulas196+// shift their relative references by the distance pasted, as in Sheets;197+// with values set, only the computed values are pasted. Like Sheets, a198+// destination that is an exact multiple of the clip's size is tiled;199+// otherwise the clip is pasted once at dst's top-left corner.200+func (s *Sheet) Paste(c *Clip, dst Rect, values bool) (Rect, error) {201+ cols, rows := c.Size()202+ w, h := dst.To.Col-dst.From.Col+1, dst.To.Row-dst.From.Row+1203+ if w%cols != 0 || h%rows != 0 {204+ dst.To = Addr{Col: dst.From.Col + cols - 1, Row: dst.From.Row + rows - 1}205+ w, h = cols, rows206+ }207+ if !dst.To.Valid() {208+ return Rect{}, ErrPasteEdge209+ }210+ if w*h > maxFill {211+ return Rect{}, ErrFillTooBig212+ }213+ label := "paste into " + dst.String()214+ if values {215+ label = "paste values into " + dst.String()216+ }217+ s.change(label, dst, func() {218+ for r := range h {219+ for col := range w {220+ off := Addr{Col: col % cols, Row: r % rows}221+ to := Addr{Col: dst.From.Col + col, Row: dst.From.Row + r}222+ from := Addr{Col: c.Src.From.Col + off.Col, Row: c.Src.From.Row + off.Row}223+ s.pasteCell(to, c.cells[off], to.Col-from.Col, to.Row-from.Row, values)224+ }225+ }226+ })227+ return dst, nil228+}229+230+func (s *Sheet) pasteCell(a Addr, c *Cell, dc, dr int, values bool) {231+ switch {232+ case c == nil:233+ if s.cells[a] != nil {234+ s.place(a, nil)235+ }236+ case values:237+ s.put(a, valueInput(c.Value))238+ default:239+ s.place(a, c.rewritten(shiftRefs(dc, dr)).clone())240+ }241+}242+243+// valueInput is the entry that stores v as a constant. Text that would244+// read as a number, boolean or formula gets a leading ' to stay text.245+func valueInput(v Value) string {246+ switch v.Kind {247+ case Number:248+ return strconv.FormatFloat(v.Num, 'f', -1, 64)249+ case Text:250+ if n, _, _ := classify(v.Str); n != nil || (len(v.Str) > 0 && v.Str[0] == '\'') {251+ return "'" + v.Str252+ }253+ }254+ return v.String()255+}256+257+// FillDown copies the top row of r into the rest of it, adjusting258+// references (Ctrl+D). A single-row range fills from the row above.259+func (s *Sheet) FillDown(r Rect) (Rect, error) {260+ src := Rect{r.From, Addr{Col: r.To.Col, Row: r.From.Row}}261+ if r.From.Row == r.To.Row {262+ if r.From.Row == 0 {263+ return r, nil264+ }265+ src.From.Row, src.To.Row = r.From.Row-1, r.From.Row-1266+ } else {267+ r.From.Row++268+ }269+ var err error270+ s.change("fill down "+r.String(), r, func() { r, err = s.Paste(s.Copy(src), r, false) })271+ return r, err272+}273+274+// FillRight copies the left column of r into the rest of it (Ctrl+R). A275+// single-column range fills from the column to the left.276+func (s *Sheet) FillRight(r Rect) (Rect, error) {277+ src := Rect{r.From, Addr{Col: r.From.Col, Row: r.To.Row}}278+ if r.From.Col == r.To.Col {279+ if r.From.Col == 0 {280+ return r, nil281+ }282+ src.From.Col, src.To.Col = r.From.Col-1, r.From.Col-1283+ } else {284+ r.From.Col++285+ }286+ var err error287+ s.change("fill right "+r.String(), r, func() { r, err = s.Paste(s.Copy(src), r, false) })288+ return r, err289+}290+291+// FillEntry stores input in every cell of r as if it had been typed at292+// origin and copied to each cell, adjusting references (Ctrl+Enter).293+func (s *Sheet) FillEntry(r Rect, origin Addr, input string) error {294+ w, h := r.To.Col-r.From.Col+1, r.To.Row-r.From.Row+1295+ if w*h > maxFill {296+ return ErrFillTooBig297+ }298+ if _, _, err := classify(input); err != nil {299+ return err300+ }301+ return s.Batch(Change{"fill " + r.String(), r}, func() error {302+ if err := s.put(origin, input); err != nil {303+ return err304+ }305+ c := s.cells[origin].clone()306+ for row := r.From.Row; row <= r.To.Row; row++ {307+ for col := r.From.Col; col <= r.To.Col; col++ {308+ if a := (Addr{Col: col, Row: row}); a != origin {309+ s.pasteCell(a, c, a.Col-origin.Col, a.Row-origin.Row, false)310+ }311+ }312+ }313+ return nil314+ })315+}316+317+func abs(n int) int { return max(n, -n) }
M internal/sheet/parse.go +48 -16
@@ -10,14 +10,23 @@ import (
1010 type Node any1111 1212 type (13- numLit struct{ v float64 }14- strLit struct{ v string }15- boolLit struct{ v bool }16- refNode struct{ a Addr }17- rangeNode struct{ r Rect }18- nameNode struct{ name string } // an identifier that isn't a cell; #NAME? until names exist19- emptyArg struct{} // an omitted argument, as in XLOOKUP(a, b, c, , 1)20- unaryNode struct {13+ numLit struct{ v float64 }14+ strLit struct{ v string }15+ boolLit struct{ v bool }16+ refNode struct {17+ a Addr18+ abs absFlags19+ }20+ // rangeNode is kept normalized (r.From is the top-left corner); abs21+ // holds the absolute markers of r.From and r.To.22+ rangeNode struct {23+ r Rect24+ abs [2]absFlags25+ }26+ refErrNode struct{} // a reference to deleted cells: #REF!27+ nameNode struct{ name string } // an identifier that isn't a cell; #NAME? until names exist28+ emptyArg struct{} // an omitted argument, as in XLOOKUP(a, b, c, , 1)29+ unaryNode struct {2130 op string2231 x Node2332 }
@@ -37,9 +46,10 @@ const (
3746 tokEOF tokKind = iota3847 tokNum3948 tokStr40- tokIdent // cell reference, TRUE/FALSE or a name41- tokFunc // identifier directly followed by "("42- tokOp49+ tokIdent // cell reference, TRUE/FALSE or a name50+ tokFunc // identifier directly followed by "("51+ tokOp // operators and punctuation52+ tokRefErr // #REF!, left behind when a referenced cell is deleted4353 )4454 4555 type token struct {
@@ -132,6 +142,9 @@ func lex(src string) ([]token, error) {
132142 kind = tokFunc // @PI without parentheses133143 }134144 toks = append(toks, token{kind, name, start})145+ case c == '#' && strings.HasPrefix(strings.ToUpper(src[i:]), "#REF!"):146+ i += len("#REF!")147+ toks = append(toks, token{tokRefErr, "#REF!", start})135148 case c == '#':136149 end := strings.IndexByte(src[i+1:], '#')137150 if end < 0 {
@@ -229,7 +242,7 @@ func (p *parser) expr(minPower int) (Node, error) {
229242 for {230243 if p.isOp("%") && percentPower > minPower {231244 p.next()232- left = binaryNode{op: "/", l: left, r: numLit{100}}245+ left = unaryNode{op: "%", x: left}233246 continue234247 }235248 t := p.peek()
@@ -261,6 +274,8 @@ func (p *parser) prefix() (Node, error) {
261274 return p.ident(t)262275 case tokFunc:263276 return p.call(t)277+ case tokRefErr:278+ return refErrNode{}, nil264279 case tokOp:265280 switch t.text {266281 case "(":
@@ -293,7 +308,7 @@ func (p *parser) prefix() (Node, error) {
293308 }294309 295310 func (p *parser) ident(t token) (Node, error) {296- a, isRef := ParseAddr(t.text)311+ a, abs, isRef := parseRef(t.text)297312 if !isRef {298313 switch t.text {299314 case "TRUE":
@@ -306,13 +321,30 @@ func (p *parser) ident(t token) (Node, error) {
306321 if p.isOp(":") || p.isOp("..") {307322 sep := p.next()308323 end := p.next()309- b, ok := ParseAddr(end.text)324+ b, bAbs, ok := parseRef(end.text)310325 if end.kind != tokIdent || !ok {311326 return nil, &ParseError{end.pos, "Expected a cell after " + sep.text}312327 }313- return rangeNode{NewRect(a, b)}, nil328+ return newRange(a, b, abs, bAbs), nil329+ }330+ return refNode{a, abs}, nil331+}332+333+// newRange builds a normalized range from two corners as written. Each334+// absolute marker stays with its column or row, so $B1:A$2 becomes A1:$B$2.335+func newRange(a, b Addr, aAbs, bAbs absFlags) rangeNode {336+ swap := func(bit absFlags) {337+ aAbs, bAbs = aAbs&^bit|bAbs&bit, bAbs&^bit|aAbs&bit338+ }339+ if a.Col > b.Col {340+ a.Col, b.Col = b.Col, a.Col341+ swap(absCol)342+ }343+ if a.Row > b.Row {344+ a.Row, b.Row = b.Row, a.Row345+ swap(absRow)314346 }315- return refNode{a}, nil347+ return rangeNode{Rect{a, b}, [2]absFlags{aAbs, bAbs}}316348 }317349 318350 func (p *parser) call(t token) (Node, error) {
A internal/sheet/print.go +100 -0
@@ -0,0 +1,100 @@
1+package sheet2+3+import (4+ "math"5+ "strconv"6+ "strings"7+)8+9+// formulaText prints a parsed formula back to text, with a leading "=".10+// Rewritten formulas (after a paste or an inserted row) are stored this11+// way, in Sheets' spelling: ranges as A1:B3, functions without @.12+func formulaText(n Node) string {13+ var b strings.Builder14+ b.WriteByte('=')15+ printNode(&b, n)16+ return b.String()17+}18+19+// atomPower is the binding power of nodes that never need parentheses.20+const atomPower = 10021+22+// power returns how tightly n binds, using the parser's binding powers, so23+// the printer adds parentheses exactly where the parser needs them.24+func power(n Node) int {25+ switch n := n.(type) {26+ case binaryNode:27+ return infixPower[n.op]28+ case unaryNode:29+ switch n.op {30+ case "%":31+ return percentPower32+ case "#NOT#":33+ return notPower34+ }35+ return unaryPower36+ }37+ return atomPower38+}39+40+func printNode(b *strings.Builder, n Node) {41+ switch n := n.(type) {42+ case numLit:43+ b.WriteString(numText(n.v))44+ case strLit:45+ b.WriteString(`"` + strings.ReplaceAll(n.v, `"`, `""`) + `"`)46+ case boolLit:47+ b.WriteString(strings.ToUpper(strconv.FormatBool(n.v)))48+ case refNode:49+ b.WriteString(refString(n.a, n.abs))50+ case rangeNode:51+ b.WriteString(refString(n.r.From, n.abs[0]) + ":" + refString(n.r.To, n.abs[1]))52+ case refErrNode:53+ b.WriteString("#REF!")54+ case nameNode:55+ b.WriteString(n.name)56+ case unaryNode:57+ if n.op == "%" {58+ printChild(b, n.x, power(n.x) < percentPower)59+ b.WriteByte('%')60+ return61+ }62+ b.WriteString(n.op)63+ printChild(b, n.x, power(n.x) < power(n))64+ case binaryNode:65+ p := infixPower[n.op]66+ // Operators associate to the left, so a right operand of equal67+ // power needs parentheses: 1-(2-3).68+ printChild(b, n.l, power(n.l) < p)69+ b.WriteString(n.op)70+ printChild(b, n.r, power(n.r) <= p)71+ case callNode:72+ b.WriteString(n.fn.Name + "(")73+ for i, a := range n.args {74+ if i > 0 {75+ b.WriteByte(',')76+ }77+ printNode(b, a)78+ }79+ b.WriteByte(')')80+ }81+}82+83+func printChild(b *strings.Builder, n Node, paren bool) {84+ if paren {85+ b.WriteByte('(')86+ }87+ printNode(b, n)88+ if paren {89+ b.WriteByte(')')90+ }91+}92+93+// numText writes a number literal so it parses back to the same float:94+// plainly in everyday ranges, in E notation for very large or small ones.95+func numText(v float64) string {96+ if a := math.Abs(v); a == 0 || (a >= 1e-6 && a < 1e21) {97+ return strconv.FormatFloat(v, 'f', -1, 64)98+ }99+ return strconv.FormatFloat(v, 'E', -1, 64)100+}
A internal/sheet/refs.go +196 -0
@@ -0,0 +1,196 @@
1+package sheet2+3+// Reference rewriting: copying a formula shifts its relative references,4+// and moving or inserting and deleting cells updates every reference to5+// the cells that moved, as Sheets does. A reference that can't be kept6+// becomes #REF!.7+8+// refRewrite maps the references in a formula. Either function may return9+// refErrNode.10+type refRewrite struct {11+ ref func(refNode) Node12+ rng func(rangeNode) Node13+}14+15+// rewrite returns n with its references mapped, and whether anything16+// changed. Unchanged subtrees are shared.17+func rewrite(n Node, rw refRewrite) (Node, bool) {18+ switch n := n.(type) {19+ case refNode:20+ out := rw.ref(n)21+ return out, out != Node(n)22+ case rangeNode:23+ out := rw.rng(n)24+ return out, out != Node(n)25+ case unaryNode:26+ x, ok := rewrite(n.x, rw)27+ if ok {28+ n.x = x29+ }30+ return n, ok31+ case binaryNode:32+ l, okL := rewrite(n.l, rw)33+ r, okR := rewrite(n.r, rw)34+ if okL || okR {35+ n.l, n.r = l, r36+ }37+ return n, okL || okR38+ case callNode:39+ var args []Node40+ for i, a := range n.args {41+ if b, ok := rewrite(a, rw); ok {42+ if args == nil {43+ args = append([]Node(nil), n.args...)44+ }45+ args[i] = b46+ }47+ }48+ if args == nil {49+ return n, false50+ }51+ n.args = args52+ return n, true53+ }54+ return n, false55+}56+57+// shiftRefs is the rewrite for copying a formula by (dc, dr): relative58+// parts move, $absolute parts stay, and references pushed off the sheet59+// become #REF!.60+func shiftRefs(dc, dr int) refRewrite {61+ move := func(a Addr, abs absFlags) (Addr, bool) {62+ if abs&absCol == 0 {63+ a.Col += dc64+ }65+ if abs&absRow == 0 {66+ a.Row += dr67+ }68+ return a, a.Valid()69+ }70+ return refRewrite{71+ ref: func(n refNode) Node {72+ a, ok := move(n.a, n.abs)73+ if !ok {74+ return refErrNode{}75+ }76+ return refNode{a, n.abs}77+ },78+ rng: func(n rangeNode) Node {79+ from, ok1 := move(n.r.From, n.abs[0])80+ to, ok2 := move(n.r.To, n.abs[1])81+ if !ok1 || !ok2 {82+ return refErrNode{}83+ }84+ return newRange(from, to, n.abs[0], n.abs[1])85+ },86+ }87+}88+89+// relocate is the rewrite for cells that move: cell maps where each cell90+// went (false if it's gone), and rng maps whole ranges.91+func relocate(cell func(Addr) (Addr, bool), rng func(Rect) (Rect, bool)) refRewrite {92+ return refRewrite{93+ ref: func(n refNode) Node {94+ a, ok := cell(n.a)95+ if !ok {96+ return refErrNode{}97+ }98+ return refNode{a, n.abs}99+ },100+ rng: func(n rangeNode) Node {101+ r, ok := rng(n.r)102+ if !ok {103+ return refErrNode{}104+ }105+ return rangeNode{r, n.abs}106+ },107+ }108+}109+110+// withFormula returns a copy of c holding expression n, printed as its111+// new input. Other fields (formats, say) come along unchanged.112+func (c *Cell) withFormula(n Node) *Cell {113+ cp := c.clone()114+ cp.Input = formulaText(n)115+ cp.setExpr(n)116+ return cp117+}118+119+// rewritten returns c with its references rewritten, or c itself if none120+// changed.121+func (c *Cell) rewritten(rw refRewrite) *Cell {122+ if c.expr == nil || (len(c.refs) == 0 && len(c.ranges) == 0) {123+ return c124+ }125+ n, changed := rewrite(c.expr, rw)126+ if !changed {127+ return c128+ }129+ return c.withFormula(n)130+}131+132+// span inserts (n > 0) or deletes (n < 0) lines starting at index at,133+// along an axis with size lines.134+type span struct{ at, n, size int }135+136+// point maps a line index; false if the line was deleted or pushed off137+// the end.138+func (sp span) point(v int) (int, bool) {139+ switch {140+ case v < sp.at:141+ return v, true142+ case sp.n < 0 && v < sp.at-sp.n:143+ return 0, false144+ }145+ v += sp.n146+ return v, v < sp.size147+}148+149+// interval maps a range's lines lo..hi as Sheets does: inserting inside150+// the range grows it, deleting part of it shrinks it, and deleting all of151+// it leaves #REF!.152+func (sp span) interval(lo, hi int) (int, int, bool) {153+ if sp.n > 0 {154+ lo, okLo := sp.point(lo)155+ if !okLo {156+ return 0, 0, false157+ }158+ hi, _ := sp.point(hi)159+ return lo, min(hi, sp.size-1), true160+ }161+ end := sp.at - sp.n // first line after the deletion162+ if lo >= sp.at && hi < end {163+ return 0, 0, false164+ }165+ if lo >= sp.at {166+ lo = max(lo, end) + sp.n167+ }168+ if hi >= sp.at {169+ hi = max(hi+sp.n, sp.at-1)170+ }171+ return lo, hi, true172+}173+174+// axisRewrite is the cell and range mapping for inserting or deleting rows175+// (rows true) or columns.176+func axisRewrite(rows bool, sp span) (func(Addr) (Addr, bool), func(Rect) (Rect, bool)) {177+ cell := func(a Addr) (Addr, bool) {178+ var ok bool179+ if rows {180+ a.Row, ok = sp.point(a.Row)181+ } else {182+ a.Col, ok = sp.point(a.Col)183+ }184+ return a, ok185+ }186+ rng := func(r Rect) (Rect, bool) {187+ var ok bool188+ if rows {189+ r.From.Row, r.To.Row, ok = sp.interval(r.From.Row, r.To.Row)190+ } else {191+ r.From.Col, r.To.Col, ok = sp.interval(r.From.Col, r.To.Col)192+ }193+ return r, ok194+ }195+ return cell, rng196+}
A internal/sheet/refs_test.go +365 -0
@@ -0,0 +1,365 @@
1+package sheet2+3+import (4+ "maps"5+ "reflect"6+ "strings"7+ "testing"8+)9+10+func TestParseAbsoluteRefs(t *testing.T) {11+ tests := []struct {12+ in string13+ want Node14+ }{15+ {"=A1", refNode{at("A1"), 0}},16+ {"=$A1", refNode{at("A1"), absCol}},17+ {"=A$1", refNode{at("A1"), absRow}},18+ {"=$a$1", refNode{at("A1"), absCol | absRow}},19+ {"=$B$3:A1", rangeNode{NewRect(at("A1"), at("B3")), [2]absFlags{0, absCol | absRow}}},20+ // Each marker stays with its column or row when corners swap.21+ {"=$B1:A$2", rangeNode{NewRect(at("A1"), at("B2")), [2]absFlags{0, absCol | absRow}}},22+ {"=A1..$B2", rangeNode{NewRect(at("A1"), at("B2")), [2]absFlags{0, absCol}}},23+ {"=A$$1", nameNode{"A$$1"}},24+ {"=A1$", nameNode{"A1$"}},25+ {"=#REF!+1", binaryNode{"+", refErrNode{}, numLit{1}}},26+ }27+ for _, tt := range tests {28+ got, err := Parse(tt.in)29+ if err != nil || !reflect.DeepEqual(got, tt.want) {30+ t.Errorf("Parse(%q) = %#v, %v; want %#v", tt.in, got, err, tt.want)31+ }32+ }33+}34+35+func TestPrintFormula(t *testing.T) {36+ tests := []struct{ in, want string }{37+ {"=a1+$b$2*C$3", "=A1+$B$2*C$3"},38+ {"=@SUM(A1..B3; 2)", "=SUM(A1:B3,2)"},39+ {"=(1+2)*3", "=(1+2)*3"},40+ {"=1-(2-3)", "=1-(2-3)"},41+ {"=(1-2)-3", "=1-2-3"},42+ {"=2^3^2", "=2^3^2"},43+ {"=2^(3^2)", "=2^(3^2)"},44+ {"=-2^2", "=-2^2"},45+ {"=(-2)^2", "=-2^2"}, // negation binds tighter than ^46+ {"=-(2^2)", "=-(2^2)"},47+ {"=-(A1+1)", "=-(A1+1)"},48+ {"=50%", "=50%"},49+ {"=(A1+1)%", "=(A1+1)%"},50+ {"=#NOT#(A1=1) #AND# B1", "=#NOT#A1=1#AND#B1"},51+ {"=1+(#NOT#A1)", "=1+(#NOT#A1)"},52+ {`="say ""hi"""&A1`, `="say ""hi"""&A1`},53+ {"=1.5E3+1e-9+2E21", "=1500+1E-09+2E+21"},54+ {"=@PI", "=PI()"},55+ {"=IF(A1>=2,TRUE,profit)", "=IF(A1>=2,TRUE,PROFIT)"},56+ {"=SUM(#REF!)", "=SUM(#REF!)"},57+ {"+A1", "=+A1"},58+ }59+ for _, tt := range tests {60+ n, err := Parse(tt.in)61+ if err != nil {62+ t.Fatalf("Parse(%q): %v", tt.in, err)63+ }64+ if got := formulaText(n); got != tt.want {65+ t.Errorf("print(%q) = %q, want %q", tt.in, got, tt.want)66+ }67+ }68+}69+70+func TestShiftRefs(t *testing.T) {71+ tests := []struct {72+ in string73+ dc, dr int74+ want string75+ }{76+ {"=A1+B2", 1, 2, "=B3+C4"},77+ {"=$A$1+A1", 1, 1, "=$A$1+B2"},78+ {"=$A1+A$1", 2, 3, "=$A4+C$1"},79+ {"=SUM(A1:B2)", 0, 5, "=SUM(A6:B7)"},80+ {"=SUM($A$1:B2)", 1, 1, "=SUM($A$1:C3)"},81+ {"=A2", 0, -1, "=A1"},82+ {"=A2", 0, -2, "=#REF!"},83+ {"=SUM(A1:B2)+1", -1, 0, "=SUM(#REF!)+1"},84+ {"=$A2", -1, 0, "=$A2"},85+ {"=IV1", 1, 0, "=#REF!"},86+ // A mixed range can flip when one corner is anchored.87+ {"=SUM($C1:D1)", -2, 0, "=SUM(B1:$C1)"},88+ }89+ for _, tt := range tests {90+ n, _ := Parse(tt.in)91+ out, _ := rewrite(n, shiftRefs(tt.dc, tt.dr))92+ if got := formulaText(out); got != tt.want {93+ t.Errorf("shift(%q, %d, %d) = %q, want %q", tt.in, tt.dc, tt.dr, got, tt.want)94+ }95+ }96+}97+98+func TestSpanInterval(t *testing.T) {99+ tests := []struct {100+ sp span101+ lo, hi int102+ wLo, wHi int103+ wOK bool104+ name string105+ checkPoint bool106+ }{107+ {span{2, 2, 100}, 0, 1, 0, 1, true, "insert below", false},108+ {span{2, 2, 100}, 1, 3, 1, 5, true, "insert inside grows", false},109+ {span{2, 2, 100}, 2, 3, 4, 5, true, "insert at start shifts", false},110+ {span{2, 2, 100}, 50, 99, 52, 99, true, "insert clamps at the edge", false},111+ {span{2, -2, 100}, 1, 4, 1, 2, true, "delete inside shrinks", false},112+ {span{2, -2, 100}, 2, 4, 2, 2, true, "delete top part", false},113+ {span{2, -2, 100}, 1, 2, 1, 1, true, "delete bottom part", false},114+ {span{2, -2, 100}, 3, 6, 2, 4, true, "delete overlapping start", false},115+ {span{2, -2, 100}, 5, 6, 3, 4, true, "delete above shifts", false},116+ {span{2, -2, 100}, 2, 3, 0, 0, false, "delete all of it", false},117+ }118+ for _, tt := range tests {119+ lo, hi, ok := tt.sp.interval(tt.lo, tt.hi)120+ if ok != tt.wOK || (ok && (lo != tt.wLo || hi != tt.wHi)) {121+ t.Errorf("%s: interval(%d, %d) = %d, %d, %v", tt.name, tt.lo, tt.hi, lo, hi, ok)122+ }123+ }124+}125+126+func TestInsertDeleteRows(t *testing.T) {127+ base := map[string]string{128+ "A1": "1", "A2": "2", "A3": "3", "A4": "4",129+ "B1": "=SUM(A1:A4)", "B2": "=A3*2", "B3": "=$A$4", "B4": "=SUM(A3:A4)",130+ }131+ tests := []struct {132+ name string133+ op func(s *Sheet)134+ want map[string]string135+ vals map[string]float64136+ }{137+ {"insert inside a range", func(s *Sheet) { s.InsertRows(2, 1) }, map[string]string{138+ "A1": "1", "A2": "2", "A4": "3", "A5": "4",139+ "B1": "=SUM(A1:A5)", "B2": "=A4*2", "B4": "=$A$5", "B5": "=SUM(A4:A5)",140+ }, map[string]float64{"B1": 10, "B2": 6, "B4": 4}},141+ {"delete a referenced row", func(s *Sheet) { s.DeleteRows(2, 1) }, map[string]string{142+ "A1": "1", "A2": "2", "A3": "4",143+ "B1": "=SUM(A1:A3)", "B2": "=#REF!*2", "B3": "=SUM(A3:A3)",144+ }, map[string]float64{"B1": 7, "B3": 4}},145+ {"delete every row of a range", func(s *Sheet) { s.DeleteRows(2, 2) }, map[string]string{146+ "A1": "1", "A2": "2", "B1": "=SUM(A1:A2)", "B2": "=#REF!*2",147+ }, map[string]float64{"B1": 3}},148+ }149+ for _, tt := range tests {150+ s := sheetOf(t, base)151+ tt.op(s)152+ if got := inputs(s); !maps.Equal(got, tt.want) {153+ t.Errorf("%s:\n got %v\nwant %v", tt.name, got, tt.want)154+ }155+ for a, v := range tt.vals {156+ if got := s.Value(at(a)); got.Kind != Number || got.Num != v {157+ t.Errorf("%s: %s = %+v, want %v", tt.name, a, got, v)158+ }159+ }160+ for a, in := range tt.want {161+ if strings.Contains(in, "#REF!") && s.Value(at(a)) != ErrRef {162+ t.Errorf("%s: %s = %+v, want #REF!", tt.name, a, s.Value(at(a)))163+ }164+ }165+ // Recalc still follows the rewritten references.166+ s.Set(at("A1"), "101")167+ if got := s.Value(at("B1")).Num; got != tt.vals["B1"]+100 {168+ t.Errorf("%s: B1 after edit = %v", tt.name, got)169+ }170+ // Undo restores the sheet exactly.171+ s.Undo()172+ s.Undo()173+ if got := inputs(s); !maps.Equal(got, base) {174+ t.Errorf("%s: undo left %v", tt.name, got)175+ }176+ }177+}178+179+func TestInsertDeleteColsShiftWidths(t *testing.T) {180+ s := sheetOf(t, map[string]string{"A1": "1", "B1": "2", "C1": "=A1+B1"})181+ s.SetColWidth(1, 15)182+ if err := s.InsertCols(1, 2); err != nil {183+ t.Fatal(err)184+ }185+ if got := inputs(s); got["E1"] != "=A1+D1" || got["D1"] != "2" || s.ColWidth(3) != 15 || s.ColWidth(1) != DefaultWidth {186+ t.Errorf("after insert: %v, width D %d", got, s.ColWidth(3))187+ }188+ s.DeleteCols(0, 1)189+ if got := inputs(s)["D1"]; got != "=#REF!+C1" || s.ColWidth(2) != 15 {190+ t.Errorf("after delete: D1 %q, width C %d", got, s.ColWidth(2))191+ }192+ c1, _ := s.Undo()193+ c2, _ := s.Undo()194+ if c1.Label != "delete 1 column" || c2.Label != "insert 2 columns" || c2.Focus != colRect(1, 2) {195+ t.Errorf("undid %+v then %+v", c1, c2)196+ }197+ if got := inputs(s)["C1"]; got != "=A1+B1" || s.ColWidth(1) != 15 {198+ t.Errorf("after undo: C1 %q width B %d", got, s.ColWidth(1))199+ }200+}201+202+func TestInsertRefusesToPushDataOff(t *testing.T) {203+ s := sheetOf(t, map[string]string{"A8192": "last"})204+ if err := s.InsertRows(0, 1); err != ErrPushedOff {205+ t.Errorf("err = %v", err)206+ }207+ if err := s.InsertRows(8191, 1); err != ErrPushedOff {208+ t.Errorf("err = %v", err)209+ }210+ if err := s.InsertRows(8192-3, 1); err != ErrPushedOff {211+ t.Errorf("err = %v", err)212+ }213+ s = sheetOf(t, map[string]string{"A8190": "x", "B1": "=A8192"})214+ if err := s.InsertRows(0, 1); err != nil {215+ t.Fatal(err)216+ }217+ if got := inputs(s)["B2"]; got != "=#REF!" {218+ t.Errorf("reference pushed off the sheet = %q", got)219+ }220+}221+222+func TestCopyPaste(t *testing.T) {223+ tests := []struct {224+ name string225+ src string226+ dst string227+ values bool228+ want map[string]string229+ wrote string230+ }{231+ {"relative shift", "C1", "D3", false, map[string]string{"D3": "=C3+$A$1"}, "D3"},232+ {"off the sheet", "C1", "A1", false, map[string]string{"A1": "=#REF!+$A$1"}, "A1"},233+ {"tiles an exact multiple", "A1:A2", "E1:F4", false, map[string]string{234+ "E1": "1", "E2": "2", "E3": "1", "E4": "2", "F1": "1", "F2": "2", "F3": "1", "F4": "2",235+ }, "E1:F4"},236+ {"pastes once otherwise", "A1:A2", "E1:E3", false, map[string]string{"E1": "1", "E2": "2"}, "E1:E2"},237+ {"values only", "B1:C1", "E5", true, map[string]string{"E5": "'12", "F5": "13"}, "E5:F5"},238+ }239+ for _, tt := range tests {240+ s := sheetOf(t, map[string]string{"A1": "1", "A2": "2", "B1": "'12", "C1": "=B1+$A$1"})241+ src, _ := ParseRange(tt.src)242+ dst, _ := ParseRange(tt.dst)243+ before := inputs(s)244+ wrote, err := s.Paste(s.Copy(src), dst, tt.values)245+ if err != nil || wrote.String() != tt.wrote {246+ t.Errorf("%s: wrote %v, %v", tt.name, wrote, err)247+ }248+ got := inputs(s)249+ for a, in := range tt.want {250+ if got[a] != in {251+ t.Errorf("%s: %s = %q, want %q", tt.name, a, got[a], in)252+ }253+ }254+ if len(got) != len(uniqueKeys(before, tt.want)) {255+ t.Errorf("%s: unexpected cells %v", tt.name, got)256+ }257+ s.Undo()258+ if !maps.Equal(inputs(s), before) {259+ t.Errorf("%s: undo left %v", tt.name, inputs(s))260+ }261+ }262+}263+264+func uniqueKeys(ms ...map[string]string) map[string]bool {265+ out := map[string]bool{}266+ for _, m := range ms {267+ for k := range m {268+ out[k] = true269+ }270+ }271+ return out272+}273+274+func TestPasteBlanksAndEdge(t *testing.T) {275+ s := sheetOf(t, map[string]string{"A1": "1", "C1": "keep", "D1": "gone"})276+ s.Paste(s.Copy(NewRect(at("A1"), at("B1"))), NewRect(at("C1"), at("C1")), false)277+ if got := inputs(s); got["C1"] != "1" || got["D1"] != "" {278+ t.Errorf("blank source cells should clear the destination: %v", got)279+ }280+ if _, err := s.Paste(s.Copy(NewRect(at("A1"), at("B1"))), NewRect(at("IV1"), at("IV1")), false); err != ErrPasteEdge {281+ t.Errorf("err = %v", err)282+ }283+}284+285+func TestMove(t *testing.T) {286+ s := sheetOf(t, map[string]string{287+ "A1": "5", "A2": "=A1*2", "B1": "=A1+A2", "C1": "=SUM(A1:A2)", "C2": "=SUM(A1:A3)", "D1": "old", "E1": "=D1",288+ })289+ dst, err := s.Move(NewRect(at("A1"), at("A2")), at("D1"))290+ if err != nil || dst.String() != "D1:D2" {291+ t.Fatalf("Move = %v, %v", dst, err)292+ }293+ want := map[string]string{294+ "D1": "5", "D2": "=D1*2", "B1": "=D1+D2", "C1": "=SUM(D1:D2)",295+ "C2": "=SUM(A1:A3)", // not wholly inside the moved cells: unchanged296+ "E1": "=#REF!", // pointed at a cell the move overwrote297+ }298+ if got := inputs(s); !maps.Equal(got, want) {299+ t.Errorf("got %v\nwant %v", got, want)300+ }301+ if got := s.Value(at("B1")).Num; got != 15 {302+ t.Errorf("B1 = %v", got)303+ }304+ s.Undo()305+ if got := inputs(s); got["A2"] != "=A1*2" || got["D1"] != "old" || got["E1"] != "=D1" {306+ t.Errorf("undo: %v", got)307+ }308+}309+310+func TestFill(t *testing.T) {311+ s := sheetOf(t, map[string]string{"A1": "1", "B1": "=A1*2", "A2": "2", "A3": "3"})312+ if _, err := s.FillDown(NewRect(at("B1"), at("B3"))); err != nil {313+ t.Fatal(err)314+ }315+ if got := inputs(s); got["B2"] != "=A2*2" || got["B3"] != "=A3*2" || s.Value(at("B3")).Num != 6 {316+ t.Errorf("fill down: %v", got)317+ }318+ s.FillRight(NewRect(at("B1"), at("C2")))319+ if got := inputs(s); got["C1"] != "=B1*2" || got["C2"] != "=B2*2" {320+ t.Errorf("fill right: %v", got)321+ }322+ // A single cell fills from its neighbor.323+ s.FillDown(NewRect(at("B4"), at("B4")))324+ if got := inputs(s)["B4"]; got != "=A4*2" {325+ t.Errorf("single-cell fill down: %q", got)326+ }327+ if err := s.FillEntry(NewRect(at("D1"), at("E2")), at("D1"), "=A1+$A$1"); err != nil {328+ t.Fatal(err)329+ }330+ want := map[string]string{"D1": "=A1+$A$1", "E1": "=B1+$A$1", "D2": "=A2+$A$1", "E2": "=B2+$A$1"}331+ for a, in := range want {332+ if got := inputs(s)[a]; got != in {333+ t.Errorf("fill entry %s = %q, want %q", a, got, in)334+ }335+ }336+ s.Undo()337+ if got := inputs(s)["D1"]; got != "" {338+ t.Errorf("fill entry is one undo step, D1 = %q", got)339+ }340+}341+342+// FuzzPrint checks that printing a parsed formula gives text that parses343+// back to the same expression.344+func FuzzPrint(f *testing.F) {345+ for _, s := range []string{346+ "=A1*2", "=$A$1+A$2-$B3", "=SUM($A1:B$3)", "=-2^-2%", "=1-(2-3)", "=#NOT#A1=1#OR#B1",347+ "=2^(3^2)", `=IF(A1>2,"x""y",#REF!)`, "=1.5E-3^2", "=@SUM(A1..B3)", "=(1+2)%*-A1",348+ } {349+ f.Add(s)350+ }351+ f.Fuzz(func(t *testing.T, in string) {352+ n, err := Parse(in)353+ if err != nil {354+ return355+ }356+ text := formulaText(n)357+ back, err := Parse(text)358+ if err != nil {359+ t.Fatalf("%q printed as %q, which doesn't parse: %v", in, text, err)360+ }361+ if !reflect.DeepEqual(n, back) {362+ t.Fatalf("%q printed as %q parses differently:\n%#v\n%#v", in, text, n, back)363+ }364+ })365+}
M internal/sheet/sheet.go +6 -1
M internal/sheet/sheet_test.go +1 -1
A internal/ui/clipboard.go +223 -0
@@ -0,0 +1,223 @@
1+package ui2+3+import (4+ "strings"5+6+ tea "charm.land/bubbletea/v2"7+ "github.com/charmbracelet/x/ansi"8+9+ "one23/internal/sheet"10+)11+12+// Copy, cut and paste follow Sheets: Ctrl+C copies the selection and13+// marks it until Esc or the next edit, Ctrl+V pastes with references14+// adjusted, Ctrl+X then Ctrl+V moves. The copied values also go to the15+// system clipboard as TSV (OSC 52), and a multi-cell paste from the16+// terminal fills a block of cells.17+18+// clipboard is what Ctrl+V pastes.19+type clipboard struct {20+ clip *sheet.Clip21+ cut bool // pasting moves the cells rather than copying them22+ marked bool // the source shows the copy marker23+ keep bool // the last edit was a paste, which keeps the marker24+}25+26+func init() {27+ register(28+ &command{id: "edit.copy", title: "Copy", desc: "Copy the selection", run: func(m *Model) tea.Cmd { return m.copy(false) }},29+ &command{id: "edit.cut", title: "Cut", desc: "Cut the selection, to move it where you paste", run: func(m *Model) tea.Cmd { return m.copy(true) }},30+ &command{id: "edit.paste", title: "Paste", desc: "Paste into the selection, adjusting references", run: func(m *Model) tea.Cmd { return m.paste(false) }},31+ &command{id: "edit.paste_values", title: "Paste values only", desc: "Paste the copied values without formulas", run: func(m *Model) tea.Cmd { return m.paste(true) }},32+ )33+ keymap["ctrl+c"] = "edit.copy"34+ keymap["ctrl+x"] = "edit.cut"35+ keymap["ctrl+v"] = "edit.paste"36+ keymap["ctrl+shift+v"] = "edit.paste_values"37+}38+39+// copy puts the selection on the clipboard and the system clipboard.40+func (m *Model) copy(cut bool) tea.Cmd {41+ clip := m.sheet.Copy(m.copyRange())42+ m.copied = clipboard{clip: clip, cut: cut, marked: true}43+ return tea.SetClipboard(formatTSV(clip.Text()))44+}45+46+// copyRange is the selection, trimmed to the data when whole rows or47+// columns are selected, as there's no point copying thousands of blanks.48+func (m *Model) copyRange() sheet.Rect {49+ r := m.selection()50+ if m.whole == wholeNone {51+ return r52+ }53+ used, ok := m.sheet.UsedRange()54+ r.To = sheet.Addr{Col: min(r.To.Col, used.To.Col), Row: min(r.To.Row, used.To.Row)}55+ if !ok || r.To.Col < r.From.Col || r.To.Row < r.From.Row {56+ r.To = r.From57+ }58+ return r59+}60+61+// paste pastes the clipboard into the selection and selects what it62+// wrote.63+func (m *Model) paste(values bool) tea.Cmd {64+ c := m.copied65+ if c.clip == nil {66+ m.note = "Nothing to paste: copy with Ctrl+C first"67+ return nil68+ }69+ var r sheet.Rect70+ var err error71+ if c.cut && !values {72+ r, err = m.sheet.Move(c.clip.Src, m.cur)73+ m.copied = clipboard{}74+ } else {75+ r, err = m.sheet.Paste(c.clip, m.selection(), values)76+ m.copied.keep = true77+ }78+ if err != nil {79+ m.fail(err.Error())80+ return nil81+ }82+ m.selectRect(r)83+ switch {84+ case c.cut && !values:85+ m.note = "Moved " + c.clip.Src.String() + " to " + r.String()86+ case values:87+ m.note = "Pasted values into " + countCells(r) + " at " + r.String()88+ default:89+ m.note = "Pasted " + countCells(r) + " at " + r.String()90+ }91+ return nil92+}93+94+// copyMarked reports whether a shows the copy marker.95+func (m *Model) copyMarked(a sheet.Addr) bool {96+ return m.copied.marked && m.copied.clip.Src.Contains(a)97+}98+99+// clearCopyMark hides the copy marker; a pending cut is cancelled, as in100+// Sheets, since the cells it would move may have changed.101+func (m *Model) clearCopyMark() {102+ if m.copied.cut {103+ m.copied = clipboard{}104+ }105+ m.copied.marked = false106+}107+108+// pasteText fills a block of cells from pasted text with tabs or line109+// breaks, such as cells copied from another spreadsheet, and reports110+// whether it did. Each value is entered as if typed.111+func (m *Model) pasteText(content string) bool {112+ content = strings.TrimSuffix(strings.TrimSuffix(content, "\n"), "\r")113+ if !strings.ContainsAny(content, "\t\n") {114+ return false115+ }116+ rows := parseTSV(content)117+ width := 0118+ for _, row := range rows {119+ width = max(width, len(row))120+ }121+ r := sheet.Rect{From: m.cur, To: sheet.Addr{Col: m.cur.Col + width - 1, Row: m.cur.Row + len(rows) - 1}}122+ if !r.To.Valid() {123+ m.fail(sheet.ErrPasteEdge.Error())124+ return true125+ }126+ m.sheet.Batch(sheet.Change{Label: "paste into " + r.String(), Focus: r}, func() error {127+ for i, row := range rows {128+ for j := range width {129+ var v string130+ if j < len(row) {131+ v = row[j]132+ }133+ a := sheet.Addr{Col: r.From.Col + j, Row: r.From.Row + i}134+ if m.sheet.Set(a, v) != nil {135+ m.sheet.Set(a, "'"+v) // a broken formula stays as text136+ }137+ }138+ }139+ return nil140+ })141+ m.selectRect(r)142+ m.note = "Pasted " + countCells(r) + " at " + r.String()143+ return true144+}145+146+// formatTSV writes rows as tab-separated values the way Sheets puts them147+// on the clipboard: fields with tabs, line breaks or a leading quote are148+// quoted, with quotes doubled.149+func formatTSV(rows [][]string) string {150+ var b strings.Builder151+ for i, row := range rows {152+ if i > 0 {153+ b.WriteByte('\n')154+ }155+ for j, f := range row {156+ if j > 0 {157+ b.WriteByte('\t')158+ }159+ if strings.ContainsAny(f, "\t\n\r") || strings.HasPrefix(f, `"`) {160+ f = `"` + strings.ReplaceAll(f, `"`, `""`) + `"`161+ }162+ b.WriteString(f)163+ }164+ }165+ return b.String()166+}167+168+// parseTSV reads tab-separated rows, keeping blank lines and fields, and169+// unquoting fields written by formatTSV (or Sheets and Excel).170+func parseTSV(s string) [][]string {171+ var rows [][]string172+ var row []string173+ var field strings.Builder174+ quoted, fieldStart := false, true175+ for i := 0; i < len(s); i++ {176+ c := s[i]177+ switch {178+ case quoted && c == '"' && i+1 < len(s) && s[i+1] == '"':179+ field.WriteByte('"')180+ i++181+ case quoted && c == '"':182+ quoted = false183+ case quoted:184+ field.WriteByte(c)185+ case c == '"' && fieldStart:186+ quoted = true187+ case c == '\t':188+ row = append(row, field.String())189+ field.Reset()190+ fieldStart = true191+ continue192+ case c == '\n':193+ row = append(row, strings.TrimSuffix(field.String(), "\r"))194+ rows = append(rows, row)195+ row, fieldStart = nil, true196+ field.Reset()197+ continue198+ default:199+ field.WriteByte(c)200+ }201+ fieldStart = false202+ }203+ return append(rows, append(row, strings.TrimSuffix(field.String(), "\r")))204+}205+206+// readyLine is the context line in READY mode: feedback on the last207+// action, or what to do with a copied range.208+func (m *Model) readyLine() string {209+ switch {210+ case m.note != "":211+ return m.note212+ case m.copied.marked && m.copied.cut:213+ return "Cut " + m.copied.clip.Src.String() + " " + m.keyHints("Ctrl+V", "move here", "Esc", "cancel")214+ case m.copied.marked:215+ text := "Copied " + m.copied.clip.Src.String() + " "216+ full := text + m.keyHints("Ctrl+V", "paste", "Ctrl+Shift+V", "paste values", "Esc", "clear")217+ if ansi.StringWidth(full) <= m.width {218+ return full219+ }220+ return text + m.keyHints("Ctrl+V", "paste", "Esc", "clear")221+ }222+ return ""223+}
M internal/ui/commands.go +42 -22
@@ -1,7 +1,9 @@
11 package ui22 33 import (4+ "cmp"45 "slices"6+ "strings"57 68 tea "charm.land/bubbletea/v2"79
@@ -16,6 +18,15 @@ type command struct {
1618 title string // shown in menus, the palette and help, e.g. "Save"1719 desc string // one line, shown on the third panel line1820 run func(m *Model) tea.Cmd21+22+ // enabled, when set, reports whether the command can run right now.23+ // Menus and the palette show unavailable commands dimmed.24+ enabled func(m *Model) bool25+}26+27+// available reports whether the command can run in m's current state.28+func (c *command) available(m *Model) bool {29+ return c.enabled == nil || c.enabled(m)1930 }2031 2132 var commands = map[string]*command{}
@@ -32,7 +43,6 @@ func register(cmds ...*command) {
3243 // keymap binds READY-mode keys to command IDs, following Google Sheets3344 // where it has a shortcut. Movement and typing are handled separately.3445 var keymap = map[string]string{35- "f10": "menu",3646 "f1": "help",3747 "ctrl+/": "help",3848 "enter": "edit",
@@ -50,7 +60,9 @@ var keymap = map[string]string{
5060 "ctrl+q": "quit",5161 }5262 53-// keysFor returns the shortcuts bound to a command, sorted.63+// keysFor returns the shortcuts bound to a command, the one to show first64+// leading: Ctrl combinations (what Sheets shows), then function keys, then65+// Alt combinations and named keys.5466 func keysFor(id string) []string {5567 var keys []string5668 for k, c := range keymap {
@@ -58,10 +70,35 @@ func keysFor(id string) []string {
5870 keys = append(keys, k)5971 }6072 }61- slices.Sort(keys)73+ slices.SortFunc(keys, func(a, b string) int {74+ return cmp.Or(cmp.Compare(keyRank(a), keyRank(b)), cmp.Compare(a, b))75+ })6276 return keys6377 }6478 79+func keyRank(k string) int {80+ switch {81+ case strings.HasPrefix(k, "ctrl+"):82+ return 083+ case len(k) >= 2 && k[0] == 'f' && k[1] >= '0' && k[1] <= '9':84+ return 185+ case strings.HasPrefix(k, "alt+"):86+ return 287+ case k == "delete":88+ return 389+ }90+ return 491+}92+93+// shortcut is the key shown next to a command in menus and the palette,94+// e.g. "Ctrl+S", or "" if it has none.95+func shortcut(id string) string {96+ if keys := keysFor(id); len(keys) > 0 {97+ return keyLabel(keys[0])98+ }99+ return ""100+}101+65102 // runCommand runs a registered command by ID.66103 func (m *Model) runCommand(id string) tea.Cmd {67104 c, ok := commands[id]
@@ -73,14 +110,6 @@ func (m *Model) runCommand(id string) tea.Cmd {
73110 74111 func init() {75112 register(76- &command{id: "menu", title: "Menu", desc: "Open the menu", run: func(m *Model) tea.Cmd {77- m.openMenu()78- return nil79- }},80- &command{id: "help", title: "Keyboard shortcuts", desc: "Show keys and functions", run: func(m *Model) tea.Cmd {81- m.mode = modeHelp82- return nil83- }},84113 &command{id: "edit", title: "Edit cell", desc: "Edit the active cell's contents", run: (*Model).startEdit},85114 &command{id: "goto", title: "Go to", desc: "Move to a cell address", run: func(m *Model) tea.Cmd {86115 m.openGoto()
@@ -91,8 +120,9 @@ func init() {
91120 m.changed = true92121 return nil93122 }},94- &command{id: "select.none", title: "Deselect", desc: "Collapse the selection to the active cell", run: func(m *Model) tea.Cmd {123+ &command{id: "select.none", title: "Deselect", desc: "Collapse the selection and clear the copy marker", run: func(m *Model) tea.Cmd {95124 m.clearSelection()125+ m.clearCopyMark()96126 return nil97127 }},98128 &command{id: "select.all", title: "Select all", desc: "Select the data, then the whole sheet", run: (*Model).selectAll},
@@ -125,13 +155,3 @@ func (m *Model) save() tea.Cmd {
125155 }126156 return saveCmd(m.sheet, m.filename)127157 }128-129-// quit exits, confirming first when there are unsaved changes.130-func (m *Model) quit() tea.Cmd {131- if !m.changed {132- return tea.Quit133- }134- m.openMenu()135- m.menu = append(m.menu, menuLevel{items: quitConfirm})136- return nil137-}
A internal/ui/context.go +87 -0
@@ -0,0 +1,87 @@
1+package ui2+3+import (4+ tea "charm.land/bubbletea/v2"5+6+ "one23/internal/sheet"7+)8+9+// Right-click menus follow Sheets: the cell menu offers clipboard, insert10+// and delete commands, and the header menus the subset for whole columns11+// or rows. Right-clicking outside the selection first moves there, and12+// Shift+F10 opens the cell menu from the keyboard. The menus reuse the13+// dropdown, so missing commands are hidden the same way.14+15+var (16+ clipboardItems = []menuItem{17+ {cmd: "edit.cut"}, {cmd: "edit.copy"}, {cmd: "edit.paste"},18+ }19+ cellMenu = concat(clipboardItems, []menuItem{20+ {cmd: "edit.paste_values", title: "Paste values only"}, sep,21+ {cmd: "insert.row_above", title: "Insert row above"}, {cmd: "insert.row_below", title: "Insert row below"},22+ {cmd: "insert.col_left", title: "Insert column left"}, {cmd: "insert.col_right", title: "Insert column right"}, sep,23+ {cmd: "delete.row", title: "Delete row"}, {cmd: "delete.col", title: "Delete column"}, sep,24+ {cmd: "clear"},25+ })26+ columnMenu = concat(clipboardItems, []menuItem{sep,27+ {cmd: "insert.col_left", title: "Insert column left"}, {cmd: "insert.col_right", title: "Insert column right"}, sep,28+ {cmd: "delete.col", title: "Delete column"}, {cmd: "clear"}, sep,29+ {cmd: "column.width", title: "Resize column"}, {cmd: "column.reset"},30+ })31+ rowMenu = concat(clipboardItems, []menuItem{sep,32+ {cmd: "insert.row_above", title: "Insert row above"}, {cmd: "insert.row_below", title: "Insert row below"}, sep,33+ {cmd: "delete.row", title: "Delete row"}, {cmd: "clear"},34+ })35+)36+37+func concat(lists ...[]menuItem) []menuItem {38+ var out []menuItem39+ for _, l := range lists {40+ out = append(out, l...)41+ }42+ return out43+}44+45+func init() {46+ register(&command{id: "menu.context", title: "Cell menu", desc: "Open the right-click menu for the selection", run: func(m *Model) tea.Cmd {47+ x, y := m.cellPos(m.cur)48+ m.showContextMenu(cellMenu, x, y+1)49+ return nil50+ }})51+ keymap["shift+f10"] = "menu.context"52+}53+54+// rightClick opens the menu for what's under the mouse at x, y.55+func (m *Model) rightClick(x, y int) {56+ h := m.hitTest(x, y)57+ sel := m.selection()58+ switch h.kind {59+ case hitCell:60+ if !m.hasRange() || !sel.Contains(h.addr) {61+ m.cur = h.addr62+ m.clearSelection()63+ }64+ m.showContextMenu(cellMenu, x, y+1)65+ case hitColHeader, hitColBorder:66+ if m.whole != wholeCols || h.addr.Col < sel.From.Col || h.addr.Col > sel.To.Col {67+ m.cur = h.addr68+ m.selecting, m.whole, m.ext = true, wholeCols, h.addr69+ }70+ m.showContextMenu(columnMenu, x, y+1)71+ case hitRowHeader:72+ if m.whole != wholeRows || h.addr.Row < sel.From.Row || h.addr.Row > sel.To.Row {73+ m.cur = h.addr74+ m.selecting, m.whole, m.ext = true, wholeRows, h.addr75+ }76+ m.showContextMenu(rowMenu, x, y+1)77+ }78+}79+80+// cellPos returns the screen position of a visible cell's left edge.81+func (m *Model) cellPos(a sheet.Addr) (x, y int) {82+ x = rowHdrW83+ for c := m.left; c < a.Col; c++ {84+ x += m.sheet.ColWidth(c)85+ }86+ return x, gridTop + a.Row - m.top87+}
A internal/ui/context_test.go +107 -0
@@ -0,0 +1,107 @@
1+package ui2+3+import (4+ "strings"5+ "testing"6+7+ tea "charm.land/bubbletea/v2"8+9+ "one23/internal/sheet"10+)11+12+func rightClick(m *Model, x, y int) {13+ mouseAt(m, tea.MouseClickMsg{X: x, Y: y, Button: tea.MouseRight})14+ mouseAt(m, tea.MouseReleaseMsg{X: x, Y: y, Button: tea.MouseRight})15+}16+17+func menuLabels(t *testing.T, m *Model) string {18+ t.Helper()19+ var got []string20+ for _, it := range openMenu(t, m).top().items {21+ if it.sep {22+ got = append(got, "-")23+ } else {24+ got = append(got, it.label())25+ }26+ }27+ return strings.Join(got, ",")28+}29+30+// tallModel has room for full-height context menus below the click.31+func tallModel() *Model {32+ m := newModel()33+ m.Update(tea.WindowSizeMsg{Width: 80, Height: 40})34+ return m35+}36+37+func TestRightClickCellMenu(t *testing.T) {38+ copied := fakeCommand(t, "edit.copy", "Copy", nil)39+ m := tallModel()40+ press(t, m, "<shift+down>", "<shift+right>") // A1:B241+ // Inside the selection, the selection stays.42+ rightClick(m, cellX(1), gridTop+1)43+ if m.selection().String() != "A1:B2" {44+ t.Errorf("right-click inside moved the selection to %s", m.selection())45+ }46+ if got := menuLabels(t, m); got != "Cut,Copy,Paste,Paste values only,-,Insert row above,Insert row below,Insert column left,Insert column right,-,Delete row,Delete column,-,Clear" {47+ t.Errorf("cell menu %s", got)48+ }49+ o := openMenu(t, m)50+ if b := o.layout(m)[0]; b.x != cellX(1) || b.y != gridTop+2 {51+ t.Errorf("menu at %d,%d", b.x, b.y)52+ }53+ press(t, m, "<down>", "<enter>")54+ if *copied != 1 || m.overlay != nil {55+ t.Errorf("copy ran %d times", *copied)56+ }57+ // Outside the selection, the active cell moves there first.58+ rightClick(m, cellX(3), gridTop+5)59+ if m.cur != addr("D6") || m.hasRange() {60+ t.Errorf("right-click outside: cur %v range %v", m.cur, m.hasRange())61+ }62+ // Right-clicking elsewhere with a menu open moves the menu.63+ rightClick(m, cellX(0), gridTop)64+ if m.cur != addr("A1") || m.overlay == nil {65+ t.Errorf("second right-click: cur %v overlay %T", m.cur, m.overlay)66+ }67+ press(t, m, "<esc>")68+ if m.overlay != nil || m.mode != modeReady {69+ t.Error("Esc did not close the context menu")70+ }71+}72+73+func TestRightClickHeaders(t *testing.T) {74+ m := tallModel()75+ rightClick(m, cellX(2), headerLine)76+ if r := m.selection(); r.From != addr("C1") || r.To.Row != sheet.MaxRows-1 || r.To.Col != 2 {77+ t.Errorf("column header selected %s", r)78+ }79+ if got := menuLabels(t, m); got != "Cut,Copy,Paste,-,Insert column left,Insert column right,-,Delete column,Clear,-,Resize column,Reset column width" {80+ t.Errorf("column menu %s", got)81+ }82+ press(t, m, "r")83+ if highlighted(t, m) != "Resize column" {84+ t.Errorf("r highlighted %q", highlighted(t, m))85+ }86+ press(t, m, "<enter>")87+ if m.mode != modePrompt || m.prompt.kind != promptWidth {88+ t.Errorf("Resize column: mode %v", m.mode)89+ }90+ press(t, m, "<esc>")91+ rightClick(m, 1, gridTop+3)92+ if r := m.selection(); r.From != addr("A4") || r.To.Col != sheet.MaxCols-1 {93+ t.Errorf("row header selected %s", r)94+ }95+ if got := menuLabels(t, m); got != "Cut,Copy,Paste,-,Insert row above,Insert row below,-,Delete row,Clear" {96+ t.Errorf("row menu %s", got)97+ }98+}99+100+func TestShiftF10OpensCellMenu(t *testing.T) {101+ m := tallModel()102+ press(t, m, "<right>", "<down>", "<shift+f10>")103+ b := openMenu(t, m).layout(m)[0]104+ if b.x != cellX(1)-2 || b.y != gridTop+2 {105+ t.Errorf("menu at %d,%d", b.x, b.y)106+ }107+}
A internal/ui/dialog.go +106 -0
@@ -0,0 +1,106 @@
1+package ui2+3+import (4+ "strings"5+6+ tea "charm.land/bubbletea/v2"7+ "github.com/charmbracelet/x/ansi"8+)9+10+// choiceBar is a small question asked on the context line and answered11+// with a key, the way terminal programs confirm things, e.g.12+// "You have unsaved changes. Enter Save and quit D Discard Esc Cancel".13+// It takes the keyboard like an overlay but draws no box.14+type choiceBar struct {15+ msg string16+ warn bool // the message is a warning, e.g. about losing work17+ choices []choice18+}19+20+type choice struct {21+ key string // as tea reports it, e.g. "enter" or "d"22+ label string23+ run func(m *Model) tea.Cmd24+}25+26+func (c *choiceBar) indicator() string { return "MENU" }27+func (c *choiceBar) layout(*Model) []box { return nil }28+func (c *choiceBar) status(*Model) (string, string) { return "", "" }29+30+func (c *choiceBar) key(m *Model, k tea.KeyPressMsg) tea.Cmd {31+ key := strings.ToLower(k.String())32+ for _, ch := range c.choices {33+ if key == ch.key {34+ return c.choose(m, ch)35+ }36+ }37+ return nil38+}39+40+func (c *choiceBar) choose(m *Model, ch choice) tea.Cmd {41+ m.closeOverlay()42+ return ch.run(m)43+}44+45+// mouse runs a choice when its key chip or label is clicked. A click46+// anywhere else cancels, like Esc.47+func (c *choiceBar) mouse(m *Model, e mouseEvent) tea.Cmd {48+ if e.kind != mousePress {49+ return nil50+ }51+ if e.y == contextLine {52+ x := ansi.StringWidth(c.prefix(m))53+ for _, ch := range c.choices {54+ w := ansi.StringWidth(c.item(m, ch))55+ if e.x >= x && e.x < x+w {56+ return c.choose(m, ch)57+ }58+ x += w + len(choiceGap)59+ }60+ }61+ m.closeOverlay()62+ return nil63+}64+65+const choiceGap = " "66+67+func (c *choiceBar) prefix(m *Model) string {68+ if c.warn {69+ return m.th.warning.Render(c.msg) + choiceGap70+ }71+ return c.msg + choiceGap72+}73+74+func (c *choiceBar) item(m *Model, ch choice) string {75+ return m.chip(keyLabel(ch.key)) + " " + ch.label76+}77+78+// line renders the bar for the context line.79+func (c *choiceBar) line(m *Model) string {80+ items := make([]string, len(c.choices))81+ for i, ch := range c.choices {82+ items[i] = c.item(m, ch)83+ }84+ return c.prefix(m) + strings.Join(items, choiceGap)85+}86+87+// quit exits, asking first when there are unsaved changes. Enter saves88+// and quits, so the quick path never loses work.89+func (m *Model) quit() tea.Cmd {90+ if !m.changed {91+ return exit()92+ }93+ m.openOverlay(&choiceBar{94+ msg: "You have unsaved changes.",95+ warn: true,96+ choices: []choice{97+ {key: "enter", label: "Save and quit", run: func(m *Model) tea.Cmd {98+ m.quitAfterSave = true99+ return m.save()100+ }},101+ {key: "d", label: "Discard", run: func(*Model) tea.Cmd { return exit() }},102+ {key: "esc", label: "Cancel", run: func(*Model) tea.Cmd { return nil }},103+ },104+ })105+ return nil106+}
A internal/ui/edit.go +294 -0
@@ -0,0 +1,294 @@
1+package ui2+3+import (4+ "errors"5+ "fmt"6+ "slices"7+ "strings"8+ "unicode/utf8"9+10+ tea "charm.land/bubbletea/v2"11+12+ "one23/internal/sheet"13+)14+15+// Undo and redo, fill, inserting and deleting rows and columns, and F4 in16+// formulas. The engine does the work and records each change as one undo17+// step; this file maps commands onto the selection and reports back on the18+// context line.19+20+func init() {21+ register(22+ &command{id: "edit.undo", title: "Undo", desc: "Undo the last change", run: (*Model).undo},23+ &command{id: "edit.redo", title: "Redo", desc: "Redo the last undone change", run: (*Model).redo},24+ &command{id: "edit.fill_down", title: "Fill down", desc: "Copy the top row of the selection into the rows below it", run: func(m *Model) tea.Cmd {25+ return m.fill(m.sheet.FillDown)26+ }},27+ &command{id: "edit.fill_right", title: "Fill right", desc: "Copy the left column of the selection into the columns right of it", run: func(m *Model) tea.Cmd {28+ return m.fill(m.sheet.FillRight)29+ }},30+ &command{id: "insert.row_above", title: "Insert rows above", desc: "Insert as many rows above the selection as it spans", run: func(m *Model) tea.Cmd {31+ r := m.selection()32+ return m.structural(m.sheet.InsertRows(r.From.Row, r.To.Row-r.From.Row+1))33+ }},34+ &command{id: "insert.row_below", title: "Insert rows below", desc: "Insert as many rows below the selection as it spans", run: func(m *Model) tea.Cmd {35+ r := m.selection()36+ if r.To.Row == sheet.MaxRows-1 {37+ return m.structural(sheet.ErrPushedOff)38+ }39+ return m.structural(m.sheet.InsertRows(r.To.Row+1, r.To.Row-r.From.Row+1))40+ }},41+ &command{id: "insert.col_left", title: "Insert columns left", desc: "Insert as many columns left of the selection as it spans", run: func(m *Model) tea.Cmd {42+ r := m.selection()43+ return m.structural(m.sheet.InsertCols(r.From.Col, r.To.Col-r.From.Col+1))44+ }},45+ &command{id: "insert.col_right", title: "Insert columns right", desc: "Insert as many columns right of the selection as it spans", run: func(m *Model) tea.Cmd {46+ r := m.selection()47+ if r.To.Col == sheet.MaxCols-1 {48+ return m.structural(sheet.ErrPushedOff)49+ }50+ return m.structural(m.sheet.InsertCols(r.To.Col+1, r.To.Col-r.From.Col+1))51+ }},52+ &command{id: "delete.row", title: "Delete rows", desc: "Delete the selected rows; references to them become #REF!", run: func(m *Model) tea.Cmd {53+ r := m.selection()54+ m.sheet.DeleteRows(r.From.Row, r.To.Row-r.From.Row+1)55+ return nil56+ }},57+ &command{id: "delete.col", title: "Delete columns", desc: "Delete the selected columns; references to them become #REF!", run: func(m *Model) tea.Cmd {58+ r := m.selection()59+ m.sheet.DeleteCols(r.From.Col, r.To.Col-r.From.Col+1)60+ return nil61+ }},62+ // Sheets' Ctrl+Alt+= and Ctrl+Alt+- act on rows, or on columns when63+ // whole columns are selected.64+ &command{id: "insert.selection", title: "Insert rows or columns", desc: "Insert rows above the selection, or columns left of it when whole columns are selected", run: func(m *Model) tea.Cmd {65+ if m.whole == wholeCols {66+ return m.runCommand("insert.col_left")67+ }68+ return m.runCommand("insert.row_above")69+ }},70+ &command{id: "delete.selection", title: "Delete rows or columns", desc: "Delete the selected rows, or columns when whole columns are selected", run: func(m *Model) tea.Cmd {71+ if m.whole == wholeCols {72+ return m.runCommand("delete.col")73+ }74+ return m.runCommand("delete.row")75+ }},76+ )77+ keymap["ctrl+alt+="] = "insert.selection"78+ keymap["ctrl+alt+-"] = "delete.selection"79+ keymap["ctrl+z"] = "edit.undo"80+ keymap["ctrl+y"] = "edit.redo"81+ keymap["ctrl+shift+z"] = "edit.redo"82+ keymap["ctrl+d"] = "edit.fill_down"83+ keymap["ctrl+r"] = "edit.fill_right"84+}85+86+func (m *Model) undo() tea.Cmd {87+ c, ok := m.sheet.Undo()88+ m.afterHistory("Undid", "Nothing to undo", c, ok)89+ return nil90+}91+92+func (m *Model) redo() tea.Cmd {93+ c, ok := m.sheet.Redo()94+ m.afterHistory("Redid", "Nothing to redo", c, ok)95+ return nil96+}97+98+// afterHistory selects what an undo or redo changed, as Sheets does, and99+// says what it was on the context line.100+func (m *Model) afterHistory(verb, none string, c sheet.Change, ok bool) {101+ if !ok {102+ m.note = none103+ return104+ }105+ m.note = verb + ": " + c.Label106+ m.selectRect(c.Focus)107+}108+109+// selectRect selects r, as whole columns or rows when it spans the sheet.110+func (m *Model) selectRect(r sheet.Rect) {111+ allRows := r.From.Row == 0 && r.To.Row == sheet.MaxRows-1112+ allCols := r.From.Col == 0 && r.To.Col == sheet.MaxCols-1113+ switch {114+ case allRows && allCols:115+ m.selecting, m.whole, m.ext = true, wholeAll, m.cur116+ case allRows:117+ m.cur.Col = r.From.Col118+ m.ext = sheet.Addr{Col: r.To.Col, Row: m.cur.Row}119+ m.selecting, m.whole = true, wholeCols120+ case allCols:121+ m.cur.Row = r.From.Row122+ m.ext = sheet.Addr{Col: m.cur.Col, Row: r.To.Row}123+ m.selecting, m.whole = true, wholeRows124+ default:125+ m.cur, m.ext = r.From, r.To126+ m.selecting, m.whole = r.From != r.To, wholeNone127+ }128+}129+130+func (m *Model) fill(fn func(sheet.Rect) (sheet.Rect, error)) tea.Cmd {131+ if _, err := fn(m.selection()); err != nil {132+ m.fail(err.Error())133+ }134+ return nil135+}136+137+// structural reports an insert that couldn't be done.138+func (m *Model) structural(err error) tea.Cmd {139+ if err != nil {140+ m.fail(err.Error())141+ }142+ return nil143+}144+145+// fillEntry stores the entry being typed in every selected cell, adjusting146+// references as if it were copied from the active cell (Ctrl+Enter).147+func (m *Model) fillEntry() bool {148+ input := string(m.buf)149+ if err := m.sheet.FillEntry(m.selection(), m.cur, input); err != nil {150+ m.entryError(err, input)151+ return false152+ }153+ m.cancelEntry()154+ return true155+}156+157+// entryError keeps an entry that can't be stored in EDIT mode, with the158+// caret at the problem and the reason on line 3.159+func (m *Model) entryError(err error, input string) {160+ var pe *sheet.ParseError161+ m.mode = modeEdit162+ m.hint = err.Error()163+ if errors.As(err, &pe) {164+ m.bufPos = utf8.RuneCountInString(input[:min(pe.Pos, len(input))])165+ }166+}167+168+// toggleAbsolute cycles the reference at the caret through A1, $A$1, A$1169+// and $A1, as F4 does in Sheets. A range cycles both corners.170+func (m *Model) toggleAbsolute() {171+ if buf, pos, ok := cycleRef(m.buf, m.bufPos); ok {172+ m.buf, m.bufPos = buf, pos173+ }174+}175+176+// cycleRef finds the reference (or range) at or just before pos in a177+// formula and returns the text with its absolute markers cycled, and the178+// caret moved to the reference's end.179+func cycleRef(buf []rune, pos int) ([]rune, int, bool) {180+ quoted := make([]bool, len(buf))181+ in := false182+ for i, r := range buf {183+ if r == '"' {184+ in = !in185+ }186+ quoted[i] = in || r == '"'187+ }188+ isRefRune := func(i int) bool {189+ r := buf[i]190+ return !quoted[i] && (r == '$' || r >= '0' && r <= '9' || r >= 'A' && r <= 'Z' || r >= 'a' && r <= 'z')191+ }192+ // word returns the bounds of the run of reference characters around i.193+ word := func(i int) (int, int) {194+ start, end := i, i195+ for start > 0 && isRefRune(start-1) {196+ start--197+ }198+ for end < len(buf) && isRefRune(end) {199+ end++200+ }201+ return start, end202+ }203+ isRef := func(start, end int) bool {204+ if start == end || start > 0 && buf[start-1] == '@' || end < len(buf) && buf[end] == '(' {205+ return false206+ }207+ _, ok := sheet.ParseAddr(string(buf[start:end]))208+ return ok209+ }210+ start, end := word(pos)211+ if !isRef(start, end) {212+ return nil, 0, false213+ }214+ // Widen to a range written A1:B2 or A1..B2.215+ sep := func(i int) int {216+ switch {217+ case i < len(buf) && buf[i] == ':':218+ return 1219+ case i+1 < len(buf) && buf[i] == '.' && buf[i+1] == '.':220+ return 2221+ }222+ return 0223+ }224+ corners := [][2]int{{start, end}}225+ if n := sep(end); n > 0 {226+ if s2, e2 := word(end + n); s2 == end+n && isRef(s2, e2) {227+ corners = append(corners, [2]int{s2, e2})228+ }229+ } else {230+ for n := 1; n <= 2 && start-n > 0; n++ {231+ if sep(start-n) == n {232+ if s0, e0 := word(start - n - 1); e0 == start-n && isRef(s0, e0) {233+ corners = [][2]int{{s0, e0}, {start, end}}234+ }235+ break236+ }237+ }238+ }239+ next := nextMarkers(string(buf[corners[0][0]:corners[0][1]]))240+ out := slices.Clone(buf[:corners[0][0]])241+ for i, c := range corners {242+ if i > 0 {243+ out = append(out, buf[corners[i-1][1]:c[0]]...)244+ }245+ out = append(out, []rune(withMarkers(string(buf[c[0]:c[1]]), next))...)246+ }247+ caret := len(out)248+ out = append(out, buf[corners[len(corners)-1][1]:]...)249+ return out, caret, true250+}251+252+// nextMarkers returns the absolute markers that follow ref's in F4's253+// cycle: A1 -> $A$1 -> A$1 -> $A1 -> A1.254+func nextMarkers(ref string) markers {255+ col := strings.HasPrefix(ref, "$")256+ row := strings.Contains(ref[1:], "$")257+ switch {258+ case !col && !row:259+ return markers{true, true}260+ case col && row:261+ return markers{false, true}262+ case row:263+ return markers{true, false}264+ }265+ return markers{}266+}267+268+// markers says which parts of a reference are absolute.269+type markers struct{ col, row bool }270+271+// withMarkers rewrites ref with the given absolute markers.272+func withMarkers(ref string, marks markers) string {273+ ref = strings.ToUpper(strings.ReplaceAll(ref, "$", ""))274+ i := strings.IndexAny(ref, "0123456789")275+ var b strings.Builder276+ if marks.col {277+ b.WriteByte('$')278+ }279+ b.WriteString(ref[:i])280+ if marks.row {281+ b.WriteByte('$')282+ }283+ b.WriteString(ref[i:])284+ return b.String()285+}286+287+// countCells describes a paste for the context line.288+func countCells(r sheet.Rect) string {289+ n := (r.To.Col - r.From.Col + 1) * (r.To.Row - r.From.Row + 1)290+ if n == 1 {291+ return "1 cell"292+ }293+ return fmt.Sprintf("%d cells", n)294+}
A internal/ui/edit_test.go +311 -0
@@ -0,0 +1,311 @@
1+package ui2+3+import (4+ "fmt"5+ "strings"6+ "testing"7+8+ tea "charm.land/bubbletea/v2"9+)10+11+func init() {12+ named["f4"] = tea.Key{Code: tea.KeyF4}13+ named["end"] = tea.Key{Code: tea.KeyEnd}14+}15+16+func TestUndoRedoKeys(t *testing.T) {17+ t.Chdir(t.TempDir())18+ m := newModel()19+ press(t, m, "1", "<enter>", "=A1*2", "<enter>", "<ctrl+s>", "undo", "<enter>")20+ if m.changed {21+ t.Fatal("changed after save")22+ }23+ press(t, m, "<up>", "<delete>")24+ if !m.changed || input(m, "A2") != "" {25+ t.Fatalf("clear: changed %v A2 %q", m.changed, input(m, "A2"))26+ }27+ press(t, m, "<ctrl+home>", "<ctrl+z>")28+ if input(m, "A2") != "=A1*2" || m.cur != addr("A2") || m.changed {29+ t.Errorf("undo: A2 %q cur %v changed %v", input(m, "A2"), m.cur, m.changed)30+ }31+ if got := line(m, 2); got != "Undid: clear A2" {32+ t.Errorf("context line %q", got)33+ }34+ press(t, m, "<ctrl+z>", "<ctrl+z>")35+ if m.sheet.Len() != 0 || line(m, 2) != "Undid: edit A1" || !m.changed {36+ t.Errorf("undo all: %d cells, line %q, changed %v", m.sheet.Len(), line(m, 2), m.changed)37+ }38+ press(t, m, "<ctrl+z>")39+ if line(m, 2) != "Nothing to undo" {40+ t.Errorf("context line %q", line(m, 2))41+ }42+ press(t, m, "<ctrl+y>", "<ctrl+shift+z>")43+ if m.sheet.Value(addr("A2")).Num != 2 || line(m, 2) != "Redid: edit A2" {44+ t.Errorf("redo: A2 %+v line %q", m.sheet.Value(addr("A2")), line(m, 2))45+ }46+ // The note goes away with the next key.47+ press(t, m, "<down>")48+ if line(m, 2) != "" {49+ t.Errorf("note stayed: %q", line(m, 2))50+ }51+}52+53+func TestUndoColumnWidthPrompt(t *testing.T) {54+ m := newModel()55+ run(m, m.runCommand("column.width"))56+ press(t, m, "<right>", "<right>", "<enter>")57+ if m.sheet.ColWidth(0) != 12 {58+ t.Fatalf("width %d", m.sheet.ColWidth(0))59+ }60+ press(t, m, "<ctrl+z>")61+ if m.sheet.ColWidth(0) != 10 || m.sheet.CanUndo() {62+ t.Errorf("width preview and result should be one step: width %d", m.sheet.ColWidth(0))63+ }64+ run(m, m.runCommand("column.width"))65+ press(t, m, "<right>", "<esc>")66+ if m.sheet.CanUndo() || m.changed {67+ t.Errorf("cancelled width prompt left an undo step: %v %v %d %v", m.sheet.CanUndo(), m.changed, m.sheet.ColWidth(0), m.mode)68+ }69+}70+71+// clipboardText runs the copy command and returns what it sends to the72+// system clipboard.73+func clipboardText(t *testing.T, m *Model, id string) string {74+ t.Helper()75+ cmd := m.runCommand(id)76+ if cmd == nil {77+ t.Fatal("no clipboard command")78+ }79+ return fmt.Sprint(cmd())80+}81+82+func TestCopyPaste(t *testing.T) {83+ m := newModel()84+ press(t, m, "1", "<tab>", "=A1*2", "<enter>", "2", "<enter>", "<ctrl+home>", "<shift+right>")85+ if got := clipboardText(t, m, "edit.copy"); got != "1\t2" {86+ t.Errorf("system clipboard %q", got)87+ }88+ if l := line(m, 2); !m.copyMarked(addr("B1")) || !strings.HasPrefix(l, "Copied A1:B1") || !strings.Contains(l, "Ctrl+V") {89+ t.Fatalf("marker %v, line %q", m.copyMarked(addr("B1")), line(m, 2))90+ }91+ press(t, m, "<down>", "<ctrl+v>")92+ if input(m, "B2") != "=A2*2" || m.sheet.Value(addr("B2")).Num != 2 || m.selection().String() != "A2:B2" {93+ t.Errorf("paste: B2 %q = %+v, selection %v", input(m, "B2"), m.sheet.Value(addr("B2")), m.selection())94+ }95+ if line(m, 2) != "Pasted 2 cells at A2:B2" || !m.copied.marked {96+ t.Errorf("after paste: line %q marked %v", line(m, 2), m.copied.marked)97+ }98+ // Pasting into a larger multiple tiles.99+ press(t, m, "<down>", "<shift+down>", "<shift+down>", "<shift+right>", "<ctrl+v>")100+ if input(m, "B5") != "=A5*2" || m.selection().String() != "A3:B5" {101+ t.Errorf("tiled paste: B5 %q selection %v", input(m, "B5"), m.selection())102+ }103+ press(t, m, "<esc>")104+ if m.copied.marked || line(m, 2) != "" {105+ t.Errorf("Esc kept the marker: line %q", line(m, 2))106+ }107+ // Ctrl+V still pastes after the marker is gone.108+ press(t, m, "<right>", "<right>", "<ctrl+shift+v>")109+ if input(m, "C3") != "1" || input(m, "D3") != "2" {110+ t.Errorf("paste values: %q %q", input(m, "C3"), input(m, "D3"))111+ }112+}113+114+func TestEditClearsCopyMarker(t *testing.T) {115+ m := newModel()116+ press(t, m, "1", "<enter>", "<up>", "<ctrl+c>", "<down>", "x", "<enter>")117+ if m.copied.marked {118+ t.Error("an edit kept the copy marker")119+ }120+ press(t, m, "<ctrl+v>")121+ if input(m, "A3") != "1" {122+ t.Errorf("paste after edit: %q", input(m, "A3"))123+ }124+}125+126+func TestCutPasteMoves(t *testing.T) {127+ m := newModel()128+ press(t, m, "5", "<enter>", "=A1+1", "<enter>", "<ctrl+home>", "<ctrl+x>")129+ if l := line(m, 2); !strings.HasPrefix(l, "Cut A1") || !strings.Contains(l, "move here") {130+ t.Errorf("context line %q", line(m, 2))131+ }132+ press(t, m, "<right>", "<right>", "<ctrl+v>")133+ if input(m, "A1") != "" || input(m, "C1") != "5" || input(m, "A2") != "=C1+1" {134+ t.Errorf("move: A1 %q C1 %q A2 %q", input(m, "A1"), input(m, "C1"), input(m, "A2"))135+ }136+ if m.copied.clip != nil || line(m, 2) != "Moved A1 to C1" {137+ t.Errorf("cut should paste once: line %q", line(m, 2))138+ }139+ press(t, m, "<ctrl+z>")140+ if input(m, "A1") != "5" || input(m, "A2") != "=A1+1" {141+ t.Errorf("undo move: A1 %q A2 %q", input(m, "A1"), input(m, "A2"))142+ }143+}144+145+func TestCopyMarkerDrawn(t *testing.T) {146+ m := newModel()147+ press(t, m, "1", "<enter>")148+ before := m.gridRow(0)149+ press(t, m, "<up>", "<ctrl+c>", "<down>")150+ if m.gridRow(0) == before || !strings.Contains(m.gridRow(0), "\x1b[") {151+ t.Errorf("copy marker not drawn: %q", m.gridRow(0))152+ }153+}154+155+func TestPasteTSVFromTerminal(t *testing.T) {156+ m := newModel()157+ press(t, m, "<right>")158+ send(m, tea.PasteMsg{Content: "Qty\tPrice\r\n2\t3\r\n\t=B2*C2\r\n"})159+ want := map[string]string{"B1": "Qty", "C1": "Price", "B2": "2", "C2": "3", "C3": "=B2*C2"}160+ for a, in := range want {161+ if input(m, a) != in {162+ t.Errorf("%s = %q, want %q", a, input(m, a), in)163+ }164+ }165+ if m.sheet.Value(addr("C3")).Num != 6 || m.selection().String() != "B1:C3" || line(m, 2) != "Pasted 6 cells at B1:C3" {166+ t.Errorf("C3 %+v selection %v line %q", m.sheet.Value(addr("C3")), m.selection(), line(m, 2))167+ }168+ press(t, m, "<ctrl+z>")169+ if m.sheet.Len() != 0 {170+ t.Errorf("paste should undo in one step, %d cells left", m.sheet.Len())171+ }172+ // A single line still starts an entry.173+ send(m, tea.PasteMsg{Content: "hello\n"})174+ if m.mode != modeEnter || string(m.buf) != "hello" {175+ t.Errorf("mode %v buf %q", m.mode, string(m.buf))176+ }177+}178+179+func TestTSVRoundTrip(t *testing.T) {180+ rows := [][]string{{"a", "tab\there", ""}, {`"quoted"`, "line\nbreak", `5" pipe`}, {"", "", ""}}181+ text := formatTSV(rows)182+ got := parseTSV(text)183+ if fmt.Sprint(got) != fmt.Sprint(rows) {184+ t.Errorf("round trip:\n%q\n%q", got, rows)185+ }186+ if got := parseTSV("a\t\tb\n\nc"); fmt.Sprint(got) != fmt.Sprint([][]string{{"a", "", "b"}, {""}, {"c"}}) {187+ t.Errorf("blank fields and lines: %q", got)188+ }189+}190+191+func TestFillKeys(t *testing.T) {192+ m := newModel()193+ press(t, m, "1", "<enter>", "2", "<enter>", "<ctrl+home>", "<right>", "=A1*10", "<enter>")194+ press(t, m, "<up>", "<shift+down>", "<ctrl+d>")195+ if input(m, "B2") != "=A2*10" || m.sheet.Value(addr("B2")).Num != 20 {196+ t.Errorf("fill down: B2 %q", input(m, "B2"))197+ }198+ press(t, m, "<shift+right>", "<ctrl+r>")199+ if input(m, "C2") != "=B2*10" {200+ t.Errorf("fill right: C2 %q", input(m, "C2"))201+ }202+ // Ctrl+Enter fills the entry into the selection, keeping it selected.203+ press(t, m, "<esc>", "<down>", "<down>", "<shift+down>", "<shift+right>", "=A1+$A$1", "<ctrl+enter>")204+ if input(m, "C4") != "=B2+$A$1" || m.mode != modeReady || m.selection().String() != "B3:C4" {205+ t.Errorf("ctrl+enter: C4 %q mode %v selection %v", input(m, "C4"), m.mode, m.selection())206+ }207+ press(t, m, "<ctrl+z>")208+ if input(m, "B3") != "" || input(m, "C4") != "" {209+ t.Error("ctrl+enter fill is not one undo step")210+ }211+}212+213+func TestInsertDeleteRowsAndColumns(t *testing.T) {214+ m := newModel()215+ press(t, m, "1", "<enter>", "2", "<enter>", "=SUM(A1:A2)", "<enter>")216+ press(t, m, "<up>", "<up>")217+ m.runCommand("insert.row_above")218+ if input(m, "A4") != "=SUM(A1:A3)" || input(m, "A2") != "" {219+ t.Fatalf("insert above: A4 %q", input(m, "A4"))220+ }221+ m.runCommand("insert.row_below")222+ if input(m, "A5") != "=SUM(A1:A4)" {223+ t.Errorf("insert below: A5 %q", input(m, "A5"))224+ }225+ press(t, m, "<ctrl+home>")226+ m.runCommand("delete.row")227+ if input(m, "A4") != "=SUM(A1:A3)" || m.sheet.Value(addr("A4")).Num != 2 {228+ t.Errorf("delete: A4 %q = %+v", input(m, "A4"), m.sheet.Value(addr("A4")))229+ }230+ m.runCommand("insert.col_left")231+ if input(m, "B4") != "=SUM(B1:B3)" {232+ t.Errorf("insert col: B4 %q", input(m, "B4"))233+ }234+ m.runCommand("insert.col_right")235+ press(t, m, "<right>")236+ m.runCommand("delete.col")237+ if input(m, "B4") != "=SUM(B1:B3)" {238+ t.Errorf("delete col: B4 %q", input(m, "B4"))239+ }240+ press(t, m, "<ctrl+z>")241+ if line(m, 2) != "Undid: delete 1 column" || m.whole != wholeCols {242+ t.Errorf("undo: line %q whole %v", line(m, 2), m.whole)243+ }244+ // Inserting can't push data off the sheet.245+ press(t, m, "<esc>", "<ctrl+end>", "<ctrl+space>")246+ m.runCommand("insert.row_above")247+ if m.mode != modeError {248+ t.Errorf("mode %v", m.mode)249+ }250+}251+252+func TestF4CyclesReferences(t *testing.T) {253+ m := newModel()254+ press(t, m, "=A1+B2")255+ for _, want := range []string{"=A1+$B$2", "=A1+B$2", "=A1+$B2", "=A1+B2"} {256+ press(t, m, "<f4>")257+ if string(m.buf) != want {258+ t.Errorf("F4 gave %q, want %q", string(m.buf), want)259+ }260+ }261+ // F4 while pointing puts the reference in first.262+ press(t, m, "*", "<up>", "<f4>")263+ if string(m.buf) != "=A1+B2*$A$1" || m.mode != modeEnter {264+ t.Errorf("F4 in POINT: %q mode %v", string(m.buf), m.mode)265+ }266+}267+268+func TestCycleRef(t *testing.T) {269+ tests := []struct {270+ in string271+ caret int272+ want string273+ ok bool274+ }{275+ {"=a1", 3, "=$A$1", true},276+ {"=A1+1", 1, "=$A$1+1", true},277+ {"=SUM(A1:B2)", 10, "=SUM($A$1:$B$2)", true},278+ {"=SUM(A1:B2)", 7, "=SUM($A$1:$B$2)", true},279+ {"=SUM($A$1..B2)", 12, "=SUM(A$1..B$2)", true},280+ {`="A1"`, 3, "", false},281+ {"=LOG10(2)", 6, "", false},282+ {"=1+2", 2, "", false},283+ }284+ for _, tt := range tests {285+ out, pos, ok := cycleRef([]rune(tt.in), tt.caret)286+ if ok != tt.ok || string(out) != tt.want {287+ t.Errorf("cycleRef(%q, %d) = %q, %v; want %q", tt.in, tt.caret, string(out), ok, tt.want)288+ }289+ if ok && pos > len(out) {290+ t.Errorf("caret %d past end of %q", pos, string(out))291+ }292+ }293+}294+295+func TestInsertDeleteKeysFollowSelection(t *testing.T) {296+ m := newModel()297+ press(t, m, "1", "<tab>", "2", "<enter>", "=A1+B1", "<enter>", "<ctrl+home>")298+ press(t, m, "<ctrl+alt+=>")299+ if input(m, "A3") != "=A2+B2" {300+ t.Errorf("Ctrl+Alt+= on a cell inserts a row: A3 %q", input(m, "A3"))301+ }302+ press(t, m, "<ctrl+alt+->")303+ press(t, m, "<ctrl+space>", "<ctrl+alt+=>")304+ if input(m, "B2") != "=B1+C1" {305+ t.Errorf("Ctrl+Alt+= on columns inserts a column: B2 %q", input(m, "B2"))306+ }307+ press(t, m, "<right>", "<right>", "<ctrl+space>", "<ctrl+alt+->")308+ if input(m, "B2") != "=B1+#REF!" {309+ t.Errorf("Ctrl+Alt+- on columns deletes them: B2 %q", input(m, "B2"))310+ }311+}
M internal/ui/entry.go +26 -9
@@ -1,7 +1,6 @@
11 package ui22 33 import (4- "errors"54 "slices"65 "strings"76 "unicode"
@@ -15,12 +14,12 @@ import (
1514 // Entry follows Google Sheets: typing replaces the cell (ENTER), Enter or1615 // F2 edits it in place (EDIT). Enter commits and moves down, Tab commits1716 // and moves right, Esc cancels. While typing a formula, arrow keys after an18-// operator point at cells (POINT) and insert their references.17+// operator point at cells (POINT) and insert their references. The18+// selection stays while typing, so Ctrl+Enter can fill it.1919 2020 func (m *Model) startEntry(md mode, text string) {2121 m.mode = md2222 m.buf, m.bufPos, m.hint = nil, 0, ""23- m.clearSelection()2423 m.insert(text)2524 }2625
@@ -50,6 +49,10 @@ func (m *Model) enterKey(k tea.KeyPressMsg) tea.Cmd {
5049 m.mode = modeEdit5150 return nil5251 }52+ if key == "f4" {53+ m.toggleAbsolute()54+ return nil55+ }5356 if m.isFormula() && m.canPoint() && m.startPoint(key) {5457 return nil5558 }
@@ -77,6 +80,8 @@ func (m *Model) editKey(k tea.KeyPressMsg) tea.Cmd {
7780 return nil7881 }7982 switch key {83+ case "f4":84+ m.toggleAbsolute()8085 case "up", "down", "pgup", "pgdown":8186 if m.commit() {8287 m.navigate(key, &m.cur)
@@ -95,6 +100,10 @@ func (m *Model) commitKey(key string) bool {
95100 default:96101 return false97102 }103+ if key == "ctrl+enter" && m.hasRange() {104+ m.fillEntry()105+ return true106+ }98107 if !m.commit() {99108 return true100109 }
@@ -191,6 +200,10 @@ func (m *Model) pointKey(k tea.KeyPressMsg) tea.Cmd {
191200 case "esc", "backspace":192201 m.resumeEntry("")193202 return nil203+ case "f4":204+ m.resumeEntry(m.point.text())205+ m.toggleAbsolute()206+ return nil194207 case "enter", "shift+enter", "tab", "shift+tab", "ctrl+enter":195208 m.resumeEntry(m.point.text())196209 m.commitKey(key)
@@ -220,15 +233,11 @@ func (m *Model) resumeEntry(ref string) {
220233 func (m *Model) commit() bool {221234 input := string(m.buf)222235 if err := m.set(m.cur, input); err != nil {223- var pe *sheet.ParseError224- m.mode = modeEdit225- m.hint = err.Error()226- if errors.As(err, &pe) {227- m.bufPos = utf8.RuneCountInString(input[:min(pe.Pos, len(input))])228- }236+ m.entryError(err, input)229237 return false230238 }231239 m.cancelEntry()240+ m.clearSelection()232241 return true233242 }234243
@@ -261,6 +270,9 @@ func (m *Model) insert(text string) {
261270 func (m *Model) handlePaste(content string) {262271 switch m.mode {263272 case modeReady:273+ if m.pasteText(content) {274+ return275+ }264276 if content = strings.TrimSpace(content); content != "" {265277 m.startEntry(modeEnter, content)266278 }
@@ -270,6 +282,11 @@ func (m *Model) handlePaste(content string) {
270282 if m.prompt.kind != promptRange {271283 m.promptType(content)272284 }285+ case modeMenu:286+ if o, ok := m.overlay.(textOverlay); ok {287+ m.insert(content)288+ o.changed(m)289+ }273290 }274291 }275292
M internal/ui/format_test.go +11 -8

Not shown: this page already shows 6000 lines of diff.

A internal/ui/help.go +295 -0

Not shown: this page already shows 6000 lines of diff.

A internal/ui/help_test.go +124 -0

Not shown: this page already shows 6000 lines of diff.

M internal/ui/menu.go +11 -148

Not shown: this page already shows 6000 lines of diff.

A internal/ui/menubar.go +535 -0

Not shown: this page already shows 6000 lines of diff.

M internal/ui/model.go +85 -25

Not shown: this page already shows 6000 lines of diff.

M internal/ui/model_test.go +42 -67

Not shown: this page already shows 6000 lines of diff.

A internal/ui/mouse.go +397 -0

Not shown: this page already shows 6000 lines of diff.

A internal/ui/mouse_test.go +147 -0

Not shown: this page already shows 6000 lines of diff.

A internal/ui/overlay.go +217 -0

Not shown: this page already shows 6000 lines of diff.

A internal/ui/palette.go +347 -0

Not shown: this page already shows 6000 lines of diff.

A internal/ui/palette_test.go +164 -0

Not shown: this page already shows 6000 lines of diff.

A internal/ui/panel.go +241 -0

Not shown: this page already shows 6000 lines of diff.

M internal/ui/selection.go +2 -122

Not shown: this page already shows 6000 lines of diff.

A internal/ui/shell_test.go +302 -0

Not shown: this page already shows 6000 lines of diff.

M internal/ui/theme.go +40 -9

Not shown: this page already shows 6000 lines of diff.

M internal/ui/view.go +25 -240

Not shown: this page already shows 6000 lines of diff.