diff --git a/pkg/tui/tui.go b/pkg/tui/tui.go index 2912bdd..fadb90d 100644 --- a/pkg/tui/tui.go +++ b/pkg/tui/tui.go @@ -11,10 +11,12 @@ import ( "context" "fmt" "strings" + "time" cmdutil "git.mlow.ca/mlow/lmcli/pkg/cmd/util" "git.mlow.ca/mlow/lmcli/pkg/lmcli" models "git.mlow.ca/mlow/lmcli/pkg/lmcli/model" + "github.com/charmbracelet/bubbles/spinner" "github.com/charmbracelet/bubbles/textarea" "github.com/charmbracelet/bubbles/viewport" tea "github.com/charmbracelet/bubbletea" @@ -53,6 +55,7 @@ type model struct { // ui elements content viewport.Model input textarea.Model + spinner spinner.Model } type message struct { @@ -97,6 +100,7 @@ var ( func (m model) Init() tea.Cmd { return tea.Batch( textarea.Blink, + m.spinner.Tick, m.loadConversation(m.convShortname), m.waitForChunk(), m.waitForReply(), @@ -218,22 +222,28 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.err = error(msg) } - if len(cmds) > 0 { - return m, tea.Batch(cmds...) - } var cmd tea.Cmd + m.spinner, cmd = m.spinner.Update(msg) + if cmd != nil { + cmds = append(cmds, cmd) + } + + inputCaptured := false m.input, cmd = m.input.Update(msg) if cmd != nil { - return m, cmd + inputCaptured = true + cmds = append(cmds, cmd) } - m.content, cmd = m.content.Update(msg) - if cmd != nil { - return m, cmd + if !inputCaptured { + m.content, cmd = m.content.Update(msg) + if cmd != nil { + cmds = append(cmds, cmd) + } } - return m, cmd + return m, tea.Batch(cmds...) } func (m model) View() string { @@ -343,9 +353,14 @@ func (m *model) footerView() string { saving = segmentStyle.Copy().Bold(true).Foreground(lipgloss.Color("1")).Render("❌💾") } + status := m.status + if m.waitingForReply { + status += m.spinner.View() + } + leftSegments := []string{ saving, - segmentStyle.Render(m.status), + segmentStyle.Render(status), } rightSegments := []string{ segmentStyle.Render(fmt.Sprintf("Model: %s", *m.ctx.Config.Defaults.Model)), @@ -391,7 +406,19 @@ func initialModel(ctx *lmcli.Context, convShortname string) model { m.input.SetHeight(4) m.input.Focus() - m.updateContent() + m.spinner = spinner.New(spinner.WithSpinner( + spinner.Spinner{ + Frames: []string{ + ". ", + ".. ", + "...", + ".. ", + ". ", + " ", + }, + FPS: time.Second / 3, + }, + )) m.waitingForReply = false m.status = "Press ctrl+s to send" @@ -453,7 +480,7 @@ func (m *model) handleInputKey(msg tea.KeyMsg) tea.Cmd { m.content.GotoBottom() m.waitingForReply = true - m.status = "Waiting for response, press ctrl+c to cancel..." + m.status = "Press ctrl+c to cancel" return m.promptLLM() } return nil