From: "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
To: git@vger.kernel.org
Cc: "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
Subject: [PATCH 03/12] Add columnizer
Date: Sun, 7 Mar 2010 19:09:36 +0700 [thread overview]
Message-ID: <1267963785-473-4-git-send-email-pclouds@gmail.com> (raw)
In-Reply-To: <1267963785-473-1-git-send-email-pclouds@gmail.com>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
.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
next prev parent reply other threads:[~2010-03-07 12:13 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-03-07 12:09 [PATCH 00/12] Support columinized output in tag/branch/ls-files/grep Nguyễn Thái Ngọc Duy
2010-03-07 12:09 ` [PATCH 01/12] Move term_columns() to pager.c Nguyễn Thái Ngọc Duy
2010-03-07 12:09 ` [PATCH 02/12] setup_pager(): save terminal width before redirecting stdout Nguyễn Thái Ngọc Duy
2010-03-07 12:09 ` Nguyễn Thái Ngọc Duy [this message]
2010-03-07 12:09 ` [PATCH 04/12] help: use columnizer Nguyễn Thái Ngọc Duy
2010-03-07 12:09 ` [PATCH 05/12] Add builtin command "column" Nguyễn Thái Ngọc Duy
2010-03-07 12:09 ` [PATCH 06/12] Add helpers to redirect stdout to "git column" Nguyễn Thái Ngọc Duy
2010-03-07 12:09 ` [PATCH 07/12] add core.columns Nguyễn Thái Ngọc Duy
2010-03-07 12:09 ` [PATCH 08/12] tag: support column output with --columns Nguyễn Thái Ngọc Duy
2010-03-07 12:09 ` [PATCH 09/12] branch: " Nguyễn Thái Ngọc Duy
2010-03-07 12:09 ` [PATCH 10/12] ls-files: " Nguyễn Thái Ngọc Duy
2010-03-07 12:09 ` [PATCH 11/12] grep: do not return early in cmd_grep() if there is no error Nguyễn Thái Ngọc Duy
2010-03-07 12:09 ` [PATCH 12/12] grep: support column output with --columns Nguyễn Thái Ngọc Duy
2010-03-08 14:08 ` [PATCH 00/12] Support columinized output in tag/branch/ls-files/grep René Scharfe
2010-03-08 14:32 ` Nguyen Thai Ngoc Duy
2010-03-09 16:49 ` René Scharfe
2010-03-10 0:27 ` Nguyen Thai Ngoc Duy
2010-03-10 7:26 ` Johannes Sixt
2010-03-10 12:12 ` Nguyen Thai Ngoc Duy
2010-03-11 21:13 ` René Scharfe
2010-03-12 4:22 ` Nguyen Thai Ngoc Duy
2010-03-08 23:08 ` Junio C Hamano
2010-03-09 2:06 ` Nguyen Thai Ngoc Duy
2010-03-09 2:14 ` Junio C Hamano
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1267963785-473-4-git-send-email-pclouds@gmail.com \
--to=pclouds@gmail.com \
--cc=git@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).