Documentation
¶
Overview ¶
Package layout implements the layout engine for grut's TUI. It manages a binary split tree where each leaf holds a panel name, and computes absolute sizes from terminal dimensions.
Index ¶
- Constants
- func FindSplitAtBorder(root Node, x, y int, area Rect, hitZone int) (*SplitNode, Direction, Rect)
- func FirstPanelOf(node Node) string
- func Presets() map[string]Preset
- func RegisterDefaults(r *Registry, cfg *config.Config, gc git.GitClient, th *theme.Theme)
- func RenderTabBar(tabs []Tab, activeIdx, width int) string
- func Resolve(node Node, area Rect) map[string]Rect
- func SplitRect(area Rect, dir Direction, ratio float64) (Rect, Rect)
- type Direction
- type Engine
- func (e *Engine) AddTab(preset Preset) (tea.Cmd, error)
- func (e *Engine) BorderSize() int
- func (e *Engine) CloseActiveTab() error
- func (e *Engine) CloseFocusedPanel() error
- func (e *Engine) CurrentPreviewPosition() PreviewPosition
- func (e *Engine) FocusByName(name string) bool
- func (e *Engine) FocusNext()
- func (e *Engine) FocusPrev()
- func (e *Engine) FocusedName() string
- func (e *Engine) FocusedPanel() panels.Panel
- func (e *Engine) Height() int
- func (e *Engine) Init(ctx context.Context) tea.Cmd
- func (e *Engine) InnerArea() Rect
- func (e *Engine) IsDragging() bool
- func (e *Engine) IsZoomed() bool
- func (e *Engine) MoveTabLeft()
- func (e *Engine) MoveTabRight()
- func (e *Engine) NextTab()
- func (e *Engine) PanelOrder() []string
- func (e *Engine) PanelRects() map[string]Rect
- func (e *Engine) Panels() map[string]panels.Panel
- func (e *Engine) PrevTab()
- func (e *Engine) RenameActiveTab(name string) error
- func (e *Engine) ResizeGrow()
- func (e *Engine) ResizeShrink()
- func (e *Engine) RotatePreviewPosition()
- func (e *Engine) SetPreviewPosition(pos PreviewPosition)
- func (e *Engine) SetSize(width, height int)
- func (e *Engine) SplitFocusedHorizontal(newPanelType string) (tea.Cmd, error)
- func (e *Engine) SplitFocusedVertical(newPanelType string) (tea.Cmd, error)
- func (e *Engine) StatusBarHeight() int
- func (e *Engine) SwitchTab(idx int) error
- func (e *Engine) TabBarHeight() int
- func (e *Engine) TabManager() *TabManager
- func (e *Engine) ToggleZoom()
- func (e *Engine) Update(msg tea.Msg) tea.Cmd
- func (e *Engine) Width() int
- type LeafNode
- type Node
- type PanelFactory
- type Preset
- type PreviewPosition
- type Rect
- type Registry
- type SplitNode
- type Tab
- type TabManager
- func (tm *TabManager) ActiveIndex() int
- func (tm *TabManager) ActiveTab() *Tab
- func (tm *TabManager) Add(name string, tree Node)
- func (tm *TabManager) Close(idx int) error
- func (tm *TabManager) Count() int
- func (tm *TabManager) MoveLeft()
- func (tm *TabManager) MoveRight()
- func (tm *TabManager) NextTab()
- func (tm *TabManager) PrevTab()
- func (tm *TabManager) Rename(idx int, name string) error
- func (tm *TabManager) Select(idx int) error
- func (tm *TabManager) Tabs() []Tab
Constants ¶
const ( // PanelPadH is the horizontal padding (in characters) added inside each // panel's left and right edges to keep content away from the border. PanelPadH = 1 )
const SingleTabMode = true
SingleTabMode controls whether multi-tab features are active. v1: true (single-tab, tab bar hidden, tab keybindings disabled). Set to false to re-enable multi-tab in v2.
Variables ¶
This section is empty.
Functions ¶
func FindSplitAtBorder ¶
FindSplitAtBorder walks the layout tree and returns the SplitNode whose border is at or near the given (x, y) coordinates within the specified hit zone tolerance. Coordinates are relative to the panel area (not terminal). Inner (deeper) splits take precedence over outer ones. Returns the split, its direction, and the total area the split occupies.
func FirstPanelOf ¶
FirstPanelOf returns the name of the first (top-left-most) panel in the subtree rooted at node.
func RegisterDefaults ¶
RegisterDefaults registers the built-in panels. Panels with real implementations use their concrete constructors; those still under development use placeholders. The cfg parameter provides the already-loaded configuration, avoiding redundant disk reads on every panel creation. The gc parameter provides the git client for git-aware panels; if nil, git panels are not registered. The th parameter provides the theme for styled panels; if nil, panels use fallback colors.
func RenderTabBar ¶
RenderTabBar renders a one-line tab bar showing open tabs with their preset number, plus hints for unopened presets. The active tab is shown in uppercase. The result is padded or truncated to fit the given width.
v1: hidden — returns "" so the tab bar takes no vertical space. The full rendering logic is preserved below for v2 multi-tab.
Types ¶
type Engine ¶
type Engine struct {
// contains filtered or unexported fields
}
Engine manages the layout state: the active layout tree, instantiated panels, focus tracking, and zoom state.
func (*Engine) AddTab ¶
--------------------------------------------------------------------------- Tab operations --------------------------------------------------------------------------- AddTab creates a new tab from a preset, instantiating any panels not already present. Returns a tea.Cmd from initializing new panels.
func (*Engine) BorderSize ¶
BorderSize returns the width of one side of the outer border.
func (*Engine) CloseActiveTab ¶
CloseActiveTab closes the currently active tab. Returns an error if it is the last remaining tab.
func (*Engine) CloseFocusedPanel ¶
CloseFocusedPanel removes the focused panel from the current tab's tree. The sibling takes the parent split's place. Returns an error if it is the last panel in the tab.
func (*Engine) CurrentPreviewPosition ¶
func (e *Engine) CurrentPreviewPosition() PreviewPosition
CurrentPreviewPosition returns the current preview position of the active tab's layout. It checks whether "preview" is a direct child of the root split and infers position from the split direction and child order. If preview is not found at the root level, returns PreviewRight as default.
func (*Engine) FocusByName ¶
FocusByName focuses the panel with the given name. Returns false if not found.
func (*Engine) FocusNext ¶
func (e *Engine) FocusNext()
FocusNext cycles focus to the next panel in order.
func (*Engine) FocusPrev ¶
func (e *Engine) FocusPrev()
FocusPrev cycles focus to the previous panel in order.
func (*Engine) FocusedName ¶
FocusedName returns the name of the currently focused panel.
func (*Engine) FocusedPanel ¶
FocusedPanel returns the currently focused panel, or nil if none.
func (*Engine) InnerArea ¶
InnerArea returns the inner content area dimensions (after subtracting the single outer border) used to resolve panel rects.
func (*Engine) IsDragging ¶
IsDragging returns whether a mouse drag resize is in progress.
func (*Engine) MoveTabLeft ¶
func (e *Engine) MoveTabLeft()
MoveTabLeft swaps the active tab with its left neighbor.
func (*Engine) MoveTabRight ¶
func (e *Engine) MoveTabRight()
MoveTabRight swaps the active tab with its right neighbor.
func (*Engine) PanelOrder ¶
PanelOrder returns the ordered list of panel names.
func (*Engine) PanelRects ¶
PanelRects returns the resolved rectangles for each panel in the current layout, excluding the status bar and tab bar area.
func (*Engine) RenameActiveTab ¶
RenameActiveTab renames the currently active tab.
func (*Engine) ResizeGrow ¶
func (e *Engine) ResizeGrow()
ResizeGrow increases the space allocated to the focused panel by adjusting the nearest split ratio.
func (*Engine) ResizeShrink ¶
func (e *Engine) ResizeShrink()
ResizeShrink decreases the space allocated to the focused panel by adjusting the nearest split ratio.
func (*Engine) RotatePreviewPosition ¶
func (e *Engine) RotatePreviewPosition()
RotatePreviewPosition cycles the preview panel position in the active tab through right → bottom → left → top → right.
func (*Engine) SetPreviewPosition ¶
func (e *Engine) SetPreviewPosition(pos PreviewPosition)
SetPreviewPosition sets the preview panel position across all tabs whose tree is a simple two-leaf split of "filetree" and "preview". This ensures that switching tabs preserves the chosen position. If the active tab's position already matches, this is a no-op.
func (*Engine) SplitFocusedHorizontal ¶
--------------------------------------------------------------------------- Split / panel operations --------------------------------------------------------------------------- SplitFocusedHorizontal splits the focused panel with a horizontal divider, placing a new panel of the given type below.
func (*Engine) SplitFocusedVertical ¶
SplitFocusedVertical splits the focused panel with a vertical divider, placing a new panel of the given type to the right.
func (*Engine) StatusBarHeight ¶
StatusBarHeight returns the height reserved for the status bar.
func (*Engine) TabBarHeight ¶
TabBarHeight returns the exported tab bar height for rendering.
func (*Engine) TabManager ¶
func (e *Engine) TabManager() *TabManager
TabManager returns the underlying tab manager.
func (*Engine) ToggleZoom ¶
func (e *Engine) ToggleZoom()
ToggleZoom toggles the zoom state of the focused panel.
func (*Engine) Update ¶
Update routes the given message to the appropriate panel(s). Key and mouse events go only to the focused panel (we don't want unfocused panels reacting to keyboard input or mouse clicks). All other messages (async results, cross-panel notifications, etc.) are broadcast to ALL panels in the active tab, following the standard Bubble Tea v2 composite model pattern where all sub-models see all non-input messages.
type LeafNode ¶
type LeafNode struct {
Panel string
}
LeafNode is a terminal node in the layout tree, holding a panel name.
type Node ¶
type Node interface {
// PanelNames returns all panel names contained in this subtree.
PanelNames() []string
// Clone returns a deep copy of the node.
Clone() Node
// contains filtered or unexported methods
}
Node is the interface for layout tree nodes. A node is either a SplitNode (with two children) or a LeafNode (holding a panel name).
func RemoveLeaf ¶
RemoveLeaf removes the leaf named targetPanel from the tree, collapsing its parent SplitNode so the sibling takes the parent's place. Returns the new root and whether the panel was found.
newTree, ok := RemoveLeaf(tab.Tree, "terminal")
func SplitLeaf ¶
SplitLeaf replaces the leaf named targetPanel with a new SplitNode containing the original leaf as the first child and a new leaf (newPanel) as the second child, using the given direction and a 0.5 ratio. Returns the (possibly new) root node. The caller must assign the result back to their tree reference:
tab.Tree = SplitLeaf(tab.Tree, "preview", Vertical, "terminal")
type PanelFactory ¶
PanelFactory is a constructor function for creating panels by name.
type Preset ¶
Preset is a named layout configuration consisting of a layout tree and the list of panel names it requires.
func AgentPreset ¶
func AgentPreset() Preset
AgentPreset returns the "agent" layout: filetree (20%) | terminal (40%) | agents (40%)
func ExplorerPreset ¶
func ExplorerPreset() Preset
ExplorerPreset returns the default "explorer" layout: Left column (30%): filetree (35%) on top, gitinfo (25%), github (20%), commits (20%) on bottom. Right column (70%): preview (100%).
func FullPreset ¶
func FullPreset() Preset
FullPreset returns the "full" layout: filetree (15%) | gitstatus (25%) | preview (35%) | terminal (25%)
func GitPreset ¶
func GitPreset() Preset
GitPreset returns the "git" layout: filetree (30%) | preview (70%) The filetree already shows git status indicators on each file, so a separate gitstatus panel is not needed.
func ReviewPreset ¶
func ReviewPreset() Preset
ReviewPreset returns the "review" layout: filetree (20%) | review (50%) | context (30%)
type PreviewPosition ¶
type PreviewPosition int
--------------------------------------------------------------------------- Preview position cycling --------------------------------------------------------------------------- PreviewPosition represents where the preview panel sits relative to the filetree.
const ( PreviewRight PreviewPosition = iota // default: filetree | preview PreviewBottom // filetree on top, preview on bottom PreviewLeft // preview | filetree PreviewTop // preview on top, filetree on bottom )
func PreviewPositionFromString ¶
func PreviewPositionFromString(s string) PreviewPosition
PreviewPositionFromString converts a string to a PreviewPosition. Unrecognised values default to PreviewRight.
func (PreviewPosition) String ¶
func (p PreviewPosition) String() string
String returns the string representation of a PreviewPosition.
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry maps panel names to their factory functions, enabling dynamic panel creation by the layout engine.
func (*Registry) Create ¶
Create instantiates a panel by name using its registered factory. Returns an error if the name is not registered.
func (*Registry) Register ¶
func (r *Registry) Register(name string, factory PanelFactory)
Register adds a panel factory under the given name. If a factory with that name already exists, it is replaced.
type SplitNode ¶
type SplitNode struct {
First Node // left or top child
Second Node // right or bottom child
Direction Direction
Ratio float64
}
SplitNode divides space between two children according to a direction and ratio. Ratio is the fraction of space allocated to the first (left/top) child, in the range (0, 1).
func FindSplitContaining ¶
FindSplitContaining finds the innermost SplitNode whose First or Second child directly contains the given panel name. Returns the split node and which child ("first" or "second") contains it, or nil if not found. For nested trees, this returns the deepest split that directly parents the leaf — the one whose ratio directly affects the panel's size.
func (*SplitNode) PanelNames ¶
PanelNames implements Node.
type TabManager ¶
type TabManager struct {
// contains filtered or unexported fields
}
TabManager manages a set of tabs, each with its own layout tree. Only one tab is active at a time.
func NewTabManager ¶
func NewTabManager(name string, tree Node) *TabManager
NewTabManager creates a tab manager with a single initial tab.
func (*TabManager) ActiveIndex ¶
func (tm *TabManager) ActiveIndex() int
ActiveIndex returns the index of the active tab.
func (*TabManager) ActiveTab ¶
func (tm *TabManager) ActiveTab() *Tab
ActiveTab returns the currently active tab.
func (*TabManager) Add ¶
func (tm *TabManager) Add(name string, tree Node)
Add creates a new tab with the given name and layout tree, appended after the current active tab. The new tab becomes active.
func (*TabManager) Close ¶
func (tm *TabManager) Close(idx int) error
Close removes the tab at the given index. Returns an error if it's the last tab or the index is out of range.
func (*TabManager) MoveLeft ¶
func (tm *TabManager) MoveLeft()
MoveLeft swaps the active tab with its left neighbor. No-op if already at the leftmost position.
func (*TabManager) MoveRight ¶
func (tm *TabManager) MoveRight()
MoveRight swaps the active tab with its right neighbor. No-op if already at the rightmost position.
func (*TabManager) NextTab ¶
func (tm *TabManager) NextTab()
NextTab cycles to the next tab, wrapping around.
func (*TabManager) PrevTab ¶
func (tm *TabManager) PrevTab()
PrevTab cycles to the previous tab, wrapping around.
func (*TabManager) Rename ¶
func (tm *TabManager) Rename(idx int, name string) error
Rename changes the name of the tab at the given index.
func (*TabManager) Select ¶
func (tm *TabManager) Select(idx int) error
Select sets the active tab to the given index. Returns an error if the index is out of range.