1package chat
2
3import (
4 "fmt"
5
6 tea "github.com/charmbracelet/bubbletea"
7 "github.com/charmbracelet/lipgloss"
8 "github.com/kujtimiihoxha/termai/internal/config"
9 "github.com/kujtimiihoxha/termai/internal/tui/styles"
10 "github.com/kujtimiihoxha/termai/internal/version"
11)
12
13type sidebarCmp struct {
14 width, height int
15}
16
17func (m *sidebarCmp) Init() tea.Cmd {
18 return nil
19}
20
21func (m *sidebarCmp) Update(tea.Msg) (tea.Model, tea.Cmd) {
22 return m, nil
23}
24
25func (m *sidebarCmp) View() string {
26 return styles.BaseStyle.Width(m.width).Render(
27 lipgloss.JoinVertical(
28 lipgloss.Top,
29 m.header(),
30 " ",
31 m.session(),
32 " ",
33 m.modifiedFiles(),
34 " ",
35 m.lspsConfigured(),
36 ),
37 )
38}
39
40func (m *sidebarCmp) session() string {
41 sessionKey := styles.BaseStyle.Foreground(styles.PrimaryColor).Render("Session")
42 sessionValue := styles.BaseStyle.
43 Foreground(styles.Forground).
44 Width(m.width - lipgloss.Width(sessionKey)).
45 Render(": New Session")
46 return lipgloss.JoinHorizontal(
47 lipgloss.Left,
48 sessionKey,
49 sessionValue,
50 )
51}
52
53func (m *sidebarCmp) modifiedFile(filePath string, additions, removals int) string {
54 stats := ""
55 if additions > 0 && removals > 0 {
56 stats = styles.BaseStyle.Foreground(styles.ForgroundDim).Render(fmt.Sprintf("%d additions and %d removals", additions, removals))
57 } else if additions > 0 {
58 stats = styles.BaseStyle.Foreground(styles.ForgroundDim).Render(fmt.Sprintf("%d additions", additions))
59 } else if removals > 0 {
60 stats = styles.BaseStyle.Foreground(styles.ForgroundDim).Render(fmt.Sprintf("%d removals", removals))
61 }
62 filePathStr := styles.BaseStyle.Foreground(styles.Forground).Render(filePath)
63
64 return styles.BaseStyle.
65 Width(m.width).
66 Render(
67 lipgloss.JoinHorizontal(
68 lipgloss.Left,
69 filePathStr,
70 " ",
71 stats,
72 ),
73 )
74}
75
76func (m *sidebarCmp) lspsConfigured() string {
77 lsps := styles.BaseStyle.Width(m.width).Foreground(styles.PrimaryColor).Render("LSP Configuration:")
78 lspsConfigured := []struct {
79 name string
80 path string
81 }{
82 {"golsp", "path/to/lsp1"},
83 {"vtsls", "path/to/lsp2"},
84 }
85
86 var lspViews []string
87 for _, lsp := range lspsConfigured {
88 lspName := styles.BaseStyle.Foreground(styles.Forground).Render(
89 fmt.Sprintf("• %s", lsp.name),
90 )
91 lspPath := styles.BaseStyle.Foreground(styles.ForgroundDim).Render(
92 fmt.Sprintf("(%s)", lsp.path),
93 )
94 lspViews = append(lspViews,
95 styles.BaseStyle.
96 Width(m.width).
97 Render(
98 lipgloss.JoinHorizontal(
99 lipgloss.Left,
100 lspName,
101 " ",
102 lspPath,
103 ),
104 ),
105 )
106
107 }
108 return styles.BaseStyle.
109 Width(m.width).
110 Render(
111 lipgloss.JoinVertical(
112 lipgloss.Left,
113 lsps,
114 lipgloss.JoinVertical(
115 lipgloss.Left,
116 lspViews...,
117 ),
118 ),
119 )
120}
121
122func (m *sidebarCmp) modifiedFiles() string {
123 modifiedFiles := styles.BaseStyle.Width(m.width).Foreground(styles.PrimaryColor).Render("Modified Files:")
124 files := []struct {
125 path string
126 additions int
127 removals int
128 }{
129 {"file1.txt", 10, 5},
130 {"file2.txt", 20, 0},
131 {"file3.txt", 0, 15},
132 }
133 var fileViews []string
134 for _, file := range files {
135 fileViews = append(fileViews, m.modifiedFile(file.path, file.additions, file.removals))
136 }
137
138 return styles.BaseStyle.
139 Width(m.width).
140 Render(
141 lipgloss.JoinVertical(
142 lipgloss.Top,
143 modifiedFiles,
144 lipgloss.JoinVertical(
145 lipgloss.Left,
146 fileViews...,
147 ),
148 ),
149 )
150}
151
152func (m *sidebarCmp) logo() string {
153 logo := fmt.Sprintf("%s %s", styles.OpenCodeIcon, "OpenCode")
154
155 version := styles.BaseStyle.Foreground(styles.ForgroundDim).Render(version.Version)
156
157 return styles.BaseStyle.
158 Bold(true).
159 Width(m.width).
160 Render(
161 lipgloss.JoinHorizontal(
162 lipgloss.Left,
163 logo,
164 " ",
165 version,
166 ),
167 )
168}
169
170func (m *sidebarCmp) header() string {
171 header := lipgloss.JoinVertical(
172 lipgloss.Top,
173 m.logo(),
174 m.cwd(),
175 )
176 return header
177}
178
179func (m *sidebarCmp) cwd() string {
180 cwd := fmt.Sprintf("cwd: %s", config.WorkingDirectory())
181 return styles.BaseStyle.
182 Foreground(styles.ForgroundDim).
183 Width(m.width).
184 Render(cwd)
185}
186
187func (m *sidebarCmp) SetSize(width, height int) {
188 m.width = width
189 m.height = height
190}
191
192func (m *sidebarCmp) GetSize() (int, int) {
193 return m.width, m.height
194}
195
196func NewSidebarCmp() tea.Model {
197 return &sidebarCmp{}
198}