Fix configuration syntax to specify customized hunk header patterns.

This updates the hunk header customization syntax.  The special
case 'funcname' attribute is gone.

You assign the name of the type of contents to path's "diff"
attribute as a string value in .gitattributes like this:

	*.java diff=java
	*.perl diff=perl
	*.doc diff=doc

If you supply "diff.<name>.funcname" variable via the
configuration mechanism (e.g. in $HOME/.gitconfig), the value is
used as the regexp set to find the line to use for the hunk
header (the variable is called "funcname" because such a line
typically is the one that has the name of the function in
programming language source text).

If there is no such configuration, built-in default is used, if
any.  Currently there are two default patterns: default and java.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Junio C Hamano 2007-07-07 01:49:58 -07:00
parent f258475a6e
commit e0e324a4dc
3 changed files with 84 additions and 71 deletions

147
diff.c
View File

@ -56,6 +56,14 @@ static struct ll_diff_driver {
char *cmd; char *cmd;
} *user_diff, **user_diff_tail; } *user_diff, **user_diff_tail;
static void read_config_if_needed(void)
{
if (!user_diff_tail) {
user_diff_tail = &user_diff;
git_config(git_diff_ui_config);
}
}
/* /*
* Currently there is only "diff.<drivername>.command" variable; * Currently there is only "diff.<drivername>.command" variable;
* because there are "diff.color.<slot>" variables, we are parsing * because there are "diff.color.<slot>" variables, we are parsing
@ -93,6 +101,45 @@ static int parse_lldiff_command(const char *var, const char *ep, const char *val
return 0; return 0;
} }
/*
* 'diff.<what>.funcname' attribute can be specified in the configuration
* to define a customized regexp to find the beginning of a function to
* be used for hunk header lines of "diff -p" style output.
*/
static struct funcname_pattern {
char *name;
char *pattern;
struct funcname_pattern *next;
} *funcname_pattern_list;
static int parse_funcname_pattern(const char *var, const char *ep, const char *value)
{
const char *name;
int namelen;
struct funcname_pattern *pp;
name = var + 5; /* "diff." */
namelen = ep - name;
for (pp = funcname_pattern_list; pp; pp = pp->next)
if (!strncmp(pp->name, name, namelen) && !pp->name[namelen])
break;
if (!pp) {
char *namebuf;
pp = xcalloc(1, sizeof(*pp));
namebuf = xmalloc(namelen + 1);
memcpy(namebuf, name, namelen);
namebuf[namelen] = 0;
pp->name = namebuf;
pp->next = funcname_pattern_list;
funcname_pattern_list = pp;
}
if (pp->pattern)
free(pp->pattern);
pp->pattern = xstrdup(value);
return 0;
}
/* /*
* These are to give UI layer defaults. * These are to give UI layer defaults.
* The core-level commands such as git-diff-files should * The core-level commands such as git-diff-files should
@ -122,8 +169,12 @@ int git_diff_ui_config(const char *var, const char *value)
if (!prefixcmp(var, "diff.")) { if (!prefixcmp(var, "diff.")) {
const char *ep = strrchr(var, '.'); const char *ep = strrchr(var, '.');
if (ep != var + 4 && !strcmp(ep, ".command")) if (ep != var + 4) {
return parse_lldiff_command(var, ep, value); if (!strcmp(ep, ".command"))
return parse_lldiff_command(var, ep, value);
if (!strcmp(ep, ".funcname"))
return parse_funcname_pattern(var, ep, value);
}
} }
if (!prefixcmp(var, "diff.color.") || !prefixcmp(var, "color.diff.")) { if (!prefixcmp(var, "diff.color.") || !prefixcmp(var, "color.diff.")) {
int slot = parse_diff_color_slot(var, 11); int slot = parse_diff_color_slot(var, 11);
@ -1101,43 +1152,39 @@ static void emit_binary_diff(mmfile_t *one, mmfile_t *two)
static void setup_diff_attr_check(struct git_attr_check *check) static void setup_diff_attr_check(struct git_attr_check *check)
{ {
static struct git_attr *attr_diff; static struct git_attr *attr_diff;
static struct git_attr *attr_diff_func_name;
if (!attr_diff) { if (!attr_diff) {
attr_diff = git_attr("diff", 4); attr_diff = git_attr("diff", 4);
attr_diff_func_name = git_attr("funcname", 8);
} }
check[0].attr = attr_diff; check[0].attr = attr_diff;
check[1].attr = attr_diff_func_name;
} }
static void diff_filespec_check_attr(struct diff_filespec *one) static void diff_filespec_check_attr(struct diff_filespec *one)
{ {
struct git_attr_check attr_diff_check[2]; struct git_attr_check attr_diff_check;
if (one->checked_attr) if (one->checked_attr)
return; return;
setup_diff_attr_check(attr_diff_check); setup_diff_attr_check(&attr_diff_check);
one->is_binary = 0; one->is_binary = 0;
one->hunk_header_ident = NULL; one->funcname_pattern_ident = NULL;
if (!git_checkattr(one->path, ARRAY_SIZE(attr_diff_check), attr_diff_check)) { if (!git_checkattr(one->path, 1, &attr_diff_check)) {
const char *value; const char *value;
/* binaryness */ /* binaryness */
value = attr_diff_check[0].value; value = attr_diff_check.value;
if (ATTR_TRUE(value)) if (ATTR_TRUE(value))
; ;
else if (ATTR_FALSE(value)) else if (ATTR_FALSE(value))
one->is_binary = 1; one->is_binary = 1;
/* hunk header ident */ /* funcname pattern ident */
value = attr_diff_check[1].value;
if (ATTR_TRUE(value) || ATTR_FALSE(value) || ATTR_UNSET(value)) if (ATTR_TRUE(value) || ATTR_FALSE(value) || ATTR_UNSET(value))
; ;
else else
one->hunk_header_ident = value; one->funcname_pattern_ident = value;
} }
if (!one->data && DIFF_FILE_VALID(one)) if (!one->data && DIFF_FILE_VALID(one))
@ -1154,54 +1201,23 @@ int diff_filespec_is_binary(struct diff_filespec *one)
return one->is_binary; return one->is_binary;
} }
static struct hunk_header_regexp { static const char *funcname_pattern(const char *ident)
char *name;
char *regexp;
struct hunk_header_regexp *next;
} *hunk_header_regexp_list, **hunk_header_regexp_tail;
static int hunk_header_config(const char *var, const char *value)
{ {
static const char funcname[] = "funcname."; struct funcname_pattern *pp;
struct hunk_header_regexp *hh;
if (prefixcmp(var, funcname)) read_config_if_needed();
return 0; for (pp = funcname_pattern_list; pp; pp = pp->next)
var += strlen(funcname); if (!strcmp(ident, pp->name))
for (hh = hunk_header_regexp_list; hh; hh = hh->next) return pp->pattern;
if (!strcmp(var, hh->name)) {
free(hh->regexp);
hh->regexp = xstrdup(value);
return 0;
}
hh = xcalloc(1, sizeof(*hh));
hh->name = xstrdup(var);
hh->regexp = xstrdup(value);
hh->next = NULL;
*hunk_header_regexp_tail = hh;
return 0;
}
static const char *hunk_header_regexp(const char *ident)
{
struct hunk_header_regexp *hh;
if (!hunk_header_regexp_tail) {
hunk_header_regexp_tail = &hunk_header_regexp_list;
git_config(hunk_header_config);
}
for (hh = hunk_header_regexp_list; hh; hh = hh->next)
if (!strcmp(ident, hh->name))
return hh->regexp;
return NULL; return NULL;
} }
static const char *diff_hunk_header_regexp(struct diff_filespec *one) static const char *diff_funcname_pattern(struct diff_filespec *one)
{ {
const char *ident, *regexp; const char *ident, *pattern;
diff_filespec_check_attr(one); diff_filespec_check_attr(one);
ident = one->hunk_header_ident; ident = one->funcname_pattern_ident;
if (!ident) if (!ident)
/* /*
@ -1209,12 +1225,12 @@ static const char *diff_hunk_header_regexp(struct diff_filespec *one)
* regexp is used; otherwise NULL is returned and xemit uses * regexp is used; otherwise NULL is returned and xemit uses
* the built-in default. * the built-in default.
*/ */
return hunk_header_regexp("default"); return funcname_pattern("default");
/* Look up custom "funcname.$ident" regexp from config. */ /* Look up custom "funcname.$ident" regexp from config. */
regexp = hunk_header_regexp(ident); pattern = funcname_pattern(ident);
if (regexp) if (pattern)
return regexp; return pattern;
/* /*
* And define built-in fallback patterns here. Note that * And define built-in fallback patterns here. Note that
@ -1304,11 +1320,11 @@ static void builtin_diff(const char *name_a,
xdemitconf_t xecfg; xdemitconf_t xecfg;
xdemitcb_t ecb; xdemitcb_t ecb;
struct emit_callback ecbdata; struct emit_callback ecbdata;
const char *hunk_header_regexp; const char *funcname_pattern;
hunk_header_regexp = diff_hunk_header_regexp(one); funcname_pattern = diff_funcname_pattern(one);
if (!hunk_header_regexp) if (!funcname_pattern)
hunk_header_regexp = diff_hunk_header_regexp(two); funcname_pattern = diff_funcname_pattern(two);
memset(&xecfg, 0, sizeof(xecfg)); memset(&xecfg, 0, sizeof(xecfg));
memset(&ecbdata, 0, sizeof(ecbdata)); memset(&ecbdata, 0, sizeof(ecbdata));
@ -1318,8 +1334,8 @@ static void builtin_diff(const char *name_a,
xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts; xpp.flags = XDF_NEED_MINIMAL | o->xdl_opts;
xecfg.ctxlen = o->context; xecfg.ctxlen = o->context;
xecfg.flags = XDL_EMIT_FUNCNAMES; xecfg.flags = XDL_EMIT_FUNCNAMES;
if (hunk_header_regexp) if (funcname_pattern)
xdiff_set_find_func(&xecfg, hunk_header_regexp); xdiff_set_find_func(&xecfg, funcname_pattern);
if (!diffopts) if (!diffopts)
; ;
else if (!prefixcmp(diffopts, "--unified=")) else if (!prefixcmp(diffopts, "--unified="))
@ -1862,10 +1878,7 @@ static const char *external_diff_attr(const char *name)
!ATTR_UNSET(value)) { !ATTR_UNSET(value)) {
struct ll_diff_driver *drv; struct ll_diff_driver *drv;
if (!user_diff_tail) { read_config_if_needed();
user_diff_tail = &user_diff;
git_config(git_diff_ui_config);
}
for (drv = user_diff; drv; drv = drv->next) for (drv = user_diff; drv; drv = drv->next)
if (!strcmp(drv->name, value)) if (!strcmp(drv->name, value))
return drv->cmd; return drv->cmd;

View File

@ -27,7 +27,7 @@ struct diff_filespec {
char *path; char *path;
void *data; void *data;
void *cnt_data; void *cnt_data;
const void *hunk_header_ident; const char *funcname_pattern_ident;
unsigned long size; unsigned long size;
int xfrm_flags; /* for use by the xfrm */ int xfrm_flags; /* for use by the xfrm */
unsigned short mode; /* file mode */ unsigned short mode; /* file mode */

View File

@ -38,12 +38,12 @@ test_expect_success 'default behaviour' '
' '
test_expect_success 'preset java pattern' ' test_expect_success 'preset java pattern' '
echo "*.java funcname=java" >.gitattributes && echo "*.java diff=java" >.gitattributes &&
git diff Beer.java Beer-correct.java | git diff Beer.java Beer-correct.java |
grep "^@@.*@@ public static void main(" grep "^@@.*@@ public static void main("
' '
git config funcname.java '!static git config diff.java.funcname '!static
!String !String
[^ ].*s.*' [^ ].*s.*'
@ -53,7 +53,7 @@ test_expect_success 'custom pattern' '
' '
test_expect_success 'last regexp must not be negated' ' test_expect_success 'last regexp must not be negated' '
git config diff.functionnameregexp "!static" && git config diff.java.funcname "!static" &&
! git diff Beer.java Beer-correct.java ! git diff Beer.java Beer-correct.java
' '