log_panel.go

 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}