From 1bf2298536365aa6611b12cf0ce2ede6b9cd7e20 Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Wed, 15 Jul 2020 15:51:51 -0400 Subject: [PATCH] Start Glow in the file loader while file and stash listing load --- ui/stash.go | 93 ++++++++------------------------------ ui/ui.go | 127 +++++++++++++++++++++++++++++++++------------------- 2 files changed, 101 insertions(+), 119 deletions(-) diff --git a/ui/stash.go b/ui/stash.go index a93f00e..35c89c3 100644 --- a/ui/stash.go +++ b/ui/stash.go @@ -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, "…") } diff --git a/ui/ui.go b/ui/ui.go index 34643d5..7d7652c 100644 --- a/ui/ui.go +++ b/ui/ui.go @@ -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