diff --git a/pkg/tui/tui.go b/pkg/tui/tui.go index aa545f3..815bd92 100644 --- a/pkg/tui/tui.go +++ b/pkg/tui/tui.go @@ -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 {