aboutsummaryrefslogtreecommitdiffstats
path: root/config
diff options
context:
space:
mode:
authorRobin Jarry <robin@jarry.cc>2022-12-21 11:50:53 +0100
committerRobin Jarry <robin@jarry.cc>2023-01-04 22:57:31 +0100
commit012be0192c88f4fcfd5ed559edff4ca7366eb351 (patch)
tree558509153975b5d423bf2bd2995483278accd473 /config
parent1eb4c2c1e79ea8d66d53caaca24dd1b8ba32b02f (diff)
downloadaerc-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.go120
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
+}