copy_mouse_map_test.go RawHistoryFolder

1package daemon
2
3import (
4	"testing"
5
6	"github.com/stretchr/testify/require"
7
8	renderer "github.com/bnema/vev-vt"
9	"github.com/bnema/vev/internal/domain"
10	scopy "github.com/bnema/vev/internal/usecase/copy"
11	"github.com/bnema/vev/internal/usecase/mouse"
12)
13
14func TestCopyMouseMapTopBarAndContent(t *testing.T) {
15	p := newPane("pane", nil, domain.Size{Cols: 5, Rows: 2})
16	doc := scopy.NewDocument(scopy.NewSnapshotFromRows([][]renderer.Cell{testRow("alpha"), testRow("bravo")}, 5, 2), domain.DefaultWordSeparators)
17	geometry := copyMouseGeometry{pane: p, content: domain.Rect{X: 0, Y: 1, Width: 5, Height: 2}}
18
19	_, ok := mapCopyMouse(mouse.Event{Col: 0, Row: 0}, geometry, 0, doc, false)
20	require.False(t, ok)
21	mapped, ok := mapCopyMouse(mouse.Event{Col: 0, Row: 1}, geometry, 0, doc, false)
22	require.True(t, ok)
23	require.Same(t, p, mapped.pane)
24	require.Equal(t, scopy.Pos{Row: 0, Col: 0}, mapped.pos)
25	mapped, ok = mapCopyMouse(mouse.Event{Col: 4, Row: 2}, geometry, 0, doc, false)
26	require.True(t, ok)
27	require.Equal(t, scopy.Pos{Row: 1, Col: 4}, mapped.pos)
28	_, ok = mapCopyMouse(mouse.Event{Col: 0, Row: 3}, geometry, 0, doc, false)
29	require.False(t, ok, "bottom status is not content")
30}
31
32func TestCopyMouseMapClampsAndNormalizesWideCells(t *testing.T) {
33	p := newPane("pane", nil, domain.Size{Cols: 4, Rows: 1})
34	doc := scopy.NewDocument(scopy.NewSnapshotFromRows([][]renderer.Cell{{{Rune: 'a'}, {Rune: '界'}, {Continuation: true}, {Rune: 'b'}}}, 4, 1), domain.DefaultWordSeparators)
35	geometry := copyMouseGeometry{pane: p, content: domain.Rect{X: 3, Y: 1, Width: 4, Height: 1}}
36
37	mapped, ok := mapCopyMouse(mouse.Event{Col: 5, Row: 1}, geometry, 0, doc, false)
38	require.True(t, ok)
39	require.Equal(t, scopy.Pos{Row: 0, Col: 1}, mapped.pos)
40	mapped, ok = mapCopyMouse(mouse.Event{Col: 99, Row: 99}, geometry, 0, doc, true)
41	require.True(t, ok)
42	require.Equal(t, scopy.Pos{Row: 0, Col: 3}, mapped.pos)
43}
44
45func TestCopyMouseMapSplitAndFloatingRects(t *testing.T) {
46	p := newPane("pane", nil, domain.Size{Cols: 4, Rows: 2})
47	doc := scopy.NewDocument(scopy.NewSnapshotFromRows([][]renderer.Cell{testRow("abcd"), testRow("efgh")}, 4, 2), domain.DefaultWordSeparators)
48	for _, tc := range []struct {
49		name     string
50		geometry domain.Rect
51		ev       mouse.Event
52		want     scopy.Pos
53		ok       bool
54	}{
55		{"split content", domain.Rect{X: 21, Y: 2, Width: 4, Height: 2}, mouse.Event{Col: 23, Row: 3}, scopy.Pos{Row: 1, Col: 2}, true},
56		{"split title", domain.Rect{X: 21, Y: 2, Width: 4, Height: 2}, mouse.Event{Col: 21, Row: 1}, scopy.Pos{}, false},
57		{"floating inner", domain.Rect{X: 10, Y: 5, Width: 4, Height: 2}, mouse.Event{Col: 11, Row: 5}, scopy.Pos{Row: 0, Col: 1}, true},
58		{"floating border", domain.Rect{X: 10, Y: 5, Width: 4, Height: 2}, mouse.Event{Col: 9, Row: 5}, scopy.Pos{}, false},
59	} {
60		t.Run(tc.name, func(t *testing.T) {
61			mapped, ok := mapCopyMouse(tc.ev, copyMouseGeometry{pane: p, content: tc.geometry}, 0, doc, false)
62			require.Equal(t, tc.ok, ok)
63			if ok {
64				require.Equal(t, tc.want, mapped.pos)
65			}
66		})
67	}
68}
69
70func TestCopyMouseGeometryUsesClientFrameExactlyOnce(t *testing.T) {
71	p, release := newBlockingPTY(t)
72	defer release()
73	d, sess, _, _ := newManualSessionWithPTYs(t, p)
74	tb := testAttachmentTab(sess)
75
76	tb.mu.Lock()
77	geometry, ok := hitTestCopyMouseGeometryLocked(tb, d.currentFloatingConfig(), 0, 1)
78	tb.mu.Unlock()
79	require.True(t, ok)
80	require.Equal(t, 1, geometry.content.Y)
81	_, ok = mapCopyMouse(mouse.Event{Col: 0, Row: 1}, geometry, 0,
82		scopy.NewDocument(scopy.NewSnapshotFromRows([][]renderer.Cell{testRow("a")}, 80, 1), domain.DefaultWordSeparators), false)
83	require.True(t, ok)
84}

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 12

Tags 11

↑↓ moveenter openesc close