git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
To: git@vger.kernel.org, Jonathan Niedier <jrnieder@gmail.com>
Cc: "Nguyễn Thái Ngọc Duy" <pclouds@gmail.com>
Subject: [PATCH 03/16] display_columns: add COL_MODE_{COLUMN,ROW} mode
Date: Wed,  9 Feb 2011 19:24:31 +0700	[thread overview]
Message-ID: <1297254284-3729-4-git-send-email-pclouds@gmail.com> (raw)
In-Reply-To: <1297254284-3729-1-git-send-email-pclouds@gmail.com>

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

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

diff --git a/column.c b/column.c
index c7d9a84..d6e2d70 100644
--- a/column.c
+++ b/column.c
@@ -1,8 +1,58 @@
 #include "cache.h"
 #include "column.h"
+#include "parse-options.h"
 #include "string-list.h"
+#include "utf8.h"
 
 #define MODE(mode) ((mode) & COL_MODE)
+#define XY2SCALAR(mode,x,y,cols,rows) (MODE(mode) == COL_MODE_COLUMN ? (x) * (rows) + (y) : (y) * (cols) + (x))
+
+/* return length of 's' in letters, ANSI escapes stripped */
+static int item_length(const struct string_list *list, 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(const struct string_list *list,
+		   int mode, int total_width, int padding,
+		   int *width, int *rows, int *cols)
+{
+	int i;
+
+	*width = 0;
+	/* Find maximum column width */
+	for (i = 0; i < list->nr; i++) {
+		const char *s = list->items[i].string;
+		int len = item_length(list, mode, s);
+		if (*width < len)
+			*width = len;
+	}
+	*width += padding;
+
+	*cols = total_width / *width;
+	if (*cols == 0)
+		*cols = 1;
+
+	*rows = DIV_ROUND_UP(list->nr, *cols);
+}
 
 /* Display without layout, COL_MODE_PLAIN */
 static void display_plain(const struct string_list *list, const char *indent)
@@ -13,6 +63,58 @@ static void display_plain(const struct string_list *list, const char *indent)
 		printf("%s%s\n", indent, list->items[i].string);
 }
 
+static int display_cell(const struct string_list *list, int mode,
+			int *width, int initial_width,
+			const char *indent, const char *empty_cell,
+			int x, int y, int cols, int rows)
+{
+	const char *s;
+	int i, len, newline;
+
+	i = XY2SCALAR(mode, x, y, cols, rows);
+	if (i >= list->nr)
+		return -1;
+	s = list->items[i].string;
+	len = item_length(list, mode, s);
+	if (width[x] < initial_width)
+		len += initial_width - width[x];
+	if (MODE(mode) == COL_MODE_COLUMN)
+		newline = i + rows >= list->nr;
+	else
+		newline = x == cols - 1 || i == list->nr - 1;
+
+	printf("%s%s%s",
+			x == 0 ? indent : "",
+			list->items[i].string,
+			newline ? "\n" : 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)
+{
+	int x, y, i, cols, rows, initial_width, *width;
+	char *empty_cell;
+
+	layout(list, mode, total_width, padding, &initial_width, &rows, &cols);
+	width = xmalloc(sizeof(*width) * cols);
+	for (i = 0; i < cols; i++)
+		width[i] = initial_width;
+
+	empty_cell = xmalloc(initial_width + 1);
+	memset(empty_cell, ' ', initial_width);
+	empty_cell[initial_width] = '\0';
+	for (y = 0; y < rows; y++) {
+		for (x = 0; x < cols; x++)
+			if (display_cell(list, mode, width,
+					 initial_width, indent, empty_cell,
+					 x, y, cols, rows))
+				break;
+	}
+}
+
 void display_columns(const struct string_list *list, int mode, int width, int padding, const char *indent)
 {
 	int real_mode = MODE(mode);
@@ -25,6 +127,11 @@ void display_columns(const struct string_list *list, int mode, int width, int pa
 		display_plain(list, indent);
 		break;
 
+	case COL_MODE_ROW:
+	case COL_MODE_COLUMN:
+		display_table(list, mode, width, padding, indent);
+		break;
+
 	default:
 		die("BUG: invalid mode %d", MODE(mode));
 	}
diff --git a/column.h b/column.h
index da0bf9a..3ed5731 100644
--- a/column.h
+++ b/column.h
@@ -3,6 +3,9 @@
 
 #define COL_MODE          0x000F
 #define COL_MODE_PLAIN         0   /* Single column */
+#define COL_MODE_COLUMN        1   /* Fill columns before rows */
+#define COL_MODE_ROW           2   /* Fill rows before columns */
+#define COL_ANSI         (1 << 4) /* Remove ANSI escapes from string length */
 
 extern int term_columns(void);
 extern void display_columns(const struct string_list *list, int mode, int width, int padding, const char *indent);
-- 
1.7.2.2

  parent reply	other threads:[~2011-02-09 12:26 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-02-09 12:24 [PATCH 00/16] column output (v2) and git-ls Nguyễn Thái Ngọc Duy
2011-02-09 12:24 ` [PATCH 01/16] Move term_columns() to pager.c and save terminal width before pager Nguyễn Thái Ngọc Duy
2011-02-09 12:24 ` [PATCH 02/16] Add display_columns() to display in column layout Nguyễn Thái Ngọc Duy
2011-02-09 12:24 ` Nguyễn Thái Ngọc Duy [this message]
2011-02-09 12:24 ` [PATCH 04/16] display_columns: add COL_DENSE to do unequal " Nguyễn Thái Ngọc Duy
2011-02-09 12:24 ` [PATCH 05/16] Add test-column for testing " Nguyễn Thái Ngọc Duy
2011-02-09 12:24 ` [PATCH 06/16] Add core.column Nguyễn Thái Ngọc Duy
2011-02-09 12:24 ` [PATCH 07/16] parseopt: OPT_COLUMN to set struct column_layout.mode Nguyễn Thái Ngọc Duy
2011-02-09 12:24 ` [PATCH 08/16] help: reuse display_columns() for help -a Nguyễn Thái Ngọc Duy
2011-02-09 12:24 ` [PATCH 09/16] tag: add --column Nguyễn Thái Ngọc Duy
2011-02-09 12:24 ` [PATCH 10/16] branch: " Nguyễn Thái Ngọc Duy
2011-02-09 12:24 ` [PATCH 11/16] Add ls command Nguyễn Thái Ngọc Duy
2011-02-09 12:24 ` [PATCH 12/16] ls: add --column Nguyễn Thái Ngọc Duy
2011-02-09 12:24 ` [PATCH 13/16] ls: add --recursive and turn default to non-recursive mode Nguyễn Thái Ngọc Duy
2011-02-09 12:24 ` [PATCH 14/16] ls: immitate UNIX ls output style Nguyễn Thái Ngọc Duy
2011-02-09 12:24 ` [PATCH 15/16] ls: strip common directory prefix from output Nguyễn Thái Ngọc Duy
2011-02-09 12:24 ` [PATCH 16/16] ls: color output Nguyễn Thái Ngọc Duy

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1297254284-3729-4-git-send-email-pclouds@gmail.com \
    --to=pclouds@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=jrnieder@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).