All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/19] Add git-list-files
@ 2014-11-30  8:55 Nguyễn Thái Ngọc Duy
  2014-11-30  8:55 ` [PATCH 01/19] ls_colors.c: add $LS_COLORS parsing code Nguyễn Thái Ngọc Duy
                   ` (20 more replies)
  0 siblings, 21 replies; 28+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2014-11-30  8:55 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy

This is something else that's been sitting in my tree for a while now.
It adds "git list-files", intended to be aliased as "ls" with your
favourite display options.

As you can guess it's a friendlier version (and pretty close to GNU
ls) of ls-files. On one hand, I think this is a nice addition. On the
other hand, code bloat. Last version on the list is

http://thread.gmane.org/gmane.comp.version-control.git/244530/focus=245464

Nguyễn Thái Ngọc Duy (19):
  ls_colors.c: add $LS_COLORS parsing code
  ls_colors.c: parse color.ls.* from config file
  ls_colors.c: add a function to color a file name
  ls_colors.c: highlight submodules like directories
  ls-files: buffer full item in strbuf before printing
  ls-files: add --color to highlight file names
  ls-files: add --column
  ls-files: support --max-depth
  Add git-list-files, a user friendly version of ls-files and more
  list-files: -u does not imply showing stages
  list-files: add -R/--recursive short for --max-depth=-1
  list-files: add -1 short for --no-column
  list-files: add -t back
  list-files: sort output and remove duplicates
  list-files: do not show duplicate cached entries
  list-files: show directories as well as files
  list-files: add -F/--classify
  list-files -F: show submodules with the new indicator '&'
  list-files: -M aka diff-cached

 .gitignore                             |   1 +
 Documentation/config.txt               |  22 ++
 Documentation/git-list-files.txt (new) |  99 +++++++
 Documentation/git-ls-files.txt         |  20 ++
 Makefile                               |   2 +
 builtin/ls-files.c                     | 415 ++++++++++++++++++++++++---
 color.h                                |  10 +
 command-list.txt                       |   1 +
 git.c                                  |   1 +
 ls_colors.c (new)                      | 496 +++++++++++++++++++++++++++++++++
 10 files changed, 1034 insertions(+), 33 deletions(-)
 create mode 100644 Documentation/git-list-files.txt
 create mode 100644 ls_colors.c

-- 
2.2.0.60.gb7b3c64

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

* [PATCH 01/19] ls_colors.c: add $LS_COLORS parsing code
  2014-11-30  8:55 [PATCH 00/19] Add git-list-files Nguyễn Thái Ngọc Duy
@ 2014-11-30  8:55 ` Nguyễn Thái Ngọc Duy
  2014-11-30  8:55 ` [PATCH 02/19] ls_colors.c: parse color.ls.* from config file Nguyễn Thái Ngọc Duy
                   ` (19 subsequent siblings)
  20 siblings, 0 replies; 28+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2014-11-30  8:55 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy

Reusing color settings from $LS_COLORS could give a native look and
feel on file coloring.

This code is basically from coreutils.git [1], rewritten to fit Git.

As this is from GNU ls, the environment variable CLICOLOR is not
tested. It is to be decided later whether we should ignore $LS_COLORS
if $CLICOLOR is not set on Mac or FreeBSD.

[1] commit 7326d1f1a67edf21947ae98194f98c38b6e9e527 file
    src/ls.c. This is the last GPL-2 commit before coreutils turns to
    GPL-3.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Makefile          |   1 +
 color.h           |   8 ++
 ls_colors.c (new) | 398 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 407 insertions(+)
 create mode 100644 ls_colors.c

diff --git a/Makefile b/Makefile
index 827006b..459121d 100644
--- a/Makefile
+++ b/Makefile
@@ -703,6 +703,7 @@ LIB_OBJS += list-objects.o
 LIB_OBJS += ll-merge.o
 LIB_OBJS += lockfile.o
 LIB_OBJS += log-tree.o
+LIB_OBJS += ls_colors.o
 LIB_OBJS += mailmap.o
 LIB_OBJS += match-trees.o
 LIB_OBJS += merge.o
diff --git a/color.h b/color.h
index f5beab1..3eaa5bd 100644
--- a/color.h
+++ b/color.h
@@ -45,6 +45,12 @@ struct strbuf;
 #define GIT_COLOR_BG_MAGENTA	"\033[45m"
 #define GIT_COLOR_BG_CYAN	"\033[46m"
 
+#define GIT_COLOR_WHITE_ON_RED    "\033[37;41m"
+#define GIT_COLOR_WHITE_ON_BLUE   "\033[37;44m"
+#define GIT_COLOR_BLACK_ON_YELLOW "\033[30;43m"
+#define GIT_COLOR_BLUE_ON_GREEN   "\033[34;42m"
+#define GIT_COLOR_BLACK_ON_GREEN  "\033[30;42m"
+
 /* A special value meaning "no color selected" */
 #define GIT_COLOR_NIL "NIL"
 
@@ -87,4 +93,6 @@ void color_print_strbuf(FILE *fp, const char *color, const struct strbuf *sb);
 
 int color_is_nil(const char *color);
 
+void parse_ls_color(void);
+
 #endif /* COLOR_H */
diff --git a/ls_colors.c b/ls_colors.c
new file mode 100644
index 0000000..eb944f4
--- /dev/null
+++ b/ls_colors.c
@@ -0,0 +1,398 @@
+#include "cache.h"
+#include "color.h"
+
+enum color_ls {
+	LS_LC,			/* left, unused */
+	LS_RC,			/* right, unused */
+	LS_EC,			/* end color, unused */
+	LS_RS,			/* reset */
+	LS_NO,			/* normal */
+	LS_FL,			/* file, default */
+	LS_DI,			/* directory */
+	LS_LN,			/* symlink */
+
+	LS_PI,			/* pipe */
+	LS_SO,			/* socket */
+	LS_BD,			/* block device */
+	LS_CD,			/* char device */
+	LS_MI,			/* missing file */
+	LS_OR,			/* orphaned symlink */
+	LS_EX,			/* executable */
+	LS_DO,			/* Solaris door */
+
+	LS_SU,			/* setuid */
+	LS_SG,			/* setgid */
+	LS_ST,			/* sticky */
+	LS_OW,			/* other-writable */
+	LS_TW,			/* ow with sticky */
+	LS_CA,			/* cap */
+	LS_MH,			/* multi hardlink */
+	LS_CL,			/* clear end of line */
+
+	MAX_LS
+};
+
+static char ls_colors[MAX_LS][COLOR_MAXLEN] = {
+	"",
+	"",
+	"",
+	GIT_COLOR_RESET,
+	GIT_COLOR_NORMAL,
+	GIT_COLOR_NORMAL,
+	GIT_COLOR_BOLD_BLUE,
+	GIT_COLOR_BOLD_CYAN,
+
+	GIT_COLOR_YELLOW,
+	GIT_COLOR_BOLD_MAGENTA,
+	GIT_COLOR_BOLD_YELLOW,
+	GIT_COLOR_BOLD_YELLOW,
+	GIT_COLOR_NORMAL,
+	GIT_COLOR_NORMAL,
+	GIT_COLOR_BOLD_GREEN,
+	GIT_COLOR_BOLD_MAGENTA,
+
+	GIT_COLOR_WHITE_ON_RED,
+	GIT_COLOR_BLACK_ON_YELLOW,
+	GIT_COLOR_WHITE_ON_BLUE,
+	GIT_COLOR_BLUE_ON_GREEN,
+	GIT_COLOR_BLACK_ON_GREEN,
+	"",
+	"",
+	""
+};
+
+static const char *const indicator_name[] = {
+	"lc", "rc", "ec", "rs", "no", "fi", "di", "ln",
+	"pi", "so", "bd", "cd", "mi", "or", "ex", "do",
+	"su", "sg", "st", "ow", "tw", "ca", "mh", "cl",
+	NULL
+};
+
+struct bin_str {
+	size_t len;			/* Number of bytes */
+	const char *string;		/* Pointer to the same */
+};
+
+struct color_ext_type {
+	struct bin_str ext;		/* The extension we're looking for */
+	struct bin_str seq;		/* The sequence to output when we do */
+	struct color_ext_type *next;	/* Next in list */
+};
+
+static struct color_ext_type *color_ext_list = NULL;
+
+/*
+ * When true, in a color listing, color each symlink name according to the
+ * type of file it points to.  Otherwise, color them according to the `ln'
+ * directive in LS_COLORS.  Dangling (orphan) symlinks are treated specially,
+ * regardless.  This is set when `ln=target' appears in LS_COLORS.
+ */
+static int color_symlink_as_referent;
+
+/*
+ * Parse a string as part of the LS_COLORS variable; this may involve
+ * decoding all kinds of escape characters.  If equals_end is set an
+ * unescaped equal sign ends the string, otherwise only a : or \0
+ * does.  Set *OUTPUT_COUNT to the number of bytes output.  Return
+ * true if successful.
+ *
+ * The resulting string is *not* null-terminated, but may contain
+ * embedded nulls.
+ *
+ * Note that both dest and src are char **; on return they point to
+ * the first free byte after the array and the character that ended
+ * the input string, respectively.
+ */
+static int get_funky_string(char **dest, const char **src, int equals_end,
+			    size_t *output_count)
+{
+	char num;			/* For numerical codes */
+	size_t count;			/* Something to count with */
+	enum {
+		ST_GND, ST_BACKSLASH, ST_OCTAL, ST_HEX,
+		ST_CARET, ST_END, ST_ERROR
+	} state;
+	const char *p;
+	char *q;
+
+	p = *src;			/* We don't want to double-indirect */
+	q = *dest;			/* the whole darn time.  */
+
+	count = 0;			/* No characters counted in yet.  */
+	num = 0;
+
+	state = ST_GND;		/* Start in ground state.  */
+	while (state < ST_END) {
+		switch (state) {
+		case ST_GND:		/* Ground state (no escapes) */
+			switch (*p) {
+			case ':':
+			case '\0':
+				state = ST_END;	/* End of string */
+				break;
+			case '\\':
+				state = ST_BACKSLASH; /* Backslash scape sequence */
+				++p;
+				break;
+			case '^':
+				state = ST_CARET; /* Caret escape */
+				++p;
+				break;
+			case '=':
+				if (equals_end) {
+					state = ST_END; /* End */
+					break;
+				}
+				/* else fall through */
+			default:
+				*(q++) = *(p++);
+				++count;
+				break;
+			}
+			break;
+
+		case ST_BACKSLASH:	/* Backslash escaped character */
+			switch (*p) {
+			case '0':
+			case '1':
+			case '2':
+			case '3':
+			case '4':
+			case '5':
+			case '6':
+			case '7':
+				state = ST_OCTAL;	/* Octal sequence */
+				num = *p - '0';
+				break;
+			case 'x':
+			case 'X':
+				state = ST_HEX;	/* Hex sequence */
+				num = 0;
+				break;
+			case 'a':		/* Bell */
+				num = '\a';
+				break;
+			case 'b':		/* Backspace */
+				num = '\b';
+				break;
+			case 'e':		/* Escape */
+				num = 27;
+				break;
+			case 'f':		/* Form feed */
+				num = '\f';
+				break;
+			case 'n':		/* Newline */
+				num = '\n';
+				break;
+			case 'r':		/* Carriage return */
+				num = '\r';
+				break;
+			case 't':		/* Tab */
+				num = '\t';
+				break;
+			case 'v':		/* Vtab */
+				num = '\v';
+				break;
+			case '?':		/* Delete */
+				num = 127;
+				break;
+			case '_':		/* Space */
+				num = ' ';
+				break;
+			case '\0':		/* End of string */
+				state = ST_ERROR;	/* Error! */
+				break;
+			default:		/* Escaped character like \ ^ : = */
+				num = *p;
+				break;
+			}
+			if (state == ST_BACKSLASH) {
+				*(q++) = num;
+				++count;
+				state = ST_GND;
+			}
+			++p;
+			break;
+
+		case ST_OCTAL:		/* Octal sequence */
+			if (*p < '0' || *p > '7') {
+				*(q++) = num;
+				++count;
+				state = ST_GND;
+			} else
+				num = (num << 3) + (*(p++) - '0');
+			break;
+
+		case ST_HEX:		/* Hex sequence */
+			switch (*p) {
+			case '0':
+			case '1':
+			case '2':
+			case '3':
+			case '4':
+			case '5':
+			case '6':
+			case '7':
+			case '8':
+			case '9':
+				num = (num << 4) + (*(p++) - '0');
+				break;
+			case 'a':
+			case 'b':
+			case 'c':
+			case 'd':
+			case 'e':
+			case 'f':
+				num = (num << 4) + (*(p++) - 'a') + 10;
+				break;
+			case 'A':
+			case 'B':
+			case 'C':
+			case 'D':
+			case 'E':
+			case 'F':
+				num = (num << 4) + (*(p++) - 'A') + 10;
+				break;
+			default:
+				*(q++) = num;
+				++count;
+				state = ST_GND;
+				break;
+			}
+			break;
+
+		case ST_CARET:		/* Caret escape */
+			state = ST_GND;	/* Should be the next state... */
+			if (*p >= '@' && *p <= '~') {
+				*(q++) = *(p++) & 037;
+				++count;
+			} else if (*p == '?') {
+				*(q++) = 127;
+				++count;
+			} else
+				state = ST_ERROR;
+			break;
+
+		default:
+			abort();
+		}
+	}
+
+	*dest = q;
+	*src = p;
+	*output_count = count;
+
+	return state != ST_ERROR;
+}
+
+void parse_ls_color(void)
+{
+	const char *p;			/* Pointer to character being parsed */
+	char *buf;			/* color_buf buffer pointer */
+	int state;			/* State of parser */
+	int ind_no;			/* Indicator number */
+	char label[3];			/* Indicator label */
+	struct color_ext_type *ext;	/* Extension we are working on */
+	static char *color_buf;
+	char *start;
+	size_t len;
+
+	if ((p = getenv("LS_COLORS")) == NULL || *p == '\0')
+		return;
+
+	ext = NULL;
+	strcpy (label, "??");
+
+	/*
+	 * This is an overly conservative estimate, but any possible
+	 * LS_COLORS string will *not* generate a color_buf longer
+	 * than itself, so it is a safe way of allocating a buffer in
+	 * advance.
+	 */
+	buf = color_buf = xstrdup(p);
+
+	state = 1;
+	while (state > 0) {
+		switch (state) {
+		case 1:		/* First label character */
+			switch (*p) {
+			case ':':
+				++p;
+				break;
+
+			case '*':
+				/*
+				 * Allocate new extension block and add to head of
+				 * linked list (this way a later definition will
+				 * override an earlier one, which can be useful for
+				 * having terminal-specific defs override global).
+				 */
+
+				ext = xmalloc(sizeof *ext);
+				ext->next = color_ext_list;
+				color_ext_list = ext;
+
+				++p;
+				ext->ext.string = buf;
+
+				state = (get_funky_string(&buf, &p, 1, &ext->ext.len)
+					 ? 4 : -1);
+				break;
+
+			case '\0':
+				state = 0;	/* Done! */
+				break;
+
+			default:	/* Assume it is file type label */
+				label[0] = *(p++);
+				state = 2;
+				break;
+			}
+			break;
+
+		case 2:		/* Second label character */
+			if (*p) {
+				label[1] = *(p++);
+				state = 3;
+			} else
+				state = -1;	/* Error */
+			break;
+
+		case 3:		/* Equal sign after indicator label */
+			state = -1;	/* Assume failure...  */
+			if (*(p++) != '=')
+				break;
+			for (ind_no = 0; indicator_name[ind_no] != NULL; ++ind_no) {
+				if (!strcmp(label, indicator_name[ind_no])) {
+					start = buf;
+					if (get_funky_string(&buf, &p, 0, &len))
+						state = 1;
+					else
+						state = -1;
+					break;
+				}
+			}
+			if (state == -1)
+				error(_("unrecognized prefix: %s"), label);
+			else if (ind_no == LS_LN && len == 6 &&
+				 starts_with(start, "target"))
+				color_symlink_as_referent = 1;
+			else
+				sprintf(ls_colors[ind_no], "\033[%.*sm",
+				       (int)len, start);
+			break;
+
+		case 4:		/* Equal sign after *.ext */
+			if (*(p++) == '=') {
+				ext->seq.string = buf;
+				state = (get_funky_string(&buf, &p, 0, &ext->seq.len)
+					 ? 1 : -1);
+			} else
+				state = -1;
+			break;
+		}
+	}
+
+	if (!strcmp(ls_colors[LS_LN], "target"))
+		color_symlink_as_referent = 1;
+}
-- 
2.2.0.60.gb7b3c64

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

* [PATCH 02/19] ls_colors.c: parse color.ls.* from config file
  2014-11-30  8:55 [PATCH 00/19] Add git-list-files Nguyễn Thái Ngọc Duy
  2014-11-30  8:55 ` [PATCH 01/19] ls_colors.c: add $LS_COLORS parsing code Nguyễn Thái Ngọc Duy
@ 2014-11-30  8:55 ` Nguyễn Thái Ngọc Duy
  2014-11-30  8:55 ` [PATCH 03/19] ls_colors.c: add a function to color a file name Nguyễn Thái Ngọc Duy
                   ` (18 subsequent siblings)
  20 siblings, 0 replies; 28+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2014-11-30  8:55 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy

This is the second (and preferred) source for color information. This
will override $LS_COLORS.

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

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 9220725..2090866 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -940,6 +940,17 @@ color.status.<slot>::
 	to red). The values of these variables may be specified as in
 	color.branch.<slot>.
 
+color.ls.<slot>::
+	Use customized color for file name colorization. If not set
+	and the environment variable LS_COLORS is set, color settings
+	from $LS_COLORS are used. `<slot>` can be `normal`, `file`,
+	`directory`, `symlink`, `fifo`, `socket`, `block`, `char`,
+	`missing`, `orphan`, `executable`, `door`, `setuid`, `setgid`,
+	`sticky`, `otherwritable`, `stickyotherwritable`, `cap`,
+	`multihardlink`. The values of these variables may be
+	specified as in color.branch.<slot>.
+
+
 color.ui::
 	This variable determines the default value for variables such
 	as `color.diff` and `color.grep` that control the use of color
diff --git a/ls_colors.c b/ls_colors.c
index eb944f4..3e35ffe 100644
--- a/ls_colors.c
+++ b/ls_colors.c
@@ -68,6 +68,14 @@ static const char *const indicator_name[] = {
 	NULL
 };
 
+static const char* const config_name[] = {
+	"", "", "", "", "normal", "file", "directory", "symlink",
+	"fifo", "socket", "block", "char", "missing", "orphan", "executable",
+	"door", "setuid", "setgid", "sticky", "otherwritable",
+	"stickyotherwritable", "cap", "multihardlink", "",
+	NULL
+};
+
 struct bin_str {
 	size_t len;			/* Number of bytes */
 	const char *string;		/* Pointer to the same */
@@ -285,6 +293,23 @@ static int get_funky_string(char **dest, const char **src, int equals_end,
 	return state != ST_ERROR;
 }
 
+static int ls_colors_config(const char *var, const char *value, void *cb)
+{
+	int slot;
+	if (!starts_with(var, "color.ls."))
+		return 0;
+	var += 9;
+	for (slot = 0; config_name[slot]; slot++)
+		if (!strcasecmp(var, config_name[slot]))
+			break;
+	if (!config_name[slot])
+		return 0;
+	if (!value)
+		return config_error_nonbool(var);
+	color_parse(value, ls_colors[slot]);
+	return 0;
+}
+
 void parse_ls_color(void)
 {
 	const char *p;			/* Pointer to character being parsed */
@@ -395,4 +420,5 @@ void parse_ls_color(void)
 
 	if (!strcmp(ls_colors[LS_LN], "target"))
 		color_symlink_as_referent = 1;
+	git_config(ls_colors_config, NULL);
 }
-- 
2.2.0.60.gb7b3c64

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

* [PATCH 03/19] ls_colors.c: add a function to color a file name
  2014-11-30  8:55 [PATCH 00/19] Add git-list-files Nguyễn Thái Ngọc Duy
  2014-11-30  8:55 ` [PATCH 01/19] ls_colors.c: add $LS_COLORS parsing code Nguyễn Thái Ngọc Duy
  2014-11-30  8:55 ` [PATCH 02/19] ls_colors.c: parse color.ls.* from config file Nguyễn Thái Ngọc Duy
@ 2014-11-30  8:55 ` Nguyễn Thái Ngọc Duy
  2014-11-30  8:55 ` [PATCH 04/19] ls_colors.c: highlight submodules like directories Nguyễn Thái Ngọc Duy
                   ` (17 subsequent siblings)
  20 siblings, 0 replies; 28+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2014-11-30  8:55 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy

The new function is based on print_color_indicator() from commit
7326d1f1a67edf21947ae98194f98c38b6e9e527 in coreutils.git.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 color.h     |  2 ++
 ls_colors.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 68 insertions(+)

diff --git a/color.h b/color.h
index 3eaa5bd..b6904a3 100644
--- a/color.h
+++ b/color.h
@@ -94,5 +94,7 @@ void color_print_strbuf(FILE *fp, const char *color, const struct strbuf *sb);
 int color_is_nil(const char *color);
 
 void parse_ls_color(void);
+void color_filename(struct strbuf *sb, const char *name,
+		    const char *display_name, mode_t mode, int linkok);
 
 #endif /* COLOR_H */
diff --git a/ls_colors.c b/ls_colors.c
index 3e35ffe..a58da9e 100644
--- a/ls_colors.c
+++ b/ls_colors.c
@@ -422,3 +422,69 @@ void parse_ls_color(void)
 		color_symlink_as_referent = 1;
 	git_config(ls_colors_config, NULL);
 }
+
+void color_filename(struct strbuf *sb, const char *name,
+		    const char *display_name, mode_t mode, int linkok)
+{
+	int type;
+	struct color_ext_type *ext;	/* Color extension */
+
+	if (S_ISREG (mode)) {
+		type = LS_FL;
+		if ((mode & S_ISUID) != 0)
+			type = LS_SU;
+		else if ((mode & S_ISGID) != 0)
+			type = LS_SG;
+		else if ((mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0)
+			type = LS_EX;
+	} else if (S_ISDIR (mode)) {
+		if ((mode & S_ISVTX) && (mode & S_IWOTH))
+			type = LS_TW;
+		else if ((mode & S_IWOTH) != 0)
+			type = LS_OW;
+		else if ((mode & S_ISVTX) != 0)
+			type = LS_ST;
+		else
+			type = LS_DI;
+	} else if (S_ISLNK (mode))
+		type = (!linkok && *ls_colors[LS_OR]) ? LS_OR : LS_LN;
+	else if (S_ISFIFO (mode))
+		type = LS_PI;
+	else if (S_ISSOCK (mode))
+		type = LS_SO;
+	else if (S_ISBLK (mode))
+		type = LS_BD;
+	else if (S_ISCHR (mode))
+		type = LS_CD;
+#ifdef S_ISDOOR
+	else if (S_ISDOOR (mode))
+		type = LS_DO;
+#endif
+	else
+		/* Classify a file of some other type as C_ORPHAN.  */
+		type = LS_OR;
+
+	/* Check the file's suffix only if still classified as C_FILE.  */
+	ext = NULL;
+	if (type == LS_FL) {
+		/* Test if NAME has a recognized suffix.  */
+		size_t len = strlen(name);
+		const char *p = name + len;		/* Pointer to final \0.  */
+		for (ext = color_ext_list; ext != NULL; ext = ext->next) {
+			if (ext->ext.len <= len &&
+			    !strncmp(p - ext->ext.len, ext->ext.string, ext->ext.len))
+				break;
+		}
+	}
+
+	if (display_name)
+		name = display_name;
+	if (ext)
+		strbuf_addf(sb, "\033[%.*sm%s%s",
+			    (int)ext->seq.len, ext->seq.string,
+			    name, GIT_COLOR_RESET);
+	else if (*ls_colors[type])
+		strbuf_addf(sb, "%s%s%s", ls_colors[type], name, GIT_COLOR_RESET);
+	else
+		strbuf_addstr(sb, name);
+}
-- 
2.2.0.60.gb7b3c64

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

* [PATCH 04/19] ls_colors.c: highlight submodules like directories
  2014-11-30  8:55 [PATCH 00/19] Add git-list-files Nguyễn Thái Ngọc Duy
                   ` (2 preceding siblings ...)
  2014-11-30  8:55 ` [PATCH 03/19] ls_colors.c: add a function to color a file name Nguyễn Thái Ngọc Duy
@ 2014-11-30  8:55 ` Nguyễn Thái Ngọc Duy
  2014-11-30  8:55 ` [PATCH 05/19] ls-files: buffer full item in strbuf before printing Nguyễn Thái Ngọc Duy
                   ` (16 subsequent siblings)
  20 siblings, 0 replies; 28+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2014-11-30  8:55 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 | 3 ++-
 ls_colors.c              | 8 +++++++-
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 2090866..2290c47 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -944,7 +944,8 @@ color.ls.<slot>::
 	Use customized color for file name colorization. If not set
 	and the environment variable LS_COLORS is set, color settings
 	from $LS_COLORS are used. `<slot>` can be `normal`, `file`,
-	`directory`, `symlink`, `fifo`, `socket`, `block`, `char`,
+	`directory`, `submodule`,
+	`symlink`, `fifo`, `socket`, `block`, `char`,
 	`missing`, `orphan`, `executable`, `door`, `setuid`, `setgid`,
 	`sticky`, `otherwritable`, `stickyotherwritable`, `cap`,
 	`multihardlink`. The values of these variables may be
diff --git a/ls_colors.c b/ls_colors.c
index a58da9e..e62e74b 100644
--- a/ls_colors.c
+++ b/ls_colors.c
@@ -29,6 +29,8 @@ enum color_ls {
 	LS_MH,			/* multi hardlink */
 	LS_CL,			/* clear end of line */
 
+	LS_SUBMODULE,
+
 	MAX_LS
 };
 
@@ -58,7 +60,8 @@ static char ls_colors[MAX_LS][COLOR_MAXLEN] = {
 	GIT_COLOR_BLACK_ON_GREEN,
 	"",
 	"",
-	""
+	"",
+	GIT_COLOR_BOLD_BLUE
 };
 
 static const char *const indicator_name[] = {
@@ -73,6 +76,7 @@ static const char* const config_name[] = {
 	"fifo", "socket", "block", "char", "missing", "orphan", "executable",
 	"door", "setuid", "setgid", "sticky", "otherwritable",
 	"stickyotherwritable", "cap", "multihardlink", "",
+	"submodule",
 	NULL
 };
 
@@ -448,6 +452,8 @@ void color_filename(struct strbuf *sb, const char *name,
 			type = LS_DI;
 	} else if (S_ISLNK (mode))
 		type = (!linkok && *ls_colors[LS_OR]) ? LS_OR : LS_LN;
+	else if (S_ISGITLINK(mode))
+		type = LS_SUBMODULE;
 	else if (S_ISFIFO (mode))
 		type = LS_PI;
 	else if (S_ISSOCK (mode))
-- 
2.2.0.60.gb7b3c64

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

* [PATCH 05/19] ls-files: buffer full item in strbuf before printing
  2014-11-30  8:55 [PATCH 00/19] Add git-list-files Nguyễn Thái Ngọc Duy
                   ` (3 preceding siblings ...)
  2014-11-30  8:55 ` [PATCH 04/19] ls_colors.c: highlight submodules like directories Nguyễn Thái Ngọc Duy
@ 2014-11-30  8:55 ` Nguyễn Thái Ngọc Duy
  2014-11-30  8:55 ` [PATCH 06/19] ls-files: add --color to highlight file names Nguyễn Thái Ngọc Duy
                   ` (15 subsequent siblings)
  20 siblings, 0 replies; 28+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2014-11-30  8:55 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy

Buffering so that we can manipulate the strings (e.g. coloring)
further before finally printing them.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/ls-files.c | 48 +++++++++++++++++++++++++++++++++++-------------
 1 file changed, 35 insertions(+), 13 deletions(-)

diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 99cee20..f20c0fd 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -47,18 +47,30 @@ static const char *tag_modified = "";
 static const char *tag_skip_worktree = "";
 static const char *tag_resolve_undo = "";
 
-static void write_name(const char *name)
+static void write_name(struct strbuf *sb, const char *name)
 {
 	/*
 	 * With "--full-name", prefix_len=0; this caller needs to pass
 	 * an empty string in that case (a NULL is good for "").
 	 */
-	write_name_quoted_relative(name, prefix_len ? prefix : NULL,
-				   stdout, line_terminator);
+	const char *real_prefix = prefix_len ? prefix : NULL;
+	if (!line_terminator) {
+		struct strbuf sb2 = STRBUF_INIT;
+		strbuf_addstr(sb, relative_path(name, real_prefix, &sb2));
+		strbuf_release(&sb2);
+	} else
+		quote_path_relative(name, real_prefix, sb);
+	strbuf_addch(sb, line_terminator);
+}
+
+static void strbuf_fputs(struct strbuf *sb, FILE *fp)
+{
+	fwrite(sb->buf, sb->len, 1, fp);
 }
 
 static void show_dir_entry(const char *tag, struct dir_entry *ent)
 {
+	static struct strbuf sb = STRBUF_INIT;
 	int len = max_prefix_len;
 
 	if (len >= ent->len)
@@ -67,8 +79,10 @@ static void show_dir_entry(const char *tag, struct dir_entry *ent)
 	if (!dir_path_match(ent, &pathspec, len, ps_matched))
 		return;
 
-	fputs(tag, stdout);
-	write_name(ent->name);
+	strbuf_reset(&sb);
+	strbuf_addstr(&sb, tag);
+	write_name(&sb, ent->name);
+	strbuf_fputs(&sb, stdout);
 }
 
 static void show_other_files(struct dir_struct *dir)
@@ -134,6 +148,7 @@ static void show_killed_files(struct dir_struct *dir)
 
 static void show_ce_entry(const char *tag, const struct cache_entry *ce)
 {
+	static struct strbuf sb = STRBUF_INIT;
 	int len = max_prefix_len;
 
 	if (len >= ce_namelen(ce))
@@ -161,16 +176,18 @@ static void show_ce_entry(const char *tag, const struct cache_entry *ce)
 		tag = alttag;
 	}
 
+	strbuf_reset(&sb);
 	if (!show_stage) {
-		fputs(tag, stdout);
+		strbuf_addstr(&sb, tag);
 	} else {
-		printf("%s%06o %s %d\t",
-		       tag,
-		       ce->ce_mode,
-		       find_unique_abbrev(ce->sha1,abbrev),
-		       ce_stage(ce));
+		strbuf_addf(&sb, "%s%06o %s %d\t",
+			    tag,
+			    ce->ce_mode,
+			    find_unique_abbrev(ce->sha1,abbrev),
+			    ce_stage(ce));
 	}
-	write_name(ce->name);
+	write_name(&sb, ce->name);
+	strbuf_fputs(&sb, stdout);
 	if (debug_mode) {
 		const struct stat_data *sd = &ce->ce_stat_data;
 
@@ -206,7 +223,12 @@ static void show_ru_info(void)
 			printf("%s%06o %s %d\t", tag_resolve_undo, ui->mode[i],
 			       find_unique_abbrev(ui->sha1[i], abbrev),
 			       i + 1);
-			write_name(path);
+			/*
+			 * With "--full-name", prefix_len=0; this caller needs to pass
+			 * an empty string in that case (a NULL is good for "").
+			 */
+			write_name_quoted_relative(path, prefix_len ? prefix : NULL,
+						   stdout, line_terminator);
 		}
 	}
 }
-- 
2.2.0.60.gb7b3c64

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

* [PATCH 06/19] ls-files: add --color to highlight file names
  2014-11-30  8:55 [PATCH 00/19] Add git-list-files Nguyễn Thái Ngọc Duy
                   ` (4 preceding siblings ...)
  2014-11-30  8:55 ` [PATCH 05/19] ls-files: buffer full item in strbuf before printing Nguyễn Thái Ngọc Duy
@ 2014-11-30  8:55 ` Nguyễn Thái Ngọc Duy
  2014-11-30  8:55 ` [PATCH 07/19] ls-files: add --column Nguyễn Thái Ngọc Duy
                   ` (14 subsequent siblings)
  20 siblings, 0 replies; 28+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2014-11-30  8:55 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/git-ls-files.txt |  7 +++++++
 builtin/ls-files.c             | 38 +++++++++++++++++++++++++++++++++++---
 2 files changed, 42 insertions(+), 3 deletions(-)

diff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt
index e26f01f..148f226 100644
--- a/Documentation/git-ls-files.txt
+++ b/Documentation/git-ls-files.txt
@@ -147,6 +147,13 @@ a space) at the start of each line:
 	possible for manual inspection; the exact format may change at
 	any time.
 
+--color[=<when>]::
+--no-color::
+	Color file names. The value must be `always`, `never`, or
+	`auto`. `--no-color` is equivalent to
+	`--color=never`. `--color` is equivalent to
+	`--color=auto`.
+
 \--::
 	Do not interpret any more arguments as options.
 
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index f20c0fd..4ddd49f 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -14,6 +14,7 @@
 #include "resolve-undo.h"
 #include "string-list.h"
 #include "pathspec.h"
+#include "color.h"
 
 static int abbrev;
 static int show_deleted;
@@ -27,6 +28,7 @@ static int show_killed;
 static int show_valid_bit;
 static int line_terminator = '\n';
 static int debug_mode;
+static int use_color;
 
 static const char *prefix;
 static int max_prefix_len;
@@ -60,7 +62,6 @@ static void write_name(struct strbuf *sb, const char *name)
 		strbuf_release(&sb2);
 	} else
 		quote_path_relative(name, real_prefix, sb);
-	strbuf_addch(sb, line_terminator);
 }
 
 static void strbuf_fputs(struct strbuf *sb, FILE *fp)
@@ -68,6 +69,21 @@ static void strbuf_fputs(struct strbuf *sb, FILE *fp)
 	fwrite(sb->buf, sb->len, 1, fp);
 }
 
+static void write_dir_entry(struct strbuf *sb, const struct dir_entry *ent)
+{
+	struct strbuf quoted = STRBUF_INIT;
+	struct stat st;
+	if (stat(ent->name, &st))
+		st.st_mode = 0;
+	write_name(&quoted, ent->name);
+	if (want_color(use_color))
+		color_filename(sb, ent->name, quoted.buf, st.st_mode, 1);
+	else
+		strbuf_addbuf(sb, &quoted);
+	strbuf_addch(sb, line_terminator);
+	strbuf_release(&quoted);
+}
+
 static void show_dir_entry(const char *tag, struct dir_entry *ent)
 {
 	static struct strbuf sb = STRBUF_INIT;
@@ -81,7 +97,7 @@ static void show_dir_entry(const char *tag, struct dir_entry *ent)
 
 	strbuf_reset(&sb);
 	strbuf_addstr(&sb, tag);
-	write_name(&sb, ent->name);
+	write_dir_entry(&sb, ent);
 	strbuf_fputs(&sb, stdout);
 }
 
@@ -146,6 +162,18 @@ static void show_killed_files(struct dir_struct *dir)
 	}
 }
 
+static void write_ce_name(struct strbuf *sb, const struct cache_entry *ce)
+{
+	struct strbuf quoted = STRBUF_INIT;
+	write_name(&quoted, ce->name);
+	if (want_color(use_color))
+		color_filename(sb, ce->name, quoted.buf, ce->ce_mode, 1);
+	else
+		strbuf_addbuf(sb, &quoted);
+	strbuf_addch(sb, line_terminator);
+	strbuf_release(&quoted);
+}
+
 static void show_ce_entry(const char *tag, const struct cache_entry *ce)
 {
 	static struct strbuf sb = STRBUF_INIT;
@@ -186,7 +214,7 @@ static void show_ce_entry(const char *tag, const struct cache_entry *ce)
 			    find_unique_abbrev(ce->sha1,abbrev),
 			    ce_stage(ce));
 	}
-	write_name(&sb, ce->name);
+	write_ce_name(&sb, ce);
 	strbuf_fputs(&sb, stdout);
 	if (debug_mode) {
 		const struct stat_data *sd = &ce->ce_stat_data;
@@ -523,6 +551,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 			N_("if any <file> is not in the index, treat this as an error")),
 		OPT_STRING(0, "with-tree", &with_tree, N_("tree-ish"),
 			N_("pretend that paths removed since <tree-ish> are still present")),
+		OPT__COLOR(&use_color, N_("show color")),
 		OPT__ABBREV(&abbrev),
 		OPT_BOOL(0, "debug", &debug_mode, N_("show debugging data")),
 		OPT_END()
@@ -570,6 +599,9 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 	if (require_work_tree && !is_inside_work_tree())
 		setup_work_tree();
 
+	if (want_color(use_color))
+		parse_ls_color();
+
 	parse_pathspec(&pathspec, 0,
 		       PATHSPEC_PREFER_CWD |
 		       PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP,
-- 
2.2.0.60.gb7b3c64

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

* [PATCH 07/19] ls-files: add --column
  2014-11-30  8:55 [PATCH 00/19] Add git-list-files Nguyễn Thái Ngọc Duy
                   ` (5 preceding siblings ...)
  2014-11-30  8:55 ` [PATCH 06/19] ls-files: add --color to highlight file names Nguyễn Thái Ngọc Duy
@ 2014-11-30  8:55 ` Nguyễn Thái Ngọc Duy
  2014-11-30  8:55 ` [PATCH 08/19] ls-files: support --max-depth Nguyễn Thái Ngọc Duy
                   ` (13 subsequent siblings)
  20 siblings, 0 replies; 28+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2014-11-30  8:55 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/git-ls-files.txt |  6 ++++++
 builtin/ls-files.c             | 28 ++++++++++++++++++++++++++++
 2 files changed, 34 insertions(+)

diff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt
index 148f226..99328b9 100644
--- a/Documentation/git-ls-files.txt
+++ b/Documentation/git-ls-files.txt
@@ -154,6 +154,12 @@ a space) at the start of each line:
 	`--color=never`. `--color` is equivalent to
 	`--color=auto`.
 
+--column[=<options>]::
+--no-column::
+	Display files in columns. See configuration variable column.ui
+	for option syntax. `--column` and `--no-column` without options
+	are equivalent to 'always' and 'never' respectively.
+
 \--::
 	Do not interpret any more arguments as options.
 
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 4ddd49f..79e1944 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -15,6 +15,7 @@
 #include "string-list.h"
 #include "pathspec.h"
 #include "color.h"
+#include "column.h"
 
 static int abbrev;
 static int show_deleted;
@@ -29,6 +30,7 @@ static int show_valid_bit;
 static int line_terminator = '\n';
 static int debug_mode;
 static int use_color;
+static unsigned int colopts;
 
 static const char *prefix;
 static int max_prefix_len;
@@ -39,6 +41,7 @@ static char *ps_matched;
 static const char *with_tree;
 static int exc_given;
 static int exclude_args;
+static struct string_list output = STRING_LIST_INIT_NODUP;
 
 static const char *tag_cached = "";
 static const char *tag_unmerged = "";
@@ -66,6 +69,10 @@ static void write_name(struct strbuf *sb, const char *name)
 
 static void strbuf_fputs(struct strbuf *sb, FILE *fp)
 {
+	if (column_active(colopts)) {
+		string_list_append(&output, strbuf_detach(sb, NULL));
+		return;
+	}
 	fwrite(sb->buf, sb->len, 1, fp);
 }
 
@@ -552,6 +559,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 		OPT_STRING(0, "with-tree", &with_tree, N_("tree-ish"),
 			N_("pretend that paths removed since <tree-ish> are still present")),
 		OPT__COLOR(&use_color, N_("show color")),
+		OPT_COLUMN(0, "column", &colopts, N_("show files in columns")),
 		OPT__ABBREV(&abbrev),
 		OPT_BOOL(0, "debug", &debug_mode, N_("show debugging data")),
 		OPT_END()
@@ -596,6 +604,18 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 	if (dir.exclude_per_dir)
 		exc_given = 1;
 
+	finalize_colopts(&colopts, -1);
+	if (explicitly_enable_column(colopts)) {
+		if (!line_terminator)
+			die(_("--column and -z are incompatible"));
+		if (show_resolve_undo)
+			die(_("--column and --resolve-undo are incompatible"));
+		if (debug_mode)
+			die(_("--column and --debug are incompatible"));
+	}
+	if (column_active(colopts))
+		line_terminator = 0;
+
 	if (require_work_tree && !is_inside_work_tree())
 		setup_work_tree();
 
@@ -638,6 +658,14 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 	if (show_resolve_undo)
 		show_ru_info();
 
+	if (column_active(colopts)) {
+		struct column_options copts;
+		memset(&copts, 0, sizeof(copts));
+		copts.padding = 2;
+		print_columns(&output, colopts, &copts);
+		string_list_clear(&output, 0);
+	}
+
 	if (ps_matched) {
 		int bad;
 		bad = report_path_error(ps_matched, &pathspec, prefix);
-- 
2.2.0.60.gb7b3c64

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

* [PATCH 08/19] ls-files: support --max-depth
  2014-11-30  8:55 [PATCH 00/19] Add git-list-files Nguyễn Thái Ngọc Duy
                   ` (6 preceding siblings ...)
  2014-11-30  8:55 ` [PATCH 07/19] ls-files: add --column Nguyễn Thái Ngọc Duy
@ 2014-11-30  8:55 ` Nguyễn Thái Ngọc Duy
  2014-11-30  8:55 ` [PATCH 09/19] Add git-list-files, a user friendly version of ls-files and more Nguyễn Thái Ngọc Duy
                   ` (12 subsequent siblings)
  20 siblings, 0 replies; 28+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2014-11-30  8:55 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/git-ls-files.txt | 7 +++++++
 builtin/ls-files.c             | 7 +++++++
 2 files changed, 14 insertions(+)

diff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt
index 99328b9..3d921eb 100644
--- a/Documentation/git-ls-files.txt
+++ b/Documentation/git-ls-files.txt
@@ -160,6 +160,13 @@ a space) at the start of each line:
 	for option syntax. `--column` and `--no-column` without options
 	are equivalent to 'always' and 'never' respectively.
 
+--max-depth=<depth>::
+	For each <pathspec> given on command line, descend at most <depth>
+	levels of directories. A negative value means no limit (default).
+	This option is ignored if <pathspec> contains active wildcards.
+	In other words if "a*" matches a directory named "a*",
+	"*" is matched literally so --max-depth is still effective.
+
 \--::
 	Do not interpret any more arguments as options.
 
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 79e1944..40fe0f2 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -503,6 +503,7 @@ static int option_parse_exclude_standard(const struct option *opt,
 int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 {
 	int require_work_tree = 0, show_tag = 0, i;
+	int max_depth = -1;
 	const char *max_prefix;
 	struct dir_struct dir;
 	struct exclude_list *el;
@@ -560,6 +561,9 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 			N_("pretend that paths removed since <tree-ish> are still present")),
 		OPT__COLOR(&use_color, N_("show color")),
 		OPT_COLUMN(0, "column", &colopts, N_("show files in columns")),
+		{ OPTION_INTEGER, 0, "max-depth", &max_depth, N_("depth"),
+			N_("descend at most <depth> levels"), PARSE_OPT_NONEG,
+			NULL, 1 },
 		OPT__ABBREV(&abbrev),
 		OPT_BOOL(0, "debug", &debug_mode, N_("show debugging data")),
 		OPT_END()
@@ -624,8 +628,11 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 
 	parse_pathspec(&pathspec, 0,
 		       PATHSPEC_PREFER_CWD |
+		       (max_depth != -1 ? PATHSPEC_MAXDEPTH_VALID : 0) |
 		       PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP,
 		       prefix, argv);
+	pathspec.max_depth = max_depth;
+	pathspec.recursive = 1;
 
 	/* Find common prefix for all pathspec's */
 	max_prefix = common_prefix(&pathspec);
-- 
2.2.0.60.gb7b3c64

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

* [PATCH 09/19] Add git-list-files, a user friendly version of ls-files and more
  2014-11-30  8:55 [PATCH 00/19] Add git-list-files Nguyễn Thái Ngọc Duy
                   ` (7 preceding siblings ...)
  2014-11-30  8:55 ` [PATCH 08/19] ls-files: support --max-depth Nguyễn Thái Ngọc Duy
@ 2014-11-30  8:55 ` Nguyễn Thái Ngọc Duy
  2014-12-02  2:50   ` Eric Sunshine
  2014-11-30  8:55 ` [PATCH 10/19] list-files: -u does not imply showing stages Nguyễn Thái Ngọc Duy
                   ` (11 subsequent siblings)
  20 siblings, 1 reply; 28+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2014-11-30  8:55 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy

This is more user friendly version of ls-files:

* it's automatically colored and columnized
* it refreshes the index like all porcelain commands
* it defaults to non-recursive behavior like ls
* :(glob) is on by default so '*.c' means a.c but not a/b.c, use
  '**/*.c' for that.
* auto pager

The name 'ls' is not taken. It is left for the user to make an alias
with better default options.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 .gitignore                             |  1 +
 Documentation/config.txt               | 10 +++++
 Documentation/git-list-files.txt (new) | 80 ++++++++++++++++++++++++++++++++++
 Makefile                               |  1 +
 builtin/ls-files.c                     | 69 +++++++++++++++++++++++++++--
 command-list.txt                       |  1 +
 git.c                                  |  1 +
 7 files changed, 159 insertions(+), 4 deletions(-)
 create mode 100644 Documentation/git-list-files.txt

diff --git a/.gitignore b/.gitignore
index a052419..9727ecc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -76,6 +76,7 @@
 /git-init-db
 /git-interpret-trailers
 /git-instaweb
+/git-list-files
 /git-log
 /git-ls-files
 /git-ls-remote
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 2290c47..74da715 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -940,6 +940,12 @@ color.status.<slot>::
 	to red). The values of these variables may be specified as in
 	color.branch.<slot>.
 
+color.list-files::
+	A boolean to enable/disable color in the output of
+	linkgit:git-list-files[1]. May be set to `always`, `false` (or
+	`never`) or `auto` (or `true`), in which case colors are used
+	only when the output is to a terminal. Defaults to false.
+
 color.ls.<slot>::
 	Use customized color for file name colorization. If not set
 	and the environment variable LS_COLORS is set, color settings
@@ -1012,6 +1018,10 @@ column.clean::
 	Specify the layout when list items in `git clean -i`, which always
 	shows files and directories in columns. See `column.ui` for details.
 
+column.list-files::
+	Specify whether to output tag listing in `git list-files` 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.
diff --git a/Documentation/git-list-files.txt b/Documentation/git-list-files.txt
new file mode 100644
index 0000000..3039e1e
--- /dev/null
+++ b/Documentation/git-list-files.txt
@@ -0,0 +1,80 @@
+git-list-files(1)
+===============
+
+NAME
+----
+git-list-files - List files
+
+SYNOPSIS
+--------
+[verse]
+'git list-files [options] [<pathspec>...]
+
+DESCRIPTION
+-----------
+List files (by default in current working directory) that are in the
+index. Depending on the chosen options, maybe only modified files in
+working tree are shown, or untracked files...
+
+OPTIONS
+-------
+-c::
+--cached::
+	Show cached files (default)
+
+-d::
+--deleted::
+	Show cached files that are deleted on working directory
+
+-m::
+--modified::
+	Show cached files that have modification on working directory
+
+-o::
+--others::
+	Show untracked files (and only unignored ones unless -i is
+	specified)
+
+-i::
+--ignored::
+	Show only ignored files. When showing files in the index,
+	print only those matched by an exclude pattern. When showing
+	"other" files, show only those matched by an exclude pattern.
+
+-u::
+--unmerged::
+	Show unmerged files
+
+--color[=<when>]::
+--no-color::
+	Color file names. The value must be `always`, `never`, or
+	`auto`. `--no-color` is equivalent to
+	`--color=never`. `--color` is equivalent to
+	`--color=auto`. See configuration variable `color.list-files`
+	for the default settings.
+
+--column[=<options>]::
+--no-column::
+	Display files in columns. See configuration variable column.ui
+	for option syntax. `--column` and `--no-column` without options
+	are equivalent to 'always' and 'never' respectively.
+
+--max-depth=<depth>::
+	For each <pathspec> given on command line, descend at most <depth>
+	levels of directories. A negative value means no limit.
+	This option is ignored if <pathspec> contains active wildcards.
+	In other words if "a*" matches a directory named "a*",
+	"*" is matched literally so --max-depth is still effective.
+	The default is `--max-depth=0`.
+
+<pathspec>::
+	Files to show. :(glob) magic is enabled and recursion disabled
+	by default.
+
+SEE ALSO
+--------
+linkgit:git-ls-files[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Makefile b/Makefile
index 459121d..23a0751 100644
--- a/Makefile
+++ b/Makefile
@@ -587,6 +587,7 @@ BUILT_INS += git-cherry-pick$X
 BUILT_INS += git-format-patch$X
 BUILT_INS += git-fsck-objects$X
 BUILT_INS += git-init$X
+BUILT_INS += git-list-files$X
 BUILT_INS += git-merge-subtree$X
 BUILT_INS += git-show$X
 BUILT_INS += git-stage$X
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 40fe0f2..f3873a8 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -31,6 +31,7 @@ static int line_terminator = '\n';
 static int debug_mode;
 static int use_color;
 static unsigned int colopts;
+static int porcelain;
 
 static const char *prefix;
 static int max_prefix_len;
@@ -459,6 +460,11 @@ static const char * const ls_files_usage[] = {
 	NULL
 };
 
+static const char * const ls_usage[] = {
+	N_("git list-files [options] [<file>...]"),
+	NULL
+};
+
 static int option_parse_z(const struct option *opt,
 			  const char *arg, int unset)
 {
@@ -500,6 +506,17 @@ static int option_parse_exclude_standard(const struct option *opt,
 	return 0;
 }
 
+static int git_ls_config(const char *var, const char *value, void *cb)
+{
+	if (starts_with(var, "column."))
+		return git_column_config(var, value, "list-files", &colopts);
+	if (!strcmp(var, "color.list-files")) {
+		use_color = git_config_colorbool(var, value);
+		return 0;
+	}
+	return git_color_default_config(var, value, cb);
+}
+
 int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 {
 	int require_work_tree = 0, show_tag = 0, i;
@@ -568,21 +585,61 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 		OPT_BOOL(0, "debug", &debug_mode, N_("show debugging data")),
 		OPT_END()
 	};
+	struct option builtin_ls_options[] = {
+		OPT_BOOL('c', "cached", &show_cached,
+			N_("show cached files (default)")),
+		OPT_BOOL('d', "deleted", &show_deleted,
+			N_("show cached files that are deleted on working directory")),
+		OPT_BOOL('m', "modified", &show_modified,
+			N_("show cached files that have modification on working directory")),
+		OPT_BOOL('o', "others", &show_others,
+			N_("show untracked files")),
+		OPT_BIT('i', "ignored", &dir.flags,
+			N_("show ignored files"),
+			DIR_SHOW_IGNORED),
+		OPT_BOOL('u', "unmerged", &show_unmerged,
+			N_("show unmerged files")),
+		OPT__COLOR(&use_color, N_("show color")),
+		OPT_COLUMN(0, "column", &colopts, N_("show files in columns")),
+		{ OPTION_INTEGER, 0, "max-depth", &max_depth, N_("depth"),
+			N_("descend at most <depth> levels"), PARSE_OPT_NONEG,
+			NULL, 1 },
+		OPT__ABBREV(&abbrev),
+		OPT_END()
+	};
+	struct option *options;
+	const char * const *help_usage;
 
+	if (!strcmp(argv[0], "list-files")) {
+		help_usage = ls_usage;
+		options = builtin_ls_options;
+		porcelain = 1;
+	} else {
+		help_usage = ls_files_usage;
+		options = builtin_ls_files_options;
+	}
 	if (argc == 2 && !strcmp(argv[1], "-h"))
-		usage_with_options(ls_files_usage, builtin_ls_files_options);
+		usage_with_options(help_usage, options);
 
 	memset(&dir, 0, sizeof(dir));
 	prefix = cmd_prefix;
 	if (prefix)
 		prefix_len = strlen(prefix);
-	git_config(git_default_config, NULL);
+
+	if (porcelain) {
+		setenv(GIT_GLOB_PATHSPECS_ENVIRONMENT, "1", 1);
+		exc_given = 1;
+		setup_standard_excludes(&dir);
+		use_color = -1;
+		max_depth = 0;
+		git_config(git_ls_config, NULL);
+	} else
+		git_config(git_default_config, NULL);
 
 	if (read_cache() < 0)
 		die("index file corrupt");
 
-	argc = parse_options(argc, argv, prefix, builtin_ls_files_options,
-			ls_files_usage, 0);
+	argc = parse_options(argc, argv, prefix, options, help_usage, 0);
 	el = add_exclude_list(&dir, EXC_CMDL, "--exclude option");
 	for (i = 0; i < exclude_list.nr; i++) {
 		add_exclude(exclude_list.items[i].string, "", 0, el, --exclude_args);
@@ -661,6 +718,10 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 			die("ls-files --with-tree is incompatible with -s or -u");
 		overlay_tree_on_cache(with_tree, max_prefix);
 	}
+	if (porcelain) {
+		refresh_index(&the_index, REFRESH_QUIET, &pathspec, NULL, NULL);
+		setup_pager();
+	}
 	show_files(&dir);
 	if (show_resolve_undo)
 		show_ru_info();
diff --git a/command-list.txt b/command-list.txt
index f1eae08..32101de 100644
--- a/command-list.txt
+++ b/command-list.txt
@@ -64,6 +64,7 @@ git-init                                mainporcelain common
 git-instaweb                            ancillaryinterrogators
 git-interpret-trailers                  purehelpers
 gitk                                    mainporcelain
+git-list-files                          mainporcelain
 git-log                                 mainporcelain common
 git-ls-files                            plumbinginterrogators
 git-ls-remote                           plumbinginterrogators
diff --git a/git.c b/git.c
index 18fbf79..617c083 100644
--- a/git.c
+++ b/git.c
@@ -418,6 +418,7 @@ static struct cmd_struct commands[] = {
 	{ "init", cmd_init_db, NO_SETUP },
 	{ "init-db", cmd_init_db, NO_SETUP },
 	{ "interpret-trailers", cmd_interpret_trailers, RUN_SETUP },
+	{ "list-files", cmd_ls_files, RUN_SETUP },
 	{ "log", cmd_log, RUN_SETUP },
 	{ "ls-files", cmd_ls_files, RUN_SETUP },
 	{ "ls-remote", cmd_ls_remote, RUN_SETUP_GENTLY },
-- 
2.2.0.60.gb7b3c64

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

* [PATCH 10/19] list-files: -u does not imply showing stages
  2014-11-30  8:55 [PATCH 00/19] Add git-list-files Nguyễn Thái Ngọc Duy
                   ` (8 preceding siblings ...)
  2014-11-30  8:55 ` [PATCH 09/19] Add git-list-files, a user friendly version of ls-files and more Nguyễn Thái Ngọc Duy
@ 2014-11-30  8:55 ` Nguyễn Thái Ngọc Duy
  2014-11-30  8:55 ` [PATCH 11/19] list-files: add -R/--recursive short for --max-depth=-1 Nguyễn Thái Ngọc Duy
                   ` (10 subsequent siblings)
  20 siblings, 0 replies; 28+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2014-11-30  8:55 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy

Showing full index entry information is something for ls-files
only. The users of "git list-files" may just want to know what entries
are not unmerged.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/ls-files.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index f3873a8..f2b62b5 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -656,7 +656,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 	}
 	if (show_modified || show_others || show_deleted || (dir.flags & DIR_SHOW_IGNORED) || show_killed)
 		require_work_tree = 1;
-	if (show_unmerged)
+	if (show_unmerged && !porcelain)
 		/*
 		 * There's no point in showing unmerged unless
 		 * you also show the stage information.
-- 
2.2.0.60.gb7b3c64

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

* [PATCH 11/19] list-files: add -R/--recursive short for --max-depth=-1
  2014-11-30  8:55 [PATCH 00/19] Add git-list-files Nguyễn Thái Ngọc Duy
                   ` (9 preceding siblings ...)
  2014-11-30  8:55 ` [PATCH 10/19] list-files: -u does not imply showing stages Nguyễn Thái Ngọc Duy
@ 2014-11-30  8:55 ` Nguyễn Thái Ngọc Duy
  2014-11-30  8:56 ` [PATCH 12/19] list-files: add -1 short for --no-column Nguyễn Thái Ngọc Duy
                   ` (9 subsequent siblings)
  20 siblings, 0 replies; 28+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2014-11-30  8:55 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/git-list-files.txt | 4 ++++
 builtin/ls-files.c               | 2 ++
 2 files changed, 6 insertions(+)

diff --git a/Documentation/git-list-files.txt b/Documentation/git-list-files.txt
index 3039e1e..5dccbbc 100644
--- a/Documentation/git-list-files.txt
+++ b/Documentation/git-list-files.txt
@@ -45,6 +45,10 @@ OPTIONS
 --unmerged::
 	Show unmerged files
 
+-R::
+--recursive::
+	Equivalent of `--max-depth=-1` (infinite recursion).
+
 --color[=<when>]::
 --no-color::
 	Color file names. The value must be `always`, `never`, or
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index f2b62b5..d0d39bd 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -594,6 +594,8 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 			N_("show cached files that have modification on working directory")),
 		OPT_BOOL('o', "others", &show_others,
 			N_("show untracked files")),
+		OPT_SET_INT('R', "recursive", &max_depth,
+			    N_("shortcut for --max-depth=-1"), -1),
 		OPT_BIT('i', "ignored", &dir.flags,
 			N_("show ignored files"),
 			DIR_SHOW_IGNORED),
-- 
2.2.0.60.gb7b3c64

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

* [PATCH 12/19] list-files: add -1 short for --no-column
  2014-11-30  8:55 [PATCH 00/19] Add git-list-files Nguyễn Thái Ngọc Duy
                   ` (10 preceding siblings ...)
  2014-11-30  8:55 ` [PATCH 11/19] list-files: add -R/--recursive short for --max-depth=-1 Nguyễn Thái Ngọc Duy
@ 2014-11-30  8:56 ` Nguyễn Thái Ngọc Duy
  2014-11-30  8:56 ` [PATCH 13/19] list-files: add -t back Nguyễn Thái Ngọc Duy
                   ` (8 subsequent siblings)
  20 siblings, 0 replies; 28+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2014-11-30  8:56 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/git-list-files.txt | 3 +++
 builtin/ls-files.c               | 2 ++
 2 files changed, 5 insertions(+)

diff --git a/Documentation/git-list-files.txt b/Documentation/git-list-files.txt
index 5dccbbc..725a236 100644
--- a/Documentation/git-list-files.txt
+++ b/Documentation/git-list-files.txt
@@ -49,6 +49,9 @@ OPTIONS
 --recursive::
 	Equivalent of `--max-depth=-1` (infinite recursion).
 
+-1::
+	Equivalent of --no-column.
+
 --color[=<when>]::
 --no-color::
 	Color file names. The value must be `always`, `never`, or
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index d0d39bd..be9a39c 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -603,6 +603,8 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 			N_("show unmerged files")),
 		OPT__COLOR(&use_color, N_("show color")),
 		OPT_COLUMN(0, "column", &colopts, N_("show files in columns")),
+		OPT_SET_INT('1', NULL, &colopts,
+			    N_("shortcut for --no-column"), COL_PARSEOPT),
 		{ OPTION_INTEGER, 0, "max-depth", &max_depth, N_("depth"),
 			N_("descend at most <depth> levels"), PARSE_OPT_NONEG,
 			NULL, 1 },
-- 
2.2.0.60.gb7b3c64

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

* [PATCH 13/19] list-files: add -t back
  2014-11-30  8:55 [PATCH 00/19] Add git-list-files Nguyễn Thái Ngọc Duy
                   ` (11 preceding siblings ...)
  2014-11-30  8:56 ` [PATCH 12/19] list-files: add -1 short for --no-column Nguyễn Thái Ngọc Duy
@ 2014-11-30  8:56 ` Nguyễn Thái Ngọc Duy
  2014-11-30  8:56 ` [PATCH 14/19] list-files: sort output and remove duplicates Nguyễn Thái Ngọc Duy
                   ` (7 subsequent siblings)
  20 siblings, 0 replies; 28+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2014-11-30  8:56 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy

Tag "H" (cached) is not shown though because it's usually the majority
and becomes noise. Not showing it makes the other tags stand out. -t
is on by default if more than one file category is selected.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/git-list-files.txt |  6 ++++++
 builtin/ls-files.c               | 27 +++++++++++++++++----------
 2 files changed, 23 insertions(+), 10 deletions(-)

diff --git a/Documentation/git-list-files.txt b/Documentation/git-list-files.txt
index 725a236..0ef616b 100644
--- a/Documentation/git-list-files.txt
+++ b/Documentation/git-list-files.txt
@@ -45,6 +45,12 @@ OPTIONS
 --unmerged::
 	Show unmerged files
 
+-t::
+--[no-]tag::
+	Show a tag to indicate file type. Automatically turned on with
+	multiple file selections. See linkgit::git-ls-files[1] option
+	`-t` for more information.
+
 -R::
 --recursive::
 	Equivalent of `--max-depth=-1` (infinite recursion).
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index be9a39c..c7aaade 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -596,6 +596,8 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 			N_("show untracked files")),
 		OPT_SET_INT('R', "recursive", &max_depth,
 			    N_("shortcut for --max-depth=-1"), -1),
+		OPT_BOOL('t', "tag", &show_tag,
+			N_("identify the file status with tags")),
 		OPT_BIT('i', "ignored", &dir.flags,
 			N_("show ignored files"),
 			DIR_SHOW_IGNORED),
@@ -636,6 +638,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 		setup_standard_excludes(&dir);
 		use_color = -1;
 		max_depth = 0;
+		show_tag = -1;
 		git_config(git_ls_config, NULL);
 	} else
 		git_config(git_default_config, NULL);
@@ -648,16 +651,6 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 	for (i = 0; i < exclude_list.nr; i++) {
 		add_exclude(exclude_list.items[i].string, "", 0, el, --exclude_args);
 	}
-	if (show_tag || show_valid_bit) {
-		tag_cached = "H ";
-		tag_unmerged = "M ";
-		tag_removed = "R ";
-		tag_modified = "C ";
-		tag_other = "? ";
-		tag_killed = "K ";
-		tag_skip_worktree = "S ";
-		tag_resolve_undo = "U ";
-	}
 	if (show_modified || show_others || show_deleted || (dir.flags & DIR_SHOW_IGNORED) || show_killed)
 		require_work_tree = 1;
 	if (show_unmerged && !porcelain)
@@ -711,6 +704,20 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 	      show_killed || show_modified || show_resolve_undo))
 		show_cached = 1;
 
+	if (show_tag == -1)
+		show_tag = (show_cached + show_deleted + show_others +
+			    show_unmerged + show_killed + show_modified) > 1;
+	if (show_tag || show_valid_bit) {
+		tag_cached = porcelain ? "  " : "H ";
+		tag_unmerged = "M ";
+		tag_removed = "R ";
+		tag_modified = "C ";
+		tag_other = "? ";
+		tag_killed = "K ";
+		tag_skip_worktree = "S ";
+		tag_resolve_undo = "U ";
+	}
+
 	if (max_prefix)
 		prune_cache(max_prefix);
 	if (with_tree) {
-- 
2.2.0.60.gb7b3c64

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

* [PATCH 14/19] list-files: sort output and remove duplicates
  2014-11-30  8:55 [PATCH 00/19] Add git-list-files Nguyễn Thái Ngọc Duy
                   ` (12 preceding siblings ...)
  2014-11-30  8:56 ` [PATCH 13/19] list-files: add -t back Nguyễn Thái Ngọc Duy
@ 2014-11-30  8:56 ` Nguyễn Thái Ngọc Duy
  2014-11-30  8:56 ` [PATCH 15/19] list-files: do not show duplicate cached entries Nguyễn Thái Ngọc Duy
                   ` (6 subsequent siblings)
  20 siblings, 0 replies; 28+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2014-11-30  8:56 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy

When you mix different file types, with ls-files you may get separate
listing. For example, "ls-files -cm" will show file "abc" twice: one
as part of cached list, one of modified list. With "ls" (and this
patch) they will be in a single sorted list (easier for the eye).

Duplicate entries are also removed. Note that display content is
compared, so if you have "-t" on, or you color file types differently,
you will get duplicate textual entries. This is good imo.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/ls-files.c | 36 ++++++++++++++++++++++++------------
 1 file changed, 24 insertions(+), 12 deletions(-)

diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index c7aaade..42c530d 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -53,6 +53,13 @@ static const char *tag_modified = "";
 static const char *tag_skip_worktree = "";
 static const char *tag_resolve_undo = "";
 
+static int compare_output(const void *a_, const void *b_)
+{
+	const struct string_list_item *a = a_;
+	const struct string_list_item *b = b_;
+	return strcmp(a->util, b->util);
+}
+
 static void write_name(struct strbuf *sb, const char *name)
 {
 	/*
@@ -68,10 +75,12 @@ static void write_name(struct strbuf *sb, const char *name)
 		quote_path_relative(name, real_prefix, sb);
 }
 
-static void strbuf_fputs(struct strbuf *sb, FILE *fp)
+static void strbuf_fputs(struct strbuf *sb, const char *full_name, FILE *fp)
 {
-	if (column_active(colopts)) {
-		string_list_append(&output, strbuf_detach(sb, NULL));
+	if (column_active(colopts) || porcelain) {
+		struct string_list_item *it;
+		it = string_list_append(&output, strbuf_detach(sb, NULL));
+		it->util = (void*)full_name;
 		return;
 	}
 	fwrite(sb->buf, sb->len, 1, fp);
@@ -106,7 +115,7 @@ static void show_dir_entry(const char *tag, struct dir_entry *ent)
 	strbuf_reset(&sb);
 	strbuf_addstr(&sb, tag);
 	write_dir_entry(&sb, ent);
-	strbuf_fputs(&sb, stdout);
+	strbuf_fputs(&sb, ent->name, stdout);
 }
 
 static void show_other_files(struct dir_struct *dir)
@@ -223,7 +232,7 @@ static void show_ce_entry(const char *tag, const struct cache_entry *ce)
 			    ce_stage(ce));
 	}
 	write_ce_name(&sb, ce);
-	strbuf_fputs(&sb, stdout);
+	strbuf_fputs(&sb, ce->name, stdout);
 	if (debug_mode) {
 		const struct stat_data *sd = &ce->ce_stat_data;
 
@@ -524,6 +533,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 	const char *max_prefix;
 	struct dir_struct dir;
 	struct exclude_list *el;
+	struct column_options copts;
 	struct string_list exclude_list = STRING_LIST_INIT_NODUP;
 	struct option builtin_ls_files_options[] = {
 		{ OPTION_CALLBACK, 'z', NULL, NULL, NULL,
@@ -671,7 +681,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 		if (debug_mode)
 			die(_("--column and --debug are incompatible"));
 	}
-	if (column_active(colopts))
+	if (column_active(colopts) || porcelain)
 		line_terminator = 0;
 
 	if (require_work_tree && !is_inside_work_tree())
@@ -737,13 +747,15 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 	if (show_resolve_undo)
 		show_ru_info();
 
-	if (column_active(colopts)) {
-		struct column_options copts;
-		memset(&copts, 0, sizeof(copts));
-		copts.padding = 2;
-		print_columns(&output, colopts, &copts);
-		string_list_clear(&output, 0);
+	memset(&copts, 0, sizeof(copts));
+	copts.padding = 2;
+	if (porcelain) {
+		qsort(output.items, output.nr, sizeof(*output.items),
+		      compare_output);
+		string_list_remove_duplicates(&output, 0);
 	}
+	print_columns(&output, colopts, &copts);
+	string_list_clear(&output, 0);
 
 	if (ps_matched) {
 		int bad;
-- 
2.2.0.60.gb7b3c64

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

* [PATCH 15/19] list-files: do not show duplicate cached entries
  2014-11-30  8:55 [PATCH 00/19] Add git-list-files Nguyễn Thái Ngọc Duy
                   ` (13 preceding siblings ...)
  2014-11-30  8:56 ` [PATCH 14/19] list-files: sort output and remove duplicates Nguyễn Thái Ngọc Duy
@ 2014-11-30  8:56 ` Nguyễn Thái Ngọc Duy
  2014-11-30  8:56 ` [PATCH 16/19] list-files: show directories as well as files Nguyễn Thái Ngọc Duy
                   ` (5 subsequent siblings)
  20 siblings, 0 replies; 28+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2014-11-30  8:56 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy

With the current show_files() "list-files -tcm" will show

  foo.c
M foo.c

The first item is redundant. If "foo.c" is modified, we know it's in
the cache. Introduce show_files_compact to do that because ls-files is
plumbing and scripts may already depend on current display behavior.

Another difference in show_files_compact() is it does not show
skip-worktree (aka outside sparse checkout) entries anymore, which
makes sense in porcelain context.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/ls-files.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 51 insertions(+), 1 deletion(-)

diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 42c530d..fc70265 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -333,6 +333,53 @@ static void show_files(struct dir_struct *dir)
 	}
 }
 
+static void show_files_compact(struct dir_struct *dir)
+{
+	int i;
+
+	/* For cached/deleted files we don't need to even do the readdir */
+	if (show_others || show_killed) {
+		if (!show_others)
+			dir->flags |= DIR_COLLECT_KILLED_ONLY;
+		fill_directory(dir, &pathspec);
+		if (show_others)
+			show_other_files(dir);
+		if (show_killed)
+			show_killed_files(dir);
+	}
+	if (!(show_cached || show_stage || show_deleted || show_modified))
+		return;
+	for (i = 0; i < active_nr; i++) {
+		const struct cache_entry *ce = active_cache[i];
+		struct stat st;
+		int err, shown = 0;
+		if ((dir->flags & DIR_SHOW_IGNORED) &&
+		    !ce_excluded(dir, ce))
+			continue;
+		if (show_unmerged && !ce_stage(ce))
+			continue;
+		if (ce->ce_flags & CE_UPDATE)
+			continue;
+		if (ce_skip_worktree(ce))
+			continue;
+		err = lstat(ce->name, &st);
+		if (show_deleted && err) {
+			show_ce_entry(tag_removed, ce);
+			shown = 1;
+		}
+		if (show_modified && (err || ce_modified(ce, &st, 0))) {
+			show_ce_entry(tag_modified, ce);
+			shown = 1;
+		}
+		if (ce_stage(ce)) {
+			show_ce_entry(tag_unmerged, ce);
+			shown = 1;
+		}
+		if (!shown && show_cached)
+			show_ce_entry(tag_cached, ce);
+	}
+}
+
 /*
  * Prune the index to only contain stuff starting with "prefix"
  */
@@ -743,7 +790,10 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 		refresh_index(&the_index, REFRESH_QUIET, &pathspec, NULL, NULL);
 		setup_pager();
 	}
-	show_files(&dir);
+	if (porcelain)
+		show_files_compact(&dir);
+	else
+		show_files(&dir);
 	if (show_resolve_undo)
 		show_ru_info();
 
-- 
2.2.0.60.gb7b3c64

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

* [PATCH 16/19] list-files: show directories as well as files
  2014-11-30  8:55 [PATCH 00/19] Add git-list-files Nguyễn Thái Ngọc Duy
                   ` (14 preceding siblings ...)
  2014-11-30  8:56 ` [PATCH 15/19] list-files: do not show duplicate cached entries Nguyễn Thái Ngọc Duy
@ 2014-11-30  8:56 ` Nguyễn Thái Ngọc Duy
  2014-11-30  8:56 ` [PATCH 17/19] list-files: add -F/--classify Nguyễn Thái Ngọc Duy
                   ` (4 subsequent siblings)
  20 siblings, 0 replies; 28+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2014-11-30  8:56 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy

The index does not store directories explicitly (except submodules) so
we have to figure them out from file list. The function
show_directories() deliberately generates duplicate directories and
expects the previous patch to remove duplicates.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/ls-files.c | 44 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 43 insertions(+), 1 deletion(-)

diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index fc70265..41efdaa 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -27,6 +27,8 @@ static int show_resolve_undo;
 static int show_modified;
 static int show_killed;
 static int show_valid_bit;
+static int show_tag;
+static int show_dirs;
 static int line_terminator = '\n';
 static int debug_mode;
 static int use_color;
@@ -333,6 +335,43 @@ static void show_files(struct dir_struct *dir)
 	}
 }
 
+static void show_directories(const struct cache_entry *ce)
+{
+	static const char *last_directory;
+	struct strbuf sb = STRBUF_INIT;
+	const char *p = ce->name + prefix_len;
+	const char *sep;
+
+	if (last_directory) {
+		int len = strlen(last_directory);
+		if (!strncmp(ce->name, last_directory, len) &&
+		    ce->name[len] == '/')
+			p += len + 1;
+	}
+
+	while (*p && (sep = strchr(p, '/'))) {
+		struct strbuf sb2 = STRBUF_INIT;
+		strbuf_reset(&sb);
+		strbuf_add(&sb, ce->name, sep - ce->name);
+		p = sep + 1;
+		if (!match_pathspec(&pathspec, sb.buf, sb.len,
+				    prefix_len, NULL, 1))
+			continue;
+		write_name(&sb2, sb.buf);
+		if (want_color(use_color)) {
+			struct strbuf sb3 = STRBUF_INIT;
+			color_filename(&sb3, ce->name, sb2.buf, S_IFDIR, 1);
+			strbuf_release(&sb2);
+			sb2 = sb3;
+		}
+		if (show_tag)
+			strbuf_insert(&sb2, 0, tag_cached, strlen(tag_cached));
+		last_directory = strbuf_detach(&sb, NULL);
+		strbuf_fputs(&sb2, last_directory, NULL);
+		strbuf_release(&sb2);
+	}
+}
+
 static void show_files_compact(struct dir_struct *dir)
 {
 	int i;
@@ -353,6 +392,8 @@ static void show_files_compact(struct dir_struct *dir)
 		const struct cache_entry *ce = active_cache[i];
 		struct stat st;
 		int err, shown = 0;
+		if (show_dirs)
+			show_directories(ce);
 		if ((dir->flags & DIR_SHOW_IGNORED) &&
 		    !ce_excluded(dir, ce))
 			continue;
@@ -575,7 +616,7 @@ static int git_ls_config(const char *var, const char *value, void *cb)
 
 int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 {
-	int require_work_tree = 0, show_tag = 0, i;
+	int require_work_tree = 0, i;
 	int max_depth = -1;
 	const char *max_prefix;
 	struct dir_struct dir;
@@ -696,6 +737,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 		use_color = -1;
 		max_depth = 0;
 		show_tag = -1;
+		show_dirs = 1;
 		git_config(git_ls_config, NULL);
 	} else
 		git_config(git_default_config, NULL);
-- 
2.2.0.60.gb7b3c64

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

* [PATCH 17/19] list-files: add -F/--classify
  2014-11-30  8:55 [PATCH 00/19] Add git-list-files Nguyễn Thái Ngọc Duy
                   ` (15 preceding siblings ...)
  2014-11-30  8:56 ` [PATCH 16/19] list-files: show directories as well as files Nguyễn Thái Ngọc Duy
@ 2014-11-30  8:56 ` Nguyễn Thái Ngọc Duy
  2014-11-30  8:56 ` [PATCH 18/19] list-files -F: show submodules with the new indicator '&' Nguyễn Thái Ngọc Duy
                   ` (3 subsequent siblings)
  20 siblings, 0 replies; 28+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2014-11-30  8:56 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy

This appends an indicator after the file name if it's executable, a
directory and so on, like in GNU ls. In fact append_indicator() is a
rewrite from get_type_indicator() in coreutils.git commit
7326d1f1a67edf21947ae98194f98c38b6e9e527.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/git-list-files.txt |  6 ++++++
 builtin/ls-files.c               | 31 +++++++++++++++++++++++++++++++
 2 files changed, 37 insertions(+)

diff --git a/Documentation/git-list-files.txt b/Documentation/git-list-files.txt
index 0ef616b..22084eb 100644
--- a/Documentation/git-list-files.txt
+++ b/Documentation/git-list-files.txt
@@ -51,6 +51,12 @@ OPTIONS
 	multiple file selections. See linkgit::git-ls-files[1] option
 	`-t` for more information.
 
+-F::
+--classify::
+	Append indicator (one of `*/=>@|`, which is executable,
+	directory, socket, Solaris door, symlink, or fifo
+	respectively) to entries.
+
 -R::
 --recursive::
 	Equivalent of `--max-depth=-1` (infinite recursion).
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 41efdaa..28737cb 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -29,6 +29,7 @@ static int show_killed;
 static int show_valid_bit;
 static int show_tag;
 static int show_dirs;
+static int show_indicator;
 static int line_terminator = '\n';
 static int debug_mode;
 static int use_color;
@@ -77,6 +78,28 @@ static void write_name(struct strbuf *sb, const char *name)
 		quote_path_relative(name, real_prefix, sb);
 }
 
+static void append_indicator(struct strbuf *sb, mode_t mode)
+{
+	char c = 0;
+	if (S_ISREG(mode)) {
+		if (mode & (S_IXUSR | S_IXGRP | S_IXOTH))
+			c = '*';
+	} else if (S_ISDIR(mode))
+		c = '/';
+	else if (S_ISLNK(mode))
+		c = '@';
+	else if (S_ISFIFO(mode))
+		c = '|';
+	else if (S_ISSOCK(mode))
+		c = '=';
+#ifdef S_ISDOOR
+	else if (S_ISDOOR(mode))
+		c = '>';
+#endif
+	if (c)
+		strbuf_addch(sb, c);
+}
+
 static void strbuf_fputs(struct strbuf *sb, const char *full_name, FILE *fp)
 {
 	if (column_active(colopts) || porcelain) {
@@ -99,6 +122,8 @@ static void write_dir_entry(struct strbuf *sb, const struct dir_entry *ent)
 		color_filename(sb, ent->name, quoted.buf, st.st_mode, 1);
 	else
 		strbuf_addbuf(sb, &quoted);
+	if (show_indicator && st.st_mode)
+		append_indicator(sb, st.st_mode);
 	strbuf_addch(sb, line_terminator);
 	strbuf_release(&quoted);
 }
@@ -189,6 +214,8 @@ static void write_ce_name(struct strbuf *sb, const struct cache_entry *ce)
 		color_filename(sb, ce->name, quoted.buf, ce->ce_mode, 1);
 	else
 		strbuf_addbuf(sb, &quoted);
+	if (show_indicator)
+		append_indicator(sb, ce->ce_mode);
 	strbuf_addch(sb, line_terminator);
 	strbuf_release(&quoted);
 }
@@ -366,6 +393,8 @@ static void show_directories(const struct cache_entry *ce)
 		}
 		if (show_tag)
 			strbuf_insert(&sb2, 0, tag_cached, strlen(tag_cached));
+		if (show_indicator)
+			append_indicator(&sb2, S_IFDIR);
 		last_directory = strbuf_detach(&sb, NULL);
 		strbuf_fputs(&sb2, last_directory, NULL);
 		strbuf_release(&sb2);
@@ -701,6 +730,8 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 			DIR_SHOW_IGNORED),
 		OPT_BOOL('u', "unmerged", &show_unmerged,
 			N_("show unmerged files")),
+		OPT_BOOL('F', "classify", &show_indicator,
+			 N_("append indicator (one of */=>@|) to entries")),
 		OPT__COLOR(&use_color, N_("show color")),
 		OPT_COLUMN(0, "column", &colopts, N_("show files in columns")),
 		OPT_SET_INT('1', NULL, &colopts,
-- 
2.2.0.60.gb7b3c64

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

* [PATCH 18/19] list-files -F: show submodules with the new indicator '&'
  2014-11-30  8:55 [PATCH 00/19] Add git-list-files Nguyễn Thái Ngọc Duy
                   ` (16 preceding siblings ...)
  2014-11-30  8:56 ` [PATCH 17/19] list-files: add -F/--classify Nguyễn Thái Ngọc Duy
@ 2014-11-30  8:56 ` Nguyễn Thái Ngọc Duy
  2014-11-30  8:56 ` [PATCH 19/19] list-files: -M aka diff-cached Nguyễn Thái Ngọc Duy
                   ` (2 subsequent siblings)
  20 siblings, 0 replies; 28+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2014-11-30  8:56 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/git-list-files.txt | 4 ++--
 builtin/ls-files.c               | 2 ++
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-list-files.txt b/Documentation/git-list-files.txt
index 22084eb..c57129b 100644
--- a/Documentation/git-list-files.txt
+++ b/Documentation/git-list-files.txt
@@ -53,8 +53,8 @@ OPTIONS
 
 -F::
 --classify::
-	Append indicator (one of `*/=>@|`, which is executable,
-	directory, socket, Solaris door, symlink, or fifo
+	Append indicator (one of `*/=>@|&`, which is executable,
+	directory, socket, Solaris door, symlink, fifo, or submodule
 	respectively) to entries.
 
 -R::
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 28737cb..5b5a068 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -92,6 +92,8 @@ static void append_indicator(struct strbuf *sb, mode_t mode)
 		c = '|';
 	else if (S_ISSOCK(mode))
 		c = '=';
+	else if (S_ISGITLINK(mode))
+		c = '&';
 #ifdef S_ISDOOR
 	else if (S_ISDOOR(mode))
 		c = '>';
-- 
2.2.0.60.gb7b3c64

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

* [PATCH 19/19] list-files: -M aka diff-cached
  2014-11-30  8:55 [PATCH 00/19] Add git-list-files Nguyễn Thái Ngọc Duy
                   ` (17 preceding siblings ...)
  2014-11-30  8:56 ` [PATCH 18/19] list-files -F: show submodules with the new indicator '&' Nguyễn Thái Ngọc Duy
@ 2014-11-30  8:56 ` Nguyễn Thái Ngọc Duy
  2014-12-01 20:02 ` [PATCH 00/19] Add git-list-files Junio C Hamano
  2014-12-02  5:42 ` Jeff King
  20 siblings, 0 replies; 28+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2014-11-30  8:56 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>
---
 builtin/ls-files.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 54 insertions(+), 3 deletions(-)

diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 5b5a068..08ae206 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -16,6 +16,9 @@
 #include "pathspec.h"
 #include "color.h"
 #include "column.h"
+#include "diff.h"
+#include "diffcore.h"
+#include "revision.h"
 
 static int abbrev;
 static int show_deleted;
@@ -25,6 +28,7 @@ static int show_stage;
 static int show_unmerged;
 static int show_resolve_undo;
 static int show_modified;
+static int show_diff_cached;
 static int show_killed;
 static int show_valid_bit;
 static int show_tag;
@@ -53,6 +57,7 @@ static const char *tag_removed = "";
 static const char *tag_other = "";
 static const char *tag_killed = "";
 static const char *tag_modified = "";
+static const char *tag_diff_cached = "";
 static const char *tag_skip_worktree = "";
 static const char *tag_resolve_undo = "";
 
@@ -343,7 +348,7 @@ static void show_files(struct dir_struct *dir)
 				(ce_skip_worktree(ce) ? tag_skip_worktree : tag_cached), ce);
 		}
 	}
-	if (show_deleted || show_modified) {
+	if (show_deleted || show_modified || show_diff_cached) {
 		for (i = 0; i < active_nr; i++) {
 			const struct cache_entry *ce = active_cache[i];
 			struct stat st;
@@ -358,7 +363,15 @@ static void show_files(struct dir_struct *dir)
 			err = lstat(ce->name, &st);
 			if (show_deleted && err)
 				show_ce_entry(tag_removed, ce);
-			if (show_modified && ce_modified(ce, &st, 0))
+			if (show_diff_cached && (ce->ce_flags & CE_MATCHED)) {
+				show_ce_entry(tag_diff_cached, ce);
+				/*
+				 * if we don't clear, it'll confuse write_ce_name()
+				 * when show_ce_entry(tag_modified, ce) is called
+				 */
+				active_cache[i]->ce_flags &= ~CE_MATCHED;
+			}
+			if (show_modified && (err || ce_modified(ce, &st, 0)))
 				show_ce_entry(tag_modified, ce);
 		}
 	}
@@ -452,6 +465,38 @@ static void show_files_compact(struct dir_struct *dir)
 	}
 }
 
+static void mark_diff_cached(struct diff_queue_struct *q,
+			     struct diff_options *options,
+			     void *data)
+{
+	int i;
+
+	for (i = 0; i < q->nr; i++) {
+		struct diff_filepair *p = q->queue[i];
+		int pos = cache_name_pos(p->two->path, strlen(p->two->path));
+		if (pos < 0)
+			continue;
+		active_cache[pos]->ce_flags |= CE_MATCHED;
+	}
+}
+
+static void diff_cached(struct pathspec *pathspec)
+{
+	struct rev_info rev;
+	const char *argv[] = { "ls-files", "HEAD", NULL };
+
+	init_revisions(&rev, NULL);
+	setup_revisions(2, argv, &rev, NULL);
+
+	rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
+	rev.diffopt.format_callback = mark_diff_cached;
+	rev.diffopt.detect_rename = 1;
+	rev.diffopt.rename_limit = 200;
+	rev.diffopt.break_opt = 0;
+	copy_pathspec(&rev.prune_data, pathspec);
+	run_diff_index(&rev, 1);
+}
+
 /*
  * Prune the index to only contain stuff starting with "prefix"
  */
@@ -721,6 +766,8 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 			N_("show cached files that are deleted on working directory")),
 		OPT_BOOL('m', "modified", &show_modified,
 			N_("show cached files that have modification on working directory")),
+		OPT_BOOL('M', "modified", &show_diff_cached,
+			N_("show modified files in the cache")),
 		OPT_BOOL('o', "others", &show_others,
 			N_("show untracked files")),
 		OPT_SET_INT('R', "recursive", &max_depth,
@@ -833,11 +880,12 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 
 	/* With no flags, we default to showing the cached files */
 	if (!(show_stage || show_deleted || show_others || show_unmerged ||
-	      show_killed || show_modified || show_resolve_undo))
+	      show_killed || show_modified || show_resolve_undo || show_diff_cached))
 		show_cached = 1;
 
 	if (show_tag == -1)
 		show_tag = (show_cached + show_deleted + show_others +
+			    show_diff_cached +
 			    show_unmerged + show_killed + show_modified) > 1;
 	if (show_tag || show_valid_bit) {
 		tag_cached = porcelain ? "  " : "H ";
@@ -845,6 +893,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 		tag_removed = "R ";
 		tag_modified = "C ";
 		tag_other = "? ";
+		tag_diff_cached = "X ";
 		tag_killed = "K ";
 		tag_skip_worktree = "S ";
 		tag_resolve_undo = "U ";
@@ -865,6 +914,8 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 		refresh_index(&the_index, REFRESH_QUIET, &pathspec, NULL, NULL);
 		setup_pager();
 	}
+	if (show_diff_cached)
+		diff_cached(&pathspec);
 	if (porcelain)
 		show_files_compact(&dir);
 	else
-- 
2.2.0.60.gb7b3c64

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

* Re: [PATCH 00/19] Add git-list-files
  2014-11-30  8:55 [PATCH 00/19] Add git-list-files Nguyễn Thái Ngọc Duy
                   ` (18 preceding siblings ...)
  2014-11-30  8:56 ` [PATCH 19/19] list-files: -M aka diff-cached Nguyễn Thái Ngọc Duy
@ 2014-12-01 20:02 ` Junio C Hamano
  2014-12-02 11:33   ` Duy Nguyen
  2014-12-02  5:42 ` Jeff King
  20 siblings, 1 reply; 28+ messages in thread
From: Junio C Hamano @ 2014-12-01 20:02 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: git

Does this contain a lot of borrowed code or something?  The style
violation in the patches are unusually high, even compared with your
other series.

I've tried to fix it up and will push out the result on 'pu' if
things work OK, but this does not even have tests, so it is unlikely
that it would break anything but itself ;-)

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

* Re: [PATCH 09/19] Add git-list-files, a user friendly version of ls-files and more
  2014-11-30  8:55 ` [PATCH 09/19] Add git-list-files, a user friendly version of ls-files and more Nguyễn Thái Ngọc Duy
@ 2014-12-02  2:50   ` Eric Sunshine
  2014-12-02 12:06     ` Duy Nguyen
  0 siblings, 1 reply; 28+ messages in thread
From: Eric Sunshine @ 2014-12-02  2:50 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: git

On Sunday, November 30, 2014, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:
>
> This is more user friendly version of ls-files:
>
> * it's automatically colored and columnized
> * it refreshes the index like all porcelain commands
> * it defaults to non-recursive behavior like ls
> * :(glob) is on by default so '*.c' means a.c but not a/b.c, use
>   '**/*.c' for that.
> * auto pager
>
> The name 'ls' is not taken. It is left for the user to make an alias
> with better default options.

I understand that your original version was named git-ls and that you
renamed it to git-list-files in order to leave 'ls' available so users
can create an 'ls' alias specifying their own default options. Would
it make sense, however, to restore the name to git-ls and allow users
to set default options via a config variable instead? Doing so would
make the short-and-sweet git-ls command work for all users
out-of-the-box, which might be well appreciated by Unix users.

More below.

> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
> ---
> diff --git a/Documentation/git-list-files.txt b/Documentation/git-list-files.txt
> new file mode 100644
> index 0000000..3039e1e
> --- /dev/null
> +++ b/Documentation/git-list-files.txt
> @@ -0,0 +1,80 @@
> +git-list-files(1)
> +===============
> +
> +NAME
> +----
> +git-list-files - List files
> +
> +SYNOPSIS
> +--------
> +[verse]
> +'git list-files [options] [<pathspec>...]
> +
> +DESCRIPTION
> +-----------
> +List files (by default in current working directory) that are in the
> +index. Depending on the chosen options, maybe only modified files in
> +working tree are shown, or untracked files...
> +
> +OPTIONS
> +-------
> +-c::
> +--cached::
> +       Show cached files (default)

I realize that this mirrors what is in git-ls-files.txt, but:

s/$/./

> +-d::
> +--deleted::
> +       Show cached files that are deleted on working directory

s/$/./

> +-m::
> +--modified::
> +       Show cached files that have modification on working directory

s/$/./

> +-o::
> +--others::
> +       Show untracked files (and only unignored ones unless -i is

s/-i/`-i`/

> +       specified)

s/$/./

> +-i::
> +--ignored::
> +       Show only ignored files. When showing files in the index,
> +       print only those matched by an exclude pattern. When showing
> +       "other" files, show only those matched by an exclude pattern.
> +
> +-u::
> +--unmerged::
> +       Show unmerged files

s/$/./

> +--color[=<when>]::
> +--no-color::
> +       Color file names. The value must be `always`, `never`, or
> +       `auto`. `--no-color` is equivalent to
> +       `--color=never`. `--color` is equivalent to
> +       `--color=auto`. See configuration variable `color.list-files`
> +       for the default settings.
> +
> +--column[=<options>]::
> +--no-column::
> +       Display files in columns. See configuration variable column.ui

s/column.ui/`column.ui`/

> +       for option syntax. `--column` and `--no-column` without options
> +       are equivalent to 'always' and 'never' respectively.
> +
> +--max-depth=<depth>::
> +       For each <pathspec> given on command line, descend at most <depth>
> +       levels of directories. A negative value means no limit.
> +       This option is ignored if <pathspec> contains active wildcards.
> +       In other words if "a*" matches a directory named "a*",
> +       "*" is matched literally so --max-depth is still effective.
> +       The default is `--max-depth=0`.
> +
> +<pathspec>::
> +       Files to show. :(glob) magic is enabled and recursion disabled
> +       by default.
> +
> +SEE ALSO
> +--------
> +linkgit:git-ls-files[1]
> +
> +GIT
> +---
> +Part of the linkgit:git[1] suite

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

* Re: [PATCH 00/19] Add git-list-files
  2014-11-30  8:55 [PATCH 00/19] Add git-list-files Nguyễn Thái Ngọc Duy
                   ` (19 preceding siblings ...)
  2014-12-01 20:02 ` [PATCH 00/19] Add git-list-files Junio C Hamano
@ 2014-12-02  5:42 ` Jeff King
  2014-12-02 11:45   ` Duy Nguyen
  2014-12-02 12:40   ` Michael J Gruber
  20 siblings, 2 replies; 28+ messages in thread
From: Jeff King @ 2014-12-02  5:42 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: git

On Sun, Nov 30, 2014 at 03:55:48PM +0700, Nguyễn Thái Ngọc Duy wrote:

> This is something else that's been sitting in my tree for a while now.
> It adds "git list-files", intended to be aliased as "ls" with your
> favourite display options.

When I read the subject, I thought "why isn't this called git-ls?". Then
when I read this paragraph, I thought "if the point is for everybody to
make their own ls alias, why do we need list-files at all, instead of
just adding options to ls-files"?

I'll let you decide which (if any) you'd like to answer. :)

My guesses:

  1. If it were "git-ls", it would stomp on existing aliases people have
     constructed.

  2. If it is a wrapper around ls-files, then the options may be
     constrained; ls-files already squats on useful options like "-d"
     (which, if we are matching traditional ls, is more like our "-t").

I somewhat feel like (1) can be mitigated by the fact that your command
is what people were probably trying to approximate with their aliases,
and that as porcelain it should be very configurable (so they should be
able to accomplish the same things as their aliases). But I dunno. I do
not have an "ls" alias, so I am biased. :)

As a side note, I wonder if it would be sensible to whitelist some
commands as porcelain, and allow aliases to override them (either
entirely, or just to add-in some options).

-Peff

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

* Re: [PATCH 00/19] Add git-list-files
  2014-12-01 20:02 ` [PATCH 00/19] Add git-list-files Junio C Hamano
@ 2014-12-02 11:33   ` Duy Nguyen
  0 siblings, 0 replies; 28+ messages in thread
From: Duy Nguyen @ 2014-12-02 11:33 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git Mailing List

On Tue, Dec 2, 2014 at 3:02 AM, Junio C Hamano <gitster@pobox.com> wrote:
> Does this contain a lot of borrowed code or something?  The style
> violation in the patches are unusually high, even compared with your
> other series.

The first one is from coreutils, but I reformatted (and trimmed) to
fit Git. I recall you had a script to spot style violation, right?
Where can I find the script? Else I'll reread CodingGuidlines again
and go through the patch.


> I've tried to fix it up and will push out the result on 'pu' if
> things work OK, but this does not even have tests, so it is unlikely
> that it would break anything but itself ;-)

Heh.. ;) Next version will come with tests. Thanks for the reminder.
-- 
Duy

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

* Re: [PATCH 00/19] Add git-list-files
  2014-12-02  5:42 ` Jeff King
@ 2014-12-02 11:45   ` Duy Nguyen
  2014-12-02 20:18     ` Jeff King
  2014-12-02 12:40   ` Michael J Gruber
  1 sibling, 1 reply; 28+ messages in thread
From: Duy Nguyen @ 2014-12-02 11:45 UTC (permalink / raw)
  To: Jeff King; +Cc: Git Mailing List

On Tue, Dec 2, 2014 at 12:42 PM, Jeff King <peff@peff.net> wrote:
> On Sun, Nov 30, 2014 at 03:55:48PM +0700, Nguyễn Thái Ngọc Duy wrote:
>
>> This is something else that's been sitting in my tree for a while now.
>> It adds "git list-files", intended to be aliased as "ls" with your
>> favourite display options.
>
> When I read the subject, I thought "why isn't this called git-ls?". Then
> when I read this paragraph, I thought "if the point is for everybody to
> make their own ls alias, why do we need list-files at all, instead of
> just adding options to ls-files"?
>
> I'll let you decide which (if any) you'd like to answer. :)
>
> My guesses:
>
>   1. If it were "git-ls", it would stomp on existing aliases people have
>      constructed.

Yes, Matthew Moy (I think) at least had this git-ls alias and he did
complain. Also we could not agree on what should be the good defaults
for git-ls if it's built in.

>   2. If it is a wrapper around ls-files, then the options may be
>      constrained; ls-files already squats on useful options like "-d"
>      (which, if we are matching traditional ls, is more like our "-t").

Also right. I want to keep option names close to GNU ls.

> As a side note, I wonder if it would be sensible to whitelist some
> commands as porcelain, and allow aliases to override them (either
> entirely, or just to add-in some options).

Agreed. Maybe not all porcelain (some like git-branch almost functions
like plumbing).

We also need away to stop alias (e.g. in scripts). In scripts I can
specify full path to a command to make sure I won't hit an alias. I
guess we can't do the same here. The closet to "full path" is git-cmd
form, as opposed to "git cmd" form) but I think we don't want to bring
back git-cmd. Maybe just a "git --no-alias cmd" and GIT_NO_ALIAS..

And if  people now can override standard commands, I think it makes
sense to ship a default alias set (with lower priority than
user-defined aliases). After all people need to check twice if the
command they type really means what they think it is..
-- 
Duy

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

* Re: [PATCH 09/19] Add git-list-files, a user friendly version of ls-files and more
  2014-12-02  2:50   ` Eric Sunshine
@ 2014-12-02 12:06     ` Duy Nguyen
  0 siblings, 0 replies; 28+ messages in thread
From: Duy Nguyen @ 2014-12-02 12:06 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: git

On Tue, Dec 2, 2014 at 9:50 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:
> On Sunday, November 30, 2014, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:
>>
>> This is more user friendly version of ls-files:
>>
>> * it's automatically colored and columnized
>> * it refreshes the index like all porcelain commands
>> * it defaults to non-recursive behavior like ls
>> * :(glob) is on by default so '*.c' means a.c but not a/b.c, use
>>   '**/*.c' for that.
>> * auto pager
>>
>> The name 'ls' is not taken. It is left for the user to make an alias
>> with better default options.
>
> I understand that your original version was named git-ls and that you
> renamed it to git-list-files in order to leave 'ls' available so users
> can create an 'ls' alias specifying their own default options. Would
> it make sense, however, to restore the name to git-ls and allow users
> to set default options via a config variable instead? Doing so would
> make the short-and-sweet git-ls command work for all users
> out-of-the-box, which might be well appreciated by Unix users.

Or I just make git-ls the first alias shipped by default.. I don't
really like using config var to define default options. Sounds like a
workaround to our alias. Jeff raised it elsewhere in this thread:

http://thread.gmane.org/gmane.comp.version-control.git/260423/focus=260538
-- 
Duy

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

* Re: [PATCH 00/19] Add git-list-files
  2014-12-02  5:42 ` Jeff King
  2014-12-02 11:45   ` Duy Nguyen
@ 2014-12-02 12:40   ` Michael J Gruber
  1 sibling, 0 replies; 28+ messages in thread
From: Michael J Gruber @ 2014-12-02 12:40 UTC (permalink / raw)
  To: Jeff King, Nguyễn Thái Ngọc Duy; +Cc: git

Jeff King schrieb am 02.12.2014 um 06:42:
> On Sun, Nov 30, 2014 at 03:55:48PM +0700, Nguyễn Thái Ngọc Duy wrote:
> 
>> This is something else that's been sitting in my tree for a while now.
>> It adds "git list-files", intended to be aliased as "ls" with your
>> favourite display options.
> 
> When I read the subject, I thought "why isn't this called git-ls?". Then
> when I read this paragraph, I thought "if the point is for everybody to
> make their own ls alias, why do we need list-files at all, instead of
> just adding options to ls-files"?
> 
> I'll let you decide which (if any) you'd like to answer. :)
> 
> My guesses:
> 
>   1. If it were "git-ls", it would stomp on existing aliases people have
>      constructed.
> 
>   2. If it is a wrapper around ls-files, then the options may be
>      constrained; ls-files already squats on useful options like "-d"
>      (which, if we are matching traditional ls, is more like our "-t").
> 
> I somewhat feel like (1) can be mitigated by the fact that your command
> is what people were probably trying to approximate with their aliases,
> and that as porcelain it should be very configurable (so they should be
> able to accomplish the same things as their aliases). But I dunno. I do
> not have an "ls" alias, so I am biased. :)
> 
> As a side note, I wonder if it would be sensible to whitelist some
> commands as porcelain, and allow aliases to override them (either
> entirely, or just to add-in some options).
> 
> -Peff
> 

I'd like to second all that ("+1", "like").

User friendly listing of files in the git repo is dearly needed, and
following names and default behaviour of mv/cp/ls is a way to follow the
principle of least surprise.

While "ls" might be an alias for many, I'm sure "stage" was for quite a
few people, too. We should be able to take any new name for new command,
regardless of aliases people may be using.

Allowing to alias at least porcelain commands, at least to the extent of
adding default options, is something we've talked about before and which
would have prevented us from the increasing bloat by the default
changing config knobs. "git -c ..." somehow took us down the other road.

I'm still dreaming of a git future where either "git foo --bar=baz" is
equivalent to "git -c foo.bar=baz foo" (i.e. unify the naming), or we
are simply able to alias "foo" to "foo --bar=baz" if that is what we
like as default (i.e. get rid of many of the special config knobs).

Right now, we have two "sets of options" with often differing names.

Also, we could ship a few commonly used aliases (such as co=checkout,
ci=commit, st=status) which could be overriden easily.

Michael

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

* Re: [PATCH 00/19] Add git-list-files
  2014-12-02 11:45   ` Duy Nguyen
@ 2014-12-02 20:18     ` Jeff King
  0 siblings, 0 replies; 28+ messages in thread
From: Jeff King @ 2014-12-02 20:18 UTC (permalink / raw)
  To: Duy Nguyen; +Cc: Git Mailing List

On Tue, Dec 02, 2014 at 06:45:52PM +0700, Duy Nguyen wrote:

> > As a side note, I wonder if it would be sensible to whitelist some
> > commands as porcelain, and allow aliases to override them (either
> > entirely, or just to add-in some options).
> 
> Agreed. Maybe not all porcelain (some like git-branch almost functions
> like plumbing).

Yeah, many things straddle the plumbing/porcelain line (e.g., "commit"
is porcelain, but it's basically the only sane way for scripts to make a
commit, so many use it). So I'd pick just a few things that should be
safe to override.

> We also need away to stop alias (e.g. in scripts).

Do we? I think the point of allowing this only for porcelain is that you
do not have to care about scripts. That is, a script running "git ls"
would get whatever the user's preferences are for "ls" output. A script
parsing the output of "ls" deserves whatever crap it gets.

> In scripts I can specify full path to a command to make sure I won't
> hit an alias. I guess we can't do the same here. The closet to "full
> path" is git-cmd form, as opposed to "git cmd" form) but I think we
> don't want to bring back git-cmd. Maybe just a "git --no-alias cmd"
> and GIT_NO_ALIAS..

Yeah, I think "--no-alias"/GIT_NO_ALIAS would work. But the problem is
one of compatibility. Scripts are not written to specify no-alias, so
you cannot just turn on the override-commands-with-aliases feature
immediately (and likewise, scripts have little incentive to bother
annotating their calls if it the override feature is not enabled).

-Peff

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

end of thread, other threads:[~2014-12-02 20:18 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-11-30  8:55 [PATCH 00/19] Add git-list-files Nguyễn Thái Ngọc Duy
2014-11-30  8:55 ` [PATCH 01/19] ls_colors.c: add $LS_COLORS parsing code Nguyễn Thái Ngọc Duy
2014-11-30  8:55 ` [PATCH 02/19] ls_colors.c: parse color.ls.* from config file Nguyễn Thái Ngọc Duy
2014-11-30  8:55 ` [PATCH 03/19] ls_colors.c: add a function to color a file name Nguyễn Thái Ngọc Duy
2014-11-30  8:55 ` [PATCH 04/19] ls_colors.c: highlight submodules like directories Nguyễn Thái Ngọc Duy
2014-11-30  8:55 ` [PATCH 05/19] ls-files: buffer full item in strbuf before printing Nguyễn Thái Ngọc Duy
2014-11-30  8:55 ` [PATCH 06/19] ls-files: add --color to highlight file names Nguyễn Thái Ngọc Duy
2014-11-30  8:55 ` [PATCH 07/19] ls-files: add --column Nguyễn Thái Ngọc Duy
2014-11-30  8:55 ` [PATCH 08/19] ls-files: support --max-depth Nguyễn Thái Ngọc Duy
2014-11-30  8:55 ` [PATCH 09/19] Add git-list-files, a user friendly version of ls-files and more Nguyễn Thái Ngọc Duy
2014-12-02  2:50   ` Eric Sunshine
2014-12-02 12:06     ` Duy Nguyen
2014-11-30  8:55 ` [PATCH 10/19] list-files: -u does not imply showing stages Nguyễn Thái Ngọc Duy
2014-11-30  8:55 ` [PATCH 11/19] list-files: add -R/--recursive short for --max-depth=-1 Nguyễn Thái Ngọc Duy
2014-11-30  8:56 ` [PATCH 12/19] list-files: add -1 short for --no-column Nguyễn Thái Ngọc Duy
2014-11-30  8:56 ` [PATCH 13/19] list-files: add -t back Nguyễn Thái Ngọc Duy
2014-11-30  8:56 ` [PATCH 14/19] list-files: sort output and remove duplicates Nguyễn Thái Ngọc Duy
2014-11-30  8:56 ` [PATCH 15/19] list-files: do not show duplicate cached entries Nguyễn Thái Ngọc Duy
2014-11-30  8:56 ` [PATCH 16/19] list-files: show directories as well as files Nguyễn Thái Ngọc Duy
2014-11-30  8:56 ` [PATCH 17/19] list-files: add -F/--classify Nguyễn Thái Ngọc Duy
2014-11-30  8:56 ` [PATCH 18/19] list-files -F: show submodules with the new indicator '&' Nguyễn Thái Ngọc Duy
2014-11-30  8:56 ` [PATCH 19/19] list-files: -M aka diff-cached Nguyễn Thái Ngọc Duy
2014-12-01 20:02 ` [PATCH 00/19] Add git-list-files Junio C Hamano
2014-12-02 11:33   ` Duy Nguyen
2014-12-02  5:42 ` Jeff King
2014-12-02 11:45   ` Duy Nguyen
2014-12-02 20:18     ` Jeff King
2014-12-02 12:40   ` Michael J Gruber

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.