10
#include "quote.h"
11
#include "ref-filter.h"
12
#include "revision.h"
13
+#include "utf8.h"
14
15
typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type;
16
54
{ "flag" },
55
{ "HEAD" },
56
{ "color" },
57
+ { "align" },
58
+ { "end" },
59
};
60
61
#define REF_FORMATTING_STATE_INIT { 0, NULL }
62
63
+struct align {
64
+ align_type position;
65
+ unsigned int width;
66
+};
67
+
68
struct ref_formatting_stack {
69
struct ref_formatting_stack *prev;
70
struct strbuf output;
71
+ void (*at_end)(struct ref_formatting_stack *stack);
72
+ void *at_end_data;
73
};
74
75
struct ref_formatting_state {
79
80
struct atom_value {
81
const char *s;
82
+ union {
83
+ struct align align;
84
+ } u;
85
void (*handler)(struct atom_value *atomv, struct ref_formatting_state *state);
86
unsigned long ul; /* used for sorting when not FIELD_STR */
87
};
178
179
static void append_atom(struct atom_value *v, struct ref_formatting_state *state)
180
{
168
- quote_formatting(&state->stack->output, v->s, state->quote_style);
181
+ /*
182
+ * Quote formatting is only done when the stack has a single
183
+ * element. Otherwise quote formatting is done on the
184
+ * element's entire output strbuf when the %(end) atom is
185
+ * encountered.
186
+ */
187
+ if (!state->stack->prev)
188
+ quote_formatting(&state->stack->output, v->s, state->quote_style);
189
+ else
190
+ strbuf_addstr(&state->stack->output, v->s);
191
}
192
193
static void push_stack_element(struct ref_formatting_stack **stack)
211
*stack = prev;
212
}
213
214
+static void end_align_handler(struct ref_formatting_stack *stack)
215
+{
216
+ struct align *align = (struct align *)stack->at_end_data;
217
+ struct strbuf s = STRBUF_INIT;
218
+
219
+ strbuf_utf8_align(&s, align->position, align->width, stack->output.buf);
220
+ strbuf_swap(&stack->output, &s);
221
+ strbuf_release(&s);
222
+}
223
+
224
+static void align_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state)
225
+{
226
+ struct ref_formatting_stack *new;
227
+
228
+ push_stack_element(&state->stack);
229
+ new = state->stack;
230
+ new->at_end = end_align_handler;
231
+ new->at_end_data = &atomv->u.align;
232
+}
233
+
234
+static void end_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state)
235
+{
236
+ struct ref_formatting_stack *current = state->stack;
237
+ struct strbuf s = STRBUF_INIT;
238
+
239
+ if (!current->at_end)
240
+ die(_("format: %%(end) atom used without corresponding atom"));
241
+ current->at_end(current);
242
+
243
+ /*
244
+ * Perform quote formatting when the stack element is that of
245
+ * a supporting atom. If nested then perform quote formatting
246
+ * only on the topmost supporting atom.
247
+ */
248
+ if (!state->stack->prev->prev) {
249
+ quote_formatting(&s, current->output.buf, state->quote_style);
250
+ strbuf_swap(¤t->output, &s);
251
+ }
252
+ strbuf_release(&s);
253
+ pop_stack_element(&state->stack);
254
+}
255
+
256
static int match_atom_name(const char *name, const char *atom_name, const char **val)
257
{
258
const char *body;
837
else
838
v->s = " ";
839
continue;
840
+ } else if (match_atom_name(name, "align", &valp)) {
841
+ struct align *align = &v->u.align;
842
+ struct strbuf **s, **to_free;
843
+ int width = -1;
844
+
845
+ if (!valp)
846
+ die(_("expected format: %%(align:<width>,<position>)"));
847
+
848
+ /*
849
+ * TODO: Implement a function similar to strbuf_split_str()
850
+ * which would omit the separator from the end of each value.
851
+ */
852
+ s = to_free = strbuf_split_str(valp, ',', 0);
853
+
854
+ align->position = ALIGN_LEFT;
855
+
856
+ while (*s) {
857
+ /* Strip trailing comma */
858
+ if (s[1])
859
+ strbuf_setlen(s[0], s[0]->len - 1);
860
+ if (!strtoul_ui(s[0]->buf, 10, (unsigned int *)&width))
861
+ ;
862
+ else if (!strcmp(s[0]->buf, "left"))
863
+ align->position = ALIGN_LEFT;
864
+ else if (!strcmp(s[0]->buf, "right"))
865
+ align->position = ALIGN_RIGHT;
866
+ else if (!strcmp(s[0]->buf, "middle"))
867
+ align->position = ALIGN_MIDDLE;
868
+ else
869
+ die(_("improper format entered align:%s"), s[0]->buf);
870
+ s++;
871
+ }
872
+
873
+ if (width < 0)
874
+ die(_("positive width expected with the %%(align) atom"));
875
+ align->width = width;
876
+ strbuf_list_free(to_free);
877
+ v->handler = align_atom_handler;
878
+ continue;
879
+ } else if (!strcmp(name, "end")) {
880
+ v->handler = end_atom_handler;
881
+ continue;
882
} else
883
continue;
884
1453
resetv.s = color;
1454
append_atom(&resetv, &state);
1455
}
1456
+ if (state.stack->prev)
1457
+ die(_("format: %%(end) atom missing"));
1458
final_buf = &state.stack->output;
1459
fwrite(final_buf->buf, 1, final_buf->len, stdout);
1460
pop_stack_element(&state.stack);