chore: use proposed api

This commit is contained in:
Ayman Bagabas 2024-05-13 17:01:14 -04:00
commit ab51fe2632
No known key found for this signature in database
GPG key ID: C8D51D2157C919AC
9 changed files with 277 additions and 203 deletions

View file

@ -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) {

View file

@ -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("Cant load stash") + maybeOffline
return m.common.styles.SubtleStyle.Render("Cant 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 {

View file

@ -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

View file

@ -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)
}
}

View file

@ -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)"),
}
}

View file

@ -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.Context) (tea.Model, 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
@ -273,7 +281,7 @@ func (m model) Update(ctx tea.Context, 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(ctx tea.Context, 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(ctx tea.Context, 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(ctx tea.Context, 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(ctx tea.Context, 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(ctx tea.Context, 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)
}
@ -448,18 +456,18 @@ func (m model) Update(ctx tea.Context, msg tea.Msg) (tea.Model, tea.Cmd) {
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)
}