tree.go RawHistoryFolder

1package layout
2
3import "github.com/bnema/vev/internal/domain"
4
5// PaneID is an opaque pane identifier owned by higher layers.
6type PaneID string
7
8// Kind identifies the topology role of a Node.
9type Kind int
10
11const (
12	Leaf Kind = iota
13	Split
14	Stack
15)
16
17// Direction is used for split and focus operations.
18type Direction int
19
20const (
21	Left Direction = iota
22	Right
23	Up
24	Down
25)
26
27// SplitDir is the axis used by a split container.
28type SplitDir int
29
30const (
31	Horizontal SplitDir = iota // children are laid out left-to-right
32	Vertical                   // children are laid out top-to-bottom
33)
34
35const (
36	MinPaneCols = 20
37	MinPaneRows = 2
38)
39
40// Axis identifies the dimension changed by a resize operation.
41type Axis int
42
43const (
44	Width Axis = iota
45	Height
46)
47
48// Node is a recursive pane layout node. Leaf is meaningful for Leaf nodes; Dir
49// and Children are meaningful for Split nodes; Children and Expanded are
50// meaningful for Stack nodes.
51type Node struct {
52	Kind     Kind
53	Dir      SplitDir
54	Children []*Node
55	Leaf     PaneID
56	Expanded PaneID
57	Weight   float64
58}
59
60// Tree is a pane layout plus its focused pane.
61type Tree struct {
62	Root  *Node
63	Focus PaneID
64}
65
66// Placement is the solved geometry for a pane.
67type Placement struct {
68	ID        PaneID
69	Content   domain.Rect
70	TitleBar  domain.Rect
71	Collapsed bool
72	InStack   bool
73}
74
75func NewLeaf(id PaneID) *Node { return &Node{Kind: Leaf, Leaf: id} }
76
77func NewTree(id PaneID) *Tree { return &Tree{Root: NewLeaf(id), Focus: id} }
78
79func axisFor(dir Direction) SplitDir {
80	if dir == Left || dir == Right {
81		return Horizontal
82	}
83	return Vertical
84}
85
86func (n *Node) clone() *Node {
87	if n == nil {
88		return nil
89	}
90	out := *n
91	if len(n.Children) > 0 {
92		out.Children = make([]*Node, len(n.Children))
93		for i, child := range n.Children {
94			out.Children[i] = child.clone()
95		}
96	}
97	return &out
98}
99
100func (t *Tree) clone() *Tree {
101	if t == nil {
102		return nil
103	}
104	return &Tree{Root: t.Root.clone(), Focus: t.Focus}
105}
106
107// Clone returns an independent copy of the tree.
108func (t *Tree) Clone() *Tree { return t.clone() }

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