diff options
| author | Paul Buetow <paul@buetow.org> | 2026-03-06 14:21:30 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-03-06 14:21:30 +0200 |
| commit | aa4f638206b9b79de267f9a1daab7ec6698b241d (patch) | |
| tree | 44c913b6be46460c184eac580d26a11973a6e283 /internal/tui/flamegraph/model.go | |
| parent | ef12ce837176bd21deb455eb50a6c839af02b510 (diff) | |
Fix real live flamegraph key handling and startup viewport sync
Diffstat (limited to 'internal/tui/flamegraph/model.go')
| -rw-r--r-- | internal/tui/flamegraph/model.go | 39 |
1 files changed, 35 insertions, 4 deletions
diff --git a/internal/tui/flamegraph/model.go b/internal/tui/flamegraph/model.go index b205d33..66fefc9 100644 --- a/internal/tui/flamegraph/model.go +++ b/internal/tui/flamegraph/model.go @@ -87,8 +87,7 @@ type Model struct { animation AnimationState animating bool paused bool - // hasNavigableSnapshot flips once we have at least one selectable non-root - // frame. Paused mode can still bootstrap snapshots until then. + // hasNavigableSnapshot flips once we have at least one selectable non-root frame. hasNavigableSnapshot bool isDark bool keys flameKeyMap @@ -308,8 +307,9 @@ func (m *Model) RefreshFromLiveTrie() bool { if m.liveTrie == nil { return false } - // Keep bootstrapping while paused until we have a navigable snapshot. - if m.paused && m.snapshot != nil && m.hasNavigableSnapshot { + // Once a snapshot exists, paused mode must freeze it regardless of current + // navigability so selection and percentages remain stable. + if m.paused && m.snapshot != nil { return false } version := m.liveTrie.Version() @@ -371,6 +371,11 @@ func (m *Model) SetDarkMode(isDark bool) { } func (m *Model) rebuildFrames(animate bool) { + prevPath := "" + if len(m.frames) > 0 && m.selectedIdx >= 0 && m.selectedIdx < len(m.frames) { + prevPath = m.frames[m.selectedIdx].Path + } + var root *snapshotNode rootPath := "" if m.zoomRoot != nil { @@ -391,6 +396,7 @@ func (m *Model) rebuildFrames(animate bool) { if len(m.frames) > 1 { m.hasNavigableSnapshot = true } + m.restoreSelectionByPath(prevPath) m.clampSelection() m.recomputeFilterState() m.ensureSelectionNavigable() @@ -398,6 +404,31 @@ func (m *Model) rebuildFrames(animate bool) { m.subtreeSet = computeSubtreeSetInto(m.frames, m.selectedIdx, m.subtreeSet) } +func (m *Model) restoreSelectionByPath(path string) { + if path == "" || len(m.frames) == 0 { + return + } + if idx := m.frameIndexByPath(path); idx >= 0 { + m.selectedIdx = idx + return + } + for idx, frame := range m.frames { + if hasPathBoundaryPrefix(path, frame.Path) || hasPathBoundaryPrefix(frame.Path, path) { + m.selectedIdx = idx + return + } + } +} + +func (m Model) frameIndexByPath(path string) int { + for idx, frame := range m.frames { + if frame.Path == path { + return idx + } + } + return -1 +} + func (m *Model) zoomIn() { if len(m.frames) == 0 || m.snapshot == nil { m.statusMessage = "Zoom unavailable: no frame selected" |
