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