diff options
| author | Paul Buetow <paul@buetow.org> | 2026-03-06 08:18:51 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-03-06 08:18:51 +0200 |
| commit | 4445eefb69a50d178d4c6bd02fd534312d774542 (patch) | |
| tree | c70efee49a5ce574bf472bd9cce1b5170234efd2 /internal/tui/flamegraph/model.go | |
| parent | c6ec3b3ee34c9e77daa7159e8c164e413c2101b5 (diff) | |
Keep flame selection visible and improve arrow-key fallback
Diffstat (limited to 'internal/tui/flamegraph/model.go')
| -rw-r--r-- | internal/tui/flamegraph/model.go | 56 |
1 files changed, 54 insertions, 2 deletions
diff --git a/internal/tui/flamegraph/model.go b/internal/tui/flamegraph/model.go index 4453452..27e356b 100644 --- a/internal/tui/flamegraph/model.go +++ b/internal/tui/flamegraph/model.go @@ -194,9 +194,9 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { case key.Matches(msg, m.keys.ZoomReset): m.zoomReset() case key.Matches(msg, m.keys.MoveShallower): - m.moveVertical(-1) + m.moveVerticalWithFallback(-1, 1) case key.Matches(msg, m.keys.MoveDeeper): - m.moveVertical(1) + m.moveVerticalWithFallback(1, -1) case key.Matches(msg, m.keys.PrevSibling): m.moveSibling(-1) case key.Matches(msg, m.keys.NextSibling): @@ -348,6 +348,7 @@ func (m *Model) rebuildFrames(animate bool) { m.frames = append(m.frames[:0], m.targetFrames...) } m.clampSelection() + m.ensureSelectionVisible() m.subtreeSet = computeSubtreeSetInto(m.frames, m.selectedIdx, m.subtreeSet) } @@ -435,6 +436,14 @@ func (m *Model) moveVertical(delta int) { m.selectedIdx = best } +func (m *Model) moveVerticalWithFallback(primaryDelta, fallbackDelta int) { + before := m.selectedIdx + m.moveVertical(primaryDelta) + if m.selectedIdx == before && fallbackDelta != 0 { + m.moveVertical(fallbackDelta) + } +} + func (m *Model) moveSibling(delta int) { if len(m.frames) == 0 { return @@ -517,3 +526,46 @@ func (m Model) currentRootPath() string { } return m.frames[0].Path } + +func (m Model) visibleRowOffset() int { + if len(m.frames) == 0 { + return 0 + } + availableRows := m.height - 2 // toolbar + status + if availableRows <= 0 { + return 0 + } + maxRow := maxFrameRow(m.frames) + if maxRow+1 <= availableRows { + return 0 + } + return maxRow + 1 - availableRows +} + +func (m *Model) ensureSelectionVisible() { + if len(m.frames) == 0 { + return + } + m.clampSelection() + rowOffset := m.visibleRowOffset() + selected := m.frames[m.selectedIdx] + if selected.Row >= rowOffset { + return + } + + bestIdx := -1 + bestScore := int(^uint(0) >> 1) + for idx, frame := range m.frames { + if frame.Row < rowOffset { + continue + } + score := abs(frame.Row-rowOffset)*1000 + abs(frame.Col-selected.Col) + if score < bestScore { + bestIdx = idx + bestScore = score + } + } + if bestIdx >= 0 { + m.selectedIdx = bestIdx + } +} |
