summaryrefslogtreecommitdiff
path: root/column.c
diff options
context:
space:
mode:
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>2012-04-13 17:54:36 +0700
committerJunio C Hamano <gitster@pobox.com>2012-04-27 09:26:38 -0700
commit3f8eccbe166ecff79a986b7ce87df4963cc873b2 (patch)
tree05ed415a20f13d1c71b45e5e8ce876b98d6774c1 /column.c
parentf78b1c5f8237d68fffe7c04d22bf93f2ad0bc730 (diff)
downloadgit-3f8eccbe166ecff79a986b7ce87df4963cc873b2.tar.gz
column: add dense layout support
Normally all cells (and in turn columns) share the same width. This layout mode can waste space because one long item can stretch our all columns. With COL_DENSE enabled, column width is calculated indepdendently. All columns are shrunk to minimum, then it attempts to push cells of the last row over to the next column with hope that everything still fits even there's one row less. The process is repeated until the new layout cannot fit in given width any more, or there's only one row left (perfect!). Apparently, this mode consumes more cpu than the old one, but it makes better use of terminal space. For layouting one or two screens, cpu usage should not be detectable. This patch introduces option handling code besides layout modes and enable/disable to expose this feature as "dense". The feature can be turned off by specifying "nodense". Thanks-to: Ramsay Jones <ramsay@ramsay1.demon.co.uk> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'column.c')
-rw-r--r--column.c84
1 files changed, 83 insertions, 1 deletions
diff --git a/column.c b/column.c
index 05fa3e361c..d6c115c1bf 100644
--- a/column.c
+++ b/column.c
@@ -15,6 +15,7 @@ struct column_data {
int rows, cols;
int *len; /* cell length */
+ int *width; /* index to the longest row in column */
};
/* return length of 's' in letters, ANSI escapes stripped */
@@ -56,6 +57,57 @@ static void layout(struct column_data *data, int *width)
data->rows = DIV_ROUND_UP(data->list->nr, data->cols);
}
+static void compute_column_width(struct column_data *data)
+{
+ int i, x, y;
+ for (x = 0; x < data->cols; x++) {
+ data->width[x] = XY2LINEAR(data, x, 0);
+ for (y = 0; y < data->rows; y++) {
+ i = XY2LINEAR(data, x, y);
+ if (i < data->list->nr &&
+ data->len[data->width[x]] < data->len[i])
+ data->width[x] = i;
+ }
+ }
+}
+
+/*
+ * Shrink all columns by shortening them one row each time (and adding
+ * more columns along the way). Hopefully the longest cell will be
+ * moved to the next column, column is shrunk so we have more space
+ * for new columns. The process ends when the whole thing no longer
+ * fits in data->total_width.
+ */
+static void shrink_columns(struct column_data *data)
+{
+ data->width = xrealloc(data->width,
+ sizeof(*data->width) * data->cols);
+ while (data->rows > 1) {
+ int x, total_width, cols, rows;
+ rows = data->rows;
+ cols = data->cols;
+
+ data->rows--;
+ data->cols = DIV_ROUND_UP(data->list->nr, data->rows);
+ if (data->cols != cols)
+ data->width = xrealloc(data->width,
+ sizeof(*data->width) * data->cols);
+ compute_column_width(data);
+
+ total_width = strlen(data->opts.indent);
+ for (x = 0; x < data->cols; x++) {
+ total_width += data->len[data->width[x]];
+ total_width += data->opts.padding;
+ }
+ if (total_width > data->opts.width) {
+ data->rows = rows;
+ data->cols = cols;
+ break;
+ }
+ }
+ compute_column_width(data);
+}
+
/* Display without layout when not enabled */
static void display_plain(const struct string_list *list,
const char *indent, const char *nl)
@@ -75,7 +127,18 @@ static int display_cell(struct column_data *data, int initial_width,
i = XY2LINEAR(data, x, y);
if (i >= data->list->nr)
return -1;
+
len = data->len[i];
+ if (data->width && data->len[data->width[x]] < initial_width) {
+ /*
+ * empty_cell has initial_width chars, if real column
+ * is narrower, increase len a bit so we fill less
+ * space.
+ */
+ len += initial_width - data->len[data->width[x]];
+ len -= data->opts.padding;
+ }
+
if (COL_LAYOUT(data->colopts) == COL_COLUMN)
newline = i + data->rows >= data->list->nr;
else
@@ -108,6 +171,9 @@ static void display_table(const struct string_list *list,
layout(&data, &initial_width);
+ if (colopts & COL_DENSE)
+ shrink_columns(&data);
+
empty_cell = xmalloc(initial_width + 1);
memset(empty_cell, ' ', initial_width);
empty_cell[initial_width] = '\0';
@@ -118,6 +184,7 @@ static void display_table(const struct string_list *list,
}
free(data.len);
+ free(data.width);
free(empty_cell);
}
@@ -183,13 +250,22 @@ static int parse_option(const char *arg, int len, unsigned int *colopts,
{ "plain", COL_PLAIN, COL_LAYOUT_MASK },
{ "column", COL_COLUMN, COL_LAYOUT_MASK },
{ "row", COL_ROW, COL_LAYOUT_MASK },
+ { "dense", COL_DENSE, 0 },
};
int i;
for (i = 0; i < ARRAY_SIZE(opts); i++) {
- int arg_len = len, name_len;
+ int set = 1, arg_len = len, name_len;
const char *arg_str = arg;
+ if (!opts[i].mask) {
+ if (arg_len > 2 && !strncmp(arg_str, "no", 2)) {
+ arg_str += 2;
+ arg_len -= 2;
+ set = 0;
+ }
+ }
+
name_len = strlen(opts[i].name);
if (arg_len != name_len ||
strncmp(arg_str, opts[i].name, name_len))
@@ -206,6 +282,12 @@ static int parse_option(const char *arg, int len, unsigned int *colopts,
if (opts[i].mask)
*colopts = (*colopts & ~opts[i].mask) | opts[i].value;
+ else {
+ if (set)
+ *colopts |= opts[i].value;
+ else
+ *colopts &= ~opts[i].value;
+ }
return 0;
}