From ed4075517c42690668de1d50993787cbd86f3888 Mon Sep 17 00:00:00 2001 From: Sam Coe Date: Wed, 23 Sep 2020 15:02:59 +0200 Subject: [PATCH] Check for terminal background color before starting pager --- go.mod | 1 + pkg/cmd/gist/view/view.go | 3 ++- pkg/cmd/issue/view/view.go | 9 ++++++--- pkg/cmd/pr/review/review.go | 3 ++- pkg/cmd/pr/view/view.go | 10 +++++++--- pkg/cmd/release/view/view.go | 3 ++- pkg/cmd/repo/view/view.go | 5 ++++- pkg/iostreams/iostreams.go | 28 ++++++++++++++++++++++++++ pkg/markdown/markdown.go | 38 ++++++++++++++++++++++++++++++++++++ utils/utils.go | 24 ----------------------- 10 files changed, 90 insertions(+), 34 deletions(-) create mode 100644 pkg/markdown/markdown.go diff --git a/go.mod b/go.mod index 3b1788ef7..c60c1994b 100644 --- a/go.mod +++ b/go.mod @@ -18,6 +18,7 @@ require ( github.com/mattn/go-runewidth v0.0.9 github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d github.com/mitchellh/go-homedir v1.1.0 + github.com/muesli/termenv v0.6.0 github.com/rivo/uniseg v0.1.0 github.com/shurcooL/githubv4 v0.0.0-20200802174311-f27d2ca7f6d5 github.com/shurcooL/graphql v0.0.0-20181231061246-d48a9a75455f diff --git a/pkg/cmd/gist/view/view.go b/pkg/cmd/gist/view/view.go index aae6b93ba..f5fa9fe14 100644 --- a/pkg/cmd/gist/view/view.go +++ b/pkg/cmd/gist/view/view.go @@ -10,6 +10,7 @@ import ( "github.com/cli/cli/pkg/cmd/gist/shared" "github.com/cli/cli/pkg/cmdutil" "github.com/cli/cli/pkg/iostreams" + "github.com/cli/cli/pkg/markdown" "github.com/cli/cli/utils" "github.com/spf13/cobra" ) @@ -115,7 +116,7 @@ func viewRun(opts *ViewOptions) error { } content := gistFile.Content if strings.Contains(gistFile.Type, "markdown") && !opts.Raw { - rendered, err := utils.RenderMarkdown(gistFile.Content) + rendered, err := markdown.Render(gistFile.Content, opts.IO.ResolveBgColor()) if err == nil { content = rendered } diff --git a/pkg/cmd/issue/view/view.go b/pkg/cmd/issue/view/view.go index 2795ca23b..cb9a7511f 100644 --- a/pkg/cmd/issue/view/view.go +++ b/pkg/cmd/issue/view/view.go @@ -16,6 +16,7 @@ import ( prShared "github.com/cli/cli/pkg/cmd/pr/shared" "github.com/cli/cli/pkg/cmdutil" "github.com/cli/cli/pkg/iostreams" + "github.com/cli/cli/pkg/markdown" "github.com/cli/cli/utils" "github.com/spf13/cobra" ) @@ -89,6 +90,7 @@ func viewRun(opts *ViewOptions) error { return utils.OpenInBrowser(openURL) } + opts.IO.ResolveBgColor() err = opts.IO.StartPager() if err != nil { return err @@ -96,7 +98,7 @@ func viewRun(opts *ViewOptions) error { defer opts.IO.StopPager() if opts.IO.IsStdoutTTY() { - return printHumanIssuePreview(opts.IO.Out, issue) + return printHumanIssuePreview(opts.IO, issue) } return printRawIssuePreview(opts.IO.Out, issue) } @@ -122,7 +124,8 @@ func printRawIssuePreview(out io.Writer, issue *api.Issue) error { return nil } -func printHumanIssuePreview(out io.Writer, issue *api.Issue) error { +func printHumanIssuePreview(io *iostreams.IOStreams, issue *api.Issue) error { + out := io.Out now := time.Now() ago := now.Sub(issue.CreatedAt) @@ -158,7 +161,7 @@ func printHumanIssuePreview(out io.Writer, issue *api.Issue) error { // Body if issue.Body != "" { fmt.Fprintln(out) - md, err := utils.RenderMarkdown(issue.Body) + md, err := markdown.Render(issue.Body, io.BgColor()) if err != nil { return err } diff --git a/pkg/cmd/pr/review/review.go b/pkg/cmd/pr/review/review.go index d51d109da..e36acc1af 100644 --- a/pkg/cmd/pr/review/review.go +++ b/pkg/cmd/pr/review/review.go @@ -14,6 +14,7 @@ import ( "github.com/cli/cli/pkg/cmd/pr/shared" "github.com/cli/cli/pkg/cmdutil" "github.com/cli/cli/pkg/iostreams" + "github.com/cli/cli/pkg/markdown" "github.com/cli/cli/pkg/prompt" "github.com/cli/cli/pkg/surveyext" "github.com/cli/cli/utils" @@ -252,7 +253,7 @@ func reviewSurvey(io *iostreams.IOStreams, editorCommand string) (*api.PullReque } if len(bodyAnswers.Body) > 0 { - renderedBody, err := utils.RenderMarkdown(bodyAnswers.Body) + renderedBody, err := markdown.Render(bodyAnswers.Body, io.ResolveBgColor()) if err != nil { return nil, err } diff --git a/pkg/cmd/pr/view/view.go b/pkg/cmd/pr/view/view.go index a1a15ec42..3bc8f51d6 100644 --- a/pkg/cmd/pr/view/view.go +++ b/pkg/cmd/pr/view/view.go @@ -16,6 +16,7 @@ import ( "github.com/cli/cli/pkg/cmd/pr/shared" "github.com/cli/cli/pkg/cmdutil" "github.com/cli/cli/pkg/iostreams" + "github.com/cli/cli/pkg/markdown" "github.com/cli/cli/utils" "github.com/spf13/cobra" ) @@ -99,6 +100,7 @@ func viewRun(opts *ViewOptions) error { return utils.OpenInBrowser(openURL) } + opts.IO.ResolveBgColor() err = opts.IO.StartPager() if err != nil { return err @@ -106,7 +108,7 @@ func viewRun(opts *ViewOptions) error { defer opts.IO.StopPager() if connectedToTerminal { - return printHumanPrPreview(opts.IO.Out, pr) + return printHumanPrPreview(opts.IO, pr) } return printRawPrPreview(opts.IO.Out, pr) } @@ -134,7 +136,9 @@ func printRawPrPreview(out io.Writer, pr *api.PullRequest) error { return nil } -func printHumanPrPreview(out io.Writer, pr *api.PullRequest) error { +func printHumanPrPreview(io *iostreams.IOStreams, pr *api.PullRequest) error { + out := io.Out + // Header (Title and State) fmt.Fprintln(out, utils.Bold(pr.Title)) fmt.Fprintf(out, "%s", shared.StateTitleWithColor(*pr)) @@ -172,7 +176,7 @@ func printHumanPrPreview(out io.Writer, pr *api.PullRequest) error { // Body if pr.Body != "" { fmt.Fprintln(out) - md, err := utils.RenderMarkdown(pr.Body) + md, err := markdown.Render(pr.Body, io.BgColor()) if err != nil { return err } diff --git a/pkg/cmd/release/view/view.go b/pkg/cmd/release/view/view.go index 8eb8ce03c..6e720291e 100644 --- a/pkg/cmd/release/view/view.go +++ b/pkg/cmd/release/view/view.go @@ -12,6 +12,7 @@ import ( "github.com/cli/cli/pkg/cmd/release/shared" "github.com/cli/cli/pkg/cmdutil" "github.com/cli/cli/pkg/iostreams" + "github.com/cli/cli/pkg/markdown" "github.com/cli/cli/utils" "github.com/spf13/cobra" ) @@ -122,7 +123,7 @@ func renderReleaseTTY(io *iostreams.IOStreams, release *shared.Release) error { fmt.Fprintf(w, "%s\n", iofmt.Gray(fmt.Sprintf("%s released this %s", release.Author.Login, utils.FuzzyAgo(time.Since(release.PublishedAt))))) } - renderedDescription, err := utils.RenderMarkdown(release.Body) + renderedDescription, err := markdown.Render(release.Body, io.ResolveBgColor()) if err != nil { return err } diff --git a/pkg/cmd/repo/view/view.go b/pkg/cmd/repo/view/view.go index e5dafa6fb..f3cab9925 100644 --- a/pkg/cmd/repo/view/view.go +++ b/pkg/cmd/repo/view/view.go @@ -14,6 +14,7 @@ import ( "github.com/cli/cli/internal/ghrepo" "github.com/cli/cli/pkg/cmdutil" "github.com/cli/cli/pkg/iostreams" + "github.com/cli/cli/pkg/markdown" "github.com/cli/cli/utils" "github.com/enescakir/emoji" "github.com/spf13/cobra" @@ -114,6 +115,8 @@ func viewRun(opts *ViewOptions) error { return err } + opts.IO.ResolveBgColor() + err = opts.IO.StartPager() if err != nil { return err @@ -153,7 +156,7 @@ func viewRun(opts *ViewOptions) error { readmeContent = utils.Gray("This repository does not have a README") } else if isMarkdownFile(readme.Filename) { var err error - readmeContent, err = utils.RenderMarkdown(readme.Content) + readmeContent, err = markdown.Render(readme.Content, opts.IO.BgColor()) if err != nil { return fmt.Errorf("error rendering markdown: %w", err) } diff --git a/pkg/iostreams/iostreams.go b/pkg/iostreams/iostreams.go index 968f06e06..d1d8fa14a 100644 --- a/pkg/iostreams/iostreams.go +++ b/pkg/iostreams/iostreams.go @@ -15,6 +15,7 @@ import ( "github.com/google/shlex" "github.com/mattn/go-colorable" "github.com/mattn/go-isatty" + "github.com/muesli/termenv" "golang.org/x/crypto/ssh/terminal" ) @@ -27,6 +28,7 @@ type IOStreams struct { originalOut io.Writer colorEnabled bool is256enabled bool + bgColor string progressIndicatorEnabled bool progressIndicator *spinner.Spinner @@ -52,6 +54,32 @@ func (s *IOStreams) ColorSupport256() bool { return s.is256enabled } +func (s *IOStreams) ResolveBgColor() string { + style := os.Getenv("GLAMOUR_STYLE") + if (!s.ColorEnabled()) || + (style != "" && style != "auto") || + (s.pagerProcess != nil) { + s.bgColor = "none" + return "none" + } + + if termenv.HasDarkBackground() { + s.bgColor = "dark" + return "dark" + } + + s.bgColor = "light" + return "light" +} + +func (s *IOStreams) BgColor() string { + if s.bgColor == "" { + return "none" + } + + return s.bgColor +} + func (s *IOStreams) SetStdinTTY(isTTY bool) { s.stdinTTYOverride = true s.stdinIsTTY = isTTY diff --git a/pkg/markdown/markdown.go b/pkg/markdown/markdown.go new file mode 100644 index 000000000..5854cd265 --- /dev/null +++ b/pkg/markdown/markdown.go @@ -0,0 +1,38 @@ +package markdown + +import ( + "os" + "strings" + + "github.com/charmbracelet/glamour" +) + +func Render(text string, bgColor string) (string, error) { + // Glamour rendering preserves carriage return characters in code blocks, but + // we need to ensure that no such characters are present in the output. + text = strings.ReplaceAll(text, "\r\n", "\n") + + tr, err := glamour.NewTermRenderer( + glamour.WithStylePath(getEnvironmentStyle(bgColor)), + // glamour.WithBaseURL(""), // TODO: make configurable + // glamour.WithWordWrap(80), // TODO: make configurable + ) + if err != nil { + return "", err + } + + return tr.Render(text) +} + +func getEnvironmentStyle(bgColor string) string { + style := os.Getenv("GLAMOUR_STYLE") + if style != "" && style != "auto" { + return style + } + + if bgColor == "light" || bgColor == "dark" { + return bgColor + } + + return "notty" +} diff --git a/utils/utils.go b/utils/utils.go index 0e36f4824..379ecc08b 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -8,7 +8,6 @@ import ( "time" "github.com/briandowns/spinner" - "github.com/charmbracelet/glamour" "github.com/cli/cli/internal/run" "github.com/cli/cli/pkg/browser" ) @@ -29,29 +28,6 @@ func OpenInBrowser(url string) error { return err } -func RenderMarkdown(text string) (string, error) { - // Glamour rendering preserves carriage return characters in code blocks, but - // we need to ensure that no such characters are present in the output. - text = strings.ReplaceAll(text, "\r\n", "\n") - - renderStyle := glamour.WithStandardStyle("notty") - // TODO: make color an input parameter - if isColorEnabled() { - renderStyle = glamour.WithEnvironmentConfig() - } - - tr, err := glamour.NewTermRenderer( - renderStyle, - // glamour.WithBaseURL(""), // TODO: make configurable - // glamour.WithWordWrap(80), // TODO: make configurable - ) - if err != nil { - return "", err - } - - return tr.Render(text) -} - func Pluralize(num int, thing string) string { if num == 1 { return fmt.Sprintf("%d %s", num, thing)