whitespace: allocate a few more bits and define WS_INCOMPLETE_LINE

Reserve a few more bits in the diff flags word to be used for future whitespace rules. Add WS_INCOMPLETE_LINE without implementing the behaviour (yet). Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed Nov 12, 2025 at 14:02 UTC a675104c399d242dd3ff5a0823fcd770563cf60f
5 files changed +21 -12
Documentation/config/core.adoc
+2
@@ -626,6 +626,8 @@ core.whitespace::
626 part of the line terminator, i.e. with it, `trailing-space`
627 does not trigger if the character before such a carriage-return
628 is not a whitespace (not enabled by default).
629 +* `incomplete-line` treats the last line of a file that is missing the
630 + newline at the end as an error (not enabled by default).
631 * `tabwidth=<n>` tells how many character positions a tab occupies; this
632 is relevant for `indent-with-non-tab` and when Git fixes `tab-in-indent`
633 errors. The default tab width is 8. Allowed values are 1 to 63.
diff.c
+8 -8
@@ -804,15 +804,15 @@ enum diff_symbol {
804
805 /*
806 * Flags for content lines:
807 - * 0..11 are whitespace rules (see ws.h)
808 - * 12..14 are WSEH_NEW | WSEH_CONTEXT | WSEH_OLD
809 - * 16 is marking if the line is blank at EOF
810 - * 17..19 are used for color-moved.
807 + * 0..15 are whitespace rules (see ws.h)
808 + * 16..18 are WSEH_NEW | WSEH_CONTEXT | WSEH_OLD
809 + * 19 is marking if the line is blank at EOF
810 + * 20..22 are used for color-moved.
811 */
812 -#define DIFF_SYMBOL_CONTENT_BLANK_LINE_EOF (1<<16)
813 -#define DIFF_SYMBOL_MOVED_LINE (1<<17)
814 -#define DIFF_SYMBOL_MOVED_LINE_ALT (1<<18)
815 -#define DIFF_SYMBOL_MOVED_LINE_UNINTERESTING (1<<19)
812 +#define DIFF_SYMBOL_CONTENT_BLANK_LINE_EOF (1<<19)
813 +#define DIFF_SYMBOL_MOVED_LINE (1<<20)
814 +#define DIFF_SYMBOL_MOVED_LINE_ALT (1<<21)
815 +#define DIFF_SYMBOL_MOVED_LINE_UNINTERESTING (1<<22)
816
817 #define DIFF_SYMBOL_CONTENT_WS_MASK (WSEH_NEW | WSEH_OLD | WSEH_CONTEXT | WS_RULE_MASK)
818
diff.h
+3 -3
@@ -331,9 +331,9 @@ struct diff_options {
331
332 int ita_invisible_in_index;
333 /* white-space error highlighting */
334 -#define WSEH_NEW (1<<12)
335 -#define WSEH_CONTEXT (1<<13)
336 -#define WSEH_OLD (1<<14)
334 +#define WSEH_NEW (1<<16)
335 +#define WSEH_CONTEXT (1<<17)
336 +#define WSEH_OLD (1<<18)
337 unsigned ws_error_highlight;
338 const char *prefix;
339 int prefix_length;
ws.c
+6
@@ -26,6 +26,7 @@ static struct whitespace_rule {
26 { "blank-at-eol", WS_BLANK_AT_EOL, 0 },
27 { "blank-at-eof", WS_BLANK_AT_EOF, 0 },
28 { "tab-in-indent", WS_TAB_IN_INDENT, 0, 1 },
29 + { "incomplete-line", WS_INCOMPLETE_LINE, 0, 0 },
30 };
31
32 unsigned parse_whitespace_rule(const char *string)
@@ -139,6 +140,11 @@ char *whitespace_error_string(unsigned ws)
140 strbuf_addstr(&err, ", ");
141 strbuf_addstr(&err, "tab in indent");
142 }
143 + if (ws & WS_INCOMPLETE_LINE) {
144 + if (err.len)
145 + strbuf_addstr(&err, ", ");
146 + strbuf_addstr(&err, "no newline at the end of file");
147 + }
148 return strbuf_detach(&err, NULL);
149 }
150
ws.h
+2 -1
@@ -15,13 +15,14 @@ struct strbuf;
15 #define WS_CR_AT_EOL (1<<9)
16 #define WS_BLANK_AT_EOF (1<<10)
17 #define WS_TAB_IN_INDENT (1<<11)
18 +#define WS_INCOMPLETE_LINE (1<<12)
19
20 #define WS_TRAILING_SPACE (WS_BLANK_AT_EOL|WS_BLANK_AT_EOF)
21 #define WS_DEFAULT_RULE (WS_TRAILING_SPACE|WS_SPACE_BEFORE_TAB|8)
22 #define WS_TAB_WIDTH_MASK ((1<<6)-1)
23
24 /* All WS_* -- when extended, adapt constants defined after diff.c:diff_symbol */
24 -#define WS_RULE_MASK ((1<<12)-1)
25 +#define WS_RULE_MASK ((1<<16)-1)
26
27 extern unsigned whitespace_rule_cfg;
28 unsigned whitespace_rule(struct index_state *, const char *);