mirror of
https://github.com/charmbracelet/glow.git
synced 2026-08-19 22:54:17 +02:00
Merge a020293fc2 into 53788271b3
This commit is contained in:
commit
56bf64686d
4 changed files with 129 additions and 4 deletions
|
|
@ -173,6 +173,12 @@ either the `dark` or the `light` style for you.
|
|||
glow -s [dark|light]
|
||||
```
|
||||
|
||||
For piped output, use `--color=always` to keep colorized output even when stdout is not a terminal.
|
||||
|
||||
```bash
|
||||
glow --color=always
|
||||
```
|
||||
|
||||
Alternatively you can also supply a custom JSON stylesheet:
|
||||
|
||||
```bash
|
||||
|
|
@ -201,6 +207,8 @@ Here's an example config:
|
|||
```yaml
|
||||
# style name or JSON path (default "auto")
|
||||
style: "light"
|
||||
# colorize output when piped (auto|always)
|
||||
color: "auto"
|
||||
# mouse wheel support (TUI-mode only)
|
||||
mouse: true
|
||||
# use pager to display markdown
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ import (
|
|||
|
||||
const defaultConfig = `# style name or JSON path (default "auto")
|
||||
style: "auto"
|
||||
# colorize output when piped (auto|always)
|
||||
color: "auto"
|
||||
# mouse support (TUI-mode only)
|
||||
mouse: false
|
||||
# use pager to display markdown
|
||||
|
|
|
|||
75
glow_test.go
75
glow_test.go
|
|
@ -2,6 +2,9 @@ package main
|
|||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/charmbracelet/glamour/styles"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
)
|
||||
|
||||
func TestGlowFlags(t *testing.T) {
|
||||
|
|
@ -27,6 +30,12 @@ func TestGlowFlags(t *testing.T) {
|
|||
return width == 40
|
||||
},
|
||||
},
|
||||
{
|
||||
args: []string{"--color", "always"},
|
||||
check: func() bool {
|
||||
return colorMode == "always"
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, v := range tt {
|
||||
|
|
@ -39,3 +48,69 @@ func TestGlowFlags(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestShouldUseNoTTYStyle(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
mode string
|
||||
isTerminal bool
|
||||
styleFlag bool
|
||||
expectNoTTY bool
|
||||
}{
|
||||
{name: "auto non-terminal", mode: "auto", isTerminal: false, expectNoTTY: true},
|
||||
{name: "always non-terminal", mode: "always", isTerminal: false, expectNoTTY: false},
|
||||
{name: "auto terminal", mode: "auto", isTerminal: true, expectNoTTY: false},
|
||||
{name: "auto style flag set", mode: "auto", isTerminal: false, styleFlag: true, expectNoTTY: false},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if got := shouldUseNoTTYStyle(tc.mode, tc.isTerminal, tc.styleFlag); got != tc.expectNoTTY {
|
||||
t.Fatalf("shouldUseNoTTYStyle(%q, %v, %v) = %v, want %v", tc.mode, tc.isTerminal, tc.styleFlag, got, tc.expectNoTTY)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveStyleForColorMode(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
mode string
|
||||
currentStyle string
|
||||
isTerminal bool
|
||||
styleFlag bool
|
||||
expectStyle string
|
||||
}{
|
||||
{name: "auto non-terminal keeps auto when style explicit", mode: "always", currentStyle: "dark", isTerminal: false, styleFlag: true, expectStyle: "dark"},
|
||||
{name: "auto terminal keeps auto", mode: "always", currentStyle: styles.AutoStyle, isTerminal: true, expectStyle: styles.AutoStyle},
|
||||
{name: "auto mode keeps auto", mode: "auto", currentStyle: styles.AutoStyle, isTerminal: false, expectStyle: styles.AutoStyle},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if got := resolveStyleForColorMode(tc.mode, tc.currentStyle, tc.isTerminal, tc.styleFlag); got != tc.expectStyle {
|
||||
t.Fatalf("resolveStyleForColorMode(%q, %q, %v, %v) = %q, want %q", tc.mode, tc.currentStyle, tc.isTerminal, tc.styleFlag, got, tc.expectStyle)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
want := styles.DarkStyle
|
||||
if !lipgloss.HasDarkBackground() {
|
||||
want = styles.LightStyle
|
||||
}
|
||||
if got := resolveStyleForColorMode("always", styles.AutoStyle, false, false); got != want {
|
||||
t.Fatalf("resolveStyleForColorMode(always, auto, false, false) = %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateColorMode(t *testing.T) {
|
||||
if err := validateColorMode("auto"); err != nil {
|
||||
t.Fatalf("expected auto to be valid: %v", err)
|
||||
}
|
||||
if err := validateColorMode("always"); err != nil {
|
||||
t.Fatalf("expected always to be valid: %v", err)
|
||||
}
|
||||
if err := validateColorMode("never"); err == nil {
|
||||
t.Fatal("expected never to be invalid")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
48
main.go
48
main.go
|
|
@ -23,6 +23,7 @@ import (
|
|||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/charmbracelet/log"
|
||||
gap "github.com/muesli/go-app-paths"
|
||||
"github.com/muesli/termenv"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"golang.org/x/term"
|
||||
|
|
@ -44,6 +45,7 @@ var (
|
|||
showLineNumbers bool
|
||||
preserveNewLines bool
|
||||
mouse bool
|
||||
colorMode string
|
||||
|
||||
rootCmd = &cobra.Command{
|
||||
Use: "glow [SOURCE|DIR]",
|
||||
|
|
@ -164,8 +166,36 @@ func validateStyle(style string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func validateColorMode(mode string) error {
|
||||
switch mode {
|
||||
case "auto", "always":
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("invalid color mode %q: must be one of auto or always", mode)
|
||||
}
|
||||
}
|
||||
|
||||
func resolveStyleForColorMode(mode string, currentStyle string, isTerminal bool, styleFlagChanged bool) string {
|
||||
if mode != "always" || styleFlagChanged || currentStyle != styles.AutoStyle || isTerminal {
|
||||
return currentStyle
|
||||
}
|
||||
if lipgloss.HasDarkBackground() {
|
||||
return styles.DarkStyle
|
||||
}
|
||||
return styles.LightStyle
|
||||
}
|
||||
|
||||
func shouldUseNoTTYStyle(mode string, isTerminal bool, styleFlagChanged bool) bool {
|
||||
return mode != "always" && !isTerminal && !styleFlagChanged
|
||||
}
|
||||
|
||||
func validateOptions(cmd *cobra.Command) error {
|
||||
// grab config values from Viper
|
||||
colorMode = viper.GetString("color")
|
||||
if err := validateColorMode(colorMode); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
width = viper.GetUint("width")
|
||||
mouse = viper.GetBool("mouse")
|
||||
pager = viper.GetBool("pager")
|
||||
|
|
@ -185,10 +215,12 @@ func validateOptions(cmd *cobra.Command) error {
|
|||
}
|
||||
|
||||
isTerminal := term.IsTerminal(int(os.Stdout.Fd()))
|
||||
styleFlagChanged := cmd.Flags().Changed("style")
|
||||
style = resolveStyleForColorMode(colorMode, style, isTerminal, styleFlagChanged)
|
||||
// We want to use a special no-TTY style, when stdout is not a terminal
|
||||
// and there was no specific style passed by arg
|
||||
if !isTerminal && !cmd.Flags().Changed("style") {
|
||||
style = "notty"
|
||||
// and there was no specific style passed by arg.
|
||||
if shouldUseNoTTYStyle(colorMode, isTerminal, styleFlagChanged) {
|
||||
style = styles.NoTTYStyle
|
||||
}
|
||||
|
||||
// Detect terminal width
|
||||
|
|
@ -290,9 +322,14 @@ func executeCLI(cmd *cobra.Command, src *source, w io.Writer) error {
|
|||
|
||||
isCode := !utils.IsMarkdownFile(src.URL)
|
||||
|
||||
colorProfile := lipgloss.ColorProfile()
|
||||
if colorMode == "always" {
|
||||
colorProfile = termenv.TrueColor
|
||||
}
|
||||
|
||||
// initialize glamour
|
||||
r, err := glamour.NewTermRenderer(
|
||||
glamour.WithColorProfile(lipgloss.ColorProfile()),
|
||||
glamour.WithColorProfile(colorProfile),
|
||||
utils.GlamourStyle(style, isCode),
|
||||
glamour.WithWordWrap(int(width)), //nolint:gosec
|
||||
glamour.WithBaseURL(baseURL),
|
||||
|
|
@ -403,6 +440,7 @@ func init() {
|
|||
rootCmd.Flags().BoolVarP(&pager, "pager", "p", false, "display with pager")
|
||||
rootCmd.Flags().BoolVarP(&tui, "tui", "t", false, "display with tui")
|
||||
rootCmd.Flags().StringVarP(&style, "style", "s", styles.AutoStyle, "style name or JSON path")
|
||||
rootCmd.Flags().StringVar(&colorMode, "color", "auto", "when to enable colors (auto|always)")
|
||||
rootCmd.Flags().UintVarP(&width, "width", "w", 0, "word-wrap at width (set to 0 to disable)")
|
||||
rootCmd.Flags().BoolVarP(&showAllFiles, "all", "a", false, "show system files and directories (TUI-mode only)")
|
||||
rootCmd.Flags().BoolVarP(&showLineNumbers, "line-numbers", "l", false, "show line numbers (TUI-mode only)")
|
||||
|
|
@ -414,6 +452,7 @@ func init() {
|
|||
_ = viper.BindPFlag("pager", rootCmd.Flags().Lookup("pager"))
|
||||
_ = viper.BindPFlag("tui", rootCmd.Flags().Lookup("tui"))
|
||||
_ = viper.BindPFlag("style", rootCmd.Flags().Lookup("style"))
|
||||
_ = viper.BindPFlag("color", rootCmd.Flags().Lookup("color"))
|
||||
_ = viper.BindPFlag("width", rootCmd.Flags().Lookup("width"))
|
||||
_ = viper.BindPFlag("debug", rootCmd.Flags().Lookup("debug"))
|
||||
_ = viper.BindPFlag("mouse", rootCmd.Flags().Lookup("mouse"))
|
||||
|
|
@ -422,6 +461,7 @@ func init() {
|
|||
_ = viper.BindPFlag("all", rootCmd.Flags().Lookup("all"))
|
||||
|
||||
viper.SetDefault("style", styles.AutoStyle)
|
||||
viper.SetDefault("color", "auto")
|
||||
viper.SetDefault("width", 0)
|
||||
viper.SetDefault("all", true)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue