cat / 012
clone

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

main
012 / internal / ui / nbview / full.go
full.go 2.6K
1package nbview23import (4 tea "charm.land/bubbletea/v2"56 "src.rest/cat/012/internal/locale"7 "src.rest/cat/012/internal/ui/theme"8)910// Full is an output shown full-screen, read-only: a table or record as11// the UI's grid at the body's size, which the UI gives the keys, and12// anything else as its lines, scrolled with a pointer. Esc goes back to13// the notebook.14type Full struct {15 Title string16 sh *shown1718 row, top int // the pointer and the first line shown, for lines19 width, height int20}2122func newFull(title string, sh *shown, width, height int) *Full {23 f := &Full{Title: title, sh: sh}24 f.resize(width, height)25 return f26}2728func (f *Full) resize(width, height int) { f.width, f.height = width, max(height, 2) }2930// Grid is the output's grid, when it's drawn as one: the UI gives it31// the keys.32func (f *Full) Grid() Grid { return f.sh.grid }3334// rowsShown is how many lines there are to scroll through.35func (f *Full) rowsShown() int { return f.sh.height(true, f.width-1) }3637// Key takes a key, reporting whether Esc left the view.38func (f *Full) Key(k tea.KeyPressMsg) (closed bool) {39 page := max(f.height-1, 1)40 switch k.String() {41 case "esc", "q":42 return true43 case "up", "k":44 f.row--45 case "down", "j":46 f.row++47 case "pgup":48 f.row -= page49 case "pgdown", "space":50 f.row += page51 case "home", "g":52 f.row = 053 case "end", "G":54 f.row = f.rowsShown() - 155 }56 f.settle()57 return false58}5960// settle keeps the pointer on the lines and on screen.61func (f *Full) settle() {62 f.row = max(min(f.row, f.rowsShown()-1), 0)63 f.top = max(min(f.top, f.row), f.row-f.height+1, 0)64}6566// lines draws the view: the grid at full size, its header on the first67// line, or the output's lines with the pointer's marked.68func (f *Full) lines(th *theme.Theme, loc *locale.Locale) []string {69 out := make([]string, 0, f.height)70 if g := f.sh.grid; g != nil {71 rows := f.height - 172 from := g.Top()73 for i := range min(g.Rows(), rows) + 1 {74 out = append(out, g.Line(i, from, rows, f.width))75 }76 return padLines(out, f.height)77 }78 for i := f.top; i < f.top+f.height && i < f.rowsShown(); i++ {79 line := f.sh.line(th, loc, i, fold{whole: true}, f.width-1)80 if i == f.row {81 line = th.Selection.Render("▌") + line82 } else {83 line = " " + line84 }85 out = append(out, line)86 }87 return padLines(out, f.height)88}8990func boolInt(b bool) int {91 if b {92 return 193 }94 return 095}9697func padLines(out []string, n int) []string {98 for len(out) < n {99 out = append(out, "")100 }101 return out102}103104// ContextLine says what's shown and the keys.105func (f *Full) ContextLine(th *theme.Theme) (string, string) {106 return th.Muted.Render(f.Title), th.KeyHints("Esc", "back")107}