@@ -127,7 +127,6 @@ type Style struct {
127127 LineNumber lipgloss.Style
128128 Placeholder lipgloss.Style
129129 Prompt lipgloss.Style
130- NextPrompt lipgloss.Style
131130 Text lipgloss.Style
132131}
133132
@@ -136,15 +135,28 @@ type Model struct {
136135 Err error
137136
138137 // General settings.
139- Prompt string
140- Placeholder string
141- ShowLineNumbers bool
138+
139+ // Prompt is printed at the beginning of each line.
140+ //
141+ // When changing the value of Prompt after the model has been
142+ // initialized, ensure that SetWidth() gets called afterwards.
143+ //
144+ // See also SetPromptFunc().
145+ Prompt string
146+
147+ // Placeholder is the text displayed when the user
148+ // hasn't entered anything yet.
149+ Placeholder string
150+
151+ // ShowLineNumbers, if enabled, causes line numbers to be printed
152+ // after the prompt.
153+ ShowLineNumbers bool
154+
155+ // EndOfBufferCharacter is displayed at the end of the input.
142156 EndOfBufferCharacter rune
143- KeyMap KeyMap
144157
145- // NextPrompt, if set, is used for all lines
146- // except the first.
147- NextPrompt string
158+ // KeyMap encodes the keybindings recognized by the widget.
159+ KeyMap KeyMap
148160
149161 // Styling. FocusedStyle and BlurredStyle are used to style the textarea in
150162 // focused and blurred states.
@@ -163,6 +175,13 @@ type Model struct {
163175 // accept. If 0 or less, there's no limit.
164176 CharLimit int
165177
178+ // If promptFunc is set, it replaces Prompt as a generator for
179+ // prompt strings at the beginning of each line.
180+ promptFunc func (line int ) string
181+
182+ // promptWidth is the width of the prompt.
183+ promptWidth int
184+
166185 // width is the maximum number of characters that can be displayed at once.
167186 // If 0 or less this setting is ignored.
168187 width int
@@ -245,7 +264,6 @@ func DefaultStyles() (Style, Style) {
245264 LineNumber : lipgloss .NewStyle ().Foreground (lipgloss.AdaptiveColor {Light : "249" , Dark : "7" }),
246265 Placeholder : lipgloss .NewStyle ().Foreground (lipgloss .Color ("240" )),
247266 Prompt : lipgloss .NewStyle ().Foreground (lipgloss .Color ("7" )),
248- NextPrompt : lipgloss .NewStyle ().Foreground (lipgloss .Color ("7" )),
249267 Text : lipgloss .NewStyle (),
250268 }
251269 blurred := Style {
@@ -256,7 +274,6 @@ func DefaultStyles() (Style, Style) {
256274 LineNumber : lipgloss .NewStyle ().Foreground (lipgloss.AdaptiveColor {Light : "249" , Dark : "7" }),
257275 Placeholder : lipgloss .NewStyle ().Foreground (lipgloss .Color ("240" )),
258276 Prompt : lipgloss .NewStyle ().Foreground (lipgloss .Color ("7" )),
259- NextPrompt : lipgloss .NewStyle ().Foreground (lipgloss .Color ("7" )),
260277 Text : lipgloss .NewStyle ().Foreground (lipgloss.AdaptiveColor {Light : "245" , Dark : "7" }),
261278 }
262279
@@ -791,10 +808,26 @@ func (m *Model) SetWidth(w int) {
791808 // Account for base style borders and padding.
792809 inputWidth -= m .style .Base .GetHorizontalFrameSize ()
793810
794- inputWidth -= max (rw .StringWidth (m .Prompt ), rw .StringWidth (m .NextPrompt ))
811+ if m .promptFunc == nil {
812+ m .promptWidth = rw .StringWidth (m .Prompt )
813+ }
814+
815+ inputWidth -= m .promptWidth
795816 m .width = clamp (inputWidth , minWidth , maxWidth )
796817}
797818
819+ // SetPromptFunc supersedes the Prompt field and sets a dynamic prompt
820+ // instead.
821+ // If the function returns a prompt that is shorter than the
822+ // specified promptWidth, it will be padded to the left.
823+ // If it returns a prompt that is longer, display artifacts
824+ // may occur; the caller is responsible for computing an adequate
825+ // promptWidth.
826+ func (m * Model ) SetPromptFunc (promptWidth int , fn func (lineIdx int ) string ) {
827+ m .promptFunc = fn
828+ m .promptWidth = promptWidth
829+ }
830+
798831// Height returns the current height of the textarea.
799832func (m Model ) Height () int {
800833 return m .height
@@ -929,11 +962,17 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
929962 case key .Matches (msg , m .KeyMap .ToggleOverwriteMode ):
930963 m .overwrite = ! m .overwrite
931964 default :
932- if m .CharLimit > 0 && rw .StringWidth (m .Value ())+ len (msg .Runes ) >= m .CharLimit {
933- break
934- }
935- for _ , r := range msg .Runes {
936- m .InsertRune (r )
965+ if ! m .overwrite {
966+ if m .CharLimit > 0 && rw .StringWidth (m .Value ())+ len (msg .Runes ) >= m .CharLimit {
967+ break
968+ }
969+ for _ , r := range msg .Runes {
970+ m .InsertRune (r )
971+ }
972+ } else {
973+ for _ , r := range msg .Runes {
974+ m .overwriteRune (r )
975+ }
937976 }
938977 }
939978
@@ -974,11 +1013,7 @@ func (m Model) View() string {
9741013
9751014 var newLines int
9761015
977- prompt , nextPrompt := m .getPromptStrings ()
978- prompt = m .style .Prompt .Render (prompt )
979- nextPrompt = m .style .NextPrompt .Render (nextPrompt )
980-
981- firstDisplayLine := true
1016+ displayLine := 0
9821017 for l , line := range m .value {
9831018 wrappedLines := wrap (line , m .width )
9841019
@@ -989,12 +1024,10 @@ func (m Model) View() string {
9891024 }
9901025
9911026 for wl , wrappedLine := range wrappedLines {
992- selectedPrompt := nextPrompt
993- if firstDisplayLine {
994- selectedPrompt = prompt
995- firstDisplayLine = false
996- }
997- s .WriteString (style .Render (selectedPrompt ))
1027+ prompt := m .getPromptString (displayLine )
1028+ prompt = m .style .Prompt .Render (prompt )
1029+ s .WriteString (style .Render (prompt ))
1030+ displayLine ++
9981031
9991032 if m .ShowLineNumbers {
10001033 if wl == 0 {
@@ -1043,7 +1076,10 @@ func (m Model) View() string {
10431076 // Always show at least `m.Height` lines at all times.
10441077 // To do this we can simply pad out a few extra new lines in the view.
10451078 for i := 0 ; i < m .height ; i ++ {
1046- s .WriteString (nextPrompt )
1079+ prompt := m .getPromptString (displayLine )
1080+ prompt = m .style .Prompt .Render (prompt )
1081+ s .WriteString (prompt )
1082+ displayLine ++
10471083
10481084 if m .ShowLineNumbers {
10491085 lineNumber := m .style .EndOfBuffer .Render ((fmt .Sprintf (m .lineNumberFormat , string (m .EndOfBufferCharacter ))))
@@ -1056,20 +1092,17 @@ func (m Model) View() string {
10561092 return m .style .Base .Render (m .viewport .View ())
10571093}
10581094
1059- func (m Model ) getPromptStrings ( ) (prompt , nextPrompt string ) {
1095+ func (m Model ) getPromptString ( displayLine int ) (prompt string ) {
10601096 prompt = m .Prompt
1061- nextPrompt = m .NextPrompt
1062- if nextPrompt == "" {
1063- return prompt , prompt
1097+ if m .promptFunc == nil {
1098+ return prompt
10641099 }
1100+ prompt = m .promptFunc (displayLine )
10651101 pl := rw .StringWidth (prompt )
1066- npl := rw .StringWidth (nextPrompt )
1067- if pl > npl {
1068- nextPrompt = fmt .Sprintf ("%*s" , pl - npl , "" ) + nextPrompt
1069- } else if npl > pl {
1070- prompt = fmt .Sprintf ("%*s" , npl - pl , "" ) + prompt
1102+ if pl < m .promptWidth {
1103+ prompt = fmt .Sprintf ("%*s%s" , m .promptWidth - pl , "" , prompt )
10711104 }
1072- return prompt , nextPrompt
1105+ return prompt
10731106}
10741107
10751108// placeholderView returns the prompt and placeholder view, if any.
@@ -1080,8 +1113,7 @@ func (m Model) placeholderView() string {
10801113 style = m .style .Placeholder .Inline (true )
10811114 )
10821115
1083- prompt , nextPrompt := m .getPromptStrings ()
1084-
1116+ prompt := m .getPromptString (0 )
10851117 prompt = m .style .Prompt .Render (prompt )
10861118 s .WriteString (m .style .CursorLine .Render (prompt ))
10871119
@@ -1097,10 +1129,11 @@ func (m Model) placeholderView() string {
10971129 s .WriteString (m .style .CursorLine .Render (style .Render (p [1 :] + strings .Repeat (" " , max (0 , m .width - rw .StringWidth (p ))))))
10981130
10991131 // The rest of the new lines
1100- nextPrompt = m .style .NextPrompt .Render (nextPrompt )
11011132 for i := 1 ; i < m .height ; i ++ {
11021133 s .WriteRune ('\n' )
1103- s .WriteString (nextPrompt )
1134+ prompt := m .getPromptString (i )
1135+ prompt = m .style .Prompt .Render (prompt )
1136+ s .WriteString (prompt )
11041137
11051138 if m .ShowLineNumbers {
11061139 eob := m .style .EndOfBuffer .Render ((fmt .Sprintf (m .lineNumberFormat , string (m .EndOfBufferCharacter ))))
0 commit comments