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 (
|
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))
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue