mirror of
https://github.com/git/git
synced 2024-08-24 18:26:02 +00:00
builtin-apply: teach whitespace_rules
We earlier introduced core.whitespace to allow users to tweak the definition of what the "whitespace errors" are, for the purpose of diff output highlighting. This teaches the same to git-apply, so that the command can both detect (when --whitespace=warn option is given) and fix (when --whitespace=fix option is given) as configured. Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
81bf96bb2e
commit
d5a4164140
|
@ -910,23 +910,35 @@ static void check_whitespace(const char *line, int len)
|
|||
* this function. That is, an addition of an empty line would
|
||||
* check the '+' here. Sneaky...
|
||||
*/
|
||||
if (isspace(line[len-2]))
|
||||
if ((whitespace_rule & WS_TRAILING_SPACE) && isspace(line[len-2]))
|
||||
goto error;
|
||||
|
||||
/*
|
||||
* Make sure that there is no space followed by a tab in
|
||||
* indentation.
|
||||
*/
|
||||
err = "Space in indent is followed by a tab";
|
||||
for (i = 1; i < len; i++) {
|
||||
if (line[i] == '\t') {
|
||||
if (seen_space)
|
||||
goto error;
|
||||
if (whitespace_rule & WS_SPACE_BEFORE_TAB) {
|
||||
err = "Space in indent is followed by a tab";
|
||||
for (i = 1; i < len; i++) {
|
||||
if (line[i] == '\t') {
|
||||
if (seen_space)
|
||||
goto error;
|
||||
}
|
||||
else if (line[i] == ' ')
|
||||
seen_space = 1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
else if (line[i] == ' ')
|
||||
seen_space = 1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure that the indentation does not contain more than
|
||||
* 8 spaces.
|
||||
*/
|
||||
if ((whitespace_rule & WS_INDENT_WITH_NON_TAB) &&
|
||||
(8 < len) && !strncmp("+ ", line, 9)) {
|
||||
err = "Indent more than 8 places with spaces";
|
||||
goto error;
|
||||
}
|
||||
return;
|
||||
|
||||
|
@ -1581,7 +1593,8 @@ static int apply_line(char *output, const char *patch, int plen)
|
|||
/*
|
||||
* Strip trailing whitespace
|
||||
*/
|
||||
if (1 < plen && isspace(patch[plen-1])) {
|
||||
if ((whitespace_rule & WS_TRAILING_SPACE) &&
|
||||
(1 < plen && isspace(patch[plen-1]))) {
|
||||
if (patch[plen] == '\n')
|
||||
add_nl_to_tail = 1;
|
||||
plen--;
|
||||
|
@ -1597,11 +1610,16 @@ static int apply_line(char *output, const char *patch, int plen)
|
|||
char ch = patch[i];
|
||||
if (ch == '\t') {
|
||||
last_tab_in_indent = i;
|
||||
if (0 <= last_space_in_indent)
|
||||
if ((whitespace_rule & WS_SPACE_BEFORE_TAB) &&
|
||||
0 <= last_space_in_indent)
|
||||
need_fix_leading_space = 1;
|
||||
} else if (ch == ' ') {
|
||||
last_space_in_indent = i;
|
||||
if ((whitespace_rule & WS_INDENT_WITH_NON_TAB) &&
|
||||
last_tab_in_indent < 0 &&
|
||||
8 <= i)
|
||||
need_fix_leading_space = 1;
|
||||
}
|
||||
else if (ch == ' ')
|
||||
last_space_in_indent = i;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
@ -1609,11 +1627,21 @@ static int apply_line(char *output, const char *patch, int plen)
|
|||
buf = output;
|
||||
if (need_fix_leading_space) {
|
||||
int consecutive_spaces = 0;
|
||||
int last = last_tab_in_indent + 1;
|
||||
|
||||
if (whitespace_rule & WS_INDENT_WITH_NON_TAB) {
|
||||
/* have "last" point at one past the indent */
|
||||
if (last_tab_in_indent < last_space_in_indent)
|
||||
last = last_space_in_indent + 1;
|
||||
else
|
||||
last = last_tab_in_indent + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* between patch[1..last_tab_in_indent] strip the
|
||||
* funny spaces, updating them to tab as needed.
|
||||
* between patch[1..last], strip the funny spaces,
|
||||
* updating them to tab as needed.
|
||||
*/
|
||||
for (i = 1; i < last_tab_in_indent; i++, plen--) {
|
||||
for (i = 1; i < last; i++, plen--) {
|
||||
char ch = patch[i];
|
||||
if (ch != ' ') {
|
||||
consecutive_spaces = 0;
|
||||
|
@ -1626,8 +1654,10 @@ static int apply_line(char *output, const char *patch, int plen)
|
|||
}
|
||||
}
|
||||
}
|
||||
while (0 < consecutive_spaces--)
|
||||
*output++ = ' ';
|
||||
fixed = 1;
|
||||
i = last_tab_in_indent;
|
||||
i = last;
|
||||
}
|
||||
else
|
||||
i = 1;
|
||||
|
|
133
t/t4124-apply-ws-rule.sh
Executable file
133
t/t4124-apply-ws-rule.sh
Executable file
|
@ -0,0 +1,133 @@
|
|||
#!/bin/sh
|
||||
|
||||
test_description='core.whitespace rules and git-apply'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
prepare_test_file () {
|
||||
|
||||
# A line that has character X is touched iff RULE is in effect:
|
||||
# X RULE
|
||||
# ! trailing-space
|
||||
# @ space-before-tab
|
||||
# # indent-with-non-tab
|
||||
sed -e "s/_/ /g" -e "s/>/ /" <<-\EOF
|
||||
An_SP in an ordinary line>and a HT.
|
||||
>A HT.
|
||||
_>A SP and a HT (@).
|
||||
_>_A SP, a HT and a SP (@).
|
||||
_______Seven SP.
|
||||
________Eight SP (#).
|
||||
_______>Seven SP and a HT (@).
|
||||
________>Eight SP and a HT (@#).
|
||||
_______>_Seven SP, a HT and a SP (@).
|
||||
________>_Eight SP, a HT and a SP (@#).
|
||||
_______________Fifteen SP (#).
|
||||
_______________>Fifteen SP and a HT (@#).
|
||||
________________Sixteen SP (#).
|
||||
________________>Sixteen SP and a HT (@#).
|
||||
_____a__Five SP, a non WS, two SP.
|
||||
A line with a (!) trailing SP_
|
||||
A line with a (!) trailing HT>
|
||||
EOF
|
||||
}
|
||||
|
||||
apply_patch () {
|
||||
>target &&
|
||||
sed -e "s|\([ab]\)/file|\1/target|" <patch |
|
||||
git apply "$@"
|
||||
}
|
||||
|
||||
test_fix () {
|
||||
|
||||
# fix should not barf
|
||||
apply_patch --whitespace=fix || return 1
|
||||
|
||||
# find touched lines
|
||||
diff file target | sed -n -e "s/^> //p" >fixed
|
||||
|
||||
# the changed lines are all expeced to change
|
||||
fixed_cnt=$(wc -l <fixed)
|
||||
case "$1" in
|
||||
'') expect_cnt=$fixed_cnt ;;
|
||||
?*) expect_cnt=$(grep "[$1]" <fixed | wc -l) ;;
|
||||
esac
|
||||
test $fixed_cnt -eq $expect_cnt || return 1
|
||||
|
||||
# and we are not missing anything
|
||||
case "$1" in
|
||||
'') expect_cnt=0 ;;
|
||||
?*) expect_cnt=$(grep "[$1]" <file | wc -l) ;;
|
||||
esac
|
||||
test $fixed_cnt -eq $expect_cnt || return 1
|
||||
|
||||
# Get the patch actually applied
|
||||
git diff-files -p target >fixed-patch
|
||||
test -s fixed-patch && return 0
|
||||
|
||||
# Make sure it is complaint-free
|
||||
>target
|
||||
git apply --whitespace=error-all <fixed-patch
|
||||
|
||||
}
|
||||
|
||||
test_expect_success setup '
|
||||
|
||||
>file &&
|
||||
git add file &&
|
||||
prepare_test_file >file &&
|
||||
git diff-files -p >patch &&
|
||||
>target &&
|
||||
git add target
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'whitespace=nowarn, default rule' '
|
||||
|
||||
apply_patch --whitespace=nowarn &&
|
||||
diff file target
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'whitespace=warn, default rule' '
|
||||
|
||||
apply_patch --whitespace=warn &&
|
||||
diff file target
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'whitespace=error-all, default rule' '
|
||||
|
||||
apply_patch --whitespace=error-all && return 1
|
||||
test -s target && return 1
|
||||
: happy
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'whitespace=error-all, no rule' '
|
||||
|
||||
git config core.whitespace -trailing,-space-before,-indent &&
|
||||
apply_patch --whitespace=error-all &&
|
||||
diff file target
|
||||
|
||||
'
|
||||
|
||||
for t in - ''
|
||||
do
|
||||
case "$t" in '') tt='!' ;; *) tt= ;; esac
|
||||
for s in - ''
|
||||
do
|
||||
case "$s" in '') ts='@' ;; *) ts= ;; esac
|
||||
for i in - ''
|
||||
do
|
||||
case "$i" in '') ti='#' ;; *) ti= ;; esac
|
||||
rule=${t}trailing,${s}space,${i}indent &&
|
||||
test_expect_success "rule=$rule" '
|
||||
git config core.whitespace "$rule" &&
|
||||
test_fix "$tt$ts$ti"
|
||||
'
|
||||
done
|
||||
done
|
||||
done
|
||||
|
||||
test_done
|
Loading…
Reference in a new issue