git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH v4 00/13] Column display again
@ 2012-02-03 13:34 Nguyễn Thái Ngọc Duy
  2012-02-03 13:34 ` [PATCH v4 01/13] Save terminal width before setting up pager Nguyễn Thái Ngọc Duy
                   ` (13 more replies)
  0 siblings, 14 replies; 43+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2012-02-03 13:34 UTC (permalink / raw
  To: git; +Cc: Nguyễn Thái Ngọc Duy

Reroll of v3 [1]. This series adds support for column display like
"ls". "git branch", "git tag -l" and "git status"'s untracked files
can now be displayed in columns. There's also "git-column" to help
do the layout for commands that are not aware of column display. In
fact git-tag uses it this way.

I've been thinking of supporting the layout where a cell's content can
occupy more than one cell. It'll make better use of space when there
are a few long entries. Something like this:

abc    def    ghk
longlonglong  short
again  here   now

"git status" may benefit when you have untracked files in some deep
directories.

"ls -R" layout is also an option ("branch -r" and ls-files will
benefit due to dense tree output). But these ideas will have to wait
until later.

Compared to v3, it has "git status" support, the return of git-column,
and column.* conf vars.

[1] http://mid.gmane.org/1300625873-18435-1-git-send-email-pclouds@gmail.com

Nguyễn Thái Ngọc Duy (13):
  Save terminal width before setting up pager
  column: add API to print items in columns
  parseopt: make OPT_INTEGER support hexadecimal as well
  Add git-column and column mode parsing
  Stop starting pager recursively
  column: add columnar layout
  column: support columns with different widths
  column: add column.ui for default column output settings
  help: reuse print_columns() for help -a
  branch: add --column
  status: add --column
  column: support piping stdout to external git-column process
  tag: add --column

 .gitignore                   |    1 +
 Documentation/config.txt     |   38 ++++
 Documentation/git-branch.txt |    9 +
 Documentation/git-column.txt |   53 +++++
 Documentation/git-status.txt |    7 +
 Documentation/git-tag.txt    |   11 +-
 Makefile                     |    3 +
 builtin.h                    |    1 +
 builtin/branch.c             |   26 ++-
 builtin/column.c             |   64 ++++++
 builtin/commit.c             |   13 +-
 builtin/tag.c                |   25 ++-
 column.c                     |  493 ++++++++++++++++++++++++++++++++++++++++++
 column.h                     |   41 ++++
 command-list.txt             |    1 +
 git.c                        |    1 +
 help.c                       |   70 ++-----
 pager.c                      |   37 +++-
 parse-options.c              |    5 +-
 parse-options.h              |    2 +
 t/t9002-column.sh            |  135 ++++++++++++
 wt-status.c                  |   38 +++-
 wt-status.h                  |    2 +-
 23 files changed, 1002 insertions(+), 74 deletions(-)
 create mode 100644 Documentation/git-column.txt
 create mode 100644 builtin/column.c
 create mode 100644 column.c
 create mode 100644 column.h
 create mode 100755 t/t9002-column.sh

-- 
1.7.8.36.g69ee2

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH v4 01/13] Save terminal width before setting up pager
  2012-02-03 13:34 [PATCH v4 00/13] Column display again Nguyễn Thái Ngọc Duy
@ 2012-02-03 13:34 ` Nguyễn Thái Ngọc Duy
  2012-02-03 13:34 ` [PATCH v4 02/13] column: add API to print items in columns Nguyễn Thái Ngọc Duy
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 43+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2012-02-03 13:34 UTC (permalink / raw
  To: git; +Cc: Nguyễn Thái Ngọc Duy

term_columns() checks for terminal width via ioctl(2). After
redirecting, stdin is no longer terminal to get terminal width.

Check terminal width and save it before redirect stdin in
setup_pager() and let term_columns() reuse the value.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Makefile |    1 +
 column.h |    6 ++++++
 help.c   |   23 +----------------------
 pager.c  |   35 +++++++++++++++++++++++++++++++++++
 4 files changed, 43 insertions(+), 22 deletions(-)
 create mode 100644 column.h

diff --git a/Makefile b/Makefile
index c457c34..cbbc699 100644
--- a/Makefile
+++ b/Makefile
@@ -2114,6 +2114,7 @@ builtin/prune.o builtin/reflog.o reachable.o: reachable.h
 builtin/commit.o builtin/revert.o wt-status.o: wt-status.h
 builtin/tar-tree.o archive-tar.o: tar.h
 connect.o transport.o url.o http-backend.o: url.h
+help.o pager.o: column.h
 http-fetch.o http-walker.o remote-curl.o transport.o walker.o: walker.h
 http.o http-walker.o http-push.o http-fetch.o remote-curl.o: http.h url.h
 
diff --git a/column.h b/column.h
new file mode 100644
index 0000000..55d8067
--- /dev/null
+++ b/column.h
@@ -0,0 +1,6 @@
+#ifndef COLUMN_H
+#define COLUMN_H
+
+extern int term_columns(void);
+
+#endif
diff --git a/help.c b/help.c
index cbbe966..672561b 100644
--- a/help.c
+++ b/help.c
@@ -4,28 +4,7 @@
 #include "levenshtein.h"
 #include "help.h"
 #include "common-cmds.h"
-
-/* most GUI terminals set COLUMNS (although some don't export it) */
-static int term_columns(void)
-{
-	char *col_string = getenv("COLUMNS");
-	int n_cols;
-
-	if (col_string && (n_cols = atoi(col_string)) > 0)
-		return n_cols;
-
-#ifdef TIOCGWINSZ
-	{
-		struct winsize ws;
-		if (!ioctl(1, TIOCGWINSZ, &ws)) {
-			if (ws.ws_col)
-				return ws.ws_col;
-		}
-	}
-#endif
-
-	return 80;
-}
+#include "column.h"
 
 void add_cmdname(struct cmdnames *cmds, const char *name, int len)
 {
diff --git a/pager.c b/pager.c
index 975955b..772a5a6 100644
--- a/pager.c
+++ b/pager.c
@@ -6,6 +6,21 @@
 #define DEFAULT_PAGER "less"
 #endif
 
+static int spawned_pager;
+static int max_columns;
+
+static int retrieve_terminal_width(void)
+{
+#ifdef TIOCGWINSZ
+	struct winsize ws;
+	if (ioctl(1, TIOCGWINSZ, &ws))  /* e.g., ENOSYS */
+		return 0;
+	return ws.ws_col;
+#else
+	return 0;
+#endif
+}
+
 /*
  * This is split up from the rest of git so that we can do
  * something different on Windows.
@@ -72,12 +87,17 @@ const char *git_pager(int stdout_is_tty)
 void setup_pager(void)
 {
 	const char *pager = git_pager(isatty(1));
+	int width;
 
 	if (!pager)
 		return;
 
 	setenv("GIT_PAGER_IN_USE", "true", 1);
 
+	width = retrieve_terminal_width();
+	if (width)
+		max_columns = width;
+
 	/* spawn the pager */
 	pager_argv[0] = pager;
 	pager_process.use_shell = 1;
@@ -110,3 +130,18 @@ int pager_in_use(void)
 	env = getenv("GIT_PAGER_IN_USE");
 	return env ? git_config_bool("GIT_PAGER_IN_USE", env) : 0;
 }
+
+int term_columns()
+{
+	char *col_string = getenv("COLUMNS");
+	int n_cols;
+
+	if (col_string && (n_cols = atoi(col_string)) > 0)
+		return n_cols;
+
+	if (spawned_pager && max_columns)
+		return max_columns;
+
+	n_cols = retrieve_terminal_width();
+	return n_cols ? n_cols : 80;
+}
-- 
1.7.8.36.g69ee2

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH v4 02/13] column: add API to print items in columns
  2012-02-03 13:34 [PATCH v4 00/13] Column display again Nguyễn Thái Ngọc Duy
  2012-02-03 13:34 ` [PATCH v4 01/13] Save terminal width before setting up pager Nguyễn Thái Ngọc Duy
@ 2012-02-03 13:34 ` Nguyễn Thái Ngọc Duy
  2012-02-03 22:55   ` Junio C Hamano
  2012-02-03 23:16   ` Junio C Hamano
  2012-02-03 13:34 ` [PATCH v4 03/13] parseopt: make OPT_INTEGER support hexadecimal as well Nguyễn Thái Ngọc Duy
                   ` (11 subsequent siblings)
  13 siblings, 2 replies; 43+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2012-02-03 13:34 UTC (permalink / raw
  To: git; +Cc: Nguyễn Thái Ngọc Duy

Simple code that print line-by-line and wants to columnize can do
this:

print_cell(...);
print_cell(...);
...
print_columns(...);

if column layout is disabled, print_cell() prints directly and
print_columns() becomes no-op. Otherwise print_cell() saves all items
in a string list for print_columns() to process later.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Makefile |    3 ++-
 column.c |   54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 column.h |   17 +++++++++++++++++
 3 files changed, 73 insertions(+), 1 deletions(-)
 create mode 100644 column.c

diff --git a/Makefile b/Makefile
index cbbc699..5f0531b 100644
--- a/Makefile
+++ b/Makefile
@@ -637,6 +637,7 @@ LIB_OBJS += bulk-checkin.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 += compat/obstack.o
@@ -2114,7 +2115,7 @@ builtin/prune.o builtin/reflog.o reachable.o: reachable.h
 builtin/commit.o builtin/revert.o wt-status.o: wt-status.h
 builtin/tar-tree.o archive-tar.o: tar.h
 connect.o transport.o url.o http-backend.o: url.h
-help.o pager.o: column.h
+column.o help.o pager.o: column.h
 http-fetch.o http-walker.o remote-curl.o transport.o walker.o: walker.h
 http.o http-walker.o http-push.o http-fetch.o remote-curl.o: http.h url.h
 
diff --git a/column.c b/column.c
new file mode 100644
index 0000000..4ae98f3
--- /dev/null
+++ b/column.c
@@ -0,0 +1,54 @@
+#include "cache.h"
+#include "column.h"
+#include "string-list.h"
+
+#define MODE(mode) ((mode) & COL_MODE)
+
+struct string_list_item *add_cell_to_list(struct string_list *list,
+					  int mode,
+					  const char *string)
+{
+	if (mode & COL_ENABLED)
+		return string_list_append(list, string);
+	return NULL;
+}
+
+void print_cell(struct string_list *list, int mode, const char *string)
+{
+	if (!add_cell_to_list(list, mode, string))
+		printf("%s\n", string);
+}
+
+/* Display without layout when COL_ENABLED is not set */
+static void display_plain(const struct string_list *list,
+			  const char *indent, const char *nl)
+{
+	int i;
+
+	for (i = 0; i < list->nr; i++)
+		printf("%s%s%s", indent, list->items[i].string, nl);
+}
+
+void print_columns(const struct string_list *list, int mode,
+		   struct column_options *opts)
+{
+	const char *indent = "", *nl = "\n";
+	int padding = 1, width = term_columns();
+
+	if (!list->nr)
+		return;
+	if (opts) {
+		if (opts->indent)
+			indent = opts->indent;
+		if (opts->nl)
+			nl = opts->nl;
+		if (opts->width)
+			width = opts->width;
+		padding = opts->padding;
+	}
+	if (width <= 1 || !(mode & COL_ENABLED)) {
+		display_plain(list, indent, nl);
+		return;
+	}
+	die("BUG: invalid mode %d", MODE(mode));
+}
diff --git a/column.h b/column.h
index 55d8067..e0f8c26 100644
--- a/column.h
+++ b/column.h
@@ -1,6 +1,23 @@
 #ifndef COLUMN_H
 #define COLUMN_H
 
+#define COL_MODE          0x000F
+#define COL_ENABLED      (1 << 4)
+
+struct column_options {
+	int width;
+	int padding;
+	const char *indent;
+	const char *nl;
+};
+
 extern int term_columns(void);
+extern struct string_list_item *add_cell_to_list(struct string_list *list,
+						 int mode,
+						 const char *string);
+/* add cell to list, or print it out if column mode is disabled */
+extern void print_cell(struct string_list *list, int mode, const char *string);
+extern void print_columns(const struct string_list *list,
+			  int mode, struct column_options *opts);
 
 #endif
-- 
1.7.8.36.g69ee2

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH v4 03/13] parseopt: make OPT_INTEGER support hexadecimal as well
  2012-02-03 13:34 [PATCH v4 00/13] Column display again Nguyễn Thái Ngọc Duy
  2012-02-03 13:34 ` [PATCH v4 01/13] Save terminal width before setting up pager Nguyễn Thái Ngọc Duy
  2012-02-03 13:34 ` [PATCH v4 02/13] column: add API to print items in columns Nguyễn Thái Ngọc Duy
@ 2012-02-03 13:34 ` Nguyễn Thái Ngọc Duy
  2012-02-03 22:59   ` Junio C Hamano
  2012-02-03 13:34 ` [PATCH v4 04/13] Add git-column and column mode parsing Nguyễn Thái Ngọc Duy
                   ` (10 subsequent siblings)
  13 siblings, 1 reply; 43+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2012-02-03 13:34 UTC (permalink / raw
  To: git; +Cc: Nguyễn Thái Ngọc Duy


Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 parse-options.c |    5 ++++-
 1 files changed, 4 insertions(+), 1 deletions(-)

diff --git a/parse-options.c b/parse-options.c
index f0098eb..7c9109d 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -139,7 +139,10 @@ static int get_value(struct parse_opt_ctx_t *p,
 		}
 		if (get_arg(p, opt, flags, &arg))
 			return -1;
-		*(int *)opt->value = strtol(arg, (char **)&s, 10);
+		if (!prefixcmp(arg, "0x") || !prefixcmp(arg, "0X"))
+			*(int *)opt->value = strtol(arg + 2, (char **)&s, 16);
+		else
+			*(int *)opt->value = strtol(arg, (char **)&s, 10);
 		if (*s)
 			return opterror(opt, "expects a numerical value", flags);
 		return 0;
-- 
1.7.8.36.g69ee2

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH v4 04/13] Add git-column and column mode parsing
  2012-02-03 13:34 [PATCH v4 00/13] Column display again Nguyễn Thái Ngọc Duy
                   ` (2 preceding siblings ...)
  2012-02-03 13:34 ` [PATCH v4 03/13] parseopt: make OPT_INTEGER support hexadecimal as well Nguyễn Thái Ngọc Duy
@ 2012-02-03 13:34 ` Nguyễn Thái Ngọc Duy
  2012-02-03 13:34 ` [PATCH v4 05/13] Stop starting pager recursively Nguyễn Thái Ngọc Duy
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 43+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2012-02-03 13:34 UTC (permalink / raw
  To: git; +Cc: Nguyễn Thái Ngọc Duy

A column option string consists of many token separated by either
space of commas. A token belongs to one of three groups:

 - enabling: always, never and auto
 - layout mode: to be implemented
 - other tuning, which could be negated be prefix 'no'

A command line option without argument (e.g. --column) will enable
column output and reuse existing settings (layout mode and options..).
--no-column disables columnar output.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 .gitignore                   |    1 +
 Documentation/git-column.txt |   49 ++++++++++++++++
 Makefile                     |    1 +
 builtin.h                    |    1 +
 builtin/column.c             |   41 ++++++++++++++
 column.c                     |  125 ++++++++++++++++++++++++++++++++++++++++++
 column.h                     |    6 ++
 command-list.txt             |    1 +
 git.c                        |    1 +
 parse-options.h              |    2 +
 t/t9002-column.sh            |   27 +++++++++
 11 files changed, 255 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/.gitignore b/.gitignore
index 3b7680e..039e5ef 100644
--- a/.gitignore
+++ b/.gitignore
@@ -26,6 +26,7 @@
 /git-cherry-pick
 /git-clean
 /git-clone
+/git-column
 /git-commit
 /git-commit-tree
 /git-config
diff --git a/Documentation/git-column.txt b/Documentation/git-column.txt
new file mode 100644
index 0000000..508b85f
--- /dev/null
+++ b/Documentation/git-column.txt
@@ -0,0 +1,49 @@
+git-column(1)
+=============
+
+NAME
+----
+git-column - Display data in columns
+
+SYNOPSIS
+--------
+[verse]
+'git column' [--mode=<mode> | --rawmode=<n>] [--width=<width>]
+	     [--indent=<string>] [--nl=<string>] [--pading=<n>]
+
+DESCRIPTION
+-----------
+This command formats its input into multiple columns.
+
+OPTIONS
+-------
+--mode=<mode>::
+	Specify layout mode. See configuration variable column.ui for option
+	syntax.
+
+--rawmode=<n>::
+	Same as --mode but take mode encoded as a number. This is mainly used
+	by other commands that have already parsed layout mode.
+
+--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.
+
+--indent=<string>::
+	String to be printed at the beginning of each line.
+
+--nl=<N>::
+	String to be printed at the end of each line,
+	including newline character.
+
+--padding=<N>::
+	The number of spaces between columns. One space by default.
+
+
+Author
+------
+Written by Nguyen Thai Ngoc Duy <pclouds@gmail.com>
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Makefile b/Makefile
index 5f0531b..92700ca 100644
--- a/Makefile
+++ b/Makefile
@@ -766,6 +766,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 857b9c8..338f540 100644
--- a/builtin.h
+++ b/builtin.h
@@ -61,6 +61,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_config(int argc, const char **argv, const char *prefix);
diff --git a/builtin/column.c b/builtin/column.c
new file mode 100644
index 0000000..c4a0431
--- /dev/null
+++ b/builtin/column.c
@@ -0,0 +1,41 @@
+#include "builtin.h"
+#include "cache.h"
+#include "strbuf.h"
+#include "parse-options.h"
+#include "string-list.h"
+#include "column.h"
+
+static const char * const builtin_column_usage[] = {
+	"git column [options]",
+	NULL
+};
+static int colopts;
+
+int cmd_column(int argc, const char **argv, const char *prefix)
+{
+	struct string_list list = STRING_LIST_INIT_DUP;
+	struct strbuf sb = STRBUF_INIT;
+	struct column_options copts;
+	struct option options[] = {
+		OPT_COLUMN(0, "mode", &colopts, "layout to use"),
+		OPT_INTEGER(0, "rawmode", &colopts, "layout to use"),
+		OPT_INTEGER(0, "width", &copts.width, "Maximum width"),
+		OPT_STRING(0, "indent", &copts.indent, "string", "Padding space on left border"),
+		OPT_INTEGER(0, "nl", &copts.nl, "Padding space on right border"),
+		OPT_INTEGER(0, "padding", &copts.padding, "Padding space between columns"),
+		OPT_END()
+	};
+
+	memset(&copts, 0, sizeof(copts));
+	copts.width = term_columns();
+	copts.padding = 1;
+	argc = parse_options(argc, argv, "", options, builtin_column_usage, 0);
+	if (argc)
+		usage_with_options(builtin_column_usage, options);
+
+	while (!strbuf_getline(&sb, stdin, '\n'))
+		string_list_append(&list, sb.buf);
+
+	print_columns(&list, colopts, &copts);
+	return 0;
+}
diff --git a/column.c b/column.c
index 4ae98f3..bd15bea 100644
--- a/column.c
+++ b/column.c
@@ -1,6 +1,7 @@
 #include "cache.h"
 #include "column.h"
 #include "string-list.h"
+#include "parse-options.h"
 
 #define MODE(mode) ((mode) & COL_MODE)
 
@@ -52,3 +53,127 @@ void print_columns(const struct string_list *list, int mode,
 	}
 	die("BUG: invalid mode %d", MODE(mode));
 }
+
+struct colopt {
+	enum {
+		ENABLE,
+		MODE,
+		OPTION
+	} type;
+	const char *name;
+	int value;
+};
+
+/*
+ * Set COL_ENABLED and COL_ENABLED_SET. If 'set' is -1, check if
+ * stdout is tty.
+ */
+static int set_enable_bit(int *mode, int set, int stdout_is_tty)
+{
+	if (set < 0) {	/* auto */
+		if (stdout_is_tty < 0)
+			stdout_is_tty = isatty(1);
+		set = stdout_is_tty || (pager_in_use() && pager_use_color);
+	}
+	if (set)
+		*mode = *mode | COL_ENABLED | COL_ENABLED_SET;
+	else
+		*mode = (*mode & ~COL_ENABLED) | COL_ENABLED_SET;
+	return 0;
+}
+
+/*
+ * Set COL_MODE_*. mode is intially copied from column.ui. If
+ * COL_ENABLED_SET is not set, then neither 'always', 'never' nor
+ * 'auto' has been used. Default to 'always'.
+ */
+static int set_mode(int *mode, int value)
+{
+	*mode = (*mode & ~COL_MODE) | value;
+	if (!(*mode & COL_ENABLED_SET))
+		*mode |= COL_ENABLED | COL_ENABLED_SET;
+
+	return 0;
+}
+
+/* Set or unset other COL_* */
+static int set_option(int *mode, int opt, int set)
+{
+	if (set)
+		*mode |= opt;
+	else
+		*mode &= ~opt;
+	return 0;
+}
+
+static int parse_option(const char *arg, int len,
+			int *mode, int stdout_is_tty)
+{
+	struct colopt opts[] = {
+		{ ENABLE, "always",  1 },
+		{ ENABLE, "never",   0 },
+		{ ENABLE, "auto",   -1 },
+	};
+	int i, set, name_len;
+
+	for (i = 0; i < ARRAY_SIZE(opts); i++) {
+		if (opts[i].type == OPTION) {
+			if (len > 2 && !strncmp(arg, "no", 2)) {
+				arg += 2;
+				len -= 2;
+				set = 0;
+			}
+			else
+				set = 1;
+		}
+
+		name_len = strlen(opts[i].name);
+		if (len != name_len ||
+		    strncmp(arg, opts[i].name, name_len))
+			continue;
+
+		switch (opts[i].type) {
+		case ENABLE: return set_enable_bit(mode, opts[i].value,
+						   stdout_is_tty);
+		case MODE: return set_mode(mode, opts[i].value);
+		case OPTION: return set_option(mode, opts[i].value, set);
+		default: die("BUG: Unknown option type %d", opts[i].type);
+		}
+	}
+
+	return error("unsupported style '%s'", arg);
+}
+
+int git_config_column(int *mode, const char *value,
+		      int stdout_is_tty)
+{
+	const char *sep = " ,";
+
+	while (*value) {
+		int len = strcspn(value, sep);
+		if (len) {
+			if (parse_option(value, len, mode, stdout_is_tty))
+				return -1;
+
+			value += len;
+		}
+		value += strspn(value, sep);
+	}
+	return 0;
+}
+
+int parseopt_column_callback(const struct option *opt,
+			     const char *arg, int unset)
+{
+	int *mode = opt->value;
+	if (unset) {
+		*mode = (*mode & ~COL_ENABLED) | COL_ENABLED_SET;
+		return 0;
+	}
+	if (arg)
+		return git_config_column(mode, arg, -1);
+
+	/* no arg, turn it on */
+	*mode |= COL_ENABLED | COL_ENABLED_SET;
+	return 0;
+}
diff --git a/column.h b/column.h
index e0f8c26..59f26dc 100644
--- a/column.h
+++ b/column.h
@@ -3,6 +3,7 @@
 
 #define COL_MODE          0x000F
 #define COL_ENABLED      (1 << 4)
+#define COL_ENABLED_SET  (1 << 5)  /* Has COL_ENABLED been set by config? */
 
 struct column_options {
 	int width;
@@ -19,5 +20,10 @@ extern struct string_list_item *add_cell_to_list(struct string_list *list,
 extern void print_cell(struct string_list *list, int mode, const char *string);
 extern void print_columns(const struct string_list *list,
 			  int mode, struct column_options *opts);
+extern int git_config_column(int *mode, const char *value, int stdout_is_tty);
+
+struct option;
+extern int parseopt_column_callback(const struct option *opt,
+				    const char *arg, int unset);
 
 #endif
diff --git a/command-list.txt b/command-list.txt
index a36ee9b..fe06f15 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
diff --git a/git.c b/git.c
index 3805616..419e3cc 100644
--- a/git.c
+++ b/git.c
@@ -348,6 +348,7 @@ static void handle_internal_command(int argc, const char **argv)
 		{ "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE },
 		{ "clean", cmd_clean, RUN_SETUP | NEED_WORK_TREE },
 		{ "clone", cmd_clone },
+		{ "column", cmd_column },
 		{ "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE },
 		{ "commit-tree", cmd_commit_tree, RUN_SETUP },
 		{ "config", cmd_config, RUN_SETUP_GENTLY },
diff --git a/parse-options.h b/parse-options.h
index 2e811dc..56fcafd 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -238,5 +238,7 @@ extern int parse_opt_noop_cb(const struct option *, const char *, int);
 	  PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }
 #define OPT__COLOR(var, h) \
 	OPT_COLOR_FLAG(0, "color", (var), (h))
+#define OPT_COLUMN(s, l, v, h) \
+	{ OPTION_CALLBACK, (s), (l), (v), "style", (h), PARSE_OPT_OPTARG, parseopt_column_callback }
 
 #endif
diff --git a/t/t9002-column.sh b/t/t9002-column.sh
new file mode 100755
index 0000000..b0b6d62
--- /dev/null
+++ b/t/t9002-column.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+test_description='git column'
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+	cat >lista <<\EOF
+one
+two
+three
+four
+five
+six
+seven
+eight
+nine
+ten
+eleven
+EOF
+'
+
+test_expect_success 'never' '
+	git column --mode=never <lista >actual &&
+	test_cmp lista actual
+'
+
+test_done
-- 
1.7.8.36.g69ee2

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH v4 05/13] Stop starting pager recursively
  2012-02-03 13:34 [PATCH v4 00/13] Column display again Nguyễn Thái Ngọc Duy
                   ` (3 preceding siblings ...)
  2012-02-03 13:34 ` [PATCH v4 04/13] Add git-column and column mode parsing Nguyễn Thái Ngọc Duy
@ 2012-02-03 13:34 ` Nguyễn Thái Ngọc Duy
  2012-02-03 13:34 ` [PATCH v4 06/13] column: add columnar layout Nguyễn Thái Ngọc Duy
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 43+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2012-02-03 13:34 UTC (permalink / raw
  To: git; +Cc: Nguyễn Thái Ngọc Duy

git-column can be used as a pager for other git commands, something
like this:

    GIT_PAGER="git -p column --mode='dense color'" git -p branch

The problem with this is that "git -p column" also has $GIT_PAGER
set so the pager runs itself again as a pager, then again and again.

Stop this.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 pager.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/pager.c b/pager.c
index 772a5a6..e4353dc 100644
--- a/pager.c
+++ b/pager.c
@@ -89,7 +89,7 @@ void setup_pager(void)
 	const char *pager = git_pager(isatty(1));
 	int width;
 
-	if (!pager)
+	if (!pager || pager_in_use())
 		return;
 
 	setenv("GIT_PAGER_IN_USE", "true", 1);
-- 
1.7.8.36.g69ee2

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH v4 06/13] column: add columnar layout
  2012-02-03 13:34 [PATCH v4 00/13] Column display again Nguyễn Thái Ngọc Duy
                   ` (4 preceding siblings ...)
  2012-02-03 13:34 ` [PATCH v4 05/13] Stop starting pager recursively Nguyễn Thái Ngọc Duy
@ 2012-02-03 13:34 ` Nguyễn Thái Ngọc Duy
  2012-02-03 13:34 ` [PATCH v4 07/13] column: support columns with different widths Nguyễn Thái Ngọc Duy
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 43+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2012-02-03 13:34 UTC (permalink / raw
  To: git; +Cc: Nguyễn Thái Ngọc Duy

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 to be in UTF-8. If strings contain ANSI escape
strings, COL_ANSI must be specified for correct length calculation.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 column.c          |  131 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 column.h          |    3 +
 t/t9002-column.sh |   86 +++++++++++++++++++++++++++++++++++
 3 files changed, 219 insertions(+), 1 deletions(-)

diff --git a/column.c b/column.c
index bd15bea..4681106 100644
--- a/column.c
+++ b/column.c
@@ -2,8 +2,66 @@
 #include "column.h"
 #include "string-list.h"
 #include "parse-options.h"
+#include "utf8.h"
 
 #define MODE(mode) ((mode) & COL_MODE)
+#define XY2LINEAR(d,x,y) (MODE((d)->mode) == COL_MODE_COLUMN ? \
+			  (x) * (d)->rows + (y) : \
+			  (y) * (d)->cols + (x))
+
+struct column_data {
+	const struct string_list *list; /* list of all cells */
+	int mode;			/* COL_MODE */
+	int total_width;		/* terminal width */
+	int padding;			/* cell padding */
+	const char *indent;		/* left most column indentation */
+	const char *nl;
+
+	int rows, cols;
+	int *len;			/* cell length */
+};
+
+/* return length of 's' in letters, ANSI escapes stripped */
+static int item_length(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(struct column_data *data, int *width)
+{
+	int i;
+
+	*width = 0;
+	for (i = 0; i < data->list->nr; i++)
+		if (*width < data->len[i])
+			*width = data->len[i];
+
+	*width += data->padding;
+
+	data->cols = (data->total_width - strlen(data->indent)) / *width;
+	if (data->cols == 0)
+		data->cols = 1;
+
+	data->rows = DIV_ROUND_UP(data->list->nr, data->cols);
+}
 
 struct string_list_item *add_cell_to_list(struct string_list *list,
 					  int mode,
@@ -30,6 +88,65 @@ static void display_plain(const struct string_list *list,
 		printf("%s%s%s", indent, list->items[i].string, nl);
 }
 
+/* Print a cell to stdout with all necessary leading/traling space */
+static int display_cell(struct column_data *data, int initial_width,
+			const char *empty_cell, int x, int y)
+{
+	int i, len, newline;
+
+	i = XY2LINEAR(data, x, y);
+	if (i >= data->list->nr)
+		return -1;
+	len = data->len[i];
+	if (MODE(data->mode) == COL_MODE_COLUMN)
+		newline = i + data->rows >= data->list->nr;
+	else
+		newline = x == data->cols - 1 || i == data->list->nr - 1;
+
+	printf("%s%s%s",
+			x == 0 ? data->indent : "",
+			data->list->items[i].string,
+			newline ? data->nl : 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,
+			  const char *nl)
+{
+	struct column_data data;
+	int x, y, i, initial_width;
+	char *empty_cell;
+
+	memset(&data, 0, sizeof(data));
+	data.list = list;
+	data.mode = mode;
+	data.total_width = total_width;
+	data.padding = padding;
+	data.indent = indent;
+	data.nl = nl;
+
+	data.len = xmalloc(sizeof(*data.len) * list->nr);
+	for (i = 0; i < list->nr; i++)
+		data.len[i] = item_length(mode, list->items[i].string);
+
+	layout(&data, &initial_width);
+
+	empty_cell = xmalloc(initial_width + 1);
+	memset(empty_cell, ' ', initial_width);
+	empty_cell[initial_width] = '\0';
+	for (y = 0; y < data.rows; y++) {
+		for (x = 0; x < data.cols; x++)
+			if (display_cell(&data, initial_width, empty_cell, x, y))
+				break;
+	}
+
+	free(data.len);
+	free(empty_cell);
+}
+
 void print_columns(const struct string_list *list, int mode,
 		   struct column_options *opts)
 {
@@ -51,7 +168,16 @@ void print_columns(const struct string_list *list, int mode,
 		display_plain(list, indent, nl);
 		return;
 	}
-	die("BUG: invalid mode %d", MODE(mode));
+
+	switch (MODE(mode)) {
+	case COL_MODE_ROW:
+	case COL_MODE_COLUMN:
+		display_table(list, mode, width, padding, indent, nl);
+		break;
+
+	default:
+		die("BUG: invalid mode %d", MODE(mode));
+	}
 }
 
 struct colopt {
@@ -113,6 +239,9 @@ static int parse_option(const char *arg, int len,
 		{ ENABLE, "always",  1 },
 		{ ENABLE, "never",   0 },
 		{ ENABLE, "auto",   -1 },
+		{ MODE,   "column", COL_MODE_COLUMN },
+		{ MODE,   "row",    COL_MODE_ROW },
+		{ OPTION, "color",  COL_ANSI },
 	};
 	int i, set, name_len;
 
diff --git a/column.h b/column.h
index 59f26dc..38976ea 100644
--- a/column.h
+++ b/column.h
@@ -2,8 +2,11 @@
 #define COLUMN_H
 
 #define COL_MODE          0x000F
+#define COL_MODE_COLUMN        0   /* Fill columns before rows */
+#define COL_MODE_ROW           1   /* Fill rows before columns */
 #define COL_ENABLED      (1 << 4)
 #define COL_ENABLED_SET  (1 << 5)  /* Has COL_ENABLED been set by config? */
+#define COL_ANSI         (1 << 6)  /* Remove ANSI escapes from string length */
 
 struct column_options {
 	int width;
diff --git a/t/t9002-column.sh b/t/t9002-column.sh
index b0b6d62..cffb029 100755
--- a/t/t9002-column.sh
+++ b/t/t9002-column.sh
@@ -24,4 +24,90 @@ test_expect_success 'never' '
 	test_cmp lista actual
 '
 
+test_expect_success '80 columns' '
+	cat >expected <<\EOF &&
+one    two    three  four   five   six    seven  eight  nine   ten    eleven
+EOF
+	COLUMNS=80 git column --mode=column <lista >actual &&
+	test_cmp expected actual
+'
+
+test_expect_success 'COLUMNS = 1' '
+	cat >expected <<\EOF &&
+one
+two
+three
+four
+five
+six
+seven
+eight
+nine
+ten
+eleven
+EOF
+	COLUMNS=1 git column --mode=column <lista >actual &&
+	test_cmp expected actual
+'
+
+test_expect_success 'width = 1' '
+	git column --mode=column --width=1 <lista >actual &&
+	test_cmp expected actual
+'
+
+COLUMNS=20
+export COLUMNS
+
+test_expect_success '20 columns' '
+	cat >expected <<\EOF &&
+one    seven
+two    eight
+three  nine
+four   ten
+five   eleven
+six
+EOF
+	git column --mode=column <lista >actual &&
+	test_cmp expected actual
+'
+
+test_expect_success '20 columns, padding 2' '
+	cat >expected <<\EOF &&
+one     seven
+two     eight
+three   nine
+four    ten
+five    eleven
+six
+EOF
+	git column --mode=column --padding 2 <lista >actual &&
+	test_cmp expected actual
+'
+
+test_expect_success '20 columns, indented' '
+	cat >expected <<\EOF &&
+  one    seven
+  two    eight
+  three  nine
+  four   ten
+  five   eleven
+  six
+EOF
+	git column --mode=column --indent="  " <lista >actual &&
+	test_cmp expected actual
+'
+
+test_expect_success '20 columns, row first' '
+	cat >expected <<\EOF &&
+one    two
+three  four
+five   six
+seven  eight
+nine   ten
+eleven
+EOF
+	git column --mode=row <lista >actual &&
+	test_cmp expected actual
+'
+
 test_done
-- 
1.7.8.36.g69ee2

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH v4 07/13] column: support columns with different widths
  2012-02-03 13:34 [PATCH v4 00/13] Column display again Nguyễn Thái Ngọc Duy
                   ` (5 preceding siblings ...)
  2012-02-03 13:34 ` [PATCH v4 06/13] column: add columnar layout Nguyễn Thái Ngọc Duy
@ 2012-02-03 13:34 ` Nguyễn Thái Ngọc Duy
  2012-02-03 13:34 ` [PATCH v4 08/13] column: add column.ui for default column output settings Nguyễn Thái Ngọc Duy
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 43+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2012-02-03 13:34 UTC (permalink / raw
  To: git; +Cc: Nguyễn Thái Ngọc Duy


Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 column.c          |   80 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 column.h          |    2 +
 t/t9002-column.sh |   22 ++++++++++++++
 3 files changed, 104 insertions(+), 0 deletions(-)

diff --git a/column.c b/column.c
index 4681106..0f658d9 100644
--- a/column.c
+++ b/column.c
@@ -19,6 +19,7 @@ struct column_data {
 
 	int rows, cols;
 	int *len;			/* cell length */
+	int *width;			/* index to the longest row in column */
 };
 
 /* return length of 's' in letters, ANSI escapes stripped */
@@ -63,6 +64,69 @@ static void layout(struct column_data *data, int *width)
 	data->rows = DIV_ROUND_UP(data->list->nr, data->cols);
 }
 
+static void compute_column_width(struct column_data *data)
+{
+	int i, x, y;
+	for (x = 0; x < data->cols; x++) {
+		data->width[x] = XY2LINEAR(data, x, 0);
+		for (y = 0; y < data->rows; y++) {
+			i = XY2LINEAR(data, x, y);
+			if (i >= data->list->nr)
+				continue;
+			if (data->len[data->width[x]] < data->len[i])
+				data->width[x] = i;
+		}
+	}
+}
+
+/*
+ * Shrink all columns by shortening them one row each time (and adding
+ * more columns along the way). Hopefully the longest cell will be
+ * moved to the next column, column is shrunk so we have more space
+ * for new columns. The process ends when the whole thing no longer
+ * fits in data->total_width.
+ */
+static void shrink_columns(struct column_data *data)
+{
+	int x, y, total_width, cols, rows;
+
+	data->width = xrealloc(data->width,
+			       sizeof(*data->width) * data->cols);
+	for (x = 0; x < data->cols; x++) {
+		data->width[x] = 0;
+		for (y = 0; y < data->rows; y++) {
+			int len1 = data->len[data->width[x]];
+			int len2 = data->len[XY2LINEAR(data, x, y)];
+			if (len1 < len2)
+				data->width[x] = y;
+		}
+	}
+
+	while (data->rows > 1) {
+		rows = data->rows;
+		cols = data->cols;
+
+		data->rows--;
+		data->cols = DIV_ROUND_UP(data->list->nr, data->rows);
+		if (data->cols != cols)
+			data->width = xrealloc(data->width, sizeof(*data->width) * data->cols);
+
+		compute_column_width(data);
+
+		total_width = strlen(data->indent);
+		for (x = 0; x < data->cols; x++) {
+			total_width += data->len[data->width[x]];
+			total_width += data->padding;
+		}
+		if (total_width > data->total_width) {
+			data->rows = rows;
+			data->cols = cols;
+			compute_column_width(data);
+			break;
+		}
+	}
+}
+
 struct string_list_item *add_cell_to_list(struct string_list *list,
 					  int mode,
 					  const char *string)
@@ -97,7 +161,18 @@ static int display_cell(struct column_data *data, int initial_width,
 	i = XY2LINEAR(data, x, y);
 	if (i >= data->list->nr)
 		return -1;
+
 	len = data->len[i];
+	if (data->width && data->len[data->width[x]] < initial_width) {
+		/*
+		 * empty_cell has initial_width chars, if real column
+		 * is narrower, increase len a bit so we fill less
+		 * space.
+		 */
+		len += initial_width - data->len[data->width[x]];
+		len -= data->padding;
+	}
+
 	if (MODE(data->mode) == COL_MODE_COLUMN)
 		newline = i + data->rows >= data->list->nr;
 	else
@@ -134,6 +209,9 @@ static void display_table(const struct string_list *list,
 
 	layout(&data, &initial_width);
 
+	if (mode & COL_DENSE)
+		shrink_columns(&data);
+
 	empty_cell = xmalloc(initial_width + 1);
 	memset(empty_cell, ' ', initial_width);
 	empty_cell[initial_width] = '\0';
@@ -144,6 +222,7 @@ static void display_table(const struct string_list *list,
 	}
 
 	free(data.len);
+	free(data.width);
 	free(empty_cell);
 }
 
@@ -242,6 +321,7 @@ static int parse_option(const char *arg, int len,
 		{ MODE,   "column", COL_MODE_COLUMN },
 		{ MODE,   "row",    COL_MODE_ROW },
 		{ OPTION, "color",  COL_ANSI },
+		{ OPTION, "dense",  COL_DENSE },
 	};
 	int i, set, name_len;
 
diff --git a/column.h b/column.h
index 38976ea..1912cb0 100644
--- a/column.h
+++ b/column.h
@@ -7,6 +7,8 @@
 #define COL_ENABLED      (1 << 4)
 #define COL_ENABLED_SET  (1 << 5)  /* Has COL_ENABLED been set by config? */
 #define COL_ANSI         (1 << 6)  /* Remove ANSI escapes from string length */
+#define COL_DENSE        (1 << 7)  /* Shrink columns when possible,
+				      making space for more columns */
 
 struct column_options {
 	int width;
diff --git a/t/t9002-column.sh b/t/t9002-column.sh
index cffb029..23d340e 100755
--- a/t/t9002-column.sh
+++ b/t/t9002-column.sh
@@ -71,6 +71,17 @@ EOF
 	test_cmp expected actual
 '
 
+test_expect_success '20 columns, dense' '
+	cat >expected <<\EOF &&
+one   five  nine
+two   six   ten
+three seven eleven
+four  eight
+EOF
+	git column --mode=column,dense < lista > actual &&
+	test_cmp expected actual
+'
+
 test_expect_success '20 columns, padding 2' '
 	cat >expected <<\EOF &&
 one     seven
@@ -110,4 +121,15 @@ EOF
 	test_cmp expected actual
 '
 
+test_expect_success '20 columns, row first, dense' '
+	cat >expected <<\EOF &&
+one   two    three
+four  five   six
+seven eight  nine
+ten   eleven
+EOF
+	git column --mode=row,dense <lista >actual &&
+	test_cmp expected actual
+'
+
 test_done
-- 
1.7.8.36.g69ee2

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH v4 08/13] column: add column.ui for default column output settings
  2012-02-03 13:34 [PATCH v4 00/13] Column display again Nguyễn Thái Ngọc Duy
                   ` (6 preceding siblings ...)
  2012-02-03 13:34 ` [PATCH v4 07/13] column: support columns with different widths Nguyễn Thái Ngọc Duy
@ 2012-02-03 13:34 ` Nguyễn Thái Ngọc Duy
  2012-02-03 23:04   ` Junio C Hamano
  2012-02-03 13:34 ` [PATCH v4 09/13] help: reuse print_columns() for help -a Nguyễn Thái Ngọc Duy
                   ` (5 subsequent siblings)
  13 siblings, 1 reply; 43+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2012-02-03 13:34 UTC (permalink / raw
  To: git; +Cc: Nguyễn Thái Ngọc Duy


Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/config.txt     |   26 ++++++++++++++++++++++++++
 Documentation/git-column.txt |    6 +++++-
 builtin/column.c             |   23 +++++++++++++++++++++++
 column.c                     |   36 ++++++++++++++++++++++++++++++++++++
 column.h                     |    4 ++++
 5 files changed, 94 insertions(+), 1 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index abeb82b..5216598 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -821,6 +821,32 @@ color.ui::
 	`never` if you prefer git commands not to use color unless enabled
 	explicitly with some other configuration or the `--color` option.
 
+column.ui::
+	Specify whether supported commands should output in columns.
+	This variable consists of a list of tokens separated by spaces
+	or commas:
++
+--
+`always`;;
+	always show in columns
+`never`;;
+	never show in columns
+`auto`;;
+	show in columns if the output is to the terminal
+`column`;;
+	fill columns before rows (default)
+`row`;;
+	fill rows before columns
+`dense`;;
+	make unequal size columns to utilize more space
+`nodense`;;
+	make equal size columns
+`color`;;
+	input contains ANSI escape sequence for coloring
+--
++
+	This option defaults to 'never'.
+
 commit.status::
 	A boolean to enable/disable inclusion of status information in the
 	commit message template when using an editor to prepare the commit
diff --git a/Documentation/git-column.txt b/Documentation/git-column.txt
index 508b85f..94fd7ac 100644
--- a/Documentation/git-column.txt
+++ b/Documentation/git-column.txt
@@ -8,7 +8,7 @@ git-column - Display data in columns
 SYNOPSIS
 --------
 [verse]
-'git column' [--mode=<mode> | --rawmode=<n>] [--width=<width>]
+'git column' [--command=<name>] [--[raw]mode=<mode>] [--width=<width>]
 	     [--indent=<string>] [--nl=<string>] [--pading=<n>]
 
 DESCRIPTION
@@ -17,6 +17,10 @@ This command formats its input into multiple columns.
 
 OPTIONS
 -------
+--command=<name>::
+	Look up layout mode using configuration variable column.<name> and
+	column.ui.
+
 --mode=<mode>::
 	Specify layout mode. See configuration variable column.ui for option
 	syntax.
diff --git a/builtin/column.c b/builtin/column.c
index c4a0431..c4e1fe4 100644
--- a/builtin/column.c
+++ b/builtin/column.c
@@ -11,12 +11,19 @@ static const char * const builtin_column_usage[] = {
 };
 static int colopts;
 
+static int column_config(const char *var, const char *value, void *cb)
+{
+	return git_column_config(var, value, cb, &colopts);
+}
+
 int cmd_column(int argc, const char **argv, const char *prefix)
 {
 	struct string_list list = STRING_LIST_INIT_DUP;
 	struct strbuf sb = STRBUF_INIT;
 	struct column_options copts;
+	const char *command = NULL, *real_command = NULL;
 	struct option options[] = {
+		OPT_STRING(0, "command", &real_command, "name", "lookup config vars"),
 		OPT_COLUMN(0, "mode", &colopts, "layout to use"),
 		OPT_INTEGER(0, "rawmode", &colopts, "layout to use"),
 		OPT_INTEGER(0, "width", &copts.width, "Maximum width"),
@@ -26,6 +33,17 @@ int cmd_column(int argc, const char **argv, const char *prefix)
 		OPT_END()
 	};
 
+	/* This one is special and must be the first one */
+	if (argc > 1 && !prefixcmp(argv[1], "--command=")) {
+		int nonitok = 0;
+		setup_git_directory_gently(&nonitok);
+
+		command = argv[1] + 10;
+		git_config(column_config, (void*)command);
+		if (!colopts)
+			colopts = git_colopts;
+	}
+
 	memset(&copts, 0, sizeof(copts));
 	copts.width = term_columns();
 	copts.padding = 1;
@@ -33,6 +51,11 @@ int cmd_column(int argc, const char **argv, const char *prefix)
 	if (argc)
 		usage_with_options(builtin_column_usage, options);
 
+	if (real_command || command) {
+		if (!real_command || !command || strcmp(real_command, command))
+			die(_("--command must be the first argument"));
+	}
+
 	while (!strbuf_getline(&sb, stdin, '\n'))
 		string_list_append(&list, sb.buf);
 
diff --git a/column.c b/column.c
index 0f658d9..671ee5d 100644
--- a/column.c
+++ b/column.c
@@ -2,6 +2,7 @@
 #include "column.h"
 #include "string-list.h"
 #include "parse-options.h"
+#include "color.h"
 #include "utf8.h"
 
 #define MODE(mode) ((mode) & COL_MODE)
@@ -22,6 +23,8 @@ struct column_data {
 	int *width;			/* index to the longest row in column */
 };
 
+int git_colopts;
+
 /* return length of 's' in letters, ANSI escapes stripped */
 static int item_length(int mode, const char *s)
 {
@@ -371,6 +374,39 @@ int git_config_column(int *mode, const char *value,
 	return 0;
 }
 
+static int column_config(const char *var, const char *value,
+			 const char *key, int *colopts)
+{
+	if (!strcmp(var, key)) {
+		int ret = git_config_column(colopts, value, -1);
+		if (ret)
+			die("invalid %s mode %s", key, value);
+		return 0;
+	}
+	return 1;		/* go on */
+}
+
+int git_column_config(const char *var, const char *value,
+		      const char *command, int *colopts)
+{
+	int ret;
+
+	ret = column_config(var, value, "column.ui", &git_colopts);
+	if (ret <= 0)
+		return ret;
+
+	if (command) {
+		struct strbuf sb = STRBUF_INIT;
+		strbuf_addf(&sb, "column.%s", command);
+		ret = column_config(var, value, sb.buf, colopts);
+		strbuf_release(&sb);
+		if (ret <= 0)
+			return ret;
+	}
+
+	return 1;		/* go on */
+}
+
 int parseopt_column_callback(const struct option *opt,
 			     const char *arg, int unset)
 {
diff --git a/column.h b/column.h
index 1912cb0..afdafc4 100644
--- a/column.h
+++ b/column.h
@@ -17,6 +17,8 @@ struct column_options {
 	const char *nl;
 };
 
+extern int git_colopts;
+
 extern int term_columns(void);
 extern struct string_list_item *add_cell_to_list(struct string_list *list,
 						 int mode,
@@ -26,6 +28,8 @@ extern void print_cell(struct string_list *list, int mode, const char *string);
 extern void print_columns(const struct string_list *list,
 			  int mode, struct column_options *opts);
 extern int git_config_column(int *mode, const char *value, int stdout_is_tty);
+extern int git_column_config(const char *var, const char *value,
+			     const char *command, int *colopts);
 
 struct option;
 extern int parseopt_column_callback(const struct option *opt,
-- 
1.7.8.36.g69ee2

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH v4 09/13] help: reuse print_columns() for help -a
  2012-02-03 13:34 [PATCH v4 00/13] Column display again Nguyễn Thái Ngọc Duy
                   ` (7 preceding siblings ...)
  2012-02-03 13:34 ` [PATCH v4 08/13] column: add column.ui for default column output settings Nguyễn Thái Ngọc Duy
@ 2012-02-03 13:34 ` Nguyễn Thái Ngọc Duy
  2012-02-03 23:05   ` Junio C Hamano
  2012-02-03 13:34 ` [PATCH v4 10/13] branch: add --column Nguyễn Thái Ngọc Duy
                   ` (4 subsequent siblings)
  13 siblings, 1 reply; 43+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2012-02-03 13:34 UTC (permalink / raw
  To: git; +Cc: Nguyễn Thái Ngọc Duy


Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 help.c |   47 +++++++++++++----------------------------------
 1 files changed, 13 insertions(+), 34 deletions(-)

diff --git a/help.c b/help.c
index 672561b..d6d2e19 100644
--- a/help.c
+++ b/help.c
@@ -4,6 +4,7 @@
 #include "levenshtein.h"
 #include "help.h"
 #include "common-cmds.h"
+#include "string-list.h"
 #include "column.h"
 
 void add_cmdname(struct cmdnames *cmds, const char *name, int len)
@@ -71,31 +72,18 @@ void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes)
 	cmds->cnt = cj;
 }
 
-static void pretty_print_string_list(struct cmdnames *cmds, int longest)
+static void pretty_print_string_list(struct cmdnames *cmds)
 {
-	int cols = 1, rows;
-	int space = longest + 1; /* min 1 SP between words */
-	int max_cols = term_columns() - 1; /* don't print *on* the edge */
-	int i, j;
-
-	if (space < max_cols)
-		cols = max_cols / space;
-	rows = DIV_ROUND_UP(cmds->cnt, cols);
-
-	for (i = 0; i < rows; i++) {
-		printf("  ");
+	struct string_list list = STRING_LIST_INIT_NODUP;
+	struct column_options copts;
+	int i;
 
-		for (j = 0; j < cols; j++) {
-			int n = j * rows + i;
-			int size = space;
-			if (n >= cmds->cnt)
-				break;
-			if (j == cols-1 || n + rows >= cmds->cnt)
-				size = 1;
-			printf("%-*s", size, cmds->names[n]->name);
-		}
-		putchar('\n');
-	}
+	for (i = 0; i < cmds->cnt; i++)
+		string_list_append(&list, cmds->names[i]->name);
+	memset(&copts, 0, sizeof(copts));
+	copts.indent = "  ";
+	print_columns(&list, COL_MODE_COLUMN | COL_ENABLED, &copts);
+	string_list_clear(&list, 0);
 }
 
 static int is_executable(const char *name)
@@ -207,22 +195,13 @@ void load_command_list(const char *prefix,
 void list_commands(const char *title, struct cmdnames *main_cmds,
 		   struct cmdnames *other_cmds)
 {
-	int i, longest = 0;
-
-	for (i = 0; i < main_cmds->cnt; i++)
-		if (longest < main_cmds->names[i]->len)
-			longest = main_cmds->names[i]->len;
-	for (i = 0; i < other_cmds->cnt; i++)
-		if (longest < other_cmds->names[i]->len)
-			longest = other_cmds->names[i]->len;
-
 	if (main_cmds->cnt) {
 		const char *exec_path = git_exec_path();
 		printf("available %s in '%s'\n", title, exec_path);
 		printf("----------------");
 		mput_char('-', strlen(title) + strlen(exec_path));
 		putchar('\n');
-		pretty_print_string_list(main_cmds, longest);
+		pretty_print_string_list(main_cmds);
 		putchar('\n');
 	}
 
@@ -231,7 +210,7 @@ void list_commands(const char *title, struct cmdnames *main_cmds,
 		printf("---------------------------------------");
 		mput_char('-', strlen(title));
 		putchar('\n');
-		pretty_print_string_list(other_cmds, longest);
+		pretty_print_string_list(other_cmds);
 		putchar('\n');
 	}
 }
-- 
1.7.8.36.g69ee2

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH v4 10/13] branch: add --column
  2012-02-03 13:34 [PATCH v4 00/13] Column display again Nguyễn Thái Ngọc Duy
                   ` (8 preceding siblings ...)
  2012-02-03 13:34 ` [PATCH v4 09/13] help: reuse print_columns() for help -a Nguyễn Thái Ngọc Duy
@ 2012-02-03 13:34 ` Nguyễn Thái Ngọc Duy
  2012-02-03 23:11   ` Junio C Hamano
  2012-02-03 13:34 ` [PATCH v4 11/13] status: " Nguyễn Thái Ngọc Duy
                   ` (3 subsequent siblings)
  13 siblings, 1 reply; 43+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2012-02-03 13:34 UTC (permalink / raw
  To: git; +Cc: Nguyễn Thái Ngọc Duy


Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/config.txt     |    4 ++++
 Documentation/git-branch.txt |    9 +++++++++
 Makefile                     |    2 +-
 builtin/branch.c             |   26 +++++++++++++++++++++++---
 4 files changed, 37 insertions(+), 4 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 5216598..c14db27 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -847,6 +847,10 @@ column.ui::
 +
 	This option defaults to 'never'.
 
+column.branch::
+	Specify whether to output branch listing in `git branch` in columns.
+	See `column.ui` for details.
+
 commit.status::
 	A boolean to enable/disable inclusion of status information in the
 	commit message template when using an editor to prepare the commit
diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index 0427e80..ba5cccb 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -10,6 +10,7 @@ SYNOPSIS
 [verse]
 'git branch' [--color[=<when>] | --no-color] [-r | -a]
 	[--list] [-v [--abbrev=<length> | --no-abbrev]]
+	[--column[=<options>] | --no-column]
 	[(--merged | --no-merged | --contains) [<commit>]] [<pattern>...]
 'git branch' [--set-upstream | --track | --no-track] [-l] [-f] <branchname> [<start-point>]
 'git branch' (-m | -M) [<oldbranch>] <newbranch>
@@ -107,6 +108,14 @@ OPTIONS
 	default to color output.
 	Same as `--color=never`.
 
+--column[=<options>]::
+--no-column::
+	Display branch listing in columns. See configuration variable
+	column.branch for option syntax.`--column` and `--no-column`
+	without options are equivalent to 'always' and 'never' respectively.
++
+This option is only applicable in non-verbose mode.
+
 -r::
 --remotes::
 	List or delete (if used with -d) the remote-tracking branches.
diff --git a/Makefile b/Makefile
index 92700ca..061f6e5 100644
--- a/Makefile
+++ b/Makefile
@@ -2116,7 +2116,7 @@ builtin/prune.o builtin/reflog.o reachable.o: reachable.h
 builtin/commit.o builtin/revert.o wt-status.o: wt-status.h
 builtin/tar-tree.o archive-tar.o: tar.h
 connect.o transport.o url.o http-backend.o: url.h
-column.o help.o pager.o: column.h
+builtin/branch.o column.o help.o pager.o: column.h
 http-fetch.o http-walker.o remote-curl.o transport.o walker.o: walker.h
 http.o http-walker.o http-push.o http-fetch.o remote-curl.o: http.h url.h
 
diff --git a/builtin/branch.c b/builtin/branch.c
index 7095718..d78690a 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -15,6 +15,8 @@
 #include "branch.h"
 #include "diff.h"
 #include "revision.h"
+#include "string-list.h"
+#include "column.h"
 
 static const char * const builtin_branch_usage[] = {
 	"git branch [options] [-r | -a] [--merged | --no-merged]",
@@ -53,6 +55,9 @@ static enum merge_filter {
 } merge_filter;
 static unsigned char merge_filter_ref[20];
 
+static struct string_list output = STRING_LIST_INIT_DUP;
+static int colopts;
+
 static int parse_branch_color_slot(const char *var, int ofs)
 {
 	if (!strcasecmp(var+ofs, "plain"))
@@ -70,6 +75,9 @@ static int parse_branch_color_slot(const char *var, int ofs)
 
 static int git_branch_config(const char *var, const char *value, void *cb)
 {
+	int status = git_column_config(var, value, "branch", &colopts);
+	if (status <= 0)
+		return status;
 	if (!strcmp(var, "color.branch")) {
 		branch_use_color = git_config_colorbool(var, value);
 		return 0;
@@ -474,7 +482,7 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
 	else if (verbose)
 		/* " f7c0c00 [ahead 58, behind 197] vcs-svn: drop obj_pool.h" */
 		add_verbose_info(&out, item, verbose, abbrev);
-	printf("%s\n", out.buf);
+	print_cell(&output, colopts, out.buf);
 	strbuf_release(&name);
 	strbuf_release(&out);
 }
@@ -727,6 +735,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 			PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NONEG,
 			opt_parse_merge_filter, (intptr_t) "HEAD",
 		},
+		OPT_COLUMN(0, "column", &colopts, "list branches in columns" ),
 		OPT_END(),
 	};
 
@@ -749,6 +758,9 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 	}
 	hashcpy(merge_filter_ref, head_sha1);
 
+	if (!colopts)
+		colopts = git_colopts | COL_ANSI;
+
 	argc = parse_options(argc, argv, prefix, options, builtin_branch_usage,
 			     0);
 
@@ -763,9 +775,17 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 
 	if (delete)
 		return delete_branches(argc, argv, delete > 1, kinds);
-	else if (list)
-		return print_ref_list(kinds, detached, verbose, abbrev,
+	else if (list) {
+		int ret;
+		if (verbose)
+			colopts = 0;
+
+		ret = print_ref_list(kinds, detached, verbose, abbrev,
 				      with_commit, argv);
+		print_columns(&output, colopts, NULL);
+		string_list_clear(&output, 0);
+		return ret;
+	}
 	else if (edit_description) {
 		const char *branch_name;
 		if (detached)
-- 
1.7.8.36.g69ee2

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH v4 11/13] status: add --column
  2012-02-03 13:34 [PATCH v4 00/13] Column display again Nguyễn Thái Ngọc Duy
                   ` (9 preceding siblings ...)
  2012-02-03 13:34 ` [PATCH v4 10/13] branch: add --column Nguyễn Thái Ngọc Duy
@ 2012-02-03 13:34 ` Nguyễn Thái Ngọc Duy
  2012-02-03 23:19   ` Junio C Hamano
  2012-02-03 13:34 ` [PATCH v4 12/13] column: support piping stdout to external git-column process Nguyễn Thái Ngọc Duy
                   ` (2 subsequent siblings)
  13 siblings, 1 reply; 43+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2012-02-03 13:34 UTC (permalink / raw
  To: git; +Cc: Nguyễn Thái Ngọc Duy


Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/config.txt     |    4 ++++
 Documentation/git-status.txt |    7 +++++++
 Makefile                     |    2 +-
 builtin/commit.c             |   13 +++++++++++--
 wt-status.c                  |   38 ++++++++++++++++++++++++++++++++------
 wt-status.h                  |    2 +-
 6 files changed, 56 insertions(+), 10 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index c14db27..ebb210c 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -851,6 +851,10 @@ column.branch::
 	Specify whether to output branch listing in `git branch` in columns.
 	See `column.ui` for details.
 
+column.status::
+	Specify whether to output untracked files in `git status` in columns.
+	See `column.ui` for details.
+
 commit.status::
 	A boolean to enable/disable inclusion of status information in the
 	commit message template when using an editor to prepare the commit
diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt
index 3d51717..2f87207 100644
--- a/Documentation/git-status.txt
+++ b/Documentation/git-status.txt
@@ -77,6 +77,13 @@ configuration variable documented in linkgit:git-config[1].
 	Terminate entries with NUL, instead of LF.  This implies
 	the `--porcelain` output format if no other format is given.
 
+--column[=<options>]::
+--no-column::
+	Display untracked files in columns. See configuration variable
+	column.status for option syntax.`--column` and `--no-column`
+	without options are equivalent to 'always' and 'never'
+	respectively.
+
 
 OUTPUT
 ------
diff --git a/Makefile b/Makefile
index 061f6e5..b2644bc 100644
--- a/Makefile
+++ b/Makefile
@@ -2116,7 +2116,7 @@ builtin/prune.o builtin/reflog.o reachable.o: reachable.h
 builtin/commit.o builtin/revert.o wt-status.o: wt-status.h
 builtin/tar-tree.o archive-tar.o: tar.h
 connect.o transport.o url.o http-backend.o: url.h
-builtin/branch.o column.o help.o pager.o: column.h
+builtin/branch.o builtin/commit.o column.o help.o pager.o: column.h
 http-fetch.o http-walker.o remote-curl.o transport.o walker.o: walker.h
 http.o http-walker.o http-push.o http-fetch.o remote-curl.o: http.h url.h
 
diff --git a/builtin/commit.c b/builtin/commit.c
index eba1377..8ce6a18 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -27,6 +27,7 @@
 #include "quote.h"
 #include "submodule.h"
 #include "gpg-interface.h"
+#include "column.h"
 
 static const char * const builtin_commit_usage[] = {
 	"git commit [options] [--] <filepattern>...",
@@ -88,6 +89,7 @@ static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
 static int no_post_rewrite, allow_empty_message;
 static char *untracked_files_arg, *force_date, *ignore_submodule_arg;
 static char *sign_commit;
+static int colopts;
 
 /*
  * The default commit message cleanup mode will remove the lines
@@ -519,7 +521,7 @@ static int run_status(FILE *fp, const char *index_file, const char *prefix, int
 		wt_porcelain_print(s, null_termination);
 		break;
 	case STATUS_FORMAT_LONG:
-		wt_status_print(s);
+		wt_status_print(s, 0);
 		break;
 	}
 
@@ -1138,7 +1140,11 @@ static int parse_status_slot(const char *var, int offset)
 static int git_status_config(const char *k, const char *v, void *cb)
 {
 	struct wt_status *s = cb;
+	int status;
 
+	status = git_column_config(k, v, "status", &colopts);
+	if (status <= 0)
+		return status;
 	if (!strcmp(k, "status.submodulesummary")) {
 		int is_bool;
 		s->submodule_summary = git_config_bool_or_int(k, v, &is_bool);
@@ -1204,6 +1210,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
 		{ OPTION_STRING, 0, "ignore-submodules", &ignore_submodule_arg, "when",
 		  "ignore changes to submodules, optional when: all, dirty, untracked. (Default: all)",
 		  PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
+		OPT_COLUMN(0, "column", &colopts, "list untracked files in columns" ),
 		OPT_END(),
 	};
 
@@ -1213,6 +1220,8 @@ int cmd_status(int argc, const char **argv, const char *prefix)
 	wt_status_prepare(&s);
 	gitmodules_config();
 	git_config(git_status_config, &s);
+	if (!colopts)
+		colopts = git_colopts | COL_ANSI;
 	determine_whence(&s);
 	argc = parse_options(argc, argv, prefix,
 			     builtin_status_options,
@@ -1251,7 +1260,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
 	case STATUS_FORMAT_LONG:
 		s.verbose = verbose;
 		s.ignore_submodule_arg = ignore_submodule_arg;
-		wt_status_print(&s);
+		wt_status_print(&s, colopts);
 		break;
 	}
 	return 0;
diff --git a/wt-status.c b/wt-status.c
index 9ffc535..86291e9 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -11,6 +11,7 @@
 #include "remote.h"
 #include "refs.h"
 #include "submodule.h"
+#include "column.h"
 
 static char default_wt_status_colors[][COLOR_MAXLEN] = {
 	GIT_COLOR_NORMAL, /* WT_STATUS_HEADER */
@@ -637,10 +638,13 @@ static void wt_status_print_submodule_summary(struct wt_status *s, int uncommitt
 static void wt_status_print_other(struct wt_status *s,
 				  struct string_list *l,
 				  const char *what,
-				  const char *how)
+				  const char *how,
+				  int colopts)
 {
 	int i;
 	struct strbuf buf = STRBUF_INIT;
+	static struct string_list output = STRING_LIST_INIT_DUP;
+	struct column_options copts;
 
 	if (!l->nr)
 		return;
@@ -649,12 +653,32 @@ static void wt_status_print_other(struct wt_status *s,
 
 	for (i = 0; i < l->nr; i++) {
 		struct string_list_item *it;
+		const char *path;
 		it = &(l->items[i]);
+		path = quote_path(it->string, strlen(it->string),
+				  &buf, s->prefix);
+		if (colopts & COL_ENABLED) {
+			add_cell_to_list(&output, colopts, path);
+			continue;
+		}
 		status_printf(s, color(WT_STATUS_HEADER, s), "\t");
 		status_printf_more(s, color(WT_STATUS_UNTRACKED, s),
-			"%s\n", quote_path(it->string, strlen(it->string),
-					    &buf, s->prefix));
+				   "%s\n", path);
 	}
+
+	strbuf_release(&buf);
+	if ((colopts & COL_ENABLED) == 0)
+		return;
+
+	strbuf_addf(&buf, "%s#\t%s",
+		    color(WT_STATUS_HEADER,s),
+		    color(WT_STATUS_UNTRACKED, s));
+	memset(&copts, 0, sizeof(copts));
+	copts.padding = 1;
+	copts.indent = buf.buf;
+	copts.nl = GIT_COLOR_RESET "\n";
+	print_columns(&output, colopts, &copts);
+	string_list_clear(&output, 0);
 	strbuf_release(&buf);
 }
 
@@ -704,7 +728,7 @@ static void wt_status_print_tracking(struct wt_status *s)
 	color_fprintf_ln(s->fp, color(WT_STATUS_HEADER, s), "#");
 }
 
-void wt_status_print(struct wt_status *s)
+void wt_status_print(struct wt_status *s, int colopts)
 {
 	const char *branch_color = color(WT_STATUS_ONBRANCH, s);
 	const char *branch_status_color = color(WT_STATUS_HEADER, s);
@@ -742,9 +766,11 @@ void wt_status_print(struct wt_status *s)
 		wt_status_print_submodule_summary(s, 1);  /* unstaged */
 	}
 	if (s->show_untracked_files) {
-		wt_status_print_other(s, &s->untracked, _("Untracked"), "add");
+		wt_status_print_other(s, &s->untracked,
+				      _("Untracked"), "add", colopts);
 		if (s->show_ignored_files)
-			wt_status_print_other(s, &s->ignored, _("Ignored"), "add -f");
+			wt_status_print_other(s, &s->ignored,
+					      _("Ignored"), "add -f", colopts);
 	} else if (s->commitable)
 		status_printf_ln(s, GIT_COLOR_NORMAL, _("Untracked files not listed%s"),
 			advice_status_hints
diff --git a/wt-status.h b/wt-status.h
index 682b4c8..4ab2799 100644
--- a/wt-status.h
+++ b/wt-status.h
@@ -69,7 +69,7 @@ struct wt_status {
 };
 
 void wt_status_prepare(struct wt_status *s);
-void wt_status_print(struct wt_status *s);
+void wt_status_print(struct wt_status *s, int colopts);
 void wt_status_collect(struct wt_status *s);
 
 void wt_shortstatus_print(struct wt_status *s, int null_termination, int show_branch);
-- 
1.7.8.36.g69ee2

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH v4 12/13] column: support piping stdout to external git-column process
  2012-02-03 13:34 [PATCH v4 00/13] Column display again Nguyễn Thái Ngọc Duy
                   ` (10 preceding siblings ...)
  2012-02-03 13:34 ` [PATCH v4 11/13] status: " Nguyễn Thái Ngọc Duy
@ 2012-02-03 13:34 ` Nguyễn Thái Ngọc Duy
  2012-02-03 13:34 ` [PATCH v4 13/13] tag: add --column Nguyễn Thái Ngọc Duy
  2012-02-04 15:59 ` [PATCH v5 00/12] Column display Nguyễn Thái Ngọc Duy
  13 siblings, 0 replies; 43+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2012-02-03 13:34 UTC (permalink / raw
  To: git; +Cc: Nguyễn Thái Ngọc Duy

For too complicated output handling, it'd be easier to just spawn
git-column and redirect stdout to it. This patch provides helpers
to do that.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 column.c |   69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 column.h |    3 ++
 2 files changed, 72 insertions(+), 0 deletions(-)

diff --git a/column.c b/column.c
index 671ee5d..ff8e4ac 100644
--- a/column.c
+++ b/column.c
@@ -2,6 +2,7 @@
 #include "column.h"
 #include "string-list.h"
 #include "parse-options.h"
+#include "run-command.h"
 #include "color.h"
 #include "utf8.h"
 
@@ -422,3 +423,71 @@ int parseopt_column_callback(const struct option *opt,
 	*mode |= COL_ENABLED | COL_ENABLED_SET;
 	return 0;
 }
+
+static int fd_out = -1;
+static struct child_process column_process;
+
+int run_column_filter(int colopts, const struct column_options *opts)
+{
+	const char *av[10];
+	int ret, ac = 0;
+	struct strbuf sb_colopt  = STRBUF_INIT;
+	struct strbuf sb_width   = STRBUF_INIT;
+	struct strbuf sb_padding = STRBUF_INIT;
+
+	if (fd_out != -1)
+		return -1;
+
+	av[ac++] = "column";
+	strbuf_addf(&sb_colopt, "--rawmode=0x%x", colopts);
+	av[ac++] = sb_colopt.buf;
+	if (opts->width) {
+		strbuf_addf(&sb_width, "--width=%d", opts->width);
+		av[ac++] = sb_width.buf;
+	}
+	if (opts->indent) {
+		av[ac++] = "--indent";
+		av[ac++] = opts->indent;
+	}
+	if (opts->padding) {
+		strbuf_addf(&sb_padding, "--padding=%d", opts->padding);
+		av[ac++] = sb_padding.buf;
+	}
+	av[ac] = NULL;
+
+	fflush(stdout);
+	memset(&column_process, 0, sizeof(column_process));
+	column_process.in = -1;
+	column_process.out = dup(1);
+	column_process.git_cmd = 1;
+	column_process.argv = av;
+
+	ret = start_command(&column_process);
+
+	strbuf_release(&sb_colopt);
+	strbuf_release(&sb_width);
+	strbuf_release(&sb_padding);
+
+	if (ret)
+		return -2;
+
+	fd_out = dup(1);
+	close(1);
+	dup2(column_process.in, 1);
+	close(column_process.in);
+	return 0;
+}
+
+int stop_column_filter()
+{
+	if (fd_out == -1)
+		return -1;
+
+	fflush(stdout);
+	close(1);
+	finish_command(&column_process);
+	dup2(fd_out, 1);
+	close(fd_out);
+	fd_out = -1;
+	return 0;
+}
diff --git a/column.h b/column.h
index afdafc4..58d73b8 100644
--- a/column.h
+++ b/column.h
@@ -35,4 +35,7 @@ struct option;
 extern int parseopt_column_callback(const struct option *opt,
 				    const char *arg, int unset);
 
+extern int run_column_filter(int colopts, const struct column_options *);
+extern int stop_column_filter();
+
 #endif
-- 
1.7.8.36.g69ee2

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH v4 13/13] tag: add --column
  2012-02-03 13:34 [PATCH v4 00/13] Column display again Nguyễn Thái Ngọc Duy
                   ` (11 preceding siblings ...)
  2012-02-03 13:34 ` [PATCH v4 12/13] column: support piping stdout to external git-column process Nguyễn Thái Ngọc Duy
@ 2012-02-03 13:34 ` Nguyễn Thái Ngọc Duy
  2012-02-03 23:30   ` Junio C Hamano
  2012-02-04 15:59 ` [PATCH v5 00/12] Column display Nguyễn Thái Ngọc Duy
  13 siblings, 1 reply; 43+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2012-02-03 13:34 UTC (permalink / raw
  To: git; +Cc: Nguyễn Thái Ngọc Duy


Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/config.txt  |    4 ++++
 Documentation/git-tag.txt |   11 ++++++++++-
 Makefile                  |    2 +-
 builtin/tag.c             |   25 ++++++++++++++++++++++---
 4 files changed, 37 insertions(+), 5 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index ebb210c..145336a 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -855,6 +855,10 @@ column.status::
 	Specify whether to output untracked files in `git status` in columns.
 	See `column.ui` for details.
 
+column.tag::
+	Specify whether to output tag listing in `git tag` in columns.
+	See `column.ui` for details.
+
 commit.status::
 	A boolean to enable/disable inclusion of status information in the
 	commit message template when using an editor to prepare the commit
diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
index 53ff5f6..5ead91e 100644
--- a/Documentation/git-tag.txt
+++ b/Documentation/git-tag.txt
@@ -12,7 +12,8 @@ SYNOPSIS
 'git tag' [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>]
 	<tagname> [<commit> | <object>]
 'git tag' -d <tagname>...
-'git tag' [-n[<num>]] -l [--contains <commit>] [<pattern>...]
+'git tag' [-n[<num>]] -l [--contains <commit>]
+	[--column[=<options>] | --no-column] [<pattern>...]
 'git tag' -v <tagname>...
 
 DESCRIPTION
@@ -83,6 +84,14 @@ OPTIONS
 	using fnmatch(3)).  Multiple patterns may be given; if any of
 	them matches, the tag is shown.
 
+--column[=<options>]::
+--no-column::
+	Display tag listing in columns. See configuration variable
+	column.tag for option syntax.`--column` and `--no-column`
+	without options are equivalent to 'always' and 'never' respectively.
++
+This option is only applicable when listing tags without annotation lines.
+
 --contains <commit>::
 	Only list tags which contain the specified commit.
 
diff --git a/Makefile b/Makefile
index b2644bc..eb7b6fc 100644
--- a/Makefile
+++ b/Makefile
@@ -2116,7 +2116,7 @@ builtin/prune.o builtin/reflog.o reachable.o: reachable.h
 builtin/commit.o builtin/revert.o wt-status.o: wt-status.h
 builtin/tar-tree.o archive-tar.o: tar.h
 connect.o transport.o url.o http-backend.o: url.h
-builtin/branch.o builtin/commit.o column.o help.o pager.o: column.h
+builtin/branch.o builtin/commit.o builtin/tag.o column.o help.o pager.o: column.h
 http-fetch.o http-walker.o remote-curl.o transport.o walker.o: walker.h
 http.o http-walker.o http-push.o http-fetch.o remote-curl.o: http.h url.h
 
diff --git a/builtin/tag.c b/builtin/tag.c
index 31f02e8..cecbe5c 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -15,6 +15,7 @@
 #include "diff.h"
 #include "revision.h"
 #include "gpg-interface.h"
+#include "column.h"
 
 static const char * const git_tag_usage[] = {
 	"git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]",
@@ -30,6 +31,8 @@ struct tag_filter {
 	struct commit_list *with_commit;
 };
 
+static int colopts;
+
 static int match_pattern(const char **patterns, const char *ref)
 {
 	/* no pattern means match everything */
@@ -230,6 +233,9 @@ static int git_tag_config(const char *var, const char *value, void *cb)
 	int status = git_gpg_config(var, value, cb);
 	if (status)
 		return status;
+	status = git_column_config(var, value, "tag", &colopts);
+	if (status <= 0)
+		return status;
 	return git_default_config(var, value, cb);
 }
 
@@ -409,6 +415,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
 		OPT_STRING('u', "local-user", &keyid, "key-id",
 					"use another key to sign the tag"),
 		OPT__FORCE(&force, "replace the tag if exists"),
+		OPT_COLUMN(0, "column", &colopts, "show tag list in columns" ),
 
 		OPT_GROUP("Tag listing options"),
 		{
@@ -421,6 +428,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
 	};
 
 	git_config(git_tag_config, NULL);
+	if (!colopts)
+		colopts = git_colopts;
 
 	memset(&opt, 0, sizeof(opt));
 
@@ -441,9 +450,19 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
 
 	if (list + delete + verify > 1)
 		usage_with_options(git_tag_usage, options);
-	if (list)
-		return list_tags(argv, lines == -1 ? 0 : lines,
-				 with_commit);
+	if (list) {
+		int ret;
+		if (lines == -1) {
+			struct column_options copts;
+			memset(&copts, 0, sizeof(copts));
+			copts.padding = 2;
+			run_column_filter(colopts, &copts);
+		}
+		ret = list_tags(argv, lines == -1 ? 0 : lines, with_commit);
+		if (lines == -1)
+			stop_column_filter();
+		return ret;
+	}
 	if (lines != -1)
 		die(_("-n option is only allowed with -l."));
 	if (with_commit)
-- 
1.7.8.36.g69ee2

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 02/13] column: add API to print items in columns
  2012-02-03 13:34 ` [PATCH v4 02/13] column: add API to print items in columns Nguyễn Thái Ngọc Duy
@ 2012-02-03 22:55   ` Junio C Hamano
  2012-02-03 23:16   ` Junio C Hamano
  1 sibling, 0 replies; 43+ messages in thread
From: Junio C Hamano @ 2012-02-03 22:55 UTC (permalink / raw
  To: Nguyễn Thái Ngọc Duy; +Cc: git

Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:

> +struct string_list_item *add_cell_to_list(struct string_list *list,
> +					  int mode,
> +					  const char *string)
> +{
> +	if (mode & COL_ENABLED)
> +		return string_list_append(list, string);
> +	return NULL;
> +}
> +
> +void print_cell(struct string_list *list, int mode, const char *string)
> +{
> +	if (!add_cell_to_list(list, mode, string))
> +		printf("%s\n", string);
> +}

I find these two functions showing an extremely bad taste in the code
design. "If we for some reason fail to add the string to the list, we
fallback to print it straight away" is the natural reading of this code,
but that is absolutly not the impression the author of this piece of
crap^Wcode wanted to give to its readers.

Am I being too ascestically perfectionist?

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 03/13] parseopt: make OPT_INTEGER support hexadecimal as well
  2012-02-03 13:34 ` [PATCH v4 03/13] parseopt: make OPT_INTEGER support hexadecimal as well Nguyễn Thái Ngọc Duy
@ 2012-02-03 22:59   ` Junio C Hamano
  2012-02-04  4:55     ` Nguyen Thai Ngoc Duy
  0 siblings, 1 reply; 43+ messages in thread
From: Junio C Hamano @ 2012-02-03 22:59 UTC (permalink / raw
  To: Nguyễn Thái Ngọc Duy; +Cc: git

Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:

> -		*(int *)opt->value = strtol(arg, (char **)&s, 10);
> +		if (!prefixcmp(arg, "0x") || !prefixcmp(arg, "0X"))
> +			*(int *)opt->value = strtol(arg + 2, (char **)&s, 16);
> +		else
> +			*(int *)opt->value = strtol(arg, (char **)&s, 10);

Can't you just do "strtol(arg, (char **)&s, 0)" instead?

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 08/13] column: add column.ui for default column output settings
  2012-02-03 13:34 ` [PATCH v4 08/13] column: add column.ui for default column output settings Nguyễn Thái Ngọc Duy
@ 2012-02-03 23:04   ` Junio C Hamano
  0 siblings, 0 replies; 43+ messages in thread
From: Junio C Hamano @ 2012-02-03 23:04 UTC (permalink / raw
  To: Nguyễn Thái Ngọc Duy; +Cc: git

Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:

> diff --git a/column.h b/column.h
> index 1912cb0..afdafc4 100644
> --- a/column.h
> +++ b/column.h
> @@ -17,6 +17,8 @@ struct column_options {
>  	const char *nl;
>  };
>  
> +extern int git_colopts;

For a global state variable, I'd prefer to see it spelled out, e.g.
git_column_opts or even git_column_options.  It's not like you would be
referring to this variable from everywhere---you would use it only from
fallback codepaths after parse_options() returns, or something, no?

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 09/13] help: reuse print_columns() for help -a
  2012-02-03 13:34 ` [PATCH v4 09/13] help: reuse print_columns() for help -a Nguyễn Thái Ngọc Duy
@ 2012-02-03 23:05   ` Junio C Hamano
  0 siblings, 0 replies; 43+ messages in thread
From: Junio C Hamano @ 2012-02-03 23:05 UTC (permalink / raw
  To: Nguyễn Thái Ngọc Duy; +Cc: git

Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:

> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
> ---
>  help.c |   47 +++++++++++++----------------------------------
>  1 files changed, 13 insertions(+), 34 deletions(-)

Nice.

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 10/13] branch: add --column
  2012-02-03 13:34 ` [PATCH v4 10/13] branch: add --column Nguyễn Thái Ngọc Duy
@ 2012-02-03 23:11   ` Junio C Hamano
  2012-02-04  5:01     ` Nguyen Thai Ngoc Duy
  0 siblings, 1 reply; 43+ messages in thread
From: Junio C Hamano @ 2012-02-03 23:11 UTC (permalink / raw
  To: Nguyễn Thái Ngọc Duy; +Cc: git

Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:

> @@ -474,7 +482,7 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
>  	else if (verbose)
>  		/* " f7c0c00 [ahead 58, behind 197] vcs-svn: drop obj_pool.h" */
>  		add_verbose_info(&out, item, verbose, abbrev);
> -	printf("%s\n", out.buf);
> +	print_cell(&output, colopts, out.buf);
>  	strbuf_release(&name);
>  	strbuf_release(&out);
>  }

Hmm, disabling column output when verbose is in effect without telling the
user what we are doing needs to be fixed, but because of that, at least
this codepath won't try to stuff potentially long strings in a columnar
form.

I am not sure about the utility of columnar output for "git branch" in the
short form.  You no longer can just scan the leftmost column to scan for
'*' to see the current branch.

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 02/13] column: add API to print items in columns
  2012-02-03 13:34 ` [PATCH v4 02/13] column: add API to print items in columns Nguyễn Thái Ngọc Duy
  2012-02-03 22:55   ` Junio C Hamano
@ 2012-02-03 23:16   ` Junio C Hamano
  1 sibling, 0 replies; 43+ messages in thread
From: Junio C Hamano @ 2012-02-03 23:16 UTC (permalink / raw
  To: Nguyễn Thái Ngọc Duy; +Cc: git

Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:

> +#define MODE(mode) ((mode) & COL_MODE)
> + ...
> +void print_columns(const struct string_list *list, int mode,
> +		   struct column_options *opts)
> +{
> +	const char *indent = "", *nl = "\n";
> +	int padding = 1, width = term_columns();
> +
> +	if (!list->nr)
> +		return;
> +	if (opts) {
> +		if (opts->indent)
> +			indent = opts->indent;
> +		if (opts->nl)
> +			nl = opts->nl;
> +		if (opts->width)
> +			width = opts->width;
> +		padding = opts->padding;
> +	}
> +	if (width <= 1 || !(mode & COL_ENABLED)) {

Unless there is a compelling reason not to, make a flag word used as
collection of bitfields an unsigned, i.e. not "int mode".

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 11/13] status: add --column
  2012-02-03 13:34 ` [PATCH v4 11/13] status: " Nguyễn Thái Ngọc Duy
@ 2012-02-03 23:19   ` Junio C Hamano
  0 siblings, 0 replies; 43+ messages in thread
From: Junio C Hamano @ 2012-02-03 23:19 UTC (permalink / raw
  To: Nguyễn Thái Ngọc Duy; +Cc: git

Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:

> @@ -1251,7 +1260,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
>  	case STATUS_FORMAT_LONG:
>  		s.verbose = verbose;
>  		s.ignore_submodule_arg = ignore_submodule_arg;
> -		wt_status_print(&s);
> +		wt_status_print(&s, colopts);
>  		break;
>  	}

Do you really need to pass colopts around as a separate parameter all the
way through the callchain?

Why isn't it a new member of wt_status that sits next to existing
use_color, verbose, etc. that define _how_ the status is shown?

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 13/13] tag: add --column
  2012-02-03 13:34 ` [PATCH v4 13/13] tag: add --column Nguyễn Thái Ngọc Duy
@ 2012-02-03 23:30   ` Junio C Hamano
  0 siblings, 0 replies; 43+ messages in thread
From: Junio C Hamano @ 2012-02-03 23:30 UTC (permalink / raw
  To: Nguyễn Thái Ngọc Duy; +Cc: git

Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:

> @@ -421,6 +428,8 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
>  	};
>  
>  	git_config(git_tag_config, NULL);
> +	if (!colopts)
> +		colopts = git_colopts;
>  
>  	memset(&opt, 0, sizeof(opt));
>  
> @@ -441,9 +450,19 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
>  
>  	if (list + delete + verify > 1)
>  		usage_with_options(git_tag_usage, options);
> -	if (list)
> -		return list_tags(argv, lines == -1 ? 0 : lines,
> -				 with_commit);
> +	if (list) {
> +		int ret;
> +		if (lines == -1) {
> +			struct column_options copts;
> +			memset(&copts, 0, sizeof(copts));
> +			copts.padding = 2;
> +			run_column_filter(colopts, &copts);
> +		}
> +		ret = list_tags(argv, lines == -1 ? 0 : lines, with_commit);
> +		if (lines == -1)
> +			stop_column_filter();
> +		return ret;
> +	}
>  	if (lines != -1)
>  		die(_("-n option is only allowed with -l."));
>  	if (with_commit)

The patch is surprisingly small, which is a good sign.  The same comment
to the silent suppression "branch -v --column" applies here to "tag -n".

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 03/13] parseopt: make OPT_INTEGER support hexadecimal as well
  2012-02-03 22:59   ` Junio C Hamano
@ 2012-02-04  4:55     ` Nguyen Thai Ngoc Duy
  2012-02-04  5:32       ` Junio C Hamano
  0 siblings, 1 reply; 43+ messages in thread
From: Nguyen Thai Ngoc Duy @ 2012-02-04  4:55 UTC (permalink / raw
  To: Junio C Hamano; +Cc: git

2012/2/4 Junio C Hamano <gitster@pobox.com>:
> Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:
>
>> -             *(int *)opt->value = strtol(arg, (char **)&s, 10);
>> +             if (!prefixcmp(arg, "0x") || !prefixcmp(arg, "0X"))
>> +                     *(int *)opt->value = strtol(arg + 2, (char **)&s, 16);
>> +             else
>> +                     *(int *)opt->value = strtol(arg, (char **)&s, 10);
>
> Can't you just do "strtol(arg, (char **)&s, 0)" instead?

I could but that means "01234" is now in base 8 and that's currently
accepted as base 10. 0x1234 does not have this problem because current
git rejects it.
-- 
Duy

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 10/13] branch: add --column
  2012-02-03 23:11   ` Junio C Hamano
@ 2012-02-04  5:01     ` Nguyen Thai Ngoc Duy
  0 siblings, 0 replies; 43+ messages in thread
From: Nguyen Thai Ngoc Duy @ 2012-02-04  5:01 UTC (permalink / raw
  To: Junio C Hamano; +Cc: git

2012/2/4 Junio C Hamano <gitster@pobox.com>:
> I am not sure about the utility of columnar output for "git branch" in the
> short form.  You no longer can just scan the leftmost column to scan for
> '*' to see the current branch.

I rely on color for that. Without color you may need to scan more
columns for '*'. Though I would really like to see "git branch
--current" added to show just current branch if I'm on colorless
terminal.
-- 
Duy

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 03/13] parseopt: make OPT_INTEGER support hexadecimal as well
  2012-02-04  4:55     ` Nguyen Thai Ngoc Duy
@ 2012-02-04  5:32       ` Junio C Hamano
  2012-02-04  6:15         ` Nguyen Thai Ngoc Duy
  0 siblings, 1 reply; 43+ messages in thread
From: Junio C Hamano @ 2012-02-04  5:32 UTC (permalink / raw
  To: Nguyen Thai Ngoc Duy; +Cc: git

Nguyen Thai Ngoc Duy <pclouds@gmail.com> writes:

> 2012/2/4 Junio C Hamano <gitster@pobox.com>:
>> Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:
>>
>>> -             *(int *)opt->value = strtol(arg, (char **)&s, 10);
>>> +             if (!prefixcmp(arg, "0x") || !prefixcmp(arg, "0X"))
>>> +                     *(int *)opt->value = strtol(arg + 2, (char **)&s, 16);
>>> +             else
>>> +                     *(int *)opt->value = strtol(arg, (char **)&s, 10);
>>
>> Can't you just do "strtol(arg, (char **)&s, 0)" instead?
>
> I could but that means "01234" is now in base 8 and that's currently
> accepted as base 10.

Yes, but I wonder if that is a problem in practice. Who in the right mind
would give 00001000 to tell git that they want one thousand?

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v4 03/13] parseopt: make OPT_INTEGER support hexadecimal as well
  2012-02-04  5:32       ` Junio C Hamano
@ 2012-02-04  6:15         ` Nguyen Thai Ngoc Duy
  0 siblings, 0 replies; 43+ messages in thread
From: Nguyen Thai Ngoc Duy @ 2012-02-04  6:15 UTC (permalink / raw
  To: Junio C Hamano; +Cc: git

On Sat, Feb 4, 2012 at 12:32 PM, Junio C Hamano <gitster@pobox.com> wrote:
> Nguyen Thai Ngoc Duy <pclouds@gmail.com> writes:
>
>> 2012/2/4 Junio C Hamano <gitster@pobox.com>:
>>> Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:
>>>
>>>> -             *(int *)opt->value = strtol(arg, (char **)&s, 10);
>>>> +             if (!prefixcmp(arg, "0x") || !prefixcmp(arg, "0X"))
>>>> +                     *(int *)opt->value = strtol(arg + 2, (char **)&s, 16);
>>>> +             else
>>>> +                     *(int *)opt->value = strtol(arg, (char **)&s, 10);
>>>
>>> Can't you just do "strtol(arg, (char **)&s, 0)" instead?
>>
>> I could but that means "01234" is now in base 8 and that's currently
>> accepted as base 10.
>
> Yes, but I wonder if that is a problem in practice. Who in the right mind
> would give 00001000 to tell git that they want one thousand?

That could come from a script, extracting info from a source (maybe a
log file) and not stripping leading zeros. If we go this route, I
think we should have one release that rejects such numbers first. If
nobody complains, then we proceed and allow octal in the next release.
-- 
Duy

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH v5 00/12] Column display
  2012-02-03 13:34 [PATCH v4 00/13] Column display again Nguyễn Thái Ngọc Duy
                   ` (12 preceding siblings ...)
  2012-02-03 13:34 ` [PATCH v4 13/13] tag: add --column Nguyễn Thái Ngọc Duy
@ 2012-02-04 15:59 ` Nguyễn Thái Ngọc Duy
  2012-02-04 15:59   ` [PATCH v5 01/12] Save terminal width before setting up pager Nguyễn Thái Ngọc Duy
                     ` (12 more replies)
  13 siblings, 13 replies; 43+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2012-02-04 15:59 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

- Turn column bitflag type to unsigned int
- Get rid of global var git_colopts
- Get rid of ill-designed print_cell()
- Refuse to run "git branch -v --column" and "git tag -l -n --column"
- Fix "git status --column --no-color" always prints ANSI reset sequence
- Drop OPT_INTEGER hexadecimal support (it's not essential, the column
  helper functions can pass arguments are decimal)
- Add some more tests for column display

Nguyễn Thái Ngọc Duy (12):
  Save terminal width before setting up pager
  column: add API to print items in columns
  Add git-column and column mode parsing
  Stop starting pager recursively
  column: add columnar layout
  column: support columns with different widths
  column: add column.ui for default column output settings
  help: reuse print_columns() for help -a
  branch: add --column
  status: add --column
  column: support piping stdout to external git-column process
  tag: add --column

 .gitignore                   |    1 +
 Documentation/config.txt     |   38 ++++
 Documentation/git-branch.txt |    9 +
 Documentation/git-column.txt |   53 +++++
 Documentation/git-status.txt |    7 +
 Documentation/git-tag.txt    |   11 +-
 Makefile                     |    3 +
 builtin.h                    |    1 +
 builtin/branch.c             |   38 +++-
 builtin/column.c             |   62 ++++++
 builtin/commit.c             |    8 +
 builtin/tag.c                |   30 +++-
 column.c                     |  480 ++++++++++++++++++++++++++++++++++++++++++
 column.h                     |   36 +++
 command-list.txt             |    1 +
 git.c                        |    1 +
 help.c                       |   70 ++-----
 pager.c                      |   37 +++-
 parse-options.h              |    2 +
 t/t3200-branch.sh            |   50 +++++
 t/t7004-tag.sh               |   44 ++++
 t/t7508-status.sh            |   24 ++
 t/t9002-column.sh            |  135 ++++++++++++
 wt-status.c                  |   28 +++-
 wt-status.h                  |    1 +
 25 files changed, 1104 insertions(+), 66 deletions(-)
 create mode 100644 Documentation/git-column.txt
 create mode 100644 builtin/column.c
 create mode 100644 column.c
 create mode 100644 column.h
 create mode 100755 t/t9002-column.sh

-- 
1.7.8.36.g69ee2

^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH v5 01/12] Save terminal width before setting up pager
  2012-02-04 15:59 ` [PATCH v5 00/12] Column display Nguyễn Thái Ngọc Duy
@ 2012-02-04 15:59   ` Nguyễn Thái Ngọc Duy
  2012-02-04 15:59   ` [PATCH v5 02/12] column: add API to print items in columns Nguyễn Thái Ngọc Duy
                     ` (11 subsequent siblings)
  12 siblings, 0 replies; 43+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2012-02-04 15:59 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

term_columns() checks for terminal width via ioctl(2). After
redirecting, stdin is no longer terminal to get terminal width.

Check terminal width and save it before redirect stdin in
setup_pager() and let term_columns() reuse the value.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Makefile |    1 +
 column.h |    6 ++++++
 help.c   |   23 +----------------------
 pager.c  |   35 +++++++++++++++++++++++++++++++++++
 4 files changed, 43 insertions(+), 22 deletions(-)
 create mode 100644 column.h

diff --git a/Makefile b/Makefile
index c457c34..cbbc699 100644
--- a/Makefile
+++ b/Makefile
@@ -2114,6 +2114,7 @@ builtin/prune.o builtin/reflog.o reachable.o: reachable.h
 builtin/commit.o builtin/revert.o wt-status.o: wt-status.h
 builtin/tar-tree.o archive-tar.o: tar.h
 connect.o transport.o url.o http-backend.o: url.h
+help.o pager.o: column.h
 http-fetch.o http-walker.o remote-curl.o transport.o walker.o: walker.h
 http.o http-walker.o http-push.o http-fetch.o remote-curl.o: http.h url.h
 
diff --git a/column.h b/column.h
new file mode 100644
index 0000000..55d8067
--- /dev/null
+++ b/column.h
@@ -0,0 +1,6 @@
+#ifndef COLUMN_H
+#define COLUMN_H
+
+extern int term_columns(void);
+
+#endif
diff --git a/help.c b/help.c
index cbbe966..672561b 100644
--- a/help.c
+++ b/help.c
@@ -4,28 +4,7 @@
 #include "levenshtein.h"
 #include "help.h"
 #include "common-cmds.h"
-
-/* most GUI terminals set COLUMNS (although some don't export it) */
-static int term_columns(void)
-{
-	char *col_string = getenv("COLUMNS");
-	int n_cols;
-
-	if (col_string && (n_cols = atoi(col_string)) > 0)
-		return n_cols;
-
-#ifdef TIOCGWINSZ
-	{
-		struct winsize ws;
-		if (!ioctl(1, TIOCGWINSZ, &ws)) {
-			if (ws.ws_col)
-				return ws.ws_col;
-		}
-	}
-#endif
-
-	return 80;
-}
+#include "column.h"
 
 void add_cmdname(struct cmdnames *cmds, const char *name, int len)
 {
diff --git a/pager.c b/pager.c
index 975955b..772a5a6 100644
--- a/pager.c
+++ b/pager.c
@@ -6,6 +6,21 @@
 #define DEFAULT_PAGER "less"
 #endif
 
+static int spawned_pager;
+static int max_columns;
+
+static int retrieve_terminal_width(void)
+{
+#ifdef TIOCGWINSZ
+	struct winsize ws;
+	if (ioctl(1, TIOCGWINSZ, &ws))  /* e.g., ENOSYS */
+		return 0;
+	return ws.ws_col;
+#else
+	return 0;
+#endif
+}
+
 /*
  * This is split up from the rest of git so that we can do
  * something different on Windows.
@@ -72,12 +87,17 @@ const char *git_pager(int stdout_is_tty)
 void setup_pager(void)
 {
 	const char *pager = git_pager(isatty(1));
+	int width;
 
 	if (!pager)
 		return;
 
 	setenv("GIT_PAGER_IN_USE", "true", 1);
 
+	width = retrieve_terminal_width();
+	if (width)
+		max_columns = width;
+
 	/* spawn the pager */
 	pager_argv[0] = pager;
 	pager_process.use_shell = 1;
@@ -110,3 +130,18 @@ int pager_in_use(void)
 	env = getenv("GIT_PAGER_IN_USE");
 	return env ? git_config_bool("GIT_PAGER_IN_USE", env) : 0;
 }
+
+int term_columns()
+{
+	char *col_string = getenv("COLUMNS");
+	int n_cols;
+
+	if (col_string && (n_cols = atoi(col_string)) > 0)
+		return n_cols;
+
+	if (spawned_pager && max_columns)
+		return max_columns;
+
+	n_cols = retrieve_terminal_width();
+	return n_cols ? n_cols : 80;
+}
-- 
1.7.8.36.g69ee2

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH v5 02/12] column: add API to print items in columns
  2012-02-04 15:59 ` [PATCH v5 00/12] Column display Nguyễn Thái Ngọc Duy
  2012-02-04 15:59   ` [PATCH v5 01/12] Save terminal width before setting up pager Nguyễn Thái Ngọc Duy
@ 2012-02-04 15:59   ` Nguyễn Thái Ngọc Duy
  2012-02-04 15:59   ` [PATCH v5 03/12] Add git-column and column mode parsing Nguyễn Thái Ngọc Duy
                     ` (10 subsequent siblings)
  12 siblings, 0 replies; 43+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2012-02-04 15:59 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

Simple code that print line-by-line and wants to columnize can do
this:

struct string_list list;
string_list_append(&list, ...);
string_list_append(&list, ...);
...
print_columns(&list, ...);

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Makefile |    3 ++-
 column.c |   39 +++++++++++++++++++++++++++++++++++++++
 column.h |   13 +++++++++++++
 3 files changed, 54 insertions(+), 1 deletions(-)
 create mode 100644 column.c

diff --git a/Makefile b/Makefile
index cbbc699..5f0531b 100644
--- a/Makefile
+++ b/Makefile
@@ -637,6 +637,7 @@ LIB_OBJS += bulk-checkin.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 += compat/obstack.o
@@ -2114,7 +2115,7 @@ builtin/prune.o builtin/reflog.o reachable.o: reachable.h
 builtin/commit.o builtin/revert.o wt-status.o: wt-status.h
 builtin/tar-tree.o archive-tar.o: tar.h
 connect.o transport.o url.o http-backend.o: url.h
-help.o pager.o: column.h
+column.o help.o pager.o: column.h
 http-fetch.o http-walker.o remote-curl.o transport.o walker.o: walker.h
 http.o http-walker.o http-push.o http-fetch.o remote-curl.o: http.h url.h
 
diff --git a/column.c b/column.c
new file mode 100644
index 0000000..742ae18
--- /dev/null
+++ b/column.c
@@ -0,0 +1,39 @@
+#include "cache.h"
+#include "column.h"
+#include "string-list.h"
+
+#define MODE(mode) ((mode) & COL_MODE)
+
+/* Display without layout when COL_ENABLED is not set */
+static void display_plain(const struct string_list *list,
+			  const char *indent, const char *nl)
+{
+	int i;
+
+	for (i = 0; i < list->nr; i++)
+		printf("%s%s%s", indent, list->items[i].string, nl);
+}
+
+void print_columns(const struct string_list *list, unsigned int mode,
+		   struct column_options *opts)
+{
+	const char *indent = "", *nl = "\n";
+	int padding = 1, width = term_columns();
+
+	if (!list->nr)
+		return;
+	if (opts) {
+		if (opts->indent)
+			indent = opts->indent;
+		if (opts->nl)
+			nl = opts->nl;
+		if (opts->width)
+			width = opts->width;
+		padding = opts->padding;
+	}
+	if (width <= 1 || !(mode & COL_ENABLED)) {
+		display_plain(list, indent, nl);
+		return;
+	}
+	die("BUG: invalid mode %d", MODE(mode));
+}
diff --git a/column.h b/column.h
index 55d8067..8e4fdaa 100644
--- a/column.h
+++ b/column.h
@@ -1,6 +1,19 @@
 #ifndef COLUMN_H
 #define COLUMN_H
 
+#define COL_MODE          0x000F
+#define COL_ENABLED      (1 << 4)
+
+struct column_options {
+	int width;
+	int padding;
+	const char *indent;
+	const char *nl;
+};
+
 extern int term_columns(void);
+extern void print_columns(const struct string_list *list,
+			  unsigned int mode,
+			  struct column_options *opts);
 
 #endif
-- 
1.7.8.36.g69ee2

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH v5 03/12] Add git-column and column mode parsing
  2012-02-04 15:59 ` [PATCH v5 00/12] Column display Nguyễn Thái Ngọc Duy
  2012-02-04 15:59   ` [PATCH v5 01/12] Save terminal width before setting up pager Nguyễn Thái Ngọc Duy
  2012-02-04 15:59   ` [PATCH v5 02/12] column: add API to print items in columns Nguyễn Thái Ngọc Duy
@ 2012-02-04 15:59   ` Nguyễn Thái Ngọc Duy
  2012-02-04 16:11     ` [PATCH v6 " Nguyễn Thái Ngọc Duy
  2012-02-04 15:59   ` [PATCH v5 04/12] Stop starting pager recursively Nguyễn Thái Ngọc Duy
                     ` (9 subsequent siblings)
  12 siblings, 1 reply; 43+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2012-02-04 15:59 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

A column option string consists of many token separated by either
space of commas. A token belongs to one of three groups:

 - enabling: always, never and auto
 - layout mode: to be implemented
 - other tuning, which could be negated be prefix 'no'

A command line option without argument (e.g. --column) will enable
column output and reuse existing settings (layout mode and options..).
--no-column disables columnar output.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 .gitignore                   |    1 +
 Documentation/git-column.txt |   49 ++++++++++++++++
 Makefile                     |    1 +
 builtin.h                    |    1 +
 builtin/column.c             |   41 ++++++++++++++
 column.c                     |  125 ++++++++++++++++++++++++++++++++++++++++++
 column.h                     |    7 ++
 command-list.txt             |    1 +
 git.c                        |    1 +
 parse-options.h              |    2 +
 t/t9002-column.sh            |   27 +++++++++
 11 files changed, 256 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/.gitignore b/.gitignore
index 3b7680e..039e5ef 100644
--- a/.gitignore
+++ b/.gitignore
@@ -26,6 +26,7 @@
 /git-cherry-pick
 /git-clean
 /git-clone
+/git-column
 /git-commit
 /git-commit-tree
 /git-config
diff --git a/Documentation/git-column.txt b/Documentation/git-column.txt
new file mode 100644
index 0000000..508b85f
--- /dev/null
+++ b/Documentation/git-column.txt
@@ -0,0 +1,49 @@
+git-column(1)
+=============
+
+NAME
+----
+git-column - Display data in columns
+
+SYNOPSIS
+--------
+[verse]
+'git column' [--mode=<mode> | --rawmode=<n>] [--width=<width>]
+	     [--indent=<string>] [--nl=<string>] [--pading=<n>]
+
+DESCRIPTION
+-----------
+This command formats its input into multiple columns.
+
+OPTIONS
+-------
+--mode=<mode>::
+	Specify layout mode. See configuration variable column.ui for option
+	syntax.
+
+--rawmode=<n>::
+	Same as --mode but take mode encoded as a number. This is mainly used
+	by other commands that have already parsed layout mode.
+
+--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.
+
+--indent=<string>::
+	String to be printed at the beginning of each line.
+
+--nl=<N>::
+	String to be printed at the end of each line,
+	including newline character.
+
+--padding=<N>::
+	The number of spaces between columns. One space by default.
+
+
+Author
+------
+Written by Nguyen Thai Ngoc Duy <pclouds@gmail.com>
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Makefile b/Makefile
index 5f0531b..92700ca 100644
--- a/Makefile
+++ b/Makefile
@@ -766,6 +766,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 857b9c8..338f540 100644
--- a/builtin.h
+++ b/builtin.h
@@ -61,6 +61,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_config(int argc, const char **argv, const char *prefix);
diff --git a/builtin/column.c b/builtin/column.c
new file mode 100644
index 0000000..c4a0431
--- /dev/null
+++ b/builtin/column.c
@@ -0,0 +1,41 @@
+#include "builtin.h"
+#include "cache.h"
+#include "strbuf.h"
+#include "parse-options.h"
+#include "string-list.h"
+#include "column.h"
+
+static const char * const builtin_column_usage[] = {
+	"git column [options]",
+	NULL
+};
+static int colopts;
+
+int cmd_column(int argc, const char **argv, const char *prefix)
+{
+	struct string_list list = STRING_LIST_INIT_DUP;
+	struct strbuf sb = STRBUF_INIT;
+	struct column_options copts;
+	struct option options[] = {
+		OPT_COLUMN(0, "mode", &colopts, "layout to use"),
+		OPT_INTEGER(0, "rawmode", &colopts, "layout to use"),
+		OPT_INTEGER(0, "width", &copts.width, "Maximum width"),
+		OPT_STRING(0, "indent", &copts.indent, "string", "Padding space on left border"),
+		OPT_INTEGER(0, "nl", &copts.nl, "Padding space on right border"),
+		OPT_INTEGER(0, "padding", &copts.padding, "Padding space between columns"),
+		OPT_END()
+	};
+
+	memset(&copts, 0, sizeof(copts));
+	copts.width = term_columns();
+	copts.padding = 1;
+	argc = parse_options(argc, argv, "", options, builtin_column_usage, 0);
+	if (argc)
+		usage_with_options(builtin_column_usage, options);
+
+	while (!strbuf_getline(&sb, stdin, '\n'))
+		string_list_append(&list, sb.buf);
+
+	print_columns(&list, colopts, &copts);
+	return 0;
+}
diff --git a/column.c b/column.c
index 742ae18..d20cf8f 100644
--- a/column.c
+++ b/column.c
@@ -1,6 +1,7 @@
 #include "cache.h"
 #include "column.h"
 #include "string-list.h"
+#include "parse-options.h"
 
 #define MODE(mode) ((mode) & COL_MODE)
 
@@ -37,3 +38,127 @@ void print_columns(const struct string_list *list, unsigned int mode,
 	}
 	die("BUG: invalid mode %d", MODE(mode));
 }
+
+struct colopt {
+	enum {
+		ENABLE,
+		MODE,
+		OPTION
+	} type;
+	const char *name;
+	int value;
+};
+
+/*
+ * Set COL_ENABLED and COL_ENABLED_SET. If 'set' is -1, check if
+ * stdout is tty.
+ */
+static int set_enable_bit(unsigned int *mode, int set, int stdout_is_tty)
+{
+	if (set < 0) {	/* auto */
+		if (stdout_is_tty < 0)
+			stdout_is_tty = isatty(1);
+		set = stdout_is_tty || (pager_in_use() && pager_use_color);
+	}
+	if (set)
+		*mode = *mode | COL_ENABLED | COL_ENABLED_SET;
+	else
+		*mode = (*mode & ~COL_ENABLED) | COL_ENABLED_SET;
+	return 0;
+}
+
+/*
+ * Set COL_MODE_*. mode is intially copied from column.ui. If
+ * COL_ENABLED_SET is not set, then neither 'always', 'never' nor
+ * 'auto' has been used. Default to 'always'.
+ */
+static int set_mode(unsigned int *mode, unsigned int value)
+{
+	*mode = (*mode & ~COL_MODE) | value;
+	if (!(*mode & COL_ENABLED_SET))
+		*mode |= COL_ENABLED | COL_ENABLED_SET;
+
+	return 0;
+}
+
+/* Set or unset other COL_* */
+static int set_option(unsigned int *mode, unsigned int opt, int set)
+{
+	if (set)
+		*mode |= opt;
+	else
+		*mode &= ~opt;
+	return 0;
+}
+
+static int parse_option(const char *arg, int len,
+			unsigned int *mode, int stdout_is_tty)
+{
+	struct colopt opts[] = {
+		{ ENABLE, "always",  1 },
+		{ ENABLE, "never",   0 },
+		{ ENABLE, "auto",   -1 },
+	};
+	int i, set, name_len;
+
+	for (i = 0; i < ARRAY_SIZE(opts); i++) {
+		if (opts[i].type == OPTION) {
+			if (len > 2 && !strncmp(arg, "no", 2)) {
+				arg += 2;
+				len -= 2;
+				set = 0;
+			}
+			else
+				set = 1;
+		}
+
+		name_len = strlen(opts[i].name);
+		if (len != name_len ||
+		    strncmp(arg, opts[i].name, name_len))
+			continue;
+
+		switch (opts[i].type) {
+		case ENABLE: return set_enable_bit(mode, opts[i].value,
+						   stdout_is_tty);
+		case MODE: return set_mode(mode, opts[i].value);
+		case OPTION: return set_option(mode, opts[i].value, set);
+		default: die("BUG: Unknown option type %d", opts[i].type);
+		}
+	}
+
+	return error("unsupported style '%s'", arg);
+}
+
+int git_config_column(unsigned int *mode, const char *value,
+		      int stdout_is_tty)
+{
+	const char *sep = " ,";
+
+	while (*value) {
+		int len = strcspn(value, sep);
+		if (len) {
+			if (parse_option(value, len, mode, stdout_is_tty))
+				return -1;
+
+			value += len;
+		}
+		value += strspn(value, sep);
+	}
+	return 0;
+}
+
+int parseopt_column_callback(const struct option *opt,
+			     const char *arg, int unset)
+{
+	unsigned int *mode = opt->value;
+	if (unset) {
+		*mode = (*mode & ~COL_ENABLED) | COL_ENABLED_SET;
+		return 0;
+	}
+	if (arg)
+		return git_config_column(mode, arg, -1);
+
+	/* no arg, turn it on */
+	*mode |= COL_ENABLED | COL_ENABLED_SET;
+	return 0;
+}
diff --git a/column.h b/column.h
index 8e4fdaa..f48fa81 100644
--- a/column.h
+++ b/column.h
@@ -3,6 +3,7 @@
 
 #define COL_MODE          0x000F
 #define COL_ENABLED      (1 << 4)
+#define COL_ENABLED_SET  (1 << 5)  /* Has COL_ENABLED been set by config? */
 
 struct column_options {
 	int width;
@@ -15,5 +16,11 @@ extern int term_columns(void);
 extern void print_columns(const struct string_list *list,
 			  unsigned int mode,
 			  struct column_options *opts);
+extern int git_config_column(unsigned int *mode, const char *value,
+			     int stdout_is_tty);
+
+struct option;
+extern int parseopt_column_callback(const struct option *opt,
+				    const char *arg, int unset);
 
 #endif
diff --git a/command-list.txt b/command-list.txt
index a36ee9b..fe06f15 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
diff --git a/git.c b/git.c
index 3805616..419e3cc 100644
--- a/git.c
+++ b/git.c
@@ -348,6 +348,7 @@ static void handle_internal_command(int argc, const char **argv)
 		{ "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE },
 		{ "clean", cmd_clean, RUN_SETUP | NEED_WORK_TREE },
 		{ "clone", cmd_clone },
+		{ "column", cmd_column },
 		{ "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE },
 		{ "commit-tree", cmd_commit_tree, RUN_SETUP },
 		{ "config", cmd_config, RUN_SETUP_GENTLY },
diff --git a/parse-options.h b/parse-options.h
index 2e811dc..56fcafd 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -238,5 +238,7 @@ extern int parse_opt_noop_cb(const struct option *, const char *, int);
 	  PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }
 #define OPT__COLOR(var, h) \
 	OPT_COLOR_FLAG(0, "color", (var), (h))
+#define OPT_COLUMN(s, l, v, h) \
+	{ OPTION_CALLBACK, (s), (l), (v), "style", (h), PARSE_OPT_OPTARG, parseopt_column_callback }
 
 #endif
diff --git a/t/t9002-column.sh b/t/t9002-column.sh
new file mode 100755
index 0000000..b0b6d62
--- /dev/null
+++ b/t/t9002-column.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+test_description='git column'
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+	cat >lista <<\EOF
+one
+two
+three
+four
+five
+six
+seven
+eight
+nine
+ten
+eleven
+EOF
+'
+
+test_expect_success 'never' '
+	git column --mode=never <lista >actual &&
+	test_cmp lista actual
+'
+
+test_done
-- 
1.7.8.36.g69ee2

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH v5 04/12] Stop starting pager recursively
  2012-02-04 15:59 ` [PATCH v5 00/12] Column display Nguyễn Thái Ngọc Duy
                     ` (2 preceding siblings ...)
  2012-02-04 15:59   ` [PATCH v5 03/12] Add git-column and column mode parsing Nguyễn Thái Ngọc Duy
@ 2012-02-04 15:59   ` Nguyễn Thái Ngọc Duy
  2012-02-04 15:59   ` [PATCH v5 05/12] column: add columnar layout Nguyễn Thái Ngọc Duy
                     ` (8 subsequent siblings)
  12 siblings, 0 replies; 43+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2012-02-04 15:59 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

git-column can be used as a pager for other git commands, something
like this:

    GIT_PAGER="git -p column --mode='dense color'" git -p branch

The problem with this is that "git -p column" also has $GIT_PAGER
set so the pager runs itself again as a pager, then again and again.

Stop this.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 pager.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/pager.c b/pager.c
index 772a5a6..e4353dc 100644
--- a/pager.c
+++ b/pager.c
@@ -89,7 +89,7 @@ void setup_pager(void)
 	const char *pager = git_pager(isatty(1));
 	int width;
 
-	if (!pager)
+	if (!pager || pager_in_use())
 		return;
 
 	setenv("GIT_PAGER_IN_USE", "true", 1);
-- 
1.7.8.36.g69ee2

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH v5 05/12] column: add columnar layout
  2012-02-04 15:59 ` [PATCH v5 00/12] Column display Nguyễn Thái Ngọc Duy
                     ` (3 preceding siblings ...)
  2012-02-04 15:59   ` [PATCH v5 04/12] Stop starting pager recursively Nguyễn Thái Ngọc Duy
@ 2012-02-04 15:59   ` Nguyễn Thái Ngọc Duy
  2012-02-04 15:59   ` [PATCH v5 06/12] column: support columns with different widths Nguyễn Thái Ngọc Duy
                     ` (7 subsequent siblings)
  12 siblings, 0 replies; 43+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2012-02-04 15:59 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

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 to be in UTF-8. If strings contain ANSI escape
strings, COL_ANSI must be specified for correct length calculation.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 column.c          |  131 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 column.h          |    3 +
 t/t9002-column.sh |   86 +++++++++++++++++++++++++++++++++++
 3 files changed, 219 insertions(+), 1 deletions(-)

diff --git a/column.c b/column.c
index d20cf8f..be4e07c 100644
--- a/column.c
+++ b/column.c
@@ -2,8 +2,66 @@
 #include "column.h"
 #include "string-list.h"
 #include "parse-options.h"
+#include "utf8.h"
 
 #define MODE(mode) ((mode) & COL_MODE)
+#define XY2LINEAR(d,x,y) (MODE((d)->mode) == COL_MODE_COLUMN ? \
+			  (x) * (d)->rows + (y) : \
+			  (y) * (d)->cols + (x))
+
+struct column_data {
+	const struct string_list *list; /* list of all cells */
+	int mode;			/* COL_MODE */
+	int total_width;		/* terminal width */
+	int padding;			/* cell padding */
+	const char *indent;		/* left most column indentation */
+	const char *nl;
+
+	int rows, cols;
+	int *len;			/* cell length */
+};
+
+/* return length of 's' in letters, ANSI escapes stripped */
+static int item_length(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(struct column_data *data, int *width)
+{
+	int i;
+
+	*width = 0;
+	for (i = 0; i < data->list->nr; i++)
+		if (*width < data->len[i])
+			*width = data->len[i];
+
+	*width += data->padding;
+
+	data->cols = (data->total_width - strlen(data->indent)) / *width;
+	if (data->cols == 0)
+		data->cols = 1;
+
+	data->rows = DIV_ROUND_UP(data->list->nr, data->cols);
+}
 
 /* Display without layout when COL_ENABLED is not set */
 static void display_plain(const struct string_list *list,
@@ -15,6 +73,65 @@ static void display_plain(const struct string_list *list,
 		printf("%s%s%s", indent, list->items[i].string, nl);
 }
 
+/* Print a cell to stdout with all necessary leading/traling space */
+static int display_cell(struct column_data *data, int initial_width,
+			const char *empty_cell, int x, int y)
+{
+	int i, len, newline;
+
+	i = XY2LINEAR(data, x, y);
+	if (i >= data->list->nr)
+		return -1;
+	len = data->len[i];
+	if (MODE(data->mode) == COL_MODE_COLUMN)
+		newline = i + data->rows >= data->list->nr;
+	else
+		newline = x == data->cols - 1 || i == data->list->nr - 1;
+
+	printf("%s%s%s",
+			x == 0 ? data->indent : "",
+			data->list->items[i].string,
+			newline ? data->nl : 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,
+			  const char *nl)
+{
+	struct column_data data;
+	int x, y, i, initial_width;
+	char *empty_cell;
+
+	memset(&data, 0, sizeof(data));
+	data.list = list;
+	data.mode = mode;
+	data.total_width = total_width;
+	data.padding = padding;
+	data.indent = indent;
+	data.nl = nl;
+
+	data.len = xmalloc(sizeof(*data.len) * list->nr);
+	for (i = 0; i < list->nr; i++)
+		data.len[i] = item_length(mode, list->items[i].string);
+
+	layout(&data, &initial_width);
+
+	empty_cell = xmalloc(initial_width + 1);
+	memset(empty_cell, ' ', initial_width);
+	empty_cell[initial_width] = '\0';
+	for (y = 0; y < data.rows; y++) {
+		for (x = 0; x < data.cols; x++)
+			if (display_cell(&data, initial_width, empty_cell, x, y))
+				break;
+	}
+
+	free(data.len);
+	free(empty_cell);
+}
+
 void print_columns(const struct string_list *list, unsigned int mode,
 		   struct column_options *opts)
 {
@@ -36,7 +153,16 @@ void print_columns(const struct string_list *list, unsigned int mode,
 		display_plain(list, indent, nl);
 		return;
 	}
-	die("BUG: invalid mode %d", MODE(mode));
+
+	switch (MODE(mode)) {
+	case COL_MODE_ROW:
+	case COL_MODE_COLUMN:
+		display_table(list, mode, width, padding, indent, nl);
+		break;
+
+	default:
+		die("BUG: invalid mode %d", MODE(mode));
+	}
 }
 
 struct colopt {
@@ -98,6 +224,9 @@ static int parse_option(const char *arg, int len,
 		{ ENABLE, "always",  1 },
 		{ ENABLE, "never",   0 },
 		{ ENABLE, "auto",   -1 },
+		{ MODE,   "column", COL_MODE_COLUMN },
+		{ MODE,   "row",    COL_MODE_ROW },
+		{ OPTION, "color",  COL_ANSI },
 	};
 	int i, set, name_len;
 
diff --git a/column.h b/column.h
index f48fa81..52181d4 100644
--- a/column.h
+++ b/column.h
@@ -2,8 +2,11 @@
 #define COLUMN_H
 
 #define COL_MODE          0x000F
+#define COL_MODE_COLUMN        0   /* Fill columns before rows */
+#define COL_MODE_ROW           1   /* Fill rows before columns */
 #define COL_ENABLED      (1 << 4)
 #define COL_ENABLED_SET  (1 << 5)  /* Has COL_ENABLED been set by config? */
+#define COL_ANSI         (1 << 6)  /* Remove ANSI escapes from string length */
 
 struct column_options {
 	int width;
diff --git a/t/t9002-column.sh b/t/t9002-column.sh
index b0b6d62..cffb029 100755
--- a/t/t9002-column.sh
+++ b/t/t9002-column.sh
@@ -24,4 +24,90 @@ test_expect_success 'never' '
 	test_cmp lista actual
 '
 
+test_expect_success '80 columns' '
+	cat >expected <<\EOF &&
+one    two    three  four   five   six    seven  eight  nine   ten    eleven
+EOF
+	COLUMNS=80 git column --mode=column <lista >actual &&
+	test_cmp expected actual
+'
+
+test_expect_success 'COLUMNS = 1' '
+	cat >expected <<\EOF &&
+one
+two
+three
+four
+five
+six
+seven
+eight
+nine
+ten
+eleven
+EOF
+	COLUMNS=1 git column --mode=column <lista >actual &&
+	test_cmp expected actual
+'
+
+test_expect_success 'width = 1' '
+	git column --mode=column --width=1 <lista >actual &&
+	test_cmp expected actual
+'
+
+COLUMNS=20
+export COLUMNS
+
+test_expect_success '20 columns' '
+	cat >expected <<\EOF &&
+one    seven
+two    eight
+three  nine
+four   ten
+five   eleven
+six
+EOF
+	git column --mode=column <lista >actual &&
+	test_cmp expected actual
+'
+
+test_expect_success '20 columns, padding 2' '
+	cat >expected <<\EOF &&
+one     seven
+two     eight
+three   nine
+four    ten
+five    eleven
+six
+EOF
+	git column --mode=column --padding 2 <lista >actual &&
+	test_cmp expected actual
+'
+
+test_expect_success '20 columns, indented' '
+	cat >expected <<\EOF &&
+  one    seven
+  two    eight
+  three  nine
+  four   ten
+  five   eleven
+  six
+EOF
+	git column --mode=column --indent="  " <lista >actual &&
+	test_cmp expected actual
+'
+
+test_expect_success '20 columns, row first' '
+	cat >expected <<\EOF &&
+one    two
+three  four
+five   six
+seven  eight
+nine   ten
+eleven
+EOF
+	git column --mode=row <lista >actual &&
+	test_cmp expected actual
+'
+
 test_done
-- 
1.7.8.36.g69ee2

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH v5 06/12] column: support columns with different widths
  2012-02-04 15:59 ` [PATCH v5 00/12] Column display Nguyễn Thái Ngọc Duy
                     ` (4 preceding siblings ...)
  2012-02-04 15:59   ` [PATCH v5 05/12] column: add columnar layout Nguyễn Thái Ngọc Duy
@ 2012-02-04 15:59   ` Nguyễn Thái Ngọc Duy
  2012-02-04 15:59   ` [PATCH v5 07/12] column: add column.ui for default column output settings Nguyễn Thái Ngọc Duy
                     ` (6 subsequent siblings)
  12 siblings, 0 replies; 43+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2012-02-04 15:59 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy


Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 column.c          |   80 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 column.h          |    2 +
 t/t9002-column.sh |   22 ++++++++++++++
 3 files changed, 104 insertions(+), 0 deletions(-)

diff --git a/column.c b/column.c
index be4e07c..fcff2fd 100644
--- a/column.c
+++ b/column.c
@@ -19,6 +19,7 @@ struct column_data {
 
 	int rows, cols;
 	int *len;			/* cell length */
+	int *width;			/* index to the longest row in column */
 };
 
 /* return length of 's' in letters, ANSI escapes stripped */
@@ -63,6 +64,69 @@ static void layout(struct column_data *data, int *width)
 	data->rows = DIV_ROUND_UP(data->list->nr, data->cols);
 }
 
+static void compute_column_width(struct column_data *data)
+{
+	int i, x, y;
+	for (x = 0; x < data->cols; x++) {
+		data->width[x] = XY2LINEAR(data, x, 0);
+		for (y = 0; y < data->rows; y++) {
+			i = XY2LINEAR(data, x, y);
+			if (i >= data->list->nr)
+				continue;
+			if (data->len[data->width[x]] < data->len[i])
+				data->width[x] = i;
+		}
+	}
+}
+
+/*
+ * Shrink all columns by shortening them one row each time (and adding
+ * more columns along the way). Hopefully the longest cell will be
+ * moved to the next column, column is shrunk so we have more space
+ * for new columns. The process ends when the whole thing no longer
+ * fits in data->total_width.
+ */
+static void shrink_columns(struct column_data *data)
+{
+	int x, y, total_width, cols, rows;
+
+	data->width = xrealloc(data->width,
+			       sizeof(*data->width) * data->cols);
+	for (x = 0; x < data->cols; x++) {
+		data->width[x] = 0;
+		for (y = 0; y < data->rows; y++) {
+			int len1 = data->len[data->width[x]];
+			int len2 = data->len[XY2LINEAR(data, x, y)];
+			if (len1 < len2)
+				data->width[x] = y;
+		}
+	}
+
+	while (data->rows > 1) {
+		rows = data->rows;
+		cols = data->cols;
+
+		data->rows--;
+		data->cols = DIV_ROUND_UP(data->list->nr, data->rows);
+		if (data->cols != cols)
+			data->width = xrealloc(data->width, sizeof(*data->width) * data->cols);
+
+		compute_column_width(data);
+
+		total_width = strlen(data->indent);
+		for (x = 0; x < data->cols; x++) {
+			total_width += data->len[data->width[x]];
+			total_width += data->padding;
+		}
+		if (total_width > data->total_width) {
+			data->rows = rows;
+			data->cols = cols;
+			compute_column_width(data);
+			break;
+		}
+	}
+}
+
 /* Display without layout when COL_ENABLED is not set */
 static void display_plain(const struct string_list *list,
 			  const char *indent, const char *nl)
@@ -82,7 +146,18 @@ static int display_cell(struct column_data *data, int initial_width,
 	i = XY2LINEAR(data, x, y);
 	if (i >= data->list->nr)
 		return -1;
+
 	len = data->len[i];
+	if (data->width && data->len[data->width[x]] < initial_width) {
+		/*
+		 * empty_cell has initial_width chars, if real column
+		 * is narrower, increase len a bit so we fill less
+		 * space.
+		 */
+		len += initial_width - data->len[data->width[x]];
+		len -= data->padding;
+	}
+
 	if (MODE(data->mode) == COL_MODE_COLUMN)
 		newline = i + data->rows >= data->list->nr;
 	else
@@ -119,6 +194,9 @@ static void display_table(const struct string_list *list,
 
 	layout(&data, &initial_width);
 
+	if (mode & COL_DENSE)
+		shrink_columns(&data);
+
 	empty_cell = xmalloc(initial_width + 1);
 	memset(empty_cell, ' ', initial_width);
 	empty_cell[initial_width] = '\0';
@@ -129,6 +207,7 @@ static void display_table(const struct string_list *list,
 	}
 
 	free(data.len);
+	free(data.width);
 	free(empty_cell);
 }
 
@@ -227,6 +306,7 @@ static int parse_option(const char *arg, int len,
 		{ MODE,   "column", COL_MODE_COLUMN },
 		{ MODE,   "row",    COL_MODE_ROW },
 		{ OPTION, "color",  COL_ANSI },
+		{ OPTION, "dense",  COL_DENSE },
 	};
 	int i, set, name_len;
 
diff --git a/column.h b/column.h
index 52181d4..2255851 100644
--- a/column.h
+++ b/column.h
@@ -7,6 +7,8 @@
 #define COL_ENABLED      (1 << 4)
 #define COL_ENABLED_SET  (1 << 5)  /* Has COL_ENABLED been set by config? */
 #define COL_ANSI         (1 << 6)  /* Remove ANSI escapes from string length */
+#define COL_DENSE        (1 << 7)  /* Shrink columns when possible,
+				      making space for more columns */
 
 struct column_options {
 	int width;
diff --git a/t/t9002-column.sh b/t/t9002-column.sh
index cffb029..23d340e 100755
--- a/t/t9002-column.sh
+++ b/t/t9002-column.sh
@@ -71,6 +71,17 @@ EOF
 	test_cmp expected actual
 '
 
+test_expect_success '20 columns, dense' '
+	cat >expected <<\EOF &&
+one   five  nine
+two   six   ten
+three seven eleven
+four  eight
+EOF
+	git column --mode=column,dense < lista > actual &&
+	test_cmp expected actual
+'
+
 test_expect_success '20 columns, padding 2' '
 	cat >expected <<\EOF &&
 one     seven
@@ -110,4 +121,15 @@ EOF
 	test_cmp expected actual
 '
 
+test_expect_success '20 columns, row first, dense' '
+	cat >expected <<\EOF &&
+one   two    three
+four  five   six
+seven eight  nine
+ten   eleven
+EOF
+	git column --mode=row,dense <lista >actual &&
+	test_cmp expected actual
+'
+
 test_done
-- 
1.7.8.36.g69ee2

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH v5 07/12] column: add column.ui for default column output settings
  2012-02-04 15:59 ` [PATCH v5 00/12] Column display Nguyễn Thái Ngọc Duy
                     ` (5 preceding siblings ...)
  2012-02-04 15:59   ` [PATCH v5 06/12] column: support columns with different widths Nguyễn Thái Ngọc Duy
@ 2012-02-04 15:59   ` Nguyễn Thái Ngọc Duy
  2012-02-04 16:12     ` [PATCH v6 " Nguyễn Thái Ngọc Duy
  2012-02-04 15:59   ` [PATCH v5 08/12] help: reuse print_columns() for help -a Nguyễn Thái Ngọc Duy
                     ` (5 subsequent siblings)
  12 siblings, 1 reply; 43+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2012-02-04 15:59 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy


Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/config.txt     |   26 ++++++++++++++++++++++++++
 Documentation/git-column.txt |    6 +++++-
 builtin/column.c             |   23 ++++++++++++++++++++++-
 column.c                     |   38 ++++++++++++++++++++++++++++++++++++++
 column.h                     |    2 ++
 5 files changed, 93 insertions(+), 2 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index abeb82b..5216598 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -821,6 +821,32 @@ color.ui::
 	`never` if you prefer git commands not to use color unless enabled
 	explicitly with some other configuration or the `--color` option.
 
+column.ui::
+	Specify whether supported commands should output in columns.
+	This variable consists of a list of tokens separated by spaces
+	or commas:
++
+--
+`always`;;
+	always show in columns
+`never`;;
+	never show in columns
+`auto`;;
+	show in columns if the output is to the terminal
+`column`;;
+	fill columns before rows (default)
+`row`;;
+	fill rows before columns
+`dense`;;
+	make unequal size columns to utilize more space
+`nodense`;;
+	make equal size columns
+`color`;;
+	input contains ANSI escape sequence for coloring
+--
++
+	This option defaults to 'never'.
+
 commit.status::
 	A boolean to enable/disable inclusion of status information in the
 	commit message template when using an editor to prepare the commit
diff --git a/Documentation/git-column.txt b/Documentation/git-column.txt
index 508b85f..94fd7ac 100644
--- a/Documentation/git-column.txt
+++ b/Documentation/git-column.txt
@@ -8,7 +8,7 @@ git-column - Display data in columns
 SYNOPSIS
 --------
 [verse]
-'git column' [--mode=<mode> | --rawmode=<n>] [--width=<width>]
+'git column' [--command=<name>] [--[raw]mode=<mode>] [--width=<width>]
 	     [--indent=<string>] [--nl=<string>] [--pading=<n>]
 
 DESCRIPTION
@@ -17,6 +17,10 @@ This command formats its input into multiple columns.
 
 OPTIONS
 -------
+--command=<name>::
+	Look up layout mode using configuration variable column.<name> and
+	column.ui.
+
 --mode=<mode>::
 	Specify layout mode. See configuration variable column.ui for option
 	syntax.
diff --git a/builtin/column.c b/builtin/column.c
index c4a0431..351375f 100644
--- a/builtin/column.c
+++ b/builtin/column.c
@@ -9,14 +9,21 @@ static const char * const builtin_column_usage[] = {
 	"git column [options]",
 	NULL
 };
-static int colopts;
+static unsigned int colopts;
+
+static int column_config(const char *var, const char *value, void *cb)
+{
+	return git_column_config(var, value, cb, &colopts);
+}
 
 int cmd_column(int argc, const char **argv, const char *prefix)
 {
 	struct string_list list = STRING_LIST_INIT_DUP;
 	struct strbuf sb = STRBUF_INIT;
 	struct column_options copts;
+	const char *command = NULL, *real_command = NULL;
 	struct option options[] = {
+		OPT_STRING(0, "command", &real_command, "name", "lookup config vars"),
 		OPT_COLUMN(0, "mode", &colopts, "layout to use"),
 		OPT_INTEGER(0, "rawmode", &colopts, "layout to use"),
 		OPT_INTEGER(0, "width", &copts.width, "Maximum width"),
@@ -26,6 +33,15 @@ int cmd_column(int argc, const char **argv, const char *prefix)
 		OPT_END()
 	};
 
+	/* This one is special and must be the first one */
+	if (argc > 1 && !prefixcmp(argv[1], "--command=")) {
+		int nonitok = 0;
+		setup_git_directory_gently(&nonitok);
+
+		command = argv[1] + 10;
+		git_config(column_config, (void*)command);
+	}
+
 	memset(&copts, 0, sizeof(copts));
 	copts.width = term_columns();
 	copts.padding = 1;
@@ -33,6 +49,11 @@ int cmd_column(int argc, const char **argv, const char *prefix)
 	if (argc)
 		usage_with_options(builtin_column_usage, options);
 
+	if (real_command || command) {
+		if (!real_command || !command || strcmp(real_command, command))
+			die(_("--command must be the first argument"));
+	}
+
 	while (!strbuf_getline(&sb, stdin, '\n'))
 		string_list_append(&list, sb.buf);
 
diff --git a/column.c b/column.c
index fcff2fd..c1233a7 100644
--- a/column.c
+++ b/column.c
@@ -2,6 +2,7 @@
 #include "column.h"
 #include "string-list.h"
 #include "parse-options.h"
+#include "color.h"
 #include "utf8.h"
 
 #define MODE(mode) ((mode) & COL_MODE)
@@ -22,6 +23,8 @@ struct column_data {
 	int *width;			/* index to the longest row in column */
 };
 
+unsigned int git_column_mode;
+
 /* return length of 's' in letters, ANSI escapes stripped */
 static int item_length(int mode, const char *s)
 {
@@ -356,6 +359,41 @@ int git_config_column(unsigned int *mode, const char *value,
 	return 0;
 }
 
+static int column_config(const char *var, const char *value,
+			 const char *key, unsigned int *colopts)
+{
+	if (!strcmp(var, key)) {
+		int ret = git_config_column(colopts, value, -1);
+		if (ret)
+			die("invalid %s mode %s", key, value);
+		return 0;
+	}
+	return 1;		/* go on */
+}
+
+int git_column_config(const char *var, const char *value,
+		      const char *command, unsigned int *colopts)
+{
+	int ret;
+
+	git_column_mode &= ~COL_ENABLED_SET;
+	ret = column_config(var, value, "column.ui", colopts);
+	if (ret <= 0)
+		return ret;
+
+	if (command) {
+		struct strbuf sb = STRBUF_INIT;
+		strbuf_addf(&sb, "column.%s", command);
+		git_column_mode &= ~COL_ENABLED_SET;
+		ret = column_config(var, value, sb.buf, colopts);
+		strbuf_release(&sb);
+		if (ret <= 0)
+			return ret;
+	}
+
+	return 1;		/* go on */
+}
+
 int parseopt_column_callback(const struct option *opt,
 			     const char *arg, int unset)
 {
diff --git a/column.h b/column.h
index 2255851..3d2ed52 100644
--- a/column.h
+++ b/column.h
@@ -23,6 +23,8 @@ extern void print_columns(const struct string_list *list,
 			  struct column_options *opts);
 extern int git_config_column(unsigned int *mode, const char *value,
 			     int stdout_is_tty);
+extern int git_column_config(const char *var, const char *value,
+			     const char *command, unsigned int *colopts);
 
 struct option;
 extern int parseopt_column_callback(const struct option *opt,
-- 
1.7.8.36.g69ee2

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH v5 08/12] help: reuse print_columns() for help -a
  2012-02-04 15:59 ` [PATCH v5 00/12] Column display Nguyễn Thái Ngọc Duy
                     ` (6 preceding siblings ...)
  2012-02-04 15:59   ` [PATCH v5 07/12] column: add column.ui for default column output settings Nguyễn Thái Ngọc Duy
@ 2012-02-04 15:59   ` Nguyễn Thái Ngọc Duy
  2012-02-04 15:59   ` [PATCH v5 09/12] branch: add --column Nguyễn Thái Ngọc Duy
                     ` (4 subsequent siblings)
  12 siblings, 0 replies; 43+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2012-02-04 15:59 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy


Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 help.c |   47 +++++++++++++----------------------------------
 1 files changed, 13 insertions(+), 34 deletions(-)

diff --git a/help.c b/help.c
index 672561b..d6d2e19 100644
--- a/help.c
+++ b/help.c
@@ -4,6 +4,7 @@
 #include "levenshtein.h"
 #include "help.h"
 #include "common-cmds.h"
+#include "string-list.h"
 #include "column.h"
 
 void add_cmdname(struct cmdnames *cmds, const char *name, int len)
@@ -71,31 +72,18 @@ void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes)
 	cmds->cnt = cj;
 }
 
-static void pretty_print_string_list(struct cmdnames *cmds, int longest)
+static void pretty_print_string_list(struct cmdnames *cmds)
 {
-	int cols = 1, rows;
-	int space = longest + 1; /* min 1 SP between words */
-	int max_cols = term_columns() - 1; /* don't print *on* the edge */
-	int i, j;
-
-	if (space < max_cols)
-		cols = max_cols / space;
-	rows = DIV_ROUND_UP(cmds->cnt, cols);
-
-	for (i = 0; i < rows; i++) {
-		printf("  ");
+	struct string_list list = STRING_LIST_INIT_NODUP;
+	struct column_options copts;
+	int i;
 
-		for (j = 0; j < cols; j++) {
-			int n = j * rows + i;
-			int size = space;
-			if (n >= cmds->cnt)
-				break;
-			if (j == cols-1 || n + rows >= cmds->cnt)
-				size = 1;
-			printf("%-*s", size, cmds->names[n]->name);
-		}
-		putchar('\n');
-	}
+	for (i = 0; i < cmds->cnt; i++)
+		string_list_append(&list, cmds->names[i]->name);
+	memset(&copts, 0, sizeof(copts));
+	copts.indent = "  ";
+	print_columns(&list, COL_MODE_COLUMN | COL_ENABLED, &copts);
+	string_list_clear(&list, 0);
 }
 
 static int is_executable(const char *name)
@@ -207,22 +195,13 @@ void load_command_list(const char *prefix,
 void list_commands(const char *title, struct cmdnames *main_cmds,
 		   struct cmdnames *other_cmds)
 {
-	int i, longest = 0;
-
-	for (i = 0; i < main_cmds->cnt; i++)
-		if (longest < main_cmds->names[i]->len)
-			longest = main_cmds->names[i]->len;
-	for (i = 0; i < other_cmds->cnt; i++)
-		if (longest < other_cmds->names[i]->len)
-			longest = other_cmds->names[i]->len;
-
 	if (main_cmds->cnt) {
 		const char *exec_path = git_exec_path();
 		printf("available %s in '%s'\n", title, exec_path);
 		printf("----------------");
 		mput_char('-', strlen(title) + strlen(exec_path));
 		putchar('\n');
-		pretty_print_string_list(main_cmds, longest);
+		pretty_print_string_list(main_cmds);
 		putchar('\n');
 	}
 
@@ -231,7 +210,7 @@ void list_commands(const char *title, struct cmdnames *main_cmds,
 		printf("---------------------------------------");
 		mput_char('-', strlen(title));
 		putchar('\n');
-		pretty_print_string_list(other_cmds, longest);
+		pretty_print_string_list(other_cmds);
 		putchar('\n');
 	}
 }
-- 
1.7.8.36.g69ee2

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH v5 09/12] branch: add --column
  2012-02-04 15:59 ` [PATCH v5 00/12] Column display Nguyễn Thái Ngọc Duy
                     ` (7 preceding siblings ...)
  2012-02-04 15:59   ` [PATCH v5 08/12] help: reuse print_columns() for help -a Nguyễn Thái Ngọc Duy
@ 2012-02-04 15:59   ` Nguyễn Thái Ngọc Duy
  2012-02-06 17:31     ` Junio C Hamano
  2012-02-04 15:59   ` [PATCH v5 10/12] status: " Nguyễn Thái Ngọc Duy
                     ` (3 subsequent siblings)
  12 siblings, 1 reply; 43+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2012-02-04 15:59 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy


Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/config.txt     |    4 +++
 Documentation/git-branch.txt |    9 +++++++
 Makefile                     |    2 +-
 builtin/branch.c             |   38 +++++++++++++++++++++++++++++--
 t/t3200-branch.sh            |   50 ++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 99 insertions(+), 4 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 5216598..c14db27 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -847,6 +847,10 @@ column.ui::
 +
 	This option defaults to 'never'.
 
+column.branch::
+	Specify whether to output branch listing in `git branch` in columns.
+	See `column.ui` for details.
+
 commit.status::
 	A boolean to enable/disable inclusion of status information in the
 	commit message template when using an editor to prepare the commit
diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index 0427e80..ba5cccb 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -10,6 +10,7 @@ SYNOPSIS
 [verse]
 'git branch' [--color[=<when>] | --no-color] [-r | -a]
 	[--list] [-v [--abbrev=<length> | --no-abbrev]]
+	[--column[=<options>] | --no-column]
 	[(--merged | --no-merged | --contains) [<commit>]] [<pattern>...]
 'git branch' [--set-upstream | --track | --no-track] [-l] [-f] <branchname> [<start-point>]
 'git branch' (-m | -M) [<oldbranch>] <newbranch>
@@ -107,6 +108,14 @@ OPTIONS
 	default to color output.
 	Same as `--color=never`.
 
+--column[=<options>]::
+--no-column::
+	Display branch listing in columns. See configuration variable
+	column.branch for option syntax.`--column` and `--no-column`
+	without options are equivalent to 'always' and 'never' respectively.
++
+This option is only applicable in non-verbose mode.
+
 -r::
 --remotes::
 	List or delete (if used with -d) the remote-tracking branches.
diff --git a/Makefile b/Makefile
index 92700ca..061f6e5 100644
--- a/Makefile
+++ b/Makefile
@@ -2116,7 +2116,7 @@ builtin/prune.o builtin/reflog.o reachable.o: reachable.h
 builtin/commit.o builtin/revert.o wt-status.o: wt-status.h
 builtin/tar-tree.o archive-tar.o: tar.h
 connect.o transport.o url.o http-backend.o: url.h
-column.o help.o pager.o: column.h
+builtin/branch.o column.o help.o pager.o: column.h
 http-fetch.o http-walker.o remote-curl.o transport.o walker.o: walker.h
 http.o http-walker.o http-push.o http-fetch.o remote-curl.o: http.h url.h
 
diff --git a/builtin/branch.c b/builtin/branch.c
index 7095718..5014b9d 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -15,6 +15,8 @@
 #include "branch.h"
 #include "diff.h"
 #include "revision.h"
+#include "string-list.h"
+#include "column.h"
 
 static const char * const builtin_branch_usage[] = {
 	"git branch [options] [-r | -a] [--merged | --no-merged]",
@@ -53,6 +55,9 @@ static enum merge_filter {
 } merge_filter;
 static unsigned char merge_filter_ref[20];
 
+static struct string_list output = STRING_LIST_INIT_DUP;
+static unsigned int colopts;
+
 static int parse_branch_color_slot(const char *var, int ofs)
 {
 	if (!strcasecmp(var+ofs, "plain"))
@@ -70,6 +75,9 @@ static int parse_branch_color_slot(const char *var, int ofs)
 
 static int git_branch_config(const char *var, const char *value, void *cb)
 {
+	int status = git_column_config(var, value, "branch", &colopts);
+	if (status <= 0)
+		return status;
 	if (!strcmp(var, "color.branch")) {
 		branch_use_color = git_config_colorbool(var, value);
 		return 0;
@@ -474,7 +482,12 @@ static void print_ref_item(struct ref_item *item, int maxwidth, int verbose,
 	else if (verbose)
 		/* " f7c0c00 [ahead 58, behind 197] vcs-svn: drop obj_pool.h" */
 		add_verbose_info(&out, item, verbose, abbrev);
-	printf("%s\n", out.buf);
+	if (colopts & COL_ENABLED) {
+		assert(!verbose && "--column and --verbose are incompatible");
+		string_list_append(&output, out.buf);
+	}
+	else
+		printf("%s\n", out.buf);
 	strbuf_release(&name);
 	strbuf_release(&out);
 }
@@ -727,6 +740,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 			PARSE_OPT_LASTARG_DEFAULT | PARSE_OPT_NONEG,
 			opt_parse_merge_filter, (intptr_t) "HEAD",
 		},
+		OPT_COLUMN(0, "column", &colopts, "list branches in columns" ),
 		OPT_END(),
 	};
 
@@ -749,6 +763,8 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 	}
 	hashcpy(merge_filter_ref, head_sha1);
 
+
+	colopts = (colopts & ~COL_ENABLED_SET) | COL_ANSI;
 	argc = parse_options(argc, argv, prefix, options, builtin_branch_usage,
 			     0);
 
@@ -761,11 +777,27 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 	if (abbrev == -1)
 		abbrev = DEFAULT_ABBREV;
 
+	if (verbose) {
+		/* only die when --column is given explicitly */
+		if ((colopts & (COL_ENABLED_SET | COL_ENABLED)) == (COL_ENABLED_SET | COL_ENABLED))
+			die(_("--column and --verbose are incompatible"));
+		else
+			colopts = 0;
+	}
+
 	if (delete)
 		return delete_branches(argc, argv, delete > 1, kinds);
-	else if (list)
-		return print_ref_list(kinds, detached, verbose, abbrev,
+	else if (list) {
+		int ret;
+		if (verbose)
+			colopts = 0;
+
+		ret = print_ref_list(kinds, detached, verbose, abbrev,
 				      with_commit, argv);
+		print_columns(&output, colopts, NULL);
+		string_list_clear(&output, 0);
+		return ret;
+	}
 	else if (edit_description) {
 		const char *branch_name;
 		if (detached)
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index ea82424..9728ee6 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -163,6 +163,56 @@ test_expect_success 'git branch --list -d t should fail' '
 	test_path_is_missing .git/refs/heads/t
 '
 
+test_expect_success 'git branch --column' '
+	COLUMNS=80 git branch --column=column >actual &&
+	cat >expected <<\EOF &&
+  a/b/c     bam       foo       l       * master    n         o/p       r
+  abc       bar       j/k       m/m       master2   o/o       q
+EOF
+	test_cmp expected actual
+'
+
+test_expect_success 'git branch with column.*' '
+	git config column.ui column &&
+	git config column.branch "dense" &&
+	COLUMNS=80 git branch >actual &&
+	git config --unset column.branch &&
+	git config --unset column.ui &&
+	cat >expected <<\EOF &&
+  a/b/c   bam   foo   l   * master    n     o/p   r
+  abc     bar   j/k   m/m   master2   o/o   q
+EOF
+	test_cmp expected actual
+'
+
+test_expect_success 'git branch --column -v should fail' '
+	test_must_fail git branch --column -v
+'
+
+test_expect_success 'git branch -v with column.ui ignored' '
+	git config column.ui column &&
+	COLUMNS=80 git branch -v | cut -c -10 >actual &&
+	git config --unset column.ui &&
+	cat >expected <<\EOF &&
+  a/b/c   
+  abc     
+  bam     
+  bar     
+  foo     
+  j/k     
+  l       
+  m/m     
+* master  
+  master2 
+  n       
+  o/o     
+  o/p     
+  q       
+  r       
+EOF
+	test_cmp expected actual
+'
+
 mv .git/config .git/config-saved
 
 test_expect_success 'git branch -m q q2 without config should succeed' '
-- 
1.7.8.36.g69ee2

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH v5 10/12] status: add --column
  2012-02-04 15:59 ` [PATCH v5 00/12] Column display Nguyễn Thái Ngọc Duy
                     ` (8 preceding siblings ...)
  2012-02-04 15:59   ` [PATCH v5 09/12] branch: add --column Nguyễn Thái Ngọc Duy
@ 2012-02-04 15:59   ` Nguyễn Thái Ngọc Duy
  2012-02-04 15:59   ` [PATCH v5 11/12] column: support piping stdout to external git-column process Nguyễn Thái Ngọc Duy
                     ` (2 subsequent siblings)
  12 siblings, 0 replies; 43+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2012-02-04 15:59 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy


Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/config.txt     |    4 ++++
 Documentation/git-status.txt |    7 +++++++
 Makefile                     |    2 +-
 builtin/commit.c             |    8 ++++++++
 t/t7508-status.sh            |   24 ++++++++++++++++++++++++
 wt-status.c                  |   28 ++++++++++++++++++++++++++--
 wt-status.h                  |    1 +
 7 files changed, 71 insertions(+), 3 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index c14db27..ebb210c 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -851,6 +851,10 @@ column.branch::
 	Specify whether to output branch listing in `git branch` in columns.
 	See `column.ui` for details.
 
+column.status::
+	Specify whether to output untracked files in `git status` in columns.
+	See `column.ui` for details.
+
 commit.status::
 	A boolean to enable/disable inclusion of status information in the
 	commit message template when using an editor to prepare the commit
diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt
index 3d51717..2f87207 100644
--- a/Documentation/git-status.txt
+++ b/Documentation/git-status.txt
@@ -77,6 +77,13 @@ configuration variable documented in linkgit:git-config[1].
 	Terminate entries with NUL, instead of LF.  This implies
 	the `--porcelain` output format if no other format is given.
 
+--column[=<options>]::
+--no-column::
+	Display untracked files in columns. See configuration variable
+	column.status for option syntax.`--column` and `--no-column`
+	without options are equivalent to 'always' and 'never'
+	respectively.
+
 
 OUTPUT
 ------
diff --git a/Makefile b/Makefile
index 061f6e5..b2644bc 100644
--- a/Makefile
+++ b/Makefile
@@ -2116,7 +2116,7 @@ builtin/prune.o builtin/reflog.o reachable.o: reachable.h
 builtin/commit.o builtin/revert.o wt-status.o: wt-status.h
 builtin/tar-tree.o archive-tar.o: tar.h
 connect.o transport.o url.o http-backend.o: url.h
-builtin/branch.o column.o help.o pager.o: column.h
+builtin/branch.o builtin/commit.o column.o help.o pager.o: column.h
 http-fetch.o http-walker.o remote-curl.o transport.o walker.o: walker.h
 http.o http-walker.o http-push.o http-fetch.o remote-curl.o: http.h url.h
 
diff --git a/builtin/commit.c b/builtin/commit.c
index eba1377..b73211c 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -27,6 +27,7 @@
 #include "quote.h"
 #include "submodule.h"
 #include "gpg-interface.h"
+#include "column.h"
 
 static const char * const builtin_commit_usage[] = {
 	"git commit [options] [--] <filepattern>...",
@@ -88,6 +89,7 @@ static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
 static int no_post_rewrite, allow_empty_message;
 static char *untracked_files_arg, *force_date, *ignore_submodule_arg;
 static char *sign_commit;
+static unsigned int colopts;
 
 /*
  * The default commit message cleanup mode will remove the lines
@@ -1138,7 +1140,11 @@ static int parse_status_slot(const char *var, int offset)
 static int git_status_config(const char *k, const char *v, void *cb)
 {
 	struct wt_status *s = cb;
+	int status;
 
+	status = git_column_config(k, v, "status", &colopts);
+	if (status <= 0)
+		return status;
 	if (!strcmp(k, "status.submodulesummary")) {
 		int is_bool;
 		s->submodule_summary = git_config_bool_or_int(k, v, &is_bool);
@@ -1204,6 +1210,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
 		{ OPTION_STRING, 0, "ignore-submodules", &ignore_submodule_arg, "when",
 		  "ignore changes to submodules, optional when: all, dirty, untracked. (Default: all)",
 		  PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
+		OPT_COLUMN(0, "column", &colopts, "list untracked files in columns" ),
 		OPT_END(),
 	};
 
@@ -1217,6 +1224,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
 	argc = parse_options(argc, argv, prefix,
 			     builtin_status_options,
 			     builtin_status_usage, 0);
+	s.colopts = colopts;
 
 	if (null_termination && status_format == STATUS_FORMAT_LONG)
 		status_format = STATUS_FORMAT_PORCELAIN;
diff --git a/t/t7508-status.sh b/t/t7508-status.sh
index fc57b13..8f5cfac 100755
--- a/t/t7508-status.sh
+++ b/t/t7508-status.sh
@@ -59,6 +59,30 @@ test_expect_success 'status (1)' '
 	test_i18ngrep "use \"git rm --cached <file>\.\.\.\" to unstage" output
 '
 
+test_expect_success 'status --column' '
+	COLUMNS=50 git status --column="column dense" >output &&
+	cat >expect <<\EOF &&
+# On branch master
+# Changes to be committed:
+#   (use "git reset HEAD <file>..." to unstage)
+#
+#	new file:   dir2/added
+#
+# Changes not staged for commit:
+#   (use "git add <file>..." to update what will be committed)
+#   (use "git checkout -- <file>..." to discard changes in working directory)
+#
+#	modified:   dir1/modified
+#
+# Untracked files:
+#   (use "git add <file>..." to include in what will be committed)
+#
+#	dir1/untracked dir2/untracked untracked
+#	dir2/modified  output
+EOF
+	test_cmp expect output
+'
+
 cat >expect <<\EOF
 # On branch master
 # Changes to be committed:
diff --git a/wt-status.c b/wt-status.c
index 9ffc535..63ce7c9 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -11,6 +11,7 @@
 #include "remote.h"
 #include "refs.h"
 #include "submodule.h"
+#include "column.h"
 
 static char default_wt_status_colors[][COLOR_MAXLEN] = {
 	GIT_COLOR_NORMAL, /* WT_STATUS_HEADER */
@@ -641,6 +642,8 @@ static void wt_status_print_other(struct wt_status *s,
 {
 	int i;
 	struct strbuf buf = STRBUF_INIT;
+	static struct string_list output = STRING_LIST_INIT_DUP;
+	struct column_options copts;
 
 	if (!l->nr)
 		return;
@@ -649,12 +652,33 @@ static void wt_status_print_other(struct wt_status *s,
 
 	for (i = 0; i < l->nr; i++) {
 		struct string_list_item *it;
+		const char *path;
 		it = &(l->items[i]);
+		path = quote_path(it->string, strlen(it->string),
+				  &buf, s->prefix);
+		if (s->colopts & COL_ENABLED) {
+			string_list_append(&output, path);
+			continue;
+		}
 		status_printf(s, color(WT_STATUS_HEADER, s), "\t");
 		status_printf_more(s, color(WT_STATUS_UNTRACKED, s),
-			"%s\n", quote_path(it->string, strlen(it->string),
-					    &buf, s->prefix));
+				   "%s\n", path);
 	}
+
+	strbuf_release(&buf);
+	if ((s->colopts & COL_ENABLED) == 0)
+		return;
+
+	strbuf_addf(&buf, "%s#\t%s",
+		    color(WT_STATUS_HEADER,s),
+		    color(WT_STATUS_UNTRACKED, s));
+	memset(&copts, 0, sizeof(copts));
+	copts.padding = 1;
+	copts.indent = buf.buf;
+	if (want_color(s->use_color))
+		copts.nl = GIT_COLOR_RESET "\n";
+	print_columns(&output, s->colopts, &copts);
+	string_list_clear(&output, 0);
 	strbuf_release(&buf);
 }
 
diff --git a/wt-status.h b/wt-status.h
index 682b4c8..6dd7207 100644
--- a/wt-status.h
+++ b/wt-status.h
@@ -56,6 +56,7 @@ struct wt_status {
 	enum untracked_status_type show_untracked_files;
 	const char *ignore_submodule_arg;
 	char color_palette[WT_STATUS_MAXSLOT][COLOR_MAXLEN];
+	int colopts;
 
 	/* These are computed during processing of the individual sections */
 	int commitable;
-- 
1.7.8.36.g69ee2

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH v5 11/12] column: support piping stdout to external git-column process
  2012-02-04 15:59 ` [PATCH v5 00/12] Column display Nguyễn Thái Ngọc Duy
                     ` (9 preceding siblings ...)
  2012-02-04 15:59   ` [PATCH v5 10/12] status: " Nguyễn Thái Ngọc Duy
@ 2012-02-04 15:59   ` Nguyễn Thái Ngọc Duy
  2012-02-04 15:59   ` [PATCH v5 12/12] tag: add --column Nguyễn Thái Ngọc Duy
  2012-02-06 17:58   ` [PATCH v5 00/12] Column display Junio C Hamano
  12 siblings, 0 replies; 43+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2012-02-04 15:59 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

For too complicated output handling, it'd be easier to just spawn
git-column and redirect stdout to it. This patch provides helpers
to do that.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 column.c |   69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 column.h |    3 ++
 2 files changed, 72 insertions(+), 0 deletions(-)

diff --git a/column.c b/column.c
index c1233a7..4098f03 100644
--- a/column.c
+++ b/column.c
@@ -2,6 +2,7 @@
 #include "column.h"
 #include "string-list.h"
 #include "parse-options.h"
+#include "run-command.h"
 #include "color.h"
 #include "utf8.h"
 
@@ -409,3 +410,71 @@ int parseopt_column_callback(const struct option *opt,
 	*mode |= COL_ENABLED | COL_ENABLED_SET;
 	return 0;
 }
+
+static int fd_out = -1;
+static struct child_process column_process;
+
+int run_column_filter(int colopts, const struct column_options *opts)
+{
+	const char *av[10];
+	int ret, ac = 0;
+	struct strbuf sb_colopt  = STRBUF_INIT;
+	struct strbuf sb_width   = STRBUF_INIT;
+	struct strbuf sb_padding = STRBUF_INIT;
+
+	if (fd_out != -1)
+		return -1;
+
+	av[ac++] = "column";
+	strbuf_addf(&sb_colopt, "--rawmode=%d", colopts);
+	av[ac++] = sb_colopt.buf;
+	if (opts->width) {
+		strbuf_addf(&sb_width, "--width=%d", opts->width);
+		av[ac++] = sb_width.buf;
+	}
+	if (opts->indent) {
+		av[ac++] = "--indent";
+		av[ac++] = opts->indent;
+	}
+	if (opts->padding) {
+		strbuf_addf(&sb_padding, "--padding=%d", opts->padding);
+		av[ac++] = sb_padding.buf;
+	}
+	av[ac] = NULL;
+
+	fflush(stdout);
+	memset(&column_process, 0, sizeof(column_process));
+	column_process.in = -1;
+	column_process.out = dup(1);
+	column_process.git_cmd = 1;
+	column_process.argv = av;
+
+	ret = start_command(&column_process);
+
+	strbuf_release(&sb_colopt);
+	strbuf_release(&sb_width);
+	strbuf_release(&sb_padding);
+
+	if (ret)
+		return -2;
+
+	fd_out = dup(1);
+	close(1);
+	dup2(column_process.in, 1);
+	close(column_process.in);
+	return 0;
+}
+
+int stop_column_filter()
+{
+	if (fd_out == -1)
+		return -1;
+
+	fflush(stdout);
+	close(1);
+	finish_command(&column_process);
+	dup2(fd_out, 1);
+	close(fd_out);
+	fd_out = -1;
+	return 0;
+}
diff --git a/column.h b/column.h
index 3d2ed52..b9dec64 100644
--- a/column.h
+++ b/column.h
@@ -30,4 +30,7 @@ struct option;
 extern int parseopt_column_callback(const struct option *opt,
 				    const char *arg, int unset);
 
+extern int run_column_filter(int colopts, const struct column_options *);
+extern int stop_column_filter();
+
 #endif
-- 
1.7.8.36.g69ee2

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH v5 12/12] tag: add --column
  2012-02-04 15:59 ` [PATCH v5 00/12] Column display Nguyễn Thái Ngọc Duy
                     ` (10 preceding siblings ...)
  2012-02-04 15:59   ` [PATCH v5 11/12] column: support piping stdout to external git-column process Nguyễn Thái Ngọc Duy
@ 2012-02-04 15:59   ` Nguyễn Thái Ngọc Duy
  2012-02-06 17:58   ` [PATCH v5 00/12] Column display Junio C Hamano
  12 siblings, 0 replies; 43+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2012-02-04 15:59 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy


Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/config.txt  |    4 ++++
 Documentation/git-tag.txt |   11 ++++++++++-
 Makefile                  |    2 +-
 builtin/tag.c             |   30 +++++++++++++++++++++++++++---
 t/t7004-tag.sh            |   44 ++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 86 insertions(+), 5 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index ebb210c..145336a 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -855,6 +855,10 @@ column.status::
 	Specify whether to output untracked files in `git status` in columns.
 	See `column.ui` for details.
 
+column.tag::
+	Specify whether to output tag listing in `git tag` in columns.
+	See `column.ui` for details.
+
 commit.status::
 	A boolean to enable/disable inclusion of status information in the
 	commit message template when using an editor to prepare the commit
diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
index 53ff5f6..5ead91e 100644
--- a/Documentation/git-tag.txt
+++ b/Documentation/git-tag.txt
@@ -12,7 +12,8 @@ SYNOPSIS
 'git tag' [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>]
 	<tagname> [<commit> | <object>]
 'git tag' -d <tagname>...
-'git tag' [-n[<num>]] -l [--contains <commit>] [<pattern>...]
+'git tag' [-n[<num>]] -l [--contains <commit>]
+	[--column[=<options>] | --no-column] [<pattern>...]
 'git tag' -v <tagname>...
 
 DESCRIPTION
@@ -83,6 +84,14 @@ OPTIONS
 	using fnmatch(3)).  Multiple patterns may be given; if any of
 	them matches, the tag is shown.
 
+--column[=<options>]::
+--no-column::
+	Display tag listing in columns. See configuration variable
+	column.tag for option syntax.`--column` and `--no-column`
+	without options are equivalent to 'always' and 'never' respectively.
++
+This option is only applicable when listing tags without annotation lines.
+
 --contains <commit>::
 	Only list tags which contain the specified commit.
 
diff --git a/Makefile b/Makefile
index b2644bc..eb7b6fc 100644
--- a/Makefile
+++ b/Makefile
@@ -2116,7 +2116,7 @@ builtin/prune.o builtin/reflog.o reachable.o: reachable.h
 builtin/commit.o builtin/revert.o wt-status.o: wt-status.h
 builtin/tar-tree.o archive-tar.o: tar.h
 connect.o transport.o url.o http-backend.o: url.h
-builtin/branch.o builtin/commit.o column.o help.o pager.o: column.h
+builtin/branch.o builtin/commit.o builtin/tag.o column.o help.o pager.o: column.h
 http-fetch.o http-walker.o remote-curl.o transport.o walker.o: walker.h
 http.o http-walker.o http-push.o http-fetch.o remote-curl.o: http.h url.h
 
diff --git a/builtin/tag.c b/builtin/tag.c
index 31f02e8..d01f918 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -15,6 +15,7 @@
 #include "diff.h"
 #include "revision.h"
 #include "gpg-interface.h"
+#include "column.h"
 
 static const char * const git_tag_usage[] = {
 	"git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]",
@@ -30,6 +31,8 @@ struct tag_filter {
 	struct commit_list *with_commit;
 };
 
+static unsigned int colopts;
+
 static int match_pattern(const char **patterns, const char *ref)
 {
 	/* no pattern means match everything */
@@ -230,6 +233,9 @@ static int git_tag_config(const char *var, const char *value, void *cb)
 	int status = git_gpg_config(var, value, cb);
 	if (status)
 		return status;
+	status = git_column_config(var, value, "tag", &colopts);
+	if (status <= 0)
+		return status;
 	return git_default_config(var, value, cb);
 }
 
@@ -409,6 +415,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
 		OPT_STRING('u', "local-user", &keyid, "key-id",
 					"use another key to sign the tag"),
 		OPT__FORCE(&force, "replace the tag if exists"),
+		OPT_COLUMN(0, "column", &colopts, "show tag list in columns" ),
 
 		OPT_GROUP("Tag listing options"),
 		{
@@ -424,6 +431,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
 
 	memset(&opt, 0, sizeof(opt));
 
+	colopts &= ~COL_ENABLED_SET;
 	argc = parse_options(argc, argv, prefix, options, git_tag_usage, 0);
 
 	if (keyid) {
@@ -441,9 +449,25 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
 
 	if (list + delete + verify > 1)
 		usage_with_options(git_tag_usage, options);
-	if (list)
-		return list_tags(argv, lines == -1 ? 0 : lines,
-				 with_commit);
+	if (list && lines != -1) {
+		/* only die when --column is given explicitly */
+		if ((colopts & (COL_ENABLED_SET | COL_ENABLED)) == (COL_ENABLED_SET | COL_ENABLED))
+			die(_("--column and -n are incompatible"));
+		colopts = 0;
+	}
+	if (list) {
+		int ret;
+		if (lines == -1 && colopts & COL_ENABLED) {
+			struct column_options copts;
+			memset(&copts, 0, sizeof(copts));
+			copts.padding = 2;
+			run_column_filter(colopts, &copts);
+		}
+		ret = list_tags(argv, lines == -1 ? 0 : lines, with_commit);
+		if (lines == -1 && colopts & COL_ENABLED)
+			stop_column_filter();
+		return ret;
+	}
 	if (lines != -1)
 		die(_("-n option is only allowed with -l."));
 	if (with_commit)
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index e93ac73..579a298 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -263,6 +263,50 @@ test_expect_success 'tag -l can accept multiple patterns' '
 	test_cmp expect actual
 '
 
+test_expect_success 'listing tags in column' '
+	COLUMNS=40 git tag -l --column=row >actual &&
+	cat >expected <<\EOF &&
+a1      aa1     cba     t210    t211
+v0.2.1  v1.0    v1.0.1  v1.1.3
+EOF
+	test_cmp expected actual
+'
+
+test_expect_success 'listing tags in column with column.*' '
+	git config column.tag row &&
+	git config column.ui dense &&
+	COLUMNS=40 git tag -l >actual &&
+	git config --unset column.ui &&
+	git config --unset column.tag &&
+	cat >expected <<\EOF &&
+a1      aa1   cba     t210    t211
+v0.2.1  v1.0  v1.0.1  v1.1.3
+EOF
+	test_cmp expected actual
+'
+
+test_expect_success 'listing tag with -n --column should fail' '
+	test_must_fail git tag --column -n
+'
+
+test_expect_success 'listing tags -n in column with column.ui ignored' '
+	git config column.ui "row dense" &&
+	COLUMNS=40 git tag -l -n >actual &&
+	git config --unset column.ui &&
+	cat >expected <<\EOF &&
+a1              Foo
+aa1             Foo
+cba             Foo
+t210            Foo
+t211            Foo
+v0.2.1          Foo
+v1.0            Foo
+v1.0.1          Foo
+v1.1.3          Foo
+EOF
+	test_cmp expected actual
+'
+
 # creating and verifying lightweight tags:
 
 test_expect_success \
-- 
1.7.8.36.g69ee2

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH v6 03/12] Add git-column and column mode parsing
  2012-02-04 15:59   ` [PATCH v5 03/12] Add git-column and column mode parsing Nguyễn Thái Ngọc Duy
@ 2012-02-04 16:11     ` Nguyễn Thái Ngọc Duy
  0 siblings, 0 replies; 43+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2012-02-04 16:11 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

A column option string consists of many token separated by either
space of commas. A token belongs to one of three groups:

 - enabling: always, never and auto
 - layout mode: to be implemented
 - other tuning, which could be negated be prefix 'no'

A command line option without argument (e.g. --column) will enable
column output and reuse existing settings (layout mode and options..).
--no-column disables columnar output.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Turn colopts to unsigned int from the beginning.

 .gitignore                   |    1 +
 Documentation/git-column.txt |   49 ++++++++++++++++
 Makefile                     |    1 +
 builtin.h                    |    1 +
 builtin/column.c             |   41 ++++++++++++++
 column.c                     |  125 ++++++++++++++++++++++++++++++++++++++++++
 column.h                     |    7 ++
 command-list.txt             |    1 +
 git.c                        |    1 +
 parse-options.h              |    2 +
 t/t9002-column.sh            |   27 +++++++++
 11 files changed, 256 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/.gitignore b/.gitignore
index 3b7680e..039e5ef 100644
--- a/.gitignore
+++ b/.gitignore
@@ -26,6 +26,7 @@
 /git-cherry-pick
 /git-clean
 /git-clone
+/git-column
 /git-commit
 /git-commit-tree
 /git-config
diff --git a/Documentation/git-column.txt b/Documentation/git-column.txt
new file mode 100644
index 0000000..508b85f
--- /dev/null
+++ b/Documentation/git-column.txt
@@ -0,0 +1,49 @@
+git-column(1)
+=============
+
+NAME
+----
+git-column - Display data in columns
+
+SYNOPSIS
+--------
+[verse]
+'git column' [--mode=<mode> | --rawmode=<n>] [--width=<width>]
+	     [--indent=<string>] [--nl=<string>] [--pading=<n>]
+
+DESCRIPTION
+-----------
+This command formats its input into multiple columns.
+
+OPTIONS
+-------
+--mode=<mode>::
+	Specify layout mode. See configuration variable column.ui for option
+	syntax.
+
+--rawmode=<n>::
+	Same as --mode but take mode encoded as a number. This is mainly used
+	by other commands that have already parsed layout mode.
+
+--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.
+
+--indent=<string>::
+	String to be printed at the beginning of each line.
+
+--nl=<N>::
+	String to be printed at the end of each line,
+	including newline character.
+
+--padding=<N>::
+	The number of spaces between columns. One space by default.
+
+
+Author
+------
+Written by Nguyen Thai Ngoc Duy <pclouds@gmail.com>
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Makefile b/Makefile
index 5f0531b..92700ca 100644
--- a/Makefile
+++ b/Makefile
@@ -766,6 +766,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 857b9c8..338f540 100644
--- a/builtin.h
+++ b/builtin.h
@@ -61,6 +61,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_config(int argc, const char **argv, const char *prefix);
diff --git a/builtin/column.c b/builtin/column.c
new file mode 100644
index 0000000..3b0f74e
--- /dev/null
+++ b/builtin/column.c
@@ -0,0 +1,41 @@
+#include "builtin.h"
+#include "cache.h"
+#include "strbuf.h"
+#include "parse-options.h"
+#include "string-list.h"
+#include "column.h"
+
+static const char * const builtin_column_usage[] = {
+	"git column [options]",
+	NULL
+};
+static unsigned int colopts;
+
+int cmd_column(int argc, const char **argv, const char *prefix)
+{
+	struct string_list list = STRING_LIST_INIT_DUP;
+	struct strbuf sb = STRBUF_INIT;
+	struct column_options copts;
+	struct option options[] = {
+		OPT_COLUMN(0, "mode", &colopts, "layout to use"),
+		OPT_INTEGER(0, "rawmode", &colopts, "layout to use"),
+		OPT_INTEGER(0, "width", &copts.width, "Maximum width"),
+		OPT_STRING(0, "indent", &copts.indent, "string", "Padding space on left border"),
+		OPT_INTEGER(0, "nl", &copts.nl, "Padding space on right border"),
+		OPT_INTEGER(0, "padding", &copts.padding, "Padding space between columns"),
+		OPT_END()
+	};
+
+	memset(&copts, 0, sizeof(copts));
+	copts.width = term_columns();
+	copts.padding = 1;
+	argc = parse_options(argc, argv, "", options, builtin_column_usage, 0);
+	if (argc)
+		usage_with_options(builtin_column_usage, options);
+
+	while (!strbuf_getline(&sb, stdin, '\n'))
+		string_list_append(&list, sb.buf);
+
+	print_columns(&list, colopts, &copts);
+	return 0;
+}
diff --git a/column.c b/column.c
index 742ae18..d20cf8f 100644
--- a/column.c
+++ b/column.c
@@ -1,6 +1,7 @@
 #include "cache.h"
 #include "column.h"
 #include "string-list.h"
+#include "parse-options.h"
 
 #define MODE(mode) ((mode) & COL_MODE)
 
@@ -37,3 +38,127 @@ void print_columns(const struct string_list *list, unsigned int mode,
 	}
 	die("BUG: invalid mode %d", MODE(mode));
 }
+
+struct colopt {
+	enum {
+		ENABLE,
+		MODE,
+		OPTION
+	} type;
+	const char *name;
+	int value;
+};
+
+/*
+ * Set COL_ENABLED and COL_ENABLED_SET. If 'set' is -1, check if
+ * stdout is tty.
+ */
+static int set_enable_bit(unsigned int *mode, int set, int stdout_is_tty)
+{
+	if (set < 0) {	/* auto */
+		if (stdout_is_tty < 0)
+			stdout_is_tty = isatty(1);
+		set = stdout_is_tty || (pager_in_use() && pager_use_color);
+	}
+	if (set)
+		*mode = *mode | COL_ENABLED | COL_ENABLED_SET;
+	else
+		*mode = (*mode & ~COL_ENABLED) | COL_ENABLED_SET;
+	return 0;
+}
+
+/*
+ * Set COL_MODE_*. mode is intially copied from column.ui. If
+ * COL_ENABLED_SET is not set, then neither 'always', 'never' nor
+ * 'auto' has been used. Default to 'always'.
+ */
+static int set_mode(unsigned int *mode, unsigned int value)
+{
+	*mode = (*mode & ~COL_MODE) | value;
+	if (!(*mode & COL_ENABLED_SET))
+		*mode |= COL_ENABLED | COL_ENABLED_SET;
+
+	return 0;
+}
+
+/* Set or unset other COL_* */
+static int set_option(unsigned int *mode, unsigned int opt, int set)
+{
+	if (set)
+		*mode |= opt;
+	else
+		*mode &= ~opt;
+	return 0;
+}
+
+static int parse_option(const char *arg, int len,
+			unsigned int *mode, int stdout_is_tty)
+{
+	struct colopt opts[] = {
+		{ ENABLE, "always",  1 },
+		{ ENABLE, "never",   0 },
+		{ ENABLE, "auto",   -1 },
+	};
+	int i, set, name_len;
+
+	for (i = 0; i < ARRAY_SIZE(opts); i++) {
+		if (opts[i].type == OPTION) {
+			if (len > 2 && !strncmp(arg, "no", 2)) {
+				arg += 2;
+				len -= 2;
+				set = 0;
+			}
+			else
+				set = 1;
+		}
+
+		name_len = strlen(opts[i].name);
+		if (len != name_len ||
+		    strncmp(arg, opts[i].name, name_len))
+			continue;
+
+		switch (opts[i].type) {
+		case ENABLE: return set_enable_bit(mode, opts[i].value,
+						   stdout_is_tty);
+		case MODE: return set_mode(mode, opts[i].value);
+		case OPTION: return set_option(mode, opts[i].value, set);
+		default: die("BUG: Unknown option type %d", opts[i].type);
+		}
+	}
+
+	return error("unsupported style '%s'", arg);
+}
+
+int git_config_column(unsigned int *mode, const char *value,
+		      int stdout_is_tty)
+{
+	const char *sep = " ,";
+
+	while (*value) {
+		int len = strcspn(value, sep);
+		if (len) {
+			if (parse_option(value, len, mode, stdout_is_tty))
+				return -1;
+
+			value += len;
+		}
+		value += strspn(value, sep);
+	}
+	return 0;
+}
+
+int parseopt_column_callback(const struct option *opt,
+			     const char *arg, int unset)
+{
+	unsigned int *mode = opt->value;
+	if (unset) {
+		*mode = (*mode & ~COL_ENABLED) | COL_ENABLED_SET;
+		return 0;
+	}
+	if (arg)
+		return git_config_column(mode, arg, -1);
+
+	/* no arg, turn it on */
+	*mode |= COL_ENABLED | COL_ENABLED_SET;
+	return 0;
+}
diff --git a/column.h b/column.h
index 8e4fdaa..f48fa81 100644
--- a/column.h
+++ b/column.h
@@ -3,6 +3,7 @@
 
 #define COL_MODE          0x000F
 #define COL_ENABLED      (1 << 4)
+#define COL_ENABLED_SET  (1 << 5)  /* Has COL_ENABLED been set by config? */
 
 struct column_options {
 	int width;
@@ -15,5 +16,11 @@ extern int term_columns(void);
 extern void print_columns(const struct string_list *list,
 			  unsigned int mode,
 			  struct column_options *opts);
+extern int git_config_column(unsigned int *mode, const char *value,
+			     int stdout_is_tty);
+
+struct option;
+extern int parseopt_column_callback(const struct option *opt,
+				    const char *arg, int unset);
 
 #endif
diff --git a/command-list.txt b/command-list.txt
index a36ee9b..fe06f15 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
diff --git a/git.c b/git.c
index 3805616..419e3cc 100644
--- a/git.c
+++ b/git.c
@@ -348,6 +348,7 @@ static void handle_internal_command(int argc, const char **argv)
 		{ "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE },
 		{ "clean", cmd_clean, RUN_SETUP | NEED_WORK_TREE },
 		{ "clone", cmd_clone },
+		{ "column", cmd_column },
 		{ "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE },
 		{ "commit-tree", cmd_commit_tree, RUN_SETUP },
 		{ "config", cmd_config, RUN_SETUP_GENTLY },
diff --git a/parse-options.h b/parse-options.h
index 2e811dc..56fcafd 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -238,5 +238,7 @@ extern int parse_opt_noop_cb(const struct option *, const char *, int);
 	  PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }
 #define OPT__COLOR(var, h) \
 	OPT_COLOR_FLAG(0, "color", (var), (h))
+#define OPT_COLUMN(s, l, v, h) \
+	{ OPTION_CALLBACK, (s), (l), (v), "style", (h), PARSE_OPT_OPTARG, parseopt_column_callback }
 
 #endif
diff --git a/t/t9002-column.sh b/t/t9002-column.sh
new file mode 100755
index 0000000..b0b6d62
--- /dev/null
+++ b/t/t9002-column.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+test_description='git column'
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+	cat >lista <<\EOF
+one
+two
+three
+four
+five
+six
+seven
+eight
+nine
+ten
+eleven
+EOF
+'
+
+test_expect_success 'never' '
+	git column --mode=never <lista >actual &&
+	test_cmp lista actual
+'
+
+test_done
-- 
1.7.8.36.g69ee2

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH v6 07/12] column: add column.ui for default column output settings
  2012-02-04 15:59   ` [PATCH v5 07/12] column: add column.ui for default column output settings Nguyễn Thái Ngọc Duy
@ 2012-02-04 16:12     ` Nguyễn Thái Ngọc Duy
  0 siblings, 0 replies; 43+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2012-02-04 16:12 UTC (permalink / raw
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy


Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Really get rid of git_colopts (aka git_column_mode in v5). Sorry.

 Documentation/config.txt     |   26 ++++++++++++++++++++++++++
 Documentation/git-column.txt |    6 +++++-
 builtin/column.c             |   21 +++++++++++++++++++++
 column.c                     |   36 ++++++++++++++++++++++++++++++++++++
 column.h                     |    2 ++
 5 files changed, 90 insertions(+), 1 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index abeb82b..5216598 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -821,6 +821,32 @@ color.ui::
 	`never` if you prefer git commands not to use color unless enabled
 	explicitly with some other configuration or the `--color` option.
 
+column.ui::
+	Specify whether supported commands should output in columns.
+	This variable consists of a list of tokens separated by spaces
+	or commas:
++
+--
+`always`;;
+	always show in columns
+`never`;;
+	never show in columns
+`auto`;;
+	show in columns if the output is to the terminal
+`column`;;
+	fill columns before rows (default)
+`row`;;
+	fill rows before columns
+`dense`;;
+	make unequal size columns to utilize more space
+`nodense`;;
+	make equal size columns
+`color`;;
+	input contains ANSI escape sequence for coloring
+--
++
+	This option defaults to 'never'.
+
 commit.status::
 	A boolean to enable/disable inclusion of status information in the
 	commit message template when using an editor to prepare the commit
diff --git a/Documentation/git-column.txt b/Documentation/git-column.txt
index 508b85f..94fd7ac 100644
--- a/Documentation/git-column.txt
+++ b/Documentation/git-column.txt
@@ -8,7 +8,7 @@ git-column - Display data in columns
 SYNOPSIS
 --------
 [verse]
-'git column' [--mode=<mode> | --rawmode=<n>] [--width=<width>]
+'git column' [--command=<name>] [--[raw]mode=<mode>] [--width=<width>]
 	     [--indent=<string>] [--nl=<string>] [--pading=<n>]
 
 DESCRIPTION
@@ -17,6 +17,10 @@ This command formats its input into multiple columns.
 
 OPTIONS
 -------
+--command=<name>::
+	Look up layout mode using configuration variable column.<name> and
+	column.ui.
+
 --mode=<mode>::
 	Specify layout mode. See configuration variable column.ui for option
 	syntax.
diff --git a/builtin/column.c b/builtin/column.c
index 3b0f74e..351375f 100644
--- a/builtin/column.c
+++ b/builtin/column.c
@@ -11,12 +11,19 @@ static const char * const builtin_column_usage[] = {
 };
 static unsigned int colopts;
 
+static int column_config(const char *var, const char *value, void *cb)
+{
+	return git_column_config(var, value, cb, &colopts);
+}
+
 int cmd_column(int argc, const char **argv, const char *prefix)
 {
 	struct string_list list = STRING_LIST_INIT_DUP;
 	struct strbuf sb = STRBUF_INIT;
 	struct column_options copts;
+	const char *command = NULL, *real_command = NULL;
 	struct option options[] = {
+		OPT_STRING(0, "command", &real_command, "name", "lookup config vars"),
 		OPT_COLUMN(0, "mode", &colopts, "layout to use"),
 		OPT_INTEGER(0, "rawmode", &colopts, "layout to use"),
 		OPT_INTEGER(0, "width", &copts.width, "Maximum width"),
@@ -26,6 +33,15 @@ int cmd_column(int argc, const char **argv, const char *prefix)
 		OPT_END()
 	};
 
+	/* This one is special and must be the first one */
+	if (argc > 1 && !prefixcmp(argv[1], "--command=")) {
+		int nonitok = 0;
+		setup_git_directory_gently(&nonitok);
+
+		command = argv[1] + 10;
+		git_config(column_config, (void*)command);
+	}
+
 	memset(&copts, 0, sizeof(copts));
 	copts.width = term_columns();
 	copts.padding = 1;
@@ -33,6 +49,11 @@ int cmd_column(int argc, const char **argv, const char *prefix)
 	if (argc)
 		usage_with_options(builtin_column_usage, options);
 
+	if (real_command || command) {
+		if (!real_command || !command || strcmp(real_command, command))
+			die(_("--command must be the first argument"));
+	}
+
 	while (!strbuf_getline(&sb, stdin, '\n'))
 		string_list_append(&list, sb.buf);
 
diff --git a/column.c b/column.c
index fcff2fd..e3cec1c 100644
--- a/column.c
+++ b/column.c
@@ -2,6 +2,7 @@
 #include "column.h"
 #include "string-list.h"
 #include "parse-options.h"
+#include "color.h"
 #include "utf8.h"
 
 #define MODE(mode) ((mode) & COL_MODE)
@@ -356,6 +357,41 @@ int git_config_column(unsigned int *mode, const char *value,
 	return 0;
 }
 
+static int column_config(const char *var, const char *value,
+			 const char *key, unsigned int *colopts)
+{
+	if (!strcmp(var, key)) {
+		int ret = git_config_column(colopts, value, -1);
+		if (ret)
+			die("invalid %s mode %s", key, value);
+		return 0;
+	}
+	return 1;		/* go on */
+}
+
+int git_column_config(const char *var, const char *value,
+		      const char *command, unsigned int *colopts)
+{
+	int ret;
+
+	*colopts &= ~COL_ENABLED_SET;
+	ret = column_config(var, value, "column.ui", colopts);
+	if (ret <= 0)
+		return ret;
+
+	if (command) {
+		struct strbuf sb = STRBUF_INIT;
+		strbuf_addf(&sb, "column.%s", command);
+		*colopts &= ~COL_ENABLED_SET;
+		ret = column_config(var, value, sb.buf, colopts);
+		strbuf_release(&sb);
+		if (ret <= 0)
+			return ret;
+	}
+
+	return 1;		/* go on */
+}
+
 int parseopt_column_callback(const struct option *opt,
 			     const char *arg, int unset)
 {
diff --git a/column.h b/column.h
index 2255851..3d2ed52 100644
--- a/column.h
+++ b/column.h
@@ -23,6 +23,8 @@ extern void print_columns(const struct string_list *list,
 			  struct column_options *opts);
 extern int git_config_column(unsigned int *mode, const char *value,
 			     int stdout_is_tty);
+extern int git_column_config(const char *var, const char *value,
+			     const char *command, unsigned int *colopts);
 
 struct option;
 extern int parseopt_column_callback(const struct option *opt,
-- 
1.7.8.36.g69ee2

^ permalink raw reply related	[flat|nested] 43+ messages in thread

* Re: [PATCH v5 09/12] branch: add --column
  2012-02-04 15:59   ` [PATCH v5 09/12] branch: add --column Nguyễn Thái Ngọc Duy
@ 2012-02-06 17:31     ` Junio C Hamano
  0 siblings, 0 replies; 43+ messages in thread
From: Junio C Hamano @ 2012-02-06 17:31 UTC (permalink / raw
  To: Nguyễn Thái Ngọc Duy; +Cc: git

Nguyễn Thái Ngọc Duy <pclouds@gmail.com> writes:

> +test_expect_success 'git branch -v with column.ui ignored' '
> +	git config column.ui column &&
> +	COLUMNS=80 git branch -v | cut -c -10 >actual &&
> +	git config --unset column.ui &&
> +	cat >expected <<\EOF &&
> +  a/b/c   
> +  abc     
> +  bam     
> +  bar     
> +  foo     
> +  j/k     
> +  l       
> +  m/m     
> +* master  
> +  master2 
> +  n       
> +  o/o     
> +  o/p     
> +  q       
> +  r       
> +EOF

For a test like these where you expect whitespaces at the end, please make
sure that these whitespaces are visible to people who read test scripts,
by doing something like this instead:

	sed -e 's/#$//' >expected <<\EOF
          a/b/c   #
          abc     #
          bam     #
          bar     #
          foo     #
        EOF

Thanks.

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH v5 00/12] Column display
  2012-02-04 15:59 ` [PATCH v5 00/12] Column display Nguyễn Thái Ngọc Duy
                     ` (11 preceding siblings ...)
  2012-02-04 15:59   ` [PATCH v5 12/12] tag: add --column Nguyễn Thái Ngọc Duy
@ 2012-02-06 17:58   ` Junio C Hamano
  12 siblings, 0 replies; 43+ messages in thread
From: Junio C Hamano @ 2012-02-06 17:58 UTC (permalink / raw
  To: Nguyễn Thái Ngọc Duy; +Cc: git

I've added two patches on top of this series and queued on 'pu'.

The first one is a fix for style issues; this is limited to absolute
minimum and I wouldn't be surprised if I fixed one instance of the same
class of style violations just as an example while ignoring bunch of
similar ones.

The second was to see how "git branch" behaves when it sees one absurdly
long entry (longer than $COLUMN width) among the normal ones, primarily
done just for fun.

You may want to tease the first one apart and squash them in to where the
problem originates. The second one is optional, but as you hinted an
interest on coming up with a heuristic to cram more info by making some
oddball entries span multi-column, it might serve as a good starting point 
to think about the possible issues.

Thanks for an amusing read.

^ permalink raw reply	[flat|nested] 43+ messages in thread

end of thread, other threads:[~2012-02-06 17:58 UTC | newest]

Thread overview: 43+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-02-03 13:34 [PATCH v4 00/13] Column display again Nguyễn Thái Ngọc Duy
2012-02-03 13:34 ` [PATCH v4 01/13] Save terminal width before setting up pager Nguyễn Thái Ngọc Duy
2012-02-03 13:34 ` [PATCH v4 02/13] column: add API to print items in columns Nguyễn Thái Ngọc Duy
2012-02-03 22:55   ` Junio C Hamano
2012-02-03 23:16   ` Junio C Hamano
2012-02-03 13:34 ` [PATCH v4 03/13] parseopt: make OPT_INTEGER support hexadecimal as well Nguyễn Thái Ngọc Duy
2012-02-03 22:59   ` Junio C Hamano
2012-02-04  4:55     ` Nguyen Thai Ngoc Duy
2012-02-04  5:32       ` Junio C Hamano
2012-02-04  6:15         ` Nguyen Thai Ngoc Duy
2012-02-03 13:34 ` [PATCH v4 04/13] Add git-column and column mode parsing Nguyễn Thái Ngọc Duy
2012-02-03 13:34 ` [PATCH v4 05/13] Stop starting pager recursively Nguyễn Thái Ngọc Duy
2012-02-03 13:34 ` [PATCH v4 06/13] column: add columnar layout Nguyễn Thái Ngọc Duy
2012-02-03 13:34 ` [PATCH v4 07/13] column: support columns with different widths Nguyễn Thái Ngọc Duy
2012-02-03 13:34 ` [PATCH v4 08/13] column: add column.ui for default column output settings Nguyễn Thái Ngọc Duy
2012-02-03 23:04   ` Junio C Hamano
2012-02-03 13:34 ` [PATCH v4 09/13] help: reuse print_columns() for help -a Nguyễn Thái Ngọc Duy
2012-02-03 23:05   ` Junio C Hamano
2012-02-03 13:34 ` [PATCH v4 10/13] branch: add --column Nguyễn Thái Ngọc Duy
2012-02-03 23:11   ` Junio C Hamano
2012-02-04  5:01     ` Nguyen Thai Ngoc Duy
2012-02-03 13:34 ` [PATCH v4 11/13] status: " Nguyễn Thái Ngọc Duy
2012-02-03 23:19   ` Junio C Hamano
2012-02-03 13:34 ` [PATCH v4 12/13] column: support piping stdout to external git-column process Nguyễn Thái Ngọc Duy
2012-02-03 13:34 ` [PATCH v4 13/13] tag: add --column Nguyễn Thái Ngọc Duy
2012-02-03 23:30   ` Junio C Hamano
2012-02-04 15:59 ` [PATCH v5 00/12] Column display Nguyễn Thái Ngọc Duy
2012-02-04 15:59   ` [PATCH v5 01/12] Save terminal width before setting up pager Nguyễn Thái Ngọc Duy
2012-02-04 15:59   ` [PATCH v5 02/12] column: add API to print items in columns Nguyễn Thái Ngọc Duy
2012-02-04 15:59   ` [PATCH v5 03/12] Add git-column and column mode parsing Nguyễn Thái Ngọc Duy
2012-02-04 16:11     ` [PATCH v6 " Nguyễn Thái Ngọc Duy
2012-02-04 15:59   ` [PATCH v5 04/12] Stop starting pager recursively Nguyễn Thái Ngọc Duy
2012-02-04 15:59   ` [PATCH v5 05/12] column: add columnar layout Nguyễn Thái Ngọc Duy
2012-02-04 15:59   ` [PATCH v5 06/12] column: support columns with different widths Nguyễn Thái Ngọc Duy
2012-02-04 15:59   ` [PATCH v5 07/12] column: add column.ui for default column output settings Nguyễn Thái Ngọc Duy
2012-02-04 16:12     ` [PATCH v6 " Nguyễn Thái Ngọc Duy
2012-02-04 15:59   ` [PATCH v5 08/12] help: reuse print_columns() for help -a Nguyễn Thái Ngọc Duy
2012-02-04 15:59   ` [PATCH v5 09/12] branch: add --column Nguyễn Thái Ngọc Duy
2012-02-06 17:31     ` Junio C Hamano
2012-02-04 15:59   ` [PATCH v5 10/12] status: " Nguyễn Thái Ngọc Duy
2012-02-04 15:59   ` [PATCH v5 11/12] column: support piping stdout to external git-column process Nguyễn Thái Ngọc Duy
2012-02-04 15:59   ` [PATCH v5 12/12] tag: add --column Nguyễn Thái Ngọc Duy
2012-02-06 17:58   ` [PATCH v5 00/12] Column display Junio C Hamano

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

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 read-only IMAP folder(s) and NNTP newsgroup(s).