Files
mautrix-telegram/pkg/connector/telegramfmt/tree.go
T
2024-08-05 15:19:39 -06:00

114 lines
2.9 KiB
Go

// mautrix-telegram - A Matrix-Telegram puppeting bridge.
// Copyright (C) 2024 Sumner Evans
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package telegramfmt
import (
"fmt"
"sort"
)
type BodyRange struct {
Start int
Length int
Value BodyRangeValue
}
type BodyRangeList []BodyRange
var _ sort.Interface = BodyRangeList(nil)
func (b BodyRangeList) Len() int {
return len(b)
}
func (b BodyRangeList) Less(i, j int) bool {
return b[i].Start < b[j].Start || b[i].Length > b[j].Length
}
func (b BodyRangeList) Swap(i, j int) {
b[i], b[j] = b[j], b[i]
}
func (b BodyRange) String() string {
return fmt.Sprintf("%d:%d:%v", b.Start, b.Length, b.Value)
}
// End returns the end index of the range.
func (b BodyRange) End() int {
return b.Start + b.Length
}
// Offset changes the start of the range without affecting the length.
func (b BodyRange) Offset(offset int) *BodyRange {
b.Start += offset
return &b
}
// TruncateStart changes the length of the range, so it starts at the given
// index and ends at the same index as before.
func (b BodyRange) TruncateStart(startAt int) *BodyRange {
if b.Start < startAt {
b.Length -= startAt - b.Start
b.Start = startAt
}
return &b
}
// TruncateEnd changes the length of the range, so it ends at or before the
// given index and starts at the same index as before.
func (b BodyRange) TruncateEnd(maxEnd int) *BodyRange {
if b.End() > maxEnd {
b.Length = maxEnd - b.Start
}
return &b
}
// LinkedRangeTree is a linked tree of formatting entities.
//
// It's meant to parse a list of Telegram entity ranges into nodes that either
// overlap completely or not at all, which enables more natural conversion to
// HTML.
type LinkedRangeTree struct {
Node *BodyRange
Sibling *LinkedRangeTree
Child *LinkedRangeTree
}
func ptrAdd(to **LinkedRangeTree, r *BodyRange) {
if *to == nil {
*to = &LinkedRangeTree{}
}
(*to).Add(r)
}
// Add adds the given formatting entity to this tree.
func (lrt *LinkedRangeTree) Add(r *BodyRange) {
if lrt.Node == nil {
lrt.Node = r
return
}
lrtEnd := lrt.Node.End()
if r.Start >= lrtEnd {
ptrAdd(&lrt.Sibling, r.Offset(-lrtEnd))
return
}
if r.End() > lrtEnd {
ptrAdd(&lrt.Sibling, r.TruncateStart(lrtEnd).Offset(-lrtEnd))
}
ptrAdd(&lrt.Child, r.TruncateEnd(lrtEnd).Offset(-lrt.Node.Start))
}