mirror of
https://github.com/JanDeDobbeleer/oh-my-posh.git
synced 2025-03-05 20:49:04 -08:00
parent
aa36303962
commit
00e62e4810
|
@ -103,8 +103,8 @@ understand how to configure a segment.
|
||||||
- invert_powerline: `boolean`
|
- invert_powerline: `boolean`
|
||||||
- leading_diamond: `string`
|
- leading_diamond: `string`
|
||||||
- trailing_diamond: `string`
|
- trailing_diamond: `string`
|
||||||
- foreground: `string` [hex color code][colors]
|
- foreground: `string` [color][colors]
|
||||||
- background: `string` [hex color code][colors]
|
- background: `string` [color][colors]
|
||||||
- properties: `array` of `Property`: `string`
|
- properties: `array` of `Property`: `string`
|
||||||
|
|
||||||
### Type
|
### Type
|
||||||
|
@ -205,8 +205,21 @@ do so like this:
|
||||||
"prefix": "<#CB4B16>┏[</>",
|
"prefix": "<#CB4B16>┏[</>",
|
||||||
```
|
```
|
||||||
|
|
||||||
Oh my Posh offers support for hex [colors][colors] as well as the `transparent` keyword to create either a transparent foreground
|
Oh my Posh mainly supports three different color types being
|
||||||
override or transparent background color using the segement's [foreground][fg] property.
|
* Typical [hex colors][hexcolors] (for example `#CB4B16`).
|
||||||
|
|
||||||
|
* The `transparent` keyword which can be used to create either a transparent foreground override
|
||||||
|
or transparent background color using the segement's foreground property.
|
||||||
|
|
||||||
|
* 16 [ANSI color names][ansicolors].
|
||||||
|
|
||||||
|
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`
|
||||||
|
|
||||||
## Full Sample
|
## Full Sample
|
||||||
|
|
||||||
|
@ -294,5 +307,7 @@ override or transparent background color using the segement's [foreground][fg] p
|
||||||
[releases]: https://github.com/JanDeDobbeleer/oh-my-posh3/releases/latest
|
[releases]: https://github.com/JanDeDobbeleer/oh-my-posh3/releases/latest
|
||||||
[nf]: https://www.nerdfonts.com/
|
[nf]: https://www.nerdfonts.com/
|
||||||
[segments]: /docs/battery
|
[segments]: /docs/battery
|
||||||
[colors]: https://htmlcolorcodes.com/color-chart/material-design-color-chart/
|
[colors]: #colors
|
||||||
|
[hexcolors]: https://htmlcolorcodes.com/color-chart/material-design-color-chart/
|
||||||
|
[ansicolors]: https://htmlcolorcodes.com/color-chart/material-design-color-chart/
|
||||||
[fg]: /docs/configure#foreground
|
[fg]: /docs/configure#foreground
|
||||||
|
|
|
@ -39,8 +39,8 @@ Battery displays the remaining power percentage for your battery.
|
||||||
- discharging_icon: `string` - icon to display on the left when discharging - defaults to empty
|
- discharging_icon: `string` - icon to display on the left when discharging - defaults to empty
|
||||||
- charged_icon: `string` - icon to display on the left when fully charged - defaults to empty
|
- charged_icon: `string` - icon to display on the left when fully charged - defaults to empty
|
||||||
- color_background: `boolean` - color the background or foreground for properties below - defaults to `false`
|
- color_background: `boolean` - color the background or foreground for properties below - defaults to `false`
|
||||||
- charged_color: `string` [hex color code][colors] - color to use when fully charged - defaults to segment color
|
- charged_color: `string` [color][colors] - color to use when fully charged - defaults to segment color
|
||||||
- charging_color: `string` [hex color code][colors] - color to use when charging - defaults to segment color
|
- charging_color: `string` [color][colors] - color to use when charging - defaults to segment color
|
||||||
- discharging_color: `string` [hex color code][colors] - color to use when discharging - defaults to segment color
|
- discharging_color: `string` [color][colors] - color to use when discharging - defaults to segment color
|
||||||
|
|
||||||
[colors]: https://htmlcolorcodes.com/color-chart/material-design-color-chart/
|
[colors]: /docs/configure#colors
|
||||||
|
|
|
@ -33,6 +33,6 @@ Displays the last exit code or that the last command failed based on the configu
|
||||||
- display_exit_code: `boolean` - show or hide the exit code - defaults to `true`
|
- display_exit_code: `boolean` - show or hide the exit code - defaults to `true`
|
||||||
- always_enabled: `boolean` - always show the status - defaults to `false`
|
- always_enabled: `boolean` - always show the status - defaults to `false`
|
||||||
- color_background: `boolean` - color the background or foreground when an error occurs - defaults to `false`
|
- color_background: `boolean` - color the background or foreground when an error occurs - defaults to `false`
|
||||||
- error_color: `string` [hex color code][colors] - color to use when an error occured
|
- error_color: `string` [color][colors] - color to use when an error occured
|
||||||
|
|
||||||
[colors]: https://htmlcolorcodes.com/color-chart/material-design-color-chart/
|
[colors]: /docs/configure#colors
|
||||||
|
|
|
@ -67,17 +67,17 @@ Local changes can also shown by default using the following syntax for both the
|
||||||
|
|
||||||
### Colors
|
### Colors
|
||||||
|
|
||||||
- working_color: `string` [hex color code][colors] - foreground color for the working area status - defaults to segment foreground
|
- working_color: `string` [color][colors] - foreground color for the working area status - defaults to segment foreground
|
||||||
- staging_color: `string` [hex color code][colors] - foreground color for the staging area status - defaults to segment foreground
|
- staging_color: `string` [color][colors] - foreground color for the staging area status - defaults to segment foreground
|
||||||
- status_colors_enabled: `boolean` - color the segment based on the repository status - defaults to `false`
|
- status_colors_enabled: `boolean` - color the segment based on the repository status - defaults to `false`
|
||||||
- color_background: `boolean` - color background or foreground - defaults to `true`
|
- color_background: `boolean` - color background or foreground - defaults to `true`
|
||||||
- local_changes_color: `string` [hex color code][colors] - segment color when there are local changes - defaults to segment
|
- local_changes_color: `string` [color][colors] - segment color when there are local changes - defaults to segment
|
||||||
foreground/background (see `color_background`)
|
foreground/background (see `color_background`)
|
||||||
- ahead_and_behind_color: `string` [hex color code][colors] - segment color when the branch is ahead and behind -
|
- ahead_and_behind_color: `string` [color][colors] - segment color when the branch is ahead and behind -
|
||||||
defaults to segment foreground/background (see `color_background`)
|
defaults to segment foreground/background (see `color_background`)
|
||||||
- behind_color: `string` [hex color code][colors] - segment color when the branch is behind - defaults to segment
|
- behind_color: `string` [color][colors] - segment color when the branch is behind - defaults to segment
|
||||||
foreground/background (see `color_background`)
|
foreground/background (see `color_background`)
|
||||||
- ahead_color: `string` [hex color code][colors] - segment color when the branch is ahead - defaults to segment
|
- ahead_color: `string` [color][colors] - segment color when the branch is ahead - defaults to segment
|
||||||
foreground/background (see `color_background`)
|
foreground/background (see `color_background`)
|
||||||
|
|
||||||
[colors]: https://htmlcolorcodes.com/color-chart/material-design-color-chart/
|
[colors]: /docs/configure#colors
|
||||||
|
|
|
@ -26,9 +26,9 @@ Show the current user and host name.
|
||||||
- user_info_separator: `string` - text/icon to put in between the user and host name - defaults to `@`
|
- user_info_separator: `string` - text/icon to put in between the user and host name - defaults to `@`
|
||||||
- ssh_icon: `string` - text/icon to display first when in an active SSH session - defaults
|
- ssh_icon: `string` - text/icon to display first when in an active SSH session - defaults
|
||||||
to `\uF817 `
|
to `\uF817 `
|
||||||
- user_color: `string` [hex color code][colors] - override the foreground color of the user name
|
- user_color: `string` [color][colors] - override the foreground color of the user name
|
||||||
- host_color: `string` [hex color code][colors] - override the foreground color of the host name
|
- host_color: `string` [color][colors] - override the foreground color of the host name
|
||||||
- display_user: `boolean` - display the user name or not - defaults to `true`
|
- display_user: `boolean` - display the user name or not - defaults to `true`
|
||||||
- display_host: `boolean` - display the host name or not - defaults to `true`
|
- display_host: `boolean` - display the host name or not - defaults to `true`
|
||||||
|
|
||||||
[colors]: https://htmlcolorcodes.com/color-chart/material-design-color-chart/
|
[colors]: /docs/configure#colors
|
||||||
|
|
|
@ -12,7 +12,7 @@ const features = [
|
||||||
description: (
|
description: (
|
||||||
<>
|
<>
|
||||||
Oh my Posh enables you to use the full color set of your terminal
|
Oh my Posh enables you to use the full color set of your terminal
|
||||||
by using hex colors to define and render the prompt.
|
by using colors to define and render the prompt.
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|
69
renderer.go
69
renderer.go
|
@ -2,6 +2,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -23,6 +24,41 @@ type formats struct {
|
||||||
clearOEL string
|
clearOEL string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Map for color names and their respective foreground [0] or background [1] color codes
|
||||||
|
ColorMap map[string][2]string = map[string][2]string {
|
||||||
|
"black": [2]string { "30", "40" },
|
||||||
|
"red": [2]string { "31", "41" },
|
||||||
|
"green": [2]string { "32", "42" },
|
||||||
|
"yellow": [2]string { "33", "43" },
|
||||||
|
"blue": [2]string { "34", "44" },
|
||||||
|
"magenta": [2]string { "35", "45" },
|
||||||
|
"cyan": [2]string { "36", "46" },
|
||||||
|
"white": [2]string { "37", "47" },
|
||||||
|
"default": [2]string { "39", "49" },
|
||||||
|
"darkGray": [2]string { "90", "100" },
|
||||||
|
"lightRed": [2]string { "91", "101" },
|
||||||
|
"lightGreen": [2]string { "92", "102" },
|
||||||
|
"lightYellow": [2]string { "93", "103" },
|
||||||
|
"lightBlue": [2]string { "94", "104" },
|
||||||
|
"lightMagenta": [2]string { "95", "105" },
|
||||||
|
"lightCyan": [2]string { "96", "106" },
|
||||||
|
"lightWhite": [2]string { "97", "107" },
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Returns the color code for a given color name
|
||||||
|
func getColorFromName(colorName string, isBackground bool) (string, error) {
|
||||||
|
colorMapOffset := 0
|
||||||
|
if isBackground {
|
||||||
|
colorMapOffset = 1
|
||||||
|
}
|
||||||
|
if colorCodes, found := ColorMap[colorName]; found {
|
||||||
|
return colorCodes[colorMapOffset], nil
|
||||||
|
}
|
||||||
|
return "", errors.New("This color name does not exist.")
|
||||||
|
}
|
||||||
|
|
||||||
//Renderer writes colorized strings
|
//Renderer writes colorized strings
|
||||||
type Renderer struct {
|
type Renderer struct {
|
||||||
Buffer *bytes.Buffer
|
Buffer *bytes.Buffer
|
||||||
|
@ -74,22 +110,29 @@ func (r *Renderer) init(shell string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Renderer) getAnsiFromHex(hexColor string, isBackground bool) string {
|
// Gets the ANSI color code for a given color string.
|
||||||
style := color.HEX(hexColor, isBackground)
|
// This can include a valid hex color in the format `#FFFFFF`,
|
||||||
|
// but also a name of one of the first 16 ANSI colors like `lightBlue`.
|
||||||
|
func (r *Renderer) getAnsiFromColorString(colorString string, isBackground bool) string {
|
||||||
|
colorFromName, err := getColorFromName(colorString, isBackground)
|
||||||
|
if err == nil {
|
||||||
|
return colorFromName
|
||||||
|
}
|
||||||
|
style := color.HEX(colorString, isBackground)
|
||||||
return style.Code()
|
return style.Code()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Renderer) writeColoredText(background string, foreground string, text string) {
|
func (r *Renderer) writeColoredText(background string, foreground string, text string) {
|
||||||
var coloredText string
|
var coloredText string
|
||||||
if foreground == Transparent && background != "" {
|
if foreground == Transparent && background != "" {
|
||||||
ansiColor := r.getAnsiFromHex(background, false)
|
ansiColor := r.getAnsiFromColorString(background, false)
|
||||||
coloredText = fmt.Sprintf(r.formats.transparent, ansiColor, text)
|
coloredText = fmt.Sprintf(r.formats.transparent, ansiColor, text)
|
||||||
} else if background == "" || background == Transparent {
|
} else if background == "" || background == Transparent {
|
||||||
ansiColor := r.getAnsiFromHex(foreground, false)
|
ansiColor := r.getAnsiFromColorString(foreground, false)
|
||||||
coloredText = fmt.Sprintf(r.formats.single, ansiColor, text)
|
coloredText = fmt.Sprintf(r.formats.single, ansiColor, text)
|
||||||
} else if foreground != "" && background != "" {
|
} else if foreground != "" && background != "" {
|
||||||
bgAnsiColor := r.getAnsiFromHex(background, true)
|
bgAnsiColor := r.getAnsiFromColorString(background, true)
|
||||||
fgAnsiColor := r.getAnsiFromHex(foreground, false)
|
fgAnsiColor := r.getAnsiFromColorString(foreground, false)
|
||||||
coloredText = fmt.Sprintf(r.formats.full, bgAnsiColor, fgAnsiColor, text)
|
coloredText = fmt.Sprintf(r.formats.full, bgAnsiColor, fgAnsiColor, text)
|
||||||
}
|
}
|
||||||
r.Buffer.WriteString(coloredText)
|
r.Buffer.WriteString(coloredText)
|
||||||
|
@ -101,13 +144,19 @@ func (r *Renderer) writeAndRemoveText(background string, foreground string, text
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Renderer) write(background string, foreground string, text string) {
|
func (r *Renderer) write(background string, foreground string, text string) {
|
||||||
rex := regexp.MustCompile(`<((#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})|transparent))>(.*?)</>`)
|
// first we match for any potentially valid color enclosed in <>
|
||||||
|
rex := regexp.MustCompile(`<([#A-Za-z0-9]+)>(.*?)<\/>`)
|
||||||
match := rex.FindAllStringSubmatch(text, -1)
|
match := rex.FindAllStringSubmatch(text, -1)
|
||||||
for i := range match {
|
for i := range match {
|
||||||
// get the text before the color override and write that first
|
extractedColor := match[i][1]
|
||||||
textBeforeColorOverride := strings.Split(text, match[i][0])[0]
|
if col := r.getAnsiFromColorString(extractedColor, false); col == "" && extractedColor != Transparent {
|
||||||
|
continue // we skip invalid colors
|
||||||
|
}
|
||||||
|
escapedTextSegment := match[i][0]
|
||||||
|
innerText := match[i][2]
|
||||||
|
textBeforeColorOverride := strings.Split(text, escapedTextSegment)[0]
|
||||||
text = r.writeAndRemoveText(background, foreground, textBeforeColorOverride, textBeforeColorOverride, text)
|
text = r.writeAndRemoveText(background, foreground, textBeforeColorOverride, textBeforeColorOverride, text)
|
||||||
text = r.writeAndRemoveText(background, match[i][1], match[i][4], match[i][0], text)
|
text = r.writeAndRemoveText(background, extractedColor, innerText, escapedTextSegment, text)
|
||||||
}
|
}
|
||||||
// color the remaining part of text with background and foreground
|
// color the remaining part of text with background and foreground
|
||||||
r.writeColoredText(background, foreground, text)
|
r.writeColoredText(background, foreground, text)
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/gookit/color"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestWriteAndRemoveText(t *testing.T) {
|
func TestWriteAndRemoveText(t *testing.T) {
|
||||||
|
@ -49,6 +50,36 @@ func TestWriteColorTransparent(t *testing.T) {
|
||||||
t.Log(renderer.string())
|
t.Log(renderer.string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestWriteColorName(t *testing.T) {
|
||||||
|
// given
|
||||||
|
renderer := &Renderer{
|
||||||
|
Buffer: new(bytes.Buffer),
|
||||||
|
}
|
||||||
|
renderer.init("pwsh")
|
||||||
|
text := "This is white, <red>this is red</>, white again"
|
||||||
|
|
||||||
|
// when
|
||||||
|
renderer.write("#193549", "red", text)
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert.NotContains(t, renderer.string(), "<red>")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteColorInvalid(t *testing.T) {
|
||||||
|
// given
|
||||||
|
renderer := &Renderer{
|
||||||
|
Buffer: new(bytes.Buffer),
|
||||||
|
}
|
||||||
|
renderer.init("pwsh")
|
||||||
|
text := "This is white, <invalid>this is orange</>, white again"
|
||||||
|
|
||||||
|
// when
|
||||||
|
renderer.write("#193549", "invalid", text)
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert.Contains(t, renderer.string(), "<invalid>")
|
||||||
|
}
|
||||||
|
|
||||||
func TestLenWithoutANSI(t *testing.T) {
|
func TestLenWithoutANSI(t *testing.T) {
|
||||||
text := "\x1b[44mhello\x1b[0m"
|
text := "\x1b[44mhello\x1b[0m"
|
||||||
renderer := &Renderer{
|
renderer := &Renderer{
|
||||||
|
@ -68,3 +99,68 @@ func TestLenWithoutANSIZsh(t *testing.T) {
|
||||||
strippedLength := renderer.lenWithoutANSI(text)
|
strippedLength := renderer.lenWithoutANSI(text)
|
||||||
assert.Equal(t, 5, strippedLength)
|
assert.Equal(t, 5, strippedLength)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetAnsiFromColorStringBg(t *testing.T) {
|
||||||
|
// given
|
||||||
|
renderer := &Renderer{
|
||||||
|
Buffer: new(bytes.Buffer),
|
||||||
|
}
|
||||||
|
|
||||||
|
// when
|
||||||
|
colorCode := renderer.getAnsiFromColorString("blue", true)
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert.Equal(t, color.BgBlue.Code(), colorCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetAnsiFromColorStringFg(t *testing.T) {
|
||||||
|
// given
|
||||||
|
renderer := &Renderer{
|
||||||
|
Buffer: new(bytes.Buffer),
|
||||||
|
}
|
||||||
|
|
||||||
|
// when
|
||||||
|
colorCode := renderer.getAnsiFromColorString("red", false)
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert.Equal(t, color.FgRed.Code(), colorCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetAnsiFromColorStringHex(t *testing.T) {
|
||||||
|
// given
|
||||||
|
renderer := &Renderer{
|
||||||
|
Buffer: new(bytes.Buffer),
|
||||||
|
}
|
||||||
|
|
||||||
|
// when
|
||||||
|
colorCode := renderer.getAnsiFromColorString("#AABBCC", false)
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert.Equal(t, color.HEX("#AABBCC").Code(), colorCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetAnsiFromColorStringInvalidFg(t *testing.T) {
|
||||||
|
// given
|
||||||
|
renderer := &Renderer{
|
||||||
|
Buffer: new(bytes.Buffer),
|
||||||
|
}
|
||||||
|
|
||||||
|
// when
|
||||||
|
colorCode := renderer.getAnsiFromColorString("invalid", false)
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert.Equal(t, "", colorCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetAnsiFromColorStringInvalidBg(t *testing.T) {
|
||||||
|
// given
|
||||||
|
renderer := &Renderer{
|
||||||
|
Buffer: new(bytes.Buffer),
|
||||||
|
}
|
||||||
|
|
||||||
|
// when
|
||||||
|
colorCode := renderer.getAnsiFromColorString("invalid", true)
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert.Equal(t, "", colorCode)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue