Clasp directives to the following span as required by XEP-0393

This commit is contained in:
Bohdan Horbeshko 2022-03-11 20:27:15 -05:00
parent ae8152ad87
commit c6556eb6b8
2 changed files with 130 additions and 1 deletions

View file

@ -2,6 +2,7 @@ package formatter
import ( import (
"sort" "sort"
"unicode"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/zelenin/go-tdlib/client" "github.com/zelenin/go-tdlib/client"
@ -118,6 +119,54 @@ func MergeAdjacentEntities(entities []*client.TextEntity) []*client.TextEntity {
return mergedEntities return mergedEntities
} }
// ClaspDirectives to the following span as required by XEP-0393
func ClaspDirectives(text string, entities []*client.TextEntity) []*client.TextEntity {
alignedEntities := make([]*client.TextEntity, len(entities))
copy(alignedEntities, entities)
// transform the source text into a form with uniform runes and code points,
// by duplicating the Basic Multilingual Plane
doubledRunes := make([]rune, 0, len(text)*2)
for _, cp := range text {
if cp > 0x0000ffff {
doubledRunes = append(doubledRunes, cp, cp)
} else {
doubledRunes = append(doubledRunes, cp)
}
}
for i, entity := range alignedEntities {
var dirty bool
endOffset := entity.Offset + entity.Length
if unicode.IsSpace(doubledRunes[entity.Offset]) {
for j, r := range doubledRunes[entity.Offset+1:endOffset] {
if !unicode.IsSpace(r) {
dirty = true
entity.Offset += int32(j+1)
entity.Length -= int32(j+1)
break
}
}
}
if unicode.IsSpace(doubledRunes[endOffset-1]) {
for j := endOffset-2; j >= entity.Offset; j-- {
if !unicode.IsSpace(doubledRunes[j]) {
dirty = true
entity.Length = j+1-entity.Offset
break
}
}
}
if dirty {
alignedEntities[i] = entity
}
}
return alignedEntities
}
func markupBraces(entity *client.TextEntity, lbrace, rbrace []rune) (*Insertion, *Insertion) { func markupBraces(entity *client.TextEntity, lbrace, rbrace []rune) (*Insertion, *Insertion) {
return &Insertion{ return &Insertion{
Offset: entity.Offset, Offset: entity.Offset,
@ -191,7 +240,7 @@ func Format(
return sourceText return sourceText
} }
mergedEntities := SortEntities(MergeAdjacentEntities(SortEntities(entities))) mergedEntities := SortEntities(ClaspDirectives(sourceText, MergeAdjacentEntities(SortEntities(entities))))
startStack := make(InsertionStack, 0, len(sourceText)) startStack := make(InsertionStack, 0, len(sourceText))
endStack := make(InsertionStack, 0, len(sourceText)) endStack := make(InsertionStack, 0, len(sourceText))

View file

@ -392,3 +392,83 @@ func TestFormattingXEP0393Strikethrough(t *testing.T) {
t.Errorf("Wrong strikethrough formatting: %v", markup) t.Errorf("Wrong strikethrough formatting: %v", markup)
} }
} }
func TestClaspLeft(t *testing.T) {
text := "a b c"
entities := []*client.TextEntity{
&client.TextEntity{
Offset: 1,
Length: 2,
},
}
entities = ClaspDirectives(text, entities)
if !(len(entities) == 1 &&
entities[0].Offset == 2 && entities[0].Length == 1) {
t.Errorf("Wrong claspleft: %#v", entities)
}
}
func TestClaspBoth(t *testing.T) {
text := "a b c"
entities := []*client.TextEntity{
&client.TextEntity{
Offset: 1,
Length: 3,
},
}
entities = ClaspDirectives(text, entities)
if !(len(entities) == 1 &&
entities[0].Offset == 2 && entities[0].Length == 1) {
t.Errorf("Wrong claspboth: %#v", entities)
}
}
func TestClaspNotNeeded(t *testing.T) {
text := " abc "
entities := []*client.TextEntity{
&client.TextEntity{
Offset: 1,
Length: 3,
},
}
entities = ClaspDirectives(text, entities)
if !(len(entities) == 1 &&
entities[0].Offset == 1 && entities[0].Length == 3) {
t.Errorf("Wrong claspnotneeded: %#v", entities)
}
}
func TestClaspNested(t *testing.T) {
text := "a b c"
entities := []*client.TextEntity{
&client.TextEntity{
Offset: 1,
Length: 3,
},
&client.TextEntity{
Offset: 2,
Length: 2,
},
}
entities = ClaspDirectives(text, entities)
if !(len(entities) == 2 &&
entities[0].Offset == 2 && entities[0].Length == 1 &&
entities[1].Offset == 2 && entities[1].Length == 1) {
t.Errorf("Wrong claspnested: %#v", entities)
}
}
func TestClaspEmoji(t *testing.T) {
text := "a 🐖 c"
entities := []*client.TextEntity{
&client.TextEntity{
Offset: 1,
Length: 4,
},
}
entities = ClaspDirectives(text, entities)
if !(len(entities) == 1 &&
entities[0].Offset == 2 && entities[0].Length == 2) {
t.Errorf("Wrong claspemoji: %#v", entities)
}
}