mirror of
https://github.com/zoriya/bubbles.git
synced 2026-08-07 05:36:11 +00:00
chore: conform to the proposed bubble tea API
This commit is contained in:
+7
-4
@@ -75,21 +75,24 @@ type Model struct {
|
||||
}
|
||||
|
||||
// New creates a new model with default settings.
|
||||
func New() Model {
|
||||
func New(ctx tea.Context) Model {
|
||||
return Model{
|
||||
Style: ctx.NewStyle(),
|
||||
TextStyle: ctx.NewStyle(),
|
||||
|
||||
BlinkSpeed: defaultBlinkSpeed,
|
||||
|
||||
Blink: true,
|
||||
mode: CursorBlink,
|
||||
|
||||
blinkCtx: &blinkCtx{
|
||||
ctx: context.Background(),
|
||||
ctx: ctx,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Update updates the cursor.
|
||||
func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
||||
func (m Model) Update(ctx tea.Context, msg tea.Msg) (Model, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
case initialBlinkMsg:
|
||||
// We accept all initialBlinkMsgs generated by the Blink command.
|
||||
@@ -203,7 +206,7 @@ func (m *Model) SetChar(char string) {
|
||||
}
|
||||
|
||||
// View displays the cursor.
|
||||
func (m Model) View() string {
|
||||
func (m Model) View(tea.Context) string {
|
||||
if m.Blink {
|
||||
return m.TextStyle.Inline(true).Render(m.char)
|
||||
}
|
||||
|
||||
+17
-23
@@ -29,7 +29,7 @@ func nextID() int {
|
||||
}
|
||||
|
||||
// New returns a new filepicker model with default styling and key bindings.
|
||||
func New() Model {
|
||||
func New(ctx tea.Context) Model {
|
||||
return Model{
|
||||
id: nextID(),
|
||||
CurrentDirectory: ".",
|
||||
@@ -49,7 +49,7 @@ func New() Model {
|
||||
minStack: newStack(),
|
||||
maxStack: newStack(),
|
||||
KeyMap: DefaultKeyMap(),
|
||||
Styles: DefaultStyles(),
|
||||
Styles: DefaultStyles(ctx),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,25 +112,19 @@ type Styles struct {
|
||||
}
|
||||
|
||||
// DefaultStyles defines the default styling for the file picker.
|
||||
func DefaultStyles() Styles {
|
||||
return DefaultStylesWithRenderer(lipgloss.DefaultRenderer())
|
||||
}
|
||||
|
||||
// DefaultStylesWithRenderer defines the default styling for the file picker,
|
||||
// with a given Lip Gloss renderer.
|
||||
func DefaultStylesWithRenderer(r *lipgloss.Renderer) Styles {
|
||||
func DefaultStyles(ctx tea.Context) Styles {
|
||||
return Styles{
|
||||
DisabledCursor: r.NewStyle().Foreground(lipgloss.Color("247")),
|
||||
Cursor: r.NewStyle().Foreground(lipgloss.Color("212")),
|
||||
Symlink: r.NewStyle().Foreground(lipgloss.Color("36")),
|
||||
Directory: r.NewStyle().Foreground(lipgloss.Color("99")),
|
||||
File: r.NewStyle(),
|
||||
DisabledFile: r.NewStyle().Foreground(lipgloss.Color("243")),
|
||||
DisabledSelected: r.NewStyle().Foreground(lipgloss.Color("247")),
|
||||
Permission: r.NewStyle().Foreground(lipgloss.Color("244")),
|
||||
Selected: r.NewStyle().Foreground(lipgloss.Color("212")).Bold(true),
|
||||
FileSize: r.NewStyle().Foreground(lipgloss.Color("240")).Width(fileSizeWidth).Align(lipgloss.Right),
|
||||
EmptyDirectory: r.NewStyle().Foreground(lipgloss.Color("240")).PaddingLeft(paddingLeft).SetString("Bummer. No Files Found."),
|
||||
DisabledCursor: ctx.NewStyle().Foreground(lipgloss.Color("247")),
|
||||
Cursor: ctx.NewStyle().Foreground(lipgloss.Color("212")),
|
||||
Symlink: ctx.NewStyle().Foreground(lipgloss.Color("36")),
|
||||
Directory: ctx.NewStyle().Foreground(lipgloss.Color("99")),
|
||||
File: ctx.NewStyle(),
|
||||
DisabledFile: ctx.NewStyle().Foreground(lipgloss.Color("243")),
|
||||
DisabledSelected: ctx.NewStyle().Foreground(lipgloss.Color("247")),
|
||||
Permission: ctx.NewStyle().Foreground(lipgloss.Color("244")),
|
||||
Selected: ctx.NewStyle().Foreground(lipgloss.Color("212")).Bold(true),
|
||||
FileSize: ctx.NewStyle().Foreground(lipgloss.Color("240")).Width(fileSizeWidth).Align(lipgloss.Right),
|
||||
EmptyDirectory: ctx.NewStyle().Foreground(lipgloss.Color("240")).PaddingLeft(paddingLeft).SetString("Bummer. No Files Found."),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,12 +230,12 @@ func (m Model) readDir(path string, showHidden bool) tea.Cmd {
|
||||
}
|
||||
|
||||
// Init initializes the file picker model.
|
||||
func (m Model) Init() tea.Cmd {
|
||||
func (m Model) Init(tea.Context) tea.Cmd {
|
||||
return m.readDir(m.CurrentDirectory, m.ShowHidden)
|
||||
}
|
||||
|
||||
// Update handles user interactions within the file picker model.
|
||||
func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
||||
func (m Model) Update(_ tea.Context, msg tea.Msg) (Model, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
case readDirMsg:
|
||||
if msg.id != m.id {
|
||||
@@ -363,7 +357,7 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
||||
}
|
||||
|
||||
// View returns the view of the file picker.
|
||||
func (m Model) View() string {
|
||||
func (m Model) View(tea.Context) string {
|
||||
if len(m.files) == 0 {
|
||||
return m.Styles.EmptyDirectory.Height(m.Height).MaxHeight(m.Height).String()
|
||||
}
|
||||
|
||||
@@ -2,13 +2,11 @@ module github.com/charmbracelet/bubbles
|
||||
|
||||
go 1.18
|
||||
|
||||
replace github.com/charmbracelet/bubbletea => ../bubbletea
|
||||
|
||||
require (
|
||||
github.com/MakeNowJust/heredoc v1.0.0
|
||||
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d
|
||||
github.com/atotto/clipboard v0.1.4
|
||||
github.com/charmbracelet/bubbletea v0.25.1-0.20240306212323-3df8b37dba50
|
||||
github.com/charmbracelet/bubbletea v0.26.3-0.20240510203954-a434f25ff7d3
|
||||
github.com/charmbracelet/harmonica v0.2.0
|
||||
github.com/charmbracelet/lipgloss v0.10.1-0.20240510203806-a6dc2ab509a8
|
||||
github.com/dustin/go-humanize v1.0.1
|
||||
@@ -35,5 +33,3 @@ require (
|
||||
golang.org/x/sync v0.7.0 // indirect
|
||||
golang.org/x/sys v0.20.0 // indirect
|
||||
)
|
||||
|
||||
replace github.com/charmbracelet/x/exp/term => ../x/exp/term
|
||||
|
||||
@@ -6,6 +6,8 @@ github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z
|
||||
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
||||
github.com/charmbracelet/bubbletea v0.26.3-0.20240510203954-a434f25ff7d3 h1:Bg0eRBAgsWh84rpAq5X+e52TMAfloxoWeSJkYp9Pyw0=
|
||||
github.com/charmbracelet/bubbletea v0.26.3-0.20240510203954-a434f25ff7d3/go.mod h1:jxN9TKmttdNsUKWSjjQQonHIY4nCuTBNdkDn3/Bpf7A=
|
||||
github.com/charmbracelet/harmonica v0.2.0 h1:8NxJWRWg/bzKqqEaaeFNipOu77YR5t8aSwG4pgaUBiQ=
|
||||
github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao=
|
||||
github.com/charmbracelet/lipgloss v0.10.1-0.20240510203806-a6dc2ab509a8 h1:aOfL0f8fhgqKe+iOIQYAIazSwTO4J0axB5ztPxw5JHY=
|
||||
|
||||
+5
-6
@@ -15,7 +15,6 @@ import (
|
||||
// Note that if a key is disabled (via key.Binding.SetEnabled) it will not be
|
||||
// rendered in the help view, so in theory generated help should self-manage.
|
||||
type KeyMap interface {
|
||||
|
||||
// ShortHelp returns a slice of bindings to be displayed in the short
|
||||
// version of the help. The help bubble will render help in the order in
|
||||
// which the help items are returned here.
|
||||
@@ -58,18 +57,18 @@ type Model struct {
|
||||
}
|
||||
|
||||
// New creates a new help view with some useful defaults.
|
||||
func New() Model {
|
||||
keyStyle := lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{
|
||||
func New(ctx tea.Context) Model {
|
||||
keyStyle := ctx.NewStyle().Foreground(lipgloss.AdaptiveColor{
|
||||
Light: "#909090",
|
||||
Dark: "#626262",
|
||||
})
|
||||
|
||||
descStyle := lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{
|
||||
descStyle := ctx.NewStyle().Foreground(lipgloss.AdaptiveColor{
|
||||
Light: "#B2B2B2",
|
||||
Dark: "#4A4A4A",
|
||||
})
|
||||
|
||||
sepStyle := lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{
|
||||
sepStyle := ctx.NewStyle().Foreground(lipgloss.AdaptiveColor{
|
||||
Light: "#DDDADA",
|
||||
Dark: "#3C3C3C",
|
||||
})
|
||||
@@ -118,7 +117,7 @@ func (m Model) ShortHelpView(bindings []key.Binding) string {
|
||||
|
||||
var b strings.Builder
|
||||
var totalWidth int
|
||||
var separator = m.Styles.ShortSeparator.Inline(true).Render(m.ShortSeparator)
|
||||
separator := m.Styles.ShortSeparator.Inline(true).Render(m.ShortSeparator)
|
||||
|
||||
for i, kb := range bindings {
|
||||
if !kb.Enabled() {
|
||||
|
||||
+7
-7
@@ -32,15 +32,15 @@ type DefaultItemStyles struct {
|
||||
|
||||
// NewDefaultItemStyles returns style definitions for a default item. See
|
||||
// DefaultItemView for when these come into play.
|
||||
func NewDefaultItemStyles() (s DefaultItemStyles) {
|
||||
s.NormalTitle = lipgloss.NewStyle().
|
||||
func NewDefaultItemStyles(ctx tea.Context) (s DefaultItemStyles) {
|
||||
s.NormalTitle = ctx.NewStyle().
|
||||
Foreground(lipgloss.AdaptiveColor{Light: "#1a1a1a", Dark: "#dddddd"}).
|
||||
Padding(0, 0, 0, 2)
|
||||
|
||||
s.NormalDesc = s.NormalTitle.Copy().
|
||||
Foreground(lipgloss.AdaptiveColor{Light: "#A49FA5", Dark: "#777777"})
|
||||
|
||||
s.SelectedTitle = lipgloss.NewStyle().
|
||||
s.SelectedTitle = ctx.NewStyle().
|
||||
Border(lipgloss.NormalBorder(), false, false, false, true).
|
||||
BorderForeground(lipgloss.AdaptiveColor{Light: "#F793FF", Dark: "#AD58B4"}).
|
||||
Foreground(lipgloss.AdaptiveColor{Light: "#EE6FF8", Dark: "#EE6FF8"}).
|
||||
@@ -49,14 +49,14 @@ func NewDefaultItemStyles() (s DefaultItemStyles) {
|
||||
s.SelectedDesc = s.SelectedTitle.Copy().
|
||||
Foreground(lipgloss.AdaptiveColor{Light: "#F793FF", Dark: "#AD58B4"})
|
||||
|
||||
s.DimmedTitle = lipgloss.NewStyle().
|
||||
s.DimmedTitle = ctx.NewStyle().
|
||||
Foreground(lipgloss.AdaptiveColor{Light: "#A49FA5", Dark: "#777777"}).
|
||||
Padding(0, 0, 0, 2)
|
||||
|
||||
s.DimmedDesc = s.DimmedTitle.Copy().
|
||||
Foreground(lipgloss.AdaptiveColor{Light: "#C2B8C2", Dark: "#4D4D4D"})
|
||||
|
||||
s.FilterMatch = lipgloss.NewStyle().Underline(true)
|
||||
s.FilterMatch = ctx.NewStyle().Underline(true)
|
||||
|
||||
return s
|
||||
}
|
||||
@@ -92,10 +92,10 @@ type DefaultDelegate struct {
|
||||
}
|
||||
|
||||
// NewDefaultDelegate creates a new delegate with default styles.
|
||||
func NewDefaultDelegate() DefaultDelegate {
|
||||
func NewDefaultDelegate(ctx tea.Context) DefaultDelegate {
|
||||
return DefaultDelegate{
|
||||
ShowDescription: true,
|
||||
Styles: NewDefaultItemStyles(),
|
||||
Styles: NewDefaultItemStyles(ctx),
|
||||
height: 2,
|
||||
spacing: 1,
|
||||
}
|
||||
|
||||
+20
-17
@@ -49,7 +49,7 @@ type ItemDelegate interface {
|
||||
// loop will pass through here except when the user is setting a filter.
|
||||
// Use this method to perform item-level updates appropriate to this
|
||||
// delegate.
|
||||
Update(msg tea.Msg, m *Model) tea.Cmd
|
||||
Update(ctx tea.Context, msg tea.Msg, m *Model) tea.Cmd
|
||||
}
|
||||
|
||||
type filteredItem struct {
|
||||
@@ -192,24 +192,26 @@ type Model struct {
|
||||
filteredItems filteredItems
|
||||
|
||||
delegate ItemDelegate
|
||||
|
||||
ctx tea.Context
|
||||
}
|
||||
|
||||
// New returns a new model with sensible defaults.
|
||||
func New(items []Item, delegate ItemDelegate, width, height int) Model {
|
||||
styles := DefaultStyles()
|
||||
func New(ctx tea.Context, items []Item, delegate ItemDelegate, width, height int) Model {
|
||||
styles := DefaultStyles(ctx)
|
||||
|
||||
sp := spinner.New()
|
||||
sp := spinner.New(ctx)
|
||||
sp.Spinner = spinner.Line
|
||||
sp.Style = styles.Spinner
|
||||
|
||||
filterInput := textinput.New()
|
||||
filterInput := textinput.New(ctx)
|
||||
filterInput.Prompt = "Filter: "
|
||||
filterInput.PromptStyle = styles.FilterPrompt
|
||||
filterInput.Cursor.Style = styles.FilterCursor
|
||||
filterInput.CharLimit = 64
|
||||
filterInput.Focus()
|
||||
|
||||
p := paginator.New()
|
||||
p := paginator.New(ctx)
|
||||
p.Type = paginator.Dots
|
||||
p.ActiveDot = styles.ActivePaginationDot.String()
|
||||
p.InactiveDot = styles.InactivePaginationDot.String()
|
||||
@@ -236,7 +238,8 @@ func New(items []Item, delegate ItemDelegate, width, height int) Model {
|
||||
items: items,
|
||||
Paginator: p,
|
||||
spinner: sp,
|
||||
Help: help.New(),
|
||||
Help: help.New(ctx),
|
||||
ctx: ctx,
|
||||
}
|
||||
|
||||
m.updatePagination()
|
||||
@@ -768,7 +771,7 @@ func (m *Model) hideStatusMessage() {
|
||||
}
|
||||
|
||||
// Update is the Bubble Tea update loop.
|
||||
func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
||||
func (m Model) Update(ctx tea.Context, msg tea.Msg) (Model, tea.Cmd) {
|
||||
var cmds []tea.Cmd
|
||||
|
||||
switch msg := msg.(type) {
|
||||
@@ -782,7 +785,7 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
||||
return m, nil
|
||||
|
||||
case spinner.TickMsg:
|
||||
newSpinnerModel, cmd := m.spinner.Update(msg)
|
||||
newSpinnerModel, cmd := m.spinner.Update(ctx, msg)
|
||||
m.spinner = newSpinnerModel
|
||||
if m.showSpinner {
|
||||
cmds = append(cmds, cmd)
|
||||
@@ -859,7 +862,7 @@ func (m *Model) handleBrowsing(msg tea.Msg) tea.Cmd {
|
||||
}
|
||||
}
|
||||
|
||||
cmd := m.delegate.Update(msg, m)
|
||||
cmd := m.delegate.Update(m.ctx, msg, m)
|
||||
cmds = append(cmds, cmd)
|
||||
|
||||
// Keep the index in bounds when paginating
|
||||
@@ -909,7 +912,7 @@ func (m *Model) handleFiltering(msg tea.Msg) tea.Cmd {
|
||||
}
|
||||
|
||||
// Update the filter text input component
|
||||
newFilterInputModel, inputCmd := m.FilterInput.Update(msg)
|
||||
newFilterInputModel, inputCmd := m.FilterInput.Update(m.ctx, msg)
|
||||
filterChanged := m.FilterInput.Value() != newFilterInputModel.Value()
|
||||
m.FilterInput = newFilterInputModel
|
||||
cmds = append(cmds, inputCmd)
|
||||
@@ -1003,7 +1006,7 @@ func (m Model) FullHelp() [][]key.Binding {
|
||||
}
|
||||
|
||||
// View renders the component.
|
||||
func (m Model) View() string {
|
||||
func (m Model) View(ctx tea.Context) string {
|
||||
var (
|
||||
sections []string
|
||||
availHeight = m.height
|
||||
@@ -1033,7 +1036,7 @@ func (m Model) View() string {
|
||||
availHeight -= lipgloss.Height(help)
|
||||
}
|
||||
|
||||
content := lipgloss.NewStyle().Height(availHeight).Render(m.populatedView())
|
||||
content := ctx.NewStyle().Height(availHeight).Render(m.populatedView())
|
||||
sections = append(sections, content)
|
||||
|
||||
if m.showPagination {
|
||||
@@ -1062,7 +1065,7 @@ func (m Model) titleView() string {
|
||||
|
||||
// If the filter's showing, draw that. Otherwise draw the title.
|
||||
if m.showFilter && m.filterState == Filtering {
|
||||
view += m.FilterInput.View()
|
||||
view += m.FilterInput.View(m.ctx)
|
||||
} else if m.showTitle {
|
||||
if m.showSpinner && spinnerOnLeft {
|
||||
view += spinnerView + spinnerLeftGap
|
||||
@@ -1147,13 +1150,13 @@ func (m Model) paginationView() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
s := m.Paginator.View()
|
||||
s := m.Paginator.View(m.ctx)
|
||||
|
||||
// If the dot pagination is wider than the width of the window
|
||||
// use the arabic paginator.
|
||||
if ansi.PrintableRuneWidth(s) > m.width {
|
||||
m.Paginator.Type = paginator.Arabic
|
||||
s = m.Styles.ArabicPagination.Render(m.Paginator.View())
|
||||
s = m.Styles.ArabicPagination.Render(m.Paginator.View(m.ctx))
|
||||
}
|
||||
|
||||
style := m.Styles.PaginationStyle
|
||||
@@ -1209,7 +1212,7 @@ func (m Model) helpView() string {
|
||||
}
|
||||
|
||||
func (m Model) spinnerView() string {
|
||||
return m.spinner.View()
|
||||
return m.spinner.View(m.ctx)
|
||||
}
|
||||
|
||||
func filterItems(m Model) tea.Cmd {
|
||||
|
||||
+19
-18
@@ -1,6 +1,7 @@
|
||||
package list
|
||||
|
||||
import (
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
)
|
||||
|
||||
@@ -41,57 +42,57 @@ type Styles struct {
|
||||
|
||||
// DefaultStyles returns a set of default style definitions for this list
|
||||
// component.
|
||||
func DefaultStyles() (s Styles) {
|
||||
func DefaultStyles(ctx tea.Context) (s Styles) {
|
||||
verySubduedColor := lipgloss.AdaptiveColor{Light: "#DDDADA", Dark: "#3C3C3C"}
|
||||
subduedColor := lipgloss.AdaptiveColor{Light: "#9B9B9B", Dark: "#5C5C5C"}
|
||||
|
||||
s.TitleBar = lipgloss.NewStyle().Padding(0, 0, 1, 2)
|
||||
s.TitleBar = ctx.NewStyle().Padding(0, 0, 1, 2)
|
||||
|
||||
s.Title = lipgloss.NewStyle().
|
||||
s.Title = ctx.NewStyle().
|
||||
Background(lipgloss.Color("62")).
|
||||
Foreground(lipgloss.Color("230")).
|
||||
Padding(0, 1)
|
||||
|
||||
s.Spinner = lipgloss.NewStyle().
|
||||
s.Spinner = ctx.NewStyle().
|
||||
Foreground(lipgloss.AdaptiveColor{Light: "#8E8E8E", Dark: "#747373"})
|
||||
|
||||
s.FilterPrompt = lipgloss.NewStyle().
|
||||
s.FilterPrompt = ctx.NewStyle().
|
||||
Foreground(lipgloss.AdaptiveColor{Light: "#04B575", Dark: "#ECFD65"})
|
||||
|
||||
s.FilterCursor = lipgloss.NewStyle().
|
||||
s.FilterCursor = ctx.NewStyle().
|
||||
Foreground(lipgloss.AdaptiveColor{Light: "#EE6FF8", Dark: "#EE6FF8"})
|
||||
|
||||
s.DefaultFilterCharacterMatch = lipgloss.NewStyle().Underline(true)
|
||||
s.DefaultFilterCharacterMatch = ctx.NewStyle().Underline(true)
|
||||
|
||||
s.StatusBar = lipgloss.NewStyle().
|
||||
s.StatusBar = ctx.NewStyle().
|
||||
Foreground(lipgloss.AdaptiveColor{Light: "#A49FA5", Dark: "#777777"}).
|
||||
Padding(0, 0, 1, 2)
|
||||
|
||||
s.StatusEmpty = lipgloss.NewStyle().Foreground(subduedColor)
|
||||
s.StatusEmpty = ctx.NewStyle().Foreground(subduedColor)
|
||||
|
||||
s.StatusBarActiveFilter = lipgloss.NewStyle().
|
||||
s.StatusBarActiveFilter = ctx.NewStyle().
|
||||
Foreground(lipgloss.AdaptiveColor{Light: "#1a1a1a", Dark: "#dddddd"})
|
||||
|
||||
s.StatusBarFilterCount = lipgloss.NewStyle().Foreground(verySubduedColor)
|
||||
s.StatusBarFilterCount = ctx.NewStyle().Foreground(verySubduedColor)
|
||||
|
||||
s.NoItems = lipgloss.NewStyle().
|
||||
s.NoItems = ctx.NewStyle().
|
||||
Foreground(lipgloss.AdaptiveColor{Light: "#909090", Dark: "#626262"})
|
||||
|
||||
s.ArabicPagination = lipgloss.NewStyle().Foreground(subduedColor)
|
||||
s.ArabicPagination = ctx.NewStyle().Foreground(subduedColor)
|
||||
|
||||
s.PaginationStyle = lipgloss.NewStyle().PaddingLeft(2) //nolint:gomnd
|
||||
s.PaginationStyle = ctx.NewStyle().PaddingLeft(2) //nolint:gomnd
|
||||
|
||||
s.HelpStyle = lipgloss.NewStyle().Padding(1, 0, 0, 2)
|
||||
s.HelpStyle = ctx.NewStyle().Padding(1, 0, 0, 2)
|
||||
|
||||
s.ActivePaginationDot = lipgloss.NewStyle().
|
||||
s.ActivePaginationDot = ctx.NewStyle().
|
||||
Foreground(lipgloss.AdaptiveColor{Light: "#847A85", Dark: "#979797"}).
|
||||
SetString(bullet)
|
||||
|
||||
s.InactivePaginationDot = lipgloss.NewStyle().
|
||||
s.InactivePaginationDot = ctx.NewStyle().
|
||||
Foreground(verySubduedColor).
|
||||
SetString(bullet)
|
||||
|
||||
s.DividerDot = lipgloss.NewStyle().
|
||||
s.DividerDot = ctx.NewStyle().
|
||||
Foreground(verySubduedColor).
|
||||
SetString(" " + bullet + " ")
|
||||
|
||||
|
||||
@@ -131,7 +131,7 @@ func (m Model) OnFirstPage() bool {
|
||||
}
|
||||
|
||||
// New creates a new model with defaults.
|
||||
func New() Model {
|
||||
func New(ctx tea.Context) Model {
|
||||
return Model{
|
||||
Type: Arabic,
|
||||
Page: 0,
|
||||
@@ -150,7 +150,7 @@ func New() Model {
|
||||
var NewModel = New
|
||||
|
||||
// Update is the Tea update function which binds keystrokes to pagination.
|
||||
func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
||||
func (m Model) Update(ctx tea.Context, msg tea.Msg) (Model, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
case tea.KeyMsg:
|
||||
switch {
|
||||
@@ -165,7 +165,7 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
||||
}
|
||||
|
||||
// View renders the pagination to a string.
|
||||
func (m Model) View() string {
|
||||
func (m Model) View(tea.Context) string {
|
||||
switch m.Type {
|
||||
case Dots:
|
||||
return m.dotsView()
|
||||
|
||||
+14
-31
@@ -12,7 +12,6 @@ import (
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/lucasb-eyer/go-colorful"
|
||||
"github.com/muesli/reflow/ansi"
|
||||
"github.com/muesli/termenv"
|
||||
)
|
||||
|
||||
// Internal ID management. Used during animating to assure that frame messages
|
||||
@@ -115,13 +114,6 @@ func WithSpringOptions(frequency, damping float64) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithColorProfile sets the color profile to use for the progress bar.
|
||||
func WithColorProfile(p termenv.Profile) Option {
|
||||
return func(m *Model) {
|
||||
m.colorProfile = p
|
||||
}
|
||||
}
|
||||
|
||||
// FrameMsg indicates that an animation step should occur.
|
||||
type FrameMsg struct {
|
||||
id int
|
||||
@@ -169,13 +161,10 @@ type Model struct {
|
||||
// of the progress bar. When false, the width of the gradient will be set
|
||||
// to the full width of the progress bar.
|
||||
scaleRamp bool
|
||||
|
||||
// Color profile for the progress bar.
|
||||
colorProfile termenv.Profile
|
||||
}
|
||||
|
||||
// New returns a model with default values.
|
||||
func New(opts ...Option) Model {
|
||||
func New(ctx tea.Context, opts ...Option) Model {
|
||||
m := Model{
|
||||
id: nextID(),
|
||||
Width: defaultWidth,
|
||||
@@ -185,7 +174,6 @@ func New(opts ...Option) Model {
|
||||
EmptyColor: "#606060",
|
||||
ShowPercentage: true,
|
||||
PercentFormat: " %3.0f%%",
|
||||
colorProfile: termenv.ColorProfile(),
|
||||
}
|
||||
if !m.springCustomized {
|
||||
m.SetSpringOptions(defaultFrequency, defaultDamping)
|
||||
@@ -203,15 +191,15 @@ func New(opts ...Option) Model {
|
||||
var NewModel = New
|
||||
|
||||
// Init exists to satisfy the tea.Model interface.
|
||||
func (m Model) Init() tea.Cmd {
|
||||
return nil
|
||||
func (m Model) Init(tea.Context) (tea.Model, tea.Cmd) {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// Update is used to animate the progress bar during transitions. Use
|
||||
// SetPercent to create the command you'll need to trigger the animation.
|
||||
//
|
||||
// If you're rendering with ViewAs you won't need this.
|
||||
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) {
|
||||
switch msg := msg.(type) {
|
||||
case FrameMsg:
|
||||
if msg.id != m.id || msg.tag != m.tag {
|
||||
@@ -275,15 +263,15 @@ func (m *Model) DecrPercent(v float64) tea.Cmd {
|
||||
|
||||
// View renders an animated progress bar in its current state. To render
|
||||
// a static progress bar based on your own calculations use ViewAs instead.
|
||||
func (m Model) View() string {
|
||||
return m.ViewAs(m.percentShown)
|
||||
func (m Model) View(ctx tea.Context) string {
|
||||
return m.ViewAs(ctx, m.percentShown)
|
||||
}
|
||||
|
||||
// ViewAs renders the progress bar with a given percentage.
|
||||
func (m Model) ViewAs(percent float64) string {
|
||||
func (m Model) ViewAs(ctx tea.Context, percent float64) string {
|
||||
b := strings.Builder{}
|
||||
percentView := m.percentageView(percent)
|
||||
m.barView(&b, percent, ansi.PrintableRuneWidth(percentView))
|
||||
m.barView(ctx, &b, percent, ansi.PrintableRuneWidth(percentView))
|
||||
b.WriteString(percentView)
|
||||
return b.String()
|
||||
}
|
||||
@@ -294,7 +282,7 @@ func (m *Model) nextFrame() tea.Cmd {
|
||||
})
|
||||
}
|
||||
|
||||
func (m Model) barView(b *strings.Builder, percent float64, textWidth int) {
|
||||
func (m Model) barView(ctx tea.Context, b *strings.Builder, percent float64, textWidth int) {
|
||||
var (
|
||||
tw = max(0, m.Width-textWidth) // total width
|
||||
fw = int(math.Round((float64(tw) * percent))) // filled width
|
||||
@@ -317,20 +305,19 @@ func (m Model) barView(b *strings.Builder, percent float64, textWidth int) {
|
||||
p = float64(i) / float64(tw-1)
|
||||
}
|
||||
c := m.rampColorA.BlendLuv(m.rampColorB, p).Hex()
|
||||
b.WriteString(termenv.
|
||||
String(string(m.Full)).
|
||||
Foreground(m.color(c)).
|
||||
String(),
|
||||
b.WriteString(ctx.NewStyle().
|
||||
Foreground(lipgloss.Color(c)).
|
||||
Render(string(m.Full)),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
// Solid fill
|
||||
s := termenv.String(string(m.Full)).Foreground(m.color(m.FullColor)).String()
|
||||
s := ctx.NewStyle().Foreground(lipgloss.Color(m.FullColor)).Render(string(m.Full))
|
||||
b.WriteString(strings.Repeat(s, fw))
|
||||
}
|
||||
|
||||
// Empty fill
|
||||
e := termenv.String(string(m.Empty)).Foreground(m.color(m.EmptyColor)).String()
|
||||
e := ctx.NewStyle().Foreground(lipgloss.Color(m.EmptyColor)).Render(string(m.Empty))
|
||||
n := max(0, tw-fw)
|
||||
b.WriteString(strings.Repeat(e, n))
|
||||
}
|
||||
@@ -358,10 +345,6 @@ func (m *Model) setRamp(colorA, colorB string, scaled bool) {
|
||||
m.rampColorB = b
|
||||
}
|
||||
|
||||
func (m Model) color(c string) termenv.Color {
|
||||
return m.colorProfile.Color(c)
|
||||
}
|
||||
|
||||
func max(a, b int) int {
|
||||
if a > b {
|
||||
return a
|
||||
|
||||
+4
-3
@@ -113,9 +113,10 @@ func (m Model) ID() int {
|
||||
}
|
||||
|
||||
// New returns a model with default values.
|
||||
func New(opts ...Option) Model {
|
||||
func New(ctx tea.Context, opts ...Option) Model {
|
||||
m := Model{
|
||||
Spinner: Line,
|
||||
Style: ctx.NewStyle(),
|
||||
id: nextID(),
|
||||
}
|
||||
|
||||
@@ -139,7 +140,7 @@ type TickMsg struct {
|
||||
}
|
||||
|
||||
// Update is the Tea update function.
|
||||
func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
||||
func (m Model) Update(ctx tea.Context, msg tea.Msg) (Model, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
case TickMsg:
|
||||
// If an ID is set, and the ID doesn't belong to this spinner, reject
|
||||
@@ -168,7 +169,7 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
||||
}
|
||||
|
||||
// View renders the model's view.
|
||||
func (m Model) View() string {
|
||||
func (m Model) View(ctx tea.Context) string {
|
||||
if m.frame >= len(m.Spinner.Frames) {
|
||||
return "(error)"
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ type Model struct {
|
||||
|
||||
// NewWithInterval creates a new stopwatch with the given timeout and tick
|
||||
// interval.
|
||||
func NewWithInterval(interval time.Duration) Model {
|
||||
func NewWithInterval(_ tea.Context, interval time.Duration) Model {
|
||||
return Model{
|
||||
Interval: interval,
|
||||
id: nextID(),
|
||||
@@ -63,8 +63,8 @@ func NewWithInterval(interval time.Duration) Model {
|
||||
}
|
||||
|
||||
// New creates a new stopwatch with 1s interval.
|
||||
func New() Model {
|
||||
return NewWithInterval(time.Second)
|
||||
func New(ctx tea.Context) Model {
|
||||
return NewWithInterval(ctx, time.Second)
|
||||
}
|
||||
|
||||
// ID returns the unique ID of the model.
|
||||
@@ -73,7 +73,7 @@ func (m Model) ID() int {
|
||||
}
|
||||
|
||||
// Init starts the stopwatch.
|
||||
func (m Model) Init() tea.Cmd {
|
||||
func (m Model) Init(tea.Context) tea.Cmd {
|
||||
return m.Start()
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ func (m Model) Running() bool {
|
||||
}
|
||||
|
||||
// Update handles the timer tick.
|
||||
func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
||||
func (m Model) Update(_ tea.Context, msg tea.Msg) (Model, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
case StartStopMsg:
|
||||
if msg.ID != m.id {
|
||||
@@ -141,7 +141,7 @@ func (m Model) Elapsed() time.Duration {
|
||||
}
|
||||
|
||||
// View of the timer component.
|
||||
func (m Model) View() string {
|
||||
func (m Model) View(tea.Context) string {
|
||||
return m.d.String()
|
||||
}
|
||||
|
||||
|
||||
+18
-14
@@ -24,6 +24,8 @@ type Model struct {
|
||||
viewport viewport.Model
|
||||
start int
|
||||
end int
|
||||
|
||||
ctx tea.Context
|
||||
}
|
||||
|
||||
// Row represents one line in the table.
|
||||
@@ -109,11 +111,11 @@ type Styles struct {
|
||||
}
|
||||
|
||||
// DefaultStyles returns a set of default style definitions for this table.
|
||||
func DefaultStyles() Styles {
|
||||
func DefaultStyles(ctx tea.Context) Styles {
|
||||
return Styles{
|
||||
Selected: lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("212")),
|
||||
Header: lipgloss.NewStyle().Bold(true).Padding(0, 1),
|
||||
Cell: lipgloss.NewStyle().Padding(0, 1),
|
||||
Selected: ctx.NewStyle().Bold(true).Foreground(lipgloss.Color("212")),
|
||||
Header: ctx.NewStyle().Bold(true).Padding(0, 1),
|
||||
Cell: ctx.NewStyle().Padding(0, 1),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,13 +131,15 @@ func (m *Model) SetStyles(s Styles) {
|
||||
type Option func(*Model)
|
||||
|
||||
// New creates a new model for the table widget.
|
||||
func New(opts ...Option) Model {
|
||||
func New(ctx tea.Context, opts ...Option) Model {
|
||||
m := Model{
|
||||
cursor: 0,
|
||||
viewport: viewport.New(0, 20),
|
||||
viewport: viewport.New(ctx, 0, 20),
|
||||
|
||||
KeyMap: DefaultKeyMap(),
|
||||
styles: DefaultStyles(),
|
||||
styles: DefaultStyles(ctx),
|
||||
|
||||
ctx: ctx,
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
@@ -204,7 +208,7 @@ func WithKeyMap(km KeyMap) Option {
|
||||
}
|
||||
|
||||
// Update is the Bubble Tea update loop.
|
||||
func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
||||
func (m Model) Update(ctx tea.Context, msg tea.Msg) (Model, tea.Cmd) {
|
||||
if !m.focus {
|
||||
return m, nil
|
||||
}
|
||||
@@ -255,8 +259,8 @@ func (m *Model) Blur() {
|
||||
}
|
||||
|
||||
// View renders the component.
|
||||
func (m Model) View() string {
|
||||
return m.headersView() + "\n" + m.viewport.View()
|
||||
func (m Model) View(ctx tea.Context) string {
|
||||
return m.headersView() + "\n" + m.viewport.View(ctx)
|
||||
}
|
||||
|
||||
// UpdateViewport updates the list content based on the previously defined
|
||||
@@ -409,12 +413,12 @@ func (m *Model) FromValues(value, separator string) {
|
||||
type StyleFunc func(row, col int, value string) lipgloss.Style
|
||||
|
||||
func (m Model) headersView() string {
|
||||
var s = make([]string, 0, len(m.cols))
|
||||
s := make([]string, 0, len(m.cols))
|
||||
for _, col := range m.cols {
|
||||
if col.Width <= 0 {
|
||||
continue
|
||||
}
|
||||
style := lipgloss.NewStyle().Width(col.Width).MaxWidth(col.Width).Inline(true)
|
||||
style := m.ctx.NewStyle().Width(col.Width).MaxWidth(col.Width).Inline(true)
|
||||
renderedCell := style.Render(runewidth.Truncate(col.Title, col.Width, "…"))
|
||||
s = append(s, m.styles.Header.Render(renderedCell))
|
||||
}
|
||||
@@ -422,7 +426,7 @@ func (m Model) headersView() string {
|
||||
}
|
||||
|
||||
func (m *Model) renderRow(r int) string {
|
||||
var s = make([]string, 0, len(m.cols))
|
||||
s := make([]string, 0, len(m.cols))
|
||||
for i, value := range m.rows[r] {
|
||||
if m.cols[i].Width <= 0 {
|
||||
continue
|
||||
@@ -437,7 +441,7 @@ func (m *Model) renderRow(r int) string {
|
||||
cellStyle = m.styles.Cell
|
||||
}
|
||||
|
||||
style := lipgloss.NewStyle().Width(m.cols[i].Width).MaxWidth(m.cols[i].Width).Inline(true)
|
||||
style := m.ctx.NewStyle().Width(m.cols[i].Width).MaxWidth(m.cols[i].Width).Inline(true)
|
||||
renderedCell := cellStyle.Render(style.Render(runewidth.Truncate(value, m.cols[i].Width, "…")))
|
||||
s = append(s, renderedCell)
|
||||
}
|
||||
|
||||
+32
-32
@@ -245,12 +245,12 @@ type Model struct {
|
||||
}
|
||||
|
||||
// New creates a new model with default settings.
|
||||
func New() Model {
|
||||
vp := viewport.New(0, 0)
|
||||
func New(ctx tea.Context) Model {
|
||||
vp := viewport.New(ctx, 0, 0)
|
||||
vp.KeyMap = viewport.KeyMap{}
|
||||
cur := cursor.New()
|
||||
cur := cursor.New(ctx)
|
||||
|
||||
focusedStyle, blurredStyle := DefaultStyles()
|
||||
focusedStyle, blurredStyle := DefaultStyles(ctx)
|
||||
|
||||
m := Model{
|
||||
CharLimit: defaultCharLimit,
|
||||
@@ -283,26 +283,26 @@ func New() Model {
|
||||
|
||||
// DefaultStyles returns the default styles for focused and blurred states for
|
||||
// the textarea.
|
||||
func DefaultStyles() (Style, Style) {
|
||||
func DefaultStyles(ctx tea.Context) (Style, Style) {
|
||||
focused := Style{
|
||||
Base: lipgloss.NewStyle(),
|
||||
CursorLine: lipgloss.NewStyle().Background(lipgloss.AdaptiveColor{Light: "255", Dark: "0"}),
|
||||
CursorLineNumber: lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "240"}),
|
||||
EndOfBuffer: lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "254", Dark: "0"}),
|
||||
LineNumber: lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "249", Dark: "7"}),
|
||||
Placeholder: lipgloss.NewStyle().Foreground(lipgloss.Color("240")),
|
||||
Prompt: lipgloss.NewStyle().Foreground(lipgloss.Color("7")),
|
||||
Text: lipgloss.NewStyle(),
|
||||
Base: ctx.NewStyle(),
|
||||
CursorLine: ctx.NewStyle().Background(lipgloss.AdaptiveColor{Light: "255", Dark: "0"}),
|
||||
CursorLineNumber: ctx.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "240"}),
|
||||
EndOfBuffer: ctx.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "254", Dark: "0"}),
|
||||
LineNumber: ctx.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "249", Dark: "7"}),
|
||||
Placeholder: ctx.NewStyle().Foreground(lipgloss.Color("240")),
|
||||
Prompt: ctx.NewStyle().Foreground(lipgloss.Color("7")),
|
||||
Text: ctx.NewStyle(),
|
||||
}
|
||||
blurred := Style{
|
||||
Base: lipgloss.NewStyle(),
|
||||
CursorLine: lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "245", Dark: "7"}),
|
||||
CursorLineNumber: lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "249", Dark: "7"}),
|
||||
EndOfBuffer: lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "254", Dark: "0"}),
|
||||
LineNumber: lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "249", Dark: "7"}),
|
||||
Placeholder: lipgloss.NewStyle().Foreground(lipgloss.Color("240")),
|
||||
Prompt: lipgloss.NewStyle().Foreground(lipgloss.Color("7")),
|
||||
Text: lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "245", Dark: "7"}),
|
||||
Base: ctx.NewStyle(),
|
||||
CursorLine: ctx.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "245", Dark: "7"}),
|
||||
CursorLineNumber: ctx.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "249", Dark: "7"}),
|
||||
EndOfBuffer: ctx.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "254", Dark: "0"}),
|
||||
LineNumber: ctx.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "249", Dark: "7"}),
|
||||
Placeholder: ctx.NewStyle().Foreground(lipgloss.Color("240")),
|
||||
Prompt: ctx.NewStyle().Foreground(lipgloss.Color("7")),
|
||||
Text: ctx.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "245", Dark: "7"}),
|
||||
}
|
||||
|
||||
return focused, blurred
|
||||
@@ -927,7 +927,7 @@ func (m *Model) SetHeight(h int) {
|
||||
}
|
||||
|
||||
// Update is the Bubble Tea update loop.
|
||||
func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
||||
func (m Model) Update(ctx tea.Context, msg tea.Msg) (Model, tea.Cmd) {
|
||||
if !m.focus {
|
||||
m.Cursor.Blur()
|
||||
return m, nil
|
||||
@@ -1047,12 +1047,12 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
||||
m.Err = msg
|
||||
}
|
||||
|
||||
vp, cmd := m.viewport.Update(msg)
|
||||
vp, cmd := m.viewport.Update(ctx, msg)
|
||||
m.viewport = &vp
|
||||
cmds = append(cmds, cmd)
|
||||
|
||||
newRow, newCol := m.cursorLineNumber(), m.col
|
||||
m.Cursor, cmd = m.Cursor.Update(msg)
|
||||
m.Cursor, cmd = m.Cursor.Update(ctx, msg)
|
||||
if (newRow != oldRow || newCol != oldCol) && m.Cursor.Mode() == cursor.CursorBlink {
|
||||
m.Cursor.Blink = false
|
||||
cmd = m.Cursor.BlinkCmd()
|
||||
@@ -1065,9 +1065,9 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
||||
}
|
||||
|
||||
// View renders the text area in its current state.
|
||||
func (m Model) View() string {
|
||||
func (m Model) View(ctx tea.Context) string {
|
||||
if m.Value() == "" && m.row == 0 && m.col == 0 && m.Placeholder != "" {
|
||||
return m.placeholderView()
|
||||
return m.placeholderView(ctx)
|
||||
}
|
||||
m.Cursor.TextStyle = m.style.CursorLine
|
||||
|
||||
@@ -1126,10 +1126,10 @@ func (m Model) View() string {
|
||||
s.WriteString(style.Render(string(wrappedLine[:lineInfo.ColumnOffset])))
|
||||
if m.col >= len(line) && lineInfo.CharOffset >= m.width {
|
||||
m.Cursor.SetChar(" ")
|
||||
s.WriteString(m.Cursor.View())
|
||||
s.WriteString(m.Cursor.View(ctx))
|
||||
} else {
|
||||
m.Cursor.SetChar(string(wrappedLine[lineInfo.ColumnOffset]))
|
||||
s.WriteString(style.Render(m.Cursor.View()))
|
||||
s.WriteString(style.Render(m.Cursor.View(ctx)))
|
||||
s.WriteString(style.Render(string(wrappedLine[lineInfo.ColumnOffset+1:])))
|
||||
}
|
||||
} else {
|
||||
@@ -1154,7 +1154,7 @@ func (m Model) View() string {
|
||||
}
|
||||
|
||||
m.viewport.SetContent(s.String())
|
||||
return m.style.Base.Render(m.viewport.View())
|
||||
return m.style.Base.Render(m.viewport.View(ctx))
|
||||
}
|
||||
|
||||
func (m Model) getPromptString(displayLine int) (prompt string) {
|
||||
@@ -1171,7 +1171,7 @@ func (m Model) getPromptString(displayLine int) (prompt string) {
|
||||
}
|
||||
|
||||
// placeholderView returns the prompt and placeholder view, if any.
|
||||
func (m Model) placeholderView() string {
|
||||
func (m Model) placeholderView(ctx tea.Context) string {
|
||||
var (
|
||||
s strings.Builder
|
||||
p = rw.Truncate(rw.Truncate(m.Placeholder, m.width, "..."), m.width, "")
|
||||
@@ -1188,7 +1188,7 @@ func (m Model) placeholderView() string {
|
||||
|
||||
m.Cursor.TextStyle = m.style.Placeholder
|
||||
m.Cursor.SetChar(string(p[0]))
|
||||
s.WriteString(m.style.CursorLine.Render(m.Cursor.View()))
|
||||
s.WriteString(m.style.CursorLine.Render(m.Cursor.View(ctx)))
|
||||
|
||||
// The rest of the placeholder text
|
||||
s.WriteString(m.style.CursorLine.Render(style.Render(p[1:] + strings.Repeat(" ", max(0, m.width-uniseg.StringWidth(p))))))
|
||||
@@ -1207,7 +1207,7 @@ func (m Model) placeholderView() string {
|
||||
}
|
||||
|
||||
m.viewport.SetContent(s.String())
|
||||
return m.style.Base.Render(m.viewport.View())
|
||||
return m.style.Base.Render(m.viewport.View(ctx))
|
||||
}
|
||||
|
||||
// Blink returns the blink command for the cursor.
|
||||
|
||||
+17
-14
@@ -155,15 +155,18 @@ type Model struct {
|
||||
}
|
||||
|
||||
// New creates a new model with default settings.
|
||||
func New() Model {
|
||||
func New(ctx tea.Context) Model {
|
||||
return Model{
|
||||
Prompt: "> ",
|
||||
EchoCharacter: '*',
|
||||
CharLimit: 0,
|
||||
PlaceholderStyle: lipgloss.NewStyle().Foreground(lipgloss.Color("240")),
|
||||
PromptStyle: ctx.NewStyle(),
|
||||
TextStyle: ctx.NewStyle(),
|
||||
CursorStyle: ctx.NewStyle(),
|
||||
PlaceholderStyle: ctx.NewStyle().Foreground(lipgloss.Color("240")),
|
||||
ShowSuggestions: false,
|
||||
CompletionStyle: lipgloss.NewStyle().Foreground(lipgloss.Color("240")),
|
||||
Cursor: cursor.New(),
|
||||
CompletionStyle: ctx.NewStyle().Foreground(lipgloss.Color("240")),
|
||||
Cursor: cursor.New(ctx),
|
||||
KeyMap: DefaultKeyMap,
|
||||
|
||||
suggestions: [][]rune{},
|
||||
@@ -549,7 +552,7 @@ func (m Model) echoTransform(v string) string {
|
||||
}
|
||||
|
||||
// Update is the Bubble Tea update loop.
|
||||
func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
||||
func (m Model) Update(ctx tea.Context, msg tea.Msg) (Model, tea.Cmd) {
|
||||
if !m.focus {
|
||||
return m, nil
|
||||
}
|
||||
@@ -636,7 +639,7 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
||||
var cmds []tea.Cmd
|
||||
var cmd tea.Cmd
|
||||
|
||||
m.Cursor, cmd = m.Cursor.Update(msg)
|
||||
m.Cursor, cmd = m.Cursor.Update(ctx, msg)
|
||||
cmds = append(cmds, cmd)
|
||||
|
||||
if oldPos != m.pos && m.Cursor.Mode() == cursor.CursorBlink {
|
||||
@@ -649,10 +652,10 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
||||
}
|
||||
|
||||
// View renders the textinput in its current state.
|
||||
func (m Model) View() string {
|
||||
func (m Model) View(ctx tea.Context) string {
|
||||
// Placeholder text
|
||||
if len(m.value) == 0 && m.Placeholder != "" {
|
||||
return m.placeholderView()
|
||||
return m.placeholderView(ctx)
|
||||
}
|
||||
|
||||
styleText := m.TextStyle.Inline(true).Render
|
||||
@@ -664,7 +667,7 @@ func (m Model) View() string {
|
||||
if pos < len(value) {
|
||||
char := m.echoTransform(string(value[pos]))
|
||||
m.Cursor.SetChar(char)
|
||||
v += m.Cursor.View() // cursor and text under it
|
||||
v += m.Cursor.View(ctx) // cursor and text under it
|
||||
v += styleText(m.echoTransform(string(value[pos+1:]))) // text after cursor
|
||||
v += m.completionView(0) // suggested completion
|
||||
} else {
|
||||
@@ -673,15 +676,15 @@ func (m Model) View() string {
|
||||
if len(value) < len(suggestion) {
|
||||
m.Cursor.TextStyle = m.CompletionStyle
|
||||
m.Cursor.SetChar(m.echoTransform(string(suggestion[pos])))
|
||||
v += m.Cursor.View()
|
||||
v += m.Cursor.View(ctx)
|
||||
v += m.completionView(1)
|
||||
} else {
|
||||
m.Cursor.SetChar(" ")
|
||||
v += m.Cursor.View()
|
||||
v += m.Cursor.View(ctx)
|
||||
}
|
||||
} else {
|
||||
m.Cursor.SetChar(" ")
|
||||
v += m.Cursor.View()
|
||||
v += m.Cursor.View(ctx)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -700,7 +703,7 @@ func (m Model) View() string {
|
||||
}
|
||||
|
||||
// placeholderView returns the prompt and placeholder view, if any.
|
||||
func (m Model) placeholderView() string {
|
||||
func (m Model) placeholderView(ctx tea.Context) string {
|
||||
var (
|
||||
v string
|
||||
p = []rune(m.Placeholder)
|
||||
@@ -709,7 +712,7 @@ func (m Model) placeholderView() string {
|
||||
|
||||
m.Cursor.TextStyle = m.PlaceholderStyle
|
||||
m.Cursor.SetChar(string(p[:1]))
|
||||
v += m.Cursor.View()
|
||||
v += m.Cursor.View(ctx)
|
||||
|
||||
// If the entire placeholder is already set and no padding is needed, finish
|
||||
if m.Width < 1 && len(p) <= 1 {
|
||||
|
||||
+6
-6
@@ -90,7 +90,7 @@ type Model struct {
|
||||
}
|
||||
|
||||
// NewWithInterval creates a new timer with the given timeout and tick interval.
|
||||
func NewWithInterval(timeout, interval time.Duration) Model {
|
||||
func NewWithInterval(_ tea.Context, timeout, interval time.Duration) Model {
|
||||
return Model{
|
||||
Timeout: timeout,
|
||||
Interval: interval,
|
||||
@@ -100,8 +100,8 @@ func NewWithInterval(timeout, interval time.Duration) Model {
|
||||
}
|
||||
|
||||
// New creates a new timer with the given timeout and default 1s interval.
|
||||
func New(timeout time.Duration) Model {
|
||||
return NewWithInterval(timeout, time.Second)
|
||||
func New(ctx tea.Context, timeout time.Duration) Model {
|
||||
return NewWithInterval(ctx, timeout, time.Second)
|
||||
}
|
||||
|
||||
// ID returns the model's identifier. This can be used to determine if messages
|
||||
@@ -125,12 +125,12 @@ func (m Model) Timedout() bool {
|
||||
}
|
||||
|
||||
// Init starts the timer.
|
||||
func (m Model) Init() tea.Cmd {
|
||||
func (m Model) Init(tea.Context) tea.Cmd {
|
||||
return m.tick()
|
||||
}
|
||||
|
||||
// Update handles the timer tick.
|
||||
func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
||||
func (m Model) Update(_ tea.Context, msg tea.Msg) (Model, tea.Cmd) {
|
||||
switch msg := msg.(type) {
|
||||
case StartStopMsg:
|
||||
if msg.ID != 0 && msg.ID != m.id {
|
||||
@@ -151,7 +151,7 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
||||
}
|
||||
|
||||
// View of the timer component.
|
||||
func (m Model) View() string {
|
||||
func (m Model) View(tea.Context) string {
|
||||
return m.Timeout.String()
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
|
||||
// New returns a new model with the given width and height as well as default
|
||||
// key mappings.
|
||||
func New(width, height int) (m Model) {
|
||||
func New(ctx tea.Context, width, height int) (m Model) {
|
||||
m.Width = width
|
||||
m.Height = height
|
||||
m.setInitialValues()
|
||||
@@ -64,7 +64,7 @@ func (m *Model) setInitialValues() {
|
||||
}
|
||||
|
||||
// Init exists to satisfy the tea.Model interface for composability purposes.
|
||||
func (m Model) Init() tea.Cmd {
|
||||
func (m Model) Init(tea.Context) tea.Cmd {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -276,7 +276,7 @@ func ViewUp(m Model, lines []string) tea.Cmd {
|
||||
}
|
||||
|
||||
// Update handles standard message-based viewport updates.
|
||||
func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
||||
func (m Model) Update(_ tea.Context, msg tea.Msg) (Model, tea.Cmd) {
|
||||
var cmd tea.Cmd
|
||||
m, cmd = m.updateAsModel(msg)
|
||||
return m, cmd
|
||||
@@ -354,7 +354,7 @@ func (m Model) updateAsModel(msg tea.Msg) (Model, tea.Cmd) {
|
||||
}
|
||||
|
||||
// View renders the viewport into a string.
|
||||
func (m Model) View() string {
|
||||
func (m Model) View(ctx tea.Context) string {
|
||||
if m.HighPerformanceRendering {
|
||||
// Just send newlines since we're going to be rendering the actual
|
||||
// content separately. We still need to send something that equals the
|
||||
@@ -372,7 +372,7 @@ func (m Model) View() string {
|
||||
}
|
||||
contentWidth := w - m.Style.GetHorizontalFrameSize()
|
||||
contentHeight := h - m.Style.GetVerticalFrameSize()
|
||||
contents := lipgloss.NewStyle().
|
||||
contents := ctx.NewStyle().
|
||||
Width(contentWidth). // pad to width.
|
||||
Height(contentHeight). // pad to height.
|
||||
MaxHeight(contentHeight). // truncate height if taller.
|
||||
|
||||
Reference in New Issue
Block a user