tui: removed confirm before send, dynamic footer

footer now rendered based on model data, instead of being set to a fixed
string
This commit is contained in:
Matt Low 2024-03-12 17:10:40 +00:00
parent 758f74aba5
commit d8c8262890
1 changed files with 37 additions and 43 deletions

View File

@ -30,13 +30,12 @@ type model struct {
err error
// ui state
isWaiting bool
confirmPrompt bool
isWaiting bool
status string // a general status message
// ui elements
content viewport.Model
input textarea.Model
footer string
}
type message struct {
@ -103,7 +102,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.messages[i].Content += chunk
default:
m.messages = append(m.messages, models.Message{
Role: models.MessageRoleAssistant,
Role: models.MessageRoleAssistant,
Content: chunk,
})
}
@ -112,7 +111,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
cmd = waitForChunk(m.replyChan) // wait for the next chunk
case msgResponseEnd:
m.isWaiting = false
m.footer = "Press Ctrl+S to send, Ctrl+C or 'q' to quit"
m.status = "Press ctrl+s to send"
}
if cmd != nil {
@ -147,9 +146,6 @@ func initialModel(ctx *lmcli.Context, convShortname string) model {
convShortname: convShortname,
replyChan: make(chan string),
isWaiting: false,
confirmPrompt: false,
}
m.content = viewport.New(0, 0)
@ -163,7 +159,8 @@ func initialModel(ctx *lmcli.Context, convShortname string) model {
m.updateContent()
m.footer = "Press Ctrl+S to send, Ctrl+C or 'q' to quit"
m.isWaiting = false
m.status = "Press ctrl+s to send"
return m
}
@ -173,38 +170,25 @@ func (m *model) handleKeyMsg(msg tea.KeyMsg) tea.Cmd {
case "ctrl+c", "q":
return tea.Quit
case "ctrl+s":
if !m.isWaiting && !m.confirmPrompt {
m.confirmPrompt = true
m.footer = "Press 'y' to confirm sending the message, 'n' to cancel"
return nil
}
case "y":
if m.confirmPrompt {
userInput := m.input.Value()
m.input.SetValue("")
m.messages = append(m.messages, models.Message{
Role: models.MessageRoleUser,
Content: userInput,
})
m.updateContent()
m.content.GotoBottom()
m.isWaiting = true
m.confirmPrompt = false
m.footer = "Waiting for response... (Press 's' to stop)"
return m.promptLLM()
}
case "n":
if m.confirmPrompt {
m.confirmPrompt = false
m.footer = "Press Ctrl+S to send, Ctrl+C or 'q' to quit"
userInput := strings.TrimSpace(m.input.Value())
if strings.TrimSpace(userInput) == "" {
return nil
}
m.input.SetValue("")
m.messages = append(m.messages, models.Message{
Role: models.MessageRoleUser,
Content: userInput,
})
m.updateContent()
m.content.GotoBottom()
m.isWaiting = true
m.status = "Waiting for response... (Press 's' to stop)"
return m.promptLLM()
case "s":
if m.isWaiting {
m.isWaiting = false
m.footer = "Response generation stopped. Press Ctrl+S to send, Ctrl+C or 'q' to quit"
return nil
}
// TOOD: stop response
break
}
return nil
@ -284,7 +268,7 @@ func (m *model) updateContent() {
style = assistantStyle
}
sb.WriteString(fmt.Sprintf("%s:\n\n", style.Render(string(message.Role))))
sb.WriteString(fmt.Sprintf("%s:\n\n", style.Render(string(message.Role.FriendlyRole()))))
highlighted, _ := m.ctx.Chroma.HighlightS(message.Content)
sb.WriteString(contentStyle.Width(m.content.Width - 5).Render(highlighted))
@ -306,10 +290,20 @@ func (m model) inputView() string {
}
func (m model) footerView() string {
return footerStyle.
Width(m.content.Width).
Align(lipgloss.Center).
Render(m.footer)
left := m.status
right := fmt.Sprintf("Model: %s", *m.ctx.Config.Defaults.Model)
totalWidth := lipgloss.Width(left + right)
var padding string
if m.content.Width-totalWidth > 0 {
padding = strings.Repeat(" ", m.content.Width-totalWidth)
} else {
padding = ""
}
footer := lipgloss.JoinHorizontal(lipgloss.Center, left, padding, right)
return footerStyle.Width(m.content.Width).Render(footer)
}
func Launch(ctx *lmcli.Context, convShortname string) error {