]> git.ipfire.org Git - thirdparty/git.git/blobdiff - ref-filter.c
ref-filter: implement an `align` atom
[thirdparty/git.git] / ref-filter.c
index 514de3404664d041ac1222324a01fe2be9cf7a1a..c65cd60fe52d10c1b3d0c65ffafbbf04c171b272 100644 (file)
@@ -10,6 +10,7 @@
 #include "quote.h"
 #include "ref-filter.h"
 #include "revision.h"
+#include "utf8.h"
 
 typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type;
 
@@ -53,13 +54,22 @@ static struct {
        { "flag" },
        { "HEAD" },
        { "color" },
+       { "align" },
+       { "end" },
 };
 
 #define REF_FORMATTING_STATE_INIT  { 0, NULL }
 
+struct align {
+       align_type position;
+       unsigned int width;
+};
+
 struct ref_formatting_stack {
        struct ref_formatting_stack *prev;
        struct strbuf output;
+       void (*at_end)(struct ref_formatting_stack *stack);
+       void *at_end_data;
 };
 
 struct ref_formatting_state {
@@ -69,6 +79,9 @@ struct ref_formatting_state {
 
 struct atom_value {
        const char *s;
+       union {
+               struct align align;
+       } u;
        void (*handler)(struct atom_value *atomv, struct ref_formatting_state *state);
        unsigned long ul; /* used for sorting when not FIELD_STR */
 };
@@ -165,7 +178,16 @@ static void quote_formatting(struct strbuf *s, const char *str, int quote_style)
 
 static void append_atom(struct atom_value *v, struct ref_formatting_state *state)
 {
-       quote_formatting(&state->stack->output, v->s, state->quote_style);
+       /*
+        * Quote formatting is only done when the stack has a single
+        * element. Otherwise quote formatting is done on the
+        * element's entire output strbuf when the %(end) atom is
+        * encountered.
+        */
+       if (!state->stack->prev)
+               quote_formatting(&state->stack->output, v->s, state->quote_style);
+       else
+               strbuf_addstr(&state->stack->output, v->s);
 }
 
 static void push_stack_element(struct ref_formatting_stack **stack)
@@ -189,6 +211,48 @@ static void pop_stack_element(struct ref_formatting_stack **stack)
        *stack = prev;
 }
 
+static void end_align_handler(struct ref_formatting_stack *stack)
+{
+       struct align *align = (struct align *)stack->at_end_data;
+       struct strbuf s = STRBUF_INIT;
+
+       strbuf_utf8_align(&s, align->position, align->width, stack->output.buf);
+       strbuf_swap(&stack->output, &s);
+       strbuf_release(&s);
+}
+
+static void align_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state)
+{
+       struct ref_formatting_stack *new;
+
+       push_stack_element(&state->stack);
+       new = state->stack;
+       new->at_end = end_align_handler;
+       new->at_end_data = &atomv->u.align;
+}
+
+static void end_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state)
+{
+       struct ref_formatting_stack *current = state->stack;
+       struct strbuf s = STRBUF_INIT;
+
+       if (!current->at_end)
+               die(_("format: %%(end) atom used without corresponding atom"));
+       current->at_end(current);
+
+       /*
+        * Perform quote formatting when the stack element is that of
+        * a supporting atom. If nested then perform quote formatting
+        * only on the topmost supporting atom.
+        */
+       if (!state->stack->prev->prev) {
+               quote_formatting(&s, current->output.buf, state->quote_style);
+               strbuf_swap(&current->output, &s);
+       }
+       strbuf_release(&s);
+       pop_stack_element(&state->stack);
+}
+
 static int match_atom_name(const char *name, const char *atom_name, const char **val)
 {
        const char *body;
@@ -773,6 +837,48 @@ static void populate_value(struct ref_array_item *ref)
                        else
                                v->s = " ";
                        continue;
+               } else if (match_atom_name(name, "align", &valp)) {
+                       struct align *align = &v->u.align;
+                       struct strbuf **s, **to_free;
+                       int width = -1;
+
+                       if (!valp)
+                               die(_("expected format: %%(align:<width>,<position>)"));
+
+                       /*
+                        * TODO: Implement a function similar to strbuf_split_str()
+                        * which would omit the separator from the end of each value.
+                        */
+                       s = to_free = strbuf_split_str(valp, ',', 0);
+
+                       align->position = ALIGN_LEFT;
+
+                       while (*s) {
+                               /*  Strip trailing comma */
+                               if (s[1])
+                                       strbuf_setlen(s[0], s[0]->len - 1);
+                               if (!strtoul_ui(s[0]->buf, 10, (unsigned int *)&width))
+                                       ;
+                               else if (!strcmp(s[0]->buf, "left"))
+                                       align->position = ALIGN_LEFT;
+                               else if (!strcmp(s[0]->buf, "right"))
+                                       align->position = ALIGN_RIGHT;
+                               else if (!strcmp(s[0]->buf, "middle"))
+                                       align->position = ALIGN_MIDDLE;
+                               else
+                                       die(_("improper format entered align:%s"), s[0]->buf);
+                               s++;
+                       }
+
+                       if (width < 0)
+                               die(_("positive width expected with the %%(align) atom"));
+                       align->width = width;
+                       strbuf_list_free(to_free);
+                       v->handler = align_atom_handler;
+                       continue;
+               } else if (!strcmp(name, "end")) {
+                       v->handler = end_atom_handler;
+                       continue;
                } else
                        continue;
 
@@ -1347,6 +1453,8 @@ void show_ref_array_item(struct ref_array_item *info, const char *format, int qu
                resetv.s = color;
                append_atom(&resetv, &state);
        }
+       if (state.stack->prev)
+               die(_("format: %%(end) atom missing"));
        final_buf = &state.stack->output;
        fwrite(final_buf->buf, 1, final_buf->len, stdout);
        pop_stack_element(&state.stack);