# How the witr TUI Visually Integrates Process Details with the Process Ancestry Tree View

> Discover how the witr TUI visually integrates process details with its ancestry tree view. Learn about its dynamic interface and context-aware navigation.

- Repository: [Pranshu Parmar/witr](https://github.com/pranshuparmar/witr)
- Tags: architecture
- Published: 2026-08-10

---

**The witr TUI renders process details alongside a live ancestry tree by splitting the interface into horizontal panes using `lipgloss.JoinHorizontal`, dynamically updating the tree viewport header based on the selected PID, and maintaining the tree context when transitioning to detailed process views.**

The pranshuparmar/witr repository implements a terminal user interface (TUI) that combines real-time process monitoring with hierarchical relationship visualization. Understanding how the witr TUI visually integrates process details with the process ancestry tree view reveals a sophisticated layout system built on the Bubble Tea framework and Lipgloss styling library.

## Dual-Pane Architecture in the Processes Tab

When the **Processes** tab is active, the interface presents two complementary visualization areas. The **Process List Pane** displays a tabular view of all discovered processes using `m.table`, while the **Ancestry Tree Pane** renders the parent-child relationship hierarchy for the currently highlighted process within `m.treeViewport`.

This split-view approach allows operators to scan through process lists while simultaneously inspecting the lineage of any selected entry. The architecture relies on distinct model fields defined in [`internal/tui/model.go`](https://github.com/pranshuparmar/witr/blob/main/internal/tui/model.go), where the `treeViewport` field manages the scrollable tree content independently from the main process table.

## Horizontal Layout Implementation with Lipgloss

The visual joining of these panes occurs in the `viewList` function within [`internal/tui/view.go`](https://github.com/pranshuparmar/witr/blob/main/internal/tui/view.go). Around line 37, the code uses `lipgloss.JoinHorizontal` to arrange the table and tree viewport side-by-side:

```go
mainContent := lipgloss.JoinHorizontal(lipgloss.Top,
    lipgloss.NewStyle().Width(processListPaneWidth).Render(m.table.View()),
    treeContainerStyle.Render(
        lipgloss.JoinVertical(lipgloss.Left,
            treeHeaderStyle.Render(treeHeader),
            paddedStyle.Render(m.treeViewport.View()),
        ),
    ),
)

```

The layout applies specific styling constraints to each pane. The process list receives a fixed width allocation, while the tree container stacks elements vertically—placing the dynamic header above the scrollable viewport content. This horizontal composition ensures that both data sources remain visible within the terminal dimensions without overlapping.

## Dynamic Tree Header and Scroll Indicators

The tree pane header adapts to user interaction, displaying either **"Details"** or **"PID <selected>"** depending on the current selection state (lines 81-85 in [`internal/tui/view.go`](https://github.com/pranshuparmar/witr/blob/main/internal/tui/view.go)). This immediate visual feedback confirms which process's ancestry is currently rendered in the adjacent viewport.

Navigation state is communicated through arrow symbols (↕, ↑, ↓) that indicate scroll position within the tree. These indicators update based on `AtTop` and `AtBottom` checks on the viewport (lines 87-93), alerting users when additional ancestry nodes exist beyond the current visible area.

## Populating the Ancestry Tree from Process Data

The ancestry content generation logic resides in [`internal/tui/data.go`](https://github.com/pranshuparmar/witr/blob/main/internal/tui/data.go). When a user selects a different process, the application formats the parent-child hierarchy and injects it into the viewport around line 553:

```go
m.treeViewport.SetContent("")               // clear old content
if m.treeViewport.Width > 0 {
    content = wrap.String(content, m.treeViewport.Width)
}
m.treeViewport.SetContent(content)          // set new ancestry tree

```

The code first clears existing content to prevent visual artifacts, then applies `wrap.String` to ensure the tree renders correctly within the available terminal width before setting the final formatted string. This dynamic content refresh keeps the ancestry visualization synchronized with the user's current selection in the process table.

## State Transitions to the Detail View

Pressing **Enter** on a process row triggers a state transition to `stateDetail`, which activates the detailed process view while preserving the tree context. The main `View` function in [`internal/tui/view.go`](https://github.com/pranshuparmar/witr/blob/main/internal/tui/view.go) handles this transition (around lines 25-33):

```go
case stateDetail:
    if m.selectedDetail == nil && m.selectedContainer == nil {
        return m.viewDetailLoading(outerStyle)
    }
    if m.selectedContainer != nil {
        return m.viewContainerDetail(outerStyle)
    }
    return m.viewProcessDetail(outerStyle)

```

The `viewProcessDetail` method renders comprehensive process information—including environment variables and command-line arguments—while maintaining the ancestry tree pane on the left side of the interface. This preserves the visual relationship between the detailed process data and its hierarchical position within the system.

## Summary

- **Side-by-side layout**: The `viewList` function uses `lipgloss.JoinHorizontal` to combine the process table and tree viewport in [`internal/tui/view.go`](https://github.com/pranshuparmar/witr/blob/main/internal/tui/view.go).
- **Dynamic content**: The `treeViewport` receives formatted ancestry strings via `SetContent` in [`internal/tui/data.go`](https://github.com/pranshuparmar/witr/blob/main/internal/tui/data.go) whenever the selection changes.
- **Context preservation**: Switching to `stateDetail` displays the `viewProcessDetail` pane while keeping the ancestry tree visible for reference.
- **Scroll management**: Arrow indicators update based on viewport position checks to signal additional content availability.
- **Header synchronization**: The tree pane header reflects the currently selected PID, providing immediate orientation within the process hierarchy.

## Frequently Asked Questions

### How does witr handle the layout of multiple panes?

The witr TUI uses the Lipgloss library's `JoinHorizontal` function to arrange the process list table and ancestry tree viewport side-by-side. This approach, implemented in [`internal/tui/view.go`](https://github.com/pranshuparmar/witr/blob/main/internal/tui/view.go), allows both components to share screen real estate while maintaining independent scroll states and styling contexts.

### What triggers the ancestry tree to update in the witr TUI?

The ancestry tree updates when the user highlights a different process in the main table. This selection change triggers a content refresh in [`internal/tui/data.go`](https://github.com/pranshuparmar/witr/blob/main/internal/tui/data.go), where the application generates a new parent-child hierarchy string and calls `m.treeViewport.SetContent` to render the updated lineage information.

### Can users scroll through the ancestry tree independently?

Yes, the `treeViewport` operates as an independent scrollable region within the TUI. The component tracks its own scroll position using `AtTop` and `AtBottom` methods, displaying arrow indicators (↕, ↑, ↓) to signal when additional ancestry nodes exist above or below the current view. Scroll handling logic is managed in [`internal/tui/update.go`](https://github.com/pranshuparmar/witr/blob/main/internal/tui/update.go).

### Which files control the visual integration in witr?

Four primary files orchestrate the visual integration: [`internal/tui/view.go`](https://github.com/pranshuparmar/witr/blob/main/internal/tui/view.go) handles layout rendering and state transitions; [`internal/tui/data.go`](https://github.com/pranshuparmar/witr/blob/main/internal/tui/data.go) prepares ancestry tree content; [`internal/tui/model.go`](https://github.com/pranshuparmar/witr/blob/main/internal/tui/model.go) defines the viewport and table structures; and [`internal/tui/update.go`](https://github.com/pranshuparmar/witr/blob/main/internal/tui/update.go) manages viewport dimension updates and scrolling behavior.