1package tui
2
3import (
4 "strings"
5
6 "charm.land/lipgloss/v2"
7 "github.com/charmbracelet/x/ansi"
8 "github.com/floatpane/matcha/internal/logging"
9 "github.com/floatpane/matcha/theme"
10)
11
12type LogPanel struct {
13 logger logging.Logger
14 width int
15 height int
16}
17
18func NewLogPanel(logger logging.Logger) *LogPanel {
19 return &LogPanel{logger: logger}
20}
21
22func (p *LogPanel) SetSize(width, height int) {
23 p.width = width
24 p.height = height
25}
26
27func (p *LogPanel) View() string {
28 innerHeight := max(p.height-1, 2)
29 visibleLogLines := max(innerHeight-1, 1)
30
31 lines := p.tailLines(visibleLogLines)
32 if len(lines) == 0 {
33 lines = []string{t("common.no_logs_yet")}
34 }
35
36 innerWidth := max(p.width, 1)
37 for i, line := range lines {
38 lines[i] = ansi.Truncate(line, innerWidth, "…")
39 }
40
41 header := lipgloss.NewStyle().
42 Foreground(theme.ActiveTheme.Accent).
43 Bold(true).
44 Render("[" + t("common.logs") + "]")
45 separator := lipgloss.NewStyle().
46 BorderForeground(theme.ActiveTheme.Secondary).
47 Render(strings.Repeat("─", p.width))
48 body := header + "\n" + strings.Join(lines, "\n")
49 content := lipgloss.NewStyle().
50 Width(p.width).
51 Height(innerHeight).
52 MaxHeight(innerHeight).
53 Foreground(theme.ActiveTheme.SubtleText).
54 Render(body)
55
56 return lipgloss.JoinVertical(lipgloss.Left, separator, content)
57}
58
59func (p *LogPanel) tailLines(n int) []string {
60 if p.logger == nil {
61 return nil
62 }
63
64 entries := p.logger.Tail(n)
65 lines := make([]string, 0, len(entries))
66 for _, entry := range entries {
67 lines = append(lines, entry.Text)
68 }
69 return lines
70}