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
|
package editor
import (
"strings"
"testing"
"glint/internal/theme"
"github.com/charmbracelet/lipgloss"
)
// tkBadges returns the set of span texts rendered with the TK badge background
// (theme.TK). A badge span carries theme.TK as its background color.
func tkBadges(e *Editor) map[string]bool {
tk := e.theme.TK
got := map[string]bool{}
for _, vr := range e.buildVisual() {
for _, sp := range vr.spans {
if bg, ok := sp.Style.GetBackground().(lipgloss.Color); ok && bg == tk {
got[sp.Text] = true
}
}
}
return got
}
func tkEditor(t *testing.T, content string) *Editor {
t.Helper()
e := New()
e.SetTheme(theme.FlexokiDark())
e.SetContent([]byte(content))
return e
}
func TestTKHighlightsWholeWordMarkers(t *testing.T) {
e := tkEditor(t, "Interview TK people about the $TK budget. Deadline TKTK.")
badges := tkBadges(e)
for _, want := range []string{"TK", "TKTK"} {
if !badges[want] {
t.Errorf("expected %q rendered as a TK badge; got badges %v", want, badges)
}
}
}
func TestTKCaseInsensitive(t *testing.T) {
e := tkEditor(t, "fill in tk here and Tk there")
badges := tkBadges(e)
if !badges["tk"] || !badges["Tk"] {
t.Errorf("expected lowercase tk and Tk badged; got %v", badges)
}
}
func TestTKNotInsideRealWords(t *testing.T) {
e := tkEditor(t, "The catkin on the network near Atkins and outkast")
if badges := tkBadges(e); len(badges) != 0 {
t.Errorf("no whole-word TK here; expected no badges, got %v", badges)
}
}
func TestTKSkipsCodeFiles(t *testing.T) {
e := tkEditor(t, "TK placeholder")
e.SetLanguage("main.go") // code file: TK highlighting off, like spellcheck
if badges := tkBadges(e); len(badges) != 0 {
t.Errorf("TK should not render in code files; got %v", badges)
}
}
func TestTKSkipsFrontmatter(t *testing.T) {
e := tkEditor(t, "---\ntitle: TK\n---\nBody TK here")
badges := tkBadges(e)
if badges["title: TK"] || countTKBadges(e, 1) > 1 {
t.Errorf("frontmatter TK should not badge; got %v", badges)
}
if !badges["TK"] {
t.Errorf("body TK should still badge; got %v", badges)
}
}
// countTKBadges counts badge spans whose text is exactly "TK".
func countTKBadges(e *Editor, _ int) int {
tk := e.theme.TK
n := 0
for _, vr := range e.buildVisual() {
for _, sp := range vr.spans {
if bg, ok := sp.Style.GetBackground().(lipgloss.Color); ok && bg == tk && sp.Text == "TK" {
n++
}
}
}
return n
}
// TestTKPreservesLineText guards the markup-visible invariant: badging TK must not
// add or drop any characters, so the concatenated span text equals the raw line.
func TestTKPreservesLineText(t *testing.T) {
const line = "Interview TK people; page TK; TKTK."
e := tkEditor(t, line)
var b strings.Builder
for _, vr := range e.buildVisual() {
for _, sp := range vr.spans {
b.WriteString(sp.Text)
}
}
if got := b.String(); got != line {
t.Errorf("span text concatenation = %q, want %q", got, line)
}
}
|