mirror of
https://github.com/charmbracelet/glow
synced 2024-11-10 14:14:17 +00:00
Start Glow in the file loader while file and stash listing load
This commit is contained in:
parent
d4f192487c
commit
1bf2298536
2 changed files with 101 additions and 119 deletions
93
ui/stash.go
93
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, "…")
|
||||
}
|
||||
|
|
127
ui/ui.go
127
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
|
||||
|
|
Loading…
Reference in a new issue