Clasp directives to the following span as required by XEP-0393
This commit is contained in:
parent
ae8152ad87
commit
c6556eb6b8
|
@ -2,6 +2,7 @@ package formatter
|
|||
|
||||
import (
|
||||
"sort"
|
||||
"unicode"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/zelenin/go-tdlib/client"
|
||||
|
@ -118,6 +119,54 @@ func MergeAdjacentEntities(entities []*client.TextEntity) []*client.TextEntity {
|
|||
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) {
|
||||
return &Insertion{
|
||||
Offset: entity.Offset,
|
||||
|
@ -191,7 +240,7 @@ func Format(
|
|||
return sourceText
|
||||
}
|
||||
|
||||
mergedEntities := SortEntities(MergeAdjacentEntities(SortEntities(entities)))
|
||||
mergedEntities := SortEntities(ClaspDirectives(sourceText, MergeAdjacentEntities(SortEntities(entities))))
|
||||
|
||||
startStack := make(InsertionStack, 0, len(sourceText))
|
||||
endStack := make(InsertionStack, 0, len(sourceText))
|
||||
|
|
|
@ -392,3 +392,83 @@ func TestFormattingXEP0393Strikethrough(t *testing.T) {
|
|||
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)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue