mirror of
https://github.com/maaslalani/slides.git
synced 2026-01-08 22:07:59 -05:00
132 lines
2.6 KiB
Go
132 lines
2.6 KiB
Go
package navigation
|
|
|
|
import (
|
|
"strconv"
|
|
)
|
|
|
|
type repeatableFunc func(slide, totalSlides int) int
|
|
|
|
// State tracks the current buffer, page, and total number of slides
|
|
type State struct {
|
|
Buffer string
|
|
Page int
|
|
TotalSlides int
|
|
}
|
|
|
|
// Navigate receives the current State and keyPress, and returns the new State.
|
|
func Navigate(state State, keyPress string) State {
|
|
switch keyPress {
|
|
case "0", "1", "2", "3", "4", "5", "6", "7", "8", "9":
|
|
newBuffer := keyPress
|
|
|
|
if bufferIsNumeric(state.Buffer) {
|
|
newBuffer = state.Buffer + keyPress
|
|
}
|
|
|
|
return State{
|
|
Buffer: newBuffer,
|
|
Page: state.Page,
|
|
TotalSlides: state.TotalSlides,
|
|
}
|
|
case "g":
|
|
switch state.Buffer {
|
|
case "g":
|
|
return State{
|
|
Page: 0,
|
|
TotalSlides: state.TotalSlides,
|
|
}
|
|
default:
|
|
return State{
|
|
Buffer: "g",
|
|
Page: state.Page,
|
|
TotalSlides: state.TotalSlides,
|
|
}
|
|
}
|
|
case "G":
|
|
targetSlide := state.TotalSlides - 1
|
|
if bufferIsNumeric(state.Buffer) {
|
|
targetSlide = navigateSlide(state.Buffer, state.TotalSlides)
|
|
}
|
|
|
|
return State{
|
|
Page: targetSlide,
|
|
TotalSlides: state.TotalSlides,
|
|
}
|
|
case " ", "down", "j", "right", "l", "enter", "n", "pgdown":
|
|
return State{
|
|
Page: navigateNext(state),
|
|
TotalSlides: state.TotalSlides,
|
|
}
|
|
case "up", "k", "left", "h", "p", "pgup":
|
|
return State{
|
|
Page: navigatePrevious(state),
|
|
TotalSlides: state.TotalSlides,
|
|
}
|
|
default:
|
|
return State{
|
|
Page: state.Page,
|
|
TotalSlides: state.TotalSlides,
|
|
}
|
|
}
|
|
}
|
|
|
|
func bufferIsNumeric(buffer string) bool {
|
|
_, err := strconv.Atoi(buffer)
|
|
return err == nil
|
|
}
|
|
|
|
func navigateNext(state State) int {
|
|
return repeatableAction(func(slide, totalSlides int) int {
|
|
if slide < totalSlides-1 {
|
|
return slide + 1
|
|
}
|
|
|
|
return totalSlides - 1
|
|
}, state)
|
|
}
|
|
|
|
func navigateSlide(buffer string, totalSlides int) int {
|
|
destinationSlide, _ := strconv.Atoi(buffer)
|
|
destinationSlide--
|
|
|
|
if destinationSlide > totalSlides-1 {
|
|
return totalSlides - 1
|
|
}
|
|
|
|
if destinationSlide < 0 {
|
|
return 0
|
|
}
|
|
|
|
return destinationSlide
|
|
}
|
|
|
|
func navigatePrevious(state State) int {
|
|
return repeatableAction(func(slide, totalSlides int) int {
|
|
if slide > 0 {
|
|
return slide - 1
|
|
}
|
|
|
|
return slide
|
|
}, state)
|
|
}
|
|
|
|
func repeatableAction(fn repeatableFunc, state State) int {
|
|
if !bufferIsNumeric(state.Buffer) {
|
|
return fn(state.Page, state.TotalSlides)
|
|
}
|
|
|
|
repeat, _ := strconv.Atoi(state.Buffer)
|
|
page := state.Page
|
|
|
|
if repeat == 0 {
|
|
// This is how behaviour works in Vim, so following principle of least astonishment.
|
|
return fn(state.Page, state.TotalSlides)
|
|
}
|
|
|
|
for i := 0; i < repeat; i++ {
|
|
page = fn(page, state.TotalSlides)
|
|
}
|
|
|
|
return page
|
|
}
|