Skip to content

Commit c58c512

Browse files
committed
Merge branch 'cw/ws-indent-with-tab'
* cw/ws-indent-with-tab: whitespace: tests for git-apply --whitespace=fix with tab-in-indent whitespace: add tab-in-indent support for --whitespace=fix whitespace: replumb ws_fix_copy to take a strbuf *dst instead of char *dst whitespace: tests for git-diff --check with tab-in-indent error class whitespace: add tab-in-indent error class whitespace: we cannot "catch all errors known to git" anymore
2 parents f78eeea + a347b17 commit c58c512

File tree

6 files changed

+162
-85
lines changed

6 files changed

+162
-85
lines changed

Documentation/config.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,8 @@ core.whitespace::
481481
error (enabled by default).
482482
* `indent-with-non-tab` treats a line that is indented with 8 or more
483483
space characters as an error (not enabled by default).
484+
* `tab-in-indent` treats a tab character in the initial indent part of
485+
the line as an error (not enabled by default).
484486
* `blank-at-eof` treats blank lines added at the end of file as an error
485487
(enabled by default).
486488
* `trailing-space` is a short-hand to cover both `blank-at-eol` and

builtin/apply.c

Lines changed: 39 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1854,6 +1854,8 @@ static int match_fragment(struct image *img,
18541854
{
18551855
int i;
18561856
char *fixed_buf, *buf, *orig, *target;
1857+
struct strbuf fixed;
1858+
size_t fixed_len;
18571859
int preimage_limit;
18581860

18591861
if (preimage->nr + try_lno <= img->nr) {
@@ -1977,12 +1979,12 @@ static int match_fragment(struct image *img,
19771979
* use the whitespace from the preimage.
19781980
*/
19791981
extra_chars = preimage_end - preimage_eof;
1980-
fixed_buf = xmalloc(imgoff + extra_chars);
1981-
memcpy(fixed_buf, img->buf + try, imgoff);
1982-
memcpy(fixed_buf + imgoff, preimage_eof, extra_chars);
1983-
imgoff += extra_chars;
1982+
strbuf_init(&fixed, imgoff + extra_chars);
1983+
strbuf_add(&fixed, img->buf + try, imgoff);
1984+
strbuf_add(&fixed, preimage_eof, extra_chars);
1985+
fixed_buf = strbuf_detach(&fixed, &fixed_len);
19841986
update_pre_post_images(preimage, postimage,
1985-
fixed_buf, imgoff, postlen);
1987+
fixed_buf, fixed_len, postlen);
19861988
return 1;
19871989
}
19881990

@@ -1999,27 +2001,22 @@ static int match_fragment(struct image *img,
19992001
* but in this loop we will only handle the part of the
20002002
* preimage that falls within the file.
20012003
*/
2002-
fixed_buf = xmalloc(preimage->len + 1);
2003-
buf = fixed_buf;
2004+
strbuf_init(&fixed, preimage->len + 1);
20042005
orig = preimage->buf;
20052006
target = img->buf + try;
20062007
for (i = 0; i < preimage_limit; i++) {
2007-
size_t fixlen; /* length after fixing the preimage */
20082008
size_t oldlen = preimage->line[i].len;
20092009
size_t tgtlen = img->line[try_lno + i].len;
2010-
size_t tgtfixlen; /* length after fixing the target line */
2011-
char tgtfixbuf[1024], *tgtfix;
2010+
size_t fixstart = fixed.len;
2011+
struct strbuf tgtfix;
20122012
int match;
20132013

20142014
/* Try fixing the line in the preimage */
2015-
fixlen = ws_fix_copy(buf, orig, oldlen, ws_rule, NULL);
2015+
ws_fix_copy(&fixed, orig, oldlen, ws_rule, NULL);
20162016

20172017
/* Try fixing the line in the target */
2018-
if (sizeof(tgtfixbuf) > tgtlen)
2019-
tgtfix = tgtfixbuf;
2020-
else
2021-
tgtfix = xmalloc(tgtlen);
2022-
tgtfixlen = ws_fix_copy(tgtfix, target, tgtlen, ws_rule, NULL);
2018+
strbuf_init(&tgtfix, tgtlen);
2019+
ws_fix_copy(&tgtfix, target, tgtlen, ws_rule, NULL);
20232020

20242021
/*
20252022
* If they match, either the preimage was based on
@@ -2031,15 +2028,15 @@ static int match_fragment(struct image *img,
20312028
* so we might as well take the fix together with their
20322029
* real change.
20332030
*/
2034-
match = (tgtfixlen == fixlen && !memcmp(tgtfix, buf, fixlen));
2031+
match = (tgtfix.len == fixed.len - fixstart &&
2032+
!memcmp(tgtfix.buf, fixed.buf + fixstart,
2033+
fixed.len - fixstart));
20352034

2036-
if (tgtfix != tgtfixbuf)
2037-
free(tgtfix);
2035+
strbuf_release(&tgtfix);
20382036
if (!match)
20392037
goto unmatch_exit;
20402038

20412039
orig += oldlen;
2042-
buf += fixlen;
20432040
target += tgtlen;
20442041
}
20452042

@@ -2051,32 +2048,32 @@ static int match_fragment(struct image *img,
20512048
* false).
20522049
*/
20532050
for ( ; i < preimage->nr; i++) {
2054-
size_t fixlen; /* length after fixing the preimage */
2051+
size_t fixstart = fixed.len; /* start of the fixed preimage */
20552052
size_t oldlen = preimage->line[i].len;
20562053
int j;
20572054

20582055
/* Try fixing the line in the preimage */
2059-
fixlen = ws_fix_copy(buf, orig, oldlen, ws_rule, NULL);
2056+
ws_fix_copy(&fixed, orig, oldlen, ws_rule, NULL);
20602057

2061-
for (j = 0; j < fixlen; j++)
2062-
if (!isspace(buf[j]))
2058+
for (j = fixstart; j < fixed.len; j++)
2059+
if (!isspace(fixed.buf[j]))
20632060
goto unmatch_exit;
20642061

20652062
orig += oldlen;
2066-
buf += fixlen;
20672063
}
20682064

20692065
/*
20702066
* Yes, the preimage is based on an older version that still
20712067
* has whitespace breakages unfixed, and fixing them makes the
20722068
* hunk match. Update the context lines in the postimage.
20732069
*/
2070+
fixed_buf = strbuf_detach(&fixed, &fixed_len);
20742071
update_pre_post_images(preimage, postimage,
2075-
fixed_buf, buf - fixed_buf, 0);
2072+
fixed_buf, fixed_len, 0);
20762073
return 1;
20772074

20782075
unmatch_exit:
2079-
free(fixed_buf);
2076+
strbuf_release(&fixed);
20802077
return 0;
20812078
}
20822079

@@ -2244,7 +2241,8 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
22442241
int match_beginning, match_end;
22452242
const char *patch = frag->patch;
22462243
int size = frag->size;
2247-
char *old, *new, *oldlines, *newlines;
2244+
char *old, *oldlines;
2245+
struct strbuf newlines;
22482246
int new_blank_lines_at_end = 0;
22492247
unsigned long leading, trailing;
22502248
int pos, applied_pos;
@@ -2254,16 +2252,16 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
22542252
memset(&preimage, 0, sizeof(preimage));
22552253
memset(&postimage, 0, sizeof(postimage));
22562254
oldlines = xmalloc(size);
2257-
newlines = xmalloc(size);
2255+
strbuf_init(&newlines, size);
22582256

22592257
old = oldlines;
2260-
new = newlines;
22612258
while (size > 0) {
22622259
char first;
22632260
int len = linelen(patch, size);
2264-
int plen, added;
2261+
int plen;
22652262
int added_blank_line = 0;
22662263
int is_blank_context = 0;
2264+
size_t start;
22672265

22682266
if (!len)
22692267
break;
@@ -2293,7 +2291,7 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
22932291
/* ... followed by '\No newline'; nothing */
22942292
break;
22952293
*old++ = '\n';
2296-
*new++ = '\n';
2294+
strbuf_addch(&newlines, '\n');
22972295
add_line_info(&preimage, "\n", 1, LINE_COMMON);
22982296
add_line_info(&postimage, "\n", 1, LINE_COMMON);
22992297
is_blank_context = 1;
@@ -2315,18 +2313,17 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
23152313
if (first == '+' && no_add)
23162314
break;
23172315

2316+
start = newlines.len;
23182317
if (first != '+' ||
23192318
!whitespace_error ||
23202319
ws_error_action != correct_ws_error) {
2321-
memcpy(new, patch + 1, plen);
2322-
added = plen;
2320+
strbuf_add(&newlines, patch + 1, plen);
23232321
}
23242322
else {
2325-
added = ws_fix_copy(new, patch + 1, plen, ws_rule, &applied_after_fixing_ws);
2323+
ws_fix_copy(&newlines, patch + 1, plen, ws_rule, &applied_after_fixing_ws);
23262324
}
2327-
add_line_info(&postimage, new, added,
2325+
add_line_info(&postimage, newlines.buf + start, newlines.len - start,
23282326
(first == '+' ? 0 : LINE_COMMON));
2329-
new += added;
23302327
if (first == '+' &&
23312328
(ws_rule & WS_BLANK_AT_EOF) &&
23322329
ws_blank_line(patch + 1, plen, ws_rule))
@@ -2351,9 +2348,9 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
23512348
}
23522349
if (inaccurate_eof &&
23532350
old > oldlines && old[-1] == '\n' &&
2354-
new > newlines && new[-1] == '\n') {
2351+
newlines.len > 0 && newlines.buf[newlines.len - 1] == '\n') {
23552352
old--;
2356-
new--;
2353+
strbuf_setlen(&newlines, newlines.len - 1);
23572354
}
23582355

23592356
leading = frag->leading;
@@ -2385,8 +2382,8 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
23852382
pos = frag->newpos ? (frag->newpos - 1) : 0;
23862383
preimage.buf = oldlines;
23872384
preimage.len = old - oldlines;
2388-
postimage.buf = newlines;
2389-
postimage.len = new - newlines;
2385+
postimage.buf = newlines.buf;
2386+
postimage.len = newlines.len;
23902387
preimage.line = preimage.line_allocated;
23912388
postimage.line = postimage.line_allocated;
23922389

@@ -2462,7 +2459,7 @@ static int apply_one_fragment(struct image *img, struct fragment *frag,
24622459
}
24632460

24642461
free(oldlines);
2465-
free(newlines);
2462+
strbuf_release(&newlines);
24662463
free(preimage.line_allocated);
24672464
free(postimage.line_allocated);
24682465

cache.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1042,6 +1042,7 @@ void shift_tree_by(const unsigned char *, const unsigned char *, unsigned char *
10421042
#define WS_INDENT_WITH_NON_TAB 04
10431043
#define WS_CR_AT_EOL 010
10441044
#define WS_BLANK_AT_EOF 020
1045+
#define WS_TAB_IN_INDENT 040
10451046
#define WS_TRAILING_SPACE (WS_BLANK_AT_EOL|WS_BLANK_AT_EOF)
10461047
#define WS_DEFAULT_RULE (WS_TRAILING_SPACE|WS_SPACE_BEFORE_TAB)
10471048
extern unsigned whitespace_rule_cfg;
@@ -1050,7 +1051,7 @@ extern unsigned parse_whitespace_rule(const char *);
10501051
extern unsigned ws_check(const char *line, int len, unsigned ws_rule);
10511052
extern void ws_check_emit(const char *line, int len, unsigned ws_rule, FILE *stream, const char *set, const char *reset, const char *ws);
10521053
extern char *whitespace_error_string(unsigned ws);
1053-
extern int ws_fix_copy(char *, const char *, int, unsigned, int *);
1054+
extern void ws_fix_copy(struct strbuf *, const char *, int, unsigned, int *);
10541055
extern int ws_blank_line(const char *line, int len, unsigned ws_rule);
10551056

10561057
/* ls-files */

t/t4015-diff-whitespace.sh

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,48 @@ test_expect_success 'check tabs and spaces as indentation (indent-with-non-tab:
352352
353353
'
354354

355+
test_expect_success 'check tabs as indentation (tab-in-indent: off)' '
356+
357+
git config core.whitespace "-tab-in-indent" &&
358+
echo " foo ();" > x &&
359+
git diff --check
360+
361+
'
362+
363+
test_expect_success 'check tabs as indentation (tab-in-indent: on)' '
364+
365+
git config core.whitespace "tab-in-indent" &&
366+
echo " foo ();" > x &&
367+
test_must_fail git diff --check
368+
369+
'
370+
371+
test_expect_success 'check tabs and spaces as indentation (tab-in-indent: on)' '
372+
373+
git config core.whitespace "tab-in-indent" &&
374+
echo " foo ();" > x &&
375+
test_must_fail git diff --check
376+
377+
'
378+
379+
test_expect_success 'check tab-in-indent and indent-with-non-tab conflict' '
380+
381+
git config core.whitespace "tab-in-indent,indent-with-non-tab" &&
382+
echo "foo ();" > x &&
383+
test_must_fail git diff --check
384+
385+
'
386+
387+
test_expect_success 'check tab-in-indent excluded from wildcard whitespace attribute' '
388+
389+
git config --unset core.whitespace &&
390+
echo "x whitespace" > .gitattributes &&
391+
echo " foo ();" > x &&
392+
git diff --check &&
393+
rm -f .gitattributes
394+
395+
'
396+
355397
test_expect_success 'line numbers in --check output are correct' '
356398
357399
echo "" > x &&

t/t4124-apply-ws-rule.sh

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,22 @@ prepare_test_file () {
1111
# ! trailing-space
1212
# @ space-before-tab
1313
# # indent-with-non-tab
14+
# % tab-in-indent
1415
sed -e "s/_/ /g" -e "s/>/ /" <<-\EOF
1516
An_SP in an ordinary line>and a HT.
16-
>A HT.
17-
_>A SP and a HT (@).
18-
_>_A SP, a HT and a SP (@).
17+
>A HT (%).
18+
_>A SP and a HT (@%).
19+
_>_A SP, a HT and a SP (@%).
1920
_______Seven SP.
2021
________Eight SP (#).
21-
_______>Seven SP and a HT (@).
22-
________>Eight SP and a HT (@#).
23-
_______>_Seven SP, a HT and a SP (@).
24-
________>_Eight SP, a HT and a SP (@#).
22+
_______>Seven SP and a HT (@%).
23+
________>Eight SP and a HT (@#%).
24+
_______>_Seven SP, a HT and a SP (@%).
25+
________>_Eight SP, a HT and a SP (@#%).
2526
_______________Fifteen SP (#).
26-
_______________>Fifteen SP and a HT (@#).
27+
_______________>Fifteen SP and a HT (@#%).
2728
________________Sixteen SP (#).
28-
________________>Sixteen SP and a HT (@#).
29+
________________>Sixteen SP and a HT (@#%).
2930
_____a__Five SP, a non WS, two SP.
3031
A line with a (!) trailing SP_
3132
A line with a (!) trailing HT>
@@ -39,7 +40,6 @@ apply_patch () {
3940
}
4041

4142
test_fix () {
42-
4343
# fix should not barf
4444
apply_patch --whitespace=fix || return 1
4545

@@ -130,20 +130,25 @@ do
130130
for i in - ''
131131
do
132132
case "$i" in '') ti='#' ;; *) ti= ;; esac
133-
rule=${t}trailing,${s}space,${i}indent
134-
135-
rm -f .gitattributes
136-
test_expect_success "rule=$rule" '
137-
git config core.whitespace "$rule" &&
138-
test_fix "$tt$ts$ti"
139-
'
140-
141-
test_expect_success "rule=$rule (attributes)" '
142-
git config --unset core.whitespace &&
143-
echo "target whitespace=$rule" >.gitattributes &&
144-
test_fix "$tt$ts$ti"
145-
'
146-
133+
for h in - ''
134+
do
135+
[ -z "$h$i" ] && continue
136+
case "$h" in '') th='%' ;; *) th= ;; esac
137+
rule=${t}trailing,${s}space,${i}indent,${h}tab
138+
139+
rm -f .gitattributes
140+
test_expect_success "rule=$rule" '
141+
git config core.whitespace "$rule" &&
142+
test_fix "$tt$ts$ti$th"
143+
'
144+
145+
test_expect_success "rule=$rule (attributes)" '
146+
git config --unset core.whitespace &&
147+
echo "target whitespace=$rule" >.gitattributes &&
148+
test_fix "$tt$ts$ti$th"
149+
'
150+
151+
done
147152
done
148153
done
149154
done

0 commit comments

Comments
 (0)