feat: add navigation and window size handlers with corresponding tests

This commit is contained in:
Stevan Freeborn
2025-12-29 13:45:28 -06:00
parent 3bc730db87
commit 3d3877ca41
17 changed files with 1012 additions and 0 deletions
@@ -0,0 +1,41 @@
package handlers
import (
"slices"
"github.com/StevanFreeborn/term-tier/internal/state"
tea "github.com/charmbracelet/bubbletea"
)
type downNavigationHandler struct {
keys []string
description string
}
func NewDownNavigationHandler() KeyMsgHandler {
return downNavigationHandler{
keys: []string{"down", "j"},
description: "Move down",
}
}
func (h downNavigationHandler) KeysHandled() []string {
return h.keys
}
func (h downNavigationHandler) Description() string {
return h.description
}
func (h downNavigationHandler) Match(s state.State, msg tea.KeyMsg) bool {
if s.Mode() != state.NavigationMode {
return false
}
return slices.Contains(h.keys, msg.String())
}
func (h downNavigationHandler) Handle(s state.State, msg tea.KeyMsg) tea.Cmd {
s.MoveDown()
return nil
}
@@ -0,0 +1,111 @@
package handlers_test
import (
"slices"
"testing"
"github.com/StevanFreeborn/term-tier/internal/core"
"github.com/StevanFreeborn/term-tier/internal/handlers"
"github.com/StevanFreeborn/term-tier/internal/state"
tea "github.com/charmbracelet/bubbletea"
)
func TestNewDownNavigationHandler(t *testing.T) {
h := handlers.NewDownNavigationHandler()
if h.Description() != "Move down" {
t.Errorf("Expected description 'Move down', got %q", h.Description())
}
keys := h.KeysHandled()
if !slices.Contains(keys, "down") || !slices.Contains(keys, "j") {
t.Errorf("Expected keys ['down', 'j'], got %v", keys)
}
}
func TestDownNavigationHandler_Match(t *testing.T) {
h := handlers.NewDownNavigationHandler()
tests := []struct {
name string
mode state.Mode
key string
expected bool
}{
{
name: "Matches 'down' in Navigation Mode",
mode: state.NavigationMode,
key: "down",
expected: true,
},
{
name: "Matches 'j' in Navigation Mode",
mode: state.NavigationMode,
key: "j",
expected: true,
},
{
name: "Ignores 'down' in Input Mode",
mode: state.InputMode,
key: "down",
expected: false,
},
{
name: "Ignores 'j' in Input Mode",
mode: state.InputMode,
key: "j",
expected: false,
},
{
name: "Ignores other keys in Navigation Mode",
mode: state.NavigationMode,
key: "up",
expected: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := state.New(state.WithMode(tt.mode))
msg := tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune(tt.key)}
if tt.key == "down" {
msg = tea.KeyMsg{Type: tea.KeyDown}
}
if got := h.Match(s, msg); got != tt.expected {
t.Errorf("Match() = %v, want %v", got, tt.expected)
}
})
}
}
func TestDownNavigationHandler_Handle(t *testing.T) {
h := handlers.NewDownNavigationHandler()
fullTiers := make([]core.Tier, 6)
fullTiers[0] = core.Tier{Name: "S", Items: []core.Item{"1", "2", "3"}}
fullTiers[1] = core.Tier{Name: "A", Items: []core.Item{"4"}}
s := state.New(
state.WithTiers(fullTiers),
state.WithCursor(0, 2), // Start at the end of Row 0
state.WithMode(state.NavigationMode),
)
msg := tea.KeyMsg{Type: tea.KeyDown}
cmd := h.Handle(s, msg)
if s.CursorRow() != 1 {
t.Errorf("Expected cursor to move to Row 1, got %d", s.CursorRow())
}
if s.CursorCol() != 0 {
t.Errorf("Expected cursor column to clamp to 0, got %d", s.CursorCol())
}
if cmd != nil {
t.Error("Expected Handle to return nil, got a command")
}
}
+101
View File
@@ -0,0 +1,101 @@
package handlers_test
import (
"slices"
"testing"
"github.com/StevanFreeborn/term-tier/internal/handlers"
"github.com/StevanFreeborn/term-tier/internal/state"
tea "github.com/charmbracelet/bubbletea"
)
func TestNewHelpHandler(t *testing.T) {
h := handlers.NewHelpHandler()
if h.Description() != "Toggle help menu" {
t.Errorf("Expected description 'Toggle help menu', got %q", h.Description())
}
keys := h.KeysHandled()
if !slices.Contains(keys, "?") {
t.Errorf("Expected keys ['?'], got %v", keys)
}
}
func TestHelpHandler_Match(t *testing.T) {
h := handlers.NewHelpHandler()
tests := []struct {
name string
mode state.Mode
key string
expected bool
}{
{
name: "Matches '?' in Navigation Mode",
mode: state.NavigationMode,
key: "?",
expected: true,
},
{
name: "Matches '?' in Help Mode",
mode: state.HelpMode,
key: "?",
expected: true,
},
{
name: "Ignores '?' in Input Mode",
mode: state.InputMode,
key: "?",
expected: false,
},
{
name: "Ignores other keys in Navigation Mode",
mode: state.NavigationMode,
key: "q",
expected: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := state.New(state.WithMode(tt.mode))
msg := tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune(tt.key)}
if got := h.Match(s, msg); got != tt.expected {
t.Errorf("Match() = %v, want %v", got, tt.expected)
}
})
}
}
func TestHelpHandler_Handle(t *testing.T) {
h := handlers.NewHelpHandler()
t.Run("Toggles from Navigation to Help", func(t *testing.T) {
s := state.New(state.WithMode(state.NavigationMode))
msg := tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("?")}
cmd := h.Handle(s, msg)
if s.Mode() != state.HelpMode {
t.Errorf("Expected mode to switch to HelpMode, got %v", s.Mode())
}
if cmd != nil {
t.Error("Expected nil command, got non-nil")
}
})
t.Run("Toggles from Help to Navigation", func(t *testing.T) {
s := state.New(state.WithMode(state.HelpMode))
msg := tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("?")}
h.Handle(s, msg)
if s.Mode() != state.NavigationMode {
t.Errorf("Expected mode to switch to NavigationMode, got %v", s.Mode())
}
})
}
+38
View File
@@ -0,0 +1,38 @@
package handlers
import (
"slices"
"github.com/StevanFreeborn/term-tier/internal/state"
tea "github.com/charmbracelet/bubbletea"
)
type helpHandler struct {
keys []string
description string
}
func NewHelpHandler() KeyMsgHandler {
return helpHandler{
keys: []string{"?"},
description: "Toggle help menu",
}
}
func (h helpHandler) KeysHandled() []string {
return h.keys
}
func (h helpHandler) Description() string {
return h.description
}
func (h helpHandler) Match(s state.State, msg tea.KeyMsg) bool {
return s.Mode() == state.NavigationMode && slices.Contains(h.keys, msg.String()) ||
s.Mode() == state.HelpMode && slices.Contains(h.keys, msg.String())
}
func (h helpHandler) Handle(s state.State, msg tea.KeyMsg) tea.Cmd {
s.ToggleHelp()
return nil
}
+32
View File
@@ -0,0 +1,32 @@
package handlers
import (
"github.com/StevanFreeborn/term-tier/internal/core"
"github.com/StevanFreeborn/term-tier/internal/state"
tea "github.com/charmbracelet/bubbletea"
)
type KeyMsgHandler interface {
KeysHandled() []string
Description() string
Match(s state.State, msg tea.KeyMsg) bool
Handle(s state.State, msg tea.KeyMsg) tea.Cmd
}
func GetAllKeyHandlers(saver core.Saver) []KeyMsgHandler {
return []KeyMsgHandler{
NewTextInputHandler(),
NewQuitHandler(),
NewUpNavigationHandler(),
NewDownNavigationHandler(),
NewLeftNavigationHandler(),
NewRightNavigationHandler(),
NewDeleteItemHandler(),
NewAddItemHandler(),
NewUpdateItemHandler(),
NewSelectItemHandler(),
NewLoadHandler(saver),
NewSaveHandler(saver),
NewHelpHandler(),
}
}
@@ -0,0 +1,41 @@
package handlers
import (
"slices"
"github.com/StevanFreeborn/term-tier/internal/state"
tea "github.com/charmbracelet/bubbletea"
)
type leftNavigationHandler struct {
keys []string
description string
}
func NewLeftNavigationHandler() KeyMsgHandler {
return leftNavigationHandler{
keys: []string{"left", "h"},
description: "Move left",
}
}
func (h leftNavigationHandler) KeysHandled() []string {
return h.keys
}
func (h leftNavigationHandler) Description() string {
return h.description
}
func (h leftNavigationHandler) Match(s state.State, msg tea.KeyMsg) bool {
if s.Mode() != state.NavigationMode {
return false
}
return slices.Contains(h.keys, msg.String())
}
func (h leftNavigationHandler) Handle(s state.State, msg tea.KeyMsg) tea.Cmd {
s.MoveLeft()
return nil
}
@@ -0,0 +1,101 @@
package handlers_test
import (
"slices"
"testing"
"github.com/StevanFreeborn/term-tier/internal/handlers"
"github.com/StevanFreeborn/term-tier/internal/state"
tea "github.com/charmbracelet/bubbletea"
)
func TestNewLeftNavigationHandler(t *testing.T) {
h := handlers.NewLeftNavigationHandler()
if h.Description() != "Move left" {
t.Errorf("Expected description 'Move left', got %q", h.Description())
}
keys := h.KeysHandled()
if !slices.Contains(keys, "left") || !slices.Contains(keys, "h") {
t.Errorf("Expected keys ['left', 'h'], got %v", keys)
}
}
func TestLeftNavigationHandler_Match(t *testing.T) {
h := handlers.NewLeftNavigationHandler()
tests := []struct {
name string
mode state.Mode
key string
expected bool
}{
{
name: "Matches 'left' in Navigation Mode",
mode: state.NavigationMode,
key: "left",
expected: true,
},
{
name: "Matches 'h' in Navigation Mode",
mode: state.NavigationMode,
key: "h",
expected: true,
},
{
name: "Ignores 'left' in Input Mode",
mode: state.InputMode,
key: "left",
expected: false,
},
{
name: "Ignores 'h' in Input Mode",
mode: state.InputMode,
key: "h",
expected: false,
},
{
name: "Ignores other keys in Navigation Mode",
mode: state.NavigationMode,
key: "right",
expected: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := state.New(state.WithMode(tt.mode))
msg := tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune(tt.key)}
if tt.key == "left" {
msg = tea.KeyMsg{Type: tea.KeyLeft}
}
if got := h.Match(s, msg); got != tt.expected {
t.Errorf("Match() = %v, want %v", got, tt.expected)
}
})
}
}
func TestLeftNavigationHandler_Handle(t *testing.T) {
h := handlers.NewLeftNavigationHandler()
s := state.New(
state.WithCursor(0, 1),
state.WithMode(state.NavigationMode),
)
msg := tea.KeyMsg{Type: tea.KeyLeft}
cmd := h.Handle(s, msg)
if s.CursorCol() != 0 {
t.Errorf("Expected cursor to move to Col 0, got %d", s.CursorCol())
}
if cmd != nil {
t.Error("Expected Handle to return nil, got a command")
}
}
+31
View File
@@ -0,0 +1,31 @@
package handlers_test
import (
"errors"
"github.com/StevanFreeborn/term-tier/internal/core"
)
type mockSaver struct {
shouldError bool
dataToReturn core.SaveState
savedData core.SaveState
}
func (m *mockSaver) Save(filename string, state core.SaveState) error {
if m.shouldError {
return errors.New("mock save error")
}
m.savedData = state
return nil
}
func (m *mockSaver) Load(filename string) (core.SaveState, error) {
if m.shouldError {
return core.SaveState{}, errors.New("mock load error")
}
return m.dataToReturn, nil
}
+40
View File
@@ -0,0 +1,40 @@
package handlers
import (
"slices"
"github.com/StevanFreeborn/term-tier/internal/state"
tea "github.com/charmbracelet/bubbletea"
)
type quitHandler struct {
keys []string
description string
}
func NewQuitHandler() KeyMsgHandler {
return quitHandler{
keys: []string{"ctrl+c", "q"},
description: "Quit",
}
}
func (h quitHandler) KeysHandled() []string {
return h.keys
}
func (h quitHandler) Description() string {
return h.description
}
func (h quitHandler) Match(s state.State, msg tea.KeyMsg) bool {
if s.Mode() != state.NavigationMode {
return false
}
return slices.Contains(h.keys, msg.String())
}
func (h quitHandler) Handle(s state.State, msg tea.KeyMsg) tea.Cmd {
return tea.Quit
}
+99
View File
@@ -0,0 +1,99 @@
package handlers_test
import (
"slices"
"testing"
"github.com/StevanFreeborn/term-tier/internal/handlers"
"github.com/StevanFreeborn/term-tier/internal/state"
tea "github.com/charmbracelet/bubbletea"
)
func TestNewQuitHandler(t *testing.T) {
h := handlers.NewQuitHandler()
if h.Description() != "Quit" {
t.Errorf("Expected description 'Quit', got %q", h.Description())
}
keys := h.KeysHandled()
if !slices.Contains(keys, "q") || !slices.Contains(keys, "ctrl+c") {
t.Errorf("Expected keys ['q', 'ctrl+c'], got %v", keys)
}
}
func TestQuitHandler_Match(t *testing.T) {
h := handlers.NewQuitHandler()
tests := []struct {
name string
mode state.Mode
key string
expected bool
}{
{
name: "Matches 'q' in Navigation Mode",
mode: state.NavigationMode,
key: "q",
expected: true,
},
{
name: "Matches 'ctrl+c' in Navigation Mode",
mode: state.NavigationMode,
key: "ctrl+c",
expected: true,
},
{
name: "Ignores 'q' in Input Mode",
mode: state.InputMode,
key: "q",
expected: false,
},
{
name: "Ignores 'ctrl+c' in Input Mode",
mode: state.InputMode,
key: "ctrl+c",
expected: false,
},
{
name: "Ignores other keys in Navigation Mode",
mode: state.NavigationMode,
key: "x",
expected: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := state.New(state.WithMode(tt.mode))
msg := tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune(tt.key)}
if tt.key == "ctrl+c" {
msg = tea.KeyMsg{Type: tea.KeyCtrlC}
}
if got := h.Match(s, msg); got != tt.expected {
t.Errorf("Match() = %v, want %v", got, tt.expected)
}
})
}
}
func TestQuitHandler_Handle(t *testing.T) {
h := handlers.NewQuitHandler()
s := state.New(state.WithMode(state.NavigationMode))
msg := tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("q")}
cmd := h.Handle(s, msg)
if cmd == nil {
t.Fatal("Expected Handle to return a command, got nil")
}
cmdMsg := cmd()
if _, ok := cmdMsg.(tea.QuitMsg); !ok {
t.Errorf("Expected command to produce tea.QuitMsg, got %T", cmdMsg)
}
}
@@ -0,0 +1,41 @@
package handlers
import (
"slices"
"github.com/StevanFreeborn/term-tier/internal/state"
tea "github.com/charmbracelet/bubbletea"
)
type rightNavigationHandler struct {
keys []string
description string
}
func NewRightNavigationHandler() KeyMsgHandler {
return rightNavigationHandler{
keys: []string{"right", "l"},
description: "Move right",
}
}
func (h rightNavigationHandler) KeysHandled() []string {
return h.keys
}
func (h rightNavigationHandler) Description() string {
return h.description
}
func (h rightNavigationHandler) Match(s state.State, msg tea.KeyMsg) bool {
if s.Mode() != state.NavigationMode {
return false
}
return slices.Contains(h.keys, msg.String())
}
func (h rightNavigationHandler) Handle(s state.State, msg tea.KeyMsg) tea.Cmd {
s.MoveRight()
return nil
}
@@ -0,0 +1,106 @@
package handlers_test
import (
"slices"
"testing"
"github.com/StevanFreeborn/term-tier/internal/core"
"github.com/StevanFreeborn/term-tier/internal/handlers"
"github.com/StevanFreeborn/term-tier/internal/state"
tea "github.com/charmbracelet/bubbletea"
)
func TestNewRightNavigationHandler(t *testing.T) {
h := handlers.NewRightNavigationHandler()
if h.Description() != "Move right" {
t.Errorf("Expected description 'Move right', got %q", h.Description())
}
keys := h.KeysHandled()
if !slices.Contains(keys, "right") || !slices.Contains(keys, "l") {
t.Errorf("Expected keys ['right', 'l'], got %v", keys)
}
}
func TestRightNavigationHandler_Match(t *testing.T) {
h := handlers.NewRightNavigationHandler()
tests := []struct {
name string
mode state.Mode
key string
expected bool
}{
{
name: "Matches 'right' in Navigation Mode",
mode: state.NavigationMode,
key: "right",
expected: true,
},
{
name: "Matches 'l' in Navigation Mode",
mode: state.NavigationMode,
key: "l",
expected: true,
},
{
name: "Ignores 'right' in Input Mode",
mode: state.InputMode,
key: "right",
expected: false,
},
{
name: "Ignores 'l' in Input Mode",
mode: state.InputMode,
key: "l",
expected: false,
},
{
name: "Ignores other keys in Navigation Mode",
mode: state.NavigationMode,
key: "left",
expected: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := state.New(state.WithMode(tt.mode))
msg := tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune(tt.key)}
if tt.key == "right" {
msg = tea.KeyMsg{Type: tea.KeyRight}
}
if got := h.Match(s, msg); got != tt.expected {
t.Errorf("Match() = %v, want %v", got, tt.expected)
}
})
}
}
func TestRightNavigationHandler_Handle(t *testing.T) {
h := handlers.NewRightNavigationHandler()
tiers := make([]core.Tier, 6)
tiers[0] = core.Tier{Name: "S", Items: []core.Item{"A", "B"}}
s := state.New(
state.WithTiers(tiers),
state.WithCursor(0, 0),
state.WithMode(state.NavigationMode),
)
msg := tea.KeyMsg{Type: tea.KeyRight}
cmd := h.Handle(s, msg)
if s.CursorCol() != 1 {
t.Errorf("Expected cursor to move to Col 1, got %d", s.CursorCol())
}
if cmd != nil {
t.Error("Expected Handle to return nil, got a command")
}
}
@@ -0,0 +1,21 @@
package handlers
import (
"github.com/StevanFreeborn/term-tier/internal/state"
tea "github.com/charmbracelet/bubbletea"
)
type trackWindowSizeHandler struct{}
func NewTrackWindowSizeHandler() WinSizeMsgHandler {
return trackWindowSizeHandler{}
}
func (h trackWindowSizeHandler) Match(s state.State, msg tea.WindowSizeMsg) bool {
return true
}
func (h trackWindowSizeHandler) Handle(s state.State, msg tea.WindowSizeMsg) tea.Cmd {
s.SetWindowSize(msg.Width, msg.Height)
return nil
}
@@ -0,0 +1,51 @@
package handlers_test
import (
"testing"
"github.com/StevanFreeborn/term-tier/internal/handlers"
"github.com/StevanFreeborn/term-tier/internal/state"
tea "github.com/charmbracelet/bubbletea"
)
func TestNewTrackWindowSizeHandler(t *testing.T) {
h := handlers.NewTrackWindowSizeHandler()
if h == nil {
t.Error("Expected NewTrackWindowSizeHandler to return a handler, got nil")
}
}
func TestTrackWindowSizeHandler_Match(t *testing.T) {
h := handlers.NewTrackWindowSizeHandler()
s := state.New()
msg := tea.WindowSizeMsg{Width: 100, Height: 100}
if !h.Match(s, msg) {
t.Error("Expected Match to return true for WindowSizeMsg")
}
}
func TestTrackWindowSizeHandler_Handle(t *testing.T) {
h := handlers.NewTrackWindowSizeHandler()
s := state.New()
expectedWidth := 1024
expectedHeight := 768
msg := tea.WindowSizeMsg{Width: expectedWidth, Height: expectedHeight}
cmd := h.Handle(s, msg)
if s.WindowWidth() != expectedWidth {
t.Errorf("Expected WindowWidth to be %d, got %d", expectedWidth, s.WindowWidth())
}
if s.WindowHeight() != expectedHeight {
t.Errorf("Expected WindowHeight to be %d, got %d", expectedHeight, s.WindowHeight())
}
if cmd != nil {
t.Error("Expected Handle to return nil")
}
}
+41
View File
@@ -0,0 +1,41 @@
package handlers
import (
"slices"
"github.com/StevanFreeborn/term-tier/internal/state"
tea "github.com/charmbracelet/bubbletea"
)
type upNavigationHandler struct {
keys []string
description string
}
func NewUpNavigationHandler() KeyMsgHandler {
return upNavigationHandler{
keys: []string{"up", "k"},
description: "Move up",
}
}
func (h upNavigationHandler) KeysHandled() []string {
return h.keys
}
func (h upNavigationHandler) Description() string {
return h.description
}
func (h upNavigationHandler) Match(s state.State, msg tea.KeyMsg) bool {
if s.Mode() != state.NavigationMode {
return false
}
return slices.Contains(h.keys, msg.String())
}
func (h upNavigationHandler) Handle(s state.State, msg tea.KeyMsg) tea.Cmd {
s.MoveUp()
return nil
}
@@ -0,0 +1,100 @@
package handlers_test
import (
"slices"
"testing"
"github.com/StevanFreeborn/term-tier/internal/handlers"
"github.com/StevanFreeborn/term-tier/internal/state"
tea "github.com/charmbracelet/bubbletea"
)
func TestNewUpNavigationHandler(t *testing.T) {
h := handlers.NewUpNavigationHandler()
if h.Description() != "Move up" {
t.Errorf("Expected description 'Move up', got %q", h.Description())
}
keys := h.KeysHandled()
if !slices.Contains(keys, "up") || !slices.Contains(keys, "k") {
t.Errorf("Expected keys ['up', 'k'], got %v", keys)
}
}
func TestUpNavigationHandler_Match(t *testing.T) {
h := handlers.NewUpNavigationHandler()
tests := []struct {
name string
mode state.Mode
key string
expected bool
}{
{
name: "Matches 'up' in Navigation Mode",
mode: state.NavigationMode,
key: "up",
expected: true,
},
{
name: "Matches 'k' in Navigation Mode",
mode: state.NavigationMode,
key: "k",
expected: true,
},
{
name: "Ignores 'up' in Input Mode",
mode: state.InputMode,
key: "up",
expected: false,
},
{
name: "Ignores 'k' in Input Mode",
mode: state.InputMode,
key: "k",
expected: false,
},
{
name: "Ignores other keys in Navigation Mode",
mode: state.NavigationMode,
key: "down",
expected: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := state.New(state.WithMode(tt.mode))
msg := tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune(tt.key)}
if tt.key == "up" {
msg = tea.KeyMsg{Type: tea.KeyUp}
}
if got := h.Match(s, msg); got != tt.expected {
t.Errorf("Match() = %v, want %v", got, tt.expected)
}
})
}
}
func TestUpNavigationHandler_Handle(t *testing.T) {
h := handlers.NewUpNavigationHandler()
s := state.New(
state.WithCursor(1, 0),
state.WithMode(state.NavigationMode),
)
msg := tea.KeyMsg{Type: tea.KeyUp}
cmd := h.Handle(s, msg)
if s.CursorRow() != 0 {
t.Errorf("Expected cursor to move to Row 0, got %d", s.CursorRow())
}
if cmd != nil {
t.Error("Expected Handle to return nil, got a command")
}
}
+17
View File
@@ -0,0 +1,17 @@
package handlers
import (
"github.com/StevanFreeborn/term-tier/internal/state"
tea "github.com/charmbracelet/bubbletea"
)
type WinSizeMsgHandler interface {
Match(s state.State, msg tea.WindowSizeMsg) bool
Handle(s state.State, msg tea.WindowSizeMsg) tea.Cmd
}
func GetAllWinSizeHandlers() []WinSizeMsgHandler {
return []WinSizeMsgHandler{
NewTrackWindowSizeHandler(),
}
}