mirror of
https://github.com/Maks1mS/bubbles.git
synced 2025-03-13 20:43:44 +03:00
Viewport now has customizable keybindings
This commit is contained in:
parent
9c70b6a216
commit
4aed4e0a88
42
viewport/keymap.go
Normal file
42
viewport/keymap.go
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
package viewport
|
||||||
|
|
||||||
|
import "github.com/charmbracelet/bubbles/key"
|
||||||
|
|
||||||
|
const spacebar = " "
|
||||||
|
|
||||||
|
// KeyMap defines the keybindings for the viewport. Note that you don't
|
||||||
|
// necessary need to use keybindings at all; the viewport can be controlled
|
||||||
|
// programmatically with methods like Model.LineDown(1). See the GoDocs for
|
||||||
|
// details.
|
||||||
|
type KeyMap struct {
|
||||||
|
PageDown key.Binding
|
||||||
|
PageUp key.Binding
|
||||||
|
HalfPageUp key.Binding
|
||||||
|
HalfPageDown key.Binding
|
||||||
|
Down key.Binding
|
||||||
|
Up key.Binding
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultKeyMap returns a set of pager-like default keybindings.
|
||||||
|
func DefaultKeyMap() KeyMap {
|
||||||
|
return KeyMap{
|
||||||
|
PageDown: key.NewBinding(
|
||||||
|
key.WithKeys("pgdown", spacebar, "f"),
|
||||||
|
),
|
||||||
|
PageUp: key.NewBinding(
|
||||||
|
key.WithKeys("pgup", "b"),
|
||||||
|
),
|
||||||
|
HalfPageUp: key.NewBinding(
|
||||||
|
key.WithKeys("u", "ctrl+u"),
|
||||||
|
),
|
||||||
|
HalfPageDown: key.NewBinding(
|
||||||
|
key.WithKeys("d", "ctrl+d"),
|
||||||
|
),
|
||||||
|
Up: key.NewBinding(
|
||||||
|
key.WithKeys("up", "k"),
|
||||||
|
),
|
||||||
|
Down: key.NewBinding(
|
||||||
|
key.WithKeys("down", "j"),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
@ -4,18 +4,34 @@ import (
|
|||||||
"math"
|
"math"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/charmbracelet/bubbles/key"
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
// NewModel returns a new model with the given width and height as well as
|
||||||
spacebar = " "
|
// default keymappings.
|
||||||
mouseWheelDelta = 3
|
func NewModel(width, height int) Model {
|
||||||
)
|
return Model{
|
||||||
|
Width: width,
|
||||||
|
Height: height,
|
||||||
|
KeyMap: DefaultKeyMap(),
|
||||||
|
MouseWheelEnabled: true,
|
||||||
|
MouseWheelDelta: 3,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Model is the Bubble Tea model for this viewport element.
|
// Model is the Bubble Tea model for this viewport element.
|
||||||
type Model struct {
|
type Model struct {
|
||||||
Width int
|
Width int
|
||||||
Height int
|
Height int
|
||||||
|
KeyMap KeyMap
|
||||||
|
|
||||||
|
// Whether or not to respond to the mouse. The mouse must be enabled in
|
||||||
|
// Bubble Tea for this to work. For details, see the Bubble Tea docs.
|
||||||
|
MouseWheelEnabled bool
|
||||||
|
|
||||||
|
// The number of lines the mouse wheel will scroll. By default, this is 3.
|
||||||
|
MouseWheelDelta int
|
||||||
|
|
||||||
// YOffset is the vertical scroll position.
|
// YOffset is the vertical scroll position.
|
||||||
YOffset int
|
YOffset int
|
||||||
@ -37,6 +53,11 @@ type Model struct {
|
|||||||
lines []string
|
lines []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Init exists to satisfy the tea.Model interface for composability purposes.
|
||||||
|
func (m Model) Init() tea.Cmd {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// AtTop returns whether or not the viewport is in the very top position.
|
// AtTop returns whether or not the viewport is in the very top position.
|
||||||
func (m Model) AtTop() bool {
|
func (m Model) AtTop() bool {
|
||||||
return m.YOffset <= 0
|
return m.YOffset <= 0
|
||||||
@ -227,54 +248,52 @@ func ViewUp(m Model, lines []string) tea.Cmd {
|
|||||||
return tea.ScrollUp(lines, top, bottom)
|
return tea.ScrollUp(lines, top, bottom)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UPDATE
|
// Update handles standard message-based viewport updates.
|
||||||
|
|
||||||
// Update runs the update loop with default keybindings similar to popular
|
|
||||||
// pagers. To define your own keybindings use the methods on Model (i.e.
|
|
||||||
// Model.LineDown()) and define your own update function.
|
|
||||||
func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
||||||
var cmd tea.Cmd
|
var cmd tea.Cmd
|
||||||
|
m, cmd = m.updateAsModel(msg)
|
||||||
|
return m, cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
// Author's note: this method has been broken out to make it easier to
|
||||||
|
// potentially transition Update to satisfy tea.Model.
|
||||||
|
func (m Model) updateAsModel(msg tea.Msg) (Model, tea.Cmd) {
|
||||||
|
var cmd tea.Cmd
|
||||||
|
|
||||||
switch msg := msg.(type) {
|
switch msg := msg.(type) {
|
||||||
case tea.KeyMsg:
|
case tea.KeyMsg:
|
||||||
switch msg.String() {
|
switch {
|
||||||
// Down one page
|
case key.Matches(msg, m.KeyMap.PageDown):
|
||||||
case "pgdown", spacebar, "f":
|
|
||||||
lines := m.ViewDown()
|
lines := m.ViewDown()
|
||||||
if m.HighPerformanceRendering {
|
if m.HighPerformanceRendering {
|
||||||
cmd = ViewDown(m, lines)
|
cmd = ViewDown(m, lines)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Up one page
|
case key.Matches(msg, m.KeyMap.PageUp):
|
||||||
case "pgup", "b":
|
|
||||||
lines := m.ViewUp()
|
lines := m.ViewUp()
|
||||||
if m.HighPerformanceRendering {
|
if m.HighPerformanceRendering {
|
||||||
cmd = ViewUp(m, lines)
|
cmd = ViewUp(m, lines)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Down half page
|
case key.Matches(msg, m.KeyMap.HalfPageDown):
|
||||||
case "d", "ctrl+d":
|
|
||||||
lines := m.HalfViewDown()
|
lines := m.HalfViewDown()
|
||||||
if m.HighPerformanceRendering {
|
if m.HighPerformanceRendering {
|
||||||
cmd = ViewDown(m, lines)
|
cmd = ViewDown(m, lines)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Up half page
|
case key.Matches(msg, m.KeyMap.HalfPageUp):
|
||||||
case "u", "ctrl+u":
|
|
||||||
lines := m.HalfViewUp()
|
lines := m.HalfViewUp()
|
||||||
if m.HighPerformanceRendering {
|
if m.HighPerformanceRendering {
|
||||||
cmd = ViewUp(m, lines)
|
cmd = ViewUp(m, lines)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Down one line
|
case key.Matches(msg, m.KeyMap.Down):
|
||||||
case "down", "j":
|
|
||||||
lines := m.LineDown(1)
|
lines := m.LineDown(1)
|
||||||
if m.HighPerformanceRendering {
|
if m.HighPerformanceRendering {
|
||||||
cmd = ViewDown(m, lines)
|
cmd = ViewDown(m, lines)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Up one line
|
case key.Matches(msg, m.KeyMap.Up):
|
||||||
case "up", "k":
|
|
||||||
lines := m.LineUp(1)
|
lines := m.LineUp(1)
|
||||||
if m.HighPerformanceRendering {
|
if m.HighPerformanceRendering {
|
||||||
cmd = ViewUp(m, lines)
|
cmd = ViewUp(m, lines)
|
||||||
@ -282,15 +301,18 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case tea.MouseMsg:
|
case tea.MouseMsg:
|
||||||
|
if !m.MouseWheelEnabled {
|
||||||
|
break
|
||||||
|
}
|
||||||
switch msg.Type {
|
switch msg.Type {
|
||||||
case tea.MouseWheelUp:
|
case tea.MouseWheelUp:
|
||||||
lines := m.LineUp(mouseWheelDelta)
|
lines := m.LineUp(m.MouseWheelDelta)
|
||||||
if m.HighPerformanceRendering {
|
if m.HighPerformanceRendering {
|
||||||
cmd = ViewUp(m, lines)
|
cmd = ViewUp(m, lines)
|
||||||
}
|
}
|
||||||
|
|
||||||
case tea.MouseWheelDown:
|
case tea.MouseWheelDown:
|
||||||
lines := m.LineDown(mouseWheelDelta)
|
lines := m.LineDown(m.MouseWheelDelta)
|
||||||
if m.HighPerformanceRendering {
|
if m.HighPerformanceRendering {
|
||||||
cmd = ViewDown(m, lines)
|
cmd = ViewDown(m, lines)
|
||||||
}
|
}
|
||||||
@ -300,8 +322,6 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
|||||||
return m, cmd
|
return m, cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
// VIEW
|
|
||||||
|
|
||||||
// View renders the viewport into a string.
|
// View renders the viewport into a string.
|
||||||
func (m Model) View() string {
|
func (m Model) View() string {
|
||||||
if m.HighPerformanceRendering {
|
if m.HighPerformanceRendering {
|
||||||
|
Loading…
Reference in New Issue
Block a user