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,17 +58,20 @@ 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 EchoMode EchoMode
BackgroundColor string EchoCharacter rune
PlaceholderColor string
CursorColor string // Styles.
EchoMode EchoMode PromptStyle lipgloss.Style
EchoCharacter rune 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.
@ -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,56 +557,44 @@ 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.
func (m Model) placeholderView() string { 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 termenv.String(v). return m.CursorStyle.Inline(true).Reverse(true).Render(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.