hover_test.go RawHistoryFolder

1package input
2
3import (
4	"context"
5	"reflect"
6	"testing"
7
8	"github.com/bnema/dumber/internal/domain/entity"
9	"github.com/bnema/puregotk/v4/gtk"
10)
11
12func TestHoverHandlerSchedulesCallbackOnGLibAndRejectsStaleGeneration(t *testing.T) {
13	h := NewHoverHandler(context.Background(), entity.PaneID("pane-1"))
14	var scheduled func(uintptr) bool
15	h.schedule = func(_ uint, fn func(uintptr) bool) uint {
16		scheduled = fn
17		return 7
18	}
19
20	var calls int
21	h.SetOnEnter(func(entity.PaneID) { calls++ })
22	h.handleEnter()
23	first := scheduled
24	h.handleEnter()
25	if first(0) {
26		t.Fatal("hover source must be one-shot")
27	}
28	if calls != 0 {
29		t.Fatalf("stale hover callback ran %d times", calls)
30	}
31	if scheduled == nil {
32		t.Fatal("current hover callback was not scheduled")
33	}
34	if scheduled(0) {
35		t.Fatal("hover source must be one-shot")
36	}
37	if calls != 1 {
38		t.Fatalf("current hover callback ran %d times, want 1", calls)
39	}
40}
41
42func TestHoverHandlerDetachRemovesNativeControllerAndSignalsExactlyOnce(t *testing.T) {
43	widget := &gtk.Widget{}
44	controller := &gtk.EventControllerMotion{}
45	h := NewHoverHandler(context.Background(), entity.PaneID("pane-1"))
46	h.attachedWidget = widget
47	h.motionCtrl = controller
48	h.enterSignalID = 1
49	h.leaveSignalID = 2
50	h.motionSignalID = 3
51	var disconnected []uint
52	var removed int
53	h.disconnectSignal = func(_ *gtk.EventControllerMotion, id uint) { disconnected = append(disconnected, id) }
54	h.removeController = func(gotWidget *gtk.Widget, gotController *gtk.EventController) {
55		if gotWidget != widget || gotController != &controller.EventController {
56			t.Fatal("detach removed the wrong native controller")
57		}
58		removed++
59	}
60
61	h.Detach()
62	h.Detach()
63
64	if got, want := disconnected, []uint{1, 2, 3}; !reflect.DeepEqual(got, want) {
65		t.Fatalf("disconnected signals = %v, want %v", got, want)
66	}
67	if removed != 1 {
68		t.Fatalf("native controllers removed = %d, want 1", removed)
69	}
70	if h.attachedWidget != nil || h.motionCtrl != nil || h.enterCb != nil || h.leaveCb != nil || h.motionCb != nil {
71		t.Fatal("detach must clear native and callback ownership")
72	}
73}
74
75func TestHoverHandlerDetachInvalidatesScheduledCallbackAndRemovesSource(t *testing.T) {
76	h := NewHoverHandler(context.Background(), entity.PaneID("pane-1"))
77	var scheduled func(uintptr) bool
78	var removed []uint
79	h.schedule = func(_ uint, fn func(uintptr) bool) uint { scheduled = fn; return 9 }
80	h.removeSource = func(id uint) bool { removed = append(removed, id); return true }
81	h.SetOnEnter(func(entity.PaneID) { t.Fatal("detached hover callback ran") })
82	h.handleEnter()
83	h.Detach()
84	if len(removed) != 1 || removed[0] != 9 {
85		t.Fatalf("removed sources = %v, want [9]", removed)
86	}
87	if scheduled == nil || scheduled(0) {
88		t.Fatal("detached callback must be rejected and one-shot")
89	}
90}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close