Skip to content

Commit

Permalink
fix: add better colors control
Browse files Browse the repository at this point in the history
  • Loading branch information
mrexox committed Aug 30, 2024
1 parent 2df5428 commit 3e08c09
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 25 deletions.
11 changes: 10 additions & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ func newRootCmd() *cobra.Command {
rootCmd.PersistentFlags().BoolVarP(
&options.Verbose, "verbose", "v", false, "verbose output",
)

rootCmd.PersistentFlags().StringVar(
&options.Colors, "colors", "auto", "'auto', 'on', or 'off'",
)

rootCmd.PersistentFlags().BoolVar(
&options.NoColors, "no-colors", false, "disable colored output",
)
Expand All @@ -42,7 +47,11 @@ func newRootCmd() *cobra.Command {
&options.Aggressive, "aggressive", "a", false,
"use --force flag instead",
)
err := rootCmd.Flags().MarkDeprecated("aggressive", "use command-specific --force option")
err := rootCmd.PersistentFlags().MarkDeprecated("no-colors", "use --colors")
if err != nil {
log.Warn("Unexpected error:", err)
}
err = rootCmd.Flags().MarkDeprecated("aggressive", "use command-specific --force option")
if err != nil {
log.Warn("Unexpected error:", err)
}
Expand Down
7 changes: 6 additions & 1 deletion internal/lefthook/lefthook.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ var lefthookContentRegexp = regexp.MustCompile("LEFTHOOK")
type Options struct {
Fs afero.Fs
Verbose, NoColors bool
Colors string

// DEPRECATED. Will be removed in 1.3.0.
Force, Aggressive bool
Expand All @@ -49,7 +50,11 @@ func initialize(opts *Options) (*Lefthook, error) {
log.SetLevel(log.DebugLevel)
}

log.SetColors(!opts.NoColors)
// DEPRECATED: Will be removed with a --no-colors option
if opts.NoColors && opts.Colors == "auto" {
opts.Colors = "off"
}
log.SetColors(opts.Colors)

repo, err := git.NewRepository(opts.Fs, git.NewExecutor(system.Cmd))
if err != nil {
Expand Down
15 changes: 3 additions & 12 deletions internal/lefthook/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
"github.com/evilmartians/lefthook/internal/config"
"github.com/evilmartians/lefthook/internal/lefthook/runner"
"github.com/evilmartians/lefthook/internal/log"
"github.com/evilmartians/lefthook/internal/version"
)

const (
Expand Down Expand Up @@ -91,10 +90,7 @@ func (l *Lefthook) Run(hookName string, args RunArgs, gitArgs []string) error {
// }

if logSettings.LogMeta() {
log.Box(
log.Cyan("🥊 lefthook ")+log.Gray(fmt.Sprintf("v%s", version.Version(false))),
log.Gray("hook: ")+log.Bold(hookName),
)
log.LogMeta(hookName)
}

if !args.NoAutoInstall {
Expand Down Expand Up @@ -231,7 +227,7 @@ func printSummary(
continue
}

log.Infof("✔️ %s\n", log.Green(result.Name))
log.Success(result.Name)
}
}

Expand All @@ -241,12 +237,7 @@ func printSummary(
continue
}

failText := result.Text()
if len(failText) != 0 {
failText = fmt.Sprintf(": %s", failText)
}

log.Infof("🥊 %s%s\n", log.Red(result.Name), log.Red(failText))
log.Failure(result.Name, result.Text())
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions internal/lefthook/runner/exec/execute_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ func (e CommandExecutor) Execute(ctx context.Context, opts Options, in io.Reader
fmt.Sprintf("%s=%s", strings.ToUpper(name), os.ExpandEnv(value)),
)
}
switch log.Colors() {
case log.ColorOn:
envs = append(envs, "CLICOLOR_FORCE=true")
case log.ColorOff:
envs = append(envs, "NO_COLOR=true")
}

args := &executeArgs{
in: in,
Expand Down
7 changes: 7 additions & 0 deletions internal/lefthook/runner/exec/execute_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"syscall"

"github.com/evilmartians/lefthook/internal/log"

"github.com/mattn/go-isatty"
"github.com/mattn/go-tty"
)
Expand Down Expand Up @@ -42,6 +43,12 @@ func (e CommandExecutor) Execute(ctx context.Context, opts Options, in io.Reader
fmt.Sprintf("%s=%s", strings.ToUpper(name), os.ExpandEnv(value)),
)
}
switch log.Colors() {
case log.ColorOn:
envs = append(envs, "CLICOLOR_FORCE=true")
case log.ColorOff:
envs = append(envs, "NO_COLOR=true")
}

args := &executeArgs{
in: in,
Expand Down
88 changes: 77 additions & 11 deletions internal/log/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (

"github.com/briandowns/spinner"
"github.com/charmbracelet/lipgloss"

"github.com/evilmartians/lefthook/internal/version"
)

var (
Expand Down Expand Up @@ -38,6 +40,10 @@ const (
spinnerCharSet = 14
spinnerRefreshRate = 100 * time.Millisecond
spinnerText = " waiting"

ColorAuto = iota
ColorOn
ColorOff
)

type StyleLogger struct {
Expand All @@ -48,7 +54,7 @@ type Logger struct {
level Level
out io.Writer
mu sync.Mutex
colors bool
colors int
names []string
spinner *spinner.Spinner
}
Expand All @@ -57,7 +63,7 @@ func New() *Logger {
return &Logger{
level: InfoLevel,
out: os.Stdout,
colors: true,
colors: ColorAuto,
spinner: spinner.New(
spinner.CharSets[spinnerCharSet],
spinnerRefreshRate,
Expand All @@ -66,6 +72,14 @@ func New() *Logger {
}
}

func Colors() int {
return std.colors
}

func Colorized() bool {
return std.colors == ColorAuto || std.colors == ColorOn
}

func StartSpinner() {
std.spinner.Start()
}
Expand Down Expand Up @@ -159,29 +173,49 @@ func SetLevel(level Level) {
}

func SetColors(colors interface{}) {
if colors == nil {
return
}

switch typedColors := colors.(type) {
case bool:
std.colors = typedColors
if !std.colors {
case string:
switch typedColors {
case "on":
std.colors = ColorOn
case "off":
std.colors = ColorOff
setColor(lipgloss.NoColor{}, &ColorRed)
setColor(lipgloss.NoColor{}, &ColorGreen)
setColor(lipgloss.NoColor{}, &ColorYellow)
setColor(lipgloss.NoColor{}, &ColorCyan)
setColor(lipgloss.NoColor{}, &GolorGray)
setColor(lipgloss.NoColor{}, &colorBorder)
default:
std.colors = ColorAuto
}
return
case bool:
if typedColors {
std.colors = ColorOn
return
}

std.colors = ColorOff
setColor(lipgloss.NoColor{}, &ColorRed)
setColor(lipgloss.NoColor{}, &ColorGreen)
setColor(lipgloss.NoColor{}, &ColorYellow)
setColor(lipgloss.NoColor{}, &ColorCyan)
setColor(lipgloss.NoColor{}, &GolorGray)
setColor(lipgloss.NoColor{}, &colorBorder)
case map[string]interface{}:
std.colors = true
std.colors = ColorOn
setColor(typedColors["red"], &ColorRed)
setColor(typedColors["green"], &ColorGreen)
setColor(typedColors["yellow"], &ColorYellow)
setColor(typedColors["cyan"], &ColorCyan)
setColor(typedColors["gray"], &GolorGray)
setColor(typedColors["gray"], &colorBorder)
return
default:
std.colors = true
std.colors = ColorAuto
}
}

Expand Down Expand Up @@ -227,14 +261,46 @@ func Gray(s string) string {
}

func Bold(s string) string {
if !std.colors {
if !Colorized() {
return lipgloss.NewStyle().Render(s)
}

return lipgloss.NewStyle().Bold(true).Render(s)
}

func Box(left, right string) {
func LogMeta(hookName string) {
name := "🥊 lefthook "
if !Colorized() {
name = "lefthook "
}

box(
Cyan(name)+Gray(fmt.Sprintf("v%s", version.Version(false))),
Gray("hook: ")+Bold(hookName),
)
}

func Success(name string) {
format := "✔️ %s\n"
if !Colorized() {
format = "✓ %s\n"
}
Infof(format, Green(name))
}

func Failure(name, failText string) {
if len(failText) != 0 {
failText = fmt.Sprintf(": %s", failText)
}

format := "🥊 %s%s\n"
if !Colorized() {
format = "✗ %s%s\n"
}
Infof(format, Red(name), Red(failText))
}

func box(left, right string) {
Info(
lipgloss.JoinHorizontal(
lipgloss.Top,
Expand Down

0 comments on commit 3e08c09

Please sign in to comment.