Skip to content

Commit

Permalink
textarea: support secondary prompts
Browse files Browse the repository at this point in the history
The secondary prompt is displayed on every line after the first.
See for example:
[![asciicast](https://asciinema.org/a/iFBPBwoDZOzcoRJOgfmPk8ObH.svg)](https://asciinema.org/a/iFBPBwoDZOzcoRJOgfmPk8ObH)
  • Loading branch information
knz committed Aug 14, 2022
1 parent 93e3c75 commit b3002ea
Showing 1 changed file with 41 additions and 5 deletions.
46 changes: 41 additions & 5 deletions textarea/textarea.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ type Style struct {
LineNumber lipgloss.Style
Placeholder lipgloss.Style
Prompt lipgloss.Style
NextPrompt lipgloss.Style
Text lipgloss.Style
}

Expand All @@ -123,6 +124,10 @@ type Model struct {
EndOfBufferCharacter rune
KeyMap KeyMap

// NextPrompt, if set, is used for all lines
// except the first.
NextPrompt string

// Styling. FocusedStyle and BlurredStyle are used to style the textarea in
// focused and blurred states.
FocusedStyle Style
Expand Down Expand Up @@ -219,6 +224,7 @@ func DefaultStyles() (Style, Style) {
LineNumber: lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "249", Dark: "7"}),
Placeholder: lipgloss.NewStyle().Foreground(lipgloss.Color("240")),
Prompt: lipgloss.NewStyle().Foreground(lipgloss.Color("7")),
NextPrompt: lipgloss.NewStyle().Foreground(lipgloss.Color("7")),
Text: lipgloss.NewStyle(),
}
blurred := Style{
Expand All @@ -229,6 +235,7 @@ func DefaultStyles() (Style, Style) {
LineNumber: lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "249", Dark: "7"}),
Placeholder: lipgloss.NewStyle().Foreground(lipgloss.Color("240")),
Prompt: lipgloss.NewStyle().Foreground(lipgloss.Color("7")),
NextPrompt: lipgloss.NewStyle().Foreground(lipgloss.Color("7")),
Text: lipgloss.NewStyle().Foreground(lipgloss.AdaptiveColor{Light: "245", Dark: "7"}),
}

Expand Down Expand Up @@ -682,7 +689,7 @@ func (m *Model) SetWidth(w int) {
// Account for base style borders and padding.
inputWidth -= m.style.Base.GetHorizontalFrameSize()

inputWidth -= rw.StringWidth(m.Prompt)
inputWidth -= max(rw.StringWidth(m.Prompt), rw.StringWidth(m.NextPrompt))
m.width = clamp(inputWidth, minWidth, maxWidth)
}

Expand Down Expand Up @@ -848,6 +855,11 @@ func (m Model) View() string {

var newLines int

prompt, nextPrompt := m.getPromptStrings()
prompt = m.style.Prompt.Render(prompt)
nextPrompt = m.style.NextPrompt.Render(nextPrompt)

firstDisplayLine := true
for l, line := range m.value {
wrappedLines := wrap(line, m.width)

Expand All @@ -858,7 +870,12 @@ func (m Model) View() string {
}

for wl, wrappedLine := range wrappedLines {
s.WriteString(style.Render(m.style.Prompt.Render(m.Prompt)))
selectedPrompt := nextPrompt
if firstDisplayLine {
selectedPrompt = prompt
firstDisplayLine = false
}
s.WriteString(style.Render(selectedPrompt))

if m.ShowLineNumbers {
if wl == 0 {
Expand Down Expand Up @@ -907,7 +924,7 @@ func (m Model) View() string {
// 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.
for i := 0; i < m.height; i++ {
s.WriteString(m.style.Prompt.Render(m.Prompt))
s.WriteString(nextPrompt)

if m.ShowLineNumbers {
lineNumber := m.style.EndOfBuffer.Render((fmt.Sprintf(m.lineNumberFormat, string(m.EndOfBufferCharacter))))
Expand All @@ -920,6 +937,22 @@ func (m Model) View() string {
return m.style.Base.Render(m.viewport.View())
}

func (m Model) getPromptStrings() (prompt, nextPrompt string) {
prompt = m.Prompt
nextPrompt = m.NextPrompt
if nextPrompt == "" {
return prompt, prompt
}
pl := rw.StringWidth(prompt)
npl := rw.StringWidth(nextPrompt)
if pl > npl {
nextPrompt = fmt.Sprintf("%*s", pl-npl, "") + nextPrompt
} else if npl > pl {
prompt = fmt.Sprintf("%*s", npl-pl, "") + prompt
}
return prompt, nextPrompt
}

// placeholderView returns the prompt and placeholder view, if any.
func (m Model) placeholderView() string {
var (
Expand All @@ -928,7 +961,9 @@ func (m Model) placeholderView() string {
style = m.style.Placeholder.Inline(true)
)

prompt := m.style.Prompt.Render(m.Prompt)
prompt, nextPrompt := m.getPromptStrings()

prompt = m.style.Prompt.Render(prompt)
s.WriteString(m.style.CursorLine.Render(prompt))

if m.ShowLineNumbers {
Expand All @@ -943,9 +978,10 @@ func (m Model) placeholderView() string {
s.WriteString(m.style.CursorLine.Render(style.Render(p[1:] + strings.Repeat(" ", max(0, m.width-rw.StringWidth(p))))))

// The rest of the new lines
nextPrompt = m.style.NextPrompt.Render(nextPrompt)
for i := 1; i < m.height; i++ {
s.WriteRune('\n')
s.WriteString(prompt)
s.WriteString(nextPrompt)

if m.ShowLineNumbers {
eob := m.style.EndOfBuffer.Render((fmt.Sprintf(m.lineNumberFormat, string(m.EndOfBufferCharacter))))
Expand Down

0 comments on commit b3002ea

Please sign in to comment.