v0.13.0 976176a

workspace_stack_lifecycle.go RawHistoryFolder

1// workspace_stack_lifecycle.go - Stack pane lifecycle coordination without SafeWidget wrappers
2package browser
3
4import (
5	"errors"
6	"fmt"
7	"log"
8)
9
10// StackLifecycleManager manages the lifecycle hooks around stacked pane operations.
11type StackLifecycleManager struct {
12	wm            *WorkspaceManager
13	treeValidator *TreeValidator
14}
15
16// NewStackLifecycleManager creates a new stack lifecycle manager.
17func NewStackLifecycleManager(wm *WorkspaceManager, treeValidator *TreeValidator) *StackLifecycleManager {
18	return &StackLifecycleManager{
19		wm:            wm,
20		treeValidator: treeValidator,
21	}
22}
23
24// CloseStackedPaneWithLifecycle validates the stack state and delegates the actual
25// close operation to the stacked pane manager. This keeps widget handling simple
26// (raw GTK pointers) while still giving us a single place for additional safety checks.
27func (slm *StackLifecycleManager) CloseStackedPaneWithLifecycle(node *paneNode) error {
28	if node == nil {
29		return errors.New("node is nil")
30	}
31
32	stackNode := node.parent
33	if stackNode == nil || !stackNode.isStacked {
34		return errors.New("node is not part of a stacked pane")
35	}
36
37	log.Printf("[stack-lifecycle] Closing stacked pane: node=%p stack=%p stackSize=%d",
38		node, stackNode, len(stackNode.stackedPanes))
39
40	if err := slm.validateStackState(stackNode, "before close"); err != nil {
41		return fmt.Errorf("invalid stack state before close: %w", err)
42	}
43
44	if slm.wm == nil || slm.wm.stackedPaneManager == nil {
45		return errors.New("stacked pane manager not available")
46	}
47
48	if err := slm.wm.stackedPaneManager.CloseStackedPane(node); err != nil {
49		return err
50	}
51
52	if slm.treeValidator != nil {
53		if err := slm.treeValidator.ValidateTree(slm.wm.root, "after stack close"); err != nil {
54			log.Printf("[stack-lifecycle] Tree validation failed after stack close: %v", err)
55		}
56	}
57
58	return nil
59}
60
61// validateStackState validates the current state of a stack before we perform operations.
62func (slm *StackLifecycleManager) validateStackState(stackNode *paneNode, operation string) error {
63	if stackNode == nil {
64		return errors.New("stack node is nil")
65	}
66
67	if !stackNode.isStacked {
68		return errors.New("node is not marked as stacked")
69	}
70
71	if len(stackNode.stackedPanes) == 0 {
72		return errors.New("stack has no panes")
73	}
74
75	if stackNode.activeStackIndex < 0 || stackNode.activeStackIndex >= len(stackNode.stackedPanes) {
76		return fmt.Errorf("invalid active stack index: %d (size: %d)",
77			stackNode.activeStackIndex, len(stackNode.stackedPanes))
78	}
79
80	for i, pane := range stackNode.stackedPanes {
81		if pane == nil {
82			return fmt.Errorf("stacked pane at index %d is nil", i)
83		}
84		if pane.parent != stackNode {
85			return fmt.Errorf("stacked pane at index %d has wrong parent", i)
86		}
87	}
88
89	log.Printf("[stack-lifecycle] Stack state valid for operation '%s': size=%d activeIndex=%d",
90		operation, len(stackNode.stackedPanes), stackNode.activeStackIndex)
91	return nil
92}

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 8

Tags 42

↑↓ moveenter openesc close