diff --git a/go.mod b/go.mod index 6212daf..3a84d48 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.13 require ( github.com/alecthomas/chroma v0.8.0 // indirect - github.com/charmbracelet/bubbles v0.5.2-0.20200820173131-d4a0ecd3ee70 + github.com/charmbracelet/bubbles v0.5.2-0.20200825000354-e8526ec4ef07 github.com/charmbracelet/bubbletea v0.10.3 github.com/charmbracelet/charm v0.7.1-0.20200821194648-662b3ca6fc7e github.com/charmbracelet/glamour v0.2.1-0.20200820173154-593dda41c59f diff --git a/go.sum b/go.sum index 395a3b6..ecfafe3 100644 --- a/go.sum +++ b/go.sum @@ -21,8 +21,8 @@ github.com/calmh/randomart v1.1.0 h1:evl+iwc10LXtHdMZhzLxmsCQVmWnkXs44SbC6Uk0Il8 github.com/calmh/randomart v1.1.0/go.mod h1:DQUbPVyP+7PAs21w/AnfMKG5NioxS3TbZ2F9MSK/jFM= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/charmbracelet/bubbles v0.5.1/go.mod h1:xmZpdK4/Sn3bGgBKK40YPmM9Hf4taFGgKkLqSdAb0FA= -github.com/charmbracelet/bubbles v0.5.2-0.20200820173131-d4a0ecd3ee70 h1:AqQiGoDkSIpg+aXxA6h/D7YJjB9n6a7C4vomj2Fvd1s= -github.com/charmbracelet/bubbles v0.5.2-0.20200820173131-d4a0ecd3ee70/go.mod h1:a5j/GSk+sC2NBXqNXHeaYBDqutH+vd5eFX7Hl5tSmFo= +github.com/charmbracelet/bubbles v0.5.2-0.20200825000354-e8526ec4ef07 h1:UDzKMYtj4Yy8/YDGCpTiZzbI0Ai0O9SGZM3R5oer4Dk= +github.com/charmbracelet/bubbles v0.5.2-0.20200825000354-e8526ec4ef07/go.mod h1:MxySU+YRGbAhZQJavZlW2os+fIeOW69MI3iXqA+2/WA= github.com/charmbracelet/bubbletea v0.9.1-0.20200713153904-2f53eeb54b90/go.mod h1:wjGGC5pyYvpuls0so+w4Zv+aZQW7RoPvsi9UBcDlSl8= github.com/charmbracelet/bubbletea v0.10.3 h1:arYCVde6OHbejtz08VOtAjsw4LlMR9pQhJCkqk3bwr8= github.com/charmbracelet/bubbletea v0.10.3/go.mod h1:fB1bVmlaXBYYv4G0jtuGSP/m8V2sMM97pq7QqQnubWI= @@ -65,7 +65,6 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/goterm v0.0.0-20190703233501-fc88cf888a3f h1:5CjVwnuUcp5adK4gmY6i72gpVFVnZDP2h5TmPScB6u4= github.com/google/goterm v0.0.0-20190703233501-fc88cf888a3f/go.mod h1:nOFQdrUlIlx6M6ODdSpBj1NVA+VgLC6kmw60mkw34H4= github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -117,7 +116,6 @@ github.com/muesli/reflow v0.1.1-0.20200715144030-a312cb5b2d8d/go.mod h1:I9bWAt7Q github.com/muesli/sasquatch v0.0.0-20200811221207-66979d92330a h1:Hw/15RYEOUD6T9UCRkUmNBa33kJkH33Fui6hE4sRLKU= github.com/muesli/sasquatch v0.0.0-20200811221207-66979d92330a/go.mod h1:+XG0ne5zXWBTSbbe7Z3/RWxaT8PZY6zaZ1dX6KjprYY= github.com/muesli/termenv v0.5.3-0.20200625163851-04b5c30e4c04/go.mod h1:O1/I6sw+6KcrgAmcs6uiUVr7Lui+DNVbHTzt9Lm/PlI= -github.com/muesli/termenv v0.7.0 h1:KcLfgg/KICGxOxNr+P9gmkrJ5azxOm3WzkfXMePGTq4= github.com/muesli/termenv v0.7.0/go.mod h1:SohX91w6swWA4AYU+QmPx+aSgXhWO0juiyID9UZmbpA= github.com/muesli/termenv v0.7.2 h1:r1raklL3uKE7rOvWgSenmEm2px+dnc33OTisZ8YR1fw= github.com/muesli/termenv v0.7.2/go.mod h1:ct2L5N2lmix82RaY3bMWwVu/jUFc9Ule0KGDCiKYPh8= @@ -180,7 +178,6 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de h1:ikNHVSjEfnvz6sxdSPCaPt572qowuyMDMJLLm3Db3ig= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -210,7 +207,6 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200819171115-d785dc25833f h1:KJuwZVtZBVzDmEDtB2zro9CXkD9O0dpCv4o2LHbQIAw= golang.org/x/sys v0.0.0-20200819171115-d785dc25833f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200821140526-fda516888d29 h1:mNuhGagCf3lDDm5C0376C/sxh6V7fy9WbdEu/YDNA04= golang.org/x/sys v0.0.0-20200821140526-fda516888d29/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/ui/pager.go b/ui/pager.go index 6eb2099..7d7f9bf 100644 --- a/ui/pager.go +++ b/ui/pager.go @@ -85,6 +85,7 @@ const ( pagerStateBrowse pagerState = iota pagerStateSetNote pagerStateStashing + pagerStateStashSuccess pagerStateStatusMessage ) @@ -95,8 +96,8 @@ type pagerModel struct { glamourStyle string width int height int - textInput textinput.Model showHelp bool + textInput textinput.Model spinner spinner.Model statusMessageHeader string @@ -106,6 +107,10 @@ type pagerModel struct { // Current document being rendered, sans-glamour rendering. We cache // it here so we can re-render it on resize. currentDocument markdown + + // Newly stashed markdown. We store it here temporarily so we can replace + // currentDocument above after a stash. + stashedDocument *markdown } func newPagerModel(glamourStyle string) pagerModel { @@ -130,6 +135,7 @@ func newPagerModel(glamourStyle string) pagerModel { sp := spinner.NewModel() sp.ForegroundColor = statusBarNoteFg.String() sp.BackgroundColor = statusBarBg.String() + sp.MinimumLifetime = time.Millisecond * 180 return pagerModel{ state: pagerStateBrowse, @@ -164,6 +170,23 @@ func (m *pagerModel) toggleHelp() { } } +// Perform stuff that needs to happen after a successful markdown stash. Note +// that the the returned command should be sent back the through the pager +// update function. +func (m *pagerModel) showStatusMessage(statusMessage string) tea.Cmd { + + // Show a success message to the user + m.state = pagerStateStatusMessage + m.statusMessageHeader = statusMessage + m.statusMessageBody = "" + if m.statusMessageTimer != nil { + m.statusMessageTimer.Stop() + } + m.statusMessageTimer = time.NewTimer(statusMessageTimeout) + + return waitForStatusMessageTimeout(pagerContext, m.statusMessageTimer) +} + func (m *pagerModel) unload() { if m.showHelp { m.toggleHelp() @@ -239,6 +262,7 @@ func pagerUpdate(msg tea.Msg, m pagerModel) (pagerModel, tea.Cmd) { // Stash a local document if m.state != pagerStateStashing && m.currentDocument.markdownType == localMarkdown { m.state = pagerStateStashing + m.spinner.Start() cmds = append( cmds, stashDocument(m.cc, m.currentDocument), @@ -254,10 +278,16 @@ func pagerUpdate(msg tea.Msg, m pagerModel) (pagerModel, tea.Cmd) { } case spinner.TickMsg: - if m.state == pagerStateStashing { + if m.state == pagerStateStashing || !m.spinner.MinimumLifetimeReached() { newSpinnerModel, cmd := spinner.Update(msg, m.spinner) m.spinner = newSpinnerModel cmds = append(cmds, cmd) + } else if m.state == pagerStateStashSuccess && m.spinner.MinimumLifetimeReached() { + m.state = pagerStateBrowse + m.currentDocument = *m.stashedDocument + m.stashedDocument = nil + cmd := m.showStatusMessage("Stashed!") + cmds = append(cmds, cmd) } // Glow has rendered the content @@ -274,25 +304,19 @@ func pagerUpdate(msg tea.Msg, m pagerModel) (pagerModel, tea.Cmd) { case stashSuccessMsg: // Stashing was successful. Convert the loaded document to a stashed - // one. Note that we're also handling this message in the main update - // function where we're adding this stashed item to the stash listing. - - m.state = pagerStateBrowse - - // Replace the current document in the state so its metadata becomes - // that of a stashed document, but don't re-render since the body is - // identical to what's already rendered. - m.currentDocument = markdown(msg) - - // Show a success message to the user. - m.state = pagerStateStatusMessage - m.statusMessageHeader = "Stashed!" - m.statusMessageBody = "" - if m.statusMessageTimer != nil { - m.statusMessageTimer.Stop() + // one and show a status message. Note that we're also handling this + // message in the main update function where we're adding this stashed + // item to the stash listing. + m.state = pagerStateStashSuccess + if m.spinner.MinimumLifetimeReached() { + m.state = pagerStateBrowse + m.currentDocument = markdown(msg) + cmd := m.showStatusMessage("Stashed!") + cmds = append(cmds, cmd) + } else { + md := markdown(msg) + m.stashedDocument = &md } - m.statusMessageTimer = time.NewTimer(statusMessageTimeout) - cmds = append(cmds, waitForStatusMessageTimeout(pagerContext, m.statusMessageTimer)) case stashErrMsg: // TODO @@ -364,8 +388,10 @@ func pagerStatusBarView(b *strings.Builder, m pagerModel) { // Status indicator; spinner or stash dot var statusIndicator string - if m.state == pagerStateStashing { - statusIndicator = statusBarNoteStyle(" ") + spinner.View(m.spinner) + if m.state == pagerStateStashing || m.state == pagerStateStashSuccess { + if !m.spinner.Hidden() { + statusIndicator = statusBarNoteStyle(" ") + spinner.View(m.spinner) + } } else if isStashed && showStatusMessage { statusIndicator = statusBarMessageStashDotStyle(" •") } else if isStashed {