v0.3.0 99dc266

wire_command.go RawHistoryFolder

1package ports
2
3import (
4	"encoding/binary"
5	"errors"
6	"math"
7)
8
9// ErrTooManyCommandArgs reports that a request exceeds the wire count limit.
10var ErrTooManyCommandArgs = errors.New("ports: too many command arguments")
11
12// CommandRequest asks the daemon to run one control command. Version must
13// stay first so a future payload layout can still be rejected cleanly.
14type CommandRequest struct {
15	Version       uint16
16	RequestID     uint64
17	Attached      bool
18	Self          bool
19	Slug          string
20	Args          []string
21	TargetSession string
22	TargetTab     string
23	TargetPane    string
24	JSON          bool
25}
26
27// CommandResult reports a control command's outcome.
28type CommandResult struct {
29	RequestID uint64
30	OK        bool
31	Code      uint16
32	Text      string
33	Output    string
34}
35
36// PeekCommandVersion returns the leading protocol version from a
37// CommandRequest payload.
38func PeekCommandVersion(b []byte) (uint16, bool) {
39	if len(b) < 2 {
40		return 0, false
41	}
42	return binary.BigEndian.Uint16(b), true
43}
44
45// MarshalCommandRequest encodes m into a CommandRequest payload.
46func MarshalCommandRequest(m CommandRequest) ([]byte, error) {
47	if len(m.Args) > math.MaxUint16 {
48		return nil, ErrTooManyCommandArgs
49	}
50
51	w := payloadWriter{}
52	w.putUint16(m.Version)
53	w.putUint64(m.RequestID)
54	w.putBool(m.Attached)
55	w.putBool(m.Self)
56	w.putString(m.Slug)
57	w.putUint16(uint16(len(m.Args)))
58	for _, arg := range m.Args {
59		w.putLongString(arg)
60	}
61	w.putString(m.TargetSession)
62	w.putString(m.TargetTab)
63	w.putString(m.TargetPane)
64	w.putBool(m.JSON)
65	return w.b, nil
66}
67
68// UnmarshalCommandRequest decodes a strict CommandRequest payload.
69func UnmarshalCommandRequest(b []byte) (CommandRequest, error) {
70	r := payloadReader{b: b}
71	var m CommandRequest
72	var err error
73
74	if m.Version, err = r.getUint16(); err != nil {
75		return CommandRequest{}, err
76	}
77	if m.RequestID, err = r.getUint64(); err != nil {
78		return CommandRequest{}, err
79	}
80	if m.Attached, err = r.getBool(); err != nil {
81		return CommandRequest{}, err
82	}
83	if m.Self, err = r.getBool(); err != nil {
84		return CommandRequest{}, err
85	}
86	if m.Slug, err = r.getString(); err != nil {
87		return CommandRequest{}, err
88	}
89	argCount, err := r.getUint16()
90	if err != nil {
91		return CommandRequest{}, err
92	}
93	// Every argument requires at least a uint32 length prefix. Reject an
94	// impossible count before allocating from untrusted input.
95	if uint64(argCount) > uint64(len(r.b)/4) {
96		return CommandRequest{}, errShortPayload
97	}
98	if argCount != 0 {
99		m.Args = make([]string, 0, int(argCount))
100		for range int(argCount) {
101			arg, err := r.getLongString()
102			if err != nil {
103				return CommandRequest{}, err
104			}
105			m.Args = append(m.Args, arg)
106		}
107	}
108	if m.TargetSession, err = r.getString(); err != nil {
109		return CommandRequest{}, err
110	}
111	if m.TargetTab, err = r.getString(); err != nil {
112		return CommandRequest{}, err
113	}
114	if m.TargetPane, err = r.getString(); err != nil {
115		return CommandRequest{}, err
116	}
117	if m.JSON, err = r.getBool(); err != nil {
118		return CommandRequest{}, err
119	}
120	if err := r.done(); err != nil {
121		return CommandRequest{}, err
122	}
123	return m, nil
124}
125
126// MarshalCommandResult encodes m into a CommandResult payload.
127func MarshalCommandResult(m CommandResult) []byte {
128	w := payloadWriter{}
129	w.putUint64(m.RequestID)
130	w.putBool(m.OK)
131	w.putUint16(m.Code)
132	w.putString(m.Text)
133	w.putLongString(m.Output)
134	return w.b
135}
136
137// UnmarshalCommandResult decodes a strict CommandResult payload.
138func UnmarshalCommandResult(b []byte) (CommandResult, error) {
139	r := payloadReader{b: b}
140	var m CommandResult
141	var err error
142
143	if m.RequestID, err = r.getUint64(); err != nil {
144		return CommandResult{}, err
145	}
146	if m.OK, err = r.getBool(); err != nil {
147		return CommandResult{}, err
148	}
149	if m.Code, err = r.getUint16(); err != nil {
150		return CommandResult{}, err
151	}
152	if m.Text, err = r.getString(); err != nil {
153		return CommandResult{}, err
154	}
155	if m.Output, err = r.getLongString(); err != nil {
156		return CommandResult{}, err
157	}
158	if err := r.done(); err != nil {
159		return CommandResult{}, err
160	}
161	return m, nil
162}

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