Skip to content

Commit a575234

Browse files
pcloudsgitster
authored andcommitted
pretty: support padding placeholders, %< %> and %><
Either %<, %> or %>< standing before a placeholder specifies how many columns (at least as the placeholder can exceed it) it takes. Each differs on how spaces are padded: %< pads on the right (aka left alignment) %> pads on the left (aka right alignment) %>< pads both ways equally (aka centered) The (<N>) follows them, e.g. `%<(100)', to specify the number of columns the next placeholder takes. However, if '|' stands before (<N>), e.g. `%>|(100)', then the number of columns is calculated so that it reaches the Nth column on screen. Signed-off-by: Nguyễn Thái Ngọc Duy <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent a95f067 commit a575234

File tree

3 files changed

+246
-1
lines changed

3 files changed

+246
-1
lines changed

Documentation/pretty-formats.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,14 @@ The placeholders are:
164164
- '%x00': print a byte from a hex code
165165
- '%w([<w>[,<i1>[,<i2>]]])': switch line wrapping, like the -w option of
166166
linkgit:git-shortlog[1].
167+
- '%<(<N>)': make the next placeholder take at least N columns,
168+
padding spaces on the right if necessary
169+
- '%<|(<N>)': make the next placeholder take at least until Nth
170+
columns, padding spaces on the right if necessary
171+
- '%>(<N>)', '%>|(<N>)': similar to '%<(<N>)', '%<|(<N>)'
172+
respectively, but padding spaces on the left
173+
- '%><(<N>)', '%><|(<N>)': similar to '%<(<N>)', '%<|(<N>)'
174+
respectively, but padding both sides (i.e. the text is centered)
167175

168176
NOTE: Some placeholders may depend on other options given to the
169177
revision traversal engine. For example, the `%g*` reflog options will

pretty.c

Lines changed: 116 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -769,16 +769,25 @@ struct chunk {
769769
size_t len;
770770
};
771771

772+
enum flush_type {
773+
no_flush,
774+
flush_right,
775+
flush_left,
776+
flush_both
777+
};
778+
772779
struct format_commit_context {
773780
const struct commit *commit;
774781
const struct pretty_print_context *pretty_ctx;
775782
unsigned commit_header_parsed:1;
776783
unsigned commit_message_parsed:1;
777784
struct signature_check signature_check;
785+
enum flush_type flush_type;
778786
char *message;
779787
char *commit_encoding;
780788
size_t width, indent1, indent2;
781789
int auto_color;
790+
int padding;
782791

783792
/* These offsets are relative to the start of the commit message. */
784793
struct chunk author;
@@ -993,6 +1002,52 @@ static size_t parse_color(struct strbuf *sb, /* in UTF-8 */
9931002
return 0;
9941003
}
9951004

1005+
static size_t parse_padding_placeholder(struct strbuf *sb,
1006+
const char *placeholder,
1007+
struct format_commit_context *c)
1008+
{
1009+
const char *ch = placeholder;
1010+
enum flush_type flush_type;
1011+
int to_column = 0;
1012+
1013+
switch (*ch++) {
1014+
case '<':
1015+
flush_type = flush_right;
1016+
break;
1017+
case '>':
1018+
if (*ch == '<') {
1019+
flush_type = flush_both;
1020+
ch++;
1021+
} else
1022+
flush_type = flush_left;
1023+
break;
1024+
default:
1025+
return 0;
1026+
}
1027+
1028+
/* the next value means "wide enough to that column" */
1029+
if (*ch == '|') {
1030+
to_column = 1;
1031+
ch++;
1032+
}
1033+
1034+
if (*ch == '(') {
1035+
const char *start = ch + 1;
1036+
const char *end = strchr(start, ')');
1037+
char *next;
1038+
int width;
1039+
if (!end || end == start)
1040+
return 0;
1041+
width = strtoul(start, &next, 10);
1042+
if (next == start || width == 0)
1043+
return 0;
1044+
c->padding = to_column ? -width : width;
1045+
c->flush_type = flush_type;
1046+
return end - placeholder + 1;
1047+
}
1048+
return 0;
1049+
}
1050+
9961051
static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
9971052
const char *placeholder,
9981053
void *context)
@@ -1057,6 +1112,10 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
10571112
return end - placeholder + 1;
10581113
} else
10591114
return 0;
1115+
1116+
case '<':
1117+
case '>':
1118+
return parse_padding_placeholder(sb, placeholder, c);
10601119
}
10611120

10621121
/* these depend on the commit */
@@ -1221,6 +1280,59 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
12211280
return 0; /* unknown placeholder */
12221281
}
12231282

1283+
static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
1284+
const char *placeholder,
1285+
struct format_commit_context *c)
1286+
{
1287+
struct strbuf local_sb = STRBUF_INIT;
1288+
int total_consumed = 0, len, padding = c->padding;
1289+
if (padding < 0) {
1290+
const char *start = strrchr(sb->buf, '\n');
1291+
int occupied;
1292+
if (!start)
1293+
start = sb->buf;
1294+
occupied = utf8_strnwidth(start, -1, 1);
1295+
padding = (-padding) - occupied;
1296+
}
1297+
while (1) {
1298+
int modifier = *placeholder == 'C';
1299+
int consumed = format_commit_one(&local_sb, placeholder, c);
1300+
total_consumed += consumed;
1301+
1302+
if (!modifier)
1303+
break;
1304+
1305+
placeholder += consumed;
1306+
if (*placeholder != '%')
1307+
break;
1308+
placeholder++;
1309+
total_consumed++;
1310+
}
1311+
len = utf8_strnwidth(local_sb.buf, -1, 1);
1312+
if (len > padding)
1313+
strbuf_addstr(sb, local_sb.buf);
1314+
else {
1315+
int sb_len = sb->len, offset = 0;
1316+
if (c->flush_type == flush_left)
1317+
offset = padding - len;
1318+
else if (c->flush_type == flush_both)
1319+
offset = (padding - len) / 2;
1320+
/*
1321+
* we calculate padding in columns, now
1322+
* convert it back to chars
1323+
*/
1324+
padding = padding - len + local_sb.len;
1325+
strbuf_grow(sb, padding);
1326+
strbuf_setlen(sb, sb_len + padding);
1327+
memset(sb->buf + sb_len, ' ', sb->len - sb_len);
1328+
memcpy(sb->buf + sb_len + offset, local_sb.buf,
1329+
local_sb.len);
1330+
}
1331+
strbuf_release(&local_sb);
1332+
c->flush_type = no_flush;
1333+
return total_consumed;
1334+
}
1335+
12241336
static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
12251337
const char *placeholder,
12261338
void *context)
@@ -1251,7 +1363,10 @@ static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
12511363
placeholder++;
12521364

12531365
orig_len = sb->len;
1254-
consumed = format_commit_one(sb, placeholder, context);
1366+
if (((struct format_commit_context *)context)->flush_type != no_flush)
1367+
consumed = format_and_pad_commit(sb, placeholder, context);
1368+
else
1369+
consumed = format_commit_one(sb, placeholder, context);
12551370
if (magic == NO_MAGIC)
12561371
return consumed;
12571372

t/t4205-log-pretty-formats.sh

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,4 +99,126 @@ test_expect_failure 'NUL termination with --stat' '
9999
test_i18ncmp expected actual
100100
'
101101

102+
test_expect_success 'setup more commits' '
103+
test_commit "message one" one one message-one &&
104+
test_commit "message two" two two message-two
105+
'
106+
107+
test_expect_success 'left alignment formatting' '
108+
git log --pretty="format:%<(40)%s" >actual &&
109+
# complete the incomplete line at the end
110+
echo >>actual &&
111+
qz_to_tab_space <<\EOF >expected &&
112+
message two Z
113+
message one Z
114+
add bar Z
115+
initial Z
116+
EOF
117+
test_cmp expected actual
118+
'
119+
120+
test_expect_success 'left alignment formatting at the nth column' '
121+
git log --pretty="format:%h %<|(40)%s" >actual &&
122+
# complete the incomplete line at the end
123+
echo >>actual &&
124+
qz_to_tab_space <<\EOF >expected &&
125+
fa33ab1 message two Z
126+
7cd6c63 message one Z
127+
1711bf9 add bar Z
128+
af20c06 initial Z
129+
EOF
130+
test_cmp expected actual
131+
'
132+
133+
test_expect_success 'left alignment formatting with no padding' '
134+
git log --pretty="format:%<(1)%s" >actual &&
135+
# complete the incomplete line at the end
136+
echo >>actual &&
137+
cat <<\EOF >expected &&
138+
message two
139+
message one
140+
add bar
141+
initial
142+
EOF
143+
test_cmp expected actual
144+
'
145+
146+
test_expect_success 'right alignment formatting' '
147+
git log --pretty="format:%>(40)%s" >actual &&
148+
# complete the incomplete line at the end
149+
echo >>actual &&
150+
qz_to_tab_space <<\EOF >expected &&
151+
Z message two
152+
Z message one
153+
Z add bar
154+
Z initial
155+
EOF
156+
test_cmp expected actual
157+
'
158+
159+
test_expect_success 'right alignment formatting at the nth column' '
160+
git log --pretty="format:%h %>|(40)%s" >actual &&
161+
# complete the incomplete line at the end
162+
echo >>actual &&
163+
qz_to_tab_space <<\EOF >expected &&
164+
fa33ab1 message two
165+
7cd6c63 message one
166+
1711bf9 add bar
167+
af20c06 initial
168+
EOF
169+
test_cmp expected actual
170+
'
171+
172+
test_expect_success 'right alignment formatting with no padding' '
173+
git log --pretty="format:%>(1)%s" >actual &&
174+
# complete the incomplete line at the end
175+
echo >>actual &&
176+
cat <<\EOF >expected &&
177+
message two
178+
message one
179+
add bar
180+
initial
181+
EOF
182+
test_cmp expected actual
183+
'
184+
185+
test_expect_success 'center alignment formatting' '
186+
git log --pretty="format:%><(40)%s" >actual &&
187+
# complete the incomplete line at the end
188+
echo >>actual &&
189+
qz_to_tab_space <<\EOF >expected &&
190+
Z message two Z
191+
Z message one Z
192+
Z add bar Z
193+
Z initial Z
194+
EOF
195+
test_cmp expected actual
196+
'
197+
198+
test_expect_success 'center alignment formatting at the nth column' '
199+
git log --pretty="format:%h %><|(40)%s" >actual &&
200+
# complete the incomplete line at the end
201+
echo >>actual &&
202+
qz_to_tab_space <<\EOF >expected &&
203+
fa33ab1 message two Z
204+
7cd6c63 message one Z
205+
1711bf9 add bar Z
206+
af20c06 initial Z
207+
EOF
208+
test_cmp expected actual
209+
'
210+
211+
test_expect_success 'center alignment formatting with no padding' '
212+
git log --pretty="format:%><(1)%s" >actual &&
213+
# complete the incomplete line at the end
214+
echo >>actual &&
215+
cat <<\EOF >expected &&
216+
message two
217+
message one
218+
add bar
219+
initial
220+
EOF
221+
test_cmp expected actual
222+
'
223+
102224
test_done

0 commit comments

Comments
 (0)