▍ humdrum codex / glint v1.0.2
license AGPL-3.0
2.9 KB raw
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
package editor

import (
	"testing"

	"glint/internal/theme"

	"github.com/charmbracelet/lipgloss"
)

func segText(segs []segment) string {
	s := ""
	for _, sg := range segs {
		s += sg.text
	}
	return s
}

func TestWrapLineFitsReturnsOneSegment(t *testing.T) {
	segs := wrapLine("short line", 80)
	if len(segs) != 1 || segs[0].text != "short line" || segs[0].start != 0 {
		t.Fatalf("segs = %#v", segs)
	}
}

func TestWrapLineEmpty(t *testing.T) {
	segs := wrapLine("", 80)
	if len(segs) != 1 || segs[0].text != "" || segs[0].start != 0 {
		t.Fatalf("empty line segs = %#v", segs)
	}
}

func TestWrapLineWordBreakPartition(t *testing.T) {
	line := "aaaa bbbb cccc"
	segs := wrapLine(line, 9)
	if segText(segs) != line {
		t.Errorf("partition broken: %q != %q", segText(segs), line)
	}
	if len(segs) != 2 {
		t.Fatalf("want 2 segments, got %d: %#v", len(segs), segs)
	}
	if segs[0].text != "aaaa " || segs[0].start != 0 {
		t.Errorf("seg0 = %#v", segs[0])
	}
	if segs[1].text != "bbbb cccc" || segs[1].start != 5 {
		t.Errorf("seg1 = %#v", segs[1])
	}
}

func TestWrapLineHardBreaksLongWord(t *testing.T) {
	segs := wrapLine("abcdefghij", 4)
	if segText(segs) != "abcdefghij" {
		t.Errorf("partition broken: %q", segText(segs))
	}
	want := []segment{{"abcd", 0}, {"efgh", 4}, {"ij", 8}}
	if len(segs) != len(want) {
		t.Fatalf("got %d segments, want %d", len(segs), len(want))
	}
	for i := range want {
		if segs[i] != want[i] {
			t.Errorf("seg[%d] = %#v, want %#v", i, segs[i], want[i])
		}
	}
}

func TestWrapLineMultibytePartition(t *testing.T) {
	line := "héllo wörld café"
	segs := wrapLine(line, 7)
	if segText(segs) != line {
		t.Errorf("multibyte partition broken: %q != %q", segText(segs), line)
	}
}

func TestSliceSpansAcrossBoundary(t *testing.T) {
	red := lipgloss.NewStyle().Foreground(lipgloss.Color("#ff0000"))
	blue := lipgloss.NewStyle().Foreground(lipgloss.Color("#0000ff"))
	spans := []Span{{Text: "abc", Style: red}, {Text: "def", Style: blue}}
	out := sliceSpans(spans, 2, 5) // "c" (red) + "de" (blue)
	got := ""
	for _, sp := range out {
		got += sp.Text
	}
	if got != "cde" {
		t.Errorf("sliced text = %q, want cde", got)
	}
	if len(out) != 2 || out[0].Style.GetForeground() != lipgloss.Color("#ff0000") ||
		out[1].Style.GetForeground() != lipgloss.Color("#0000ff") {
		t.Errorf("styles not preserved: %#v", out)
	}
}

func TestBuildVisualAndCursorIndex(t *testing.T) {
	e := New()
	e.SetTheme(theme.FlexokiDark())
	e.Lines = []string{"aaaa bbbb cccc", "x"}
	e.Width = 9
	rows := e.buildVisual()
	// line 0 wraps into 2 visual rows, line 1 is 1 → 3 total.
	if len(rows) != 3 {
		t.Fatalf("visual rows = %d, want 3", len(rows))
	}
	// cursor at end of seg2 of line 0 maps to the second visual row.
	if got := cursorVIndex(rows, Position{Row: 0, Col: 10}); got != 1 {
		t.Errorf("cursorVIndex = %d, want 1", got)
	}
	// cursor on line 1 maps to row index 2.
	if got := cursorVIndex(rows, Position{Row: 1, Col: 0}); got != 2 {
		t.Errorf("cursorVIndex(line1) = %d, want 2", got)
	}
}