Start Glow in the file loader while file and stash listing load

This commit is contained in:
Christian Rocha 2020-07-15 15:51:51 -04:00 committed by Christian Muehlhaeuser
parent d4f192487c
commit 1bf2298536
2 changed files with 101 additions and 119 deletions

View file

@ -5,7 +5,6 @@ import (
"fmt"
"io/ioutil"
"math"
"os"
"sort"
"strings"
"time"
@ -31,8 +30,6 @@ const (
// MSG
type gotStashMsg []*charm.Markdown
type gotNewsMsg []*charm.Markdown
type fetchedMarkdownMsg *markdown
type deletedStashedItemMsg int
@ -80,25 +77,12 @@ func (m markdownsByLocalFirst) Less(i, j int) bool {
type stashState int
const (
stashStateInit stashState = iota
stashStateReady
stashStateReady stashState = iota
stashStatePromptDelete
stashStateLoadingDocument
stashStateSettingNote
)
type stashLoadedState byte
func (s stashLoadedState) done() bool {
return s&loadedStash != 0 && s&loadedNews != 0
}
const (
loadedStash stashLoadedState = 1 << iota
loadedNews
loadedLocalFiles
)
type stashModel struct {
cc *charm.Client
state stashState
@ -107,12 +91,11 @@ type stashModel struct {
noteInput textinput.Model
terminalWidth int
terminalHeight int
loaded stashLoadedState // what's loaded? we find out with bitmasking
loading bool // are we currently loading something?
fullyLoaded bool // Have we loaded everything from the server?
hasStash bool // do we have stashed files to show?
hasLocalFiles bool // do we have local files to show?
hasNews bool // do we have news to show?
loading bool // are we currently loading something?
fullyLoaded bool // Have we loaded everything from the server?
hasStash bool // do we have stashed files to show?
hasLocalFiles bool // do we have local files to show?
hasNews bool // do we have news to show?
// This is just the index of the current page in view. To get the index
// of the selected item as it relates to the full set of documents we've
@ -154,10 +137,11 @@ func (m stashModel) markdownIndex() int {
// return the current selected markdown in the stash
func (m stashModel) selectedMarkdown() *markdown {
if len(m.markdowns) == 0 || len(m.markdowns) <= m.markdownIndex() {
i := m.markdownIndex()
if i < 0 || len(m.markdowns) == 0 || len(m.markdowns) <= i {
return nil
}
return m.markdowns[m.markdownIndex()]
return m.markdowns[i]
}
// addDocuments adds markdown documents to the model
@ -189,6 +173,7 @@ func newStashModel() stashModel {
noteInput: ni,
page: 1,
paginator: p,
loading: true,
}
return m
@ -204,10 +189,6 @@ func stashUpdate(msg tea.Msg, m stashModel) (stashModel, tea.Cmd) {
switch msg := msg.(type) {
// We're finished searching for local files
case localFileSearchFinished:
m.loaded |= loadedLocalFiles
// Stash results have come in from the server
case gotStashMsg:
m.loading = false
@ -221,11 +202,6 @@ func stashUpdate(msg tea.Msg, m stashModel) (stashModel, tea.Cmd) {
m.hasStash = true
}
m.loaded |= loadedStash
if m.loaded.done() {
m.state = stashStateReady
}
// News has come in from the server
case gotNewsMsg:
if len(msg) > 0 {
@ -234,18 +210,13 @@ func stashUpdate(msg tea.Msg, m stashModel) (stashModel, tea.Cmd) {
m.hasNews = true
}
m.loaded |= loadedNews
if m.loaded.done() {
m.state = stashStateReady
}
case spinner.TickMsg:
if m.state == stashStateInit || m.state == stashStateLoadingDocument {
if m.state == stashStateLoadingDocument {
m.spinner, cmd = spinner.Update(msg, m.spinner)
cmds = append(cmds, cmd)
}
// A note was set on a document. This may have happened in the pager, so
// A note was set on a document. This may have happened in the pager so
// we'll find the corresponding document here and update accordingly.
case noteSavedMsg:
for i := range m.markdowns {
@ -420,15 +391,9 @@ func stashUpdate(msg tea.Msg, m stashModel) (stashModel, tea.Cmd) {
func stashView(m stashModel) string {
var s string
switch m.state {
case stashStateInit:
s += " " + spinner.View(m.spinner) + " Loading stash..."
case stashStateLoadingDocument:
s += " " + spinner.View(m.spinner) + " Loading document..."
case stashStateReady:
fallthrough
case stashStateSettingNote:
fallthrough
case stashStatePromptDelete:
case stashStateReady, stashStateSettingNote, stashStatePromptDelete:
// We need to fill any empty height with newlines so the footer reaches
// the bottom.
@ -529,10 +494,14 @@ func stashPopulatedView(m stashModel) string {
func stashHelpView(m stashModel) string {
var (
h []string
md = m.selectedMarkdown()
isStashed = md != nil && md.markdownType == stashedMarkdown
isStashed bool
)
if len(m.markdowns) > 0 {
md := m.selectedMarkdown()
isStashed = md != nil && md.markdownType == stashedMarkdown
}
if m.state == stashStateSettingNote {
h = append(h, "enter: confirm", "esc: cancel")
} else if m.state == stashStatePromptDelete {
@ -621,30 +590,6 @@ func wrapMarkdowns(t markdownType, md []*charm.Markdown) (m []*markdown) {
return m
}
// Convert path to local file to Markdown. Note that we could be doing things
// like checking if the file is a directory, but we trust that gitcha has
// already done that.
func localFileToMarkdown(cwd, path string) (*markdown, error) {
md := &markdown{
markdownType: localFile,
localPath: path,
Markdown: &charm.Markdown{},
}
// Strip absolute path
md.Markdown.Note = strings.Replace(path, cwd+"/", "", -1)
// Get last modified time
info, err := os.Stat(path)
if err != nil {
return nil, err
}
t := info.ModTime()
md.CreatedAt = &t
return md, nil
}
func truncate(str string, num int) string {
return runewidth.Truncate(str, num, "…")
}

127
ui/ui.go
View file

@ -7,7 +7,6 @@ import (
"os"
"strings"
"github.com/charmbracelet/bubbles/spinner"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/charm"
"github.com/charmbracelet/charm/ui/common"
@ -55,19 +54,40 @@ type initLocalFileSearchMsg struct {
}
type foundLocalFileMsg string
type localFileSearchFinished struct{}
type gotStashMsg []*charm.Markdown
type gotNewsMsg []*charm.Markdown
// MODEL
type loadedState byte
const (
loadedStash loadedState = 1 << iota
loadedNews
loadedLocalFiles
)
func (s loadedState) done() bool {
return s&loadedStash != 0 &&
s&loadedNews != 0 &&
s&loadedLocalFiles != 0
}
type state int
const (
stateInitCharmClient state = iota
stateKeygenRunning
stateKeygenFinished
stateShowStash
stateShowStash state = iota
stateShowDocument
)
type keygenState int
const (
keygenUnstarted keygenState = iota
keygenRunning
keygenFinished
)
// String translates the staus to a human-readable string. This is just for
// debugging.
func (s state) String() string {
@ -83,15 +103,16 @@ func (s state) String() string {
type model struct {
cc *charm.Client
user *charm.User
spinner spinner.Model
keygen keygen.Model
keygenState keygenState
state state
err error
stash stashModel
pager pagerModel
terminalWidth int
terminalHeight int
cwd string // directory from which we're running Glow
cwd string // directory from which we're running Glow
loaded loadedState // what's loaded? we find out with bitmasking
// Channel that receives paths to local markdown files
// (via the github.com/muesli/gitcha package)
@ -109,10 +130,6 @@ func (m *model) unloadDocument() {
func initialize(style string) func() (tea.Model, tea.Cmd) {
return func() (tea.Model, tea.Cmd) {
s := spinner.NewModel()
s.Frames = spinner.Dot
s.ForegroundColor = common.SpinnerColor
if style == "auto" {
dbg := te.HasDarkBackground()
if dbg == true {
@ -123,14 +140,13 @@ func initialize(style string) func() (tea.Model, tea.Cmd) {
}
return model{
spinner: s,
stash: newStashModel(),
pager: newPagerModel(style),
state: stateInitCharmClient,
stash: newStashModel(),
pager: newPagerModel(style),
state: stateShowStash,
keygenState: keygenUnstarted,
}, tea.Batch(
findLocalFiles,
newCharmClient,
spinner.Tick(s),
)
}
}
@ -234,10 +250,14 @@ func update(msg tea.Msg, mdl tea.Model) (tea.Model, tea.Cmd) {
}
cmds = append(cmds, findNextLocalFile(m))
// We're finished searching for local files
case localFileSearchFinished:
m.loaded |= loadedLocalFiles
case sshAuthErrMsg:
// If we haven't run the keygen yet, do that
if m.state != stateKeygenFinished {
m.state = stateKeygenRunning
if m.keygenState != keygenFinished {
m.keygenState = keygenRunning
m.keygen = keygen.NewModel()
cmds = append(cmds, keygen.GenerateKeys)
} else {
@ -246,25 +266,11 @@ func update(msg tea.Msg, mdl tea.Model) (tea.Model, tea.Cmd) {
return m, tea.Quit
}
case spinner.TickMsg:
switch m.state {
case stateInitCharmClient:
m.spinner, cmd = spinner.Update(msg, m.spinner)
}
cmds = append(cmds, cmd)
case keygen.DoneMsg:
// The keygen's done, so let's try initializing the charm client again
m.state = stateKeygenFinished
m.keygenState = keygenFinished
cmds = append(cmds, newCharmClient)
case noteSavedMsg:
// A note was saved to a document. This will have be done in the
// pager, so we'll need to find the corresponding note in the stash.
// So, pass the message to the stash for processing.
m.stash, cmd = stashUpdate(msg, m.stash)
cmds = append(cmds, cmd)
case newCharmClientMsg:
m.cc = msg
m.state = stateShowStash
@ -272,6 +278,19 @@ func update(msg tea.Msg, mdl tea.Model) (tea.Model, tea.Cmd) {
m.pager.cc = msg
cmds = append(cmds, loadStash(m.stash), loadNews(m.stash))
case gotStashMsg:
m.loaded |= loadedStash
case gotNewsMsg:
m.loaded |= loadedNews
case noteSavedMsg:
// A note was saved to a document. This will have be done in the
// pager, so we'll need to find the corresponding note in the stash.
// So, pass the message to the stash for processing.
m.stash, cmd = stashUpdate(msg, m.stash)
cmds = append(cmds, cmd)
case fetchedMarkdownMsg:
m.pager.currentDocument = msg
cmds = append(cmds, renderWithGlamour(m.pager, msg.Body))
@ -281,10 +300,8 @@ func update(msg tea.Msg, mdl tea.Model) (tea.Model, tea.Cmd) {
}
switch m.state {
case stateKeygenRunning:
// Process keygen
// Process keygen
if m.keygenState == keygenRunning {
mdl, cmd := keygen.Update(msg, tea.Model(m.keygen))
keygenModel, ok := mdl.(keygen.Model)
if !ok {
@ -293,14 +310,16 @@ func update(msg tea.Msg, mdl tea.Model) (tea.Model, tea.Cmd) {
}
m.keygen = keygenModel
cmds = append(cmds, cmd)
}
// Process children
switch m.state {
case stateShowStash:
// Process stash
m.stash, cmd = stashUpdate(msg, m.stash)
cmds = append(cmds, cmd)
case stateShowDocument:
// Process pager
m.pager, cmd = pagerUpdate(msg, m.pager)
cmds = append(cmds, cmd)
}
@ -324,12 +343,6 @@ func view(mdl tea.Model) string {
var s string
switch m.state {
case stateInitCharmClient:
s += spinner.View(m.spinner) + " Initializing..."
case stateKeygenRunning:
s += keygen.View(m.keygen)
case stateKeygenFinished:
s += spinner.View(m.spinner) + " Re-initializing..."
case stateShowStash:
return stashView(m.stash)
case stateShowDocument:
@ -415,6 +428,30 @@ func loadNews(m stashModel) tea.Cmd {
// ETC
// Convert local file path to Markdown. Note that we could be doing things
// like checking if the file is a directory, but we trust that gitcha has
// already done that.
func localFileToMarkdown(cwd, path string) (*markdown, error) {
md := &markdown{
markdownType: localFile,
localPath: path,
Markdown: &charm.Markdown{},
}
// Strip absolute path
md.Markdown.Note = strings.Replace(path, cwd+"/", "", -1)
// Get last modified time
info, err := os.Stat(path)
if err != nil {
return nil, err
}
t := info.ModTime()
md.CreatedAt = &t
return md, nil
}
func indent(s string, n int) string {
if n <= 0 || s == "" {
return s