Merge branch 'bc/maint-diff-hunk-header-fix' into maint
* bc/maint-diff-hunk-header-fix: t4018-diff-funcname: test syntax of builtin xfuncname patterns diff hunk pattern: fix misconverted "\{" tex macro introducers diff: use extended regexp to find hunk headers diff.*.xfuncname which uses "extended" regex's for hunk header selection diff.c: associate a flag with each pattern and use it for compiling regex diff.c: return pattern entry pointer rather than just the hunk header pattern Conflicts: Documentation/gitattributes.txt
This commit is contained in:
commit
edb7e82f72
@ -288,13 +288,13 @@ for paths.
|
|||||||
*.tex diff=tex
|
*.tex diff=tex
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
Then, you would define a "diff.tex.funcname" configuration to
|
Then, you would define a "diff.tex.xfuncname" configuration to
|
||||||
specify a regular expression that matches a line that you would
|
specify a regular expression that matches a line that you would
|
||||||
want to appear as the hunk header "TEXT", like this:
|
want to appear as the hunk header "TEXT", like this:
|
||||||
|
|
||||||
------------------------
|
------------------------
|
||||||
[diff "tex"]
|
[diff "tex"]
|
||||||
funcname = "^\\(\\\\\\(sub\\)*section{.*\\)$"
|
xfuncname = "^(\\\\(sub)*section\\{.*)$"
|
||||||
------------------------
|
------------------------
|
||||||
|
|
||||||
Note. A single level of backslashes are eaten by the
|
Note. A single level of backslashes are eaten by the
|
||||||
|
98
diff.c
98
diff.c
@ -94,32 +94,37 @@ static int parse_lldiff_command(const char *var, const char *ep, const char *val
|
|||||||
* to define a customized regexp to find the beginning of a function to
|
* to define a customized regexp to find the beginning of a function to
|
||||||
* be used for hunk header lines of "diff -p" style output.
|
* be used for hunk header lines of "diff -p" style output.
|
||||||
*/
|
*/
|
||||||
static struct funcname_pattern {
|
struct funcname_pattern_entry {
|
||||||
char *name;
|
char *name;
|
||||||
char *pattern;
|
char *pattern;
|
||||||
struct funcname_pattern *next;
|
int cflags;
|
||||||
|
};
|
||||||
|
static struct funcname_pattern_list {
|
||||||
|
struct funcname_pattern_list *next;
|
||||||
|
struct funcname_pattern_entry e;
|
||||||
} *funcname_pattern_list;
|
} *funcname_pattern_list;
|
||||||
|
|
||||||
static int parse_funcname_pattern(const char *var, const char *ep, const char *value)
|
static int parse_funcname_pattern(const char *var, const char *ep, const char *value, int cflags)
|
||||||
{
|
{
|
||||||
const char *name;
|
const char *name;
|
||||||
int namelen;
|
int namelen;
|
||||||
struct funcname_pattern *pp;
|
struct funcname_pattern_list *pp;
|
||||||
|
|
||||||
name = var + 5; /* "diff." */
|
name = var + 5; /* "diff." */
|
||||||
namelen = ep - name;
|
namelen = ep - name;
|
||||||
|
|
||||||
for (pp = funcname_pattern_list; pp; pp = pp->next)
|
for (pp = funcname_pattern_list; pp; pp = pp->next)
|
||||||
if (!strncmp(pp->name, name, namelen) && !pp->name[namelen])
|
if (!strncmp(pp->e.name, name, namelen) && !pp->e.name[namelen])
|
||||||
break;
|
break;
|
||||||
if (!pp) {
|
if (!pp) {
|
||||||
pp = xcalloc(1, sizeof(*pp));
|
pp = xcalloc(1, sizeof(*pp));
|
||||||
pp->name = xmemdupz(name, namelen);
|
pp->e.name = xmemdupz(name, namelen);
|
||||||
pp->next = funcname_pattern_list;
|
pp->next = funcname_pattern_list;
|
||||||
funcname_pattern_list = pp;
|
funcname_pattern_list = pp;
|
||||||
}
|
}
|
||||||
free(pp->pattern);
|
free(pp->e.pattern);
|
||||||
pp->pattern = xstrdup(value);
|
pp->e.pattern = xstrdup(value);
|
||||||
|
pp->e.cflags = cflags;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,7 +187,13 @@ int git_diff_basic_config(const char *var, const char *value, void *cb)
|
|||||||
if (!strcmp(ep, ".funcname")) {
|
if (!strcmp(ep, ".funcname")) {
|
||||||
if (!value)
|
if (!value)
|
||||||
return config_error_nonbool(var);
|
return config_error_nonbool(var);
|
||||||
return parse_funcname_pattern(var, ep, value);
|
return parse_funcname_pattern(var, ep, value,
|
||||||
|
0);
|
||||||
|
} else if (!strcmp(ep, ".xfuncname")) {
|
||||||
|
if (!value)
|
||||||
|
return config_error_nonbool(var);
|
||||||
|
return parse_funcname_pattern(var, ep, value,
|
||||||
|
REG_EXTENDED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1377,39 +1388,40 @@ int diff_filespec_is_binary(struct diff_filespec *one)
|
|||||||
return one->is_binary;
|
return one->is_binary;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *funcname_pattern(const char *ident)
|
static const struct funcname_pattern_entry *funcname_pattern(const char *ident)
|
||||||
{
|
{
|
||||||
struct funcname_pattern *pp;
|
struct funcname_pattern_list *pp;
|
||||||
|
|
||||||
for (pp = funcname_pattern_list; pp; pp = pp->next)
|
for (pp = funcname_pattern_list; pp; pp = pp->next)
|
||||||
if (!strcmp(ident, pp->name))
|
if (!strcmp(ident, pp->e.name))
|
||||||
return pp->pattern;
|
return &pp->e;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct builtin_funcname_pattern {
|
static const struct funcname_pattern_entry builtin_funcname_pattern[] = {
|
||||||
const char *name;
|
{ "java",
|
||||||
const char *pattern;
|
"!^[ \t]*(catch|do|for|if|instanceof|new|return|switch|throw|while)\n"
|
||||||
} builtin_funcname_pattern[] = {
|
"^[ \t]*(([ \t]*[A-Za-z_][A-Za-z_0-9]*){2,}[ \t]*\\([^;]*)$",
|
||||||
{ "java", "!^[ ]*\\(catch\\|do\\|for\\|if\\|instanceof\\|"
|
REG_EXTENDED },
|
||||||
"new\\|return\\|switch\\|throw\\|while\\)\n"
|
{ "pascal",
|
||||||
"^[ ]*\\(\\([ ]*"
|
"^((procedure|function|constructor|destructor|interface|"
|
||||||
"[A-Za-z_][A-Za-z_0-9]*\\)\\{2,\\}"
|
"implementation|initialization|finalization)[ \t]*.*)$"
|
||||||
"[ ]*([^;]*\\)$" },
|
"|"
|
||||||
{ "pascal", "^\\(\\(procedure\\|function\\|constructor\\|"
|
"^(.*=[ \t]*(class|record).*)$",
|
||||||
"destructor\\|interface\\|implementation\\|"
|
REG_EXTENDED },
|
||||||
"initialization\\|finalization\\)[ \t]*.*\\)$"
|
{ "bibtex", "(@[a-zA-Z]{1,}[ \t]*\\{{0,1}[ \t]*[^ \t\"@',\\#}{~%]*).*$",
|
||||||
"\\|"
|
REG_EXTENDED },
|
||||||
"^\\(.*=[ \t]*\\(class\\|record\\).*\\)$"
|
{ "tex",
|
||||||
},
|
"^(\\\\((sub)*section|chapter|part)\\*{0,1}\\{.*)$",
|
||||||
{ "bibtex", "\\(@[a-zA-Z]\\{1,\\}[ \t]*{\\{0,1\\}[ \t]*[^ \t\"@',\\#}{~%]*\\).*$" },
|
REG_EXTENDED },
|
||||||
{ "tex", "^\\(\\\\\\(\\(sub\\)*section\\|chapter\\|part\\)\\*\\{0,1\\}{.*\\)$" },
|
{ "ruby", "^[ \t]*((class|module|def)[ \t].*)$",
|
||||||
{ "ruby", "^\\s*\\(\\(class\\|module\\|def\\)\\s.*\\)$" },
|
REG_EXTENDED },
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *diff_funcname_pattern(struct diff_filespec *one)
|
static const struct funcname_pattern_entry *diff_funcname_pattern(struct diff_filespec *one)
|
||||||
{
|
{
|
||||||
const char *ident, *pattern;
|
const char *ident;
|
||||||
|
const struct funcname_pattern_entry *pe;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
diff_filespec_check_attr(one);
|
diff_filespec_check_attr(one);
|
||||||
@ -1424,9 +1436,9 @@ static const char *diff_funcname_pattern(struct diff_filespec *one)
|
|||||||
return funcname_pattern("default");
|
return funcname_pattern("default");
|
||||||
|
|
||||||
/* Look up custom "funcname.$ident" regexp from config. */
|
/* Look up custom "funcname.$ident" regexp from config. */
|
||||||
pattern = funcname_pattern(ident);
|
pe = funcname_pattern(ident);
|
||||||
if (pattern)
|
if (pe)
|
||||||
return pattern;
|
return pe;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* And define built-in fallback patterns here. Note that
|
* And define built-in fallback patterns here. Note that
|
||||||
@ -1434,7 +1446,7 @@ static const char *diff_funcname_pattern(struct diff_filespec *one)
|
|||||||
*/
|
*/
|
||||||
for (i = 0; i < ARRAY_SIZE(builtin_funcname_pattern); i++)
|
for (i = 0; i < ARRAY_SIZE(builtin_funcname_pattern); i++)
|
||||||
if (!strcmp(ident, builtin_funcname_pattern[i].name))
|
if (!strcmp(ident, builtin_funcname_pattern[i].name))
|
||||||
return builtin_funcname_pattern[i].pattern;
|
return &builtin_funcname_pattern[i];
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -1512,11 +1524,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 *funcname_pattern;
|
const struct funcname_pattern_entry *pe;
|
||||||
|
|
||||||
funcname_pattern = diff_funcname_pattern(one);
|
pe = diff_funcname_pattern(one);
|
||||||
if (!funcname_pattern)
|
if (!pe)
|
||||||
funcname_pattern = diff_funcname_pattern(two);
|
pe = diff_funcname_pattern(two);
|
||||||
|
|
||||||
memset(&xecfg, 0, sizeof(xecfg));
|
memset(&xecfg, 0, sizeof(xecfg));
|
||||||
memset(&ecbdata, 0, sizeof(ecbdata));
|
memset(&ecbdata, 0, sizeof(ecbdata));
|
||||||
@ -1528,8 +1540,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 (funcname_pattern)
|
if (pe)
|
||||||
xdiff_set_find_func(&xecfg, funcname_pattern);
|
xdiff_set_find_func(&xecfg, pe->pattern, pe->cflags);
|
||||||
if (!diffopts)
|
if (!diffopts)
|
||||||
;
|
;
|
||||||
else if (!prefixcmp(diffopts, "--unified="))
|
else if (!prefixcmp(diffopts, "--unified="))
|
||||||
|
@ -32,7 +32,18 @@ EOF
|
|||||||
|
|
||||||
sed 's/beer\\/beer,\\/' < Beer.java > Beer-correct.java
|
sed 's/beer\\/beer,\\/' < Beer.java > Beer-correct.java
|
||||||
|
|
||||||
|
builtin_patterns="bibtex java pascal ruby tex"
|
||||||
|
for p in $builtin_patterns
|
||||||
|
do
|
||||||
|
test_expect_success "builtin $p pattern compiles" '
|
||||||
|
echo "*.java diff=$p" > .gitattributes &&
|
||||||
|
! ( git diff --no-index Beer.java Beer-correct.java 2>&1 |
|
||||||
|
grep "fatal" > /dev/null )
|
||||||
|
'
|
||||||
|
done
|
||||||
|
|
||||||
test_expect_success 'default behaviour' '
|
test_expect_success 'default behaviour' '
|
||||||
|
rm -f .gitattributes &&
|
||||||
git diff --no-index Beer.java Beer-correct.java |
|
git diff --no-index Beer.java Beer-correct.java |
|
||||||
grep "^@@.*@@ public class Beer"
|
grep "^@@.*@@ public class Beer"
|
||||||
'
|
'
|
||||||
@ -58,7 +69,7 @@ test_expect_success 'last regexp must not be negated' '
|
|||||||
'
|
'
|
||||||
|
|
||||||
test_expect_success 'alternation in pattern' '
|
test_expect_success 'alternation in pattern' '
|
||||||
git config diff.java.funcname "^[ ]*\\(\\(public\\|static\\).*\\)$"
|
git config diff.java.xfuncname "^[ ]*((public|static).*)$" &&
|
||||||
git diff --no-index Beer.java Beer-correct.java |
|
git diff --no-index Beer.java Beer-correct.java |
|
||||||
grep "^@@.*@@ public static void main("
|
grep "^@@.*@@ public static void main("
|
||||||
'
|
'
|
||||||
|
@ -206,7 +206,7 @@ static long ff_regexp(const char *line, long len,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void xdiff_set_find_func(xdemitconf_t *xecfg, const char *value)
|
void xdiff_set_find_func(xdemitconf_t *xecfg, const char *value, int cflags)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct ff_regs *regs;
|
struct ff_regs *regs;
|
||||||
@ -231,7 +231,7 @@ void xdiff_set_find_func(xdemitconf_t *xecfg, const char *value)
|
|||||||
expression = buffer = xstrndup(value, ep - value);
|
expression = buffer = xstrndup(value, ep - value);
|
||||||
else
|
else
|
||||||
expression = value;
|
expression = value;
|
||||||
if (regcomp(®->re, expression, 0))
|
if (regcomp(®->re, expression, cflags))
|
||||||
die("Invalid regexp to look for hunk header: %s", expression);
|
die("Invalid regexp to look for hunk header: %s", expression);
|
||||||
free(buffer);
|
free(buffer);
|
||||||
value = ep + 1;
|
value = ep + 1;
|
||||||
|
@ -21,6 +21,6 @@ int parse_hunk_header(char *line, int len,
|
|||||||
int read_mmfile(mmfile_t *ptr, const char *filename);
|
int read_mmfile(mmfile_t *ptr, const char *filename);
|
||||||
int buffer_is_binary(const char *ptr, unsigned long size);
|
int buffer_is_binary(const char *ptr, unsigned long size);
|
||||||
|
|
||||||
extern void xdiff_set_find_func(xdemitconf_t *xecfg, const char *line);
|
extern void xdiff_set_find_func(xdemitconf_t *xecfg, const char *line, int cflags);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user