mirror of
https://github.com/charmbracelet/glow.git
synced 2026-08-09 09:49:09 +02:00
Compare commits
5 commits
master
...
proposals-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b541514436 |
||
|
|
ab51fe2632 |
||
|
|
3104f60786 |
||
|
|
bb6a1e5561 |
||
|
|
71704a1c0b |
8 changed files with 308 additions and 817 deletions
28
go.mod
28
go.mod
|
|
@ -1,14 +1,14 @@
|
|||
module github.com/charmbracelet/glow
|
||||
|
||||
go 1.17
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/atotto/clipboard v0.1.4
|
||||
github.com/charmbracelet/bubbles v0.15.0
|
||||
github.com/charmbracelet/bubbletea v0.25.0
|
||||
github.com/charmbracelet/bubbles v0.18.1-0.20240514172444-4491293fd12c
|
||||
github.com/charmbracelet/bubbletea v0.26.3-0.20240514172421-c69b27d7eeb8
|
||||
github.com/charmbracelet/charm v0.8.7
|
||||
github.com/charmbracelet/glamour v0.6.0
|
||||
github.com/charmbracelet/lipgloss v0.6.0
|
||||
github.com/charmbracelet/lipgloss v0.10.1-0.20240514172355-88ecbb398449
|
||||
github.com/charmbracelet/x/editor v0.0.0-20231116172829-450eedbca1ab
|
||||
github.com/dustin/go-humanize v1.0.1
|
||||
github.com/mattn/go-runewidth v0.0.15
|
||||
|
|
@ -17,12 +17,11 @@ require (
|
|||
github.com/muesli/gitcha v0.2.0
|
||||
github.com/muesli/go-app-paths v0.2.2
|
||||
github.com/muesli/reflow v0.3.0
|
||||
github.com/muesli/termenv v0.15.2
|
||||
github.com/sahilm/fuzzy v0.1.0
|
||||
github.com/sahilm/fuzzy v0.1.1
|
||||
github.com/segmentio/ksuid v1.0.4
|
||||
github.com/spf13/cobra v1.8.0
|
||||
github.com/spf13/viper v1.14.0
|
||||
golang.org/x/sys v0.17.0
|
||||
golang.org/x/sys v0.20.0
|
||||
golang.org/x/term v0.15.0
|
||||
golang.org/x/text v0.14.0
|
||||
)
|
||||
|
|
@ -32,9 +31,13 @@ require (
|
|||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||
github.com/aymerick/douceur v0.2.0 // indirect
|
||||
github.com/calmh/randomart v1.1.0 // indirect
|
||||
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect
|
||||
github.com/charmbracelet/x/ansi v0.1.1 // indirect
|
||||
github.com/charmbracelet/x/input v0.1.0 // indirect
|
||||
github.com/charmbracelet/x/term v0.1.1 // indirect
|
||||
github.com/charmbracelet/x/windows v0.1.0 // indirect
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
|
||||
github.com/dlclark/regexp2 v1.4.0 // indirect
|
||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/gorilla/css v1.0.0 // indirect
|
||||
|
|
@ -43,28 +46,29 @@ require (
|
|||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||
github.com/magiconair/properties v1.8.6 // indirect
|
||||
github.com/mattn/go-isatty v0.0.18 // indirect
|
||||
github.com/mattn/go-localereader v0.0.1 // indirect
|
||||
github.com/microcosm-cc/bluemonday v1.0.21 // indirect
|
||||
github.com/mikesmitty/edkey v0.0.0-20170222072505-3356ea4e686a // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b // indirect
|
||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
|
||||
github.com/muesli/cancelreader v0.2.2 // indirect
|
||||
github.com/muesli/sasquatch v0.0.0-20200811221207-66979d92330a // indirect
|
||||
github.com/muesli/termenv v0.15.2 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/pelletier/go-toml v1.9.5 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.5 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/sabhiram/go-gitignore v0.0.0-20180611051255-d3107576ba94 // indirect
|
||||
github.com/spf13/afero v1.9.2 // indirect
|
||||
github.com/spf13/cast v1.5.0 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/subosito/gotenv v1.4.1 // indirect
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||
github.com/yuin/goldmark v1.5.2 // indirect
|
||||
github.com/yuin/goldmark-emoji v1.0.1 // indirect
|
||||
golang.org/x/crypto v0.17.0 // indirect
|
||||
golang.org/x/net v0.17.0 // indirect
|
||||
golang.org/x/sync v0.1.0 // indirect
|
||||
golang.org/x/sync v0.7.0 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
|
|
|
|||
28
ui/pager.go
28
ui/pager.go
|
|
@ -138,12 +138,12 @@ type pagerModel struct {
|
|||
|
||||
func newPagerModel(common *commonModel) pagerModel {
|
||||
// Init viewport
|
||||
vp := viewport.New(0, 0)
|
||||
vp := viewport.New(common.ctx, 0, 0)
|
||||
vp.YPosition = 0
|
||||
vp.HighPerformanceRendering = config.HighPerformancePager
|
||||
|
||||
// Text input for notes/memos
|
||||
ti := textinput.New()
|
||||
ti := textinput.New(common.ctx)
|
||||
ti.Prompt = " > "
|
||||
ti.PromptStyle = pagerNoteInputPromptStyle
|
||||
ti.TextStyle = pagerNoteInputStyle
|
||||
|
|
@ -152,7 +152,7 @@ func newPagerModel(common *commonModel) pagerModel {
|
|||
ti.Focus()
|
||||
|
||||
// Text input for search
|
||||
sp := spinner.New()
|
||||
sp := spinner.New(common.ctx)
|
||||
sp.Style = spinnerStyle
|
||||
|
||||
return pagerModel{
|
||||
|
|
@ -219,7 +219,7 @@ func (m *pagerModel) unload() {
|
|||
m.textInput.Reset()
|
||||
}
|
||||
|
||||
func (m pagerModel) update(msg tea.Msg) (pagerModel, tea.Cmd) {
|
||||
func (m pagerModel) update(ctx tea.Context, msg tea.Msg) (pagerModel, tea.Cmd) {
|
||||
var (
|
||||
cmd tea.Cmd
|
||||
cmds []tea.Cmd
|
||||
|
|
@ -339,7 +339,7 @@ func (m pagerModel) update(msg tea.Msg) (pagerModel, tea.Cmd) {
|
|||
// full lifetime. In either case we need to spin the spinner
|
||||
// irrespective of it's more fine-grained visibility rules.
|
||||
var cmd tea.Cmd
|
||||
m.spinner, cmd = m.spinner.Update(msg)
|
||||
m.spinner, cmd = m.spinner.Update(ctx, msg)
|
||||
cmds = append(cmds, cmd)
|
||||
} else if m.state == pagerStateStashSuccess {
|
||||
// Successful stash. Stop spinning and update accordingly.
|
||||
|
|
@ -396,10 +396,10 @@ func (m pagerModel) update(msg tea.Msg) (pagerModel, tea.Cmd) {
|
|||
|
||||
switch m.state {
|
||||
case pagerStateSetNote:
|
||||
m.textInput, cmd = m.textInput.Update(msg)
|
||||
m.textInput, cmd = m.textInput.Update(ctx, msg)
|
||||
cmds = append(cmds, cmd)
|
||||
default:
|
||||
m.viewport, cmd = m.viewport.Update(msg)
|
||||
m.viewport, cmd = m.viewport.Update(ctx, msg)
|
||||
cmds = append(cmds, cmd)
|
||||
}
|
||||
|
||||
|
|
@ -414,16 +414,16 @@ func (m pagerModel) spinnerVisible() bool {
|
|||
return now.After(windowStart) && now.Before(windowEnd)
|
||||
}
|
||||
|
||||
func (m pagerModel) View() string {
|
||||
func (m pagerModel) View(ctx tea.Context) string {
|
||||
var b strings.Builder
|
||||
fmt.Fprint(&b, m.viewport.View()+"\n")
|
||||
fmt.Fprint(&b, m.viewport.View(ctx)+"\n")
|
||||
|
||||
// Footer
|
||||
switch m.state {
|
||||
case pagerStateSetNote:
|
||||
m.setNoteView(&b)
|
||||
default:
|
||||
m.statusBarView(&b)
|
||||
m.statusBarView(ctx, &b)
|
||||
}
|
||||
|
||||
if m.showHelp {
|
||||
|
|
@ -433,7 +433,7 @@ func (m pagerModel) View() string {
|
|||
return b.String()
|
||||
}
|
||||
|
||||
func (m pagerModel) statusBarView(b *strings.Builder) {
|
||||
func (m pagerModel) statusBarView(ctx tea.Context, b *strings.Builder) {
|
||||
const (
|
||||
minPercent float64 = 0.0
|
||||
maxPercent float64 = 1.0
|
||||
|
|
@ -444,7 +444,7 @@ func (m pagerModel) statusBarView(b *strings.Builder) {
|
|||
showStatusMessage := m.state == pagerStateStatusMessage
|
||||
|
||||
// Logo
|
||||
logo := glowLogoView(" Glow ")
|
||||
logo := m.common.styles.LogoStyle.Render(" Glow ")
|
||||
|
||||
// Scroll percent
|
||||
percent := math.Max(minPercent, math.Min(maxPercent, m.viewport.ScrollPercent()))
|
||||
|
|
@ -468,7 +468,7 @@ func (m pagerModel) statusBarView(b *strings.Builder) {
|
|||
if m.state == pagerStateStashing || m.state == pagerStateStashSuccess {
|
||||
var spinner string
|
||||
if m.spinnerVisible() {
|
||||
spinner = m.spinner.View()
|
||||
spinner = m.spinner.View(ctx)
|
||||
}
|
||||
statusIndicator = statusBarNoteStyle(" ") + spinner
|
||||
} else if isStashed && showStatusMessage {
|
||||
|
|
@ -528,7 +528,7 @@ func (m pagerModel) statusBarView(b *strings.Builder) {
|
|||
|
||||
func (m pagerModel) setNoteView(b *strings.Builder) {
|
||||
fmt.Fprint(b, noteHeading)
|
||||
fmt.Fprint(b, m.textInput.View())
|
||||
fmt.Fprint(b, m.textInput.View(m.common.ctx))
|
||||
}
|
||||
|
||||
func (m pagerModel) helpView() (s string) {
|
||||
|
|
|
|||
125
ui/stash.go
125
ui/stash.go
|
|
@ -14,7 +14,6 @@ import (
|
|||
"github.com/charmbracelet/bubbles/textinput"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/charm"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/muesli/reflow/ansi"
|
||||
"github.com/muesli/reflow/truncate"
|
||||
"github.com/sahilm/fuzzy"
|
||||
|
|
@ -33,26 +32,6 @@ var (
|
|||
alreadyStashedStatusMessage = statusMessage{subtleStatusMessage, "Already stashed"}
|
||||
)
|
||||
|
||||
var (
|
||||
dividerDot = darkGrayFg.SetString(" • ")
|
||||
dividerBar = darkGrayFg.SetString(" │ ")
|
||||
offlineHeaderNote = darkGrayFg.SetString("(Offline)")
|
||||
|
||||
logoStyle = lipgloss.NewStyle().
|
||||
Foreground(lipgloss.Color("#ECFD65")).
|
||||
Background(fuchsia).
|
||||
Bold(true)
|
||||
|
||||
stashSpinnerStyle = lipgloss.NewStyle().
|
||||
Foreground(gray)
|
||||
stashInputPromptStyle = lipgloss.NewStyle().
|
||||
Foreground(yellowGreen).
|
||||
MarginRight(1)
|
||||
stashInputCursorStyle = lipgloss.NewStyle().
|
||||
Foreground(fuchsia).
|
||||
MarginRight(1)
|
||||
)
|
||||
|
||||
// MSG
|
||||
|
||||
type (
|
||||
|
|
@ -134,41 +113,41 @@ type statusMessage struct {
|
|||
message string
|
||||
}
|
||||
|
||||
func initSections() {
|
||||
func initSections(c *commonModel) {
|
||||
sections = map[sectionKey]section{
|
||||
localSection: {
|
||||
key: localSection,
|
||||
docTypes: NewDocTypeSet(LocalDoc),
|
||||
paginator: newStashPaginator(),
|
||||
paginator: newStashPaginator(c),
|
||||
},
|
||||
stashedSection: {
|
||||
key: stashedSection,
|
||||
docTypes: NewDocTypeSet(StashedDoc, ConvertedDoc),
|
||||
paginator: newStashPaginator(),
|
||||
paginator: newStashPaginator(c),
|
||||
},
|
||||
newsSection: {
|
||||
key: newsSection,
|
||||
docTypes: NewDocTypeSet(NewsDoc),
|
||||
paginator: newStashPaginator(),
|
||||
paginator: newStashPaginator(c),
|
||||
},
|
||||
filterSection: {
|
||||
key: filterSection,
|
||||
docTypes: DocTypeSet{},
|
||||
paginator: newStashPaginator(),
|
||||
paginator: newStashPaginator(c),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// String returns a styled version of the status message appropriate for the
|
||||
// Render returns a styled version of the status message appropriate for the
|
||||
// given context.
|
||||
func (s statusMessage) String() string {
|
||||
func (s statusMessage) Render(st *styles) string {
|
||||
switch s.status {
|
||||
case subtleStatusMessage:
|
||||
return dimGreenFg(s.message)
|
||||
return st.DimGreenFg(s.message)
|
||||
case errorStatusMessage:
|
||||
return redFg(s.message)
|
||||
return st.RedFg(s.message)
|
||||
default:
|
||||
return greenFg(s.message)
|
||||
return st.GreenFg(s.message)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -514,21 +493,21 @@ func (m *stashModel) moveCursorDown() {
|
|||
// INIT
|
||||
|
||||
func newStashModel(common *commonModel) stashModel {
|
||||
sp := spinner.New()
|
||||
sp := spinner.New(common.ctx)
|
||||
sp.Spinner = spinner.Line
|
||||
sp.Style = stashSpinnerStyle
|
||||
sp.Style = common.styles.StashSpinnerStyle
|
||||
|
||||
ni := textinput.New()
|
||||
ni := textinput.New(common.ctx)
|
||||
ni.Prompt = "Memo:"
|
||||
ni.PromptStyle = stashInputPromptStyle
|
||||
ni.CursorStyle = stashInputCursorStyle
|
||||
ni.PromptStyle = common.styles.StashInputPromptStyle
|
||||
ni.CursorStyle = common.styles.StashInputCursorStyle
|
||||
ni.CharLimit = noteCharacterLimit
|
||||
ni.Focus()
|
||||
|
||||
si := textinput.New()
|
||||
si := textinput.New(common.ctx)
|
||||
si.Prompt = "Find:"
|
||||
si.PromptStyle = stashInputPromptStyle
|
||||
si.CursorStyle = stashInputCursorStyle
|
||||
si.PromptStyle = common.styles.StashInputPromptStyle
|
||||
si.CursorStyle = common.styles.StashInputCursorStyle
|
||||
si.CharLimit = noteCharacterLimit
|
||||
si.Focus()
|
||||
|
||||
|
|
@ -563,17 +542,17 @@ func newStashModel(common *commonModel) stashModel {
|
|||
return m
|
||||
}
|
||||
|
||||
func newStashPaginator() paginator.Model {
|
||||
p := paginator.New()
|
||||
func newStashPaginator(common *commonModel) paginator.Model {
|
||||
p := paginator.New(common.ctx)
|
||||
p.Type = paginator.Dots
|
||||
p.ActiveDot = brightGrayFg("•")
|
||||
p.InactiveDot = darkGrayFg.Render("•")
|
||||
p.ActiveDot = common.styles.BrightGrayFg("•")
|
||||
p.InactiveDot = common.styles.DarkGrayFg("•")
|
||||
return p
|
||||
}
|
||||
|
||||
// UPDATE
|
||||
|
||||
func (m stashModel) update(msg tea.Msg) (stashModel, tea.Cmd) {
|
||||
func (m stashModel) update(ctx tea.Context, msg tea.Msg) (stashModel, tea.Cmd) {
|
||||
var cmds []tea.Cmd
|
||||
|
||||
switch msg := msg.(type) {
|
||||
|
|
@ -651,7 +630,7 @@ func (m stashModel) update(msg tea.Msg) (stashModel, tea.Cmd) {
|
|||
case spinner.TickMsg:
|
||||
if m.shouldSpin() {
|
||||
var cmd tea.Cmd
|
||||
m.spinner, cmd = m.spinner.Update(msg)
|
||||
m.spinner, cmd = m.spinner.Update(ctx, msg)
|
||||
cmds = append(cmds, cmd)
|
||||
}
|
||||
|
||||
|
|
@ -919,7 +898,7 @@ func (m *stashModel) handleDocumentBrowsing(msg tea.Msg) tea.Cmd {
|
|||
// Update paginator. Pagination key handling is done here, but it could
|
||||
// also be moved up to this level, in which case we'd use model methods
|
||||
// like model.PageUp().
|
||||
newPaginatorModel, cmd := m.paginator().Update(msg)
|
||||
newPaginatorModel, cmd := m.paginator().Update(m.common.ctx, msg)
|
||||
m.setPaginator(newPaginatorModel)
|
||||
cmds = append(cmds, cmd)
|
||||
|
||||
|
|
@ -1071,7 +1050,7 @@ func (m *stashModel) handleFiltering(msg tea.Msg) tea.Cmd {
|
|||
}
|
||||
|
||||
// Update the filter text input component
|
||||
newFilterInputModel, inputCmd := m.filterInput.Update(msg)
|
||||
newFilterInputModel, inputCmd := m.filterInput.Update(m.common.ctx, msg)
|
||||
currentFilterVal := m.filterInput.Value()
|
||||
newFilterVal := newFilterInputModel.Value()
|
||||
m.filterInput = newFilterInputModel
|
||||
|
|
@ -1128,7 +1107,7 @@ func (m *stashModel) handleNoteInput(msg tea.Msg) tea.Cmd {
|
|||
}
|
||||
|
||||
// Update the note text input component
|
||||
newNoteInputModel, noteInputCmd := m.noteInput.Update(msg)
|
||||
newNoteInputModel, noteInputCmd := m.noteInput.Update(m.common.ctx, msg)
|
||||
m.noteInput = newNoteInputModel
|
||||
cmds = append(cmds, noteInputCmd)
|
||||
|
||||
|
|
@ -1137,26 +1116,26 @@ func (m *stashModel) handleNoteInput(msg tea.Msg) tea.Cmd {
|
|||
|
||||
// VIEW
|
||||
|
||||
func (m stashModel) view() string {
|
||||
func (m stashModel) view(ctx tea.Context) string {
|
||||
var s string
|
||||
switch m.viewState {
|
||||
case stashStateShowingError:
|
||||
return errorView(m.err, false)
|
||||
return errorView(&m.common.styles, m.err, false)
|
||||
case stashStateLoadingDocument:
|
||||
s += " " + m.spinner.View() + " Loading document..."
|
||||
s += " " + m.spinner.View(ctx) + " Loading document..."
|
||||
case stashStateReady:
|
||||
|
||||
loadingIndicator := " "
|
||||
if m.shouldSpin() {
|
||||
loadingIndicator = m.spinner.View()
|
||||
loadingIndicator = m.spinner.View(ctx)
|
||||
}
|
||||
|
||||
var header string
|
||||
switch m.selectionState {
|
||||
case selectionPromptingDelete:
|
||||
header = redFg("Delete this item from your stash? ") + faintRedFg("(y/N)")
|
||||
header = m.common.styles.RedFg("Delete this item from your stash? ") + m.common.styles.FaintRedFg("(y/N)")
|
||||
case selectionSettingNote:
|
||||
header = yellowFg("Set the memo for this item?")
|
||||
header = m.common.styles.YellowFg("Set the memo for this item?")
|
||||
}
|
||||
|
||||
// Only draw the normal header if we're not using the header area for
|
||||
|
|
@ -1168,13 +1147,13 @@ func (m stashModel) view() string {
|
|||
// Rules for the logo, filter and status message.
|
||||
logoOrFilter := " "
|
||||
if m.showStatusMessage && m.filterState == filtering {
|
||||
logoOrFilter += m.statusMessage.String()
|
||||
logoOrFilter += m.statusMessage.Render(&m.common.styles)
|
||||
} else if m.filterState == filtering {
|
||||
logoOrFilter += m.filterInput.View()
|
||||
logoOrFilter += m.filterInput.View(ctx)
|
||||
} else {
|
||||
logoOrFilter += glowLogoView(" Glow ")
|
||||
logoOrFilter += m.common.styles.LogoStyle.Render(" Glow ")
|
||||
if m.showStatusMessage {
|
||||
logoOrFilter += " " + m.statusMessage.String()
|
||||
logoOrFilter += " " + m.statusMessage.Render(&m.common.styles)
|
||||
}
|
||||
}
|
||||
logoOrFilter = truncate.StringWithTail(logoOrFilter, uint(m.common.width-1), ellipsis)
|
||||
|
|
@ -1195,7 +1174,7 @@ func (m stashModel) view() string {
|
|||
|
||||
var pagination string
|
||||
if m.paginator().TotalPages > 1 {
|
||||
pagination = m.paginator().View()
|
||||
pagination = m.paginator().View(ctx)
|
||||
|
||||
// If the dot pagination is wider than the width of the window
|
||||
// use the arabic paginator.
|
||||
|
|
@ -1210,7 +1189,7 @@ func (m stashModel) view() string {
|
|||
// pointers in our model should be refactored away.
|
||||
var p paginator.Model = *(m.paginator())
|
||||
p.Type = paginator.Arabic
|
||||
pagination = paginationStyle.Render(p.View())
|
||||
pagination = m.common.styles.PaginationStyle.Render(p.View(ctx))
|
||||
}
|
||||
|
||||
// We could also look at m.stashFullyLoaded and add an indicator
|
||||
|
|
@ -1232,10 +1211,6 @@ func (m stashModel) view() string {
|
|||
return "\n" + indent(s, stashIndent)
|
||||
}
|
||||
|
||||
func glowLogoView(text string) string {
|
||||
return logoStyle.Render(text)
|
||||
}
|
||||
|
||||
func (m stashModel) headerView() string {
|
||||
localCount := m.countMarkdowns(LocalDoc)
|
||||
stashedCount := m.countMarkdowns(StashedDoc) + m.countMarkdowns(ConvertedDoc)
|
||||
|
|
@ -1246,7 +1221,7 @@ func (m stashModel) headerView() string {
|
|||
// Filter results
|
||||
if m.filterState == filtering {
|
||||
if localCount+stashedCount+newsCount == 0 {
|
||||
return grayFg("Nothing found.")
|
||||
return m.common.styles.GrayFg("Nothing found.")
|
||||
}
|
||||
if localCount > 0 {
|
||||
sections = append(sections, fmt.Sprintf("%d local", localCount))
|
||||
|
|
@ -1256,22 +1231,22 @@ func (m stashModel) headerView() string {
|
|||
}
|
||||
|
||||
for i := range sections {
|
||||
sections[i] = grayFg(sections[i])
|
||||
sections[i] = m.common.styles.GrayFg(sections[i])
|
||||
}
|
||||
|
||||
return strings.Join(sections, dividerDot.String())
|
||||
return strings.Join(sections, m.common.styles.DividerDot)
|
||||
}
|
||||
|
||||
if m.loadingDone() && len(m.markdowns) == 0 {
|
||||
var maybeOffline string
|
||||
if m.common.authStatus == authFailed {
|
||||
maybeOffline = " " + offlineHeaderNote.String()
|
||||
maybeOffline = " " + m.common.styles.OfflineHeaderNote
|
||||
}
|
||||
|
||||
if m.stashedOnly() {
|
||||
return subtleStyle.Render("Can’t load stash") + maybeOffline
|
||||
return m.common.styles.SubtleStyle.Render("Can’t load stash") + maybeOffline
|
||||
}
|
||||
return subtleStyle.Render("No markdown files found") + maybeOffline
|
||||
return m.common.styles.SubtleStyle.Render("No markdown files found") + maybeOffline
|
||||
}
|
||||
|
||||
// Tabs
|
||||
|
|
@ -1299,16 +1274,16 @@ func (m stashModel) headerView() string {
|
|||
}
|
||||
|
||||
if m.sectionIndex == i && len(m.sections) > 1 {
|
||||
s = selectedTabStyle.Render(s)
|
||||
s = m.common.styles.SelectedTabStyle.Render(s)
|
||||
} else {
|
||||
s = tabStyle.Render(s)
|
||||
s = m.common.styles.TabStyle.Render(s)
|
||||
}
|
||||
sections = append(sections, s)
|
||||
}
|
||||
|
||||
s := strings.Join(sections, dividerBar.String())
|
||||
s := strings.Join(sections, m.common.styles.DividerBar)
|
||||
if m.common.authStatus == authFailed {
|
||||
s += dividerDot.String() + offlineHeaderNote.String()
|
||||
s += m.common.styles.DividerDot + m.common.styles.OfflineHeaderNote
|
||||
}
|
||||
|
||||
return s
|
||||
|
|
@ -1322,7 +1297,7 @@ func (m stashModel) populatedView() string {
|
|||
// Empty states
|
||||
if len(mds) == 0 {
|
||||
f := func(s string) {
|
||||
b.WriteString(" " + grayFg(s))
|
||||
b.WriteString(" " + m.common.styles.GrayFg(s))
|
||||
}
|
||||
|
||||
switch m.sections[m.sectionIndex].key {
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ func newHelpColumn(pairs ...string) (h helpColumn) {
|
|||
}
|
||||
|
||||
// render returns styled and formatted rows from keys and values.
|
||||
func (h helpColumn) render(height int) (rows []string) {
|
||||
func (h helpColumn) render(st *styles, height int) (rows []string) {
|
||||
keyWidth, valWidth := h.maxWidths()
|
||||
|
||||
for i := 0; i < height; i++ {
|
||||
|
|
@ -44,11 +44,11 @@ func (h helpColumn) render(height int) (rows []string) {
|
|||
|
||||
switch k {
|
||||
case "s":
|
||||
k = greenFg(k)
|
||||
v = semiDimGreenFg(v)
|
||||
k = st.GreenFg(k)
|
||||
v = st.SemiDimGreenFg(v)
|
||||
default:
|
||||
k = grayFg(k)
|
||||
v = midGrayFg(v)
|
||||
k = st.GrayFg(k)
|
||||
v = st.MidGrayFg(v)
|
||||
}
|
||||
}
|
||||
b.WriteString(k)
|
||||
|
|
@ -196,12 +196,13 @@ func (m stashModel) renderHelp(groups ...[]string) (string, int) {
|
|||
// would otherwise wrap to two lines. Help view entries should come in as pairs,
|
||||
// with the first being the key and the second being the help text.
|
||||
func (m stashModel) miniHelpView(entries ...string) string {
|
||||
st := &m.common.styles
|
||||
if len(entries) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
var (
|
||||
truncationChar = subtleStyle.Render("…")
|
||||
truncationChar = st.SubtleStyle.Render("…")
|
||||
truncationWidth = ansi.PrintableRuneWidth(truncationChar)
|
||||
)
|
||||
|
||||
|
|
@ -221,17 +222,17 @@ func (m stashModel) miniHelpView(entries ...string) string {
|
|||
|
||||
switch k {
|
||||
case "s":
|
||||
k = greenFg(k)
|
||||
v = semiDimGreenFg(v)
|
||||
k = st.GreenFg(k)
|
||||
v = st.SemiDimGreenFg(v)
|
||||
default:
|
||||
k = grayFg(k)
|
||||
v = midGrayFg(v)
|
||||
k = st.GrayFg(k)
|
||||
v = st.MidGrayFg(v)
|
||||
}
|
||||
|
||||
next = fmt.Sprintf("%s %s", k, v)
|
||||
|
||||
if i < len(entries)-2 {
|
||||
next += dividerDot.String()
|
||||
next += st.DividerDot
|
||||
}
|
||||
|
||||
// Only this (and the following) help text items if we have the
|
||||
|
|
@ -269,7 +270,7 @@ func (m stashModel) fullHelpView(groups ...[]string) string {
|
|||
|
||||
// Build columns
|
||||
for _, c := range columns {
|
||||
renderedCols = append(renderedCols, c.render(tallestCol))
|
||||
renderedCols = append(renderedCols, c.render(&m.common.styles, tallestCol))
|
||||
}
|
||||
|
||||
// Merge columns
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ func stashItemView(b *strings.Builder, m stashModel, index int, md *markdown) {
|
|||
isSelected := index == m.cursor()
|
||||
isFiltering := m.filterState == filtering
|
||||
singleFilteredItem := isFiltering && len(m.getVisibleMarkdowns()) == 1
|
||||
styles := &m.common.styles
|
||||
|
||||
// If there are multiple items being filtered don't highlight a selected
|
||||
// item in the results. If we've filtered down to one item, however,
|
||||
|
|
@ -55,33 +56,33 @@ func stashItemView(b *strings.Builder, m stashModel, index int, md *markdown) {
|
|||
|
||||
switch m.selectionState {
|
||||
case selectionPromptingDelete:
|
||||
gutter = faintRedFg(verticalLine)
|
||||
icon = faintRedFg(icon)
|
||||
title = redFg(title)
|
||||
date = faintRedFg(date)
|
||||
gutter = styles.FaintRedFg(verticalLine)
|
||||
icon = styles.FaintRedFg(icon)
|
||||
title = styles.RedFg(title)
|
||||
date = styles.FaintRedFg(date)
|
||||
case selectionSettingNote:
|
||||
gutter = dullYellowFg(verticalLine)
|
||||
gutter = styles.DullYellowFg(verticalLine)
|
||||
icon = ""
|
||||
title = m.noteInput.View()
|
||||
date = dullYellowFg(date)
|
||||
title = m.noteInput.View(m.common.ctx)
|
||||
date = styles.DullYellowFg(date)
|
||||
default:
|
||||
if m.common.latestFileStashed == md.stashID &&
|
||||
m.statusMessage == stashingStatusMessage {
|
||||
gutter = greenFg(verticalLine)
|
||||
icon = dimGreenFg(icon)
|
||||
title = greenFg(title)
|
||||
date = semiDimGreenFg(date)
|
||||
gutter = styles.GreenFg(verticalLine)
|
||||
icon = styles.DimGreenFg(icon)
|
||||
title = styles.GreenFg(title)
|
||||
date = styles.SemiDimGreenFg(date)
|
||||
} else {
|
||||
gutter = dullFuchsiaFg(verticalLine)
|
||||
icon = dullFuchsiaFg(icon)
|
||||
gutter = styles.DullFuchsiaFg(verticalLine)
|
||||
icon = styles.DullFuchsiaFg(icon)
|
||||
if m.currentSection().key == filterSection &&
|
||||
m.filterState == filterApplied || singleFilteredItem {
|
||||
s := lipgloss.NewStyle().Foreground(fuchsia)
|
||||
title = styleFilteredText(title, m.filterInput.Value(), s, s.Copy().Underline(true))
|
||||
} else {
|
||||
title = fuchsiaFg(title)
|
||||
title = styles.FuchsiaFg(title)
|
||||
}
|
||||
date = dullFuchsiaFg(date)
|
||||
date = styles.DullFuchsiaFg(date)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -91,35 +92,35 @@ func stashItemView(b *strings.Builder, m stashModel, index int, md *markdown) {
|
|||
|
||||
if m.common.latestFileStashed == md.stashID &&
|
||||
m.statusMessage == stashingStatusMessage {
|
||||
icon = dimGreenFg(icon)
|
||||
title = greenFg(title)
|
||||
date = semiDimGreenFg(date)
|
||||
icon = styles.DimGreenFg(icon)
|
||||
title = styles.GreenFg(title)
|
||||
date = styles.SemiDimGreenFg(date)
|
||||
} else if md.docType == NewsDoc {
|
||||
if isFiltering && m.filterInput.Value() == "" {
|
||||
title = dimIndigoFg(title)
|
||||
date = dimSubtleIndigoFg(date)
|
||||
title = styles.DimIndigoFg(title)
|
||||
date = styles.DimSubtleIndigoFg(date)
|
||||
} else {
|
||||
s := lipgloss.NewStyle().Foreground(indigo)
|
||||
title = styleFilteredText(title, m.filterInput.Value(), s, s.Copy().Underline(true))
|
||||
date = subtleIndigoFg(date)
|
||||
date = styles.SubtleIndigoFg(date)
|
||||
}
|
||||
} else if isFiltering && m.filterInput.Value() == "" {
|
||||
icon = dimGreenFg(icon)
|
||||
icon = styles.DimGreenFg(icon)
|
||||
if title == noMemoTitle {
|
||||
title = dimBrightGrayFg(title)
|
||||
title = styles.DimBrightGrayFg(title)
|
||||
} else {
|
||||
title = dimNormalFg(title)
|
||||
title = styles.DimNormalFg(title)
|
||||
}
|
||||
date = dimBrightGrayFg(date)
|
||||
date = styles.DimBrightGrayFg(date)
|
||||
} else {
|
||||
icon = greenFg(icon)
|
||||
icon = styles.GreenFg(icon)
|
||||
if title == noMemoTitle {
|
||||
title = brightGrayFg(title)
|
||||
title = styles.BrightGrayFg(title)
|
||||
} else {
|
||||
s := lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "#1a1a1a", Dark: "#dddddd"})
|
||||
title = styleFilteredText(title, m.filterInput.Value(), s, s.Copy().Underline(true))
|
||||
}
|
||||
date = brightGrayFg(date)
|
||||
date = styles.BrightGrayFg(date)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
146
ui/styles.go
146
ui/styles.go
|
|
@ -1,6 +1,10 @@
|
|||
package ui
|
||||
|
||||
import . "github.com/charmbracelet/lipgloss" //nolint: revive
|
||||
import (
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
. "github.com/charmbracelet/lipgloss"
|
||||
) //nolint: revive
|
||||
|
||||
// Colors.
|
||||
var (
|
||||
|
|
@ -30,55 +34,125 @@ var (
|
|||
dimGreen = AdaptiveColor{Light: "#72D2B0", Dark: "#0B5137"}
|
||||
)
|
||||
|
||||
type styler func(...string) string
|
||||
|
||||
// Ulimately, we'll transition to named styles.
|
||||
// nolint:deadcode,unused,varcheck
|
||||
var (
|
||||
normalFg = NewStyle().Foreground(normal).Render
|
||||
dimNormalFg = NewStyle().Foreground(normalDim).Render
|
||||
type styles struct {
|
||||
NormalFg styler
|
||||
DimNormalFg styler
|
||||
|
||||
brightGrayFg = NewStyle().Foreground(brightGray).Render
|
||||
dimBrightGrayFg = NewStyle().Foreground(dimBrightGray).Render
|
||||
BrightGrayFg styler
|
||||
DimBrightGrayFg styler
|
||||
|
||||
grayFg = NewStyle().Foreground(gray).Render
|
||||
midGrayFg = NewStyle().Foreground(midGray).Render
|
||||
darkGrayFg = NewStyle().Foreground(darkGray)
|
||||
GrayFg styler
|
||||
MidGrayFg styler
|
||||
DarkGrayFg styler
|
||||
|
||||
greenFg = NewStyle().Foreground(green).Render
|
||||
semiDimGreenFg = NewStyle().Foreground(semiDimGreen).Render
|
||||
dimGreenFg = NewStyle().Foreground(dimGreen).Render
|
||||
GreenFg styler
|
||||
SemiDimGreenFg styler
|
||||
DimGreenFg styler
|
||||
|
||||
fuchsiaFg = NewStyle().Foreground(fuchsia).Render
|
||||
dimFuchsiaFg = NewStyle().Foreground(dimFuchsia).Render
|
||||
FuchsiaFg styler
|
||||
DimFuchsiaFg styler
|
||||
|
||||
dullFuchsiaFg = NewStyle().Foreground(dullFuchsia).Render
|
||||
dimDullFuchsiaFg = NewStyle().Foreground(dimDullFuchsia).Render
|
||||
DullFuchsiaFg styler
|
||||
DimDullFuchsiaFg styler
|
||||
|
||||
indigoFg = NewStyle().Foreground(fuchsia).Render
|
||||
dimIndigoFg = NewStyle().Foreground(dimIndigo).Render
|
||||
IndigoFg styler
|
||||
DimIndigoFg styler
|
||||
|
||||
subtleIndigoFg = NewStyle().Foreground(subtleIndigo).Render
|
||||
dimSubtleIndigoFg = NewStyle().Foreground(dimSubtleIndigo).Render
|
||||
SubtleIndigoFg styler
|
||||
DimSubtleIndigoFg styler
|
||||
|
||||
yellowFg = NewStyle().Foreground(yellowGreen).Render // renders light green on light backgrounds
|
||||
dullYellowFg = NewStyle().Foreground(dullYellowGreen).Render // renders light green on light backgrounds
|
||||
redFg = NewStyle().Foreground(red).Render
|
||||
faintRedFg = NewStyle().Foreground(faintRed).Render
|
||||
)
|
||||
YellowFg styler
|
||||
DullYellowFg styler
|
||||
RedFg styler
|
||||
FaintRedFg styler
|
||||
|
||||
var (
|
||||
tabStyle = NewStyle().
|
||||
Foreground(AdaptiveColor{Light: "#909090", Dark: "#626262"})
|
||||
TabStyle Style
|
||||
SelectedTabStyle Style
|
||||
ErrorTitleStyle Style
|
||||
SubtleStyle Style
|
||||
PaginationStyle Style
|
||||
|
||||
selectedTabStyle = NewStyle().
|
||||
Foreground(AdaptiveColor{Light: "#333333", Dark: "#979797"})
|
||||
LogoStyle Style
|
||||
StashSpinnerStyle Style
|
||||
StashInputPromptStyle Style
|
||||
StashInputCursorStyle Style
|
||||
|
||||
errorTitleStyle = NewStyle().
|
||||
DividerDot string
|
||||
DividerBar string
|
||||
OfflineHeaderNote string
|
||||
}
|
||||
|
||||
func defaultStyles(ctx tea.Context) styles {
|
||||
darkGrayFg := ctx.NewStyle().Foreground(darkGray).Render
|
||||
subtleStyle := ctx.NewStyle().
|
||||
Foreground(AdaptiveColor{Light: "#9B9B9B", Dark: "#5C5C5C"})
|
||||
|
||||
return styles{
|
||||
NormalFg: ctx.NewStyle().Foreground(normal).Render,
|
||||
DimNormalFg: ctx.NewStyle().Foreground(normalDim).Render,
|
||||
|
||||
BrightGrayFg: ctx.NewStyle().Foreground(brightGray).Render,
|
||||
DimBrightGrayFg: ctx.NewStyle().Foreground(dimBrightGray).Render,
|
||||
|
||||
GrayFg: ctx.NewStyle().Foreground(gray).Render,
|
||||
MidGrayFg: ctx.NewStyle().Foreground(midGray).Render,
|
||||
DarkGrayFg: darkGrayFg,
|
||||
|
||||
GreenFg: ctx.NewStyle().Foreground(green).Render,
|
||||
SemiDimGreenFg: ctx.NewStyle().Foreground(semiDimGreen).Render,
|
||||
DimGreenFg: ctx.NewStyle().Foreground(dimGreen).Render,
|
||||
|
||||
FuchsiaFg: ctx.NewStyle().Foreground(fuchsia).Render,
|
||||
DimFuchsiaFg: ctx.NewStyle().Foreground(dimFuchsia).Render,
|
||||
|
||||
DullFuchsiaFg: ctx.NewStyle().Foreground(dullFuchsia).Render,
|
||||
DimDullFuchsiaFg: ctx.NewStyle().Foreground(dimDullFuchsia).Render,
|
||||
|
||||
IndigoFg: ctx.NewStyle().Foreground(fuchsia).Render,
|
||||
DimIndigoFg: ctx.NewStyle().Foreground(dimIndigo).Render,
|
||||
|
||||
SubtleIndigoFg: ctx.NewStyle().Foreground(subtleIndigo).Render,
|
||||
DimSubtleIndigoFg: ctx.NewStyle().Foreground(dimSubtleIndigo).Render,
|
||||
|
||||
YellowFg: ctx.NewStyle().Foreground(yellowGreen).Render, // renders light green on light backgrounds
|
||||
DullYellowFg: ctx.NewStyle().Foreground(dullYellowGreen).Render, // renders light green on light backgrounds
|
||||
RedFg: ctx.NewStyle().Foreground(red).Render,
|
||||
FaintRedFg: ctx.NewStyle().Foreground(faintRed).Render,
|
||||
TabStyle: ctx.NewStyle().
|
||||
Foreground(AdaptiveColor{Light: "#909090", Dark: "#626262"}),
|
||||
|
||||
SelectedTabStyle: ctx.NewStyle().
|
||||
Foreground(AdaptiveColor{Light: "#333333", Dark: "#979797"}),
|
||||
|
||||
ErrorTitleStyle: ctx.NewStyle().
|
||||
Foreground(cream).
|
||||
Background(red).
|
||||
Padding(0, 1)
|
||||
Padding(0, 1),
|
||||
|
||||
subtleStyle = NewStyle().
|
||||
Foreground(AdaptiveColor{Light: "#9B9B9B", Dark: "#5C5C5C"})
|
||||
SubtleStyle: subtleStyle,
|
||||
|
||||
paginationStyle = subtleStyle.Copy()
|
||||
)
|
||||
PaginationStyle: subtleStyle.Copy(),
|
||||
|
||||
LogoStyle: ctx.NewStyle().
|
||||
Foreground(lipgloss.Color("#ECFD65")).
|
||||
Background(fuchsia).
|
||||
Bold(true),
|
||||
|
||||
StashSpinnerStyle: ctx.NewStyle().
|
||||
Foreground(gray),
|
||||
StashInputPromptStyle: ctx.NewStyle().
|
||||
Foreground(yellowGreen).
|
||||
MarginRight(1),
|
||||
StashInputCursorStyle: ctx.NewStyle().
|
||||
Foreground(fuchsia).
|
||||
MarginRight(1),
|
||||
|
||||
DividerDot: darkGrayFg(" • "),
|
||||
DividerBar: darkGrayFg(" │ "),
|
||||
OfflineHeaderNote: darkGrayFg("(Offline)"),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
68
ui/ui.go
68
ui/ui.go
|
|
@ -14,7 +14,6 @@ import (
|
|||
"github.com/charmbracelet/charm/keygen"
|
||||
"github.com/charmbracelet/glow/utils"
|
||||
"github.com/muesli/gitcha"
|
||||
te "github.com/muesli/termenv"
|
||||
"github.com/segmentio/ksuid"
|
||||
)
|
||||
|
||||
|
|
@ -141,6 +140,7 @@ const (
|
|||
|
||||
// Common stuff we'll need to access in all models.
|
||||
type commonModel struct {
|
||||
ctx tea.Context
|
||||
cfg Config
|
||||
cc *charm.Client
|
||||
cwd string
|
||||
|
|
@ -158,6 +158,8 @@ type commonModel struct {
|
|||
// Files currently being stashed. We remove files from this set once
|
||||
// a stash operation has either succeeded or failed.
|
||||
filesStashing map[ksuid.KSUID]struct{}
|
||||
|
||||
styles styles
|
||||
}
|
||||
|
||||
func (c commonModel) isStashing() bool {
|
||||
|
|
@ -199,16 +201,6 @@ func (m *model) unloadDocument() []tea.Cmd {
|
|||
}
|
||||
|
||||
func newModel(cfg Config) tea.Model {
|
||||
initSections()
|
||||
|
||||
if cfg.GlamourStyle == "auto" {
|
||||
if te.HasDarkBackground() {
|
||||
cfg.GlamourStyle = "dark"
|
||||
} else {
|
||||
cfg.GlamourStyle = "light"
|
||||
}
|
||||
}
|
||||
|
||||
if len(cfg.DocumentTypes) == 0 {
|
||||
cfg.DocumentTypes.Add(LocalDoc, StashedDoc, ConvertedDoc, NewsDoc)
|
||||
}
|
||||
|
|
@ -224,12 +216,28 @@ func newModel(cfg Config) tea.Model {
|
|||
common: &common,
|
||||
state: stateShowStash,
|
||||
keygenState: keygenUnstarted,
|
||||
pager: newPagerModel(&common),
|
||||
stash: newStashModel(&common),
|
||||
}
|
||||
}
|
||||
|
||||
func (m model) Init() tea.Cmd {
|
||||
func (m model) Init(ctx tea.Context) (tea.Model, tea.Cmd) {
|
||||
if m.common.cfg.GlamourStyle == "auto" {
|
||||
if ctx.HasLightBackground() {
|
||||
m.common.cfg.GlamourStyle = "light"
|
||||
} else {
|
||||
m.common.cfg.GlamourStyle = "dark"
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize styles & sub-models
|
||||
m.common.ctx = ctx
|
||||
m.common.styles = defaultStyles(ctx)
|
||||
|
||||
// Initialize sections after we have the styles
|
||||
initSections(m.common)
|
||||
|
||||
m.pager = newPagerModel(m.common)
|
||||
m.stash = newStashModel(m.common)
|
||||
|
||||
var cmds []tea.Cmd
|
||||
d := m.common.cfg.DocumentTypes
|
||||
|
||||
|
|
@ -244,10 +252,10 @@ func (m model) Init() tea.Cmd {
|
|||
cmds = append(cmds, findLocalFiles(m))
|
||||
}
|
||||
|
||||
return tea.Batch(cmds...)
|
||||
return m, tea.Batch(cmds...)
|
||||
}
|
||||
|
||||
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
func (m model) Update(ctx tea.Context, msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
// If there's been an error, any key exits
|
||||
if m.fatalErr != nil {
|
||||
if _, ok := msg.(tea.KeyMsg); ok {
|
||||
|
|
@ -273,7 +281,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
case stateShowStash:
|
||||
// pass through all keys if we're editing the filter
|
||||
if m.stash.filterState == filtering || m.stash.selectionState == selectionSettingNote {
|
||||
m.stash, cmd = m.stash.update(msg)
|
||||
m.stash, cmd = m.stash.update(ctx, msg)
|
||||
return m, cmd
|
||||
}
|
||||
|
||||
|
|
@ -283,7 +291,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
// If setting a note send all keys straight through
|
||||
case pagerStateSetNote:
|
||||
var batch []tea.Cmd
|
||||
newPagerModel, cmd := m.pager.update(msg)
|
||||
newPagerModel, cmd := m.pager.update(ctx, msg)
|
||||
m.pager = newPagerModel
|
||||
batch = append(batch, cmd)
|
||||
return m, tea.Batch(batch...)
|
||||
|
|
@ -370,7 +378,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
// A note was saved to a document. This will have been 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.
|
||||
stashModel, cmd := m.stash.update(msg)
|
||||
stashModel, cmd := m.stash.update(ctx, msg)
|
||||
m.stash = stashModel
|
||||
return m, cmd
|
||||
|
||||
|
|
@ -378,7 +386,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
// Always pass these messages to the stash so we can keep it updated
|
||||
// about network activity, even if the user isn't currently viewing
|
||||
// the stash.
|
||||
stashModel, cmd := m.stash.update(msg)
|
||||
stashModel, cmd := m.stash.update(ctx, msg)
|
||||
m.stash = stashModel
|
||||
return m, cmd
|
||||
|
||||
|
|
@ -424,7 +432,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
|
||||
case filteredMarkdownMsg:
|
||||
if m.state == stateShowDocument {
|
||||
newStashModel, cmd := m.stash.update(msg)
|
||||
newStashModel, cmd := m.stash.update(ctx, msg)
|
||||
m.stash = newStashModel
|
||||
cmds = append(cmds, cmd)
|
||||
}
|
||||
|
|
@ -433,12 +441,12 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
// Process children
|
||||
switch m.state {
|
||||
case stateShowStash:
|
||||
newStashModel, cmd := m.stash.update(msg)
|
||||
newStashModel, cmd := m.stash.update(ctx, msg)
|
||||
m.stash = newStashModel
|
||||
cmds = append(cmds, cmd)
|
||||
|
||||
case stateShowDocument:
|
||||
newPagerModel, cmd := m.pager.update(msg)
|
||||
newPagerModel, cmd := m.pager.update(ctx, msg)
|
||||
m.pager = newPagerModel
|
||||
cmds = append(cmds, cmd)
|
||||
}
|
||||
|
|
@ -446,20 +454,20 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||
return m, tea.Batch(cmds...)
|
||||
}
|
||||
|
||||
func (m model) View() string {
|
||||
func (m model) View(ctx tea.Context) string {
|
||||
if m.fatalErr != nil {
|
||||
return errorView(m.fatalErr, true)
|
||||
return errorView(&m.common.styles, m.fatalErr, true)
|
||||
}
|
||||
|
||||
switch m.state {
|
||||
case stateShowDocument:
|
||||
return m.pager.View()
|
||||
return m.pager.View(ctx)
|
||||
default:
|
||||
return m.stash.view()
|
||||
return m.stash.view(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
func errorView(err error, fatal bool) string {
|
||||
func errorView(st *styles, err error, fatal bool) string {
|
||||
exitMsg := "press any key to "
|
||||
if fatal {
|
||||
exitMsg += "exit"
|
||||
|
|
@ -467,9 +475,9 @@ func errorView(err error, fatal bool) string {
|
|||
exitMsg += "return"
|
||||
}
|
||||
s := fmt.Sprintf("%s\n\n%v\n\n%s",
|
||||
errorTitleStyle.Render("ERROR"),
|
||||
st.ErrorTitleStyle.Render("ERROR"),
|
||||
err,
|
||||
subtleStyle.Render(exitMsg),
|
||||
st.SubtleStyle.Render(exitMsg),
|
||||
)
|
||||
return "\n" + indent(s, 3)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue