Skip to content

Commit 79cbfa8

Browse files
committed
Draw box around file and ruler around commit lines
The `diff-so-fancy.rulerWidth` config still applies, but to the ruler around the commit line. File lines have a box around them with just the size of the file name and prefixes/suffixes (e.g. `modified: diff-so-fancy`). This allows for a better hierarchical view of commits, with commit lines having a configurable wider ruler around them and file lines ("children" of commits) having a shorter box around them.
1 parent 81f104e commit 79cbfa8

File tree

3 files changed

+74
-72
lines changed

3 files changed

+74
-72
lines changed

diff-so-fancy

Lines changed: 58 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,31 @@ my $ruler_width = git_config("diff-so-fancy.rulerWidth", undef);
2828
my $git_strip_prefix = git_config_boolean("diff.noprefix","false");
2929
my $has_stdin = has_stdin();
3030

31+
my $box_horizontal;
32+
my $box_vertical;
33+
my $box_down;
34+
my $box_up;
35+
# BOX DRAWINGS LIGHT HORIZONTAL http://www.fileformat.info/info/unicode/char/2500/index.htm
36+
# BOX DRAWINGS LIGHT VERTICAL https://www.fileformat.info/info/unicode/char/2502/index.htm
37+
# BOX DRAWINGS LIGHT DOWN AND LEFT https://www.fileformat.info/info/unicode/char/2510/index.htm
38+
# BOX DRAWINGS LIGHT UP AND LEFT https://www.fileformat.info/info/unicode/char/2518/index.htm
39+
if ($use_unicode_dash_for_ruler && should_print_unicode()) {
40+
$box_horizontal = Encode::encode('UTF-8', "\x{2500}");
41+
$box_vertical = Encode::encode('UTF-8', "\x{2502}");
42+
$box_down = Encode::encode('UTF-8', "\x{2510}");
43+
$box_up = Encode::encode('UTF-8', "\x{2518}");
44+
} else {
45+
$box_horizontal = "-";
46+
$box_vertical = "|";
47+
$box_down = ".";
48+
$box_up = "'";
49+
}
50+
3151
my $ansi_color_regex = qr/(\e\[([0-9]{1,3}(;[0-9]{1,3}){0,10})[mK])?/;
3252
my $reset_color = color("reset");
3353
my $bold = color("bold");
3454
my $meta_color = "";
55+
my $commit_color = "";
3556

3657
my ($file_1,$file_2);
3758
my $args = argv(); # Hashref of all the ARGV stuff
@@ -145,13 +166,17 @@ sub do_dsf_stuff {
145166

146167
#######################################################################
147168

169+
########################
170+
# Look for commit line #
171+
########################
172+
if ($line =~ /^${ansi_color_regex}commit [0-9a-f]{40}/) {
173+
$commit_color = $1 || get_config_color("commit");
174+
print_commit_box($line);
148175
####################################################################
149176
# Look for git index and replace it horizontal line (header later) #
150177
####################################################################
151-
if ($line =~ /^${ansi_color_regex}index /) {
152-
# Print the line color and then the actual line
178+
} elsif ($line =~ /^${ansi_color_regex}index /) {
153179
$meta_color = $1 || get_config_color("meta");
154-
155180
# Get the next line without incrementing counter while loop
156181
my $next = $input->[0] || "";
157182
my ($file_1,$file_2);
@@ -171,9 +196,7 @@ sub do_dsf_stuff {
171196
}
172197

173198
if ($file_1 && $file_2) {
174-
print horizontal_rule($meta_color);
175-
print $meta_color . file_change_string($file_1,$file_2) . "\n";
176-
print horizontal_rule($meta_color);
199+
print_file_change_box(file_change_string($file_1,$file_2));
177200
}
178201
#########################
179202
# Look for the filename #
@@ -184,7 +207,6 @@ sub do_dsf_stuff {
184207
# Mercurial looks like: diff -r 82e55d328c8c hello.c
185208
if ($4 eq "-r") {
186209
$is_mercurial = 1;
187-
$meta_color ||= get_config_color("meta");
188210
# Git looks like: diff --git a/diff-so-fancy b/diff-so-fancy
189211
} else {
190212
$last_file_seen = $5;
@@ -200,8 +222,6 @@ sub do_dsf_stuff {
200222
# Find the first file: --- a/README.md #
201223
########################################
202224
} elsif (!$in_hunk && $line =~ /^$ansi_color_regex--- (\w\/)?(.+?)(\e|\t|$)/) {
203-
$meta_color ||= get_config_color("meta");
204-
205225
if ($git_strip_prefix) {
206226
my $file_dir = $4 || "";
207227
$file_1 = $file_dir . $5;
@@ -226,20 +246,7 @@ sub do_dsf_stuff {
226246
$last_file_seen = $file_2;
227247
}
228248

229-
# Print out the top horizontal line of the header
230-
print $reset_color;
231-
print horizontal_rule($meta_color);
232-
233-
# Mercurial coloring is slightly different so we need to hard reset colors
234-
if ($is_mercurial) {
235-
print $reset_color;
236-
}
237-
238-
print $meta_color;
239-
print file_change_string($file_1,$file_2) . "\n";
240-
241-
# Print out the bottom horizontal line of the header
242-
print horizontal_rule($meta_color);
249+
print_file_change_box(file_change_string($file_1,$file_2));
243250
########################################
244251
# Check for "@@ -3,41 +3,63 @@" syntax #
245252
########################################
@@ -309,10 +316,8 @@ sub do_dsf_stuff {
309316
# Look for binary file changes #
310317
################################
311318
} elsif ($line =~ /^Binary files (\w\/)?(.+?) and (\w\/)?(.+?) differ/) {
312-
my $change = file_change_string($2,$4);
313-
print horizontal_rule($meta_color);
314-
print "$meta_color$change (binary)\n";
315-
print horizontal_rule($meta_color);
319+
my ($change,$change_length) = file_change_string($2,$4);
320+
print_file_change_box($change . " (binary)", $change_length + 9);
316321
#####################################################
317322
# Check if we're changing the permissions of a file #
318323
#####################################################
@@ -351,14 +356,7 @@ sub do_dsf_stuff {
351356
my ($file2) = $next =~ /rename to (.+?)(\e|\t|$)/;
352357

353358
if ($file1 && $file2) {
354-
# We may not have extracted this yet, so we pull from the config if not
355-
$meta_color ||= get_config_color("meta");
356-
357-
my $change = file_change_string($file1,$file2);
358-
359-
print horizontal_rule($meta_color);
360-
print $meta_color . $change . "\n";
361-
print horizontal_rule($meta_color);
359+
print_file_change_box(file_change_string($file1,$file2));
362360
}
363361

364362
$i += 3; # We've consumed three lines
@@ -624,25 +622,23 @@ sub trim {
624622
return $s;
625623
}
626624

627-
# Print a line of em-dash or line-drawing chars the full width of the screen
628-
sub horizontal_rule {
629-
my $color = $_[0] || "";
630-
my $width = get_terminal_width();
631-
632-
# em-dash http://www.fileformat.info/info/unicode/char/2014/index.htm
633-
#my $dash = "\x{2014}";
634-
# BOX DRAWINGS LIGHT HORIZONTAL http://www.fileformat.info/info/unicode/char/2500/index.htm
635-
my $dash;
636-
if ($use_unicode_dash_for_ruler && should_print_unicode()) {
637-
$dash = Encode::encode('UTF-8', "\x{2500}");
638-
} else {
639-
$dash = "-";
640-
}
641-
642-
# Draw the line
643-
my $ret = $color . ($dash x $width) . "$reset_color\n";
625+
sub print_commit_box {
626+
my $line = shift();
627+
my $ruler = $box_horizontal x get_terminal_width();
628+
$commit_color ||= get_config_color("commit");
629+
print $commit_color,$ruler,$reset_color,"\n";
630+
print $line;
631+
print $commit_color,$ruler,$reset_color,"\n";
632+
}
644633

645-
return $ret;
634+
sub print_file_change_box {
635+
my $change = shift();
636+
my $change_length = shift();
637+
my $ruler = $box_horizontal x ($change_length + 1);
638+
$meta_color ||= get_config_color("meta");
639+
print $meta_color,$ruler,$box_down,$reset_color,"\n";
640+
print $meta_color,$change," ",$meta_color,$box_vertical,$reset_color,"\n";
641+
print $meta_color,$ruler,$box_up,$reset_color,"\n";
646642
}
647643

648644
sub file_change_string {
@@ -651,25 +647,26 @@ sub file_change_string {
651647

652648
# If they're the same it's a modify
653649
if ($file_1 eq $file_2) {
654-
return "modified: $file_1";
650+
return ("modified: $file_1", 10 + length($file_1));
655651
# If the first is /dev/null it's a new file
656652
} elsif ($file_1 eq "/dev/null") {
657653
my $add_color = $DiffHighlight::NEW_HIGHLIGHT[1];
658-
return "added: $add_color$file_2$reset_color";
654+
return ("added: $add_color$file_2$reset_color", 7 + length($file_2));
659655
# If the second is /dev/null it's a deletion
660656
} elsif ($file_2 eq "/dev/null") {
661657
my $del_color = $DiffHighlight::OLD_HIGHLIGHT[1];
662-
return "deleted: $del_color$file_1$reset_color";
658+
return ("deleted: $del_color$file_1$reset_color", 9 + length($file_1));
663659
# If the files aren't the same it's a rename
664660
} elsif ($file_1 ne $file_2) {
665661
my ($old, $new) = DiffHighlight::highlight_pair($file_1,$file_2,{only_diff => 1});
666662
# highlight_pair already includes reset_color, but adds newline characters that need to be trimmed off
667663
$old = trim($old);
668664
$new = trim($new);
669-
return "renamed: $old$meta_color to $new"
665+
$meta_color ||= get_config_color("meta");
666+
return ("renamed: $old$meta_color to $new", 13 + length($file_1) + length($file_2));
670667
# Something we haven't thought of yet
671668
} else {
672-
return "$file_1 -> $file_2";
669+
return ("$file_1 -> $file_2", 4 + length($file_1) + length($file_2));
673670
}
674671
}
675672

@@ -871,6 +868,9 @@ sub color {
871868
if ($str eq "meta") {
872869
# Default ANSI yellow
873870
$ret = DiffHighlight::color_config('color.diff.meta', color(11));
871+
} elsif ($str eq "commit") {
872+
# Default ANSI yellow bold
873+
$ret = DiffHighlight::color_config('color.diff.commit', color('11_bold'));
874874
} elsif ($str eq "reset") {
875875
$ret = color("reset");
876876
} elsif ($str eq "add_line") {

test/diff-so-fancy.bats

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -53,20 +53,22 @@ output=$( load_fixture "ls-function" | $diff_so_fancy )
5353
@test "header format uses a native line-drawing character" {
5454
header=$( printf "%s" "$output" | head -n3 )
5555
run printf "%s" "$header"
56-
assert_line --index 0 --partial "─────"
57-
assert_line --index 1 --partial "modified: fish/functions/ls.fish"
58-
assert_line --index 2 --partial "─────"
56+
# the meta color is captured directly from the output, not from the configuration
57+
assert_line --index 0 --partial "─────────────────────────────────┐"
58+
assert_line --index 1 --partial "modified: fish/functions/ls.fish │"
59+
assert_line --index 2 --partial "─────────────────────────────────┘"
5960
}
6061

6162
# see https://git.io/vrOF4
6263
@test "Should not show unicode bytes in hex if missing LC_*/LANG _and_ piping the output" {
6364
unset LESSCHARSET LESSCHARDEF LC_ALL LC_CTYPE LANG
6465
# pipe to cat(1) so we don't open stdout
65-
header=$( printf "%s" "$(load_fixture "ls-function" | $diff_so_fancy | cat)" | head -n3 )
66+
header=$( load_fixture "ls-function" | $diff_so_fancy | cat | head -n3 )
6667
run printf "%s" "$header"
67-
assert_line --index 0 --partial "-----"
68-
assert_line --index 1 --partial "modified: fish/functions/ls.fish"
69-
assert_line --index 2 --partial "-----"
68+
# the meta color is captured directly from the output, not from the configuration
69+
assert_line --index 0 --partial "---------------------------------."
70+
assert_line --index 1 --partial "modified: fish/functions/ls.fish |"
71+
assert_line --index 2 --partial "---------------------------------'"
7072
set_env # reset env
7173
}
7274

@@ -105,13 +107,13 @@ output=$( load_fixture "ls-function" | $diff_so_fancy )
105107
@test "Empty file add" {
106108
output=$( load_fixture "add_empty_file" | $diff_so_fancy )
107109
run printf "%s" "$output"
108-
assert_line --index 5 --regexp "added:.*empty_file.txt"
110+
assert_line --index 7 --regexp "added:.*empty_file.txt"
109111
}
110112

111113
@test "Empty file delete" {
112114
output=$( load_fixture "remove_empty_file" | $diff_so_fancy )
113115
run printf "%s" "$output"
114-
assert_line --index 5 --regexp "deleted:.*empty_file.txt"
116+
assert_line --index 7 --regexp "deleted:.*empty_file.txt"
115117
}
116118

117119
@test "Move with content change" {
@@ -193,8 +195,8 @@ output=$( load_fixture "ls-function" | $diff_so_fancy )
193195
output=$( load_fixture "complex-hunks" | $diff_so_fancy 2>&1 )
194196
run printf "%s" "$output"
195197

196-
assert_line --index 4 --partial "@ libs/header_clean/header_clean.pl:107 @"
197-
refute_output --partial 'Use of uninitialized value'
198+
assert_line --index 6 --partial "@ libs/header_clean/header_clean.pl:107 @"
199+
refute_output --partial 'Use of uninitialized value'
198200
}
199201

200202
@test "Hunk formatting: @@ -1,6 +1,6 @@" {
@@ -207,7 +209,7 @@ output=$( load_fixture "ls-function" | $diff_so_fancy )
207209
# stderr forced into output
208210
output=$( load_fixture "single-line-remove" | $diff_so_fancy )
209211
run printf "%s" "$output"
210-
assert_line --index 4 --regexp 'var delayedMessage = "It worked";'
212+
assert_line --index 4 --partial 'var delayedMessage = "It worked";'
211213
}
212214

213215
@test "Three way merge" {

test/test_helper/util.bash

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ set_env() {
1313

1414
# applying colors so ANSI color values will match
1515
# FIXME: not everyone will have these set, so we need to test for that.
16-
git config color.diff.meta "227"
16+
git config color.diff.meta "yellow"
1717
git config color.diff.frag "magenta bold"
18-
git config color.diff.commit "227 bold"
18+
git config color.diff.commit "yellow bold"
1919
git config color.diff.old "red bold"
2020
git config color.diff.new "green bold"
2121
git config color.diff.whitespace "red reverse"

0 commit comments

Comments
 (0)