registry.go RawHistoryFolder

1package command
2
3import "strings"
4
5// Registry returns all palette and control commands in stable display order.
6func Registry() []Command {
7	commands := []Command{
8		paletteControl("new-tab", "CNT", "New tab", "Create a new tab", TargetSession, func(ctx Context, _ []string) error { return ctx.CreateTab() }, func(ctx ControlContext) error { return ctx.CreateTab() }),
9		paletteOptionalOne("new-session", "CNS", "New session", "Create named session", TargetSession, func(ctx Context) error { return ctx.CreateSession() }, func(ctx Context, name string) error { return ctx.CreateSessionNamed(name) }, func(ctx ControlContext, name string) error { return ctx.CreateSessionNamed(name) }),
10		paletteOnly("create-ephemeral-session", "CES", "New ephemeral session", "Create ephemeral session", func(ctx Context, _ []string) error { return ctx.CreateEphemeralSession() }),
11		paletteControl("close-tab", "CLT", "Close tab", "Close the current tab", TargetTab, func(ctx Context, _ []string) error { return ctx.CloseTab() }, func(ctx ControlContext) error { return ctx.CloseTab() }),
12		paletteControl("split-right", "SPR", "Split right", "Split the focused pane to the right", TargetPane, func(ctx Context, _ []string) error { return ctx.SplitRight() }, func(ctx ControlContext) error { return ctx.SplitRight() }),
13		paletteControl("split-left", "SPL", "Split left", "Split the focused pane to the left", TargetPane, func(ctx Context, _ []string) error { return ctx.SplitLeft() }, func(ctx ControlContext) error { return ctx.SplitLeft() }),
14		paletteControl("split-up", "SPU", "Split up", "Split the focused pane upward", TargetPane, func(ctx Context, _ []string) error { return ctx.SplitUp() }, func(ctx ControlContext) error { return ctx.SplitUp() }),
15		paletteControl("split-down", "SPD", "Split down", "Split the focused pane downward", TargetPane, func(ctx Context, _ []string) error { return ctx.SplitDown() }, func(ctx ControlContext) error { return ctx.SplitDown() }),
16		paletteControl("consume-or-expel-pane-left", "MPL", "Consume or expel pane left", "Move the focused pane left", TargetPane, func(ctx Context, _ []string) error { return ctx.ConsumeOrExpelPaneLeft() }, func(ctx ControlContext) error { return ctx.ConsumeOrExpelPaneLeft() }),
17		paletteControl("consume-or-expel-pane-right", "MPR", "Consume or expel pane right", "Move the focused pane right", TargetPane, func(ctx Context, _ []string) error { return ctx.ConsumeOrExpelPaneRight() }, func(ctx ControlContext) error { return ctx.ConsumeOrExpelPaneRight() }),
18		paletteControl("stack-pane", "STP", "Stack pane", "Create a new pane in a stack", TargetPane, func(ctx Context, _ []string) error { return ctx.StackPane() }, func(ctx ControlContext) error { return ctx.StackPane() }),
19		paletteControl("toggle-stack", "TFS", "Toggle stack", "Toggle the focused pane stack", TargetPane, func(ctx Context, _ []string) error { return ctx.ToggleStack() }, func(ctx ControlContext) error { return ctx.ToggleStack() }),
20		paletteOnly("toggle-floating-pane", "TFP", "Toggle floating pane", "Toggle the floating pane", func(ctx Context, _ []string) error { return ctx.ToggleFloatingPane() }),
21		paletteControl("close-pane", "CFP", "Close pane", "Close the focused pane", TargetPane, func(ctx Context, _ []string) error { return ctx.ClosePane() }, func(ctx ControlContext) error { return ctx.ClosePane() }),
22		movePaneCommand(),
23		moveTabCommand(),
24		paletteControl("focus-pane-left", "FPL", "Focus pane left", "Focus the pane to the left", TargetPane, func(ctx Context, _ []string) error { return ctx.FocusPaneLeft() }, func(ctx ControlContext) error { return ctx.FocusPaneLeft() }),
25		paletteControl("focus-pane-right", "FPR", "Focus pane right", "Focus the pane to the right", TargetPane, func(ctx Context, _ []string) error { return ctx.FocusPaneRight() }, func(ctx ControlContext) error { return ctx.FocusPaneRight() }),
26		paletteControl("focus-pane-up", "FPU", "Focus pane up", "Focus the pane above", TargetPane, func(ctx Context, _ []string) error { return ctx.FocusPaneUp() }, func(ctx ControlContext) error { return ctx.FocusPaneUp() }),
27		paletteControl("focus-pane-down", "FPD", "Focus pane down", "Focus the pane below", TargetPane, func(ctx Context, _ []string) error { return ctx.FocusPaneDown() }, func(ctx ControlContext) error { return ctx.FocusPaneDown() }),
28		paletteOnly("resize-pane", "RSZ", "Resize pane", "Enter pane resize mode", func(ctx Context, _ []string) error { return ctx.EnterResizeMode() }),
29		paletteControl("grow-pane-width", "GPW", "Grow pane width", "Grow the pane by two columns", TargetPane, func(ctx Context, _ []string) error { return ctx.GrowPaneWidth() }, func(ctx ControlContext) error { return ctx.GrowPaneWidth() }),
30		paletteControl("shrink-pane-width", "SPW", "Shrink pane width", "Shrink the pane by two columns", TargetPane, func(ctx Context, _ []string) error { return ctx.ShrinkPaneWidth() }, func(ctx ControlContext) error { return ctx.ShrinkPaneWidth() }),
31		paletteControl("grow-pane-height", "GPH", "Grow pane height", "Grow the pane by one row", TargetPane, func(ctx Context, _ []string) error { return ctx.GrowPaneHeight() }, func(ctx ControlContext) error { return ctx.GrowPaneHeight() }),
32		paletteControl("shrink-pane-height", "SPH", "Shrink pane height", "Shrink the pane by one row", TargetPane, func(ctx Context, _ []string) error { return ctx.ShrinkPaneHeight() }, func(ctx ControlContext) error { return ctx.ShrinkPaneHeight() }),
33		paletteControl("equalize-panes", "EQP", "Equalize panes", "Equalize pane sizes", TargetTab, func(ctx Context, _ []string) error { return ctx.EqualizePanes() }, func(ctx ControlContext) error { return ctx.EqualizePanes() }),
34		paletteControl("next-tab", "NXT", "Next tab", "Switch to the next tab", TargetSession, func(ctx Context, _ []string) error { return ctx.NextTab() }, func(ctx ControlContext) error { return ctx.NextTab() }),
35		paletteControl("previous-tab", "PVT", "Previous tab", "Switch to the previous tab", TargetSession, func(ctx Context, _ []string) error { return ctx.PrevTab() }, func(ctx ControlContext) error { return ctx.PrevTab() }),
36		paletteOnly("back-session", "BCK", "Previous session", "Switch to previous session", func(ctx Context, _ []string) error { return ctx.BackSession() }),
37		{Slug: "jump-recent-session", Code: "JRS", Name: "Jump to recent session", Desc: "Jump to a recent session by rank", Usage: "jump-recent-session <rank>", PaletteVisible: true, Arguments: ArgumentsRequired, ContextHint: ContextHintRecentSessions, Run: func(ctx Context, args []string) error {
38			rank, err := ParsePositiveDecimal(args)
39			if err != nil {
40				return err
41			}
42			return ctx.JumpRecentSession(rank)
43		}},
44		paletteOnly("session-picker", "SSP", "Session picker", "Open the session picker", func(ctx Context, _ []string) error { return ctx.OpenSessionPicker() }),
45		paletteOnly("notifications", "NTC", "Notifications", "Show notification history", func(ctx Context, _ []string) error { return ctx.OpenNotifications() }),
46		paletteOnly("yank-last-notification", "YLN", "Yank last notification", "Copy last notice", func(ctx Context, _ []string) error { return ctx.YankLastNotification() }),
47		paletteOnly("visual-mode", "VIS", "Visual mode", "Enter visual mode", func(ctx Context, _ []string) error { return ctx.EnterVisualMode() }),
48		paletteOptionalOne("rename-session", "RNS", "Rename session", "Rename session", TargetSession, func(ctx Context) error { return ctx.RenameSession() }, func(ctx Context, name string) error { return ctx.RenameSessionTo(name) }, func(ctx ControlContext, name string) error { return ctx.RenameSessionTo(name) }),
49		paletteOptionalOne("rename-tab", "RNT", "Rename tab", "Rename the current tab", TargetTab, func(ctx Context) error { return ctx.RenameTab() }, func(ctx Context, name string) error { return ctx.RenameTabTo(name) }, func(ctx ControlContext, name string) error { return ctx.RenameTabTo(name) }),
50		paletteOnly("detach", "DET", "Detach", "Detach from the session", func(ctx Context, _ []string) error { return ctx.Detach() }),
51		toastCommand(),
52		listCommand("list-sessions", "List sessions", "List sessions with active markers", TargetNone, func(ctx ControlContext, json bool) (string, error) { return ctx.ListSessions(json) }),
53		listCommand("list-tabs", "List tabs", "List tabs in the target session", TargetSession, func(ctx ControlContext, json bool) (string, error) { return ctx.ListTabs(json) }),
54		listCommand("list-panes", "List panes", "List panes in the target tab", TargetTab, func(ctx ControlContext, json bool) (string, error) { return ctx.ListPanes(json) }),
55		listCommand("env", "Session environment", "Print the session's desktop and login variables (JSON null means unset)", TargetSession, func(ctx ControlContext, json bool) (string, error) { return ctx.SessionEnvironment(json) }),
56		remoteCatalogCommand(),
57		sessionRecoveryCommand(),
58	}
59	return commands
60}
61
62func paletteOnly(slug, code, name, desc string, run func(Context, []string) error) Command {
63	return Command{Slug: slug, Code: code, Name: name, Desc: desc, Usage: slug, PaletteVisible: true, Run: run}
64}
65
66func paletteControl(slug, code, name, desc string, target TargetKind, run func(Context, []string) error, control func(ControlContext) error) Command {
67	return Command{Slug: slug, Code: code, Name: name, Desc: desc, Usage: slug, PaletteVisible: true, Scriptable: true, Target: target, Run: run, Control: func(ctx ControlContext, args []string, _ ControlOptions) (ControlResult, error) {
68		if len(args) != 0 {
69			return ControlResult{}, ErrInvalidArguments
70		}
71		return ControlResult{}, control(ctx)
72	}}
73}
74
75func paletteOptionalOne(slug, code, name, desc string, target TargetKind, prompt func(Context) error, direct func(Context, string) error, control func(ControlContext, string) error) Command {
76	cmd := Command{Slug: slug, Code: code, Name: name, Desc: desc, Usage: slug + " [name]", PaletteVisible: true, Scriptable: true, Target: target, Arguments: ArgumentsOptional}
77	cmd.Preview = func(args []string, hasArgument bool) string {
78		if len(args) == 0 {
79			if hasArgument {
80				return "Type a name, or press Enter"
81			}
82			return desc
83		}
84		if len(args) > 1 {
85			return "Use one name"
86		}
87		switch slug {
88		case "new-session":
89			return "Create session “" + args[0] + "”"
90		case "rename-session":
91			return "Rename this session to “" + args[0] + "”"
92		default:
93			return "Rename this tab to “" + args[0] + "”"
94		}
95	}
96	cmd.Run = func(ctx Context, args []string) error {
97		switch len(args) {
98		case 0:
99			return prompt(ctx)
100		case 1:
101			return direct(ctx, args[0])
102		default:
103			return ErrInvalidArguments
104		}
105	}
106	cmd.Control = func(ctx ControlContext, args []string, _ ControlOptions) (ControlResult, error) {
107		if len(args) != 1 || args[0] == "" {
108			return ControlResult{}, ErrInvalidArguments
109		}
110		return ControlResult{}, control(ctx, args[0])
111	}
112	return cmd
113}
114
115func movePaneCommand() Command {
116	return Command{
117		Slug: "move-pane", Code: "MFP", Name: "Move pane to tab",
118		Desc: "Move focused pane to tab", Usage: "move-pane <destination-session> <destination-tab-id>",
119		PaletteVisible: true, Scriptable: true, Target: TargetPane, Scope: CommandScopeCrossSession,
120		Run: func(ctx Context, _ []string) error { return ctx.OpenMovePanePicker() },
121		Control: func(ctx ControlContext, args []string, _ ControlOptions) (ControlResult, error) {
122			if len(args) != 2 || args[0] == "" || args[1] == "" {
123				return ControlResult{}, ErrInvalidArguments
124			}
125			return ControlResult{}, ctx.MovePane(args[0], args[1])
126		},
127	}
128}
129
130func moveTabCommand() Command {
131	return Command{
132		Slug: "move-tab", Code: "MAT", Name: "Move tab to session",
133		Desc: "Move active tab to session", Usage: "move-tab <destination-session>",
134		PaletteVisible: true, Scriptable: true, Target: TargetTab, Scope: CommandScopeCrossSession,
135		Run: func(ctx Context, _ []string) error { return ctx.OpenMoveTabPicker() },
136		Control: func(ctx ControlContext, args []string, _ ControlOptions) (ControlResult, error) {
137			if len(args) != 1 || args[0] == "" {
138				return ControlResult{}, ErrInvalidArguments
139			}
140			return ControlResult{}, ctx.MoveTab(args[0])
141		},
142	}
143}
144
145func toastCommand() Command {
146	return Command{Slug: "toast", Name: "Toast", Desc: "Show a toast notification in the target session", Usage: "toast [-l info|warn|error] <message>", Scriptable: true, Target: TargetSession, Control: func(ctx ControlContext, args []string, _ ControlOptions) (ControlResult, error) {
147		severity := "info"
148		if len(args) >= 2 && args[0] == "-l" {
149			severity = args[1]
150			args = args[2:]
151		}
152		if len(args) != 1 || args[0] == "" {
153			return ControlResult{}, ErrInvalidArguments
154		}
155		return ControlResult{}, ctx.Toast(severity, args[0])
156	}}
157}
158
159func sessionRecoveryCommand() Command {
160	return Command{
161		Slug: "session-recovery", Name: "Session recovery", Desc: "Discard a broken durable session's persisted state",
162		Usage:      "session-recovery discard",
163		Scriptable: true, Target: TargetNone,
164		Control: func(ctx ControlContext, args []string, _ ControlOptions) (ControlResult, error) {
165			if len(args) != 1 || args[0] != "discard" {
166				return ControlResult{}, ErrInvalidArguments
167			}
168			output, err := ctx.SessionRecovery("discard")
169			return ControlResult{Output: output}, err
170		},
171	}
172}
173
174func remoteCatalogCommand() Command {
175	return Command{
176		Slug: "remote-catalog", Name: "Remote catalog",
177		Desc:  "Return the versioned session catalog for remote discovery",
178		Usage: "remote-catalog --json", Scriptable: true, Target: TargetNone,
179		Control: func(ctx ControlContext, args []string, opts ControlOptions) (ControlResult, error) {
180			if len(args) != 0 || !opts.JSON {
181				return ControlResult{}, ErrInvalidArguments
182			}
183			output, err := ctx.RemoteCatalog(true)
184			return ControlResult{Output: output}, err
185		},
186	}
187}
188
189func listCommand(slug, name, desc string, target TargetKind, list func(ControlContext, bool) (string, error)) Command {
190	return Command{Slug: slug, Name: name, Desc: desc, Usage: slug + " [--json]", Scriptable: true, Target: target, Control: func(ctx ControlContext, args []string, opts ControlOptions) (ControlResult, error) {
191		if len(args) != 0 {
192			return ControlResult{}, ErrInvalidArguments
193		}
194		out, err := list(ctx, opts.JSON)
195		return ControlResult{Output: out}, err
196	}}
197}
198
199// ByCode returns the command matching code, case-insensitively.
200func ByCode(code string) (Command, bool) {
201	code = strings.ToUpper(code)
202	for _, cmd := range PaletteRegistry() {
203		if cmd.Code == code {
204			return cmd, true
205		}
206	}
207	return Command{}, false
208}
209
210// BySlug returns the exact command slug. Slugs are stable CLI identifiers.
211func BySlug(slug string) (Command, bool) {
212	for _, cmd := range Registry() {
213		if cmd.Slug == slug {
214			return cmd, true
215		}
216	}
217	return Command{}, false
218}
219
220// PaletteRegistry returns commands visible in the in-band palette.
221func PaletteRegistry() []Command {
222	all := Registry()
223	out := make([]Command, 0, len(all))
224	for _, cmd := range all {
225		if cmd.PaletteVisible {
226			out = append(out, cmd)
227		}
228	}
229	return out
230}

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