TextInput now uses Lip Gloss for styling

This commit is contained in:
Christian Rocha 2021-04-12 18:16:28 -04:00
parent 7242bbe8dc
commit ddd48d9ab7

View File

@ -8,15 +8,12 @@ import (
"github.com/atotto/clipboard" "github.com/atotto/clipboard"
tea "github.com/charmbracelet/bubbletea" tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
rw "github.com/mattn/go-runewidth" rw "github.com/mattn/go-runewidth"
"github.com/muesli/termenv"
) )
const defaultBlinkSpeed = time.Millisecond * 530 const defaultBlinkSpeed = time.Millisecond * 530
// color is a helper for returning colors.
var color func(s string) termenv.Color = termenv.ColorProfile().Color
// blinkMsg and blinkCanceled are used to manage cursor blinking. // blinkMsg and blinkCanceled are used to manage cursor blinking.
type blinkMsg struct{} type blinkMsg struct{}
type blinkCanceled struct{} type blinkCanceled struct{}
@ -61,18 +58,21 @@ const (
type Model struct { type Model struct {
Err error Err error
// General settings // General settings.
Prompt string Prompt string
Placeholder string Placeholder string
Cursor string Cursor string
BlinkSpeed time.Duration BlinkSpeed time.Duration
TextColor string
BackgroundColor string
PlaceholderColor string
CursorColor string
EchoMode EchoMode EchoMode EchoMode
EchoCharacter rune EchoCharacter rune
// Styles.
PromptStyle lipgloss.Style
TextStyle lipgloss.Style
BackgroundStyle lipgloss.Style
PlaceholderStyle lipgloss.Style
CursorStyle lipgloss.Style
// CharLimit is the maximum amount of characters this input element will // CharLimit is the maximum amount of characters this input element will
// accept. If 0 or less, there's no limit. // accept. If 0 or less, there's no limit.
CharLimit int CharLimit int
@ -111,13 +111,10 @@ type Model struct {
func NewModel() Model { func NewModel() Model {
return Model{ return Model{
Prompt: "> ", Prompt: "> ",
Placeholder: "",
BlinkSpeed: defaultBlinkSpeed, BlinkSpeed: defaultBlinkSpeed,
TextColor: "",
PlaceholderColor: "240",
CursorColor: "",
EchoCharacter: '*', EchoCharacter: '*',
CharLimit: 0, CharLimit: 0,
PlaceholderStyle: lipgloss.NewStyle().Foreground(lipgloss.Color("240")),
value: nil, value: nil,
focus: false, focus: false,
@ -291,26 +288,6 @@ func (m *Model) handleOverflow() {
} }
} }
// colorText colorizes a given string according to the TextColor value of the
// model.
func (m *Model) colorText(s string) string {
return termenv.
String(s).
Foreground(color(m.TextColor)).
Background(color(m.BackgroundColor)).
String()
}
// colorPlaceholder colorizes a given string according to the TextColor value
// of the model.
func (m *Model) colorPlaceholder(s string) string {
return termenv.
String(s).
Foreground(color(m.PlaceholderColor)).
Background(color(m.BackgroundColor)).
String()
}
// deleteWordLeft deletes the word left to the cursor. Returns whether or not // deleteWordLeft deletes the word left to the cursor. Returns whether or not
// the cursor blink should be reset. // the cursor blink should be reset.
func (m *Model) deleteWordLeft() bool { func (m *Model) deleteWordLeft() bool {
@ -564,13 +541,15 @@ func (m Model) View() string {
return m.placeholderView() return m.placeholderView()
} }
styleText := m.TextStyle.Inline(true).Render
value := m.value[m.offset:m.offsetRight] value := m.value[m.offset:m.offsetRight]
pos := max(0, m.pos-m.offset) pos := max(0, m.pos-m.offset)
v := m.colorText(m.echoTransform(string(value[:pos]))) v := styleText(m.echoTransform(string(value[:pos])))
if pos < len(value) { if pos < len(value) {
v += m.cursorView(m.echoTransform(string(value[pos]))) // cursor and text under it v += m.cursorView(m.echoTransform(string(value[pos]))) // cursor and text under it
v += m.colorText(m.echoTransform(string(value[pos+1:]))) // text after cursor v += styleText(m.echoTransform(string(value[pos+1:]))) // text after cursor
} else { } else {
v += m.cursorView(" ") v += m.cursorView(" ")
} }
@ -578,18 +557,15 @@ func (m Model) View() string {
// If a max width and background color were set fill the empty spaces with // If a max width and background color were set fill the empty spaces with
// the background color. // the background color.
valWidth := rw.StringWidth(string(value)) valWidth := rw.StringWidth(string(value))
if m.Width > 0 && len(m.BackgroundColor) > 0 && valWidth <= m.Width { if m.Width > 0 && valWidth <= m.Width {
padding := max(0, m.Width-valWidth) padding := max(0, m.Width-valWidth)
if valWidth+padding <= m.Width && pos < len(value) { if valWidth+padding <= m.Width && pos < len(value) {
padding++ padding++
} }
v += strings.Repeat( v += styleText(strings.Repeat(" ", padding))
termenv.String(" ").Background(color(m.BackgroundColor)).String(),
padding,
)
} }
return m.Prompt + v return m.PromptStyle.Render(m.Prompt) + v
} }
// placeholderView returns the prompt and placeholder view, if any. // placeholderView returns the prompt and placeholder view, if any.
@ -597,37 +573,28 @@ func (m Model) placeholderView() string {
var ( var (
v string v string
p = m.Placeholder p = m.Placeholder
style = m.PlaceholderStyle.Inline(true).Render
) )
// Cursor // Cursor
if m.blink && m.PlaceholderColor != "" { if m.blink {
v += m.cursorView(m.colorPlaceholder(p[:1])) v += m.cursorView(style(p[:1]))
} else { } else {
v += m.cursorView(p[:1]) v += m.cursorView(p[:1])
} }
// The rest of the placeholder text // The rest of the placeholder text
v += m.colorPlaceholder(p[1:]) v += style(p[1:])
return m.Prompt + v return m.PromptStyle.Render(m.Prompt) + v
} }
// cursorView styles the cursor. // cursorView styles the cursor.
func (m Model) cursorView(v string) string { func (m Model) cursorView(v string) string {
if m.blink { if m.blink {
if m.TextColor != "" || m.BackgroundColor != "" { return m.TextStyle.Render(v)
return termenv.String(v).
Foreground(color(m.TextColor)).
Background(color(m.BackgroundColor)).
String()
} }
return v return m.CursorStyle.Inline(true).Reverse(true).Render(v)
}
return termenv.String(v).
Foreground(color(m.CursorColor)).
Background(color(m.BackgroundColor)).
Reverse().
String()
} }
// blinkCmd is an internal command used to manage cursor blinking. // blinkCmd is an internal command used to manage cursor blinking.