internal/progress/progress.go (view raw)
1package progress
2
3import (
4 "fmt"
5 "io"
6
7 "codeberg.org/maxwelljensen/llm_aggregator/internal/style"
8)
9
10// Logger is the minimal interface for progress and verbose logging implementations.
11type Logger interface {
12 Logf(format string, args ...any)
13 Warningf(format string, args ...any)
14 Debugf(format string, args ...any)
15}
16
17// Progress extends Logger with stage/count/timing reporting.
18// Implementations: NoopLogger (no output), SimpleLogger (stdout), TUIProgress (tea messages).
19type Progress interface {
20 Logger
21 SetStage(stage string)
22 SetSubStage(status string)
23 SetArticleCount(total, processed int)
24 SetTokenEstimate(total, used int)
25 StartWaiting()
26}
27
28// SimpleLogger writes formatted output to an io.Writer.
29type SimpleLogger struct {
30 writer io.Writer
31 debug bool
32}
33
34// NewSimpleLogger creates a SimpleLogger; set debug=true to enable Debugf output.
35func NewSimpleLogger(writer io.Writer, debug bool) *SimpleLogger {
36 return &SimpleLogger{
37 writer: writer,
38 debug: debug,
39 }
40}
41
42func (sl *SimpleLogger) Logf(format string, args ...any) {
43 _, _ = fmt.Fprintf(sl.writer, format+"\n", args...)
44}
45
46func (sl *SimpleLogger) Warningf(format string, args ...any) {
47 // Use style.Warningf for orange bold WARNING prefix
48 _, _ = fmt.Fprintf(sl.writer, "%s\n", style.Warningf(format, args...))
49}
50
51func (sl *SimpleLogger) Debugf(format string, args ...any) {
52 if sl.debug {
53 // Use style.Debugf for styled debug output
54 _, _ = fmt.Fprintf(sl.writer, "%s\n", style.Debugf(format, args...))
55 }
56}
57
58func (sl *SimpleLogger) SetStage(stage string) {}
59func (sl *SimpleLogger) SetSubStage(stage string) {}
60func (sl *SimpleLogger) SetArticleCount(total, processed int) {}
61func (sl *SimpleLogger) SetTokenEstimate(total, used int) {}
62func (sl *SimpleLogger) StartWaiting() {}
63
64// NoopLogger discards all output. Used as the default when no progress is desired.
65type NoopLogger struct{}
66
67func (nl *NoopLogger) Logf(format string, args ...any) {}
68func (nl *NoopLogger) Warningf(format string, args ...any) {}
69func (nl *NoopLogger) Debugf(format string, args ...any) {}
70func (nl *NoopLogger) SetStage(stage string) {}
71func (nl *NoopLogger) SetSubStage(status string) {}
72func (nl *NoopLogger) SetArticleCount(total, processed int) {}
73func (nl *NoopLogger) SetTokenEstimate(total, used int) {}
74func (nl *NoopLogger) StartWaiting() {}
75
76// Context wraps a Logger and guards against nil receiver.
77type Context struct {
78 logger Logger
79}
80
81// NewContext wraps a Logger. Passing nil produces a no-op context.
82func NewContext(logger Logger) *Context {
83 return &Context{
84 logger: logger,
85 }
86}
87
88// Logf logs a message
89func (c *Context) Logf(format string, args ...any) {
90 if c.logger != nil {
91 c.logger.Logf(format, args...)
92 }
93}
94
95// Warningf logs a warning
96func (c *Context) Warningf(format string, args ...any) {
97 if c.logger != nil {
98 c.logger.Warningf(format, args...)
99 }
100}
101
102// Debugf logs a debug message
103func (c *Context) Debugf(format string, args ...any) {
104 if c.logger != nil {
105 c.logger.Debugf(format, args...)
106 }
107}