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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
package editor
import (
"testing"
tea "github.com/charmbracelet/bubbletea"
)
// sel sets a selection from (ar,ac) to (cr,cc) (anchor → cursor).
func sel(e *Editor, ar, ac, cr, cc int) {
a := Position{Row: ar, Col: ac}
e.anchor = &a
e.Cursor = Position{Row: cr, Col: cc}
}
func TestWrapBoldNoSelectionInsertsPair(t *testing.T) {
e := newEditorWith("")
e.WrapBold()
if e.Lines[0] != "****" {
t.Fatalf("Lines[0] = %q, want %q", e.Lines[0], "****")
}
if e.Cursor.Col != 2 {
t.Fatalf("Cursor.Col = %d, want 2 (between markers)", e.Cursor.Col)
}
}
func TestWrapBoldWrapsSelection(t *testing.T) {
e := newEditorWith("word")
sel(e, 0, 0, 0, 4)
e.WrapBold()
if e.Lines[0] != "**word**" {
t.Fatalf("Lines[0] = %q, want %q", e.Lines[0], "**word**")
}
if got := e.SelectedText(); got != "word" {
t.Fatalf("selection = %q, want inner %q", got, "word")
}
}
func TestWrapBoldTogglesOffMarkersInsideSelection(t *testing.T) {
e := newEditorWith("**word**")
sel(e, 0, 0, 0, 8)
e.WrapBold()
if e.Lines[0] != "word" {
t.Fatalf("Lines[0] = %q, want %q", e.Lines[0], "word")
}
if got := e.SelectedText(); got != "word" {
t.Fatalf("selection = %q, want %q", got, "word")
}
}
func TestWrapBoldTogglesOffMarkersOutsideSelection(t *testing.T) {
e := newEditorWith("**word**")
sel(e, 0, 2, 0, 6) // select just "word", markers sit outside
e.WrapBold()
if e.Lines[0] != "word" {
t.Fatalf("Lines[0] = %q, want %q", e.Lines[0], "word")
}
if got := e.SelectedText(); got != "word" {
t.Fatalf("selection = %q, want %q", got, "word")
}
}
func TestWrapItalicUsesUnderscore(t *testing.T) {
e := newEditorWith("hi")
sel(e, 0, 0, 0, 2)
e.WrapItalic()
if e.Lines[0] != "_hi_" {
t.Fatalf("Lines[0] = %q, want %q", e.Lines[0], "_hi_")
}
}
func TestWrapCodeUsesBacktick(t *testing.T) {
e := newEditorWith("x")
sel(e, 0, 0, 0, 1)
e.WrapCode()
if e.Lines[0] != "`x`" {
t.Fatalf("Lines[0] = %q, want %q", e.Lines[0], "`x`")
}
}
func TestWrapLinkWrapsSelectionCursorInParens(t *testing.T) {
e := newEditorWith("text")
sel(e, 0, 0, 0, 4)
e.WrapLink()
if e.Lines[0] != "[text]()" {
t.Fatalf("Lines[0] = %q, want %q", e.Lines[0], "[text]()")
}
// cursor parked inside the () — just before the closing paren
if e.Cursor.Col != 7 {
t.Fatalf("Cursor.Col = %d, want 7 (inside parens)", e.Cursor.Col)
}
if e.HasSelection() {
t.Fatal("link wrap should collapse selection")
}
}
func TestWrapLinkNoSelectionCursorInBrackets(t *testing.T) {
e := newEditorWith("")
e.WrapLink()
if e.Lines[0] != "[]()" {
t.Fatalf("Lines[0] = %q, want %q", e.Lines[0], "[]()")
}
if e.Cursor.Col != 1 {
t.Fatalf("Cursor.Col = %d, want 1 (inside brackets)", e.Cursor.Col)
}
}
func TestWrapLinkTogglesOff(t *testing.T) {
e := newEditorWith("[text](url)")
sel(e, 0, 0, 0, 11)
e.WrapLink()
if e.Lines[0] != "text" {
t.Fatalf("Lines[0] = %q, want %q", e.Lines[0], "text")
}
}
func TestAltSKeyBoldsAsOneUndoGroup(t *testing.T) {
e := newEditorWith("word")
sel(e, 0, 0, 0, 4)
e.HandleKey(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("s"), Alt: true})
if e.Lines[0] != "**word**" {
t.Fatalf("Lines[0] = %q, want %q", e.Lines[0], "**word**")
}
e.Undo()
if e.Lines[0] != "word" {
t.Fatalf("after undo Lines[0] = %q, want %q", e.Lines[0], "word")
}
}
|