diff --git a/pkg/tui/conversation.go b/pkg/tui/chat.go similarity index 97% rename from pkg/tui/conversation.go rename to pkg/tui/chat.go index 22faba5..d6eeddf 100644 --- a/pkg/tui/conversation.go +++ b/pkg/tui/chat.go @@ -14,6 +14,20 @@ import ( "gopkg.in/yaml.v2" ) +type focusState int + +const ( + focusInput focusState = iota + focusMessages +) + +type editorTarget int + +const ( + input editorTarget = iota + selectedMessage +) + // custom tea.Msg types type ( // sent on each chunk received from LLM @@ -63,10 +77,10 @@ var ( footerStyle = lipgloss.NewStyle() ) -func (m *model) handleConversationInput(msg tea.KeyMsg) tea.Cmd { +func (m *model) handleChatInput(msg tea.KeyMsg) tea.Cmd { switch msg.String() { case "esc": - m.state = stateConversationList + m.state = stateConversations return m.loadConversations() case "ctrl+p": m.persistence = !m.persistence @@ -81,15 +95,15 @@ func (m *model) handleConversationInput(msg tea.KeyMsg) tea.Cmd { default: switch m.focus { case focusInput: - return m.handleInputKey(msg) + return m.handleChatInputKey(msg) case focusMessages: - return m.handleMessagesKey(msg) + return m.handleChatMessagesKey(msg) } } return nil } -func (m *model) handleConversationUpdate(msg tea.Msg) []tea.Cmd { +func (m *model) handleChatUpdate(msg tea.Msg) []tea.Cmd { var cmds []tea.Cmd switch msg := msg.(type) { case msgTempfileEditorClosed: @@ -248,7 +262,7 @@ func (m *model) handleConversationUpdate(msg tea.Msg) []tea.Cmd { return cmds } -func (m *model) handleMessagesKey(msg tea.KeyMsg) tea.Cmd { +func (m *model) handleChatMessagesKey(msg tea.KeyMsg) tea.Cmd { switch msg.String() { case "tab": m.focus = focusInput @@ -287,7 +301,7 @@ func (m *model) handleMessagesKey(msg tea.KeyMsg) tea.Cmd { return nil } -func (m *model) handleInputKey(msg tea.KeyMsg) tea.Cmd { +func (m *model) handleChatInputKey(msg tea.KeyMsg) tea.Cmd { switch msg.String() { case "esc": m.focus = focusMessages diff --git a/pkg/tui/conversation_list.go b/pkg/tui/conversations.go similarity index 92% rename from pkg/tui/conversation_list.go rename to pkg/tui/conversations.go index efcb299..51adecb 100644 --- a/pkg/tui/conversation_list.go +++ b/pkg/tui/conversations.go @@ -17,10 +17,10 @@ type ( msgConversationsLoaded []models.Conversation ) -func (m *model) handleConversationListInput(msg tea.KeyMsg) tea.Cmd { +func (m *model) handleConversationsInput(msg tea.KeyMsg) tea.Cmd { switch msg.String() { case "enter": - m.state = stateConversation + m.state = stateChat m.updateContent() // load selected conversation and switch state case "n": @@ -37,12 +37,12 @@ func (m *model) handleConversationListInput(msg tea.KeyMsg) tea.Cmd { return nil } -func (m *model) handleConversationListUpdate(msg tea.Msg) []tea.Cmd { +func (m *model) handleConversationsUpdate(msg tea.Msg) []tea.Cmd { var cmds []tea.Cmd switch msg := msg.(type) { case msgConversationsLoaded: m.conversations = msg - m.content.SetContent(m.conversationListView()) + m.content.SetContent(m.renderConversationList()) } var cmd tea.Cmd @@ -73,7 +73,7 @@ func (m *model) loadConversations() tea.Cmd { } } -func (m *model) loadConversationLastReplies(conversations []models.Conversation) tea.Cmd { +func (m *model) loadConversationLastestReplies(conversations []models.Conversation) tea.Cmd { return func() tea.Msg { //lastMessage, err := m.ctx.Store.LastMessage(&conversation) return nil @@ -83,7 +83,7 @@ func (m *model) loadConversationLastReplies(conversations []models.Conversation) func (m *model) setConversations(conversations []models.Conversation) { } -func (m *model) conversationListView() string { +func (m *model) renderConversationList() string { sb := &strings.Builder{} type AgeGroup struct { name string diff --git a/pkg/tui/tui.go b/pkg/tui/tui.go index 50b1c47..d947480 100644 --- a/pkg/tui/tui.go +++ b/pkg/tui/tui.go @@ -24,28 +24,15 @@ import ( type appState int const ( - stateConversation = iota - stateConversationList + stateChat = iota + stateConversations //stateModelSelect // stateOptions? //stateHelp ) -type focusState int - -const ( - focusInput focusState = iota - focusMessages -) - -type editorTarget int - -const ( - input editorTarget = iota - selectedMessage -) - -// we populate these fields as part of Update(), and let View() be -// responsible for returning the final composition of elements +// this struct holds the final rendered content of various UI components, and +// gets populated in the application's Update() method. View() simply composes +// these elements into the final view type views struct { header string content string @@ -113,7 +100,7 @@ func initialModel(ctx *lmcli.Context, convShortname string) model { views: &views{}, } - m.state = stateConversation + m.state = stateChat m.content = viewport.New(0, 0) @@ -155,11 +142,11 @@ func (m model) Init() tea.Cmd { m.waitForReply(), } switch m.state { - case stateConversation: + case stateChat: if m.convShortname != "" { cmds = append(cmds, m.loadConversation(m.convShortname)) } - case stateConversationList: + case stateConversations: cmds = append(cmds, m.loadConversations()) } return tea.Batch(cmds...) @@ -180,10 +167,10 @@ func (m *model) handleGlobalInput(msg tea.KeyMsg) tea.Cmd { } default: switch m.state { - case stateConversation: - return m.handleConversationInput(msg) - case stateConversationList: - return m.handleConversationListInput(msg) + case stateChat: + return m.handleChatInput(msg) + case stateConversations: + return m.handleConversationsInput(msg) } } return nil @@ -210,10 +197,10 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } switch m.state { - case stateConversationList: - cmds = append(cmds, m.handleConversationListUpdate(msg)...) - case stateConversation: - cmds = append(cmds, m.handleConversationUpdate(msg)...) + case stateConversations: + cmds = append(cmds, m.handleConversationsUpdate(msg)...) + case stateChat: + cmds = append(cmds, m.handleChatUpdate(msg)...) } return m, tea.Batch(cmds...) @@ -233,12 +220,12 @@ func (m model) View() string { } switch m.state { - case stateConversationList: + case stateConversations: sections = append(sections, m.views.content) if m.views.error != "" { sections = append(sections, m.views.error) } - case stateConversation: + case stateChat: sections = append(sections, m.views.content) if m.views.error != "" { sections = append(sections, m.views.error) @@ -257,7 +244,7 @@ func (m *model) headerView() string { titleStyle := lipgloss.NewStyle().Bold(true) var header string switch m.state { - case stateConversation: + case stateChat: var title string if m.conversation != nil && m.conversation.Title != "" { title = m.conversation.Title @@ -266,7 +253,7 @@ func (m *model) headerView() string { } title = truncateToCellWidth(title, m.width-headerStyle.GetHorizontalPadding(), "...") header = titleStyle.Render(title) - case stateConversationList: + case stateConversations: header = titleStyle.Render("Conversations") } return headerStyle.Width(m.width).Render(header)