diff options
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/tui/flamegraph/keys.go | 96 | ||||
| -rw-r--r-- | internal/tui/flamegraph/model.go | 88 |
2 files changed, 96 insertions, 88 deletions
diff --git a/internal/tui/flamegraph/keys.go b/internal/tui/flamegraph/keys.go new file mode 100644 index 0000000..5b6dd04 --- /dev/null +++ b/internal/tui/flamegraph/keys.go @@ -0,0 +1,96 @@ +package flamegraph + +import ( + "strings" + + "charm.land/bubbles/v2/key" + tea "charm.land/bubbletea/v2" +) + +func keyString(msg tea.KeyPressMsg) string { + if s := msg.String(); s != "" { + return s + } + return msg.Text +} + +func isSearchOpenKey(msg tea.KeyPressMsg) bool { return keyString(msg) == "/" } +func isNextMatchKey(msg tea.KeyPressMsg) bool { return keyString(msg) == "n" } +func isPrevMatchKey(msg tea.KeyPressMsg) bool { return keyString(msg) == "N" } +func isPauseKey(msg tea.KeyPressMsg) bool { + k := keyString(msg) + return k == " " || k == "space" || msg.Code == tea.KeySpace +} +func isResetBaselineKey(msg tea.KeyPressMsg) bool { + return keyString(msg) == "r" +} +func isCycleOrderKey(msg tea.KeyPressMsg) bool { return keyString(msg) == "o" } +func isCycleMetricKey(msg tea.KeyPressMsg) bool { + return keyString(msg) == "b" +} +func isToggleHeightKey(msg tea.KeyPressMsg) bool { return keyString(msg) == "v" } +func isHelpToggleKey(msg tea.KeyPressMsg) bool { return keyString(msg) == "?" } + +func isZoomInKey(msg tea.KeyPressMsg, keys flameKeyMap) bool { + return key.Matches(msg, keys.ZoomIn) || msg.Code == tea.KeyEnter || strings.EqualFold(keyString(msg), "enter") +} + +func isZoomUndoKey(msg tea.KeyPressMsg, keys flameKeyMap) bool { + return key.Matches(msg, keys.ZoomUndo) || msg.Code == tea.KeyBackspace || msg.Code == tea.KeyEsc +} + +func isZoomResetKey(msg tea.KeyPressMsg, keys flameKeyMap) bool { + return key.Matches(msg, keys.ZoomReset) +} + +func isMoveShallowerKey(msg tea.KeyPressMsg, keys flameKeyMap) bool { + k := keyString(msg) + return key.Matches(msg, keys.MoveShallower) || msg.Code == tea.KeyDown || keyMatchesDirection(k, "down", 'B') +} + +func isMoveDeeperKey(msg tea.KeyPressMsg, keys flameKeyMap) bool { + k := keyString(msg) + return key.Matches(msg, keys.MoveDeeper) || msg.Code == tea.KeyUp || keyMatchesDirection(k, "up", 'A') +} + +func isPrevSiblingKey(msg tea.KeyPressMsg, keys flameKeyMap) bool { + k := keyString(msg) + return key.Matches(msg, keys.PrevSibling) || msg.Code == tea.KeyLeft || keyMatchesDirection(k, "left", 'D') +} + +func isNextSiblingKey(msg tea.KeyPressMsg, keys flameKeyMap) bool { + k := keyString(msg) + return key.Matches(msg, keys.NextSibling) || msg.Code == tea.KeyRight || keyMatchesDirection(k, "right", 'C') +} + +func isJumpTopKey(msg tea.KeyPressMsg, keys flameKeyMap) bool { + k := strings.ToLower(keyString(msg)) + return key.Matches(msg, keys.JumpTop) || msg.Code == tea.KeyPgUp || k == "pgup" || k == "pageup" +} + +func isJumpRootKey(msg tea.KeyPressMsg, keys flameKeyMap) bool { + k := strings.ToLower(keyString(msg)) + return key.Matches(msg, keys.JumpRoot) || msg.Code == tea.KeyPgDown || k == "pgdown" || k == "pgdn" || k == "pagedown" +} + +func keyMatchesDirection(keyName, plain string, ansiFinal byte) bool { + if keyName == plain || strings.HasSuffix(keyName, "+"+plain) { + return true + } + return isArrowEscapeSequence(keyName, ansiFinal) +} + +func isArrowEscapeSequence(value string, ansiFinal byte) bool { + body, ok := strings.CutPrefix(value, "\x1b") + if !ok || len(body) < 2 { + return false + } + switch body[0] { + case '[': + return body[len(body)-1] == ansiFinal + case 'O': + return len(body) == 2 && body[1] == ansiFinal + default: + return false + } +} diff --git a/internal/tui/flamegraph/model.go b/internal/tui/flamegraph/model.go index b73368f..f65925a 100644 --- a/internal/tui/flamegraph/model.go +++ b/internal/tui/flamegraph/model.go @@ -940,94 +940,6 @@ func (m Model) visibleTraversalOrder() []int { return visibleTraversalOrder(m.frames, m.searchQuery, m.filterVisible) } -func keyString(msg tea.KeyPressMsg) string { - if s := msg.String(); s != "" { - return s - } - return msg.Text -} - -func isSearchOpenKey(msg tea.KeyPressMsg) bool { return keyString(msg) == "/" } -func isNextMatchKey(msg tea.KeyPressMsg) bool { return keyString(msg) == "n" } -func isPrevMatchKey(msg tea.KeyPressMsg) bool { return keyString(msg) == "N" } -func isPauseKey(msg tea.KeyPressMsg) bool { - k := keyString(msg) - return k == " " || k == "space" || msg.Code == tea.KeySpace -} -func isResetBaselineKey(msg tea.KeyPressMsg) bool { - return keyString(msg) == "r" -} -func isCycleOrderKey(msg tea.KeyPressMsg) bool { return keyString(msg) == "o" } -func isCycleMetricKey(msg tea.KeyPressMsg) bool { - return keyString(msg) == "b" -} -func isToggleHeightKey(msg tea.KeyPressMsg) bool { return keyString(msg) == "v" } -func isHelpToggleKey(msg tea.KeyPressMsg) bool { return keyString(msg) == "?" } - -func isZoomInKey(msg tea.KeyPressMsg, keys flameKeyMap) bool { - return key.Matches(msg, keys.ZoomIn) || msg.Code == tea.KeyEnter || strings.EqualFold(keyString(msg), "enter") -} - -func isZoomUndoKey(msg tea.KeyPressMsg, keys flameKeyMap) bool { - return key.Matches(msg, keys.ZoomUndo) || msg.Code == tea.KeyBackspace || msg.Code == tea.KeyEsc -} - -func isZoomResetKey(msg tea.KeyPressMsg, keys flameKeyMap) bool { - return key.Matches(msg, keys.ZoomReset) -} - -func isMoveShallowerKey(msg tea.KeyPressMsg, keys flameKeyMap) bool { - k := keyString(msg) - return key.Matches(msg, keys.MoveShallower) || msg.Code == tea.KeyDown || keyMatchesDirection(k, "down", 'B') -} - -func isMoveDeeperKey(msg tea.KeyPressMsg, keys flameKeyMap) bool { - k := keyString(msg) - return key.Matches(msg, keys.MoveDeeper) || msg.Code == tea.KeyUp || keyMatchesDirection(k, "up", 'A') -} - -func isPrevSiblingKey(msg tea.KeyPressMsg, keys flameKeyMap) bool { - k := keyString(msg) - return key.Matches(msg, keys.PrevSibling) || msg.Code == tea.KeyLeft || keyMatchesDirection(k, "left", 'D') -} - -func isNextSiblingKey(msg tea.KeyPressMsg, keys flameKeyMap) bool { - k := keyString(msg) - return key.Matches(msg, keys.NextSibling) || msg.Code == tea.KeyRight || keyMatchesDirection(k, "right", 'C') -} - -func isJumpTopKey(msg tea.KeyPressMsg, keys flameKeyMap) bool { - k := strings.ToLower(keyString(msg)) - return key.Matches(msg, keys.JumpTop) || msg.Code == tea.KeyPgUp || k == "pgup" || k == "pageup" -} - -func isJumpRootKey(msg tea.KeyPressMsg, keys flameKeyMap) bool { - k := strings.ToLower(keyString(msg)) - return key.Matches(msg, keys.JumpRoot) || msg.Code == tea.KeyPgDown || k == "pgdown" || k == "pgdn" || k == "pagedown" -} - -func keyMatchesDirection(keyName, plain string, ansiFinal byte) bool { - if keyName == plain || strings.HasSuffix(keyName, "+"+plain) { - return true - } - return isArrowEscapeSequence(keyName, ansiFinal) -} - -func isArrowEscapeSequence(value string, ansiFinal byte) bool { - body, ok := strings.CutPrefix(value, "\x1b") - if !ok || len(body) < 2 { - return false - } - switch body[0] { - case '[': - return body[len(body)-1] == ansiFinal - case 'O': - return len(body) == 2 && body[1] == ansiFinal - default: - return false - } -} - // visibleRowOffset delegates row offset calculation to SelectionManager. func (m Model) visibleRowOffset() int { return visibleRowOffset(m.frames, m.height, m.searchQuery, m.filterVisible) |
