refactor(tree-renderer): pass context as first parameter in layout rendering
Remove stored ctx field from TreeRenderer and update all methods (Build, renderNode, renderLeaf, renderSplit, renderStacked) to accept context as first parameter, following project convention of using log := logging.FromContext(ctx) for logging operations.
- commit
- 4d6f6fd701502dc4ad4ef01941af6968e406e549
- author
- brice · · 2025-12-17 06:44 UTC
- parent
- 39222bf
- signature
- unsigned
1 file · +18 -19
M internal/ui/layout/tree.go +18 -19
| @@ -34,13 +34,13 @@ type TreeRenderer struct { | |||
| 34 | 34 | // paneToStack maps pane IDs to their containing StackedView. | |
| 35 | 35 | // Every leaf pane is wrapped in a StackedView for easy stacking later. | |
| 36 | 36 | paneToStack map[string]*StackedView | |
| 37 | - | ctx context.Context | |
| 38 | 37 | mu sync.RWMutex | |
| 39 | 38 | } | |
| 40 | 39 | ||
| 41 | 40 | // NewTreeRenderer creates a new tree renderer. | |
| 42 | 41 | func NewTreeRenderer(ctx context.Context, factory WidgetFactory, paneViewFactory PaneViewFactory) *TreeRenderer { | |
| 43 | 42 | log := logging.FromContext(ctx) | |
| 43 | + | log.Debug().Msg("creating tree renderer") | |
| 44 | 44 | ||
| 45 | 45 | return &TreeRenderer{ | |
| 46 | 46 | factory: factory, | |
| @@ -48,13 +48,12 @@ func NewTreeRenderer(ctx context.Context, factory WidgetFactory, paneViewFactory | |||
| 48 | 48 | logger: log.With().Str("component", "tree-renderer").Logger(), | |
| 49 | 49 | nodeToWidget: make(map[string]Widget), | |
| 50 | 50 | paneToStack: make(map[string]*StackedView), | |
| 51 | - | ctx: ctx, | |
| 52 | 51 | } | |
| 53 | 52 | } | |
| 54 | 53 | ||
| 55 | 54 | // Build constructs the entire widget tree from a root PaneNode. | |
| 56 | 55 | // Returns the root widget that can be embedded in a container. | |
| 57 | - | func (tr *TreeRenderer) Build(root *entity.PaneNode) (Widget, error) { | |
| 56 | + | func (tr *TreeRenderer) Build(ctx context.Context, root *entity.PaneNode) (Widget, error) { | |
| 58 | 57 | if root == nil { | |
| 59 | 58 | return nil, ErrNilRoot | |
| 60 | 59 | } | |
| @@ -66,12 +65,12 @@ func (tr *TreeRenderer) Build(root *entity.PaneNode) (Widget, error) { | |||
| 66 | 65 | tr.nodeToWidget = make(map[string]Widget) | |
| 67 | 66 | tr.paneToStack = make(map[string]*StackedView) | |
| 68 | 67 | ||
| 69 | - | return tr.renderNode(root) | |
| 68 | + | return tr.renderNode(ctx, root) | |
| 70 | 69 | } | |
| 71 | 70 | ||
| 72 | 71 | // renderNode recursively renders a single node and its children. | |
| 73 | 72 | // Must be called with lock held. | |
| 74 | - | func (tr *TreeRenderer) renderNode(node *entity.PaneNode) (Widget, error) { | |
| 73 | + | func (tr *TreeRenderer) renderNode(ctx context.Context, node *entity.PaneNode) (Widget, error) { | |
| 75 | 74 | if node == nil { | |
| 76 | 75 | return nil, nil | |
| 77 | 76 | } | |
| @@ -81,15 +80,15 @@ func (tr *TreeRenderer) renderNode(node *entity.PaneNode) (Widget, error) { | |||
| 81 | 80 | ||
| 82 | 81 | switch { | |
| 83 | 82 | case node.IsLeaf(): | |
| 84 | - | widget = tr.renderLeaf(node) | |
| 83 | + | widget = tr.renderLeaf(ctx, node) | |
| 85 | 84 | case node.IsSplit(): | |
| 86 | - | widget, err = tr.renderSplit(node) | |
| 85 | + | widget, err = tr.renderSplit(ctx, node) | |
| 87 | 86 | case node.IsStacked: | |
| 88 | - | widget, err = tr.renderStacked(node) | |
| 87 | + | widget, err = tr.renderStacked(ctx, node) | |
| 89 | 88 | default: | |
| 90 | 89 | // Unknown node type - treat as leaf if it has a pane | |
| 91 | 90 | if node.Pane != nil { | |
| 92 | - | widget = tr.renderLeaf(node) | |
| 91 | + | widget = tr.renderLeaf(ctx, node) | |
| 93 | 92 | } | |
| 94 | 93 | } | |
| 95 | 94 | ||
| @@ -108,7 +107,7 @@ func (tr *TreeRenderer) renderNode(node *entity.PaneNode) (Widget, error) { | |||
| 108 | 107 | // renderLeaf creates a PaneView widget wrapped in a StackedView. | |
| 109 | 108 | // Every pane is wrapped in a StackedView from the start, making stacking trivial. | |
| 110 | 109 | // When there's only 1 pane, the StackedView shows no title bar. | |
| 111 | - | func (tr *TreeRenderer) renderLeaf(node *entity.PaneNode) Widget { | |
| 110 | + | func (tr *TreeRenderer) renderLeaf(ctx context.Context, node *entity.PaneNode) Widget { | |
| 112 | 111 | if tr.paneViewFactory == nil { | |
| 113 | 112 | return nil | |
| 114 | 113 | } | |
| @@ -136,7 +135,7 @@ func (tr *TreeRenderer) renderLeaf(node *entity.PaneNode) Widget { | |||
| 136 | 135 | Str("title", title). | |
| 137 | 136 | Msg("TreeRenderer.renderLeaf: wrapping pane in StackedView") | |
| 138 | 137 | ||
| 139 | - | stackedView.AddPane(tr.ctx, title, "", paneWidget) | |
| 138 | + | stackedView.AddPane(ctx, title, "", paneWidget) | |
| 140 | 139 | ||
| 141 | 140 | // Track this pane's StackedView for later stacking operations | |
| 142 | 141 | if node.Pane != nil { | |
| @@ -147,14 +146,14 @@ func (tr *TreeRenderer) renderLeaf(node *entity.PaneNode) Widget { | |||
| 147 | 146 | } | |
| 148 | 147 | ||
| 149 | 148 | // renderSplit creates a SplitView for a split node. | |
| 150 | - | func (tr *TreeRenderer) renderSplit(node *entity.PaneNode) (Widget, error) { | |
| 149 | + | func (tr *TreeRenderer) renderSplit(ctx context.Context, node *entity.PaneNode) (Widget, error) { | |
| 151 | 150 | // Render children first | |
| 152 | - | leftWidget, err := tr.renderNode(node.Left()) | |
| 151 | + | leftWidget, err := tr.renderNode(ctx, node.Left()) | |
| 153 | 152 | if err != nil { | |
| 154 | 153 | return nil, err | |
| 155 | 154 | } | |
| 156 | 155 | ||
| 157 | - | rightWidget, err := tr.renderNode(node.Right()) | |
| 156 | + | rightWidget, err := tr.renderNode(ctx, node.Right()) | |
| 158 | 157 | if err != nil { | |
| 159 | 158 | return nil, err | |
| 160 | 159 | } | |
| @@ -166,13 +165,13 @@ func (tr *TreeRenderer) renderSplit(node *entity.PaneNode) (Widget, error) { | |||
| 166 | 165 | } | |
| 167 | 166 | ||
| 168 | 167 | // Create split view | |
| 169 | - | splitView := NewSplitView(tr.ctx, tr.factory, orientation, leftWidget, rightWidget, node.SplitRatio) | |
| 168 | + | splitView := NewSplitView(ctx, tr.factory, orientation, leftWidget, rightWidget, node.SplitRatio) | |
| 170 | 169 | ||
| 171 | 170 | return splitView.Widget(), nil | |
| 172 | 171 | } | |
| 173 | 172 | ||
| 174 | 173 | // renderStacked creates a StackedView for a stacked node. | |
| 175 | - | func (tr *TreeRenderer) renderStacked(node *entity.PaneNode) (Widget, error) { | |
| 174 | + | func (tr *TreeRenderer) renderStacked(ctx context.Context, node *entity.PaneNode) (Widget, error) { | |
| 176 | 175 | stackedView := NewStackedView(tr.factory) | |
| 177 | 176 | ||
| 178 | 177 | tr.logger.Debug(). | |
| @@ -181,7 +180,7 @@ func (tr *TreeRenderer) renderStacked(node *entity.PaneNode) (Widget, error) { | |||
| 181 | 180 | ||
| 182 | 181 | // Add each child pane to the stack | |
| 183 | 182 | for _, child := range node.Children { | |
| 184 | - | childWidget, err := tr.renderNode(child) | |
| 183 | + | childWidget, err := tr.renderNode(ctx, child) | |
| 185 | 184 | if err != nil { | |
| 186 | 185 | return nil, err | |
| 187 | 186 | } | |
| @@ -196,7 +195,7 @@ func (tr *TreeRenderer) renderStacked(node *entity.PaneNode) (Widget, error) { | |||
| 196 | 195 | favicon = child.Pane.FaviconURL | |
| 197 | 196 | } | |
| 198 | 197 | ||
| 199 | - | stackedView.AddPane(tr.ctx, title, favicon, childWidget) | |
| 198 | + | stackedView.AddPane(ctx, title, favicon, childWidget) | |
| 200 | 199 | ||
| 201 | 200 | // Override paneToStack to point to THIS stacked view, not the child's wrapper. | |
| 202 | 201 | // This ensures geometric navigation and stack sync work correctly. | |
| @@ -207,7 +206,7 @@ func (tr *TreeRenderer) renderStacked(node *entity.PaneNode) (Widget, error) { | |||
| 207 | 206 | ||
| 208 | 207 | // Set active index | |
| 209 | 208 | if node.ActiveStackIndex >= 0 && node.ActiveStackIndex < stackedView.Count() { | |
| 210 | - | _ = stackedView.SetActive(tr.ctx, node.ActiveStackIndex) | |
| 209 | + | _ = stackedView.SetActive(ctx, node.ActiveStackIndex) | |
| 211 | 210 | } | |
| 212 | 211 | ||
| 213 | 212 | return stackedView.Widget(), nil | |
| @@ -34,13 +34,13 @@ type TreeRenderer struct { | |||||
| 34 | // paneToStack maps pane IDs to their containing StackedView. | 34 | // paneToStack maps pane IDs to their containing StackedView. | ||
| 35 | // Every leaf pane is wrapped in a StackedView for easy stacking later. | 35 | // Every leaf pane is wrapped in a StackedView for easy stacking later. | ||
| 36 | paneToStack map[string]*StackedView | 36 | paneToStack map[string]*StackedView | ||
| 37 | - | ctx context.Context | |||
| 38 | mu sync.RWMutex | 37 | mu sync.RWMutex | ||
| 39 | } | 38 | } | ||
| 40 | 39 | ||||
| 41 | // NewTreeRenderer creates a new tree renderer. | 40 | // NewTreeRenderer creates a new tree renderer. | ||
| 42 | func NewTreeRenderer(ctx context.Context, factory WidgetFactory, paneViewFactory PaneViewFactory) *TreeRenderer { | 41 | func NewTreeRenderer(ctx context.Context, factory WidgetFactory, paneViewFactory PaneViewFactory) *TreeRenderer { | ||
| 43 | log := logging.FromContext(ctx) | 42 | log := logging.FromContext(ctx) | ||
| 43 | + | log.Debug().Msg("creating tree renderer") | |||
| 44 | 44 | ||||
| 45 | return &TreeRenderer{ | 45 | return &TreeRenderer{ | ||
| 46 | factory: factory, | 46 | factory: factory, | ||
| @@ -48,13 +48,12 @@ func NewTreeRenderer(ctx context.Context, factory WidgetFactory, paneViewFactory | |||||
| 48 | logger: log.With().Str("component", "tree-renderer").Logger(), | 48 | logger: log.With().Str("component", "tree-renderer").Logger(), | ||
| 49 | nodeToWidget: make(map[string]Widget), | 49 | nodeToWidget: make(map[string]Widget), | ||
| 50 | paneToStack: make(map[string]*StackedView), | 50 | paneToStack: make(map[string]*StackedView), | ||
| 51 | - | ctx: ctx, | |||
| 52 | } | 51 | } | ||
| 53 | } | 52 | } | ||
| 54 | 53 | ||||
| 55 | // Build constructs the entire widget tree from a root PaneNode. | 54 | // Build constructs the entire widget tree from a root PaneNode. | ||
| 56 | // Returns the root widget that can be embedded in a container. | 55 | // Returns the root widget that can be embedded in a container. | ||
| 57 | - | func (tr *TreeRenderer) Build(root *entity.PaneNode) (Widget, error) { | 56 | + | func (tr *TreeRenderer) Build(ctx context.Context, root *entity.PaneNode) (Widget, error) { |
| 58 | if root == nil { | 57 | if root == nil { | ||
| 59 | return nil, ErrNilRoot | 58 | return nil, ErrNilRoot | ||
| 60 | } | 59 | } | ||
| @@ -66,12 +65,12 @@ func (tr *TreeRenderer) Build(root *entity.PaneNode) (Widget, error) { | |||||
| 66 | tr.nodeToWidget = make(map[string]Widget) | 65 | tr.nodeToWidget = make(map[string]Widget) | ||
| 67 | tr.paneToStack = make(map[string]*StackedView) | 66 | tr.paneToStack = make(map[string]*StackedView) | ||
| 68 | 67 | ||||
| 69 | - | return tr.renderNode(root) | 68 | + | return tr.renderNode(ctx, root) |
| 70 | } | 69 | } | ||
| 71 | 70 | ||||
| 72 | // renderNode recursively renders a single node and its children. | 71 | // renderNode recursively renders a single node and its children. | ||
| 73 | // Must be called with lock held. | 72 | // Must be called with lock held. | ||
| 74 | - | func (tr *TreeRenderer) renderNode(node *entity.PaneNode) (Widget, error) { | 73 | + | func (tr *TreeRenderer) renderNode(ctx context.Context, node *entity.PaneNode) (Widget, error) { |
| 75 | if node == nil { | 74 | if node == nil { | ||
| 76 | return nil, nil | 75 | return nil, nil | ||
| 77 | } | 76 | } | ||
| @@ -81,15 +80,15 @@ func (tr *TreeRenderer) renderNode(node *entity.PaneNode) (Widget, error) { | |||||
| 81 | 80 | ||||
| 82 | switch { | 81 | switch { | ||
| 83 | case node.IsLeaf(): | 82 | case node.IsLeaf(): | ||
| 84 | - | widget = tr.renderLeaf(node) | 83 | + | widget = tr.renderLeaf(ctx, node) |
| 85 | case node.IsSplit(): | 84 | case node.IsSplit(): | ||
| 86 | - | widget, err = tr.renderSplit(node) | 85 | + | widget, err = tr.renderSplit(ctx, node) |
| 87 | case node.IsStacked: | 86 | case node.IsStacked: | ||
| 88 | - | widget, err = tr.renderStacked(node) | 87 | + | widget, err = tr.renderStacked(ctx, node) |
| 89 | default: | 88 | default: | ||
| 90 | // Unknown node type - treat as leaf if it has a pane | 89 | // Unknown node type - treat as leaf if it has a pane | ||
| 91 | if node.Pane != nil { | 90 | if node.Pane != nil { | ||
| 92 | - | widget = tr.renderLeaf(node) | 91 | + | widget = tr.renderLeaf(ctx, node) |
| 93 | } | 92 | } | ||
| 94 | } | 93 | } | ||
| 95 | 94 | ||||
| @@ -108,7 +107,7 @@ func (tr *TreeRenderer) renderNode(node *entity.PaneNode) (Widget, error) { | |||||
| 108 | // renderLeaf creates a PaneView widget wrapped in a StackedView. | 107 | // renderLeaf creates a PaneView widget wrapped in a StackedView. | ||
| 109 | // Every pane is wrapped in a StackedView from the start, making stacking trivial. | 108 | // Every pane is wrapped in a StackedView from the start, making stacking trivial. | ||
| 110 | // When there's only 1 pane, the StackedView shows no title bar. | 109 | // When there's only 1 pane, the StackedView shows no title bar. | ||
| 111 | - | func (tr *TreeRenderer) renderLeaf(node *entity.PaneNode) Widget { | 110 | + | func (tr *TreeRenderer) renderLeaf(ctx context.Context, node *entity.PaneNode) Widget { |
| 112 | if tr.paneViewFactory == nil { | 111 | if tr.paneViewFactory == nil { | ||
| 113 | return nil | 112 | return nil | ||
| 114 | } | 113 | } | ||
| @@ -136,7 +135,7 @@ func (tr *TreeRenderer) renderLeaf(node *entity.PaneNode) Widget { | |||||
| 136 | Str("title", title). | 135 | Str("title", title). | ||
| 137 | Msg("TreeRenderer.renderLeaf: wrapping pane in StackedView") | 136 | Msg("TreeRenderer.renderLeaf: wrapping pane in StackedView") | ||
| 138 | 137 | ||||
| 139 | - | stackedView.AddPane(tr.ctx, title, "", paneWidget) | 138 | + | stackedView.AddPane(ctx, title, "", paneWidget) |
| 140 | 139 | ||||
| 141 | // Track this pane's StackedView for later stacking operations | 140 | // Track this pane's StackedView for later stacking operations | ||
| 142 | if node.Pane != nil { | 141 | if node.Pane != nil { | ||
| @@ -147,14 +146,14 @@ func (tr *TreeRenderer) renderLeaf(node *entity.PaneNode) Widget { | |||||
| 147 | } | 146 | } | ||
| 148 | 147 | ||||
| 149 | // renderSplit creates a SplitView for a split node. | 148 | // renderSplit creates a SplitView for a split node. | ||
| 150 | - | func (tr *TreeRenderer) renderSplit(node *entity.PaneNode) (Widget, error) { | 149 | + | func (tr *TreeRenderer) renderSplit(ctx context.Context, node *entity.PaneNode) (Widget, error) { |
| 151 | // Render children first | 150 | // Render children first | ||
| 152 | - | leftWidget, err := tr.renderNode(node.Left()) | 151 | + | leftWidget, err := tr.renderNode(ctx, node.Left()) |
| 153 | if err != nil { | 152 | if err != nil { | ||
| 154 | return nil, err | 153 | return nil, err | ||
| 155 | } | 154 | } | ||
| 156 | 155 | ||||
| 157 | - | rightWidget, err := tr.renderNode(node.Right()) | 156 | + | rightWidget, err := tr.renderNode(ctx, node.Right()) |
| 158 | if err != nil { | 157 | if err != nil { | ||
| 159 | return nil, err | 158 | return nil, err | ||
| 160 | } | 159 | } | ||
| @@ -166,13 +165,13 @@ func (tr *TreeRenderer) renderSplit(node *entity.PaneNode) (Widget, error) { | |||||
| 166 | } | 165 | } | ||
| 167 | 166 | ||||
| 168 | // Create split view | 167 | // Create split view | ||
| 169 | - | splitView := NewSplitView(tr.ctx, tr.factory, orientation, leftWidget, rightWidget, node.SplitRatio) | 168 | + | splitView := NewSplitView(ctx, tr.factory, orientation, leftWidget, rightWidget, node.SplitRatio) |
| 170 | 169 | ||||
| 171 | return splitView.Widget(), nil | 170 | return splitView.Widget(), nil | ||
| 172 | } | 171 | } | ||
| 173 | 172 | ||||
| 174 | // renderStacked creates a StackedView for a stacked node. | 173 | // renderStacked creates a StackedView for a stacked node. | ||
| 175 | - | func (tr *TreeRenderer) renderStacked(node *entity.PaneNode) (Widget, error) { | 174 | + | func (tr *TreeRenderer) renderStacked(ctx context.Context, node *entity.PaneNode) (Widget, error) { |
| 176 | stackedView := NewStackedView(tr.factory) | 175 | stackedView := NewStackedView(tr.factory) | ||
| 177 | 176 | ||||
| 178 | tr.logger.Debug(). | 177 | tr.logger.Debug(). | ||
| @@ -181,7 +180,7 @@ func (tr *TreeRenderer) renderStacked(node *entity.PaneNode) (Widget, error) { | |||||
| 181 | 180 | ||||
| 182 | // Add each child pane to the stack | 181 | // Add each child pane to the stack | ||
| 183 | for _, child := range node.Children { | 182 | for _, child := range node.Children { | ||
| 184 | - | childWidget, err := tr.renderNode(child) | 183 | + | childWidget, err := tr.renderNode(ctx, child) |
| 185 | if err != nil { | 184 | if err != nil { | ||
| 186 | return nil, err | 185 | return nil, err | ||
| 187 | } | 186 | } | ||
| @@ -196,7 +195,7 @@ func (tr *TreeRenderer) renderStacked(node *entity.PaneNode) (Widget, error) { | |||||
| 196 | favicon = child.Pane.FaviconURL | 195 | favicon = child.Pane.FaviconURL | ||
| 197 | } | 196 | } | ||
| 198 | 197 | ||||
| 199 | - | stackedView.AddPane(tr.ctx, title, favicon, childWidget) | 198 | + | stackedView.AddPane(ctx, title, favicon, childWidget) |
| 200 | 199 | ||||
| 201 | // Override paneToStack to point to THIS stacked view, not the child's wrapper. | 200 | // Override paneToStack to point to THIS stacked view, not the child's wrapper. | ||
| 202 | // This ensures geometric navigation and stack sync work correctly. | 201 | // This ensures geometric navigation and stack sync work correctly. | ||
| @@ -207,7 +206,7 @@ func (tr *TreeRenderer) renderStacked(node *entity.PaneNode) (Widget, error) { | |||||
| 207 | 206 | ||||
| 208 | // Set active index | 207 | // Set active index | ||
| 209 | if node.ActiveStackIndex >= 0 && node.ActiveStackIndex < stackedView.Count() { | 208 | if node.ActiveStackIndex >= 0 && node.ActiveStackIndex < stackedView.Count() { | ||
| 210 | - | _ = stackedView.SetActive(tr.ctx, node.ActiveStackIndex) | 209 | + | _ = stackedView.SetActive(ctx, node.ActiveStackIndex) |
| 211 | } | 210 | } | ||
| 212 | 211 | ||||
| 213 | return stackedView.Widget(), nil | 212 | return stackedView.Widget(), nil | ||