A layout tape opens a trip plan and gives it a merged title, borders (a thick outline, a double line under the headers) and wrapped notes from the palette; formatting.md and the README show it, the README beside the locale still. The architecture describes the engine's layout and the grid's bands, ux.md how the layout reads without color, and the roadmap lists it as shipped. Keystroke stress cases for the laid-out shape.
- commit
- 7867877752abf7090e8040089877a694219ff3be
- parent
- 2def060eab32372cf7300c568f0cb9bb539ff7cb
- author
- Dami <dami.etoile@gmail.com>
- kind
- docs risk score 0.3 of 3, Jev's estimate
| M | README.md | 6 | +++- |
| M | ROADMAP.md | 2 | +- |
| A | demos/ | 21 | +++++++++++ |
| A | demos/ | 59 | ++++++++++++++++++++++++++++++ |
| M | docs/ | 21 | +++++++++-- |
| M | docs/ | 1 | + |
| A | docs/ | bin | |
| M | docs/ | 2 | + |
| M | internal/ | 3 | ++ |
@@ -32,7 +32,9 @@ rest: building from a clone, importing files, `012 serve` and settings.
3232 ([formulas](docs/formulas/README.md)).3333 - **Data tools**: freeze, sort, filter, find and replace, conditional3434 formatting, dropdowns and checkboxes, notes, protected ranges, and live35- pivot tables ([working with data](docs/sheets/README.md)).35+ pivot tables ([working with data](docs/sheets/README.md)); wrapped36+ text, borders and merged cells drawn with the terminal's box-drawing37+ lines ([formatting](docs/sheets/formatting.md#wrapping)).3638 - **Charts** that float over the grid and follow their data, drawn as real3739 images in kitty, Ghostty and WezTerm and as text elsewhere3840 ([charts](docs/sheets/charts.md)).@@ -60,6 +62,8 @@ rest: building from a clone, importing files, `012 serve` and settings.
6062 | JEV functions in formulas | Formats detected as you type |6163 |  |  |6264 | Arrays that spill | Macros |65+|  |  |66+| Wrapped text, borders and merged cells | A locale per file |6367 6468 The recordings are [VHS](https://github.com/charmbracelet/vhs) tapes in6569 [`demos/`](demos), rendered by `make demos` in the Catppuccin Mocha@@ -26,7 +26,6 @@ Sizes: S (a day or two), M (about a week), L (weeks).
2626 2727 | Item | Notes | Size |2828 |---|---|---|29-| Wrap text, row heights, borders, merged cells | Layout changes in the grid renderer | M to L |3029 | Locale, what's left: month and day names in the locale's language (`mmm`, `dddd`), Excel downloads with the locale's Currency and Date formats | The rest follows the locale: [Locale](docs/sheets/locale.md) | S |3130 3231 ### 3. Scale@@ -73,6 +72,7 @@ by a gateway dialing the iroh ticket.
7372 - Undo and redo for every change, across sheets: [Editing](docs/sheets/editing.md#undo)7473 - Copy, cut, paste and fill with relative and `$absolute` references; insert and delete rows and columns: [Editing](docs/sheets/editing.md#copy-paste-and-fill)7574 - Entries detected as typed (currency, percent, dates, times) and number formats: [Formulas](docs/formulas/README.md#what-you-type)75+- Wrapped and clipped text, row heights, borders and merged cells, in `.012` files and XLSX both ways: [Formatting](docs/sheets/formatting.md#wrapping)7676 - Named ranges; several sheets with references between them, hidden sheets: [References](docs/formulas/references.md)7777 - Sheets' everyday, math, text, lookup, date and finance functions, checked against excelize: [Functions](docs/reference/functions.md), [Testing](docs/contributing/testing.md#the-excelize-oracle)7878 - Dynamic arrays that spill (FILTER, SORT, UNIQUE, SEQUENCE and more, ARRAYFORMULA), LET and LAMBDA, SPLIT and the REGEX functions: [Arrays and spills](docs/formulas/arrays.md)@@ -0,0 +1,21 @@
1+{2+ "version": 2,3+ "widths": {"C": 16},4+ "cells": {5+ "A1": "Trip to Lisbon",6+ "A2": "Day",7+ "B2": "Cost",8+ "C2": "Notes",9+ "A3": "Fri",10+ "B3": "120",11+ "C3": "Train, book the early fare",12+ "A4": "Sat",13+ "B4": "45",14+ "C4": "Tram 28 and the castle, before the crowds",15+ "A5": "Sun",16+ "B5": "60",17+ "C5": "Fly home",18+ "A6": "Total",19+ "B6": "=SUM(B3:B5)"20+ }21+}@@ -0,0 +1,59 @@
1+# Layout: a trip plan gets a title merged across it, borders (a thick2+# outline and a double line under the headers), and notes that wrap,3+# their rows growing to fit, all from the command palette. Go to4+# (Ctrl+G) selects the ranges.5+Output out/layout.gif6+Source lib/setup.tape7+8+Hide9+Type "../bin/012 data/trip.012" Enter10+Sleep 1.5s11+Show12+13+Sleep 800ms14+Ctrl+G15+Type "A1:C1" Enter16+Ctrl+K17+Type "merge all"18+Sleep 300ms19+Enter20+Sleep 800ms21+Ctrl+G22+Type "A2:C6" Enter23+Ctrl+K24+Type "all borders"25+Sleep 300ms26+Enter27+Sleep 800ms28+Ctrl+K29+Type "thick lines"30+Sleep 300ms31+Enter32+Ctrl+K33+Type "outer borders"34+Sleep 300ms35+Enter36+Sleep 800ms37+Ctrl+G38+Type "A2:C2" Enter39+Ctrl+K40+Type "double lines"41+Sleep 300ms42+Enter43+Ctrl+K44+Type "bottom border"45+Sleep 300ms46+Enter47+Sleep 800ms48+Ctrl+G49+Type "C3:C5" Enter50+Ctrl+K51+Type "wrap"52+Sleep 300ms53+Enter54+Sleep 800ms55+Ctrl+G56+Type "C4" Enter57+Sleep 2s58+Screenshot out/stills/layout-trip.png59+Sleep 1s@@ -130,6 +130,15 @@ style.
130130 changing recalculates the formulas reading any cell of it, found through131131 the dependency indexes (`linereaders.go`), so they infer their format132132 from blank cells too.133+- **Layout.** A cell's style holds how its text wraps and the lines on134+ its edges (`borders.go`), so both fall back on lines and travel with135+ copies. Rows' heights set by hand are kept per sheet as column widths136+ are, and merged ranges in the view state, replaced whole, so undo, the137+ file and inserted lines follow them (`rowlayout.go`, `merge.go`, which138+ finds a cell's merge through an interval index). Cells whose own style139+ wraps or draws borders are indexed by row, so the grid measures the140+ rows it shows at their cost, and a sheet with none of these (not141+ `Shaped`) is drawn a line per row without asking.133142 - **Parsing.** `internal/formula`'s hand-written Pratt parser turns134143 formulas into an AST, keeping absolute markers so references can be135144 rewritten when cells move. Its printer turns ASTs back into text in@@ -342,7 +351,7 @@ draw. The components:
342351 343352 | Component | Type | Owns |344353 |---|---|---|345-| grid (embedded) | `grid` | the sheet shown, active cell, scroll, window size, selection; mapping rows and columns to the screen, frozen panes, moving and selecting (`grid.go`, `panes.go`, `selection.go`) |354+| grid (embedded) | `grid` | the sheet shown, active cell, scroll, window size, selection; mapping rows and columns to the screen (rows as bands of lines, `bands.go`), frozen panes, moving and selecting (`grid.go`, `panes.go`, `selection.go`) |346355 | edit line | `lineedit.Line` | the one-line editor shared by cell entries, prompts and search fields (package `lineedit`) |347356 | cell entry | `entry`, `assist` | typing into a cell, pointing at references, other sheets while pointing, formula suggestions and signatures (`entry.go`, `assist.go`) |348357 | prompt | `prompt` | a question on the context line, typed or pointed at (`prompt.go`) |@@ -393,8 +402,14 @@ goes through `runCommand`, so macros record them and pivots guard them.
393402 the grid rows and the status line, then composites the floating layers394403 with Lip Gloss: charts over the grid, then the open overlay's boxes or the395404 formula suggestions, so the grid never shifts under them. Only the visible396-cells are rendered; `rowtext` lays out each row's text in one pass over397-the cells that can reach the screen. Styles come from `theme`, a small set405+cells are rendered; `rowtext` lays out each line of a row's text in one406+pass over the cells that can reach the screen. A row is a band of lines407+(`bands.go`): a rule line when a border lies along its top, then as many408+lines as its height or the text it wraps takes (`rowtext.Shapes`, kept409+until the sheet changes); navigation, the mouse and charts map rows to410+lines through the bands. Borders, merged cells and the rule lines are411+drawn over the laid-out text (`gridlines.go`), with what a frame has412+drawn in each role kept for the rest of it. Styles come from `theme`, a small set398413 of roles with dark and light variants on the terminal's 16 ANSI colors,399414 so the user's palette applies; its widgets (framed boxes, key chips, key400415 hints) are what every overlay is drawn with.@@ -100,6 +100,7 @@ there.
100100 | Search matches, traced cells | Reverse video, with a count or the list on the context line |101101 | The copied range | A dashed underline |102102 | Dropdowns, checkboxes, active filters | `▾`; `[ ]` and `[✓]`; `▼` instead of `▾` |103+| Borders, wrapped text, merged cells, tall rows | Characters: box-drawing lines, the text's own lines, one value across the merge, the row's number on its last line; the pointer on a merged cell reverses all of it |103104 104105 The reverse-video roles (`Theme.standouts`) keep their look in color:105106 their colors are stored swapped, so SGR 7 swaps them back. ConditionalBinary file.
@@ -45,6 +45,8 @@ number formats and text styles and keeps the contents.
4545 4646 ## Wrapping4747 48+49+4850 Format > Wrapping says what text wider than its column does, as in4951 Sheets:5052 @@ -192,6 +192,9 @@ func BenchmarkKeystroke(b *testing.B) {
192192 nil, []string{"7", "enter", "up"}},193193 {"type/dense-8192x26", uiShapes()[1], nil, []string{"7", "enter", "up"}},194194 {"arrow/scale-8192x26", uiShapes()[7], nil, []string{"down", "up"}},195+ {"arrow/laidout-8192x26", uiShapes()[8], nil, []string{"down", "up"}},196+ {"pgdown/laidout-8192x26", uiShapes()[8], nil, []string{"pgdown", "pgup"}},197+ {"type/laidout-8192x26", uiShapes()[8], nil, []string{"7", "enter", "up"}},195198 {"type/scale-8192x26", uiShapes()[7], nil, []string{"7", "enter", "up"}},196199 {"jump/sparse-1M", uiShapes()[6], nil, []string{"ctrl+down", "ctrl+down", "ctrl+up", "ctrl+up"}},197200 {"select-sheet/sparse-1M", uiShapes()[6], []string{"ctrl+a", "ctrl+a"}, nil},