X-Git-Url: https://git.giacomolli.uk/onechat/blobdiff_plain/9f17bfb1173524553fff5301b0664267b430e6e3..442c68e1d384a7da0d9ab039704bf763a1c3ac35:/view.go diff --git a/view.go b/view.go index 158b59e..ddd97ed 100644 --- a/view.go +++ b/view.go @@ -13,6 +13,11 @@ const ( chatHigh = 128000 chatLow = 64000 + // compactionHigh and compactionLow are the limits of the compaction + // view in bytes. + compactionHigh = 32000 + compactionLow = 16000 + // pending is the text of a line that is not built yet. pending = "(not summarized yet: zoom it)" ) @@ -96,23 +101,27 @@ func (v *View) State() viewState { } // Append adds the leaf of the next message as a line and merges when the view -// is too large. -func (v *View) Append(tree nodeReader) { +// is too large. It tells if a merge changed the view. +func (v *View) Append(tree nodeReader) bool { v.lines = append(v.lines, nodeKey{0, v.end}) v.end++ - v.fit(tree) + + return v.fit(tree) } -func (v *View) fit(tree nodeReader) { +// fit merges the most due pairs while a batch runs, and tells if a merge +// changed the view. +func (v *View) fit(tree nodeReader) bool { size := v.Size(tree) if size > v.high { v.merging = true } + merged := false for v.merging && size > v.low { best := v.mostDue(tree) if best < 0 { - return + return merged } left, right := v.lines[best], v.lines[best+1] @@ -120,9 +129,42 @@ func (v *View) fit(tree nodeReader) { size += lineSize(tree, parent) - lineSize(tree, left) - lineSize(tree, right) v.lines[best] = parent v.lines = append(v.lines[:best+1], v.lines[best+2:]...) + merged = true } v.merging = false + + return merged +} + +// Coarsen takes each merge of other, a view of the same messages, and then +// merges in one batch until the size is at most low. Each line of the result is +// the coarser of the two lines that start at its first message. Dyadic ranges +// either nest or do not overlap, so the result covers the messages without a +// gap. +func (v *View) Coarsen(other *View, tree nodeReader) { + lines := make([]nodeKey, 0, len(v.lines)) + mine, theirs := 0, 0 + for start := 0; start < v.end; { + line := v.lines[mine] + if other.lines[theirs].level > line.level { + line = other.lines[theirs] + } + + lines = append(lines, line) + start = nodeEnd(line.level, line.index) + for mine < len(v.lines) && v.lines[mine].index<\n") + for _, line := range v.lines { + _, built := tree.Node(line.level, line.index) + if !built || nodeEnd(line.level, line.index) > end { + break + } + + renderLine(&text, tree, line) + } + + text.WriteString("") + + return text.String() +} + // lineSize returns the size of a view line. func lineSize(tree nodeReader, line nodeKey) int { node, built := tree.Node(line.level, line.index)