v0.15.0 6b178f8

shell_escape_test.go RawHistoryFolder

1package modes
2
3import (
4	"context"
5	"runtime"
6	"strings"
7	"testing"
8	"time"
9
10	"github.com/bnema/zut/packages/core"
11)
12
13func TestShellEscapeAddsOutputToAgentContext(t *testing.T) {
14	agent := core.NewAgent(nil, "", "", nil)
15	i := NewInteractive(InteractiveConfig{Agent: agent, CWD: t.TempDir()})
16	cmd := "printf zut-shell-context"
17	if runtime.GOOS == "windows" {
18		cmd = "echo zut-shell-context"
19	}
20
21	i.startShellEscape(context.Background(), cmd)
22
23	deadline := time.Now().Add(5 * time.Second)
24	for time.Now().Before(deadline) {
25		messages := agent.Messages()
26		i.mu.Lock()
27		running := i.shellRunning
28		i.mu.Unlock()
29		if len(messages) == 1 && !running {
30			text := userMessageText(messages[0])
31			if !strings.Contains(text, "zut-shell-context") {
32				t.Fatalf("shell context = %q, want command output", text)
33			}
34			if messages[0].Meta[shellEscapeMetaKey] != "true" {
35				t.Fatalf("shell context metadata = %v", messages[0].Meta)
36			}
37			return
38		}
39		time.Sleep(10 * time.Millisecond)
40	}
41	t.Fatal("shell output was not appended to agent context")
42}
43
44func TestShellEscapeCommand(t *testing.T) {
45	cases := []struct {
46		in      string
47		wantCmd string
48		wantOK  bool
49	}{
50		{"!ls -la", "ls -la", true},
51		{"  !pwd", "pwd", true},
52		{"!  go test ./...  ", "go test ./...", true},
53		{"!", "", false},
54		{"!   ", "", false},
55		{"ls -la", "", false},
56		{"/help", "", false},
57		{"hello !world", "", false},
58	}
59	for _, c := range cases {
60		cmd, ok := shellEscapeCommand(c.in)
61		if ok != c.wantOK || cmd != c.wantCmd {
62			t.Errorf("shellEscapeCommand(%q) = (%q,%v); want (%q,%v)",
63				c.in, cmd, ok, c.wantCmd, c.wantOK)
64		}
65	}
66}

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