column.con commit Stop starting pager recursively (88e8f90)
   1#include "cache.h"
   2#include "column.h"
   3#include "string-list.h"
   4#include "parse-options.h"
   5
   6/* Display without layout when not enabled */
   7static void display_plain(const struct string_list *list,
   8                          const char *indent, const char *nl)
   9{
  10        int i;
  11
  12        for (i = 0; i < list->nr; i++)
  13                printf("%s%s%s", indent, list->items[i].string, nl);
  14}
  15
  16void print_columns(const struct string_list *list, unsigned int colopts,
  17                   const struct column_options *opts)
  18{
  19        struct column_options nopts;
  20
  21        if (!list->nr)
  22                return;
  23        assert((colopts & COL_ENABLE_MASK) != COL_AUTO);
  24
  25        memset(&nopts, 0, sizeof(nopts));
  26        nopts.indent = opts && opts->indent ? opts->indent : "";
  27        nopts.nl = opts && opts->nl ? opts->nl : "\n";
  28        nopts.padding = opts ? opts->padding : 1;
  29        nopts.width = opts && opts->width ? opts->width : term_columns() - 1;
  30        if (!column_active(colopts)) {
  31                display_plain(list, "", "\n");
  32                return;
  33        }
  34        switch (COL_LAYOUT(colopts)) {
  35        case COL_PLAIN:
  36                display_plain(list, nopts.indent, nopts.nl);
  37                break;
  38        default:
  39                die("BUG: invalid layout mode %d", COL_LAYOUT(colopts));
  40        }
  41}
  42
  43int finalize_colopts(unsigned int *colopts, int stdout_is_tty)
  44{
  45        if ((*colopts & COL_ENABLE_MASK) == COL_AUTO) {
  46                if (stdout_is_tty < 0)
  47                        stdout_is_tty = isatty(1);
  48                *colopts &= ~COL_ENABLE_MASK;
  49                if (stdout_is_tty)
  50                        *colopts |= COL_ENABLED;
  51        }
  52        return 0;
  53}
  54
  55struct colopt {
  56        const char *name;
  57        unsigned int value;
  58        unsigned int mask;
  59};
  60
  61#define LAYOUT_SET 1
  62#define ENABLE_SET 2
  63
  64static int parse_option(const char *arg, int len, unsigned int *colopts,
  65                        int *group_set)
  66{
  67        struct colopt opts[] = {
  68                { "always", COL_ENABLED,  COL_ENABLE_MASK },
  69                { "never",  COL_DISABLED, COL_ENABLE_MASK },
  70                { "auto",   COL_AUTO,     COL_ENABLE_MASK },
  71                { "plain",  COL_PLAIN,    COL_LAYOUT_MASK },
  72        };
  73        int i;
  74
  75        for (i = 0; i < ARRAY_SIZE(opts); i++) {
  76                int arg_len = len, name_len;
  77                const char *arg_str = arg;
  78
  79                name_len = strlen(opts[i].name);
  80                if (arg_len != name_len ||
  81                    strncmp(arg_str, opts[i].name, name_len))
  82                        continue;
  83
  84                switch (opts[i].mask) {
  85                case COL_ENABLE_MASK:
  86                        *group_set |= ENABLE_SET;
  87                        break;
  88                case COL_LAYOUT_MASK:
  89                        *group_set |= LAYOUT_SET;
  90                        break;
  91                }
  92
  93                if (opts[i].mask)
  94                        *colopts = (*colopts & ~opts[i].mask) | opts[i].value;
  95                return 0;
  96        }
  97
  98        return error("unsupported option '%s'", arg);
  99}
 100
 101static int parse_config(unsigned int *colopts, const char *value)
 102{
 103        const char *sep = " ,";
 104        int group_set = 0;
 105
 106        while (*value) {
 107                int len = strcspn(value, sep);
 108                if (len) {
 109                        if (parse_option(value, len, colopts, &group_set))
 110                                return -1;
 111
 112                        value += len;
 113                }
 114                value += strspn(value, sep);
 115        }
 116        /*
 117         * Setting layout implies "always" if neither always, never
 118         * nor auto is specified.
 119         *
 120         * Current value in COL_ENABLE_MASK is disregarded. This means if
 121         * you set column.ui = auto and pass --column=row, then "auto"
 122         * will become "always".
 123         */
 124        if ((group_set & LAYOUT_SET) && !(group_set & ENABLE_SET))
 125                *colopts = (*colopts & ~COL_ENABLE_MASK) | COL_ENABLED;
 126        return 0;
 127}
 128
 129static int column_config(const char *var, const char *value,
 130                         const char *key, unsigned int *colopts)
 131{
 132        if (!value)
 133                return config_error_nonbool(var);
 134        if (parse_config(colopts, value))
 135                return error("invalid column.%s mode %s", key, value);
 136        return 0;
 137}
 138
 139int git_column_config(const char *var, const char *value,
 140                      const char *command, unsigned int *colopts)
 141{
 142        const char *it = skip_prefix(var, "column.");
 143        if (!it)
 144                return 0;
 145
 146        if (!strcmp(it, "ui"))
 147                return column_config(var, value, "ui", colopts);
 148
 149        if (command && !strcmp(it, command))
 150                return column_config(var, value, it, colopts);
 151
 152        return 0;
 153}
 154
 155int parseopt_column_callback(const struct option *opt,
 156                             const char *arg, int unset)
 157{
 158        unsigned int *colopts = opt->value;
 159        *colopts |= COL_PARSEOPT;
 160        *colopts &= ~COL_ENABLE_MASK;
 161        if (unset)              /* --no-column == never */
 162                return 0;
 163        /* --column == always unless "arg" states otherwise */
 164        *colopts |= COL_ENABLED;
 165        if (arg)
 166                return parse_config(colopts, arg);
 167
 168        return 0;
 169}