diff options
author | Robin Jarry <robin@jarry.cc> | 2022-12-21 11:50:53 +0100 |
---|---|---|
committer | Robin Jarry <robin@jarry.cc> | 2023-01-04 22:57:31 +0100 |
commit | 012be0192c88f4fcfd5ed559edff4ca7366eb351 (patch) | |
tree | 558509153975b5d423bf2bd2995483278accd473 /config | |
parent | 1eb4c2c1e79ea8d66d53caaca24dd1b8ba32b02f (diff) | |
download | aerc-012be0192c88f4fcfd5ed559edff4ca7366eb351.tar.gz |
ui: add reusable table widget
This will be used by the message list index and by the status line.
A table is constructed from rows/width dimensions, a list of column
definitions and a column separator.
Provide functions to parse column definitions from ini config files.
This will be used in the next commit.
Signed-off-by: Robin Jarry <robin@jarry.cc>
Acked-by: Tim Culverhouse <tim@timculverhouse.com>
Diffstat (limited to 'config')
-rw-r--r-- | config/columns.go | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/config/columns.go b/config/columns.go new file mode 100644 index 00000000..659be2c3 --- /dev/null +++ b/config/columns.go @@ -0,0 +1,120 @@ +package config + +import ( + "bytes" + "fmt" + "regexp" + "strconv" + "strings" + "text/template" + + "git.sr.ht/~rjarry/aerc/lib/templates" + "github.com/go-ini/ini" +) + +type ColumnFlags uint32 + +func (f ColumnFlags) Has(o ColumnFlags) bool { return f&o == o } + +const ( + ALIGN_LEFT ColumnFlags = 1 << iota + ALIGN_CENTER + ALIGN_RIGHT + WIDTH_AUTO // whatever is left + WIDTH_FRACTION // ratio of total width + WIDTH_EXACT // exact number of characters + WIDTH_FIT // fit to column content width +) + +type ColumnDef struct { + Name string + Flags ColumnFlags + Width float64 + Template *template.Template +} + +var columnRe = regexp.MustCompile(`^([\w-]+)(?:([<:>])(=|\*|\d+%?)?)?$`) + +func parseColumnDef(col string, section *ini.Section) (*ColumnDef, error) { + col = strings.TrimSpace(col) + match := columnRe.FindStringSubmatch(col) + if match == nil { + return nil, fmt.Errorf("invalid column def: %v", col) + } + name := match[1] + keyName := fmt.Sprintf("column-%s", name) + + var flags ColumnFlags + switch match[2] { + case "<", "": + flags |= ALIGN_LEFT + case ":": + flags |= ALIGN_CENTER + case ">": + flags |= ALIGN_RIGHT + } + + var width float64 = 0 + switch match[3] { + case "=": + flags |= WIDTH_FIT + case "*", "": + flags |= WIDTH_AUTO + default: + s := match[3] + var divider float64 = 1 + if strings.HasSuffix(s, "%") { + divider = 100 + s = strings.TrimSuffix(s, "%") + flags |= WIDTH_FRACTION + } else { + flags |= WIDTH_EXACT + } + w, err := strconv.ParseFloat(s, 64) + if err != nil { + return nil, fmt.Errorf("%s: %w", keyName, err) + } + if divider == 100 && w > 100 { + return nil, fmt.Errorf("%s: invalid width %.0f%%", keyName, w) + } + width = w / divider + } + key, err := section.GetKey(keyName) + if err != nil { + return nil, err + } + + t, err := templates.ParseTemplate(keyName, key.String()) + if err != nil { + return nil, err + } + + data := templates.DummyData() + var buf bytes.Buffer + err = t.Execute(&buf, data) + if err != nil { + return nil, err + } + + return &ColumnDef{ + Name: name, + Flags: flags, + Width: width, + Template: t, + }, nil +} + +func ParseColumnDefs(key *ini.Key, section *ini.Section) ([]*ColumnDef, error) { + var columns []*ColumnDef + for _, col := range key.Strings(",") { + c, err := parseColumnDef(col, section) + if err != nil { + return nil, err + } + columns = append(columns, c) + } + if len(columns) == 0 { + return nil, fmt.Errorf("%s cannot be empty", key.Name()) + } + return columns, nil +} |