mirror of
https://github.com/ivuorinen/gibidify.git
synced 2026-02-10 16:48:10 +00:00
feat: many features, check TODO.md
This commit is contained in:
173
cli/ui.go
Normal file
173
cli/ui.go
Normal file
@@ -0,0 +1,173 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/schollz/progressbar/v3"
|
||||
)
|
||||
|
||||
// UIManager handles CLI user interface elements.
|
||||
type UIManager struct {
|
||||
enableColors bool
|
||||
enableProgress bool
|
||||
progressBar *progressbar.ProgressBar
|
||||
output io.Writer
|
||||
}
|
||||
|
||||
// NewUIManager creates a new UI manager.
|
||||
func NewUIManager() *UIManager {
|
||||
return &UIManager{
|
||||
enableColors: isColorTerminal(),
|
||||
enableProgress: isInteractiveTerminal(),
|
||||
output: os.Stderr, // Progress and colors go to stderr
|
||||
}
|
||||
}
|
||||
|
||||
// SetColorOutput enables or disables colored output.
|
||||
func (ui *UIManager) SetColorOutput(enabled bool) {
|
||||
ui.enableColors = enabled
|
||||
color.NoColor = !enabled
|
||||
}
|
||||
|
||||
// SetProgressOutput enables or disables progress bars.
|
||||
func (ui *UIManager) SetProgressOutput(enabled bool) {
|
||||
ui.enableProgress = enabled
|
||||
}
|
||||
|
||||
// StartProgress initializes a progress bar for file processing.
|
||||
func (ui *UIManager) StartProgress(total int, description string) {
|
||||
if !ui.enableProgress || total <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
ui.progressBar = progressbar.NewOptions(total,
|
||||
progressbar.OptionSetWriter(ui.output),
|
||||
progressbar.OptionSetDescription(description),
|
||||
progressbar.OptionSetTheme(progressbar.Theme{
|
||||
Saucer: color.GreenString("█"),
|
||||
SaucerHead: color.GreenString("█"),
|
||||
SaucerPadding: " ",
|
||||
BarStart: "[",
|
||||
BarEnd: "]",
|
||||
}),
|
||||
progressbar.OptionShowCount(),
|
||||
progressbar.OptionShowIts(),
|
||||
progressbar.OptionSetWidth(40),
|
||||
progressbar.OptionThrottle(100*time.Millisecond),
|
||||
progressbar.OptionOnCompletion(func() {
|
||||
_, _ = fmt.Fprint(ui.output, "\n")
|
||||
}),
|
||||
progressbar.OptionSetRenderBlankState(true),
|
||||
)
|
||||
}
|
||||
|
||||
// UpdateProgress increments the progress bar.
|
||||
func (ui *UIManager) UpdateProgress(increment int) {
|
||||
if ui.progressBar != nil {
|
||||
_ = ui.progressBar.Add(increment)
|
||||
}
|
||||
}
|
||||
|
||||
// FinishProgress completes the progress bar.
|
||||
func (ui *UIManager) FinishProgress() {
|
||||
if ui.progressBar != nil {
|
||||
_ = ui.progressBar.Finish()
|
||||
ui.progressBar = nil
|
||||
}
|
||||
}
|
||||
|
||||
// PrintSuccess prints a success message in green.
|
||||
func (ui *UIManager) PrintSuccess(format string, args ...interface{}) {
|
||||
if ui.enableColors {
|
||||
color.Green("✓ "+format, args...)
|
||||
} else {
|
||||
ui.printf("✓ "+format+"\n", args...)
|
||||
}
|
||||
}
|
||||
|
||||
// PrintError prints an error message in red.
|
||||
func (ui *UIManager) PrintError(format string, args ...interface{}) {
|
||||
if ui.enableColors {
|
||||
color.Red("✗ "+format, args...)
|
||||
} else {
|
||||
ui.printf("✗ "+format+"\n", args...)
|
||||
}
|
||||
}
|
||||
|
||||
// PrintWarning prints a warning message in yellow.
|
||||
func (ui *UIManager) PrintWarning(format string, args ...interface{}) {
|
||||
if ui.enableColors {
|
||||
color.Yellow("⚠ "+format, args...)
|
||||
} else {
|
||||
ui.printf("⚠ "+format+"\n", args...)
|
||||
}
|
||||
}
|
||||
|
||||
// PrintInfo prints an info message in blue.
|
||||
func (ui *UIManager) PrintInfo(format string, args ...interface{}) {
|
||||
if ui.enableColors {
|
||||
color.Blue("ℹ "+format, args...)
|
||||
} else {
|
||||
ui.printf("ℹ "+format+"\n", args...)
|
||||
}
|
||||
}
|
||||
|
||||
// PrintHeader prints a header message in bold.
|
||||
func (ui *UIManager) PrintHeader(format string, args ...interface{}) {
|
||||
if ui.enableColors {
|
||||
_, _ = color.New(color.Bold).Fprintf(ui.output, format+"\n", args...)
|
||||
} else {
|
||||
ui.printf(format+"\n", args...)
|
||||
}
|
||||
}
|
||||
|
||||
// isColorTerminal checks if the terminal supports colors.
|
||||
func isColorTerminal() bool {
|
||||
// Check common environment variables
|
||||
term := os.Getenv("TERM")
|
||||
if term == "" || term == "dumb" {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check for CI environments that typically don't support colors
|
||||
if os.Getenv("CI") != "" {
|
||||
// GitHub Actions supports colors
|
||||
if os.Getenv("GITHUB_ACTIONS") == "true" {
|
||||
return true
|
||||
}
|
||||
// Most other CI systems don't
|
||||
return false
|
||||
}
|
||||
|
||||
// Check if NO_COLOR is set (https://no-color.org/)
|
||||
if os.Getenv("NO_COLOR") != "" {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check if FORCE_COLOR is set
|
||||
if os.Getenv("FORCE_COLOR") != "" {
|
||||
return true
|
||||
}
|
||||
|
||||
// Default to true for interactive terminals
|
||||
return isInteractiveTerminal()
|
||||
}
|
||||
|
||||
// isInteractiveTerminal checks if we're running in an interactive terminal.
|
||||
func isInteractiveTerminal() bool {
|
||||
// Check if stderr is a terminal (where we output progress/colors)
|
||||
fileInfo, err := os.Stderr.Stat()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return (fileInfo.Mode() & os.ModeCharDevice) != 0
|
||||
}
|
||||
|
||||
// printf is a helper that ignores printf errors (for UI output).
|
||||
func (ui *UIManager) printf(format string, args ...interface{}) {
|
||||
_, _ = fmt.Fprintf(ui.output, format, args...)
|
||||
}
|
||||
Reference in New Issue
Block a user