소스 검색

pkg/ui: Add NormalizeText.

Qi Xiao 1 년 전
부모
커밋
975e68c584
2개의 변경된 파일84개의 추가작업 그리고 0개의 파일을 삭제
  1. 41 0
      pkg/ui/text.go
  2. 43 0
      pkg/ui/text_test.go

+ 41 - 0
pkg/ui/text.go

@@ -29,6 +29,47 @@ func Concat(texts ...Text) Text {
 	return ret
 }
 
+// NormalizeText converts a Text to a normal form:
+//
+//   - If the Text is empty or only contains empty segments, the normal form is
+//     nil.
+//
+//   - Otherwise the normal form contains no empty segments, and no adjacent
+//     segments with the same style.
+//
+// The normal forms can be more easily compared.
+func NormalizeText(t Text) Text {
+	// Find first non-empty segment
+	first := 0
+	for first < len(t) && t[first].Text == "" {
+		first++
+	}
+	if first == len(t) {
+		return nil
+	}
+	var normal Text
+	var segText strings.Builder
+	segText.WriteString(t[first].Text)
+	segStyle := t[first].Style
+	for _, seg := range t[first+1:] {
+		if seg.Text == "" {
+			continue
+		}
+		if seg.Style == segStyle {
+			segText.WriteString(seg.Text)
+		} else {
+			normal = append(normal, &Segment{segStyle, segText.String()})
+			segText.Reset()
+			segText.WriteString(seg.Text)
+			segStyle = seg.Style
+		}
+	}
+	if segText.Len() > 0 {
+		normal = append(normal, &Segment{segStyle, segText.String()})
+	}
+	return normal
+}
+
 // Kind returns "styled-text".
 func (Text) Kind() string { return "ui:text" }
 

+ 43 - 0
pkg/ui/text_test.go

@@ -1,6 +1,7 @@
 package ui
 
 import (
+	"reflect"
 	"testing"
 
 	"src.elv.sh/pkg/eval/vals"
@@ -39,6 +40,48 @@ var (
 func red(s string) *Segment  { return &Segment{Style{Foreground: Red}, s} }
 func blue(s string) *Segment { return &Segment{Style{Foreground: Blue}, s} }
 
+var normalizeTextTests = []struct {
+	name   string
+	before Text
+	after  Text
+}{
+	{
+		name:   "empty text",
+		before: Text{},
+		after:  nil,
+	},
+	{
+		name:   "text with only empty segments",
+		before: Text{&Segment{}, &Segment{}},
+		after:  nil,
+	},
+	{
+		name:   "consecutive segments with the same style are merged",
+		before: Concat(T("a"), T("b")), after: T("ab"),
+	},
+	{
+		name:   "segments with different styles are kept separate",
+		before: Concat(T("a"), T("b", Bold)),
+		after:  Concat(T("a"), T("b", Bold)),
+	},
+	{
+		name:   "segments with the same style separated by empty segments are merged",
+		before: Concat(T("a", Bold), T(""), T("b", Bold)),
+		after:  T("ab", Bold),
+	},
+}
+
+func TestNormalizeText(t *testing.T) {
+	for _, tc := range normalizeTextTests {
+		t.Run(tc.name, func(t *testing.T) {
+			got := NormalizeText(tc.before)
+			if !reflect.DeepEqual(got, tc.after) {
+				t.Errorf("NormalizeText(%v) -> %v, want %v", tc.before, got, tc.after)
+			}
+		})
+	}
+}
+
 var partitionTests = tt.Table{
 	Args(text0).Rets([]Text{nil}),
 	Args(text1).Rets([]Text{text1}),