Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

config: option for overrides to chroma styles #32

Merged
merged 1 commit into from
Jan 7, 2023
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
24 changes: 20 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Flags:
-v, --version version for jqp
```

`jqp` also supports input from STDIN.
`jqp` also supports input from STDIN. STDIN takes precedence over the command line flag.

```
➜ curl "https://api.github.com/repos/stedolan/jq/issues?per_page=2" | jqp
Expand Down Expand Up @@ -97,20 +97,36 @@ If a configuration option is present in both the configuration file and the comm
### Available Configuration Options

```yaml
theme: "nord" # controls the color scheme
file: "/path/to/input/file.json" # stdin takes precedence over command line flag and this option
theme:
name: "nord" # controls the color scheme
chromaStyleOverrides: # override parts of the chroma style
kc: "#009900 underline" # keys use the chroma short names
```

## Themes

Themes can be specified on the command line via the `-t/--theme <themeName>` flag. You can also set a theme in your [configuration file](#configuration).

```yaml
theme: "monokai"
theme:
name: "monokai"
```

<img width="1624" alt="Screen Shot 2022-10-02 at 5 31 40 PM" src="https://user-images.githubusercontent.com/23270779/193477383-db5ca769-12bf-4fd0-b826-b1fd4086eac3.png">

### Chroma Style Overrides

Overrides to the chroma styles used for a theme can be configured in your [configuration file](#configuration).

For the list of short keys, see [`chroma.StandardTypes`](https://github.com/alecthomas/chroma/blob/d38b87110b078027006bc34aa27a065fa22295a1/types.go#L210-L308). To see which token to use for a value, see the [JSON lexer](https://github.com/alecthomas/chroma/blob/master/lexers/embedded/json.xml) (look for `<token>` tags). To see the color and what's used in the style you're using, look for your style in the chroma [styles directory](https://github.com/alecthomas/chroma/tree/master/styles).

```yaml
theme:
name: "monokai" # name is required to know which theme to override
chromaStyleOverrides:
kc: "#009900 underline"
```

Themes are broken up into [light](#light-themes) and [dark](#dark-themes) themes. Light themes work best in terminals with a light background and dark themes work best in a terminal with a dark background. If no theme is specified or a non-existant theme is provided, the default theme is used, which was created to work with both terminals with a light and dark background.

### Light Themes
Expand Down
52 changes: 37 additions & 15 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import (
"fmt"
"os"

"github.com/alecthomas/chroma/v2"
"github.com/charmbracelet/bubbletea"
"github.com/noahgorstein/jqp/tui/bubbles/jqplayground"
"github.com/noahgorstein/jqp/tui/theme"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/spf13/viper"
)

Expand All @@ -20,14 +20,33 @@ var rootCmd = &cobra.Command{
Long: `jqp is a TUI to explore the jq command line utility`,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
configTheme := viper.GetString(configKeysName.themeName)
if !cmd.Flags().Changed(flagsName.theme) {
flags.theme = configTheme
}
themeOverrides := viper.GetStringMapString(configKeysName.themeOverrides)

jqtheme, defaultTheme := theme.GetTheme(flags.theme)
// If not using the default theme,
// and if theme specified is the same as in the config,
// which happens if the theme flag was used,
// apply chroma style overrides.
if !defaultTheme && configTheme == flags.theme && len(themeOverrides) > 0 {
// Reverse chroma.StandardTypes to be keyed by short string
chromaTypes := make(map[string]chroma.TokenType)
for tokenType, short := range chroma.StandardTypes {
chromaTypes[short] = tokenType
}

cmd.Flags().VisitAll(func(f *pflag.Flag) {
// Apply the viper config value to the flag when the flag is not set and viper has a value
if !f.Changed && viper.IsSet(f.Name) {
val := viper.Get(f.Name)
cmd.Flags().Set(f.Name, fmt.Sprintf("%v", val))
builder := jqtheme.ChromaStyle.Builder()
for k, v := range themeOverrides {
builder.Add(chromaTypes[k], v)
}
})
style, err := builder.Build()
if err == nil {
jqtheme.ChromaStyle = style
}
}

if isInputFromPipe() {
stdin := streamToBytes(os.Stdin)
Expand All @@ -37,7 +56,7 @@ var rootCmd = &cobra.Command{
return errors.New("JSON is not valid")
}

bubble := jqplayground.New(stdin, "STDIN", theme.GetTheme(flags.theme))
bubble := jqplayground.New(stdin, "STDIN", jqtheme)
p := tea.NewProgram(bubble, tea.WithAltScreen())
if err := p.Start(); err != nil {
return err
Expand Down Expand Up @@ -69,7 +88,7 @@ var rootCmd = &cobra.Command{
return err
}

bubble := jqplayground.New(data, fi.Name(), theme.GetTheme(flags.theme))
bubble := jqplayground.New(data, fi.Name(), jqtheme)
p := tea.NewProgram(bubble, tea.WithAltScreen())

if err := p.Start(); err != nil {
Expand Down Expand Up @@ -107,22 +126,25 @@ func initConfig() {
}

var flags struct {
filepath string
theme string
filepath, theme string
}

var flagsName = struct {
file string
fileShort string
theme string
themeShort string
file, fileShort, theme, themeShort string
}{
file: "file",
fileShort: "f",
theme: "theme",
themeShort: "t",
}

var configKeysName = struct {
themeName, themeOverrides string
}{
themeName: "theme.name",
themeOverrides: "theme.chromaStyleOverrides",
}

var cfgFile string

func Execute() {
Expand Down
7 changes: 3 additions & 4 deletions tui/bubbles/inputdata/inputdata.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"strings"

"github.com/alecthomas/chroma/v2"
"github.com/alecthomas/chroma/v2/quick"
"github.com/charmbracelet/bubbles/viewport"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
Expand All @@ -34,7 +33,7 @@ func New(inputJson []byte, filename string, theme theme.Theme) Bubble {
Styles: styles,
viewport: v,
inputJson: inputJson,
highlightedJson: highlightInputJson(inputJson, *theme.ChromaStyle),
highlightedJson: highlightInputJson(inputJson, theme.ChromaStyle),
filename: filename,
}
return b
Expand All @@ -45,7 +44,7 @@ func (b *Bubble) SetBorderColor(color lipgloss.TerminalColor) {
b.Styles.infoStyle.BorderForeground(color)
}

func highlightInputJson(inputJson []byte, chromaStyle chroma.Style) *bytes.Buffer {
func highlightInputJson(inputJson []byte, chromaStyle *chroma.Style) *bytes.Buffer {
var f interface{}
// TODO: error handling
json.Unmarshal(inputJson, &f)
Expand All @@ -55,7 +54,7 @@ func highlightInputJson(inputJson []byte, chromaStyle chroma.Style) *bytes.Buffe
json.Indent(&prettyJSON, []byte(inputJson), "", " ")

buf := new(bytes.Buffer)
quick.Highlight(buf, prettyJSON.String(), "json", utils.GetTerminalColorSupport(), chromaStyle.Name)
utils.HighlightJson(buf, prettyJSON.String(), chromaStyle)

return buf
}
Expand Down
2 changes: 1 addition & 1 deletion tui/bubbles/jqplayground/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func (b *Bubble) executeQuery(ctx context.Context) tea.Cmd {
results.WriteString(fmt.Sprintf("%s\n", string(r)))
}

highlightedOutput := highlightJson([]byte(results.String()), *b.theme.ChromaStyle)
highlightedOutput := highlightJson([]byte(results.String()), b.theme.ChromaStyle)
return queryResultMsg{
rawResults: results.String(),
highlightedResults: highlightedOutput.String(),
Expand Down
7 changes: 3 additions & 4 deletions tui/bubbles/jqplayground/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"encoding/json"

"github.com/alecthomas/chroma/v2"
"github.com/alecthomas/chroma/v2/quick"
"github.com/noahgorstein/jqp/tui/utils"
)

Expand All @@ -14,18 +13,18 @@ func isValidJson(input []byte) bool {
return json.Unmarshal(input, &js) == nil
}

func highlightJson(input []byte, chromaStyle chroma.Style) *bytes.Buffer {
func highlightJson(input []byte, chromaStyle *chroma.Style) *bytes.Buffer {

if isValidJson(input) {
var f interface{}
json.Unmarshal(input, &f)
var prettyJSON bytes.Buffer
json.Indent(&prettyJSON, []byte(input), "", " ")
buf := new(bytes.Buffer)
quick.Highlight(buf, prettyJSON.String(), "json", utils.GetTerminalColorSupport(), chromaStyle.Name)
utils.HighlightJson(buf, prettyJSON.String(), chromaStyle)
return buf
}
buf := new(bytes.Buffer)
quick.Highlight(buf, string(input), "json", utils.GetTerminalColorSupport(), chromaStyle.Name)
utils.HighlightJson(buf, string(input), chromaStyle)
return buf
}
7 changes: 4 additions & 3 deletions tui/theme/theme.go
Original file line number Diff line number Diff line change
Expand Up @@ -427,11 +427,12 @@ var themeMap = map[string]Theme{
},
}

func GetTheme(theme string) Theme {
// returns a theme by name, and true if default theme was returned
func GetTheme(theme string) (Theme, bool) {
lowercasedTheme := strings.ToLower(strings.TrimSpace(theme))
if value, ok := themeMap[lowercasedTheme]; ok {
return value
return value, false
} else {
return getDefaultTheme()
return getDefaultTheme(), true
}
}
31 changes: 30 additions & 1 deletion tui/utils/utils.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,41 @@
package utils

import (
"io"

"github.com/alecthomas/chroma/v2"
"github.com/alecthomas/chroma/v2/formatters"
"github.com/alecthomas/chroma/v2/lexers"
"github.com/alecthomas/chroma/v2/styles"
"github.com/charmbracelet/lipgloss"
"github.com/muesli/termenv"
)

func HighlightJson(w io.Writer, source string, style *chroma.Style) error {
l := lexers.Get("json")
if l == nil {
l = lexers.Fallback
}
l = chroma.Coalesce(l)

f := formatters.Get(getTerminalColorSupport())
if f == nil {
f = formatters.Fallback
}

if style == nil {
style = styles.Fallback
}

it, err := l.Tokenise(nil, source)
if err != nil {
return err
}
return f.Format(w, style, it)
}

// returns a string used for chroma syntax highlighting
func GetTerminalColorSupport() string {
func getTerminalColorSupport() string {
switch lipgloss.ColorProfile() {
case termenv.Ascii:
return "terminal"
Expand Down