Subject: [PATCH 05/12] Add builtin command "column"

From: Nguyễn Thái Ngọc Duy <[email-masked]>
Date: Sun, 7 Mar 2010 19:09:38 +0700

Signed-off-by: Nguyễn Thái Ngọc Duy <[email-masked]>
---
 Documentation/git-column.txt |   40 ++++++++++++++++
 Makefile                     |    1 +
 builtin.h                    |    1 +
 builtin/column.c             |   42 +++++++++++++++++
 git.c                        |    1 +
 t/t9002-column.sh            |  101 ++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 186 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/git-column.txt
 create mode 100644 builtin/column.c
 create mode 100755 t/t9002-column.sh

diff --git a/Documentation/git-column.txt b/Documentation/git-column.txt
new file mode 100644
index 0000000..3ee887f
--- /dev/null
+++ b/Documentation/git-column.txt
@@ -0,0 +1,40 @@
+git-column(1)
+=============
+
+NAME
+----
+git-column - Columnate lists
+
+SYNOPSIS
+--------
+[verse]
+'git column' [--mode=<mode>] [--width=<width>] [--left-space=<N>] [--right-space=<N>]
+
+DESCRIPTION
+-----------
+This command formats its input into multiple columns. Rows are filled before
+columns.
+
+OPTIONS
+-------
+--width=<width>::
+	Specify the terminal width. By default 'git column' will detect the
+	terminal width, or fall back to 80 if it is unable to do so.
+
+--left-space=<N>::
+	Prepend a number of spaces on the first column.
+
+--right-space=<N>::
+	Append a number of spaces after the last column.
+
+--mode=<mode>::
+	Which layout mode to use. Supported modes are 'row' (default mode,
+	fill rows first) and 'column' (fill columns first)
+
+Author
+------
+Written by Nguyen Thai Ngoc Duy <[email-masked]>
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Makefile b/Makefile
index 337f5bf..53686a2 100644
--- a/Makefile
+++ b/Makefile
@@ -640,6 +640,7 @@ BUILTIN_OBJS += builtin/checkout-index.o
 BUILTIN_OBJS += builtin/checkout.o
 BUILTIN_OBJS += builtin/clean.o
 BUILTIN_OBJS += builtin/clone.o
+BUILTIN_OBJS += builtin/column.o
 BUILTIN_OBJS += builtin/commit-tree.o
 BUILTIN_OBJS += builtin/commit.o
 BUILTIN_OBJS += builtin/config.o
diff --git a/builtin.h b/builtin.h
index cdf9847..c68c758 100644
--- a/builtin.h
+++ b/builtin.h
@@ -39,6 +39,7 @@ extern int cmd_cherry(int argc, const char **argv, const char *prefix);
 extern int cmd_cherry_pick(int argc, const char **argv, const char *prefix);
 extern int cmd_clone(int argc, const char **argv, const char *prefix);
 extern int cmd_clean(int argc, const char **argv, const char *prefix);
+extern int cmd_column(int argc, const char **argv, const char *prefix);
 extern int cmd_commit(int argc, const char **argv, const char *prefix);
 extern int cmd_commit_tree(int argc, const char **argv, const char *prefix);
 extern int cmd_count_objects(int argc, const char **argv, const char *prefix);
diff --git a/builtin/column.c b/builtin/column.c
new file mode 100644
index 0000000..d5d7f80
--- /dev/null
+++ b/builtin/column.c
@@ -0,0 +1,42 @@
+#include "cache.h"
+#include "strbuf.h"
+#include "parse-options.h"
+#include "column.h"
+
+static const char * const builtin_column_usage[] = {
+	"git column [--mode=<mode>] [--width=<width>] [--left-space=<N>] [--right-space=<N>]",
+	NULL
+};
+
+int cmd_column(int argc, const char **argv, const char *prefix)
+{
+	struct columnizer cp;
+	const char *mode = NULL;
+	struct strbuf sb = STRBUF_INIT;
+	struct option options[] = {
+		OPT_INTEGER(0, "width", &cp.terminal_width, "Maximum width"),
+		OPT_INTEGER(0, "left-space", &cp.left_space, "Padding space on left border"),
+		OPT_INTEGER(0, "right-space", &cp.right_space, "Padding space on right border"),
+		OPT_STRING(0, "mode", &mode, "mode", "Which layout mode to use"),
+		OPT_END()
+	};
+
+	memset(&cp, 0, sizeof(cp));
+	cp.space = 1;
+	cp.detach = free;
+
+	argc = parse_options(argc, argv, prefix, options, builtin_column_usage, 0);
+
+	if (!mode || !strcmp(mode, "column"))
+		cp.flags = COLUMNIZER_COLUMN_FIRST | COLUMNIZER_HAVE_ANSI | COLUMNIZER_HOMOGENEOUS;
+	else if (!strcmp(mode, "row"))
+		cp.flags = COLUMNIZER_ROW_FIRST | COLUMNIZER_HAVE_ANSI | COLUMNIZER_HOMOGENEOUS;
+	else
+		die("Invalid mode '%s'", mode);
+
+	while (!strbuf_getline(&sb, stdin, '\n'))
+		feed_columnizer(&cp, strbuf_detach(&sb, NULL));
+
+	feed_columnizer(&cp, NULL);
+	return 0;
+}
diff --git a/git.c b/git.c
index 6bae305..8dc6fdd 100644
--- a/git.c
+++ b/git.c
@@ -301,6 +301,7 @@ static void handle_internal_command(int argc, const char **argv)
 		{ "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE },
 		{ "clone", cmd_clone },
 		{ "clean", cmd_clean, RUN_SETUP | NEED_WORK_TREE },
+		{ "column", cmd_column },
 		{ "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE },
 		{ "commit-tree", cmd_commit_tree, RUN_SETUP },
 		{ "config", cmd_config },
diff --git a/t/t9002-column.sh b/t/t9002-column.sh
new file mode 100755
index 0000000..b5b46fc
--- /dev/null
+++ b/t/t9002-column.sh
@@ -0,0 +1,101 @@
+#!/bin/sh
+
+test_description='git column'
+. ./test-lib.sh
+
+cat >lista <<\EOF
+one
+two
+three
+four
+five
+six
+seven
+eight
+nine
+ten
+EOF
+
+cat >expected <<\EOF
+one   two   three four  five  six   seven eight nine  ten   
+EOF
+test_expect_success '80 columns' '
+	COLUMNS=80 git column < lista > actual &&
+	test_cmp expected actual
+'
+
+cat >expected <<\EOF
+one
+two
+three
+four
+five
+six
+seven
+eight
+nine
+ten
+EOF
+test_expect_success '1 column' '
+	COLUMNS=1 git column < lista > actual &&
+	test_cmp expected actual
+'
+
+test_expect_success '1 column (--width)' '
+	git column --width=1 < lista > actual &&
+	test_cmp expected actual
+'
+
+COLUMNS=20
+export COLUMNS
+
+cat >expected <<\EOF
+one   five  nine
+two   six   ten
+three seven 
+four  eight 
+EOF
+test_expect_success '20 columns' '
+	git column < lista > actual &&
+	test_cmp expected actual
+'
+
+cat >expected <<\EOF
+one   two   three
+four  five  six
+seven eight nine
+ten   
+EOF
+test_expect_success '20 columns, row mode' '
+	git column --mode=row < lista > actual &&
+	test_cmp expected actual
+'
+
+test_expect_success 'unsupported mode' '
+	test_must_fail git column --mode=foo
+'
+
+cat >expected <<\EOF
+  one   five  nine
+  two   six   ten
+  three seven 
+  four  eight 
+EOF
+test_expect_success '20 columns, left indented' '
+	git column --left-space=2 < lista > actual &&
+	test_cmp expected actual
+'
+
+cat >expected <<\EOF
+one     six
+two     seven
+three   eight
+four    nine
+five    ten
+EOF
+test_expect_success '20 columns, right indented' '
+	git column --right-space=3 < lista > actual &&
+	test_cmp expected actual
+'
+
+test_done
-- 
1.7.0.1.370.gd3c5