The editor and its field picker act on the model through pivotHost: the pivot's sheet and workbook, the modified flag, and the pickers, filter values list and range prompt it opens, whose callbacks no longer hand it the model. It stays in package ui, needing fourteen methods.
- commit
- 829df5d7e91ef0fe26d48fc5b73e7b0ff5c4a632
- parent
- 897a8144249f569631a4845ee0c2f04bdb59095b
- author
- Dami <dami.etoile@gmail.com>
| M | internal/ | 2 | +- |
| M | internal/ | 2 | +- |
| M | internal/ | 23 | +++++++- |
| M | internal/ | 2 | +- |
| M | internal/ | 2 | +- |
| M | internal/ | 2 | +- |
| M | internal/ | 2 | +- |
| M | internal/ | 2 | +- |
| M | internal/ | 61 | +++++++++---------- |
| M | internal/ | 99 | +++++++++++++++++++----------- |
| M | internal/ | 2 | +- |
| M | internal/ | 4 | +- |
@@ -23,7 +23,7 @@ func init() {
2323 return nil2424 }},2525 &command{id: "help.functions", macro: macroNever, title: "Function list", desc: "Search the functions formulas can use", run: func(m *Model) tea.Cmd {26- p := newPicker(m, "Functions", "Type a function name, e.g. sum or if", 100, functionItems(m))26+ p := m.newPicker("Functions", "Type a function name, e.g. sum or if", 100, functionItems(m))2727 p.Action = "insert"2828 m.openOverlay(p)2929 return nil@@ -34,6 +34,27 @@ var (
3434 func (m *Model) styles() *theme.Theme { return &m.th }3535 func (m *Model) size() (width, height int) { return m.width, m.height }3636 func (m *Model) available(id string) bool { return commands[id].available(m) }37+func (m *Model) sheetShown() *sheet.Sheet { return m.sheet }38+39+// syncChanged makes the modified flag follow the undo history.40+func (m *Model) syncChanged() { m.changed = m.sheet.StateID() != m.saved }41+42+// pickValues opens a filter's values list titled title at screen column43+// x; apply gets the criteria chosen, and cancel runs after Esc.44+func (m *Model) pickValues(title string, x int, values []sheet.FilterValue, cond sheet.Condition, apply func(sheet.Criteria), cancel func()) {45+ fp := m.openValuesPicker(title, x, values, cond, func(_ *Model, cr sheet.Criteria) { apply(cr) })46+ fp.onCancel = func(*Model) { cancel() }47+}48+49+// pointRange asks for a range on the context line; done gets it, and50+// cancel runs after Esc.51+func (m *Model) pointRange(label string, done func(sheet.Rect), cancel func()) {52+ m.openRange(label, func(_ *Model, r sheet.Rect) tea.Cmd {53+ done(r)54+ return nil55+ })56+ m.prompt.onCancel = func(*Model) { cancel() }57+}3758 3859 // What every component with a text field needs.3960 @@ -47,7 +68,7 @@ func (h host) Close() { h.m.closeOverlay() }
4768 func (h host) RecordAnswer(answer string, cancelled bool) { h.m.recordAnswer(answer, cancelled) }4869 4970 // newPicker returns a picker of items over the model; the caller opens it.50-func newPicker(m *Model, title, placeholder string, maxW int, items []picker.Item) *picker.Picker {71+func (m *Model) newPicker(title, placeholder string, maxW int, items []picker.Item) *picker.Picker {5172 return picker.New(m.host(), title, placeholder, maxW, items)5273 }5374 @@ -63,7 +63,7 @@ func (m *Model) askImportPlace(name string) tea.Cmd {
6363 }6464 items = append(items, item("Replace spreadsheet", detail, "Open "+base+" instead, as File > Open does",6565 func(m *Model) tea.Cmd { return m.confirmImport(name, fileio.Options{}) }))66- p := newPicker(m, "Import "+base, "Import location", 60, items)66+ p := m.newPicker("Import "+base, "Import location", 60, items)6767 p.Action = "import"6868 m.openOverlay(p)6969 return nil@@ -51,7 +51,7 @@ func init() {
5151 enabled: func(m *Model) bool { return idle(m) && len(m.book().Macros()) > 0 },5252 desc: "Pick a saved macro and run it",5353 run: func(m *Model) tea.Cmd {54- p := newPicker(m, "Run macro", "Type a macro's name", 60, macroRunItems(m))54+ p := m.newPicker("Run macro", "Type a macro's name", 60, macroRunItems(m))5555 m.openOverlay(p)5656 return nil5757 }},@@ -33,7 +33,7 @@ const writeMacroTitle = "+ Write a macro"
3333 3434 // openMacros opens the manager with the macro named sel highlighted.3535 func (m *Model) openMacros(sel string) {36- p := newPicker(m, "Macros", "Type a macro's name", 72, macroManageItems(m))36+ p := m.newPicker("Macros", "Type a macro's name", 72, macroManageItems(m))3737 p.Action = "run"3838 for i, pm := range p.Shown() {3939 if strings.EqualFold(pm.Item.Title, sel) {@@ -38,7 +38,7 @@ type namesPicker struct {
3838 3939 // openNames opens the picker; sel is what "Add a range" names.4040 func (m *Model) openNames(sel sheet.Rect) {41- p := newPicker(m, "Named ranges", "Type a name", 60, namesItems(m, sel))41+ p := m.newPicker("Named ranges", "Type a name", 60, namesItems(m, sel))4242 p.Action = "go to"4343 m.clearSelection()4444 m.openOverlay(&namesPicker{m: m, Picker: p, sel: sel})@@ -14,7 +14,7 @@ import (
1414 1515 func init() {1616 register(&command{id: "palette", macro: macroNever, title: "Search the menus", desc: "Find and run any command by name", run: func(m *Model) tea.Cmd {17- m.openOverlay(newPicker(m, "Search the menus", "Type a command, e.g. save or width", 76, paletteItems(m)))17+ m.openOverlay(m.newPicker("Search the menus", "Type a command, e.g. save or width", 76, paletteItems(m)))1818 return nil1919 }})2020 for _, k := range []string{"alt+/", "ctrl+k", "ctrl+shift+p"} {@@ -14,7 +14,7 @@ import (
1414 // What the pivot editor's keys do to the pivot, and how its fields read.1515 1616 // fieldName is the source field a field line is about.17-func (e *pivotEditor) fieldName(m *Model, p sheet.Pivot, it pivotItem) string {17+func (e *pivotEditor) fieldName(m pivotHost, p sheet.Pivot, it pivotItem) string {1818 return m.book().FieldName(p, fieldCol(p, it))1919 }2020 @@ -40,10 +40,10 @@ func groups(p *sheet.Pivot, sect int) *[]sheet.PivotGroup {
4040 4141 // fieldDetail is the right side of a field line: a group's order, a4242 // value's summary as a chip to change, a filter's criteria.43-func (e *pivotEditor) fieldDetail(m *Model, p sheet.Pivot, it pivotItem, sel bool) string {44- dim, chip := m.th.Muted, m.th.KeyChip43+func (e *pivotEditor) fieldDetail(m pivotHost, p sheet.Pivot, it pivotItem, sel bool) string {44+ dim, chip := m.styles().Muted, m.styles().KeyChip4545 if sel {46- dim, chip = m.th.MenuSelected, m.th.MenuSelected46+ dim, chip = m.styles().MenuSelected, m.styles().MenuSelected4747 }4848 switch it.sect {4949 case sectValues:@@ -61,7 +61,7 @@ func (e *pivotEditor) fieldDetail(m *Model, p sheet.Pivot, it pivotItem, sel boo
6161 }6262 6363 // orderText says how a group is ordered: A→Z, or by a value's total.64-func orderText(m *Model, p sheet.Pivot, g sheet.PivotGroup) string {64+func orderText(m pivotHost, p sheet.Pivot, g sheet.PivotGroup) string {6565 if i := g.SortBy - 1; i >= 0 && i < len(p.Values) {6666 arrow := "↑"6767 if g.Desc {@@ -86,7 +86,7 @@ func criteriaText(cr sheet.Criteria) string {
8686 }8787 8888 // act does what Space does on a line.89-func (e *pivotEditor) act(m *Model, it pivotItem) tea.Cmd {89+func (e *pivotEditor) act(m pivotHost, it pivotItem) tea.Cmd {9090 switch {9191 case it.kind == itemSource:9292 e.editSource(m)@@ -110,7 +110,7 @@ func (e *pivotEditor) act(m *Model, it pivotItem) tea.Cmd {
110110 111111 // adjust steps a field's setting d places: a group's order (A→Z, Z→A,112112 // then by each value, smallest and largest first), or a value's summary.113-func (e *pivotEditor) adjust(m *Model, it pivotItem, d int) {113+func (e *pivotEditor) adjust(m pivotHost, it pivotItem, d int) {114114 switch {115115 case it.kind == itemToggle:116116 e.act(m, it)@@ -145,7 +145,7 @@ func boolInt(b bool) int {
145145 }146146 147147 // cycleShowAs steps a value through Sheets' "Show as" choices.148-func (e *pivotEditor) cycleShowAs(m *Model, it pivotItem) {148+func (e *pivotEditor) cycleShowAs(m pivotHost, it pivotItem) {149149 if it.kind != itemField || it.sect != sectValues {150150 return151151 }@@ -158,7 +158,7 @@ func (e *pivotEditor) cycleShowAs(m *Model, it pivotItem) {
158158 }159159 160160 // remove takes a field out of its section.161-func (e *pivotEditor) remove(m *Model, it pivotItem) {161+func (e *pivotEditor) remove(m pivotHost, it pivotItem) {162162 if it.kind != itemField {163163 return164164 }@@ -188,7 +188,7 @@ func (e *pivotEditor) remove(m *Model, it pivotItem) {
188188 189189 // reorder moves a row or column field up or down within its section,190190 // which nests the groups differently.191-func (e *pivotEditor) reorder(m *Model, it pivotItem, down bool) {191+func (e *pivotEditor) reorder(m pivotHost, it pivotItem, down bool) {192192 if it.kind != itemField || it.sect == sectFilters {193193 return194194 }@@ -212,7 +212,7 @@ func (e *pivotEditor) reorder(m *Model, it pivotItem, down bool) {
212212 }213213 214214 // addField picks a field of the source to add to a section.215-func (e *pivotEditor) addField(m *Model, sect int) {215+func (e *pivotEditor) addField(m pivotHost, sect int) {216216 p := e.pivot(m)217217 used := map[int]bool{}218218 switch sect {@@ -234,18 +234,18 @@ func (e *pivotEditor) addField(m *Model, sect int) {
234234 Pick: func() tea.Cmd {235235 m.closeOverlay()236236 e.add(m, sect, col)237- e.reopen(m)237+ e.reopen()238238 return nil239239 },240240 })241241 }242- fp := newPicker(m, "Add to "+sectNames[sect], "Type a field name", 50, items)242+ fp := m.newPicker("Add to "+sectNames[sect], "Type a field name", 50, items)243243 fp.Action = "add"244244 m.openOverlay(&fieldPicker{m: m, Picker: fp, back: e})245245 }246246 247247 // add puts the field in column col at the end of a section.248-func (e *pivotEditor) add(m *Model, sect, col int) {248+func (e *pivotEditor) add(m pivotHost, sect, col int) {249249 name := m.book().FieldName(e.pivot(m), col)250250 e.set(m, "add "+name+" to "+sectNames[sect], func(p *sheet.Pivot) {251251 switch sect {@@ -263,7 +263,7 @@ func (e *pivotEditor) add(m *Model, sect, col int) {
263263 264264 // fieldPicker is the picker of fields to add; Esc returns to the editor.265265 type fieldPicker struct {266- m *Model // the model it acts on266+ m pivotHost // the model, through what the editor needs of it267267 *picker.Picker268268 back *pivotEditor269269 }@@ -272,7 +272,7 @@ func (f *fieldPicker) Key(k tea.KeyPressMsg) tea.Cmd {
272272 m := f.m273273 if k.String() == "esc" {274274 m.closeOverlay()275- f.back.reopen(m)275+ f.back.reopen()276276 return nil277277 }278278 return f.Picker.Key(k)@@ -282,7 +282,7 @@ func (f *fieldPicker) Mouse(e overlay.MouseEvent) tea.Cmd {
282282 m := f.m283283 if e.Box != picker.ID && e.Kind == overlay.MousePress {284284 m.closeOverlay()285- f.back.reopen(m)285+ f.back.reopen()286286 return nil287287 }288288 return f.Picker.Mouse(e)@@ -290,24 +290,23 @@ func (f *fieldPicker) Mouse(e overlay.MouseEvent) tea.Cmd {
290290 291291 // editFilter opens the values list of filter i, in the manner of a292292 // filter's column.293-func (e *pivotEditor) editFilter(m *Model, i int) {293+func (e *pivotEditor) editFilter(m pivotHost, i int) {294294 p := e.pivot(m)295295 f := p.Filters[i]296296 name := m.book().FieldName(p, f.Col)297297 x, _, _ := e.box(m)298- fp := m.openValuesPicker("Filter "+name, x, m.book().PivotFilterValues(p, f.Col), f.Criteria.Cond,299- func(m *Model, cr sheet.Criteria) {298+ m.pickValues("Filter "+name, x, m.book().PivotFilterValues(p, f.Col), f.Criteria.Cond,299+ func(cr sheet.Criteria) {300300 e.set(m, "filter "+name, func(p *sheet.Pivot) { p.Filters[i].Criteria = cr })301- e.reopen(m)302- })303- fp.onCancel = e.reopen301+ e.reopen()302+ }, e.reopen)304303 }305304 306305 // editSource points at the data on its sheet, starting from the current307306 // range; fields outside the new range are dropped.308-func (e *pivotEditor) editSource(m *Model) {307+func (e *pivotEditor) editSource(m pivotHost) {309308 p := e.pivot(m)310- src, home := m.book().Lookup(p.Source), m.sheet309+ src, home := m.book().Lookup(p.Source), m.sheetShown()311310 if src == nil || src == home {312311 e.msg = "The source sheet " + p.Source + " doesn't exist"313312 return@@ -321,13 +320,13 @@ func (e *pivotEditor) editSource(m *Model) {
321320 if !p.Lost {322321 m.selectRect(p.Range)323322 }324- back := func(m *Model) {323+ back := func() {325324 m.clearSelection()326325 m.showSheet(home)327- e.reopen(m)326+ e.reopen()328327 }329- m.openRange("Pivot data:", func(m *Model, r sheet.Rect) tea.Cmd {330- back(m)328+ m.pointRange("Pivot data:", func(r sheet.Rect) {329+ back()331330 e.set(m, "change the pivot's data to "+r.String(), func(p *sheet.Pivot) {332331 p.Source, p.Range, p.Lost = src.Name(), r, false333332 in := func(c int) bool { return c >= r.From.Col && c <= r.To.Col }@@ -337,7 +336,5 @@ func (e *pivotEditor) editSource(m *Model) {
337336 p.Values = slices.DeleteFunc(p.Values, func(v sheet.PivotValue) bool { return !in(v.Col) })338337 p.Filters = slices.DeleteFunc(p.Filters, func(f sheet.PivotFilter) bool { return !in(f.Col) })339338 })340- return nil341- })342- m.prompt.onCancel = back339+ }, back)343340 }@@ -9,6 +9,7 @@ import (
99 1010 "github.com/FelineStateMachine/012/internal/sheet"1111 "github.com/FelineStateMachine/012/internal/ui/overlay"12+ "github.com/FelineStateMachine/012/internal/ui/picker"1213 "github.com/FelineStateMachine/012/internal/ui/theme"1314 )1415 @@ -22,13 +23,38 @@ import (
2223 // it. Enter keeps the changes; Esc undoes them, removing a pivot just2324 // created.2425 type pivotEditor struct {25- m *Model // the model it acts on26+ m pivotHost // the model, through what the editor needs of it2627 start int // the workbook's state before editing, to undo back to2728 back *sheet.Sheet // for a new pivot, the sheet it summarizes, shown again on Esc2829 msg string // why the last change was refused, for the status line2930 overlay.List3031 }3132 33+// pivotHost is what the pivot editor acts on. The model implements it.34+// The editor stays in package ui: besides the pivot on the sheet shown,35+// it opens the model's pickers, filter values list and range prompt and36+// comes back from them, which takes more than a small interface.37+type pivotHost interface {38+ styles() *theme.Theme39+ size() (width, height int)40+ book() *sheet.Workbook41+ // sheetShown is the sheet the pivot is on while it's edited.42+ sheetShown() *sheet.Sheet43+ // syncChanged makes the modified flag follow the undo history.44+ syncChanged()45+ openOverlay(o overlay.Overlay)46+ closeOverlay()47+ afterSheetsChange(prefer *sheet.Sheet, index int)48+ showSheet(s *sheet.Sheet)49+ selectRect(r sheet.Rect)50+ clearSelection()51+ newPicker(title, placeholder string, maxW int, items []picker.Item) *picker.Picker52+ // pickValues opens a filter's values list at screen column x.53+ pickValues(title string, x int, values []sheet.FilterValue, cond sheet.Condition, apply func(sheet.Criteria), cancel func())54+ // pointRange asks for a range, pointed at or typed.55+ pointRange(label string, done func(sheet.Rect), cancel func())56+}57+3258 // Sections of the editor, in order.3359 const (3460 sectRows = iota@@ -78,16 +104,16 @@ func (m *Model) openPivotEditor(start int, back *sheet.Sheet) {
78104 79105 func (e *pivotEditor) Indicator() string { return "PIVOT" }80106 81-func (e *pivotEditor) pivot(m *Model) sheet.Pivot {82- p, _ := m.sheet.Pivot()107+func (e *pivotEditor) pivot(m pivotHost) sheet.Pivot {108+ p, _ := m.sheetShown().Pivot()83109 return p84110 }85111 86112 // items lists the editor's lines for the pivot as it is now.87-func (e *pivotEditor) items(m *Model) []pivotItem {113+func (e *pivotEditor) items(m pivotHost) []pivotItem {88114 p := e.pivot(m)89115 items := []pivotItem{{kind: itemSource}}90- if m.sheet.PivotError() != "" {116+ if m.sheetShown().PivotError() != "" {91117 items = append(items, pivotItem{kind: itemError})92118 }93119 items = append(items, pivotItem{kind: itemSep})@@ -117,7 +143,7 @@ func (e *pivotEditor) step(items []pivotItem, d int) {
117143 }118144 119145 // current is the highlighted line, kept on a selectable one.120-func (e *pivotEditor) current(m *Model) pivotItem {146+func (e *pivotEditor) current(m pivotHost) pivotItem {121147 items := e.items(m)122148 e.Sel = clamp(e.Sel, 0, len(items)-1)123149 if !selectable(items[e.Sel]) {@@ -127,7 +153,7 @@ func (e *pivotEditor) current(m *Model) pivotItem {
127153 }128154 129155 // selectItem highlights the line showing it, if any.130-func (e *pivotEditor) selectItem(m *Model, it pivotItem) {156+func (e *pivotEditor) selectItem(m pivotHost, it pivotItem) {131157 for i, x := range e.items(m) {132158 if x == it {133159 e.Sel = i@@ -136,19 +162,19 @@ func (e *pivotEditor) selectItem(m *Model, it pivotItem) {
136162 }137163 138164 // set applies a change to the pivot as its own undo step.139-func (e *pivotEditor) set(m *Model, label string, fn func(p *sheet.Pivot)) {165+func (e *pivotEditor) set(m pivotHost, label string, fn func(p *sheet.Pivot)) {140166 p := e.pivot(m)141167 fn(&p)142168 e.msg = ""143- if err := m.sheet.SetPivot(p, label); err != nil {169+ if err := m.sheetShown().SetPivot(p, label); err != nil {144170 e.msg = err.Error()145171 }146- m.changed = m.sheet.StateID() != m.saved172+ m.syncChanged()147173 }148174 149175 func (e *pivotEditor) Key(k tea.KeyPressMsg) tea.Cmd {150176 m := e.m151- if _, ok := m.sheet.Pivot(); !ok {177+ if _, ok := m.sheetShown().Pivot(); !ok {152178 m.closeOverlay()153179 return nil154180 }@@ -186,17 +212,17 @@ func (e *pivotEditor) Key(k tea.KeyPressMsg) tea.Cmd {
186212 187213 // cancel undoes the editor's changes and closes it; a pivot just created188214 // goes with its sheet.189-func (e *pivotEditor) cancel(m *Model) {190- for m.sheet.StateID() != e.start && m.sheet.CanUndo() {191- m.sheet.Undo()215+func (e *pivotEditor) cancel(m pivotHost) {216+ for m.sheetShown().StateID() != e.start && m.sheetShown().CanUndo() {217+ m.sheetShown().Undo()192218 }193219 m.closeOverlay()194220 m.afterSheetsChange(e.back, m.book().Active())195- m.changed = m.sheet.StateID() != m.saved221+ m.syncChanged()196222 }197223 198224 // reopen returns to the editor after a picker or prompt.199-func (e *pivotEditor) reopen(m *Model) { m.openOverlay(e) }225+func (e *pivotEditor) reopen() { e.m.openOverlay(e) }200226 201227 func (e *pivotEditor) Mouse(ev overlay.MouseEvent) tea.Cmd {202228 m := e.m@@ -224,14 +250,16 @@ func (e *pivotEditor) Mouse(ev overlay.MouseEvent) tea.Cmd {
224250 }225251 226252 // rows is how many lines of the list show.227-func (e *pivotEditor) rows(m *Model, n int) int {228- return max(min(n, m.height-1-gridTop-2), 1)253+func (e *pivotEditor) rows(m pivotHost, n int) int {254+ _, height := m.size()255+ return max(min(n, height-1-gridTop-2), 1)229256 }230257 231258 // box places the editor at the right of the grid.232-func (e *pivotEditor) box(m *Model) (x, y, inner int) {233- inner = min(44, m.width-2)234- return max(m.width-inner-2, 0), gridTop, inner259+func (e *pivotEditor) box(m pivotHost) (x, y, inner int) {260+ width, _ := m.size()261+ inner = min(44, width-2)262+ return max(width-inner-2, 0), gridTop, inner235263 }236264 237265 func (e *pivotEditor) Layout() []overlay.Box {@@ -251,28 +279,28 @@ func (e *pivotEditor) Layout() []overlay.Box {
251279 lines = append(lines, e.line(m, p, items[i], i == e.Sel, inner))252280 }253281 footer := ""254- if out, ok := m.sheet.PivotRange(); ok && m.sheet.PivotError() == "" {282+ if out, ok := m.sheetShown().PivotRange(); ok && m.sheetShown().PivotError() == "" {255283 footer = "results " + out.String()256284 }257- return []overlay.Box{{ID: pivotEditorID, X: x, Y: y, Lines: m.th.Frame(inner, "Pivot table", footer, lines)}}285+ return []overlay.Box{{ID: pivotEditorID, X: x, Y: y, Lines: m.styles().Frame(inner, "Pivot table", footer, lines)}}258286 }259287 260288 // line draws one line of the editor, inner columns wide.261-func (e *pivotEditor) line(m *Model, p sheet.Pivot, it pivotItem, sel bool, inner int) string {262- base, dim := m.th.MenuBar, m.th.Muted289+func (e *pivotEditor) line(m pivotHost, p sheet.Pivot, it pivotItem, sel bool, inner int) string {290+ base, dim := m.styles().MenuBar, m.styles().Muted263291 if sel {264- base, dim = m.th.MenuSelected, m.th.MenuSelected292+ base, dim = m.styles().MenuSelected, m.styles().MenuSelected265293 }266294 var left, right string267295 switch it.kind {268296 case itemSep:269297 return theme.SepRow270298 case itemError:271- return theme.Cells(m.th.Warning, " "+m.sheet.PivotError(), inner)299+ return theme.Cells(m.styles().Warning, " "+m.sheetShown().PivotError(), inner)272300 case itemSource:273301 left = base.Render(" Data ") + e.sourceText(m, p, sel)274302 case itemSection:275- title := m.th.Title303+ title := m.styles().Title276304 if sel {277305 title = base278306 }@@ -307,29 +335,30 @@ func spreadIn(base lipgloss.Style, left, right string, w int) string {
307335 return ansi.Truncate(left+base.Render(strings.Repeat(" ", gap))+right, w, "")308336 }309337 310-func (e *pivotEditor) sourceText(m *Model, p sheet.Pivot, sel bool) string {338+func (e *pivotEditor) sourceText(m pivotHost, p sheet.Pivot, sel bool) string {311339 text := sheet.QuoteSheet(p.Source) + "!" + p.Range.String()312340 if p.Lost {313341 text = sheet.QuoteSheet(p.Source) + "!#REF!"314342 }315343 if sel {316- return m.th.MenuSelected.Render(text)344+ return m.styles().MenuSelected.Render(text)317345 }318- return m.th.Key.Render(text)346+ return m.styles().Key.Render(text)319347 }320348 321349 func (e *pivotEditor) Status() (string, string) {322350 m := e.m323351 it := e.current(m)352+ width, _ := m.size()324353 desc, pairs := e.help(m, it)325354 if e.msg != "" {326- desc = m.th.Warning.Render(e.msg)355+ desc = m.styles().Warning.Render(e.msg)327356 }328357 pairs = append(pairs, "Enter", "done", "Esc", "cancel")329358 for {330- keys := m.th.KeyHints(pairs...)359+ keys := m.styles().KeyHints(pairs...)331360 switch {332- case ansi.StringWidth(desc)+3+ansi.StringWidth(keys) <= m.width:361+ case ansi.StringWidth(desc)+3+ansi.StringWidth(keys) <= width:333362 return desc, keys334363 case desc != "":335364 desc = ""@@ -346,7 +375,7 @@ func (e *pivotEditor) Status() (string, string) {
346375 }347376 348377 // help is what the highlighted line is and the keys that act on it.349-func (e *pivotEditor) help(m *Model, it pivotItem) (string, []string) {378+func (e *pivotEditor) help(m pivotHost, it pivotItem) (string, []string) {350379 p := e.pivot(m)351380 switch it.kind {352381 case itemSource:@@ -136,7 +136,7 @@ func (m *Model) openImport() tea.Cmd {
136136 return m.askImportPlace(name)137137 }})138138 }139- p := newPicker(m, "Import", "Type to filter, or a path", 72, items)139+ p := m.newPicker("Import", "Type to filter, or a path", 72, items)140140 p.Action = "import"141141 p.Enter = func(query string) (tea.Cmd, bool) {142142 // A path, or a name that matched nothing: import it by name.@@ -373,7 +373,7 @@ func (m *Model) openTablePicker(name string, tables []fileio.TableInfo, place im
373373 m.prompt.indicator = "SQL"374374 return nil375375 }})376- p := newPicker(m, "Import from "+filepath.Base(name), "Type to filter tables", 72, items)376+ p := m.newPicker("Import from "+filepath.Base(name), "Type to filter tables", 72, items)377377 p.Action = "import"378378 m.openOverlay(p)379379 }