diff --git a/internal/ui/confirmation/confirmation.go b/internal/ui/confirmation/confirmation.go index 953b201..9e935f0 100644 --- a/internal/ui/confirmation/confirmation.go +++ b/internal/ui/confirmation/confirmation.go @@ -1,6 +1,7 @@ package confirmation import ( + "github.com/charmbracelet/bubbles/key" "strings" "github.com/charmbracelet/lipgloss" @@ -10,11 +11,19 @@ import ( tea "github.com/charmbracelet/bubbletea" ) +var ( + right = key.NewBinding(key.WithKeys("right", "l")) + left = key.NewBinding(key.WithKeys("left", "h")) + enter = key.NewBinding(key.WithKeys("enter")) + cancel = key.NewBinding(key.WithKeys("esc")) +) + type CloseMsg struct{} type option struct { - label string - cmd tea.Cmd + label string + cmd tea.Cmd + keyBinding key.Binding } type Model struct { @@ -44,21 +53,24 @@ func (m *Model) Init() tea.Cmd { func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { switch msg := msg.(type) { case tea.KeyMsg: - switch msg.Type { - case tea.KeyLeft: + switch { + case key.Matches(msg, left): if m.selected > 0 { m.selected-- } - case tea.KeyRight: + case key.Matches(msg, right): if m.selected < len(m.options) { m.selected++ } - case tea.KeyEnter: + case key.Matches(msg, enter): selectedOption := m.options[m.selected] return m, selectedOption.cmd - case tea.KeyEscape: - return m, Close default: + for _, option := range m.options { + if key.Matches(msg, option.keyBinding) { + return m, option.cmd + } + } } } return m, nil @@ -78,8 +90,8 @@ func (m *Model) View() string { return lipgloss.NewStyle().Border(lipgloss.RoundedBorder()).Padding(0, 1, 0, 1).Render(w.String()) } -func (m *Model) AddOption(label string, cmd tea.Cmd) { - m.options = append(m.options, option{label, cmd}) +func (m *Model) AddOption(label string, cmd tea.Cmd, keyBinding key.Binding) { + m.options = append(m.options, option{label, cmd, keyBinding}) } func New(message string) Model { diff --git a/internal/ui/operations/abandon/abandon.go b/internal/ui/operations/abandon/abandon.go index cdda3be..08041d1 100644 --- a/internal/ui/operations/abandon/abandon.go +++ b/internal/ui/operations/abandon/abandon.go @@ -1,6 +1,7 @@ package abandon import ( + "github.com/charmbracelet/bubbles/key" "github.com/idursun/jjui/internal/ui/common" "github.com/idursun/jjui/internal/ui/confirmation" @@ -28,8 +29,8 @@ func (m Model) View() string { func New(commands common.UICommands, revision string) tea.Model { model := confirmation.New("Are you sure you want to abandon this revision?") - model.AddOption("Yes", tea.Batch(commands.Abandon(revision), common.Close)) - model.AddOption("No", common.Close) + model.AddOption("Yes", tea.Batch(commands.Abandon(revision), common.Close), key.NewBinding(key.WithKeys("y"))) + model.AddOption("No", common.Close, key.NewBinding(key.WithKeys("n", "esc"))) return Model{ confirmation: &model, diff --git a/internal/ui/operations/details/details.go b/internal/ui/operations/details/details.go index 6aa3fcc..e2c3180 100644 --- a/internal/ui/operations/details/details.go +++ b/internal/ui/operations/details/details.go @@ -159,8 +159,8 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { unselectedHint: "moves to the new revision", }) model := confirmation.New("Are you sure you want to split the selected files?") - model.AddOption("Yes", tea.Batch(m.UICommands.Split(m.revision, selectedFiles), common.Close)) - model.AddOption("No", confirmation.Close) + model.AddOption("Yes", tea.Batch(m.UICommands.Split(m.revision, selectedFiles), common.Close), key.NewBinding(key.WithKeys("y"))) + model.AddOption("No", confirmation.Close, key.NewBinding(key.WithKeys("n", "esc"))) m.confirmation = &model return m, m.confirmation.Init() case key.Matches(msg, restore): @@ -171,8 +171,8 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { unselectedHint: "stays as is", }) model := confirmation.New("Are you sure you want to restore the selected files?") - model.AddOption("Yes", tea.Batch(m.UICommands.Restore(m.revision, selectedFiles), common.Close)) - model.AddOption("No", confirmation.Close) + model.AddOption("Yes", tea.Batch(m.UICommands.Restore(m.revision, selectedFiles), common.Close), key.NewBinding(key.WithKeys("y"))) + model.AddOption("No", confirmation.Close, key.NewBinding(key.WithKeys("n", "esc"))) m.confirmation = &model return m, m.confirmation.Init() case key.Matches(msg, mark): diff --git a/internal/ui/operations/undo/undo_operation.go b/internal/ui/operations/undo/undo_operation.go index b1c8388..d8a68ab 100644 --- a/internal/ui/operations/undo/undo_operation.go +++ b/internal/ui/operations/undo/undo_operation.go @@ -1,6 +1,7 @@ package undo import ( + "github.com/charmbracelet/bubbles/key" tea "github.com/charmbracelet/bubbletea" "github.com/idursun/jjui/internal/ui/common" "github.com/idursun/jjui/internal/ui/confirmation" @@ -27,7 +28,7 @@ func (o Operation) Render() string { func NewOperation(commands common.UICommands) (operations.Operation, tea.Cmd) { model := confirmation.New("Are you sure you want to undo last change?") - model.AddOption("Yes", tea.Batch(commands.Undo(), common.Close)) - model.AddOption("No", common.Close) + model.AddOption("Yes", tea.Batch(commands.Undo(), common.Close), key.NewBinding(key.WithKeys("y"))) + model.AddOption("No", common.Close, key.NewBinding(key.WithKeys("n", "esc"))) return Operation{Overlay: &model}, model.Init() }