Repository: JanDeDobbeleer/oh-my-posh
Pull request #2303 (2022-05-22 07:13:43)

feat(windows): accent color
### Prerequisites

- [x] I have read and understood the [contributing guide][CONTRIBUTING.md]
- [x] The commit message follows the [conventional commits][cc] guidelines
- [x] Tests for the changes have been added (for bug fixes/features)
- [ ] Docs have been added/updated (for bug fixes/features)

### Description

https://github.com/JanDeDobbeleer/oh-my-posh/discussions/2302

https://user-images.githubusercontent.com/2492783/169683531-c84513fc-c5ac-4657-9d56-6a372e1ae486.mov




<!---

Tips:

If you're not comfortable with working with Git, we're working a guide (https://ohmyposh.dev/docs/contributing_git) to help you out.
Oh My Posh advises GitKraken (https://www.gitkraken.com/invite/nQmDPR9D) as your preferred cross platform Git GUI power tool.

-->

[CONTRIBUTING.md]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/CONTRIBUTING.md
[cc]: https://www.conventionalcommits.org/en/v1.0.0/#summary



Patch:
diff --git a/src/color/colors.go b/src/color/colors.go
index c2c9b204..3571a8c2 100644
--- a/src/color/colors.go
+++ b/src/color/colors.go
@@ -6,8 +6,10 @@ import (
 	"github.com/gookit/color"
 )
 
-func MakeColors(palette Palette, cacheEnabled bool) (colors AnsiColors) {
-	colors = &DefaultColors{}
+func MakeColors(palette Palette, cacheEnabled bool, accentColor string) (colors AnsiColors) {
+	defaultColors := &DefaultColors{}
+	defaultColors.SetAccentColor(accentColor)
+	colors = defaultColors
 	if palette != nil {
 		colors = &PaletteColors{ansiColors: colors, palette: palette}
 	}
@@ -18,7 +20,9 @@ func MakeColors(palette Palette, cacheEnabled bool) (colors AnsiColors) {
 }
 
 // DefaultColors is the default AnsiColors implementation.
-type DefaultColors struct{}
+type DefaultColors struct {
+	accent *Color
+}
 
 var (
 	// Map for color names and their respective foreground [0] or background [1] color codes
@@ -48,13 +52,22 @@ const (
 	backgroundIndex = 1
 )
 
-func (*DefaultColors) AnsiColorFromString(colorString string, isBackground bool) AnsiColor {
+func (d *DefaultColors) AnsiColorFromString(colorString string, isBackground bool) AnsiColor {
 	if len(colorString) == 0 {
 		return emptyAnsiColor
 	}
 	if colorString == Transparent {
 		return transparentAnsiColor
 	}
+	if colorString == Accent {
+		if d.accent == nil {
+			return emptyAnsiColor
+		}
+		if isBackground {
+			return AnsiColor(d.accent.Background)
+		}
+		return AnsiColor(d.accent.Foreground)
+	}
 	colorFromName, err := getAnsiColorFromName(colorString, isBackground)
 	if err == nil {
 		return colorFromName
diff --git a/src/color/colors_unix.go b/src/color/colors_unix.go
new file mode 100644
index 00000000..55835782
--- /dev/null
+++ b/src/color/colors_unix.go
@@ -0,0 +1,13 @@
+//go:build !windows
+
+package color
+
+func (d *DefaultColors) SetAccentColor(defaultColor string) {
+	if len(defaultColor) == 0 {
+		return
+	}
+	d.accent = &Color{
+		Foreground: string(d.AnsiColorFromString(defaultColor, false)),
+		Background: string(d.AnsiColorFromString(defaultColor, true)),
+	}
+}
diff --git a/src/color/colors_windows.go b/src/color/colors_windows.go
new file mode 100644
index 00000000..2fd003e8
--- /dev/null
+++ b/src/color/colors_windows.go
@@ -0,0 +1,38 @@
+package color
+
+import (
+	"syscall"
+	"unsafe"
+
+	"github.com/gookit/color"
+	"golang.org/x/sys/windows"
+)
+
+var (
+	dwmapi                      = syscall.NewLazyDLL("dwmapi.dll")
+	procDwmGetColorizationColor = dwmapi.NewProc("DwmGetColorizationColor")
+)
+
+func (d *DefaultColors) SetAccentColor(defaultColor string) {
+	var accentColor uint32
+	var pfOpaqueBlend bool
+	_, _, e := procDwmGetColorizationColor.Call(
+		uintptr(unsafe.Pointer(&accentColor)),
+		uintptr(unsafe.Pointer(&pfOpaqueBlend)))
+	if e != windows.ERROR_SUCCESS {
+		d.accent = &Color{
+			Foreground: string(d.AnsiColorFromString(defaultColor, false)),
+			Background: string(d.AnsiColorFromString(defaultColor, true)),
+		}
+		return
+	}
+	r := byte(accentColor >> 16)
+	g := byte(accentColor >> 8)
+	b := byte(accentColor)
+	foreground := color.RGB(r, g, b, false)
+	background := color.RGB(r, g, b, true)
+	d.accent = &Color{
+		Foreground: foreground.String(),
+		Background: background.String(),
+	}
+}
diff --git a/src/color/writer.go b/src/color/writer.go
index b19a603a..163ae719 100644
--- a/src/color/writer.go
+++ b/src/color/writer.go
@@ -73,6 +73,8 @@ func (c AnsiColor) ToForeground() AnsiColor {
 const (
 	// Transparent implies a transparent color
 	Transparent = "transparent"
+	// Accent is the OS accent color
+	Accent = "accent"
 	// ParentBackground takes the previous segment's background color
 	ParentBackground = "parentBackground"
 	// ParentForeground takes the previous segment's color
diff --git a/src/engine/config.go b/src/engine/config.go
index 446f0806..b5028103 100644
--- a/src/engine/config.go
+++ b/src/engine/config.go
@@ -35,6 +35,7 @@ type Config struct {
 	OSC99                bool          `json:"osc99,omitempty"`
 	ConsoleTitleTemplate string        `json:"console_title_template,omitempty"`
 	TerminalBackground   string        `json:"terminal_background,omitempty"`
+	AccentColor          string        `json:"accent_color,omitempty"`
 	Blocks               []*Block      `json:"blocks,omitempty"`
 	Tooltips             []*Segment    `json:"tooltips,omitempty"`
 	TransientPrompt      *Segment      `json:"transient_prompt,omitempty"`
@@ -56,7 +57,7 @@ type Config struct {
 // environment and configuration.
 func (cfg *Config) MakeColors(env environment.Environment) color.AnsiColors {
 	cacheDisabled := env.Getenv("OMP_CACHE_DISABLED") == "1"
-	return color.MakeColors(cfg.Palette, !cacheDisabled)
+	return color.MakeColors(cfg.Palette, !cacheDisabled, cfg.AccentColor)
 }
 
 func (cfg *Config) print(message string) {
diff --git a/themes/schema.json b/themes/schema.json
index 999b863f..e8879625 100644
--- a/themes/schema.json
+++ b/themes/schema.json
@@ -17,7 +17,7 @@
     },
     "color_string": {
       "type": "string",
-      "pattern": "^(#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})|black|red|green|yellow|blue|magenta|cyan|white|default|darkGray|lightRed|lightGreen|lightYellow|lightBlue|lightMagenta|lightCyan|lightWhite|transparent|parentBackground|parentForeground|background|foreground)$",
+      "pattern": "^(#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})|black|red|green|yellow|blue|magenta|cyan|white|default|darkGray|lightRed|lightGreen|lightYellow|lightBlue|lightMagenta|lightCyan|lightWhite|transparent|parentBackground|parentForeground|background|foreground|accent)$",
       "title": "Color string",
       "description": "https://ohmyposh.dev/docs/configuration/colors",
       "format": "color"
@@ -2552,6 +2552,10 @@
           "$ref": "#/definitions/color"
         }
       }
+    },
+    "accent_color": {
+      "title": "Accent color",
+      "$ref": "#/definitions/color"
     }
   }
 }
diff --git a/website/docs/configuration/colors.md b/website/docs/configuration/colors.md
index 4f63c66b..952e9b20 100644
--- a/website/docs/configuration/colors.md
+++ b/website/docs/configuration/colors.md
@@ -10,20 +10,20 @@ Oh My Posh supports multiple different color references, being:
 
 - Typical [hex colors][hexcolors] (for example `#CB4B16`).
 - 16 [ANSI color names][ansicolors].
-- The `transparent` keyword which can be used to create either a transparent foreground override
-  or transparent background color using the segment's foreground property.
-- The `foreground` keyword which can be used to reference the current segment's foreground color.
-- The `background` keyword which can be used to reference the current segment's background color.
-- The `parentForeground` keyword which can be used to inherit the previous active segment's foreground color.
-- The `parentBackground` keyword which can be used to inherit the previous active segment's background color.
-
-  These include 8 basic ANSI colors and `default`:
+  These include 8 basic ANSI colors and `default`
 
   `black` `red` `green` `yellow` `blue` `magenta` `cyan` `white` `default`
 
   as well as 8 extended ANSI colors:
 
   `darkGray` `lightRed` `lightGreen` `lightYellow` `lightBlue` `lightMagenta` `lightCyan` `lightWhite`
+- The `transparent` keyword which can be used to create either a transparent foreground override
+  or transparent background color using the segment's foreground property.
+- The `foreground` keyword which can be used to reference the current segment's foreground color.
+- The `background` keyword which can be used to reference the current segment's background color.
+- The `parentForeground` keyword which can be used to inherit the previous active segment's foreground color.
+- The `parentBackground` keyword which can be used to inherit the previous active segment's background color.
+- The `accent` keyword which references the OS accent color (Windows only).
 
 ## Color templates
 
diff --git a/website/docs/configuration/overview.md b/website/docs/configuration/overview.md
index 30cbaf69..8b0d2680 100644
--- a/website/docs/configuration/overview.md
+++ b/website/docs/configuration/overview.md
@@ -69,8 +69,11 @@ For example, the following is a valid `--config` flag:
 - osc99: `boolean` - when true adds support for OSC9;9; (notify terminal of current working directory)
 - terminal_background: `string` [color][colors] - terminal background color, set to your terminal's background color when
 you notice black elements in Windows Terminal or the Visual Studio Code integrated terminal
+- accent_color: `string` [color][colors] - accent color, used as a fallback when the `accent` [color][accent] is not supported
 
 [releases]: https://github.com/JanDeDobbeleer/oh-my-posh/releases/latest
 [font]: /docs/configuration/fonts
 [schema]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/themes/schema.json
 [themes]: https://github.com/JanDeDobbeleer/oh-my-posh/tree/main/themes
+[colors]: /docs/configuration/colors
+[accent]: /docs/configuration/colors#standard-colors


Test patch:
diff --git a/src/color/colors_test.go b/src/color/colors_test.go
index 061e3c3e..7fdfc9d9 100644
--- a/src/color/colors_test.go
+++ b/src/color/colors_test.go
@@ -30,18 +30,18 @@ func TestGetAnsiFromColorString(t *testing.T) {
 }
 
 func TestMakeColors(t *testing.T) {
-	colors := MakeColors(nil, false)
+	colors := MakeColors(nil, false, "")
 	assert.IsType(t, &DefaultColors{}, colors)
 
-	colors = MakeColors(nil, true)
+	colors = MakeColors(nil, true, "")
 	assert.IsType(t, &CachedColors{}, colors)
 	assert.IsType(t, &DefaultColors{}, colors.(*CachedColors).ansiColors)
 
-	colors = MakeColors(testPalette, false)
+	colors = MakeColors(testPalette, false, "")
 	assert.IsType(t, &PaletteColors{}, colors)
 	assert.IsType(t, &DefaultColors{}, colors.(*PaletteColors).ansiColors)
 
-	colors = MakeColors(testPalette, true)
+	colors = MakeColors(testPalette, true, "")
 	assert.IsType(t, &CachedColors{}, colors)
 	assert.IsType(t, &PaletteColors{}, colors.(*CachedColors).ansiColors)
 	assert.IsType(t, &DefaultColors{}, colors.(*CachedColors).ansiColors.(*PaletteColors).ansiColors)