29
static enum {
30
ALLOW_NO_CONTROL_CHARACTERS = 0,
31
ALLOW_ANSI_COLOR_SEQUENCES = 1<<0,
32
+ ALLOW_ANSI_CURSOR_MOVEMENTS = 1<<1,
33
+ ALLOW_ANSI_ERASE = 1<<2,
34
ALLOW_DEFAULT_ANSI_SEQUENCES = ALLOW_ANSI_COLOR_SEQUENCES,
33
- ALLOW_ALL_CONTROL_CHARACTERS = 1<<1,
34
-} allow_control_characters = ALLOW_ANSI_COLOR_SEQUENCES;
35
+ ALLOW_ALL_CONTROL_CHARACTERS = 1<<3,
36
+} allow_control_characters = ALLOW_DEFAULT_ANSI_SEQUENCES;
37
+
38
+static inline int skip_prefix_in_csv(const char *value, const char *prefix,
39
+ const char **out)
40
+{
41
+ if (!skip_prefix(value, prefix, &value) ||
42
+ (*value && *value != ','))
43
+ return 0;
44
+ *out = value + !!*value;
45
+ return 1;
46
+}
47
+
48
+static void parse_allow_control_characters(const char *value)
49
+{
50
+ allow_control_characters = ALLOW_NO_CONTROL_CHARACTERS;
51
+ while (*value) {
52
+ if (skip_prefix_in_csv(value, "default", &value))
53
+ allow_control_characters |= ALLOW_DEFAULT_ANSI_SEQUENCES;
54
+ else if (skip_prefix_in_csv(value, "color", &value))
55
+ allow_control_characters |= ALLOW_ANSI_COLOR_SEQUENCES;
56
+ else if (skip_prefix_in_csv(value, "cursor", &value))
57
+ allow_control_characters |= ALLOW_ANSI_CURSOR_MOVEMENTS;
58
+ else if (skip_prefix_in_csv(value, "erase", &value))
59
+ allow_control_characters |= ALLOW_ANSI_ERASE;
60
+ else if (skip_prefix_in_csv(value, "true", &value))
61
+ allow_control_characters = ALLOW_ALL_CONTROL_CHARACTERS;
62
+ else if (skip_prefix_in_csv(value, "false", &value))
63
+ allow_control_characters = ALLOW_NO_CONTROL_CHARACTERS;
64
+ else
65
+ warning(_("unrecognized value for `sideband."
66
+ "allowControlCharacters`: '%s'"), value);
67
+ }
68
+}
69
70
/* Returns a color setting (GIT_COLOR_NEVER, etc). */
71
static enum git_colorbool use_sideband_colors(void)
89
if (repo_config_get_string_tmp(the_repository, "sideband.allowcontrolcharacters",
90
&value))
91
; /* huh? `get_maybe_bool()` returned -1 */
58
- else if (!strcmp(value, "default"))
59
- allow_control_characters = ALLOW_DEFAULT_ANSI_SEQUENCES;
60
- else if (!strcmp(value, "color"))
61
- allow_control_characters = ALLOW_ANSI_COLOR_SEQUENCES;
92
else
63
- warning(_("unrecognized value for `sideband."
64
- "allowControlCharacters`: '%s'"), value);
93
+ parse_allow_control_characters(value);
94
break;
95
default:
96
break; /* not configured */
123
list_config_item(list, prefix, keywords[i].keyword);
124
}
125
97
-static int handle_ansi_color_sequence(struct strbuf *dest, const char *src, int n)
126
+static int handle_ansi_sequence(struct strbuf *dest, const char *src, int n)
127
{
128
int i;
129
135
* These are part of the Select Graphic Rendition sequences which
136
* contain more than just color sequences, for more details see
137
* https://en.wikipedia.org/wiki/ANSI_escape_code#SGR.
138
+ *
139
+ * The cursor movement sequences are:
140
+ *
141
+ * ESC [ n A - Cursor up n lines (CUU)
142
+ * ESC [ n B - Cursor down n lines (CUD)
143
+ * ESC [ n C - Cursor forward n columns (CUF)
144
+ * ESC [ n D - Cursor back n columns (CUB)
145
+ * ESC [ n E - Cursor next line, beginning (CNL)
146
+ * ESC [ n F - Cursor previous line, beginning (CPL)
147
+ * ESC [ n G - Cursor to column n (CHA)
148
+ * ESC [ n ; m H - Cursor position (row n, col m) (CUP)
149
+ * ESC [ n ; m f - Same as H (HVP)
150
+ *
151
+ * The sequences to erase characters are:
152
+ *
153
+ *
154
+ * ESC [ 0 J - Clear from cursor to end of screen (ED)
155
+ * ESC [ 1 J - Clear from cursor to beginning of screen (ED)
156
+ * ESC [ 2 J - Clear entire screen (ED)
157
+ * ESC [ 3 J - Clear entire screen + scrollback (ED) - xterm extension
158
+ * ESC [ 0 K - Clear from cursor to end of line (EL)
159
+ * ESC [ 1 K - Clear from cursor to beginning of line (EL)
160
+ * ESC [ 2 K - Clear entire line (EL)
161
+ * ESC [ n M - Delete n lines (DL)
162
+ * ESC [ n P - Delete n characters (DCH)
163
+ * ESC [ n X - Erase n characters (ECH)
164
+ *
165
+ * For a comprehensive list of common ANSI Escape sequences, see
166
+ * https://www.xfree86.org/current/ctlseqs.html
167
*/
168
111
- if (allow_control_characters != ALLOW_ANSI_COLOR_SEQUENCES ||
112
- n < 3 || src[0] != '\x1b' || src[1] != '[')
169
+ if (n < 3 || src[0] != '\x1b' || src[1] != '[')
170
return 0;
171
172
for (i = 2; i < n; i++) {
116
- if (src[i] == 'm') {
173
+ if (((allow_control_characters & ALLOW_ANSI_COLOR_SEQUENCES) &&
174
+ src[i] == 'm') ||
175
+ ((allow_control_characters & ALLOW_ANSI_CURSOR_MOVEMENTS) &&
176
+ strchr("ABCDEFGHf", src[i])) ||
177
+ ((allow_control_characters & ALLOW_ANSI_ERASE) &&
178
+ strchr("JKMPX", src[i]))) {
179
strbuf_add(dest, src, i + 1);
180
return i;
181
}
190
{
191
int i;
192
131
- if (allow_control_characters == ALLOW_ALL_CONTROL_CHARACTERS) {
193
+ if ((allow_control_characters & ALLOW_ALL_CONTROL_CHARACTERS)) {
194
strbuf_add(dest, src, n);
195
return;
196
}
199
for (; n && *src; src++, n--) {
200
if (!iscntrl(*src) || *src == '\t' || *src == '\n') {
201
strbuf_addch(dest, *src);
140
- } else if ((i = handle_ansi_color_sequence(dest, src, n))) {
202
+ } else if (allow_control_characters != ALLOW_NO_CONTROL_CHARACTERS &&
203
+ (i = handle_ansi_sequence(dest, src, n))) {
204
src += i;
205
n -= i;
206
} else {