Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions cmd/gh/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"path"
"strings"

surveyCore "github.com/AlecAivazis/survey/v2/core"
"github.com/cli/cli/api"
"github.com/cli/cli/command"
"github.com/cli/cli/internal/config"
Expand Down Expand Up @@ -43,6 +44,23 @@ func main() {

cmdFactory := factory.New(command.Version)
stderr := cmdFactory.IOStreams.ErrOut
if !cmdFactory.IOStreams.ColorEnabled() {
surveyCore.DisableColor = true
} else {
// override survey's poor choice of color
surveyCore.TemplateFuncsWithColor["color"] = func(style string) string {
switch style {
case "white":
if cmdFactory.IOStreams.ColorSupport256() {
return fmt.Sprintf("\x1b[%d;5;%dm", 38, 242)
}
return ansi.ColorCode("default")
default:
return ansi.ColorCode(style)
}
}
}

rootCmd := root.NewCmdRoot(cmdFactory, command.Version, command.BuildDate)

cfg, err := cmdFactory.Config()
Expand Down
9 changes: 7 additions & 2 deletions pkg/cmd/root/help_topic.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,17 @@ func NewHelpTopic(topic string) *cobra.Command {
DEBUG: set to any value to enable verbose output to standard error. Include values "api"
or "oauth" to print detailed information about HTTP requests or authentication flow.

PAGER: a paging program to send standard output to, e.g. "less".
PAGER: a terminal paging program to send standard output to, e.g. "less".

GLAMOUR_STYLE: the style to use for rendering Markdown. See
https://github.com/charmbracelet/glamour#styles

NO_COLOR: avoid printing ANSI escape sequences for color output.
NO_COLOR: set to any value to avoid printing ANSI escape sequences for color output.

CLICOLOR: set to "0" to disable printing ANSI colors in output.

CLICOLOR_FORCE: set to a value other than "0" to keep ANSI colors in output
even when the output is piped.
`)

cmd := &cobra.Command{
Expand Down
45 changes: 41 additions & 4 deletions pkg/iostreams/color.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
package iostreams

import "github.com/mgutz/ansi"
import (
"fmt"
"os"
"strings"

"github.com/mgutz/ansi"
)

var (
magenta = ansi.ColorFunc("magenta")
Expand All @@ -11,14 +17,42 @@ var (
green = ansi.ColorFunc("green")
gray = ansi.ColorFunc("black+h")
bold = ansi.ColorFunc("default+b")

gray256 = func(t string) string {
return fmt.Sprintf("\x1b[%d;5;%dm%s\x1b[m", 38, 242, t)
}
)

func NewColorScheme(enabled bool) *ColorScheme {
return &ColorScheme{enabled: enabled}
func EnvColorDisabled() bool {
return os.Getenv("NO_COLOR") != "" || os.Getenv("CLICOLOR") == "0"
}

func EnvColorForced() bool {
return os.Getenv("CLICOLOR_FORCE") != "" && os.Getenv("CLICOLOR_FORCE") != "0"
}

func Is256ColorSupported() bool {
term := os.Getenv("TERM")
colorterm := os.Getenv("COLORTERM")

return strings.Contains(term, "256") ||
strings.Contains(term, "24bit") ||
strings.Contains(term, "truecolor") ||
strings.Contains(colorterm, "256") ||
strings.Contains(colorterm, "24bit") ||
strings.Contains(colorterm, "truecolor")
}

func NewColorScheme(enabled, is256enabled bool) *ColorScheme {
return &ColorScheme{
enabled: enabled,
is256enabled: is256enabled,
}
}

type ColorScheme struct {
enabled bool
enabled bool
is256enabled bool
}

func (c *ColorScheme) Bold(t string) string {
Expand Down Expand Up @@ -53,6 +87,9 @@ func (c *ColorScheme) Gray(t string) string {
if !c.enabled {
return t
}
if c.is256enabled {
return gray256(t)
}
return gray(t)
}

Expand Down
145 changes: 145 additions & 0 deletions pkg/iostreams/color_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package iostreams

import (
"os"
"testing"
)

func TestEnvColorDisabled(t *testing.T) {
orig_NO_COLOR := os.Getenv("NO_COLOR")
orig_CLICOLOR := os.Getenv("CLICOLOR")
orig_CLICOLOR_FORCE := os.Getenv("CLICOLOR_FORCE")
t.Cleanup(func() {
os.Setenv("NO_COLOR", orig_NO_COLOR)
os.Setenv("CLICOLOR", orig_CLICOLOR)
os.Setenv("CLICOLOR_FORCE", orig_CLICOLOR_FORCE)
})

tests := []struct {
name string
NO_COLOR string
CLICOLOR string
CLICOLOR_FORCE string
want bool
}{
{
name: "pristine env",
NO_COLOR: "",
CLICOLOR: "",
CLICOLOR_FORCE: "",
want: false,
},
{
name: "NO_COLOR enabled",
NO_COLOR: "1",
CLICOLOR: "",
CLICOLOR_FORCE: "",
want: true,
},
{
name: "CLICOLOR disabled",
NO_COLOR: "",
CLICOLOR: "0",
CLICOLOR_FORCE: "",
want: true,
},
{
name: "CLICOLOR enabled",
NO_COLOR: "",
CLICOLOR: "1",
CLICOLOR_FORCE: "",
want: false,
},
{
name: "CLICOLOR_FORCE has no effect",
NO_COLOR: "",
CLICOLOR: "",
CLICOLOR_FORCE: "1",
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
os.Setenv("NO_COLOR", tt.NO_COLOR)
os.Setenv("CLICOLOR", tt.CLICOLOR)
os.Setenv("CLICOLOR_FORCE", tt.CLICOLOR_FORCE)

if got := EnvColorDisabled(); got != tt.want {
t.Errorf("EnvColorDisabled(): want %v, got %v", tt.want, got)
}
})
}
}

func TestEnvColorForced(t *testing.T) {
orig_NO_COLOR := os.Getenv("NO_COLOR")
orig_CLICOLOR := os.Getenv("CLICOLOR")
orig_CLICOLOR_FORCE := os.Getenv("CLICOLOR_FORCE")
t.Cleanup(func() {
os.Setenv("NO_COLOR", orig_NO_COLOR)
os.Setenv("CLICOLOR", orig_CLICOLOR)
os.Setenv("CLICOLOR_FORCE", orig_CLICOLOR_FORCE)
})

tests := []struct {
name string
NO_COLOR string
CLICOLOR string
CLICOLOR_FORCE string
want bool
}{
{
name: "pristine env",
NO_COLOR: "",
CLICOLOR: "",
CLICOLOR_FORCE: "",
want: false,
},
{
name: "NO_COLOR enabled",
NO_COLOR: "1",
CLICOLOR: "",
CLICOLOR_FORCE: "",
want: false,
},
{
name: "CLICOLOR disabled",
NO_COLOR: "",
CLICOLOR: "0",
CLICOLOR_FORCE: "",
want: false,
},
{
name: "CLICOLOR enabled",
NO_COLOR: "",
CLICOLOR: "1",
CLICOLOR_FORCE: "",
want: false,
},
{
name: "CLICOLOR_FORCE enabled",
NO_COLOR: "",
CLICOLOR: "",
CLICOLOR_FORCE: "1",
want: true,
},
{
name: "CLICOLOR_FORCE disabled",
NO_COLOR: "",
CLICOLOR: "",
CLICOLOR_FORCE: "0",
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
os.Setenv("NO_COLOR", tt.NO_COLOR)
os.Setenv("CLICOLOR", tt.CLICOLOR)
os.Setenv("CLICOLOR_FORCE", tt.CLICOLOR_FORCE)

if got := EnvColorForced(); got != tt.want {
t.Errorf("EnvColorForced(): want %v, got %v", tt.want, got)
}
})
}
}
10 changes: 8 additions & 2 deletions pkg/iostreams/iostreams.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type IOStreams struct {
// the original (non-colorable) output stream
originalOut io.Writer
colorEnabled bool
is256enabled bool

progressIndicatorEnabled bool
progressIndicator *spinner.Spinner
Expand All @@ -47,6 +48,10 @@ func (s *IOStreams) ColorEnabled() bool {
return s.colorEnabled
}

func (s *IOStreams) ColorSupport256() bool {
return s.is256enabled
}

func (s *IOStreams) SetStdinTTY(isTTY bool) {
s.stdinTTYOverride = true
s.stdinIsTTY = isTTY
Expand Down Expand Up @@ -200,7 +205,7 @@ func (s *IOStreams) TerminalWidth() int {
}

func (s *IOStreams) ColorScheme() *ColorScheme {
return NewColorScheme(s.ColorEnabled())
return NewColorScheme(s.ColorEnabled(), s.ColorSupport256())
}

func System() *IOStreams {
Expand All @@ -212,7 +217,8 @@ func System() *IOStreams {
originalOut: os.Stdout,
Out: colorable.NewColorable(os.Stdout),
ErrOut: colorable.NewColorable(os.Stderr),
colorEnabled: os.Getenv("NO_COLOR") == "" && stdoutIsTTY,
colorEnabled: EnvColorForced() || (!EnvColorDisabled() && stdoutIsTTY),
is256enabled: Is256ColorSupported(),
pagerCommand: os.Getenv("PAGER"),
}

Expand Down
11 changes: 10 additions & 1 deletion utils/color.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package utils

import (
"fmt"
"io"
"os"

"github.com/cli/cli/pkg/iostreams"
"github.com/mattn/go-colorable"
"github.com/mgutz/ansi"
)
Expand Down Expand Up @@ -32,14 +34,21 @@ func makeColorFunc(color string) func(string) string {
cf := ansi.ColorFunc(color)
return func(arg string) string {
if isColorEnabled() {
if color == "black+h" && iostreams.Is256ColorSupported() {
return fmt.Sprintf("\x1b[%d;5;%dm%s\x1b[m", 38, 242, arg)
}
return cf(arg)
}
return arg
}
}

func isColorEnabled() bool {
if os.Getenv("NO_COLOR") != "" {
if iostreams.EnvColorForced() {
return true
}

if iostreams.EnvColorDisabled() {
return false
}

Expand Down