COL_MODE_COLUMN and COL_MODE_ROW fill column by column (or row by row respectively), given the terminal width and how many space between columns. Strings are supposed in UTF-8. If strings contain ANSI escape strings, COL_ANSI must be specified. Signed-off-by: Nguyán ThÃi Ngác Duy <pclouds@xxxxxxxxx> --- column.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ column.h | 3 ++ 2 files changed, 110 insertions(+), 0 deletions(-) diff --git a/column.c b/column.c index c7d9a84..d6e2d70 100644 --- a/column.c +++ b/column.c @@ -1,8 +1,58 @@ #include "cache.h" #include "column.h" +#include "parse-options.h" #include "string-list.h" +#include "utf8.h" #define MODE(mode) ((mode) & COL_MODE) +#define XY2SCALAR(mode,x,y,cols,rows) (MODE(mode) == COL_MODE_COLUMN ? (x) * (rows) + (y) : (y) * (cols) + (x)) + +/* return length of 's' in letters, ANSI escapes stripped */ +static int item_length(const struct string_list *list, int mode, const char *s) +{ + int len, i = 0; + struct strbuf str = STRBUF_INIT; + + if (!(mode & COL_ANSI)) + return utf8_strwidth(s); + + strbuf_addstr(&str, s); + while ((s = strstr(str.buf + i, "\033[")) != NULL) { + int len = strspn(s + 2, "0123456789;"); + i = s - str.buf; + strbuf_remove(&str, i, len + 3); /* \033[<len><func char> */ + } + len = utf8_strwidth(str.buf); + strbuf_release(&str); + return len; +} + +/* + * Calculate cell width, rows and cols for a table of equal cells, given + * table width and how many spaces between cells. + */ +static void layout(const struct string_list *list, + int mode, int total_width, int padding, + int *width, int *rows, int *cols) +{ + int i; + + *width = 0; + /* Find maximum column width */ + for (i = 0; i < list->nr; i++) { + const char *s = list->items[i].string; + int len = item_length(list, mode, s); + if (*width < len) + *width = len; + } + *width += padding; + + *cols = total_width / *width; + if (*cols == 0) + *cols = 1; + + *rows = DIV_ROUND_UP(list->nr, *cols); +} /* Display without layout, COL_MODE_PLAIN */ static void display_plain(const struct string_list *list, const char *indent) @@ -13,6 +63,58 @@ static void display_plain(const struct string_list *list, const char *indent) printf("%s%s\n", indent, list->items[i].string); } +static int display_cell(const struct string_list *list, int mode, + int *width, int initial_width, + const char *indent, const char *empty_cell, + int x, int y, int cols, int rows) +{ + const char *s; + int i, len, newline; + + i = XY2SCALAR(mode, x, y, cols, rows); + if (i >= list->nr) + return -1; + s = list->items[i].string; + len = item_length(list, mode, s); + if (width[x] < initial_width) + len += initial_width - width[x]; + if (MODE(mode) == COL_MODE_COLUMN) + newline = i + rows >= list->nr; + else + newline = x == cols - 1 || i == list->nr - 1; + + printf("%s%s%s", + x == 0 ? indent : "", + list->items[i].string, + newline ? "\n" : empty_cell + len); + return 0; +} + +/* Display COL_MODE_COLUMN or COL_MODE_ROW */ +static void display_table(const struct string_list *list, + int mode, int total_width, + int padding, const char *indent) +{ + int x, y, i, cols, rows, initial_width, *width; + char *empty_cell; + + layout(list, mode, total_width, padding, &initial_width, &rows, &cols); + width = xmalloc(sizeof(*width) * cols); + for (i = 0; i < cols; i++) + width[i] = initial_width; + + empty_cell = xmalloc(initial_width + 1); + memset(empty_cell, ' ', initial_width); + empty_cell[initial_width] = '\0'; + for (y = 0; y < rows; y++) { + for (x = 0; x < cols; x++) + if (display_cell(list, mode, width, + initial_width, indent, empty_cell, + x, y, cols, rows)) + break; + } +} + void display_columns(const struct string_list *list, int mode, int width, int padding, const char *indent) { int real_mode = MODE(mode); @@ -25,6 +127,11 @@ void display_columns(const struct string_list *list, int mode, int width, int pa display_plain(list, indent); break; + case COL_MODE_ROW: + case COL_MODE_COLUMN: + display_table(list, mode, width, padding, indent); + break; + default: die("BUG: invalid mode %d", MODE(mode)); } diff --git a/column.h b/column.h index da0bf9a..3ed5731 100644 --- a/column.h +++ b/column.h @@ -3,6 +3,9 @@ #define COL_MODE 0x000F #define COL_MODE_PLAIN 0 /* Single column */ +#define COL_MODE_COLUMN 1 /* Fill columns before rows */ +#define COL_MODE_ROW 2 /* Fill rows before columns */ +#define COL_ANSI (1 << 4) /* Remove ANSI escapes from string length */ extern int term_columns(void); extern void display_columns(const struct string_list *list, int mode, int width, int padding, const char *indent); -- 1.7.2.2 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html