session_environment.go RawHistoryFolder

1package client
2
3import (
4	"errors"
5	"path/filepath"
6	"strings"
7	"unicode/utf8"
8
9	"github.com/bnema/vev/internal/ports"
10)
11
12// SessionEnvironmentProvenance names where a session environment came from.
13type SessionEnvironmentProvenance uint8
14
15const (
16	// SessionEnvironmentUnspecified is the zero value and never validates.
17	SessionEnvironmentUnspecified SessionEnvironmentProvenance = iota
18	// SessionEnvironmentLocalCLI carries environment and working directory
19	// captured from a local CLI invocation.
20	SessionEnvironmentLocalCLI
21	// SessionEnvironmentLocalPicker carries environment and working directory
22	// captured from a local picker selection.
23	SessionEnvironmentLocalPicker
24	// SessionEnvironmentRemote carries no local environment: remote sessions
25	// must not forward local variables or a local working directory.
26	SessionEnvironmentRemote
27)
28
29// SessionEnvironment carries the environment variables and working directory
30// proposed for a session creation.
31type SessionEnvironment struct {
32	Provenance SessionEnvironmentProvenance
33	Env        []string
34	Cwd        string
35}
36
37// Clone returns a deep copy with an independent environment slice.
38func (e SessionEnvironment) Clone() SessionEnvironment {
39	out := e
40	if e.Env != nil {
41		out.Env = make([]string, len(e.Env))
42		copy(out.Env, e.Env)
43	}
44	return out
45}
46
47// Validate reports whether the environment is well-formed for its provenance.
48func (e SessionEnvironment) Validate() error {
49	switch e.Provenance {
50	case SessionEnvironmentLocalCLI, SessionEnvironmentLocalPicker:
51		if len(e.Env) > ports.BrokerMaxEnvEntries {
52			return errors.New("client: session environment has too many entries")
53		}
54		for _, entry := range e.Env {
55			if !utf8.ValidString(entry) {
56				return errors.New("client: session environment entry is not valid UTF-8")
57			}
58			if strings.ContainsRune(entry, 0) {
59				return errors.New("client: session environment entry contains NUL")
60			}
61			if len(entry) > ports.BrokerMaxEnvEntryBytes {
62				return errors.New("client: session environment entry too long")
63			}
64			name, _, found := strings.Cut(entry, "=")
65			if !found || name == "" {
66				return errors.New("client: session environment entry must be NAME=value")
67			}
68		}
69		if e.Cwd != "" {
70			if !utf8.ValidString(e.Cwd) {
71				return errors.New("client: session environment cwd is not valid UTF-8")
72			}
73			if strings.ContainsRune(e.Cwd, 0) {
74				return errors.New("client: session environment cwd contains NUL")
75			}
76			if len(e.Cwd) > 65535 {
77				return errors.New("client: session environment cwd too long")
78			}
79			if !filepath.IsAbs(e.Cwd) {
80				return errors.New("client: session environment cwd must be absolute")
81			}
82		}
83		return nil
84	case SessionEnvironmentRemote:
85		if len(e.Env) != 0 {
86			return errors.New("client: remote session environment must not carry environment entries")
87		}
88		if e.Cwd != "" {
89			return errors.New("client: remote session environment must not carry a working directory")
90		}
91		return nil
92	default:
93		return errors.New("client: session environment provenance is unspecified or unknown")
94	}
95}

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