git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
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

  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).