mirror of
https://github.com/Maks1mS/bubbles.git
synced 2024-12-24 14:44:38 +03:00
textarea: support dynamic prompts
The dynamic prompt can be different on every line. See for example: [![asciicast](https://asciinema.org/a/iFBPBwoDZOzcoRJOgfmPk8ObH.svg)](https://asciinema.org/a/iFBPBwoDZOzcoRJOgfmPk8ObH)
This commit is contained in:
parent
c099d31570
commit
09e1f00349
@ -135,6 +135,11 @@ type Model struct {
|
|||||||
// General settings.
|
// General settings.
|
||||||
|
|
||||||
// Prompt is printed at the beginning of each line.
|
// Prompt is printed at the beginning of each line.
|
||||||
|
//
|
||||||
|
// When changing the value of Prompt after the model has been
|
||||||
|
// initialized, ensure that SetWidth() gets called afterwards.
|
||||||
|
//
|
||||||
|
// See also SetPromptFunc().
|
||||||
Prompt string
|
Prompt string
|
||||||
|
|
||||||
// Placeholder is the text displayed when the user
|
// Placeholder is the text displayed when the user
|
||||||
@ -168,6 +173,13 @@ type Model struct {
|
|||||||
// accept. If 0 or less, there's no limit.
|
// accept. If 0 or less, there's no limit.
|
||||||
CharLimit int
|
CharLimit int
|
||||||
|
|
||||||
|
// If promptFunc is set, it replaces Prompt as a generator for
|
||||||
|
// prompt strings at the beginning of each line.
|
||||||
|
promptFunc func(line int) string
|
||||||
|
|
||||||
|
// promptWidth is the width of the prompt.
|
||||||
|
promptWidth int
|
||||||
|
|
||||||
// width is the maximum number of characters that can be displayed at once.
|
// width is the maximum number of characters that can be displayed at once.
|
||||||
// If 0 or less this setting is ignored.
|
// If 0 or less this setting is ignored.
|
||||||
width int
|
width int
|
||||||
@ -785,10 +797,26 @@ func (m *Model) SetWidth(w int) {
|
|||||||
// Account for base style borders and padding.
|
// Account for base style borders and padding.
|
||||||
inputWidth -= m.style.Base.GetHorizontalFrameSize()
|
inputWidth -= m.style.Base.GetHorizontalFrameSize()
|
||||||
|
|
||||||
inputWidth -= rw.StringWidth(m.Prompt)
|
if m.promptFunc == nil {
|
||||||
|
m.promptWidth = rw.StringWidth(m.Prompt)
|
||||||
|
}
|
||||||
|
|
||||||
|
inputWidth -= m.promptWidth
|
||||||
m.width = clamp(inputWidth, minWidth, maxWidth)
|
m.width = clamp(inputWidth, minWidth, maxWidth)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetPromptFunc supersedes the Prompt field and sets a dynamic prompt
|
||||||
|
// instead.
|
||||||
|
// If the function returns a prompt that is shorter than the
|
||||||
|
// specified promptWidth, it will be padded to the left.
|
||||||
|
// If it returns a prompt that is longer, display artifacts
|
||||||
|
// may occur; the caller is responsible for computing an adequate
|
||||||
|
// promptWidth.
|
||||||
|
func (m *Model) SetPromptFunc(promptWidth int, fn func(lineIdx int) string) {
|
||||||
|
m.promptFunc = fn
|
||||||
|
m.promptWidth = promptWidth
|
||||||
|
}
|
||||||
|
|
||||||
// Height returns the current height of the textarea.
|
// Height returns the current height of the textarea.
|
||||||
func (m Model) Height() int {
|
func (m Model) Height() int {
|
||||||
return m.height
|
return m.height
|
||||||
@ -950,6 +978,7 @@ func (m Model) View() string {
|
|||||||
|
|
||||||
var newLines int
|
var newLines int
|
||||||
|
|
||||||
|
displayLine := 0
|
||||||
for l, line := range m.value {
|
for l, line := range m.value {
|
||||||
wrappedLines := wrap(line, m.width)
|
wrappedLines := wrap(line, m.width)
|
||||||
|
|
||||||
@ -960,7 +989,10 @@ func (m Model) View() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for wl, wrappedLine := range wrappedLines {
|
for wl, wrappedLine := range wrappedLines {
|
||||||
s.WriteString(style.Render(m.style.Prompt.Render(m.Prompt)))
|
prompt := m.getPromptString(displayLine)
|
||||||
|
prompt = m.style.Prompt.Render(prompt)
|
||||||
|
s.WriteString(style.Render(prompt))
|
||||||
|
displayLine++
|
||||||
|
|
||||||
if m.ShowLineNumbers {
|
if m.ShowLineNumbers {
|
||||||
if wl == 0 {
|
if wl == 0 {
|
||||||
@ -1009,7 +1041,10 @@ func (m Model) View() string {
|
|||||||
// Always show at least `m.Height` lines at all times.
|
// Always show at least `m.Height` lines at all times.
|
||||||
// To do this we can simply pad out a few extra new lines in the view.
|
// To do this we can simply pad out a few extra new lines in the view.
|
||||||
for i := 0; i < m.height; i++ {
|
for i := 0; i < m.height; i++ {
|
||||||
s.WriteString(m.style.Prompt.Render(m.Prompt))
|
prompt := m.getPromptString(displayLine)
|
||||||
|
prompt = m.style.Prompt.Render(prompt)
|
||||||
|
s.WriteString(prompt)
|
||||||
|
displayLine++
|
||||||
|
|
||||||
if m.ShowLineNumbers {
|
if m.ShowLineNumbers {
|
||||||
lineNumber := m.style.EndOfBuffer.Render((fmt.Sprintf(m.lineNumberFormat, string(m.EndOfBufferCharacter))))
|
lineNumber := m.style.EndOfBuffer.Render((fmt.Sprintf(m.lineNumberFormat, string(m.EndOfBufferCharacter))))
|
||||||
@ -1022,6 +1057,19 @@ func (m Model) View() string {
|
|||||||
return m.style.Base.Render(m.viewport.View())
|
return m.style.Base.Render(m.viewport.View())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m Model) getPromptString(displayLine int) (prompt string) {
|
||||||
|
prompt = m.Prompt
|
||||||
|
if m.promptFunc == nil {
|
||||||
|
return prompt
|
||||||
|
}
|
||||||
|
prompt = m.promptFunc(displayLine)
|
||||||
|
pl := rw.StringWidth(prompt)
|
||||||
|
if pl < m.promptWidth {
|
||||||
|
prompt = fmt.Sprintf("%*s%s", m.promptWidth-pl, "", prompt)
|
||||||
|
}
|
||||||
|
return prompt
|
||||||
|
}
|
||||||
|
|
||||||
// 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 (
|
||||||
@ -1030,7 +1078,8 @@ func (m Model) placeholderView() string {
|
|||||||
style = m.style.Placeholder.Inline(true)
|
style = m.style.Placeholder.Inline(true)
|
||||||
)
|
)
|
||||||
|
|
||||||
prompt := m.style.Prompt.Render(m.Prompt)
|
prompt := m.getPromptString(0)
|
||||||
|
prompt = m.style.Prompt.Render(prompt)
|
||||||
s.WriteString(m.style.CursorLine.Render(prompt))
|
s.WriteString(m.style.CursorLine.Render(prompt))
|
||||||
|
|
||||||
if m.ShowLineNumbers {
|
if m.ShowLineNumbers {
|
||||||
@ -1047,6 +1096,8 @@ func (m Model) placeholderView() string {
|
|||||||
// The rest of the new lines
|
// The rest of the new lines
|
||||||
for i := 1; i < m.height; i++ {
|
for i := 1; i < m.height; i++ {
|
||||||
s.WriteRune('\n')
|
s.WriteRune('\n')
|
||||||
|
prompt := m.getPromptString(i)
|
||||||
|
prompt = m.style.Prompt.Render(prompt)
|
||||||
s.WriteString(prompt)
|
s.WriteString(prompt)
|
||||||
|
|
||||||
if m.ShowLineNumbers {
|
if m.ShowLineNumbers {
|
||||||
|
Loading…
Reference in New Issue
Block a user