- commit
- 48dd84cb9b781231067b55803ed2f5a880bb12c1
- parent
- aefc926f7f198a47c8f7728f82e99ea3661cdf22
- author
- Dami <dami.etoile@gmail.com>
- kind
- docs risk score 1.0 of 3, Jev's estimate
| M | docs/ | 1 | + |
| M | docs/ | 9 | ++- |
| M | docs/ | 39 | +++++++++++ |
| M | docs/ | 9 | ++- |
| M | docs/ | 3 | +- |
| M | docs/ | 1 | + |
| M | docs/ | 6 | +- |
| A | docs/ | 107 | ++++++++++++++++++++++++++++++ |
| M | internal/ | 23 | ++++--- |
| M | internal/ | 44 | +++++++----- |
| M | internal/ | 21 | ++++++ |
@@ -100,6 +100,7 @@ there.
100100 | Values an array spilled | Italic, and `Spilled from B2` on the context line |101101 | Linked files' rows, following, paused or failing | Italic; `●`, `‖` or `!` beside the tab's name and on the context line, with the state in words (`Following`, `Paused`, the error) |102102 | A notebook's cells and outputs | `❯` before the tab's name; the selected cell's head in reverse video; the head's words for its state (`[*]` and `running`, `waiting`, `failed`, `stale`); `×` before an error; an output table's header bold and underlined; an output sent to a sheet in italic, with `Output of files` on the context line |103+| A table's header row | Bold and underlined, when the table styles its header; `Table Sales, column Amount` on the context line |103104 | Pivot table results | Their headings (`SUM of Units`, `Grand Total`), and a note in words when an edit is refused |104105 | Protected ranges | A question in words before an edit (`A1:B2 is protected.`) |105106 | Notes | A `▝` in the cell's top-right corner |@@ -8,13 +8,20 @@ sidebar_position: 3
88 - After an operator or `(`, arrow keys (or a click) pick a cell and insert99 its reference; Shift+arrows (or a drag) pick a range. Keep typing to go on.1010 - While you type a name, suggestions drop down: named ranges first, then11- the other sheets, then functions with their arguments. Tab or Enter11+ [tables](../sheets/tables.md), the other sheets, then functions with12+ their arguments. Tab or Enter1213 inserts `NAME(`, or a sheet with its `!`, quoted when it needs to be1314 (`=Su` offers `Summary!`; `=Q3` or `='Q3` offers `'Q3 plan'!`). An arrow1415 after it points into that sheet, as clicking its tab does. Hidden1516 sheets aren't offered, though formulas still read them.1617 - Inside a function's parentheses the context line shows its signature with1718 the current argument marked, e.g. `SUMIF(range, criterion, [sum_range])`.19+- Inside a table's brackets, `=SUM(Sales[a`, suggestions offer its20+ columns (after `#`, the items `#All`, `#Data`, `#Headers`, `#This Row`;21+ after `@`, the columns again), and Tab or Enter inserts one with its22+ `]`. The context line lists the table's columns, the one being typed23+ marked: `Sales[Region, Units, Amount]`24+ ([Tables by column name](references.md#tables-by-column-name)).1825 - Alt+, and Alt+. trace precedents and dependents: the cells a formula reads1926 and the formulas that read a cell. Press again to step through them.2027 Cells on hidden sheets are skipped; when that leaves nothing, the@@ -16,6 +16,8 @@ sidebar_position: 2
1616 - Named ranges: `=SUM(Sales)`. Define them from Data > Named ranges or Data >1717 Define named range. Names are case-insensitive, follow the selection when1818 rows move, and renaming one rewrites the formulas that use it.19+- Tables by column name: `=SUM(Sales[Amount])`, `=Sales[@Amount]*2`;20+ see [Tables by column name](#tables-by-column-name).1921 - Other sheets: `=Sheet2!A1`, `=SUM('Q3 plan'!B2:B9)`; names with spaces or2022 punctuation, or that look like a cell, go in single quotes. While typing a2123 formula, Ctrl+PgDn or clicking a tab points into another sheet and inserts@@ -31,6 +33,43 @@ sidebar_position: 2
3133 ten cells, and `ROWS(A:A)` is still 1,048,576. See [Bounds of support](../contributing/limits.md)3234 for what that means in practice.3335 36+## Tables by column name37+38+A [table](../sheets/tables.md), or a notebook output sent to a sheet, is39+read by its columns' names with a structured reference: the table's40+name, then in brackets what to read of it.41+42+| Reference | Reads |43+|---|---|44+| `Sales[Amount]` | The Amount column's data rows, under the header |45+| `Sales` or `Sales[]` | Every data row, header left out |46+| `Sales[#All]` | The whole table, header row included |47+| `Sales[#Headers]`, `Sales[#Data]` | The header row; the data rows |48+| `Sales[@Amount]` | The Amount cell in the formula's own row (`Sales[[#This Row],[Amount]]`, as Excel's files write it); outside the table's rows, `#REF!` |49+| `Sales[[#Headers],[Amount]]` | The Amount column's header cell |50+| `Sales[[Units]:[Amount]]` | The columns from Units to Amount |51+| `Sales[[#Headers],[#Data],[Units]]` | The Units column, header and data |52+53+Names match in any case. A column whose name has characters other than54+letters, digits, `_` and spaces goes in brackets of its own,55+`Sales[[Total, EUR]]`, and `[`, `]`, `#` and `'` in a name take a `'`56+before them: `Sales['#Items]`. In a locale that separates arguments with57+`;`, so are the items: `Sales[[#Headers];[Amount]]`.58+59+A structured reference is kept as written and read when the formula60+computes, so it follows the table: rows added at its end, columns61+inserted or moved, the table moved or resized. Renaming the table or a62+column's header rewrites the formulas that read it; a deleted column, or63+a deleted table, reads as `#REF!`. Copying, pasting and filling keep64+structured references as they are, since they name columns rather than65+positions: filled down a table, `Sales[@Units]*Sales[@Amount]` reads66+each row's own cells.67+68+While typing, the table's name is offered with the named ranges, and69+after its `[` its columns, or after `#` the items; the context line lists70+the columns with the one being typed marked71+([Building formulas](building.md)).72+3473 ## A range where one value is wanted3574 3675 A range used where a formula wants one value (with an operator, or as@@ -168,8 +168,8 @@ sooner.
168168 169169 A cell that starts `name =` gives its output that name; `n` names a170170 cell for you. Later cells read the output as `$name`, a nushell171-variable holding the value, and formulas on any sheet as `nu.name` once172-it's [sent to a sheet](#send-to-a-sheet):171+variable holding the value, and formulas on any sheet as `nu.name`, or172+a column of it as `name[column]`, once it's [sent to a sheet](#send-to-a-sheet):173173 174174 ```nu175175 files = ls@@ -230,7 +230,10 @@ with the notebook) runs them again whenever a cell they read runs.
230230 the cell, or a cell of a sheet you pick. There it's a region named after231231 the cell, italic as a linked file's rows are, that formulas read as232232 `nu.name`, header row included (`=SUM(nu.big)`, `=VLOOKUP("go.mod",233-nu.files, 3, FALSE)`), and charts and pivot tables use. A cell without a233+nu.files, 3, FALSE)`), and charts and pivot tables use. It's also a234+[table](../sheets/tables.md#notebook-outputs-and-linked-files) by the235+cell's name, read by column: `=SUM(big[size])`, `=COUNTIF(app[status],236+500)`, with `big` alone its rows under the header. A cell without a234237 name is given one first.235238 236239 ```mermaid@@ -86,7 +86,7 @@ width, a name, a confirmation) needs `answer`: the text you'd type, a range
8686 for a range question, the key of a choice (`"enter"`, `"d"`) or its8787 label, or the item picked from a list (View > Hidden sheets takes the8888 sheet's name). A command that opens a dialog takes what you'd choose in89-it as a dict (see [Dialogs](#dialogs)). Other pickers (Named ranges) can't89+it as a dict (see [Dialogs](#dialogs)). Other pickers (Named ranges, Tables) can't9090 run in a script; nor can files, menus, help, undo or macros. The ids are9191 those in the recorded scripts; a few:9292 @@ -102,6 +102,7 @@ those in the recorded scripts; a few:
102102 | `column.width` (answer: the width), `column.reset` | Column widths |103103 | `data.sort_sheet_az`, `data.sort_range_az`, `data.sort_range_za`, `data.filter`, `data.filter_remove` | Sorting and filters |104104 | `data.define_name` (answer: the name) | Name the selection |105+| `table.create` (answer: the name), `table.rename` (answer: the name), `table.resize` (answer: the range), `table.banded`, `table.header`, `table.remove` | [Tables](../sheets/tables.md): make the selection one, or change the one the active cell is in |105106 | `format.conditional_add`, `data.validation_add` (answer: the rule as a line of the file, see [The .012 format](../files/format.md#conditional-formats-and-data-validation)), `insert.checkbox`, `format.conditional_clear`, `data.validation_clear`, `data.checkbox_toggle` | Conditional formats, data validation and checkboxes |106107 | `format.conditional_set`, `data.validation_set` (answer: `{"rule": 2, ...}`, the rule's number and its new line), `format.conditional_remove`, `data.validation_remove` (answer: the rule's number), `format.conditional_move` (answer: `{"rule": 2, "to": 1}`) | Change the rules of the sheet shown, numbered from 1 as the panel lists them |107108 | `sheet.new`, `sheet.duplicate`, `sheet.rename` (answer: the name), `sheet.delete` (answer: `"enter"` when it asks), `sheet.hide`, `sheet.unhide` (answer: the sheet's name) | Sheets |@@ -16,6 +16,7 @@ working with its data.
1616 | [Formatting](formatting.md) | Number formats, text styles, column and row formats, widths |1717 | [Sheets and tabs](sheets-and-tabs.md) | Several sheets: adding, moving, hiding |1818 | [Freeze, sort and filter](sort-filter.md) | Keeping headers on screen, sorting, filtering by values or conditions |19+| [Tables](tables.md) | Named ranges with a header row that formulas read by column name, and that grow with their rows |1920 | [Find and replace](find-replace.md) | Searching one sheet, all of them or a range |2021 | [Conditional formatting and data validation](rules.md) | Coloring cells by their values; dropdowns, checkboxes and entry rules |2122 | [Pivot tables](pivots.md) | Summaries of a table on a sheet of their own, and frequency tables |@@ -15,7 +15,8 @@ does.
1515 1616 Data > Sort sheet sorts by the active column A to Z or Z to A, keeping frozen1717 rows on top. Data > Sort range sorts the selection, or the block of data18-around the active cell; its advanced option opens a bar to sort by several18+around the active cell (in a [table](tables.md), the table, its header19+row kept in place); its advanced option opens a bar to sort by several1920 columns (Left/Right picks a column, Space flips the order, Alt+A adds a2021 column, Alt+H toggles the header row). The order follows Sheets: numbers,2122 then text ignoring case, then booleans, then errors, with blanks last.@@ -23,7 +24,8 @@ then text ignoring case, then booleans, then errors, with blanks last.
2324 ## Filter2425 2526 Data > Create a filter puts a filter on the selection or the table around26-the active cell; headers show `▾`. Alt+Down or a click on `▾` opens the27+the active cell (a [table](tables.md)'s range, which the filter then28+follows as the table grows); headers show `▾`. Alt+Down or a click on `▾` opens the2729 column's filter: check values in a list (Space checks one, typing2830 narrows the list), or pick a condition such as "greater than" or "text2931 contains". Filtered-out rows are hidden, not@@ -0,0 +1,107 @@
1+---2+title: "Tables"3+sidebar_position: 134+---5+6+# Tables7+8+A table is a named range whose first row names its columns, as in9+Sheets' and Excel's tables. Formulas read it by those names,10+`=SUM(Sales[Amount])`, so they keep reading the right cells as the table11+grows and its columns move ([Structured references](../formulas/references.md#tables-by-column-name)).12+13+## Making one14+15+Format > Convert to table (Ctrl+Alt+T) makes a table of the selection, or16+of the data around the active cell, and asks for its name on the context17+line (`Table1` to start). A name follows a named range's rules, letters,18+digits, `_` and `.`, except that `Table1` is fine: only names Excel reads19+as a cell are refused. Tables, named ranges and20+[notebook outputs](#notebook-outputs-and-linked-files) share one set of21+names, so a table can't take a name one of them has.22+23+The first row is the header row: each cell's text is its column's name.24+A blank header is named after its place (`Column3`) and a repeat25+numbered (`Amount2`), in the cell too, so the header shows what formulas26+use. A selection of one row gains an empty row of data below it.27+28+```29+ A B C30+ 1 Region Units Amount31+ 2 North 2 1032+ 3 South 3 2033+ 4 East 5 3034+```35+36+Made a table named `Sales`, this reads `Sales[Amount]` as C2:C4 and37+`Sales[#All]` as A1:C4; a value typed in row 5 joins it.38+39+On a table's cell the context line names the table and the column, and40+how a formula reads it: `Table Sales, column Amount: Sales[Amount] in41+formulas`.42+43+## Growing, resizing and removing44+45+A table grows by the rows typed or pasted just below it, in the same46+undo step as the entry, so Ctrl+Z takes the row back out. It grows by47+rows only: a column added at its right joins it through Data > Table >48+Resize table, which asks for the new range, pointed at from the49+table's own, header row first.50+51+Rows and columns inserted inside a table widen it, and deleting some52+narrows it; a column inserted comes in named from its (blank) header,53+`Column2`. Deleting a table's header row removes the table. Cutting the54+whole table and pasting it elsewhere, on this sheet or another, moves55+it.56+57+Changing a header renames the column in every formula that reads it:58+typing `Revenue` over `Amount` turns `Sales[Amount]` into59+`Sales[Revenue]`. Columns moved, inserted or deleted rename nothing;60+formulas reading a deleted column show `#REF!`.61+62+Data > Table > Rename table renames the table and every formula that63+reads it. Data > Table > Remove table makes it plain cells again: the64+cells stay, and formulas that read it read the same cells by address65+(`Sales[Amount]` becomes `$C$2:$C$4`, `Sales[@Amount]` the cell in the66+formula's own row, `$C3`). Data > Table > Tables lists every table and67+notebook output: Enter goes to one, F2 renames it and Ctrl+D removes it.68+69+## Banding and the header style70+71+Data > Table > Banded rows shades every other data row, and Header style72+draws the header row bold, underlined and in the theme's accent; a new73+table has both. They are the `TableBand` and `TableHeader` roles of the74+[theme](../terminal/themes.md): a scheme draws the band a shade off its75+background. The header's bold and underline read without color76+([UX](../contributing/ux.md#reading-without-color)); the band is77+decoration only.78+79+## Sorting and filtering a table80+81+Sorting or filtering with the active cell in a table takes the table's82+range, its header row kept in place: Data > Sort range sorts its rows by83+the active column, and Data > Create a filter puts the filter on it. A84+filter on a table's range follows the table as it grows or is resized.85+86+## Notebook outputs and linked files87+88+A notebook cell's output sent to a sheet, and a linked file, is a table89+by the region's name, with no table of its own to make: `app[status]`90+reads the `status` column of the output of the cell `app`, and `app`91+alone its rows under the header. `nu.app` stays what it was, the whole92+table header row included, the same cells as `app[#All]`. Its source93+names and shapes it, so the table commands leave it alone, and a table94+can't take its name ([Notebooks](../nushell/notebooks.md#send-to-a-sheet)).95+96+## Where 012 differs from Sheets and Excel97+98+- Copying, pasting and filling keep structured references as written:99+ they name columns, not positions. Excel shifts `[Amount]` to the next100+ column when a formula is filled right.101+- A table has no totals row and no calculated columns: a formula typed in102+ a table's column isn't filled down the column for you. An Excel table's103+ totals row comes in as cells below the table ([Excel files](../files/excel.md#tables-in-excel)).104+- A structured reference names its table, `Sales[@Amount]`, even inside105+ it; Excel's `[@Amount]` alone isn't read.106+- `[@Amount]` outside the table's data rows is `#REF!`, where Excel gives107+ `#VALUE!`.@@ -105,15 +105,7 @@ func Snap(s *sheet.Sheet, r sheet.Rect, name string) *Snapshot {
105105 CondFormats: s.CondFormats(), Validations: s.Validations()}106106 snap.FrozenRows, snap.FrozenCols = s.Frozen()107107 snap.Heights, snap.Merges = heightsMergesIn(s, r)108- for _, t := range s.Tables() {109- if whole {110- // A whole sheet's range holds its tables, blank rows and all.111- snap.Range.To.Col, snap.Range.To.Row = max(snap.Range.To.Col, t.Range.To.Col), max(snap.Range.To.Row, t.Range.To.Row)112- }113- if snap.Range.Contains(t.Range.From) && snap.Range.Contains(t.Range.To) {114- snap.Tables = append(snap.Tables, t)115- }116- }108+ snapTables(snap, s, whole)117109 for _, a := range s.NotesIn(notes) {118110 if snap.Notes == nil {119111 snap.Notes = map[sheet.Addr]string{}@@ -153,6 +145,19 @@ func Snap(s *sheet.Sheet, r sheet.Rect, name string) *Snapshot {
153145 return snap154146 }155147 148+// snapTables adds the sheet's tables in the snapshot's range to it; a149+// whole sheet's range grows to hold its tables, blank rows and all.150+func snapTables(snap *Snapshot, s *sheet.Sheet, whole bool) {151+ for _, t := range s.Tables() {152+ if whole {153+ snap.Range.To.Col, snap.Range.To.Row = max(snap.Range.To.Col, t.Range.To.Col), max(snap.Range.To.Row, t.Range.To.Row)154+ }155+ if snap.Range.Contains(t.Range.From) && snap.Range.Contains(t.Range.To) {156+ snap.Tables = append(snap.Tables, t)157+ }158+ }159+}160+156161 // heightsMergesIn are the heights of the rows of r and the merges inside157162 // it.158163 func heightsMergesIn(s *sheet.Sheet, r sheet.Rect) (map[int]int, []sheet.Rect) {@@ -107,24 +107,7 @@ func (s *Sheet) shiftView(rows bool, sp formula.Span) {
107107 }108108 *frozen = min(*frozen, MaxFrozen)109109 }110- if f := v.filter; f != nil {111- _, rng := formula.AxisMaps(rows, sp)112- if r, ok := rng(f.Range); ok {113- nf := &Filter{Range: r, Cols: map[int]Criteria{}}114- for c, cr := range f.Cols {115- if !rows {116- var keep bool117- if c, keep = sp.Point(c); !keep || c < r.From.Col || c > r.To.Col {118- continue119- }120- }121- nf.Cols[c] = cr122- }123- v.filter = nf124- } else {125- v.filter = nil126- }127- }110+ v.filter = shiftFilter(v.filter, rows, sp)128111 if !v.equal(s.view) {129112 s.recordView()130113 if w := s.wb; w.hist.open != nil {@@ -134,6 +117,31 @@ func (s *Sheet) shiftView(rows bool, sp formula.Span) {
134117 }135118 }136119 120+// shiftFilter is f once rows or columns are inserted or deleted: its121+// range moved like a range reference, with its columns' criteria, or nil122+// when all of it is deleted.123+func shiftFilter(f *Filter, rows bool, sp formula.Span) *Filter {124+ if f == nil {125+ return nil126+ }127+ _, rng := formula.AxisMaps(rows, sp)128+ r, ok := rng(f.Range)129+ if !ok {130+ return nil131+ }132+ nf := &Filter{Range: r, Cols: map[int]Criteria{}}133+ for c, cr := range f.Cols {134+ if !rows {135+ var keep bool136+ if c, keep = sp.Point(c); !keep || c < r.From.Col || c > r.To.Col {137+ continue138+ }139+ }140+ nf.Cols[c] = cr141+ }142+ return nf143+}144+137145 // fileView is the view state in the file (version 3), e.g.138146 //139147 // "freeze": {"rows": 1},@@ -171,6 +171,27 @@ func TestTableSuggestions(t *testing.T) {
171171 wantShown(t, m, "D2", "2")172172 }173173 174+// Scripts answer the table commands' questions, as a recording writes175+// them.176+func TestTableCommandsInScripts(t *testing.T) {177+ m := unitsModel(t)178+ script(t, m, `179+select("A1:C4")180+run("table.create", answer="Sales")181+select("B2")182+run("table.rename", answer="Revenue")183+run("table.resize", answer="A1:B4")184+run("table.banded")185+`)186+ if m.warn != "" {187+ t.Fatal(m.warn)188+ }189+ tb, ok := m.sheet.TableAt(addr("A2"))190+ if !ok || tb.Name != "Revenue" || tb.Range != rectOf("A1:B4") || tb.Banded {191+ t.Errorf("table %+v", tb)192+ }193+}194+174195 // wantShown checks the value the cell at a shows.175196 func wantShown(t *testing.T, m *Model, a, want string) {176197 t.Helper()