Properly render one page of the stash

This commit is contained in:
Christian Rocha 2020-05-14 20:23:11 -04:00 committed by Christian Muehlhaeuser
parent c7e584c68e
commit d2e2da70e2
2 changed files with 85 additions and 22 deletions

View file

@ -7,6 +7,7 @@ import (
"strings"
"github.com/charmbracelet/boba"
"github.com/charmbracelet/boba/paginator"
"github.com/charmbracelet/boba/spinner"
"github.com/charmbracelet/charm"
"github.com/charmbracelet/charm/ui/common"
@ -14,6 +15,12 @@ import (
te "github.com/muesli/termenv"
)
const (
itemHeight = 3
topPadding = 3
bottomPadding = 2
)
// MSG
type stashErrMsg error
@ -32,13 +39,33 @@ const (
)
type stashModel struct {
cc *charm.Client
err error
state stashState
documents []*charm.Markdown
page int
spinner spinner.Model
index int
cc *charm.Client
err error
state stashState
documents []*charm.Markdown
spinner spinner.Model
index int
terminalWidth int
terminalHeight int
// This handles the local pagination, which is different than the page
// we're fetching from on the server side
paginator paginator.Model
// Page we're fetching items from on the server, which is different from
// the local pagination. Generally, the server will return more items than
// we can display at a time so we can paginate locally without having to
// fetch every time.
page int
}
func (m *stashModel) SetSize(width, height int) {
m.terminalWidth = width
m.terminalHeight = height
// Update the paginator
perPage := (m.terminalHeight - topPadding - bottomPadding) / itemHeight
m.paginator.PerPage = perPage
}
// INIT
@ -47,12 +74,13 @@ func stashInit(cc *charm.Client) (stashModel, boba.Cmd) {
s := spinner.NewModel()
s.Type = spinner.Dot
s.ForegroundColor = common.SpinnerColor
s.CustomMsgFunc = newSpinnerTickMsg
s.CustomMsgFunc = func() boba.Msg { return stashSpinnerTickMsg{} }
m := stashModel{
cc: cc,
spinner: s,
page: 1,
cc: cc,
spinner: s,
page: 1,
paginator: paginator.NewModel(),
}
return m, boba.Batch(
@ -60,9 +88,6 @@ func stashInit(cc *charm.Client) (stashModel, boba.Cmd) {
spinner.Tick(s),
)
}
func newSpinnerTickMsg() boba.Msg {
return stashSpinnerTickMsg{}
}
// UPDATE
@ -70,6 +95,11 @@ func stashUpdate(msg boba.Msg, m stashModel) (stashModel, boba.Cmd) {
switch msg := msg.(type) {
case boba.KeyMsg:
// Don't respond to keystrokes if we're still loading
if m.state == stashStateInit {
return m, nil
}
switch msg.String() {
case "k":
@ -99,8 +129,9 @@ func stashUpdate(msg boba.Msg, m stashModel) (stashModel, boba.Cmd) {
case gotStashMsg:
sort.Sort(charm.MarkdownsByCreatedAt(msg)) // sort by date
m.documents = msg
m.documents = append(m.documents, msg...)
m.state = stashStateLoaded
m.paginator.SetTotalPages(len(m.documents))
return m, nil
case stashSpinnerTickMsg:
@ -128,7 +159,16 @@ func stashView(m stashModel) string {
s += stashEmtpyView(m)
break
}
s += stashPopulatedView(m)
// Blank lines we'll need to fill with newlines fo the viewport is
// properly filled
numBlankLines := (m.terminalHeight - topPadding - bottomPadding) % itemHeight
blankLines := ""
if numBlankLines > 0 {
blankLines = strings.Repeat("\n", numBlankLines)
}
s += stashPopulatedView(m) + blankLines + helpView(m)
}
return "\n" + indent.String(s, 2)
}
@ -138,16 +178,30 @@ func stashEmtpyView(m stashModel) string {
}
func stashPopulatedView(m stashModel) string {
start, end := m.paginator.GetSliceBounds(len(m.documents))
docs := m.documents[start:end]
s := "Here's your markdown stash:\n\n"
for i, v := range m.documents {
for i, v := range docs {
state := common.StateNormal
if i == m.index {
state = common.StateSelected
}
s += stashListItemView(*v).render(state) + "\n\n"
}
s = strings.TrimSpace(s)
return s
return strings.TrimSpace(s)
}
func helpView(m stashModel) string {
h := []string{"enter: open"}
if len(m.documents) > 0 {
h = append(h, "j/k, ↑/↓: choose")
}
if m.paginator.TotalPages > 1 {
h = append(h, "h/l, ←/→: page")
}
h = append(h, []string{"x: delete", "esc: exit"}...)
return common.HelpView(h...)
}
type stashListItemView charm.Markdown

View file

@ -98,9 +98,7 @@ func initialize() (boba.Model, boba.Cmd) {
}, boba.Batch(
newCharmClient,
spinner.Tick(s),
boba.GetTerminalSize(func(w, h int, err error) boba.TerminalSizeMsg {
return terminalSizeMsg{width: w, height: h, err: err}
}),
getTerminalSize(),
)
}
@ -130,6 +128,10 @@ func update(msg boba.Msg, mdl boba.Model) (boba.Model, boba.Cmd) {
case "ctrl+c":
return m, boba.Quit
// Re-render
case "ctrl+l":
return m, getTerminalSize()
}
case fatalErrMsg:
@ -148,6 +150,7 @@ func update(msg boba.Msg, mdl boba.Model) (boba.Model, boba.Cmd) {
w, h := msg.Size()
m.terminalWidth = w
m.terminalHeight = h
m.stash.SetSize(w, h)
return m, nil
case sshAuthErrMsg:
@ -183,6 +186,7 @@ func update(msg boba.Msg, mdl boba.Model) (boba.Model, boba.Cmd) {
m.cc = msg
m.state = stateShowStash
m.stash, cmd = stashInit(m.cc)
m.stash.SetSize(m.terminalWidth, m.terminalHeight)
return m, cmd
case gotStashedItemMsg:
@ -293,6 +297,11 @@ func statusBarView(m model) string {
}
// COMMANDS
func getTerminalSize() boba.Cmd {
return boba.GetTerminalSize(func(w, h int, err error) boba.TerminalSizeMsg {
return terminalSizeMsg{width: w, height: h, err: err}
})
}
func newCharmClient() boba.Msg {
cfg, err := charm.ConfigFromEnv()