Merge branch 'rs/include-comments-before-the-function-header'

"git grep -W", "git diff -W" and their friends learned a heuristic
to extend a pre-context beyond the line that matches the "function
pattern" (aka "diff.*.xfuncname") to include a comment block, if
exists, that immediately precedes it.

* rs/include-comments-before-the-function-header:
  grep: show non-empty lines before functions with -W
  grep: update boundary variable for pre-context
  t7810: improve check of -W with user-defined function lines
  xdiff: show non-empty lines before functions with -W
  xdiff: factor out is_func_rec()
  t4051: add test for comments preceding function lines
This commit is contained in:
Junio C Hamano 2017-11-28 13:41:50 +09:00
Родитель 3b49e1b0e9 a5dc20b070
Коммит f034901648
5 изменённых файлов: 76 добавлений и 20 удалений

35
grep.c
Просмотреть файл

@ -1476,31 +1476,52 @@ static void show_funcname_line(struct grep_opt *opt, struct grep_source *gs,
}
}
static int is_empty_line(const char *bol, const char *eol);
static void show_pre_context(struct grep_opt *opt, struct grep_source *gs,
char *bol, char *end, unsigned lno)
{
unsigned cur = lno, from = 1, funcname_lno = 0;
int funcname_needed = !!opt->funcname;
if (opt->funcbody && !match_funcname(opt, gs, bol, end))
funcname_needed = 2;
unsigned cur = lno, from = 1, funcname_lno = 0, orig_from;
int funcname_needed = !!opt->funcname, comment_needed = 0;
if (opt->pre_context < lno)
from = lno - opt->pre_context;
if (from <= opt->last_shown)
from = opt->last_shown + 1;
orig_from = from;
if (opt->funcbody) {
if (match_funcname(opt, gs, bol, end))
comment_needed = 1;
else
funcname_needed = 1;
from = opt->last_shown + 1;
}
/* Rewind. */
while (bol > gs->buf &&
cur > (funcname_needed == 2 ? opt->last_shown + 1 : from)) {
while (bol > gs->buf && cur > from) {
char *next_bol = bol;
char *eol = --bol;
while (bol > gs->buf && bol[-1] != '\n')
bol--;
cur--;
if (comment_needed && (is_empty_line(bol, eol) ||
match_funcname(opt, gs, bol, eol))) {
comment_needed = 0;
from = orig_from;
if (cur < from) {
cur++;
bol = next_bol;
break;
}
}
if (funcname_needed && match_funcname(opt, gs, bol, eol)) {
funcname_lno = cur;
funcname_needed = 0;
if (opt->funcbody)
comment_needed = 1;
else
from = orig_from;
}
}

Просмотреть файл

@ -85,6 +85,10 @@ test_expect_success 'setup' '
check_diff changed_hello 'changed function'
test_expect_success ' context includes comment' '
grep "^ .*Hello comment" changed_hello.diff
'
test_expect_success ' context includes begin' '
grep "^ .*Begin of hello" changed_hello.diff
'

Просмотреть файл

@ -1,4 +1,7 @@
/*
* Hello comment.
*/
static void hello(void) // Begin of hello
{
/*

Просмотреть файл

@ -60,6 +60,18 @@ test_expect_success setup '
echo " line with leading space3"
echo "line without leading space2"
} >space &&
cat >hello.ps1 <<-\EOF &&
# No-op.
function dummy() {}
# Say hello.
function hello() {
echo "Hello world."
} # hello
# Still a no-op.
function dummy() {}
EOF
git add . &&
test_tick &&
git commit -m initial
@ -766,18 +778,27 @@ test_expect_success 'grep -W shows no trailing empty lines' '
test_cmp expected actual
'
cat >expected <<EOF
hello.c= printf("Hello world.\n");
hello.c: return 0;
hello.c- /* char ?? */
EOF
test_expect_success 'grep -W with userdiff' '
test_when_finished "rm -f .gitattributes" &&
git config diff.custom.xfuncname "(printf.*|})$" &&
echo "hello.c diff=custom" >.gitattributes &&
git grep -W return >actual &&
test_cmp expected actual
git config diff.custom.xfuncname "^function .*$" &&
echo "hello.ps1 diff=custom" >.gitattributes &&
git grep -W echo >function-context-userdiff-actual
'
test_expect_success ' includes preceding comment' '
grep "# Say hello" function-context-userdiff-actual
'
test_expect_success ' includes function line' '
grep "=function hello" function-context-userdiff-actual
'
test_expect_success ' includes matching line' '
grep ": echo" function-context-userdiff-actual
'
test_expect_success ' includes last line of the function' '
grep "} # hello" function-context-userdiff-actual
'
for threads in $(test_seq 0 10)

Просмотреть файл

@ -121,6 +121,12 @@ static long match_func_rec(xdfile_t *xdf, xdemitconf_t const *xecfg, long ri,
return xecfg->find_func(rec, len, buf, sz, xecfg->find_func_priv);
}
static int is_func_rec(xdfile_t *xdf, xdemitconf_t const *xecfg, long ri)
{
char dummy[1];
return match_func_rec(xdf, xecfg, ri, dummy, sizeof(dummy)) >= 0;
}
struct func_line {
long len;
char buf[80];
@ -178,7 +184,6 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
/* Appended chunk? */
if (i1 >= xe->xdf1.nrec) {
char dummy[1];
long i2 = xch->i2;
/*
@ -186,8 +191,7 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
* a whole function was added.
*/
while (i2 < xe->xdf2.nrec) {
if (match_func_rec(&xe->xdf2, xecfg, i2,
dummy, sizeof(dummy)) >= 0)
if (is_func_rec(&xe->xdf2, xecfg, i2))
goto post_context_calculation;
i2++;
}
@ -200,6 +204,9 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
}
fs1 = get_func_line(xe, xecfg, NULL, i1, -1);
while (fs1 > 0 && !is_empty_rec(&xe->xdf1, fs1 - 1) &&
!is_func_rec(&xe->xdf1, xecfg, fs1 - 1))
fs1--;
if (fs1 < 0)
fs1 = 0;
if (fs1 < s1) {