Skip to content

Commit 12271df

Browse files
committed
chore(textarea): nest focused and blurred styles in a parent struct
1 parent 9f3b67a commit 12271df

File tree

2 files changed

+62
-55
lines changed

2 files changed

+62
-55
lines changed

textarea/textarea.go

+54-47
Original file line numberDiff line numberDiff line change
@@ -117,14 +117,22 @@ type LineInfo struct {
117117
CharOffset int
118118
}
119119

120-
// Style that will be applied to the text area.
120+
// Styles are the styles for the textarea, separated into focused and blurred
121+
// states. The appropriate styles will be chosen based on the focus state of
122+
// the textarea.
123+
type Styles struct {
124+
Focused StyleState
125+
Blurred StyleState
126+
}
127+
128+
// StyleState that will be applied to the text area.
121129
//
122-
// Style can be applied to focused and unfocused states to change the styles
130+
// StyleState can be applied to focused and unfocused states to change the styles
123131
// depending on the focus state.
124132
//
125133
// For an introduction to styling with Lip Gloss see:
126134
// https://github.com/charmbracelet/lipgloss
127-
type Style struct {
135+
type StyleState struct {
128136
Base lipgloss.Style
129137
CursorLine lipgloss.Style
130138
CursorLineNumber lipgloss.Style
@@ -135,34 +143,34 @@ type Style struct {
135143
Text lipgloss.Style
136144
}
137145

138-
func (s Style) computedCursorLine() lipgloss.Style {
146+
func (s StyleState) computedCursorLine() lipgloss.Style {
139147
return s.CursorLine.Inherit(s.Base).Inline(true)
140148
}
141149

142-
func (s Style) computedCursorLineNumber() lipgloss.Style {
150+
func (s StyleState) computedCursorLineNumber() lipgloss.Style {
143151
return s.CursorLineNumber.
144152
Inherit(s.CursorLine).
145153
Inherit(s.Base).
146154
Inline(true)
147155
}
148156

149-
func (s Style) computedEndOfBuffer() lipgloss.Style {
157+
func (s StyleState) computedEndOfBuffer() lipgloss.Style {
150158
return s.EndOfBuffer.Inherit(s.Base).Inline(true)
151159
}
152160

153-
func (s Style) computedLineNumber() lipgloss.Style {
161+
func (s StyleState) computedLineNumber() lipgloss.Style {
154162
return s.LineNumber.Inherit(s.Base).Inline(true)
155163
}
156164

157-
func (s Style) computedPlaceholder() lipgloss.Style {
165+
func (s StyleState) computedPlaceholder() lipgloss.Style {
158166
return s.Placeholder.Inherit(s.Base).Inline(true)
159167
}
160168

161-
func (s Style) computedPrompt() lipgloss.Style {
169+
func (s StyleState) computedPrompt() lipgloss.Style {
162170
return s.Prompt.Inherit(s.Base).Inline(true)
163171
}
164172

165-
func (s Style) computedText() lipgloss.Style {
173+
func (s StyleState) computedText() lipgloss.Style {
166174
return s.Text.Inherit(s.Base).Inline(true)
167175
}
168176

@@ -210,13 +218,13 @@ type Model struct {
210218

211219
// Styling. FocusedStyle and BlurredStyle are used to style the textarea in
212220
// focused and blurred states.
213-
FocusedStyle Style
214-
BlurredStyle Style
215-
// style is the current styling to use.
221+
Styles Styles
222+
223+
// activeStyle is the current styling to use.
216224
// It is used to abstract the differences in focus state when styling the
217-
// model, since we can simply assign the set of styles to this variable
225+
// model, since we can simply assign the set of activeStyle to this variable
218226
// when switching focus states.
219-
style *Style
227+
activeStyle *StyleState
220228

221229
// Cursor is the text area cursor.
222230
Cursor cursor.Model
@@ -280,16 +288,15 @@ func New() Model {
280288
vp.KeyMap = viewport.KeyMap{}
281289
cur := cursor.New()
282290

283-
focusedStyle, blurredStyle := DefaultStyles(true)
291+
styles := DefaultStyles(true)
284292

285293
m := Model{
286294
CharLimit: defaultCharLimit,
287295
MaxHeight: defaultMaxHeight,
288296
MaxWidth: defaultMaxWidth,
289297
Prompt: lipgloss.ThickBorder().Left + " ",
290-
style: &blurredStyle,
291-
FocusedStyle: focusedStyle,
292-
BlurredStyle: blurredStyle,
298+
Styles: styles,
299+
activeStyle: &styles.Blurred,
293300
cache: memoization.NewMemoCache[line, [][]rune](defaultMaxHeight),
294301
EndOfBufferCharacter: ' ',
295302
ShowLineNumbers: true,
@@ -312,10 +319,11 @@ func New() Model {
312319

313320
// DefaultStyles returns the default styles for focused and blurred states for
314321
// the textarea.
315-
func DefaultStyles(isDark bool) (Style, Style) {
322+
func DefaultStyles(isDark bool) Styles {
316323
lightDark := lipgloss.LightDark(isDark)
317324

318-
focused := Style{
325+
var s Styles
326+
s.Focused = StyleState{
319327
Base: lipgloss.NewStyle(),
320328
CursorLine: lipgloss.NewStyle().Background(lightDark("255", "0")),
321329
CursorLineNumber: lipgloss.NewStyle().Foreground(lightDark("240", "240")),
@@ -325,7 +333,7 @@ func DefaultStyles(isDark bool) (Style, Style) {
325333
Prompt: lipgloss.NewStyle().Foreground(lipgloss.Color("7")),
326334
Text: lipgloss.NewStyle(),
327335
}
328-
blurred := Style{
336+
s.Blurred = StyleState{
329337
Base: lipgloss.NewStyle(),
330338
CursorLine: lipgloss.NewStyle().Foreground(lightDark("245", "7")),
331339
CursorLineNumber: lipgloss.NewStyle().Foreground(lightDark("249", "7")),
@@ -335,8 +343,7 @@ func DefaultStyles(isDark bool) (Style, Style) {
335343
Prompt: lipgloss.NewStyle().Foreground(lipgloss.Color("7")),
336344
Text: lipgloss.NewStyle().Foreground(lightDark("245", "7")),
337345
}
338-
339-
return focused, blurred
346+
return s
340347
}
341348

342349
// SetValue sets the value of the text input.
@@ -578,15 +585,15 @@ func (m Model) Focused() bool {
578585
// receive keyboard input and the cursor will be hidden.
579586
func (m *Model) Focus() tea.Cmd {
580587
m.focus = true
581-
m.style = &m.FocusedStyle
588+
m.activeStyle = &m.Styles.Focused
582589
return m.Cursor.Focus()
583590
}
584591

585592
// Blur removes the focus state on the model. When the model is blurred it can
586593
// not receive keyboard input and the cursor will be hidden.
587594
func (m *Model) Blur() {
588595
m.focus = false
589-
m.style = &m.BlurredStyle
596+
m.activeStyle = &m.Styles.Blurred
590597
m.Cursor.Blur()
591598
}
592599

@@ -899,7 +906,7 @@ func (m *Model) SetWidth(w int) {
899906
}
900907

901908
// Add base style borders and padding to reserved outer width.
902-
reservedOuter := m.style.Base.GetHorizontalFrameSize()
909+
reservedOuter := m.activeStyle.Base.GetHorizontalFrameSize()
903910

904911
// Add prompt width to reserved inner width.
905912
reservedInner := m.promptWidth
@@ -1098,7 +1105,7 @@ func (m Model) View() string {
10981105
if m.Value() == "" && m.row == 0 && m.col == 0 && m.Placeholder != "" {
10991106
return m.placeholderView()
11001107
}
1101-
m.Cursor.TextStyle = m.style.computedCursorLine()
1108+
m.Cursor.TextStyle = m.activeStyle.computedCursorLine()
11021109

11031110
var (
11041111
s strings.Builder
@@ -1113,33 +1120,33 @@ func (m Model) View() string {
11131120
wrappedLines := m.memoizedWrap(line, m.width)
11141121

11151122
if m.row == l {
1116-
style = m.style.computedCursorLine()
1123+
style = m.activeStyle.computedCursorLine()
11171124
} else {
1118-
style = m.style.computedText()
1125+
style = m.activeStyle.computedText()
11191126
}
11201127

11211128
for wl, wrappedLine := range wrappedLines {
11221129
prompt := m.getPromptString(displayLine)
1123-
prompt = m.style.computedPrompt().Render(prompt)
1130+
prompt = m.activeStyle.computedPrompt().Render(prompt)
11241131
s.WriteString(style.Render(prompt))
11251132
displayLine++
11261133

11271134
var ln string
11281135
if m.ShowLineNumbers { //nolint:nestif
11291136
if wl == 0 {
11301137
if m.row == l {
1131-
ln = style.Render(m.style.computedCursorLineNumber().Render(m.formatLineNumber(l + 1)))
1138+
ln = style.Render(m.activeStyle.computedCursorLineNumber().Render(m.formatLineNumber(l + 1)))
11321139
s.WriteString(ln)
11331140
} else {
1134-
ln = style.Render(m.style.computedLineNumber().Render(m.formatLineNumber(l + 1)))
1141+
ln = style.Render(m.activeStyle.computedLineNumber().Render(m.formatLineNumber(l + 1)))
11351142
s.WriteString(ln)
11361143
}
11371144
} else {
11381145
if m.row == l {
1139-
ln = style.Render(m.style.computedCursorLineNumber().Render(m.formatLineNumber(" ")))
1146+
ln = style.Render(m.activeStyle.computedCursorLineNumber().Render(m.formatLineNumber(" ")))
11401147
s.WriteString(ln)
11411148
} else {
1142-
ln = style.Render(m.style.computedLineNumber().Render(m.formatLineNumber(" ")))
1149+
ln = style.Render(m.activeStyle.computedLineNumber().Render(m.formatLineNumber(" ")))
11431150
s.WriteString(ln)
11441151
}
11451152
}
@@ -1187,20 +1194,20 @@ func (m Model) View() string {
11871194
// To do this we can simply pad out a few extra new lines in the view.
11881195
for i := 0; i < m.height; i++ {
11891196
prompt := m.getPromptString(displayLine)
1190-
prompt = m.style.computedPrompt().Render(prompt)
1197+
prompt = m.activeStyle.computedPrompt().Render(prompt)
11911198
s.WriteString(prompt)
11921199
displayLine++
11931200

11941201
// Write end of buffer content
11951202
leftGutter := string(m.EndOfBufferCharacter)
11961203
rightGapWidth := m.Width() - lipgloss.Width(leftGutter) + widestLineNumber
11971204
rightGap := strings.Repeat(" ", max(0, rightGapWidth))
1198-
s.WriteString(m.style.computedEndOfBuffer().Render(leftGutter + rightGap))
1205+
s.WriteString(m.activeStyle.computedEndOfBuffer().Render(leftGutter + rightGap))
11991206
s.WriteRune('\n')
12001207
}
12011208

12021209
m.viewport.SetContent(s.String())
1203-
return m.style.Base.Render(m.viewport.View())
1210+
return m.activeStyle.Base.Render(m.viewport.View())
12041211
}
12051212

12061213
// formatLineNumber formats the line number for display dynamically based on
@@ -1230,7 +1237,7 @@ func (m Model) placeholderView() string {
12301237
var (
12311238
s strings.Builder
12321239
p = m.Placeholder
1233-
style = m.style.computedPlaceholder()
1240+
style = m.activeStyle.computedPlaceholder()
12341241
)
12351242

12361243
// word wrap lines
@@ -1241,16 +1248,16 @@ func (m Model) placeholderView() string {
12411248
plines := strings.Split(strings.TrimSpace(pwrap), "\n")
12421249

12431250
for i := 0; i < m.height; i++ {
1244-
lineStyle := m.style.computedPlaceholder()
1245-
lineNumberStyle := m.style.computedLineNumber()
1251+
lineStyle := m.activeStyle.computedPlaceholder()
1252+
lineNumberStyle := m.activeStyle.computedLineNumber()
12461253
if len(plines) > i {
1247-
lineStyle = m.style.computedCursorLine()
1248-
lineNumberStyle = m.style.computedCursorLineNumber()
1254+
lineStyle = m.activeStyle.computedCursorLine()
1255+
lineNumberStyle = m.activeStyle.computedCursorLineNumber()
12491256
}
12501257

12511258
// render prompt
12521259
prompt := m.getPromptString(i)
1253-
prompt = m.style.computedPrompt().Render(prompt)
1260+
prompt = m.activeStyle.computedPrompt().Render(prompt)
12541261
s.WriteString(lineStyle.Render(prompt))
12551262

12561263
// when show line numbers enabled:
@@ -1274,7 +1281,7 @@ func (m Model) placeholderView() string {
12741281
// first line
12751282
case i == 0:
12761283
// first character of first line as cursor with character
1277-
m.Cursor.TextStyle = m.style.computedPlaceholder()
1284+
m.Cursor.TextStyle = m.activeStyle.computedPlaceholder()
12781285
m.Cursor.SetChar(string(plines[0][0]))
12791286
s.WriteString(lineStyle.Render(m.Cursor.View()))
12801287

@@ -1288,7 +1295,7 @@ func (m Model) placeholderView() string {
12881295
}
12891296
default:
12901297
// end of line buffer character
1291-
eob := m.style.computedEndOfBuffer().Render(string(m.EndOfBufferCharacter))
1298+
eob := m.activeStyle.computedEndOfBuffer().Render(string(m.EndOfBufferCharacter))
12921299
s.WriteString(eob)
12931300
}
12941301

@@ -1297,7 +1304,7 @@ func (m Model) placeholderView() string {
12971304
}
12981305

12991306
m.viewport.SetContent(s.String())
1300-
return m.style.Base.Render(m.viewport.View())
1307+
return m.activeStyle.Base.Render(m.viewport.View())
13011308
}
13021309

13031310
// Blink returns the blink command for the cursor.

textarea/textarea_test.go

+8-8
Original file line numberDiff line numberDiff line change
@@ -1032,7 +1032,7 @@ func TestView(t *testing.T) {
10321032
{
10331033
name: "set width with style",
10341034
modelFunc: func(m Model) Model {
1035-
m.FocusedStyle.Base = lipgloss.NewStyle().Border(lipgloss.NormalBorder())
1035+
m.Styles.Focused.Base = lipgloss.NewStyle().Border(lipgloss.NormalBorder())
10361036
m.Focus()
10371037

10381038
m.SetWidth(12)
@@ -1060,7 +1060,7 @@ func TestView(t *testing.T) {
10601060
{
10611061
name: "set width with style max width minus one",
10621062
modelFunc: func(m Model) Model {
1063-
m.FocusedStyle.Base = lipgloss.NewStyle().Border(lipgloss.NormalBorder())
1063+
m.Styles.Focused.Base = lipgloss.NewStyle().Border(lipgloss.NormalBorder())
10641064
m.Focus()
10651065

10661066
m.SetWidth(12)
@@ -1088,7 +1088,7 @@ func TestView(t *testing.T) {
10881088
{
10891089
name: "set width with style max width",
10901090
modelFunc: func(m Model) Model {
1091-
m.FocusedStyle.Base = lipgloss.NewStyle().Border(lipgloss.NormalBorder())
1091+
m.Styles.Focused.Base = lipgloss.NewStyle().Border(lipgloss.NormalBorder())
10921092
m.Focus()
10931093

10941094
m.SetWidth(12)
@@ -1116,7 +1116,7 @@ func TestView(t *testing.T) {
11161116
{
11171117
name: "set width with style max width plus one",
11181118
modelFunc: func(m Model) Model {
1119-
m.FocusedStyle.Base = lipgloss.NewStyle().Border(lipgloss.NormalBorder())
1119+
m.Styles.Focused.Base = lipgloss.NewStyle().Border(lipgloss.NormalBorder())
11201120
m.Focus()
11211121

11221122
m.SetWidth(12)
@@ -1144,7 +1144,7 @@ func TestView(t *testing.T) {
11441144
{
11451145
name: "set width without line numbers with style",
11461146
modelFunc: func(m Model) Model {
1147-
m.FocusedStyle.Base = lipgloss.NewStyle().Border(lipgloss.NormalBorder())
1147+
m.Styles.Focused.Base = lipgloss.NewStyle().Border(lipgloss.NormalBorder())
11481148
m.Focus()
11491149

11501150
m.ShowLineNumbers = false
@@ -1173,7 +1173,7 @@ func TestView(t *testing.T) {
11731173
{
11741174
name: "set width without line numbers with style max width minus one",
11751175
modelFunc: func(m Model) Model {
1176-
m.FocusedStyle.Base = lipgloss.NewStyle().Border(lipgloss.NormalBorder())
1176+
m.Styles.Focused.Base = lipgloss.NewStyle().Border(lipgloss.NormalBorder())
11771177
m.Focus()
11781178

11791179
m.ShowLineNumbers = false
@@ -1202,7 +1202,7 @@ func TestView(t *testing.T) {
12021202
{
12031203
name: "set width without line numbers with style max width",
12041204
modelFunc: func(m Model) Model {
1205-
m.FocusedStyle.Base = lipgloss.NewStyle().Border(lipgloss.NormalBorder())
1205+
m.Styles.Focused.Base = lipgloss.NewStyle().Border(lipgloss.NormalBorder())
12061206
m.Focus()
12071207

12081208
m.ShowLineNumbers = false
@@ -1231,7 +1231,7 @@ func TestView(t *testing.T) {
12311231
{
12321232
name: "set width without line numbers with style max width plus one",
12331233
modelFunc: func(m Model) Model {
1234-
m.FocusedStyle.Base = lipgloss.NewStyle().Border(lipgloss.NormalBorder())
1234+
m.Styles.Focused.Base = lipgloss.NewStyle().Border(lipgloss.NormalBorder())
12351235
m.Focus()
12361236

12371237
m.ShowLineNumbers = false

0 commit comments

Comments
 (0)