return &View{
high: high,
low: low,
- nodes: make(map[nodeKey]Node),
+ nodes: make(map[NodeKey]Node),
}
}
v := newView(high, low)
v.merging = state.Merging
for _, pair := range state.Lines {
- line := nodeKey{pair[0], pair[1]}
+ line := NodeKey{pair[0], pair[1]}
if line.level < 0 || line.level >= bits.UintSize-2 || line.index < 0 || line.index<<line.level != v.end {
return nil, fmt.Errorf("view line (%d, %d) does not start at message %d", line.level, line.index, v.end)
}
type View struct {
high int
low int
- lines []nodeKey
- nodes map[nodeKey]Node
+ lines []NodeKey
+ nodes map[NodeKey]Node
end int
merging bool
}
// Append adds the leaf of the next message as a line and merges when the view
// is too large. It tells if a merge changed the view.
func (v *View) Append(tree ViewNodeReader) (bool, error) {
- line := nodeKey{0, v.end}
+ line := NodeKey{0, v.end}
_, err := v.load(tree, line)
if err != nil {
return false, err
// either nest or do not overlap, so the result covers the messages without a
// gap.
func (v *View) Coarsen(other *View, tree ViewNodeReader) error {
- lines := make([]nodeKey, 0, len(v.lines))
- nodes := make(map[nodeKey]Node, len(v.nodes))
+ lines := make([]NodeKey, 0, len(v.lines))
+ nodes := make(map[NodeKey]Node, len(v.nodes))
mine, theirs := 0, 0
for start := 0; start < v.end; {
line := v.lines[mine]
// Refresh keeps node when it is the node of a pending line.
func (v *View) Refresh(node Node) {
- key := nodeKey{node.Level, node.Index}
+ key := NodeKey{node.Level, node.Index}
for n := len(v.lines) - 1; n >= 0; n-- {
line := v.lines[n]
if line == key {
}
}
+// Pending tells if a line of the view is not built yet.
+func (v *View) Pending() bool {
+ for _, line := range v.lines {
+ _, built := v.nodes[line]
+ if !built {
+ return true
+ }
+ }
+
+ return false
+}
+
// Render returns the view as the model reads it: one line "id+n|text" for each
// node inside <chat> tags, with the newlines of the text as spaces.
func (v *View) Render() string {
}
var text strings.Builder
+
v.renderLine(&text, line)
+
lines = append(lines, text.String())
}
// sees a pending mark or a part of a message.
func (v *View) Context(end int) string {
var text strings.Builder
+
text.WriteString("<chat>\n")
+
for _, line := range v.lines {
_, built := v.nodes[line]
if !built || nodeEnd(line.level, line.index) > end {
}
// load keeps the node of line when it is built, and tells if it is.
-func (v *View) load(tree ViewNodeReader, line nodeKey) (bool, error) {
+func (v *View) load(tree ViewNodeReader, line NodeKey) (bool, error) {
node, built, err := tree.Node(line.level, line.index)
if err != nil || !built {
return false, err
}
left, right := v.lines[best], v.lines[best+1]
- parent := nodeKey{left.level + 1, left.index / 2}
+ parent := NodeKey{left.level + 1, left.index / 2}
_, err = v.load(tree, parent)
if err != nil {
return merged, err
size += v.lineSize(parent) - v.lineSize(left) - v.lineSize(right)
delete(v.nodes, left)
delete(v.nodes, right)
+
v.lines[best] = parent
v.lines = append(v.lines[:best+1], v.lines[best+2:]...)
merged = true
}
// renderLine writes one view line, "id+n|text", and a newline.
-func (v *View) renderLine(text *strings.Builder, line nodeKey) {
+func (v *View) renderLine(text *strings.Builder, line NodeKey) {
body := viewPending
node, built := v.nodes[line]
if built {
built, err := tree.Built(left.level+1, left.index/2)
if err != nil {
- return -1, err
+ return -1, fmt.Errorf("check parent node: %w", err)
}
if built {
}
// lineSize returns the size of a view line.
-func (v *View) lineSize(line nodeKey) int {
+func (v *View) lineSize(line NodeKey) int {
node, built := v.nodes[line]
if !built {
return len(viewPending)