turbo-editors/turbo-corepublic Fork 0
28d59854361aeda8541d853093e732126f3d7bff
Commits
Clone
git clone https://git.rickub.com/turbo-editors/turbo-core.git
git clone ssh://git@rickub.com/turbo-editors/turbo-core.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

click_test.go · 140 lines · 4.7 KBGo Blame HistoryRaw
🛟 Updated. 28d5985 k33g 19h ago1package editor
2
3import (
4 "testing"
5 "time"
6
7 "github.com/gdamore/tcell/v2"
8)
9
10// clickingView returns a view onto text with a clock the test drives, so a
11// double click is a matter of what the test says rather than of how fast the
12// machine is.
13func clickingView(t *testing.T, text string) (*View, tcell.SimulationScreen, *time.Time) {
14 t.Helper()
15
16 view, screen, _ := newTestView(t, text, 40, 8)
17 moment := time.Date(2026, 9, 2, 12, 0, 0, 0, time.UTC)
18 view.SetClock(func() time.Time { return moment })
19 return view, screen, &moment
20}
21
22// press sends one button-down at a cell, then the button-up that ends it.
23func pressAt(view *View, x, y int) {
24 view.HandleMouse(tcell.NewEventMouse(x, y, tcell.Button1, tcell.ModNone))
25 view.HandleMouse(tcell.NewEventMouse(x, y, tcell.ButtonNone, tcell.ModNone))
26}
27
28func TestADoubleClickSelectsTheWord(t *testing.T) {
29 view, _, _ := clickingView(t, "func mainLoop() {}\n")
30 x := view.gutterWidth() + 8 // inside "mainLoop"
31
32 pressAt(view, x, 0)
33 pressAt(view, x, 0)
34
35 if got := view.Buffer().SelectedText(); got != "mainLoop" {
36 t.Errorf("the selection is %q, want %q", got, "mainLoop")
37 }
38}
39
40func TestASingleClickSelectsNothing(t *testing.T) {
41 view, _, _ := clickingView(t, "func mainLoop() {}\n")
42
43 pressAt(view, view.gutterWidth()+8, 0)
44
45 if got := view.Buffer().SelectedText(); got != "" {
46 t.Errorf("one click selected %q", got)
47 }
48}
49
50func TestTwoSlowClicksAreTwoClicks(t *testing.T) {
51 // Two unrelated clicks in the same place happen all the time while
52 // reading, and selecting a word each time would be noise.
53 view, _, moment := clickingView(t, "func mainLoop() {}\n")
54 x := view.gutterWidth() + 8
55
56 pressAt(view, x, 0)
57 *moment = moment.Add(doubleClickWithin + time.Millisecond)
58 pressAt(view, x, 0)
59
60 if got := view.Buffer().SelectedText(); got != "" {
61 t.Errorf("two clicks %v apart selected %q", doubleClickWithin, got)
62 }
63}
64
65func TestTwoClicksOnDifferentCellsAreTwoClicks(t *testing.T) {
66 // A press one column over is a different word, and selecting the first
67 // because the pointer drifted is worse than selecting nothing.
68 view, _, _ := clickingView(t, "alpha beta\n")
69
70 pressAt(view, view.gutterWidth()+1, 0)
71 pressAt(view, view.gutterWidth()+2, 0)
72
73 if got := view.Buffer().SelectedText(); got != "" {
74 t.Errorf("two clicks on different cells selected %q", got)
75 }
76}
77
78func TestADragIsNotASecondClick(t *testing.T) {
79 // tcell sends Button1 for every event of a drag. Counting those would
80 // turn a slow drag into a double click halfway through.
81 view, _, _ := clickingView(t, "alpha beta gamma\n")
82 x := view.gutterWidth()
83
84 view.HandleMouse(tcell.NewEventMouse(x+1, 0, tcell.Button1, tcell.ModNone))
85 for column := 2; column <= 9; column++ {
86 view.HandleMouse(tcell.NewEventMouse(x+column, 0, tcell.Button1, tcell.ModNone))
87 }
88 view.HandleMouse(tcell.NewEventMouse(x+9, 0, tcell.ButtonNone, tcell.ModNone))
89
90 if got := view.Buffer().SelectedText(); got != "lpha bet" {
91 t.Errorf("the drag selected %q, want the characters it crossed", got)
92 }
93}
94
95func TestADoubleClickOffAWordSelectsNothing(t *testing.T) {
96 view, _, _ := clickingView(t, "alpha beta\n")
97 x := view.gutterWidth() + 5 // the space
98
99 pressAt(view, x, 0)
100 pressAt(view, x, 0)
101
102 if got := view.Buffer().SelectedText(); got != "" {
103 t.Errorf("a double click on a space selected %q", got)
104 }
105}
106
107func TestHoldingAfterADoubleClickExtendsFromTheWordsStart(t *testing.T) {
108 // Not the word-by-word drag a large editor does — the cheap half of it.
109 // The alternative is the word collapsing back to a single character the
110 // moment the pointer twitches, which is worse than either.
111 view, _, _ := clickingView(t, "alpha beta\n")
112 x := view.gutterWidth() + 1
113
114 pressAt(view, x, 0) // first click, released
115 view.HandleMouse(tcell.NewEventMouse(x, 0, tcell.Button1, tcell.ModNone)) // second, and held
116 view.HandleMouse(tcell.NewEventMouse(x+7, 0, tcell.Button1, tcell.ModNone)) // dragged
117 view.HandleMouse(tcell.NewEventMouse(x+7, 0, tcell.ButtonNone, tcell.ModNone))
118
119 if got := view.Buffer().SelectedText(); got != "alpha be" {
120 t.Errorf("dragging after a double click left %q, want it extended from the word's start", got)
121 }
122}
123
124func TestAThirdClickIsCountedButDoesNothingYet(t *testing.T) {
125 // The counter keeps going so that a triple click can be given a meaning
126 // later without reworking any of this. Today it selects the word again.
127 view, _, _ := clickingView(t, "alpha beta\n")
128 x := view.gutterWidth() + 1
129
130 pressAt(view, x, 0)
131 pressAt(view, x, 0)
132 pressAt(view, x, 0)
133
134 if got := view.lastClick.count; got != 3 {
135 t.Errorf("the click count is %d, want 3", got)
136 }
137 if got := view.Buffer().SelectedText(); got != "alpha" {
138 t.Errorf("the third click left %q selected", got)
139 }
140}