Skip to content

Commit 6387510

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 fc55bc8 commit 6387510

File tree

3 files changed

+78
-73
lines changed

3 files changed

+78
-73
lines changed

diff-so-fancy

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

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

3560
# Set the diff highlight colors from the config
3661
init_diff_highlight_colors();
@@ -147,13 +172,17 @@ sub do_dsf_stuff {
147172

148173
#######################################################################
149174

175+
########################
176+
# Look for commit line #
177+
########################
178+
if ($line =~ /^${ansi_color_regex}commit [0-9a-f]{40}/) {
179+
$commit_color = $1 || get_config_color("commit");
180+
print_commit_box($line);
150181
####################################################################
151182
# Look for git index and replace it horizontal line (header later) #
152183
####################################################################
153-
if ($line =~ /^${ansi_color_regex}index /) {
154-
# Print the line color and then the actual line
184+
} elsif ($line =~ /^${ansi_color_regex}index /) {
155185
$meta_color = $1 || get_config_color("meta");
156-
157186
# Get the next line without incrementing counter while loop
158187
my $next = $input->[0] || "";
159188
my ($file_1,$file_2);
@@ -173,9 +202,7 @@ sub do_dsf_stuff {
173202
}
174203

175204
if ($file_1 && $file_2) {
176-
print horizontal_rule($meta_color);
177-
print $meta_color . file_change_string($file_1,$file_2) . "\n";
178-
print horizontal_rule($meta_color);
205+
print_file_change_box(file_change_string($file_1,$file_2));
179206
}
180207
#########################
181208
# Look for the filename #
@@ -186,7 +213,6 @@ sub do_dsf_stuff {
186213
# Mercurial looks like: diff -r 82e55d328c8c hello.c
187214
if ($4 eq "-r") {
188215
$is_mercurial = 1;
189-
$meta_color ||= get_config_color("meta");
190216
# Git looks like: diff --git a/diff-so-fancy b/diff-so-fancy
191217
} else {
192218
$last_file_seen = $5;
@@ -202,8 +228,6 @@ sub do_dsf_stuff {
202228
# Find the first file: --- a/README.md #
203229
########################################
204230
} elsif (!$in_hunk && $line =~ /^$ansi_color_regex--- (\w\/)?(.+?)(\e|\t|$)/) {
205-
$meta_color ||= get_config_color("meta");
206-
207231
if ($git_strip_prefix) {
208232
my $file_dir = $4 || "";
209233
$file_1 = $file_dir . $5;
@@ -228,20 +252,7 @@ sub do_dsf_stuff {
228252
$last_file_seen = $file_2;
229253
}
230254

231-
# Print out the top horizontal line of the header
232-
print $reset_color;
233-
print horizontal_rule($meta_color);
234-
235-
# Mercurial coloring is slightly different so we need to hard reset colors
236-
if ($is_mercurial) {
237-
print $reset_color;
238-
}
239-
240-
print $meta_color;
241-
print file_change_string($file_1,$file_2) . "\n";
242-
243-
# Print out the bottom horizontal line of the header
244-
print horizontal_rule($meta_color);
255+
print_file_change_box(file_change_string($file_1,$file_2));
245256
########################################
246257
# Check for "@@ -3,41 +3,63 @@" syntax #
247258
########################################
@@ -311,10 +322,8 @@ sub do_dsf_stuff {
311322
# Look for binary file changes #
312323
################################
313324
} elsif ($line =~ /^Binary files (\w\/)?(.+?) and (\w\/)?(.+?) differ/) {
314-
my $change = file_change_string($2,$4);
315-
print horizontal_rule($meta_color);
316-
print "$meta_color$change (binary)\n";
317-
print horizontal_rule($meta_color);
325+
my ($change,$change_length) = file_change_string($2,$4);
326+
print_file_change_box($change . " (binary)", $change_length + 9);
318327
#####################################################
319328
# Check if we're changing the permissions of a file #
320329
#####################################################
@@ -353,14 +362,7 @@ sub do_dsf_stuff {
353362
my ($file2) = $next =~ /rename to (.+?)(\e|\t|$)/;
354363

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

366368
$i += 3; # We've consumed three lines
@@ -623,26 +625,23 @@ sub trim {
623625
return $s;
624626
}
625627

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

645-
return $ret;
637+
sub print_file_change_box {
638+
my $change = shift();
639+
my $change_length = shift();
640+
my $ruler = $box_horizontal x ($change_length + 1);
641+
$meta_color ||= get_config_color("meta");
642+
print $meta_color.$ruler.$box_down.$reset_color."\n";
643+
print $meta_color.$change." ".$meta_color.$box_vertical.$reset_color."\n";
644+
print $meta_color.$ruler.$box_up.$reset_color."\n";
646645
}
647646

648647
sub file_change_string {
@@ -651,25 +650,26 @@ sub file_change_string {
651650

652651
# If they're the same it's a modify
653652
if ($file_1 eq $file_2) {
654-
return "modified: $file_1";
653+
return ("modified: $file_1", 10 + length($file_1));
655654
# If the first is /dev/null it's a new file
656655
} elsif ($file_1 eq "/dev/null") {
657656
my $add_color = $DiffHighlight::NEW_HIGHLIGHT[1];
658-
return "added: $add_color$file_2$reset_color";
657+
return ("added: $add_color$file_2$reset_color", 7 + length($file_2));
659658
# If the second is /dev/null it's a deletion
660659
} elsif ($file_2 eq "/dev/null") {
661660
my $del_color = $DiffHighlight::OLD_HIGHLIGHT[1];
662-
return "deleted: $del_color$file_1$reset_color";
661+
return ("deleted: $del_color$file_1$reset_color", 9 + length($file_1));
663662
# If the files aren't the same it's a rename
664663
} elsif ($file_1 ne $file_2) {
665664
my ($old, $new) = DiffHighlight::highlight_pair($file_1,$file_2,{only_diff => 1});
666665
# highlight_pair already includes reset_color, but adds newline characters that need to be trimmed off
667666
$old = trim($old);
668667
$new = trim($new);
669-
return "renamed: $old$meta_color to $new"
668+
$meta_color ||= get_config_color("meta");
669+
return ("renamed: $old$meta_color to $new", 13 + length($file_1) + length($file_2));
670670
# Something we haven't thought of yet
671671
} else {
672-
return "$file_1 -> $file_2";
672+
return ("$file_1 -> $file_2", 4 + length($file_1) + length($file_2));
673673
}
674674
}
675675

@@ -871,6 +871,9 @@ sub color {
871871
if ($str eq "meta") {
872872
# Default ANSI yellow
873873
$ret = git_ansi_color(git_config('color.diff.meta')) || color(11);
874+
} elsif ($str eq "commit") {
875+
# Default ANSI yellow bold
876+
$ret = git_ansi_color(git_config('color.diff.commit')) || color('11_bold');
874877
} elsif ($str eq "reset") {
875878
$ret = color("reset");
876879
} 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)