cat / 012
clone

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

cat/module-path
012 / internal / ui / rowheights.go
rowheights.go 3.3K
1package ui23import (4 "strconv"56 tea "charm.land/bubbletea/v2"78 "src.rest/cat/012/internal/macro"9 "src.rest/cat/012/internal/sheet"10)1112// Row heights, in lines: typed on the context line with a live preview,13// dragged by the bottom-right corner of a row's number (mouse.go), or14// fitted to the contents again by double-clicking it, as Sheets' Resize15// row offers a height or Fit to data. A row without a height fits the16// text it wraps.1718func init() {19 register(20 &command{id: "row.height", title: "Row height", desc: "Set the height of the selected rows, in lines", run: (*Model).openHeight},21 &command{id: "row.fit", title: "Fit rows to data", desc: "Size the selected rows to their contents again",22 run: func(m *Model) tea.Cmd {23 r := m.selection()24 m.fitRange(r.From.Row, r.To.Row)25 return nil26 }},27 )28}2930// openHeight asks for the height of the selected rows, previewing it31// live as the arrows change it. Esc restores the original heights.32func (m *Model) openHeight() tea.Cmd {33 r := m.selection()34 orig := map[int]int{}35 for row, h := range m.sheet.Heights() {36 if row >= r.From.Row && row <= r.To.Row {37 orig[row] = h38 }39 }40 restore := func() {41 m.sheet.Batch(sheet.Change{Label: "row height", Focus: r}, func() error {42 m.sheet.SetRowHeight(r.From.Row, r.To.Row, 0)43 for row, h := range orig {44 m.sheet.SetRowHeight(row, row, h)45 }46 return nil47 })48 }49 cur := m.shape(m.cur.Row).Lines50 m.openPrompt(&prompt{51 kind: promptWidth,52 label: "Row height (1-" + strconv.Itoa(sheet.MaxRowHeight) + " lines):",53 indicator: "HEIGHT",54 fresh: true,55 resize: func(h int) { m.sheet.SetRowHeight(r.From.Row, r.To.Row, h) },56 maxSize: sheet.MaxRowHeight,57 onText: func(text string) tea.Cmd {58 h, err := strconv.Atoi(text)59 if err != nil || h < 1 || h > sheet.MaxRowHeight {60 restore()61 m.fail("Row height must be between 1 and " + strconv.Itoa(sheet.MaxRowHeight) + " lines")62 return nil63 }64 m.sheet.SetRowHeight(r.From.Row, r.To.Row, h)65 m.changed = true66 return nil67 },68 onCancel: restore,69 }, strconv.Itoa(cur))70 return nil71}7273// fitRows fits row r to its contents, as double-clicking the border of74// its number does in Sheets; selected whole rows fit together.75func (m *Model) fitRows(r int) {76 from, to := r, r77 if sel := m.selection(); m.whole == wholeRows && r >= sel.From.Row && r <= sel.To.Row {78 from, to = sel.From.Row, sel.To.Row79 }80 m.fitRange(from, to)81 m.record(heightAction(from, to, 0))82}8384// fitRange clears the heights of rows from..to, only those that have85// one, so rows fit their contents.86func (m *Model) fitRange(from, to int) {87 m.sheet.Batch(sheet.Change{Label: "fit rows to data", Focus: sheet.Rect{From: sheet.Addr{Row: from}, To: sheet.Addr{Col: sheet.MaxCols - 1, Row: to}}}, func() error {88 for row := range m.sheet.Heights() {89 if row >= from && row <= to {90 m.sheet.SetRowHeight(row, row, 0)91 }92 }93 return nil94 })95 m.changed = true96 m.note = "Rows " + strconv.Itoa(from+1) + ":" + strconv.Itoa(to+1) + " fit their contents"97 if from == to {98 m.note = "Row " + strconv.Itoa(from+1) + " fits its contents"99 }100}101102// heightAction records setting rows from..to to h lines, 0 to fit.103func heightAction(from, to, h int) macro.Action {104 rows := strconv.Itoa(from + 1)105 if to != from {106 rows += ":" + strconv.Itoa(to+1)107 }108 return macro.Call("set_height", rows, h)109}