chat.go

  1package page
  2
  3import (
  4	"context"
  5
  6	"github.com/charmbracelet/bubbles/key"
  7	tea "github.com/charmbracelet/bubbletea"
  8	"github.com/kujtimiihoxha/termai/internal/app"
  9	"github.com/kujtimiihoxha/termai/internal/session"
 10	"github.com/kujtimiihoxha/termai/internal/tui/components/chat"
 11	"github.com/kujtimiihoxha/termai/internal/tui/layout"
 12	"github.com/kujtimiihoxha/termai/internal/tui/util"
 13)
 14
 15var ChatPage PageID = "chat"
 16
 17type chatPage struct {
 18	app     *app.App
 19	layout  layout.SplitPaneLayout
 20	session session.Session
 21}
 22
 23type ChatKeyMap struct {
 24	NewSession key.Binding
 25	Cancel     key.Binding
 26}
 27
 28var keyMap = ChatKeyMap{
 29	NewSession: key.NewBinding(
 30		key.WithKeys("ctrl+n"),
 31		key.WithHelp("ctrl+n", "new session"),
 32	),
 33	Cancel: key.NewBinding(
 34		key.WithKeys("ctrl+x"),
 35		key.WithHelp("ctrl+x", "cancel"),
 36	),
 37}
 38
 39func (p *chatPage) Init() tea.Cmd {
 40	// TODO: remove
 41	cmds := []tea.Cmd{
 42		p.layout.Init(),
 43	}
 44
 45	sessions, _ := p.app.Sessions.List(context.Background())
 46	if len(sessions) > 0 {
 47		p.session = sessions[0]
 48		cmd := p.setSidebar()
 49		cmds = append(cmds, util.CmdHandler(chat.SessionSelectedMsg(p.session)), cmd)
 50	}
 51	return tea.Batch(
 52		cmds...,
 53	)
 54}
 55
 56func (p *chatPage) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 57	switch msg := msg.(type) {
 58	case tea.WindowSizeMsg:
 59		p.layout.SetSize(msg.Width, msg.Height)
 60	case chat.SendMsg:
 61		cmd := p.sendMessage(msg.Text)
 62		if cmd != nil {
 63			return p, cmd
 64		}
 65	case tea.KeyMsg:
 66		switch {
 67		case key.Matches(msg, keyMap.NewSession):
 68			p.session = session.Session{}
 69			p.clearSidebar()
 70			return p, util.CmdHandler(chat.SessionClearedMsg{})
 71		}
 72	}
 73	u, cmd := p.layout.Update(msg)
 74	p.layout = u.(layout.SplitPaneLayout)
 75	if cmd != nil {
 76		return p, cmd
 77	}
 78	return p, nil
 79}
 80
 81func (p *chatPage) setSidebar() tea.Cmd {
 82	sidebarContainer := layout.NewContainer(
 83		chat.NewSidebarCmp(p.session),
 84		layout.WithPadding(1, 1, 1, 1),
 85	)
 86	p.layout.SetRightPanel(sidebarContainer)
 87	width, height := p.layout.GetSize()
 88	p.layout.SetSize(width, height)
 89	return sidebarContainer.Init()
 90}
 91
 92func (p *chatPage) clearSidebar() {
 93	p.layout.SetRightPanel(nil)
 94	width, height := p.layout.GetSize()
 95	p.layout.SetSize(width, height)
 96}
 97
 98func (p *chatPage) sendMessage(text string) tea.Cmd {
 99	var cmds []tea.Cmd
100	if p.session.ID == "" {
101		session, err := p.app.Sessions.Create(context.Background(), "New Session")
102		if err != nil {
103			return util.ReportError(err)
104		}
105
106		p.session = session
107		cmd := p.setSidebar()
108		if cmd != nil {
109			cmds = append(cmds, cmd)
110		}
111		cmds = append(cmds, util.CmdHandler(chat.SessionSelectedMsg(session)))
112	}
113
114	p.app.CoderAgent.Generate(context.Background(), p.session.ID, text)
115	return tea.Batch(cmds...)
116}
117
118func (p *chatPage) View() string {
119	return p.layout.View()
120}
121
122func NewChatPage(app *app.App) tea.Model {
123	messagesContainer := layout.NewContainer(
124		chat.NewMessagesCmp(app),
125		layout.WithPadding(1, 1, 0, 1),
126	)
127
128	editorContainer := layout.NewContainer(
129		chat.NewEditorCmp(),
130		layout.WithBorder(true, false, false, false),
131	)
132	return &chatPage{
133		app: app,
134		layout: layout.NewSplitPane(
135			layout.WithLeftPanel(messagesContainer),
136			layout.WithBottomPanel(editorContainer),
137		),
138	}
139}