132 lines
3.8 KiB
Go
132 lines
3.8 KiB
Go
package layout
|
|
|
|
import (
|
|
"bufio"
|
|
"io"
|
|
"log"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
/**********************************************************************************
|
|
The syntax for the layout specification is:
|
|
```
|
|
(rowspan:)?widget(/weight)?
|
|
```
|
|
1. Each line is a row
|
|
2. Empty lines are skipped
|
|
3. Spaces are compressed
|
|
4. Legal widget names are: cpu, disk, mem, temp, batt, net, procs
|
|
5. Names are not case sensitive
|
|
4. The simplest row is a single widget, by name, e.g.
|
|
```
|
|
cpu
|
|
```
|
|
5. Widgets with no weights have a weight of 1.
|
|
6. If multiple widgets are put on a row with no weights, they will all have
|
|
the same width.
|
|
7. Weights are integers
|
|
8. A widget will have a width proportional to its weight divided by the
|
|
total weight count of the row. E.g.,
|
|
```
|
|
cpu net
|
|
disk/2 mem/4
|
|
```
|
|
The first row will have two widgets: the CPU and network widgets; each
|
|
will be 50% of the total width wide. The second row will have two
|
|
widgets: disk and memory; the first will be 2/6 ~= 33% wide, and the
|
|
second will be 5/7 ~= 67% wide (or, memory will be twice as wide as disk).
|
|
9. If prefixed by a number and colon, the widget will span that number of
|
|
rows downward. E.g.
|
|
```
|
|
2:cpu
|
|
mem
|
|
```
|
|
The CPU widget will be twice as high as the memory widget. Similarly,
|
|
```
|
|
mem 2:cpu
|
|
net
|
|
```
|
|
memory and network will be in the same row as CPU, one over the other,
|
|
and each half as high as CPU.
|
|
10. Negative, 0, or non-integer weights will be recorded as "1". Same for row spans.
|
|
11. Unrecognized widgets will cause the application to abort.
|
|
12. In rows with multi-row spanning widgets **and** weights, weights in
|
|
lower rows are ignored. Put the weight on the widgets in that row, not
|
|
in later (spanned) rows.
|
|
13. Widgets are filled in top down, left-to-right order.
|
|
14. The larges row span in a row defines the top-level row span; all smaller
|
|
row spans constitude sub-rows in the row. For example, `cpu mem/3 net/5`
|
|
means that net/5 will be 5 rows tall overall, and mem will compose 3 of
|
|
them. If following rows do not have enough widgets to fill the gaps,
|
|
spacers will be used.
|
|
15. Lines beginning with "#" will be ignored. It must be the first character of
|
|
the line.
|
|
**********************************************************************************/
|
|
func ParseLayout(i io.Reader) layout {
|
|
r := bufio.NewScanner(i)
|
|
rv := layout{Rows: make([][]widgetRule, 0)}
|
|
var lineNo int
|
|
for r.Scan() {
|
|
l := strings.TrimSpace(r.Text())
|
|
if l == "" || l[0] == '#' {
|
|
continue
|
|
}
|
|
row := make([]widgetRule, 0)
|
|
ws := strings.Fields(l)
|
|
weightTotal := 0
|
|
for _, w := range ws {
|
|
wr := widgetRule{Weight: 1}
|
|
ks := strings.Split(w, "/")
|
|
rs := strings.Split(ks[0], ":")
|
|
var wid string
|
|
if len(rs) > 1 {
|
|
v, e := strconv.Atoi(rs[0])
|
|
if e != nil {
|
|
ln := strconv.Itoa(lineNo)
|
|
log.Printf(tr.Value("layout.error.format", "INT:STRING/INT", ln, rs[0], w))
|
|
v = 1
|
|
}
|
|
if v < 1 {
|
|
v = 1
|
|
}
|
|
wr.Height = v
|
|
wid = rs[1]
|
|
} else {
|
|
wr.Height = 1
|
|
wid = rs[0]
|
|
}
|
|
wr.Widget = strings.ToLower(wid)
|
|
if len(ks) > 1 {
|
|
weight, e := strconv.Atoi(ks[1])
|
|
if e != nil {
|
|
ln := strconv.Itoa(lineNo)
|
|
log.Printf(tr.Value("layout.error.format", "STRING/INT", ln, ks[1], w))
|
|
weight = 1
|
|
}
|
|
if weight < 1 {
|
|
weight = 1
|
|
}
|
|
wr.Weight = float64(weight)
|
|
if len(ks) > 2 {
|
|
ln := strconv.Itoa(lineNo)
|
|
log.Printf(tr.Value("layout.error.slashes", ln, w))
|
|
}
|
|
weightTotal += weight
|
|
} else {
|
|
weightTotal++
|
|
}
|
|
row = append(row, wr)
|
|
}
|
|
// Prevent tricksy users from breaking their own computers
|
|
if weightTotal <= 1 {
|
|
weightTotal = 1
|
|
}
|
|
for i, w := range row {
|
|
row[i].Weight = w.Weight / float64(weightTotal)
|
|
}
|
|
rv.Rows = append(rv.Rows, row)
|
|
}
|
|
return rv
|
|
}
|