Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@xxxxxxxxx> --- .gitignore | 1 + Makefile | 2 + column.c | 164 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ column.h | 23 ++++++++ command-list.txt | 1 + 5 files changed, 191 insertions(+), 0 deletions(-) create mode 100644 column.c create mode 100644 column.h diff --git a/.gitignore b/.gitignore index 7b3acb7..8e087e6 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,7 @@ /git-cherry-pick /git-clean /git-clone +/git-column /git-commit /git-commit-tree /git-config diff --git a/Makefile b/Makefile index 7358a20..337f5bf 100644 --- a/Makefile +++ b/Makefile @@ -454,6 +454,7 @@ LIB_H += builtin.h LIB_H += cache.h LIB_H += cache-tree.h LIB_H += color.h +LIB_H += column.h LIB_H += commit.h LIB_H += compat/bswap.h LIB_H += compat/cygwin.h @@ -526,6 +527,7 @@ LIB_OBJS += branch.o LIB_OBJS += bundle.o LIB_OBJS += cache-tree.o LIB_OBJS += color.o +LIB_OBJS += column.o LIB_OBJS += combine-diff.o LIB_OBJS += commit.o LIB_OBJS += config.o diff --git a/column.c b/column.c new file mode 100644 index 0000000..0e88763 --- /dev/null +++ b/column.c @@ -0,0 +1,164 @@ +#include "cache.h" +#include "column.h" + +static int ansi_length(const char *s) +{ + int a_len = 0; + + while ((s = strstr(s, "\033[")) != NULL) { + int len = strspn(s+2, "0123456789;"); + s += len+3; /* \033[<len><func char> */ + a_len += len+3; + } + return a_len; +} + +static void print_row(struct columnizer *cp, int row) +{ + int mode = cp->flags & COLUMNIZER_MODE_MASK; + int j; + + if (cp->left_space) + printf("%-*s", cp->left_space, ""); + + for (j = 0; j < cp->nr_cols; j++) { + int n, size; + + switch (mode) { + case COLUMNIZER_COLUMN_FIRST: + n = j * cp->nr_rows + row; + size = cp->column_width; + break; + case COLUMNIZER_ROW_FIRST: + n = row * cp->nr_cols + j; + size = cp->column_width; + break; + } + + if (n >= cp->cells_nr) + break; + + size += cp->space; + if (cp->flags & COLUMNIZER_HAVE_ANSI) + size += ansi_length(cp->cells[n]); + if (j == cp->nr_cols-1) + size = 1; + printf("%-*s", size, cp->cells[n]); + } + putchar('\n'); +} + +static void calculate_column_width(struct columnizer *cp) +{ + int max_cols, longest; + + if (cp->flags & COLUMNIZER_READY) + return; + + if (!cp->terminal_width) + cp->terminal_width = term_columns(); + + if (cp->column_width) + longest = cp->column_width; + else { + int i, len; + longest = 0; + for (i = 0; i < cp->cells_nr; i++) { + len = strlen(cp->cells[i]); + if (cp->flags & COLUMNIZER_HAVE_ANSI) + len -= ansi_length(cp->cells[i]); + if (longest < len) + longest = len; + } + } + + max_cols = cp->terminal_width - 1; /* don't print *on* the edge */ + max_cols -= cp->left_space + cp->right_space; + + /* we don't have space after the last column */ + max_cols += cp->space; + + cp->nr_cols = (longest + cp->space) < max_cols ? max_cols / (longest + cp->space) : 1; + cp->nr_rows = DIV_ROUND_UP(cp->cells_nr, cp->nr_cols); + if (!cp->column_width) + cp->column_width = max_cols / cp->nr_cols - cp->space; + cp->flags |= COLUMNIZER_READY; +} + +static int feed_cell(struct columnizer *cp, char *cell) +{ + int len; + + /* Non-homogeneous column is not supported yet */ + if (!(cp->flags & COLUMNIZER_HOMOGENEOUS)) + return -1; + + if (!cell) { /* EOF */ + int i; + + calculate_column_width(cp); + for (i = 0;i < cp->nr_rows; i++) + print_row(cp, i); + return 0; + } + + cp->cells_nr++; + ALLOC_GROW(cp->cells, cp->cells_nr, cp->cells_alloc); + cp->cells[cp->cells_nr-1] = cell; + + len = strlen(cell); + if (cp->flags & COLUMNIZER_HAVE_ANSI) + len -= ansi_length(cell); + + if (!cp->terminal_width) + cp->terminal_width = term_columns(); + if (cp->longest < len) + cp->longest = len; + + /* Can't have more than one column? */ + if (cp->terminal_width < cp->left_space+cp->longest*2+cp->space+cp->right_space) { + int i; + for (i = 0;i < cp->cells_nr;i++) { + if (cp->left_space) + printf("%-*s", cp->left_space, ""); + printf("%s\n", cp->cells[i]); + if (cp->detach) + cp->detach(cp->cells[i]); + } + free(cp->cells); + cp->cells_alloc = cp->cells_nr = 0; + + cp->nr_cols = 1; + cp->flags |= COLUMNIZER_READY; + } + return 0; +} + +int feed_columnizer(struct columnizer *cp, char *cell) +{ + int ret; + + /* Degradation case, no special layout needed */ + if (cp->flags & COLUMNIZER_READY && cp->nr_cols == 1) { + if (cell) { + if (cp->left_space) + printf("%-*s", cp->left_space, ""); + printf("%s\n", cell); + } + ret = 0; + } + else + ret = feed_cell(cp, cell); + + if (!cell) { /* EOF, cleanup */ + if (cp->detach) { + int i; + for (i = 0;i < cp->cells_nr;i++) + cp->detach(cp->cells[i]); + } + if (cp->cells_alloc) + free(cp->cells); + } + + return ret; +} diff --git a/column.h b/column.h new file mode 100644 index 0000000..28122e0 --- /dev/null +++ b/column.h @@ -0,0 +1,23 @@ +#define COLUMNIZER_MODE_MASK 0x000F +#define COLUMNIZER_COLUMN_FIRST 0 +#define COLUMNIZER_ROW_FIRST 1 + +#define COLUMNIZER_HOMOGENEOUS 0x0010 +#define COLUMNIZER_HAVE_ANSI 0x0020 +#define COLUMNIZER_READY 0x0040 + +struct columnizer { + int flags; + int terminal_width, column_width; + int left_space, right_space, space; + void (*detach)(void *p); + + /* private variables */ + char **cells; + int cells_nr, cells_alloc; + int nr_cols, nr_rows; + + int longest; +}; + +extern int feed_columnizer(struct columnizer *cp, char *cell); diff --git a/command-list.txt b/command-list.txt index 95bf18c..5d6bfc8 100644 --- a/command-list.txt +++ b/command-list.txt @@ -20,6 +20,7 @@ git-cherry-pick mainporcelain git-citool mainporcelain git-clean mainporcelain git-clone mainporcelain common +git-column purehelpers git-commit mainporcelain common git-commit-tree plumbingmanipulators git-config ancillarymanipulators -- 1.7.0.1.370.gd3c5 -- 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