From b5d8849c06de3d0ea410e0ba03e66b101b1ec626 Mon Sep 17 00:00:00 2001 From: Elwardi Date: Sat, 7 Aug 2021 16:06:36 +0100 Subject: [PATCH 1/3] Support match colors in `labelFormat` entry in menuFromCommand prompts --- docs/Custom_Command_Keybindings.md | 8 +++++--- pkg/gui/custom_commands.go | 7 ++++++- pkg/gui/style/basic_styles.go | 15 +++++++++++++++ pkg/theme/style.go | 19 +++---------------- 4 files changed, 29 insertions(+), 20 deletions(-) diff --git a/docs/Custom_Command_Keybindings.md b/docs/Custom_Command_Keybindings.md index c48442362..8b0c769c2 100644 --- a/docs/Custom_Command_Keybindings.md +++ b/docs/Custom_Command_Keybindings.md @@ -48,7 +48,7 @@ customCommands: command: 'git branch -r --list {{index .PromptResponses 0}}/*' filter: '.*{{index .PromptResponses 0}}/(?P.*)' valueFormat: '{{ .branch }}' - labelFormat: '' + labelFormat: '{{ .branch | green }}' ``` Looking at the command assigned to the 'n' key, here's what the result looks like: @@ -110,8 +110,10 @@ The permitted prompt fields are: | | PS: named groups keep first match only | | | labelFormat | (only applicable to 'menuFromCommand' prompts) how to format matched groups from | no | | | the filter to construct the item's label (What's shown on screen). You can use | | -| | named groups, or `{{ .group_GROUPID }}`. If this is not specified, `valueFormat` | | -| | is shown instead. | | +| | named groups, or `{{ .group_GROUPID }}`. You can also color each match with | | +| | `{{ .group_GROUPID | colorname }}` (Color names from | | +| | [here](https://github.com/jesseduffield/lazygit/blob/master/docs/Config.md)) | | +| | If `labelFormat` is not specified, `valueFormat` is shown instead. | | | | PS: named groups keep first match only | | The permitted option fields are: diff --git a/pkg/gui/custom_commands.go b/pkg/gui/custom_commands.go index a9795f7b6..d43f028cb 100644 --- a/pkg/gui/custom_commands.go +++ b/pkg/gui/custom_commands.go @@ -136,7 +136,12 @@ func (gui *Gui) GenerateMenuCandidates(commandOutput, filter, valueFormat, label return nil, gui.surfaceError(errors.New("unable to parse value format, error: " + err.Error())) } - descTemp, err := template.New("format").Parse(labelFormat) + colorFuncMap := template.FuncMap{} + for k, v := range style.ColorMap { + colorFuncMap[k] = v.Foreground.Sprint + } + + descTemp, err := template.New("format").Funcs(colorFuncMap).Parse(labelFormat) if err != nil { return nil, gui.surfaceError(errors.New("unable to parse label format, error: " + err.Error())) } diff --git a/pkg/gui/style/basic_styles.go b/pkg/gui/style/basic_styles.go index ef29904bc..373172a8b 100644 --- a/pkg/gui/style/basic_styles.go +++ b/pkg/gui/style/basic_styles.go @@ -27,6 +27,21 @@ var ( AttrUnderline = New().SetUnderline() AttrBold = New().SetBold() + + ColorMap = map[string]struct { + Foreground TextStyle + Background TextStyle + }{ + "default": {FgWhite, BgBlack}, + "black": {FgBlack, BgBlack}, + "red": {FgRed, BgRed}, + "green": {FgGreen, BgGreen}, + "yellow": {FgYellow, BgYellow}, + "blue": {FgBlue, BgBlue}, + "magenta": {FgMagenta, BgMagenta}, + "cyan": {FgCyan, BgCyan}, + "white": {FgWhite, BgWhite}, + } ) func FromBasicFg(fg color.Color) TextStyle { diff --git a/pkg/theme/style.go b/pkg/theme/style.go index ba014681a..8f607256d 100644 --- a/pkg/theme/style.go +++ b/pkg/theme/style.go @@ -6,20 +6,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/utils" ) -var colorMap = map[string]struct { - foreground style.TextStyle - background style.TextStyle -}{ - "default": {style.FgWhite, style.BgBlack}, - "black": {style.FgBlack, style.BgBlack}, - "red": {style.FgRed, style.BgRed}, - "green": {style.FgGreen, style.BgGreen}, - "yellow": {style.FgYellow, style.BgYellow}, - "blue": {style.FgBlue, style.BgBlue}, - "magenta": {style.FgMagenta, style.BgMagenta}, - "cyan": {style.FgCyan, style.BgCyan}, - "white": {style.FgWhite, style.BgWhite}, -} +var colorMap = style.ColorMap func GetTextStyle(keys []string, background bool) style.TextStyle { s := style.New() @@ -37,9 +24,9 @@ func GetTextStyle(keys []string, background bool) style.TextStyle { if present { var c style.TextStyle if background { - c = value.background + c = value.Background } else { - c = value.foreground + c = value.Foreground } s = s.MergeStyle(c) } else if utils.IsValidHexValue(key) { From e8e4fa59572915f669c5daf272bb5721f53de2d7 Mon Sep 17 00:00:00 2001 From: Elwardi Date: Mon, 9 Aug 2021 11:52:00 +0100 Subject: [PATCH 2/3] Add color functions to templates funcMaps --- pkg/gui/custom_commands.go | 5 +---- pkg/gui/style/basic_styles.go | 10 ++++++++++ pkg/theme/style.go | 4 +--- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/pkg/gui/custom_commands.go b/pkg/gui/custom_commands.go index d43f028cb..8f98d6597 100644 --- a/pkg/gui/custom_commands.go +++ b/pkg/gui/custom_commands.go @@ -136,10 +136,7 @@ func (gui *Gui) GenerateMenuCandidates(commandOutput, filter, valueFormat, label return nil, gui.surfaceError(errors.New("unable to parse value format, error: " + err.Error())) } - colorFuncMap := template.FuncMap{} - for k, v := range style.ColorMap { - colorFuncMap[k] = v.Foreground.Sprint - } + colorFuncMap := style.TemplateFuncMapAddColors(template.FuncMap{}) descTemp, err := template.New("format").Funcs(colorFuncMap).Parse(labelFormat) if err != nil { diff --git a/pkg/gui/style/basic_styles.go b/pkg/gui/style/basic_styles.go index 373172a8b..92b034f06 100644 --- a/pkg/gui/style/basic_styles.go +++ b/pkg/gui/style/basic_styles.go @@ -2,6 +2,7 @@ package style import ( "github.com/gookit/color" + "text/template" ) var ( @@ -51,3 +52,12 @@ func FromBasicFg(fg color.Color) TextStyle { func FromBasicBg(bg color.Color) TextStyle { return New().SetBg(NewBasicColor(bg)) } + +func TemplateFuncMapAddColors(m template.FuncMap) template.FuncMap { + for k, v := range ColorMap { + m[k] = v.Foreground.Sprint + } + m["underline"] = color.OpUnderscore.Sprint + m["bold"] = color.OpBold.Sprint + return m +} diff --git a/pkg/theme/style.go b/pkg/theme/style.go index 8f607256d..69c404e3b 100644 --- a/pkg/theme/style.go +++ b/pkg/theme/style.go @@ -6,8 +6,6 @@ import ( "github.com/jesseduffield/lazygit/pkg/utils" ) -var colorMap = style.ColorMap - func GetTextStyle(keys []string, background bool) style.TextStyle { s := style.New() @@ -20,7 +18,7 @@ func GetTextStyle(keys []string, background bool) style.TextStyle { case "underline": s = s.SetUnderline() default: - value, present := colorMap[key] + value, present := style.ColorMap[key] if present { var c style.TextStyle if background { From e58376f9f7e81ec5744d667a47fe6670e7a360a4 Mon Sep 17 00:00:00 2001 From: mjarkk Date: Mon, 9 Aug 2021 21:09:52 +0200 Subject: [PATCH 3/3] add tests for TemplateFuncMapAddColors --- pkg/gui/style/style_test.go | 52 +++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/pkg/gui/style/style_test.go b/pkg/gui/style/style_test.go index 298dae843..8298076a5 100644 --- a/pkg/gui/style/style_test.go +++ b/pkg/gui/style/style_test.go @@ -1,7 +1,9 @@ package style import ( + "bytes" "testing" + "text/template" "github.com/gookit/color" "github.com/stretchr/testify/assert" @@ -157,3 +159,53 @@ func TestMerge(t *testing.T) { }) } } + +func TestTemplateFuncMapAddColors(t *testing.T) { + type scenario struct { + name string + tmpl string + expect string + } + + scenarios := []scenario{ + { + "normal template", + "{{ .Foo }}", + "bar", + }, + { + "colored string", + "{{ .Foo | red }}", + "\x1b[31mbar\x1b[0m", + }, + { + "string with decorator", + "{{ .Foo | bold }}", + "\x1b[1mbar\x1b[0m", + }, + { + "string with color and decorator", + "{{ .Foo | bold | red }}", + "\x1b[31m\x1b[1mbar\x1b[0m\x1b[0m", + }, + { + "multiple string with diffrent colors", + "{{ .Foo | red }} - {{ .Foo | blue }}", + "\x1b[31mbar\x1b[0m - \x1b[34mbar\x1b[0m", + }, + } + + for _, s := range scenarios { + s := s + t.Run(s.name, func(t *testing.T) { + tmpl, err := template.New("test template").Funcs(TemplateFuncMapAddColors(template.FuncMap{})).Parse(s.tmpl) + assert.NoError(t, err) + + buff := bytes.NewBuffer(nil) + err = tmpl.Execute(buff, struct{ Foo string }{"bar"}) + assert.NoError(t, err) + + assert.Equal(t, s.expect, buff.String()) + }) + } +}