Skip to content

Commit 8949ad9

Browse files
authored
fix and maint: match most git supported color settings (#453)
* maint: set ansi colors in common routine Setting foreground and background colors is now using the same code. Signed-off-by: Chris. Webster <[email protected]> * fix: ignore negative color attributes with tests The colors in the git config may have attributes and negative versions of them (no/no- prefix). The negative versions will no longer cause a false positive checking for the attribute. A new test file is specifically for testing the settings of the ansi codes and the possible settings in the git config. Signed-off-by: Chris. Webster <[email protected]> * fix: support git config colors normal and default Normal is a placeholder and will be ignored. Default will generate ansi codes for the default foreground or background color. Git validates the config so a bright prefix on these values would not be allowed. They are added to the hash to keep the code simple. Signed-off-by: Chris. Webster <[email protected]> * fix: support #rgb colors in git config Git supports diff colors in #rrggbb notation. diff-so-fancy now supports them as well. Signed-off-by: Chris. Webster <[email protected]> --------- Signed-off-by: Chris. Webster <[email protected]>
1 parent 9ffea48 commit 8949ad9

File tree

2 files changed

+204
-37
lines changed

2 files changed

+204
-37
lines changed

diff-so-fancy

Lines changed: 33 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -904,6 +904,8 @@ sub git_ansi_color {
904904
'magenta' => 5,
905905
'cyan' => 6,
906906
'white' => 7,
907+
'default' => 9, # pseudo color (39/49 = set default)
908+
'normal' => -1, # placeholder color to be ignored
907909
};
908910

909911
# Bright colors are just offsets from the "regular" color
@@ -913,68 +915,62 @@ sub git_ansi_color {
913915

914916
my @ansi_part = ();
915917

916-
if (grep { /bold/ } @parts) {
918+
if (grep { /^bold$/ } @parts) {
917919
push(@ansi_part, "1");
918920
}
919921

920-
if (grep { /dim/ } @parts) {
922+
if (grep { /^dim$/ } @parts) {
921923
push(@ansi_part, "2");
922924
}
923925

924-
if (grep { /ul/ } @parts) {
926+
if (grep { /^ul$/ } @parts) {
925927
push(@ansi_part, "4");
926928
}
927929

928-
if (grep { /reverse/ } @parts) {
930+
if (grep { /^reverse$/ } @parts) {
929931
push(@ansi_part, "7");
930932
}
931933

932934
# Remove parts that aren't colors
933-
@parts = grep { exists $colors->{$_} || is_numeric($_) } @parts;
935+
@parts = grep { exists $colors->{$_} || is_numeric($_) || /^\#/ } @parts;
934936

935937
my $fg = $parts[0] // "";
936938
my $bg = $parts[1] // "";
937939

940+
set_ansi_color( $fg, 0, \@ansi_part, $colors ) if $fg;
941+
set_ansi_color( $bg, 10, \@ansi_part, $colors ) if $bg;
942+
938943
#############################################
939944

940-
# It's an numeric value, so it's an 8 bit color
941-
if (is_numeric($fg)) {
942-
if ($fg < 8) {
943-
push(@ansi_part, $fg + 30);
944-
} elsif ($fg < 16) {
945-
push(@ansi_part, $fg + 82);
946-
} else {
947-
push(@ansi_part, "38;5;$fg");
948-
}
949-
# It's a simple 16 color OG ansi
950-
} elsif ($fg) {
951-
my $color_num = ($colors->{$fg} // 0) + 30;
952-
push(@ansi_part, $color_num);
953-
}
945+
my $ansi_str = join(";", @ansi_part);
946+
my $ret = "\e[" . $ansi_str . "m";
954947

955-
#############################################
948+
return $ret;
949+
}
956950

957-
# It's an numeric value, so it's an 8 bit color
958-
if (is_numeric($bg)) {
959-
if ($bg < 8) {
960-
push(@ansi_part, $bg + 40);
961-
} elsif ($bg < 16) {
962-
push(@ansi_part, $bg + 92);
951+
sub set_ansi_color {
952+
my ($color, $increment, $ansi_part, $colors) = @_;
953+
my $base_code = 30 + $increment;
954+
my $base8_code = 38 + $increment;
955+
my $ext_code = 82 + $increment;
956+
957+
if (is_numeric($color)) {
958+
if ($color < 8) {
959+
push(@$ansi_part, $color + $base_code);
960+
} elsif ($color < 16) {
961+
push(@$ansi_part, $color + $ext_code);
963962
} else {
964-
push(@ansi_part, "48;5;$bg");
963+
push(@$ansi_part, "$base8_code;5;$color");
965964
}
965+
# It's a full rgb code
966+
} elsif ($color =~ /^#/) {
967+
my ($rgbr, $rgbg, $rgbb) = $color =~ /.(..)(..)(..)/;
968+
push(@$ansi_part, "$base8_code;2;" . hex($rgbr) . ";" . hex($rgbg) . ";" . hex($rgbb));
966969
# It's a simple 16 color OG ansi
967-
} elsif ($bg) {
968-
my $color_num = ($colors->{$bg} // 0) + 40;
969-
push(@ansi_part, $color_num);
970+
} elsif ($color ne "normal") {
971+
my $color_num = $colors->{$color} + $base_code;
972+
push(@$ansi_part, $color_num);
970973
}
971-
972-
#############################################
973-
974-
my $ansi_str = join(";", @ansi_part);
975-
my $ret = "\e[" . $ansi_str . "m";
976-
977-
return $ret;
978974
}
979975

980976
sub is_numeric {

test/git-config.bats

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
#!/usr/bin/env bats
2+
3+
# Used by both `setup_file` and `setup`, which are special bats callbacks.
4+
__load_imports__() {
5+
load 'test_helper/bats-support/load'
6+
load 'test_helper/bats-assert/load'
7+
load 'test_helper/util'
8+
}
9+
10+
# ansi related values
11+
escape=$'\e'
12+
ansi_bold=1
13+
ansi_dim=2
14+
ansi_ul=4
15+
ansi_reverse=7
16+
17+
# hash of colors
18+
declare -Ag ansi_colors=(
19+
[black]='0'
20+
[red]='1'
21+
[green]='2'
22+
[yellow]='3'
23+
[blue]='4'
24+
[magenta]='5'
25+
[cyan]='6'
26+
[white]='7'
27+
[default]='9'
28+
)
29+
30+
# get a foreground or background color code
31+
ansi_color() {
32+
color=$1
33+
incr=$2
34+
base_code=$((30+$incr))
35+
36+
# handle bright prefix
37+
if [[ "${1}" =~ (bright)(.*) ]]
38+
then
39+
color=${BASH_REMATCH[2]}
40+
base_code=$((90+$incr))
41+
fi
42+
code=$(($base_code+${ansi_colors[$color]}))
43+
echo "$code"
44+
}
45+
46+
# get a foreground color code
47+
fg_color() {
48+
ansi_color $1 0
49+
}
50+
51+
# get a background color code
52+
bg_color() {
53+
ansi_color $1 10
54+
}
55+
56+
# get rgb color codes from hex
57+
rgb_color() {
58+
incr=$2
59+
base_code=$((38+$incr))
60+
[[ $1 =~ ^.(..)(..)(..)$ ]]
61+
rgb1="${BASH_REMATCH[1]}"
62+
rgb2="${BASH_REMATCH[2]}"
63+
rgb3="${BASH_REMATCH[3]}"
64+
echo "${base_code};2;$(( 16#${rgb1} ));$(( 16#${rgb2} ));$(( 16#${rgb3} ))"
65+
}
66+
67+
# get a foreground color code
68+
fg_rgb_color() {
69+
rgb_color $1 0
70+
}
71+
72+
# get a background color code
73+
bg_rgb_color() {
74+
rgb_color $1 10
75+
}
76+
77+
# build config using passed in values
78+
setup_dsf_git_config() {
79+
GIT_CONFIG="$(dsf_test_git_config)" || return $?
80+
cat > "${GIT_CONFIG}" <<EOF || return $?
81+
[color "diff"]
82+
$1
83+
84+
EOF
85+
export GIT_CONFIG
86+
export GIT_CONFIG_NOSYSTEM=1
87+
}
88+
89+
setup_file() {
90+
__load_imports__
91+
# setup_default_dsf_git_config
92+
}
93+
94+
setup() {
95+
__load_imports__
96+
}
97+
98+
teardown_file() {
99+
teardown_default_dsf_git_config
100+
}
101+
102+
# General description of how colors are applied
103+
# meta = header
104+
# frag = @ filenames
105+
# func = function name after frag
106+
# old = - lines
107+
# new = + lines
108+
109+
@test "Test color attributes are removed" {
110+
config="
111+
meta = bold ul blink italic strike green no-reverse
112+
frag = nobold nodim noul noblink noreverse noitalic nostrike blue white
113+
func = dim reverse white purple
114+
old = no-bold no-dim no-ul no-blink no-reverse no-italic no-strike red yellow
115+
new = brightgreen
116+
whitespace = red reverse
117+
"
118+
setup_dsf_git_config "$config"
119+
120+
output=$( load_fixture "leading-dashes" | $diff_so_fancy )
121+
run printf "%s" "$output"
122+
123+
fg_green=$(fg_color green)
124+
fg_blue=$(fg_color blue)
125+
fg_red=$(fg_color red)
126+
fg_brightgreen=$(fg_color brightgreen)
127+
bg_white=$(bg_color white)
128+
bg_yellow=$(bg_color yellow)
129+
130+
assert_line --index 0 --partial "${escape}[${ansi_bold};${ansi_ul};${fg_green}m"
131+
assert_line --index 3 --partial "${escape}[${fg_blue};${bg_white}m@"
132+
assert_line --index 6 --partial "${escape}[${fg_red};${bg_yellow}m--"
133+
assert_line --index 7 --partial "${escape}[${fg_brightgreen}m--"
134+
}
135+
136+
@test "Test normal and default git colors" {
137+
config="
138+
frag = normal default
139+
old = default
140+
"
141+
setup_dsf_git_config "$config"
142+
143+
output=$( load_fixture "leading-dashes" | $diff_so_fancy )
144+
run printf "%s" "$output"
145+
146+
fg_default=$(fg_color default)
147+
bg_default=$(bg_color default)
148+
149+
assert_line --index 3 --partial "${escape}[${bg_default}m@"
150+
assert_line --index 6 --partial "${escape}[${fg_default}m--"
151+
}
152+
153+
# Special characters in git config must be quoted (word or all values)
154+
@test "Test rgb git colors" {
155+
rgb="#408050"
156+
config="
157+
frag = \"${rgb}\" default
158+
old = normal \"${rgb}\"
159+
"
160+
setup_dsf_git_config "$config"
161+
162+
output=$( load_fixture "leading-dashes" | $diff_so_fancy )
163+
run printf "%s" "$output"
164+
165+
fg_rgb=$(fg_rgb_color "${rgb}")
166+
bg_default=$(bg_color default)
167+
bg_rgb=$(bg_rgb_color "${rgb}")
168+
169+
assert_line --index 3 --partial "${escape}[${fg_rgb};${bg_default}m@"
170+
assert_line --index 6 --partial "${escape}[${bg_rgb}m--"
171+
}

0 commit comments

Comments
 (0)