v0.38.0 58133ea

clipboard_images_test.go RawHistoryFolder

1package modes
2
3import (
4	"strings"
5	"testing"
6
7	"github.com/bnema/zut/packages/core"
8	"github.com/bnema/zut/packages/provider"
9)
10
11func testClipboardImage(marker string, data string) clipboardImageAttachment {
12	return clipboardImageAttachment{
13		Marker: marker,
14		Image:  provider.ImageBlock{MimeType: "image/png", Data: []byte(data)},
15	}
16}
17
18func TestRestoredQueuedImageDoesNotConsumeLiteralClipboardMarker(t *testing.T) {
19	i := NewInteractive(InteractiveConfig{})
20	message := core.QueuedMessage{
21		Text:   "keep literal [clipboard image #1]",
22		Images: []provider.ImageBlock{{MimeType: "image/png", Data: []byte("png-1")}},
23	}
24
25	if !i.restoreQueuedMessageToEditor(message) {
26		t.Fatal("queued message was not restored")
27	}
28	text, images := preparePromptWithClipboardImages(i.ed.Value(), i.clipboardImages)
29
30	if text != message.Text {
31		t.Fatalf("resubmitted text = %q, want %q", text, message.Text)
32	}
33	if len(images) != 1 || string(images[0].Data) != "png-1" {
34		t.Fatalf("resubmitted images = %#v, want png-1", images)
35	}
36}
37
38func TestPreparePromptWithClipboardImagesStripsPresentMarker(t *testing.T) {
39	pending := []clipboardImageAttachment{testClipboardImage("[clipboard image #1]", "png-1")}
40
41	text, images := preparePromptWithClipboardImages("describe this [clipboard image #1] please", pending)
42
43	if text != "describe this please" {
44		t.Fatalf("text = %q, want %q", text, "describe this please")
45	}
46	if len(images) != 1 {
47		t.Fatalf("len(images) = %d, want 1", len(images))
48	}
49	if string(images[0].Data) != "png-1" {
50		t.Fatalf("image data = %q, want png-1", string(images[0].Data))
51	}
52}
53
54func TestPreparePromptWithClipboardImagesAllowsImageOnlyPrompt(t *testing.T) {
55	pending := []clipboardImageAttachment{testClipboardImage("[clipboard image #1]", "png-1")}
56
57	text, images := preparePromptWithClipboardImages("[clipboard image #1]", pending)
58
59	if text != "" {
60		t.Fatalf("text = %q, want empty", text)
61	}
62	if len(images) != 1 {
63		t.Fatalf("len(images) = %d, want 1", len(images))
64	}
65}
66
67func TestPreparePromptWithClipboardImagesIgnoresDeletedMarker(t *testing.T) {
68	pending := []clipboardImageAttachment{testClipboardImage("[clipboard image #1]", "png-1")}
69
70	text, images := preparePromptWithClipboardImages("describe this from memory", pending)
71
72	if text != "describe this from memory" {
73		t.Fatalf("text = %q, want unchanged", text)
74	}
75	if len(images) != 0 {
76		t.Fatalf("len(images) = %d, want 0", len(images))
77	}
78}
79
80func TestPreparePromptWithClipboardImagesHandlesMultipleImagesInPasteOrder(t *testing.T) {
81	pending := []clipboardImageAttachment{
82		testClipboardImage("[clipboard image #1]", "png-1"),
83		testClipboardImage("[clipboard image #2]", "png-2"),
84	}
85
86	text, images := preparePromptWithClipboardImages("compare [clipboard image #2] with [clipboard image #1]", pending)
87
88	if text != "compare with" {
89		t.Fatalf("text = %q, want %q", text, "compare with")
90	}
91	if len(images) != 2 {
92		t.Fatalf("len(images) = %d, want 2", len(images))
93	}
94	if string(images[0].Data) != "png-1" || string(images[1].Data) != "png-2" {
95		t.Fatalf("images not attached in paste order: %q, %q", string(images[0].Data), string(images[1].Data))
96	}
97}
98
99func TestPreparePromptWithClipboardImagesDuplicateMarkerAttachesOnce(t *testing.T) {
100	pending := []clipboardImageAttachment{testClipboardImage("[clipboard image #1]", "png-1")}
101
102	text, images := preparePromptWithClipboardImages("[clipboard image #1] and again [clipboard image #1]", pending)
103
104	if strings.Contains(text, "[clipboard image #1]") {
105		t.Fatalf("text still contains marker: %q", text)
106	}
107	if text != "and again" {
108		t.Fatalf("text = %q, want %q", text, "and again")
109	}
110	if len(images) != 1 {
111		t.Fatalf("len(images) = %d, want 1", len(images))
112	}
113}
114
115func TestPreparePromptWithClipboardImagesNoPendingPreservesWhitespace(t *testing.T) {
116	input := "please review:\n\nfunc main() {\n\tfmt.Println(\"hi\")\n}\n"
117
118	text, images := preparePromptWithClipboardImages(input, nil)
119
120	if text != input {
121		t.Fatalf("text changed without pending images:\n got %q\nwant %q", text, input)
122	}
123	if images != nil {
124		t.Fatalf("images = %#v, want nil", images)
125	}
126}
127
128func TestPreparePromptWithClipboardImagesPreservesMultilinePrompt(t *testing.T) {
129	pending := []clipboardImageAttachment{testClipboardImage("[clipboard image #1]", "png-1")}
130	input := "compare this image [clipboard image #1]\n\nwith this code:\n\treturn 1"
131	want := "compare this image\n\nwith this code:\n\treturn 1"
132
133	text, images := preparePromptWithClipboardImages(input, pending)
134
135	if text != want {
136		t.Fatalf("text = %q, want %q", text, want)
137	}
138	if len(images) != 1 {
139		t.Fatalf("len(images) = %d, want 1", len(images))
140	}
141}

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 1

Tags 476

↑↓ moveenter openesc close