diff options
| -rw-r--r-- | internal/tui/flamegraph/model.go | 104 | ||||
| -rw-r--r-- | internal/tui/flamegraph/model_test.go | 31 |
2 files changed, 135 insertions, 0 deletions
diff --git a/internal/tui/flamegraph/model.go b/internal/tui/flamegraph/model.go new file mode 100644 index 0000000..dd77201 --- /dev/null +++ b/internal/tui/flamegraph/model.go @@ -0,0 +1,104 @@ +package flamegraph + +import ( + "image/color" + coreflamegraph "ior/internal/flamegraph" + common "ior/internal/tui/common" + + tea "charm.land/bubbletea/v2" +) + +type snapshotNode struct { + Name string `json:"n"` + Value uint64 `json:"v"` + Total uint64 `json:"t"` + Children []*snapshotNode `json:"c,omitempty"` +} + +type zoomState struct { + path string + selectedIdx int +} + +type frameSpring struct{} + +// Model is the Bubble Tea model for the TUI flamegraph tab. +type Model struct { + liveTrie *coreflamegraph.LiveTrie + lastVersion uint64 + snapshot *snapshotNode + + frames []tuiFrame + targetFrames []tuiFrame + width int + height int + + selectedIdx int + zoomStack []zoomState + zoomRoot *snapshotNode + + searchActive bool + searchQuery string + matchIndices map[int]bool + + fieldPresets [][]string + fieldIndex int + + springs []frameSpring + paused bool + isDark bool +} + +// tuiFrame stores one terminal flamegraph frame cell. +type tuiFrame struct { + Name string + Col int + Row int + Width int + Total uint64 + Percent float64 + Fill color.Color + Depth int + Path string +} + +// NewModel constructs a flamegraph tab model with default state. +func NewModel(liveTrie *coreflamegraph.LiveTrie) Model { + return Model{ + liveTrie: liveTrie, + matchIndices: make(map[int]bool), + fieldPresets: [][]string{ + {"comm", "path"}, + {"tracepoint", "comm", "path"}, + {"pid", "tid", "comm", "path"}, + }, + isDark: true, + } +} + +// Init starts the flamegraph model. +func (m Model) Init() tea.Cmd { + return nil +} + +// Update handles incoming messages. +func (m Model) Update(tea.Msg) (tea.Model, tea.Cmd) { + return m, nil +} + +// View renders the flamegraph viewport. +func (m Model) View() tea.View { + content := common.PanelStyle.Render("Flame: model scaffold") + return tea.NewView(content) +} + +// SetViewport updates model render dimensions. +func (m *Model) SetViewport(width, height int) { + m.width = width + m.height = height +} + +// SetDarkMode sets the active color theme mode. +func (m *Model) SetDarkMode(isDark bool) { + m.isDark = isDark +} diff --git a/internal/tui/flamegraph/model_test.go b/internal/tui/flamegraph/model_test.go new file mode 100644 index 0000000..42729bb --- /dev/null +++ b/internal/tui/flamegraph/model_test.go @@ -0,0 +1,31 @@ +package flamegraph + +import "testing" + +func TestNewModelDefaults(t *testing.T) { + m := NewModel(nil) + if m.liveTrie != nil { + t.Fatalf("expected nil liveTrie when constructor input is nil") + } + if m.matchIndices == nil { + t.Fatalf("expected matchIndices map to be initialized") + } + if len(m.fieldPresets) == 0 { + t.Fatalf("expected default field presets to be initialized") + } + if !m.isDark { + t.Fatalf("expected dark mode enabled by default") + } +} + +func TestSetViewportAndDarkMode(t *testing.T) { + m := NewModel(nil) + m.SetViewport(120, 40) + m.SetDarkMode(false) + if m.width != 120 || m.height != 40 { + t.Fatalf("expected viewport 120x40, got %dx%d", m.width, m.height) + } + if m.isDark { + t.Fatalf("expected dark mode to be disabled") + } +} |
