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}