rewrite color utils

This commit is contained in:
Sky Johnson 2025-05-31 09:11:21 -05:00
parent 31a3625873
commit 3f86c31c9f
8 changed files with 108 additions and 83 deletions

View File

@ -131,7 +131,7 @@ func New(luaRouter *router.LuaRouter, staticDir string,
} }
func (s *Server) ListenAndServe(addr string) error { func (s *Server) ListenAndServe(addr string) error {
logger.Info("Catch the swell at %s", color.Apply("http://localhost"+addr, color.Cyan)) logger.Info("Catch the swell at %s", color.Cyan("http://localhost"+addr))
return s.fasthttpServer.ListenAndServe(addr) return s.fasthttpServer.ListenAndServe(addr)
} }

42
main.go
View File

@ -40,22 +40,13 @@ func main() {
flag.Parse() flag.Parse()
scriptMode := *scriptPath != "" scriptMode := *scriptPath != ""
banner() color.SetColors(color.DetectShellColors())
mode := "" banner(scriptMode)
if scriptMode {
mode = "[Script Mode]"
} else {
mode = "[Server Mode]"
}
fmt.Printf("%s %s\n\n", color.Apply(mode, color.Gray), color.Apply("v"+metadata.Version, color.Blue))
// Initialize logger
logger.InitGlobalLogger(true, false)
// Load config // Load config
cfg, err := config.Load(*configPath) cfg, err := config.Load(*configPath)
if err != nil { if err != nil {
logger.Warning("Config load failed: %v, using defaults", color.Apply(err.Error(), color.Red)) logger.Warning("Config load failed: %v, using defaults", color.Red(err.Error()))
cfg = config.New() cfg = config.New()
} }
@ -158,9 +149,9 @@ func initServerMode(cfg *config.Config, debug bool) (*Moonshark, error) {
staticDir := "" staticDir := ""
if dirExists(cfg.Dirs.Static) { if dirExists(cfg.Dirs.Static) {
staticDir = cfg.Dirs.Static staticDir = cfg.Dirs.Static
logger.Info("Static files enabled: %s", color.Apply(staticDir, color.Yellow)) logger.Info("Static files enabled: %s", color.Yellow(staticDir))
} else { } else {
logger.Warning("Static directory not found: %s", color.Apply(cfg.Dirs.Static, color.Yellow)) logger.Warning("Static directory not found: %s", color.Yellow(cfg.Dirs.Static))
} }
moonshark.HTTPServer = http.New( moonshark.HTTPServer = http.New(
@ -216,7 +207,7 @@ func (s *Moonshark) Start() error {
return errors.New("cannot start server in script mode") return errors.New("cannot start server in script mode")
} }
logger.Info("Surf's up on port %s!", color.Apply(strconv.Itoa(s.Config.Server.Port), color.Cyan)) logger.Info("Surf's up on port %s!", color.Cyan(strconv.Itoa(s.Config.Server.Port)))
go func() { go func() {
if err := s.HTTPServer.ListenAndServe(fmt.Sprintf(":%d", s.Config.Server.Port)); err != nil { if err := s.HTTPServer.ListenAndServe(fmt.Sprintf(":%d", s.Config.Server.Port)); err != nil {
@ -289,20 +280,20 @@ func initLuaRouter(s *Moonshark) error {
return fmt.Errorf("lua router init failed: %v", err) return fmt.Errorf("lua router init failed: %v", err)
} }
} }
logger.Info("LuaRouter is g2g! %s", color.Set(s.Config.Dirs.Routes, color.Yellow)) logger.Info("LuaRouter is g2g! %s", color.Yellow(s.Config.Dirs.Routes))
return nil return nil
} }
func initRunner(s *Moonshark) error { func initRunner(s *Moonshark) error {
if !dirExists(s.Config.Dirs.Override) { if !dirExists(s.Config.Dirs.Override) {
logger.Warning("Override directory not found... %s", color.Apply(s.Config.Dirs.Override, color.Yellow)) logger.Warning("Override directory not found... %s", color.Yellow(s.Config.Dirs.Override))
s.Config.Dirs.Override = "" s.Config.Dirs.Override = ""
} }
for _, dir := range s.Config.Dirs.Libs { for _, dir := range s.Config.Dirs.Libs {
if !dirExists(dir) { if !dirExists(dir) {
logger.Warning("Lib directory not found... %s", color.Apply(dir, color.Yellow)) logger.Warning("Lib directory not found... %s", color.Yellow(dir))
} }
} }
@ -339,7 +330,7 @@ func initRunner(s *Moonshark) error {
return fmt.Errorf("lua runner init failed: %v", err) return fmt.Errorf("lua runner init failed: %v", err)
} }
logger.Info("LuaRunner is g2g with %s states!", color.Apply(strconv.Itoa(poolSize), color.Yellow)) logger.Info("LuaRunner is g2g with %s states!", color.Yellow(strconv.Itoa(poolSize)))
return nil return nil
} }
@ -374,20 +365,25 @@ func setupWatchers(s *Moonshark) error {
} else { } else {
plural = "directories" plural = "directories"
} }
logger.Info("Watching %s module %s.", color.Apply(strconv.Itoa(len(moduleWatchers)), color.Yellow), plural) logger.Info("Watching %s module %s.", color.Yellow(strconv.Itoa(len(moduleWatchers))), plural)
} }
return nil return nil
} }
func banner() { func banner(scriptMode bool) {
if scriptMode {
fmt.Println(color.Blue(fmt.Sprintf("Moonshark %s << Script Mode >>", metadata.Version)))
return
}
banner := ` banner := `
_____ _________.__ __ _____ _________.__ __
/ \ ____ ____ ____ / _____/| |__ _____ _______| | __ / \ ____ ____ ____ / _____/| |__ _____ _______| | __
/ \ / \ / _ \ / _ \ / \ \_____ \ | | \\__ \\_ __ \ |/ / / \ / \ / _ \ / _ \ / \ \_____ \ | | \\__ \\_ __ \ |/ /
/ Y ( <_> | <_> ) | \/ \| Y \/ __ \| | \/ < / Y ( <_> | <_> ) | \/ \| Y \/ __ \| | \/ <
\____|__ /\____/ \____/|___| /_______ /|___| (____ /__| |__|_ \ \____|__ /\____/ \____/|___| /_______ /|___| (____ /__| |__|_ \ %s
\/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/
` `
fmt.Println(color.Apply(banner, color.Blue)) fmt.Println(color.Blue(fmt.Sprintf(banner, metadata.Version)))
} }

View File

@ -51,10 +51,10 @@ func InitEnv(dataDir string) error {
count := len(globalEnvManager.vars) count := len(globalEnvManager.vars)
if count > 0 { if count > 0 {
logger.Info("Environment loaded: %s vars from %s", logger.Info("Environment loaded: %s vars from %s",
color.Apply(fmt.Sprintf("%d", count), color.Yellow), color.Yellow(fmt.Sprintf("%d", count)),
color.Apply(envPath, color.Yellow)) color.Yellow(envPath))
} else { } else {
logger.Info("Environment initialized: %s", color.Apply(envPath, color.Yellow)) logger.Info("Environment initialized: %s", color.Yellow(envPath))
} }
return nil return nil

View File

@ -52,7 +52,7 @@ func InitFS(basePath string) error {
// Initialize file cache with 2000 entries (reasonable for most use cases) // Initialize file cache with 2000 entries (reasonable for most use cases)
fileCache = lru.NewLRUCache(2000) fileCache = lru.NewLRUCache(2000)
logger.Info("Filesystem is g2g! %s", color.Apply(fsBasePath, color.Yellow)) logger.Info("Filesystem is g2g! %s", color.Yellow(fsBasePath))
return nil return nil
} }
@ -62,8 +62,8 @@ func CleanupFS() {
fileCache.Clear() fileCache.Clear()
logger.Info( logger.Info(
"File cache cleared - %s hits, %s misses", "File cache cleared - %s hits, %s misses",
color.Apply(fmt.Sprintf("%d", stats.hits), color.Yellow), color.Yellow(fmt.Sprintf("%d", stats.hits)),
color.Apply(fmt.Sprintf("%d", stats.misses), color.Red), color.Red(fmt.Sprintf("%d", stats.misses)),
) )
} }
} }

View File

@ -134,7 +134,7 @@ func NewRunner(options ...RunnerOption) (*Runner, error) {
// initializeStates creates and initializes all states in the pool // initializeStates creates and initializes all states in the pool
func (r *Runner) initializeStates() error { func (r *Runner) initializeStates() error {
logger.Info("[LuaRunner] Creating %s states...", color.Apply(strconv.Itoa(r.poolSize), color.Yellow)) logger.Info("[LuaRunner] Creating %s states...", color.Yellow(strconv.Itoa(r.poolSize)))
for i := range r.poolSize { for i := range r.poolSize {
state, err := r.createState(i) state, err := r.createState(i)

View File

@ -28,7 +28,7 @@ var (
// InitSQLite initializes the SQLite subsystem // InitSQLite initializes the SQLite subsystem
func InitSQLite(dir string) { func InitSQLite(dir string) {
dataDir = dir dataDir = dir
logger.Info("SQLite is g2g! %s", color.Apply(dir, color.Yellow)) logger.Info("SQLite is g2g! %s", color.Yellow(dir))
} }
// SetSQLitePoolSize sets the pool size to match the runner pool size // SetSQLitePoolSize sets the pool size to match the runner pool size

View File

@ -1,20 +1,83 @@
package color package color
import (
"os"
"strings"
"syscall"
"unsafe"
)
const ioctlReadTermios = 0x5401
// ANSI color codes // ANSI color codes
const ( const (
Reset = "\033[0m" resetCode = "\033[0m"
Red = "\033[31m" redCode = "\033[31m"
Green = "\033[32m" greenCode = "\033[32m"
Yellow = "\033[33m" yellowCode = "\033[33m"
Blue = "\033[34m" blueCode = "\033[34m"
Purple = "\033[35m" purpleCode = "\033[35m"
Cyan = "\033[36m" cyanCode = "\033[36m"
White = "\033[37m" whiteCode = "\033[37m"
Gray = "\033[90m" grayCode = "\033[90m"
) )
var useColors = true var useColors = true
// Color function. Makes a call to makeColorFunc with the associated
// color code.
var (
Reset = makeColorFunc(resetCode)
Red = makeColorFunc(redCode)
Green = makeColorFunc(greenCode)
Yellow = makeColorFunc(yellowCode)
Blue = makeColorFunc(blueCode)
Purple = makeColorFunc(purpleCode)
Cyan = makeColorFunc(cyanCode)
White = makeColorFunc(whiteCode)
Gray = makeColorFunc(grayCode)
)
func makeColorFunc(code string) func(string) string {
return func(text string) string {
if useColors {
return code + text + resetCode
}
return text
}
}
// DetectShellColors checks if the current shell supports colors
func DetectShellColors() bool {
// Check NO_COLOR environment variable (standard)
if os.Getenv("NO_COLOR") != "" {
return false
}
// Check FORCE_COLOR environment variable
if os.Getenv("FORCE_COLOR") != "" {
return true
}
// Check if stdout is a terminal
if !isTerminal(os.Stdout) {
return false
}
// Check TERM environment variable
term := os.Getenv("TERM")
if term == "" || term == "dumb" {
return false
}
// Common color-supporting terminals
return strings.Contains(term, "color") ||
strings.Contains(term, "xterm") ||
strings.Contains(term, "screen") ||
strings.Contains(term, "tmux") ||
term == "linux"
}
// SetColors enables or disables colors globally // SetColors enables or disables colors globally
func SetColors(enabled bool) { func SetColors(enabled bool) {
useColors = enabled useColors = enabled
@ -25,44 +88,10 @@ func ColorsEnabled() bool {
return useColors return useColors
} }
// Apply adds color to text using global color setting // isTerminal checks if the file is a terminal
func Apply(text, color string) string { func isTerminal(f *os.File) bool {
if useColors { fd := f.Fd()
return color + text + Reset var termios syscall.Termios
} _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, fd, ioctlReadTermios, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
return text return err == 0
}
// ApplyIf adds color to text if useColors is true (for backward compatibility)
func ApplyIf(text, color string, enabled bool) string {
if enabled {
return color + text + Reset
}
return text
}
// Set adds color to text (always applies color, ignores global setting)
func Set(text, color string) string {
return color + text + Reset
}
// Strip removes ANSI color codes from a string
func Strip(s string) string {
result := ""
inEscape := false
for _, c := range s {
if inEscape {
if c == 'm' {
inEscape = false
}
continue
}
if c == '\033' {
inEscape = true
continue
}
result += string(c)
}
return result
} }

View File

@ -48,7 +48,7 @@ func WatchLuaRouter(router *router.LuaRouter, runner *runner.Runner, routesDir s
return nil, fmt.Errorf("failed to watch directory: %w", err) return nil, fmt.Errorf("failed to watch directory: %w", err)
} }
logger.Info("Started watching Lua routes! %s", color.Apply(routesDir, color.Yellow)) logger.Info("Started watching Lua routes! %s", color.Yellow(routesDir))
return watcher, nil return watcher, nil
} }
@ -77,7 +77,7 @@ func WatchLuaModules(luaRunner *runner.Runner, libDirs []string) ([]*DirectoryWa
} }
watchers = append(watchers, watcher) watchers = append(watchers, watcher)
logger.Info("Started watching Lua modules! %s", color.Apply(dir, color.Yellow)) logger.Info("Started watching Lua modules! %s", color.Yellow(dir))
} }
return watchers, nil return watchers, nil