1package sheet23import (4 "bufio"5 "encoding/json"6 "fmt"7 "maps"8 "slices"9 "strings"1011 "src.rest/cat/012/internal/formula"12)1314// Column and row formats in the file: a "lines" field after the widths,15// keyed by columns or rows as a range writes them, runs of lines with the16// same formatting together, each value a formatted blank cell:17//18// "lines": {"A:XFD": {"italic": true}, "B:B": {"format": "currency", "decimals": 2}, "1:1": {"bold": true}},19//20// A:XFD, every column, is the whole sheet's format.21//22// Earlier builds ignore the field and show those cells unformatted, so it23// needs no new version.2425// writeLines writes the "lines" field, if the sheet has line formats.26func (s *Sheet) writeLines(b *bufio.Writer, indent string) error {27 if s.lines.none() {28 return nil29 }30 b.WriteString(indent + `"lines": {`)31 first := true32 if l := s.lines.sheet; !l.IsZero() {33 raw, err := encodeCell(&Cell{Format: l.Format, Style: l.Style})34 if err != nil {35 return err36 }37 fmt.Fprintf(b, "%q: %s", s.lineRect(false, wholeSheet, wholeSheet).String(), raw)38 first = false39 }40 for _, row := range []bool{false, true} {41 m := s.lines.cols42 if row {43 m = s.lines.rows44 }45 ns := slices.Sorted(maps.Keys(m))46 for i := 0; i < len(ns); {47 j := i + 148 for j < len(ns) && ns[j] == ns[j-1]+1 && m[ns[j]] == m[ns[i]] {49 j++50 }51 l := m[ns[i]]52 raw, err := encodeCell(&Cell{Format: l.Format, Style: l.Style})53 if err != nil {54 return err55 }56 if !first {57 b.WriteString(", ")58 }59 first = false60 fmt.Fprintf(b, "%q: %s", s.lineRect(row, ns[i], ns[j-1]).String(), raw)61 i = j62 }63 }64 b.WriteString("},\n")65 return nil66}6768// readLines sets the line formats of a file's "lines" field.69func (s *Sheet) readLines(lines map[string]json.RawMessage) error {70 for key, raw := range lines {71 from, to, found := strings.Cut(key, ":")72 if !found {73 to = from74 }75 r, _, ok := formula.ParseLines(from, to)76 if !ok {77 return fmt.Errorf("invalid lines %q", key)78 }79 input, f, st, err := decodeCell(raw)80 if err != nil || input != "" {81 return fmt.Errorf("lines %s: invalid format", key)82 }83 if r.AllRows() && r.AllCols() {84 s.setLine(false, wholeSheet, lineFmt{f, st})85 continue86 }87 row := !r.AllRows()88 n0, n1 := r.From.Col, r.To.Col89 if row {90 n0, n1 = r.From.Row, r.To.Row91 }92 for n := n0; n <= n1; n++ {93 s.setLine(row, n, lineFmt{f, st})94 }95 }96 return nil97}