diff-highlight: allow module callers to pass in color config

Users of the module may want to pass in their own color config for a few obvious reasons: - they are pulling the config from different variables than diff-highlight itself uses - they are loading the config in a more efficient way (say, by parsing git-config --list) and don't want to incur the six (!) git-config calls that DiffHighlight.pm runs to check all config Let's allow users of the module to pass in the color config, and lazy-load it when needed if they haven't. Signed-off-by: Scott Baker <scott@perturb.org> Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Scott Baker committed Mar 23, 2026 at 02:02 UTC bd958e91dffdba00ef94dc9bfc04b46599362f9a
2 files changed +35 -12
contrib/diff-highlight/DiffHighlight.pm
+29 -12
@@ -9,18 +9,11 @@ use File::Spec;
9
10 my $NULL = File::Spec->devnull();
11
12 -# Highlight by reversing foreground and background. You could do
13 -# other things like bold or underline if you prefer.
14 -my @OLD_HIGHLIGHT = (
15 - color_config('color.diff-highlight.oldnormal'),
16 - color_config('color.diff-highlight.oldhighlight', "\x1b[7m"),
17 - color_config('color.diff-highlight.oldreset', "\x1b[27m")
18 -);
19 -my @NEW_HIGHLIGHT = (
20 - color_config('color.diff-highlight.newnormal', $OLD_HIGHLIGHT[0]),
21 - color_config('color.diff-highlight.newhighlight', $OLD_HIGHLIGHT[1]),
22 - color_config('color.diff-highlight.newreset', $OLD_HIGHLIGHT[2])
23 -);
12 +# The color theme is initially set to nothing here to allow outside callers
13 +# to set the colors for their application. If nothing is sent in we use
14 +# colors from git config in load_color_config().
15 +our @OLD_HIGHLIGHT = ();
16 +our @NEW_HIGHLIGHT = ();
17
18 my $RESET = "\x1b[m";
19 my $COLOR = qr/\x1b\[[0-9;]*m/;
@@ -170,6 +163,29 @@ sub show_hunk {
163 $line_cb->(@queue);
164 }
165
166 +sub load_color_config {
167 + # If the colors were NOT set from outside this module we load them on-demand
168 + # from the git config. Note that only one of elements 0 and 2 in each
169 + # array is used (depending on whether you are doing set/unset on an
170 + # attribute, or specifying normal vs highlighted coloring). So we use
171 + # element 1 as our check for whether colors were passed in; it should
172 + # always be set if you want highlighting to do anything.
173 + if (!defined $OLD_HIGHLIGHT[1]) {
174 + @OLD_HIGHLIGHT = (
175 + color_config('color.diff-highlight.oldnormal'),
176 + color_config('color.diff-highlight.oldhighlight', "\x1b[7m"),
177 + color_config('color.diff-highlight.oldreset', "\x1b[27m")
178 + );
179 + }
180 + if (!defined $NEW_HIGHLIGHT[1]) {
181 + @NEW_HIGHLIGHT = (
182 + color_config('color.diff-highlight.newnormal', $OLD_HIGHLIGHT[0]),
183 + color_config('color.diff-highlight.newhighlight', $OLD_HIGHLIGHT[1]),
184 + color_config('color.diff-highlight.newreset', $OLD_HIGHLIGHT[2])
185 + );
186 + };
187 +}
188 +
189 sub highlight_pair {
190 my @a = split_line(shift);
191 my @b = split_line(shift);
@@ -218,6 +234,7 @@ sub highlight_pair {
234 }
235
236 if (is_pair_interesting(\@a, $pa, $sa, \@b, $pb, $sb)) {
237 + load_color_config();
238 return highlight_line(\@a, $pa, $sa, \@OLD_HIGHLIGHT),
239 highlight_line(\@b, $pb, $sb, \@NEW_HIGHLIGHT);
240 }
contrib/diff-highlight/README
+6
@@ -138,6 +138,12 @@ Your script may set up one or more of the following variables:
138 processing a logical chunk of input). The default function flushes
139 stdout.
140
141 + - @DiffHighlight::OLD_HIGHLIGHT and @DiffHighlight::NEW_HIGHLIGHT - these
142 + arrays specify the normal, highlighted, and reset colors (in that order)
143 + for old/new lines. If unset, values will be retrieved by calling `git
144 + config` (see "Color Config" above). Note that these should be the literal
145 + color bytes (starting with an ANSI escape code), not color names.
146 +
147 The script may then feed lines, one at a time, to DiffHighlight::handle_line().
148 When lines are done processing, they will be fed to $line_cb. Note that
149 DiffHighlight may queue up many input lines (to analyze a whole hunk)