A frame of 8192 x 26 numbers under data bars and icons takes 0.27 / 1.5 / 4.9 ms at 80x24 / 200x60 / 400x120, from 0.54 / 3.7 / 11.4 ms with a style render per run (BenchmarkFrame bars-8192x26, median of 6). A cell's own style (its text's, a copy marker's) is still rendered, as its address isn't the theme's.
- commit
- a2e67f8801fa324033d0a9728de730efa9aab753
- parent
- 1e399dd7be22ccf6b94405556d560bc8387cf6a0
- author
- Dami <dami.etoile@gmail.com>
- kind
- refactor risk score 1.4 of 3, Jev's estimate
| M | docs/ | 14 | +++++++++++++- |
| M | internal/ | 31 | ++++++++++++++++++++++++++---- |
| M | internal/ | 4 | ++++ |
| M | internal/ | 1 | + |
| M | internal/ | 4 | ++++ |
@@ -230,7 +230,19 @@ every cell on screen a shade), at 200 x 60 (`BenchmarkFrame`,
230230 Shades and rule colors keep their escape codes, so a plain cell on one231231 costs a string concatenation, not a style render. A custom formula is232232 evaluated for each cell drawn, once per recalculation, with its233-references moved for the cell.233+references moved for the cell. Top values, averages and duplicates234+read their ranges once per recalculation, as a scale does.235+236+Data bars and icons are drawn a column at a time, their glyphs with the237+escape codes of their roles kept for the frame, so a cell under one costs238+more than a shade. `bars-8192x26` puts a data bar over239+13 columns of 8192 x 26 numbers and arrows over the other 13240+(`BenchmarkFrame`):241+242+| | 80 x 24 | 200 x 60 | 400 x 120 |243+|---|---|---|---|244+| 8192 x 26 numbers, a frame | 0.18 ms | 0.89 ms | 3.1 ms |245+| The same with bars and icons on every cell | 0.27 ms | 1.5 ms | 4.9 ms |234246 235247 Wrapped text, borders, row heights and merged cells cost what the236248 screen shows too. A sheet with none of them is drawn a line per row@@ -76,15 +76,25 @@ func (m *Model) barText(sp rowtext.Span, w int, look *sheet.Look, base *lipgloss
7676 if look.Bar {7777 cover = theme.BarCover(look.BarLen, w-1) // the last column keeps bars apart7878 }79- text := spanStyle(&m.th, *base, sp)79+ text := base80+ if !plainSpan(sp) {81+ st := spanStyle(&m.th, *base, sp)82+ text = &st83+ }8084 var b strings.Builder8185 var run strings.Builder8286 var cur *lipgloss.Style8387 flush := func() {84- if run.Len() > 0 {88+ switch {89+ case run.Len() == 0:90+ case cur == base && !colored:91+ b.WriteString(run.String())92+ case cur == text || cur == base: // either may be the cell's own, made for it8593 b.WriteString(cur.Render(run.String()))86- run.Reset()94+ default: // a theme's role, whose address stays put for the frame95+ b.WriteString(m.shade(cur).Wrap(run.String()))8796 }97+ run.Reset()8898 }8999 put := func(role *lipgloss.Style, s string) {90100 if role != cur {@@ -105,13 +115,26 @@ func (m *Model) barText(sp rowtext.Span, w int, look *sheet.Look, base *lipgloss
105115 case ch == " ":106116 put(base, ch)107117 default:108- put(&text, ch)118+ put(text, ch)109119 }110120 }111121 flush()112122 return b.String()113123 }114124 125+// shade is role with its escape codes, kept for the frame.126+func (m *Model) shade(role *lipgloss.Style) theme.Shade {127+ if sh, ok := m.shaded[role]; ok {128+ return sh129+ }130+ if m.shaded == nil {131+ m.shaded = map[*lipgloss.Style]theme.Shade{}132+ }133+ sh := theme.ShadeOf(*role)134+ m.shaded[role] = sh135+ return sh136+}137+115138 func coverAt(cover []int, x int) int {116139 if x < len(cover) {117140 return cover[x]@@ -8,6 +8,7 @@ import (
88 "time"99 1010 tea "charm.land/bubbletea/v2"11+ "charm.land/lipgloss/v2"1112 1213 "github.com/FelineStateMachine/012/internal/confine"1314 "github.com/FelineStateMachine/012/internal/sheet"@@ -95,6 +96,9 @@ type Model struct {
9596 borderColor sheet.Color9697 // painted is what borders drew this frame, by role: gridlines.go.9798 painted map[paintKey]string99+ // shaded are roles with their escape codes, for glyphs drawn one at a100+ // time (bars.go); kept for a frame as painted is.101+ shaded map[*lipgloss.Style]theme.Shade98102 // mergeLines are the lines merges show their values on, worked out99103 // once a frame (see mergeText).100104 mergeLines map[sheet.Rect][2]int@@ -32,6 +32,7 @@ func (m *Model) View() tea.View {
3232 }3333 clear(m.painted) // the theme may have changed since the last frame3434 clear(m.mergeLines)35+ clear(m.shaded)3536 lines := []string{m.menuBarLine(), m.formulaBar(), m.contextLineText(), m.headerRow()}3637 for _, b := range m.bands() {3738 lines = m.appendBand(lines, b)@@ -111,6 +111,10 @@ type Shade struct {
111111 Open, Close string112112 }113113 114+// ShadeOf is s with the escape codes that open and close it, for text115+// drawn in it often.116+func ShadeOf(s lipgloss.Style) Shade { return shadeOf(s) }117+114118 func shadeOf(s lipgloss.Style) Shade {115119 r := s.Render(shadeMark)116120 i := strings.Index(r, shadeMark)