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

Changes since 'pu' version:

 - refresh_index() in 09/21 is set not to show "XXX: needs merge"
   messages, cluttering "list-files -u" output
 - new patch 10/21 to add a default alias 'ls' to 'list-files',
   of course overridable by the user
 - fix "list-files -u" not showing anything because
   show_files_compact in 16/21 ignores show_unmerged flag
 - directory listing in 17/21 is rewritten to work filtering
   (e.g. -m, -M...)
 - new patch 21/21 adds tests for the series

Nguyễn Thái Ngọc Duy (21):
  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
  list-files: a user friendly version of ls-files and more
  list-files: make alias 'ls' default to 'list-files'
  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
  t3080: tests for git-list-files

Total diff against 'pu' is something like this

-- 8< --
diff --git a/Documentation/git-list-files.txt b/Documentation/git-list-files.txt
index c57129b..223f6fd 100644
--- a/Documentation/git-list-files.txt
+++ b/Documentation/git-list-files.txt
@@ -14,7 +14,8 @@ 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...
+working tree are shown, or untracked files... The builtin alias "ls"
+is set to "list-files".
 
 OPTIONS
 -------
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 02a9ac1..b04c712 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -213,6 +213,37 @@ static void show_killed_files(struct dir_struct *dir)
 	}
 }
 
+static int show_as_directory(const struct cache_entry *ce)
+{
+	struct strbuf sb = STRBUF_INIT;
+	const char *p;
+
+	strbuf_add(&sb, ce->name, ce_namelen(ce));
+	while (sb.len && (p = strrchr(sb.buf, '/')) != NULL) {
+		struct strbuf sb2 = STRBUF_INIT;
+		strbuf_setlen(&sb, p - sb.buf);
+		if (!match_pathspec(&pathspec, sb.buf, sb.len,
+				    max_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));
+		if (show_indicator)
+			append_indicator(&sb2, S_IFDIR);
+		strbuf_fputs(&sb2, strbuf_detach(&sb, NULL), NULL);
+		strbuf_release(&sb2);
+		return 1;
+	}
+	strbuf_release(&sb);
+	return 0;
+}
+
 static void write_ce_name(struct strbuf *sb, const struct cache_entry *ce)
 {
 	struct strbuf quoted = STRBUF_INIT;
@@ -230,16 +261,31 @@ static void write_ce_name(struct strbuf *sb, const struct cache_entry *ce)
 static void show_ce_entry(const char *tag, const struct cache_entry *ce)
 {
 	static struct strbuf sb = STRBUF_INIT;
-	int len = max_prefix_len;
+	int len = max_prefix_len, saved_max_depth;
 
 	if (len >= ce_namelen(ce))
 		die("git ls-files: internal error - cache entry not superset of prefix");
 
+	if (show_dirs) {
+		/* ignore depth to catch dirs that contain matched entries */
+		saved_max_depth = pathspec.max_depth;
+		pathspec.max_depth = -1;
+	}
+
 	if (!match_pathspec(&pathspec, ce->name, ce_namelen(ce),
 			    len, ps_matched,
 			    S_ISDIR(ce->ce_mode) || S_ISGITLINK(ce->ce_mode)))
 		return;
 
+	if (show_dirs) {
+		pathspec.max_depth = saved_max_depth;
+		if (strchr(ce->name, '/') &&
+		    !match_pathspec(&pathspec, ce->name, ce_namelen(ce),
+				    prefix_len, NULL, 1) &&
+		    show_as_directory(ce))
+			return;
+	}
+
 	if (tag && *tag && show_valid_bit &&
 	    (ce->ce_flags & CE_VALID)) {
 		static char alttag[4];
@@ -348,7 +394,7 @@ static void show_files(struct dir_struct *dir)
 				(ce_skip_worktree(ce) ? tag_skip_worktree : tag_cached), ce);
 		}
 	}
-	if (show_deleted || show_modified || show_diff_cached) {
+	if (show_deleted || show_modified) {
 		for (i = 0; i < active_nr; i++) {
 			const struct cache_entry *ce = active_cache[i];
 			struct stat st;
@@ -377,45 +423,6 @@ 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));
-		if (show_indicator)
-			append_indicator(&sb2, S_IFDIR);
-		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;
@@ -430,14 +437,13 @@ static void show_files_compact(struct dir_struct *dir)
 		if (show_killed)
 			show_killed_files(dir);
 	}
-	if (!(show_cached || show_stage || show_deleted || show_modified))
+	if (!(show_cached || show_unmerged || show_deleted ||
+	      show_modified || show_diff_cached))
 		return;
 	for (i = 0; i < active_nr; i++) {
 		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;
@@ -452,6 +458,15 @@ static void show_files_compact(struct dir_struct *dir)
 			show_ce_entry(tag_removed, ce);
 			shown = 1;
 		}
+		if (show_diff_cached && (ce->ce_flags & CE_MATCHED)) {
+			show_ce_entry(tag_diff_cached, ce);
+			shown = 1;
+			/*
+			 * 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);
 			shown = 1;
@@ -817,7 +832,6 @@ 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);
@@ -866,6 +880,8 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 		       prefix, argv);
 	pathspec.max_depth = max_depth;
 	pathspec.recursive = 1;
+	show_dirs = porcelain && max_depth != -1;
+
 
 	/* Find common prefix for all pathspec's */
 	max_prefix = common_prefix(&pathspec);
@@ -911,7 +927,7 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 		overlay_tree_on_cache(with_tree, max_prefix);
 	}
 	if (porcelain) {
-		refresh_index(&the_index, REFRESH_QUIET, &pathspec, NULL, NULL);
+		refresh_index(&the_index, REFRESH_QUIET | REFRESH_UNMERGED, &pathspec, NULL, NULL);
 		setup_pager();
 	}
 	if (show_diff_cached)
diff --git a/config.c b/config.c
index 15a2983..16209c6 100644
--- a/config.c
+++ b/config.c
@@ -40,6 +40,10 @@ static struct config_source *cf;
 
 static int zlib_compression_seen;
 
+static const char *builtin_config =
+	"[alias]\n"
+	"	ls = list-files\n";
+
 /*
  * Default config_set that contains key-value pairs from the usual set of config
  * config files (i.e repo specific .git/config, user wide ~/.gitconfig, XDG
@@ -1175,6 +1179,10 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
 
 	home_config_paths(&user_config, &xdg_config, "config");
 
+	if (git_config_system())
+		git_config_from_buf(fn, "<builtin>", builtin_config,
+				    strlen(builtin_config), data);
+
 	if (git_config_system() && !access_or_die(git_etc_gitconfig(), R_OK, 0)) {
 		ret += git_config_from_file(fn, git_etc_gitconfig(),
 					    data);
diff --git a/t/t3080-list-files.sh b/t/t3080-list-files.sh
new file mode 100755
index 0000000..6313dd9
--- /dev/null
+++ b/t/t3080-list-files.sh
@@ -0,0 +1,122 @@
+#!/bin/sh
+
+test_description='git list-files test'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+	mkdir dir &&
+	touch file dir/file &&
+	git init gitlink &&
+	( cd gitlink && test_commit foo ) &&
+	git add file dir/file gitlink &&
+	git commit -qm1
+'
+
+test_expect_success 'LS_COLORS env variable' '
+	LS_COLORS="rs=0:fi=31:di=32" \
+		git list-files --color=always | grep -v gitlink >actual &&
+	test_cmp "$TEST_DIRECTORY"/t3080/ls_colors actual
+'
+
+test_expect_success 'color.ls.*' '
+	test_config color.ls.file red &&
+	test_config color.ls.directory green &&
+	test_config color.ls.submodule yellow &&
+	git list-files --color=always >actual &&
+	test_cmp "$TEST_DIRECTORY"/t3080/color_ls actual
+'
+
+test_expect_success 'column output' '
+	COLUMNS=20 git list-files --column=always >actual &&
+	cat >expected <<-\EOF &&
+	dir      gitlink
+	file
+	EOF
+	test_cmp expected actual &&
+	git list-files -1 >actual &&
+	cat >expected <<-\EOF &&
+	dir
+	file
+	gitlink
+	EOF
+	test_cmp expected actual
+'
+
+test_expect_success '--max-depth' '
+	git list-files --max-depth=1 >actual &&
+	cat >expected <<-\EOF &&
+	dir/file
+	file
+	gitlink
+	EOF
+	test_cmp expected actual
+'
+
+test_expect_success 'recursive' '
+	git list-files -R >actual &&
+	cat >expected <<-\EOF &&
+	dir/file
+	file
+	gitlink
+	EOF
+	test_cmp expected actual
+'
+
+test_expect_success 'globbing' '
+	git list-files "f*" >actual &&
+	cat >expected <<-\EOF &&
+	file
+	EOF
+	test_cmp expected actual &&
+	git list-files "**/f*" >actual &&
+	cat >expected <<-\EOF &&
+	dir/file
+	file
+	EOF
+	test_cmp expected actual
+'
+
+test_expect_success 'no dups' '
+	echo dirty >>file &&
+	git list-files -m file >actual &&
+	echo "file" >expected &&
+	test_cmp expected actual &&
+	git list-files -cm file >actual &&
+	echo "C file" >expected &&
+	test_cmp expected actual &&
+	git list-files -tcm file >actual &&
+	test_cmp expected actual
+'
+
+test_expect_success '--classify' '
+	git list-files -F >actual &&
+	cat >expected <<-\EOF &&
+	dir/
+	file
+	gitlink&
+	EOF
+	test_cmp expected actual
+'
+
+test_expect_success 'diff-cached' '
+	echo dirty >>file &&
+	git add file &&
+	git list-files -M >actual &&
+	echo "file" >expected &&
+	test_cmp expected actual
+'
+
+test_expect_success 'unmerged files' '
+	git ls-files --stage file >index-info &&
+	sed "s/ 0/ 2/;s/file/unmerged/" index-info | git update-index --index-info &&
+	sed "s/ 0/ 3/;s,file,dir/unmerged," index-info | git update-index --index-info &&
+	git list-files -u >actual &&
+	cat >expected <<-\EOF &&
+	dir
+	unmerged
+	EOF
+	test_cmp expected actual
+'
+
+test_done
diff --git a/t/t3080/color_ls b/t/t3080/color_ls
new file mode 100644
index 0000000..47f77ad
--- /dev/null
+++ b/t/t3080/color_ls
@@ -0,0 +1,3 @@
+^[[32mdir^[[m
+^[[31mfile^[[m
+^[[33mgitlink^[[m
diff --git a/t/t3080/ls_colors b/t/t3080/ls_colors
new file mode 100644
index 0000000..423c016
--- /dev/null
+++ b/t/t3080/ls_colors
@@ -0,0 +1,2 @@
+^[[32mdir^[[m
+^[[31mfile^[[m
-- 8< --
-- 
2.2.0.84.ge9c7a8a

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

* [PATCH 01/21] ls_colors.c: add $LS_COLORS parsing code
  2015-01-25 12:37 [PATCH 00/21] nd/list-files updates Nguyễn Thái Ngọc Duy
@ 2015-01-25 12:37 ` Nguyễn Thái Ngọc Duy
  2015-01-25 12:37 ` [PATCH 02/21] ls_colors.c: parse color.ls.* from config file Nguyễn Thái Ngọc Duy
                   ` (19 subsequent siblings)
  20 siblings, 0 replies; 31+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-01-25 12:37 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy, Junio C Hamano

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>
Signed-off-by: Junio C Hamano <gitster@pobox.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..e743315
--- /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;
+
+/*
+ * 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.84.ge9c7a8a

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

* [PATCH 02/21] ls_colors.c: parse color.ls.* from config file
  2015-01-25 12:37 [PATCH 00/21] nd/list-files updates Nguyễn Thái Ngọc Duy
  2015-01-25 12:37 ` [PATCH 01/21] ls_colors.c: add $LS_COLORS parsing code Nguyễn Thái Ngọc Duy
@ 2015-01-25 12:37 ` Nguyễn Thái Ngọc Duy
  2015-01-25 12:37 ` [PATCH 03/21] 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; 31+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-01-25 12:37 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy, Junio C Hamano

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>
Signed-off-by: Junio C Hamano <gitster@pobox.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 e743315..08e7068 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.84.ge9c7a8a

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

* [PATCH 03/21] ls_colors.c: add a function to color a file name
  2015-01-25 12:37 [PATCH 00/21] nd/list-files updates Nguyễn Thái Ngọc Duy
  2015-01-25 12:37 ` [PATCH 01/21] ls_colors.c: add $LS_COLORS parsing code Nguyễn Thái Ngọc Duy
  2015-01-25 12:37 ` [PATCH 02/21] ls_colors.c: parse color.ls.* from config file Nguyễn Thái Ngọc Duy
@ 2015-01-25 12:37 ` Nguyễn Thái Ngọc Duy
  2015-01-25 12:37 ` [PATCH 04/21] ls_colors.c: highlight submodules like directories Nguyễn Thái Ngọc Duy
                   ` (17 subsequent siblings)
  20 siblings, 0 replies; 31+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-01-25 12:37 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy, Junio C Hamano

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>
Signed-off-by: Junio C Hamano <gitster@pobox.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 08e7068..7d2e2e0 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.84.ge9c7a8a

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

* [PATCH 04/21] ls_colors.c: highlight submodules like directories
  2015-01-25 12:37 [PATCH 00/21] nd/list-files updates Nguyễn Thái Ngọc Duy
                   ` (2 preceding siblings ...)
  2015-01-25 12:37 ` [PATCH 03/21] ls_colors.c: add a function to color a file name Nguyễn Thái Ngọc Duy
@ 2015-01-25 12:37 ` Nguyễn Thái Ngọc Duy
  2015-01-25 12:37 ` [PATCH 05/21] ls-files: buffer full item in strbuf before printing Nguyễn Thái Ngọc Duy
                   ` (16 subsequent siblings)
  20 siblings, 0 replies; 31+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-01-25 12:37 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy, Junio C Hamano

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.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 7d2e2e0..9259ad3 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.84.ge9c7a8a

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

* [PATCH 05/21] ls-files: buffer full item in strbuf before printing
  2015-01-25 12:37 [PATCH 00/21] nd/list-files updates Nguyễn Thái Ngọc Duy
                   ` (3 preceding siblings ...)
  2015-01-25 12:37 ` [PATCH 04/21] ls_colors.c: highlight submodules like directories Nguyễn Thái Ngọc Duy
@ 2015-01-25 12:37 ` Nguyễn Thái Ngọc Duy
  2015-01-25 12:37 ` [PATCH 06/21] ls-files: add --color to highlight file names Nguyễn Thái Ngọc Duy
                   ` (15 subsequent siblings)
  20 siblings, 0 replies; 31+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-01-25 12:37 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy, Junio C Hamano

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>
Signed-off-by: Junio C Hamano <gitster@pobox.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..b6f0d9f 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.84.ge9c7a8a

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

* [PATCH 06/21] ls-files: add --color to highlight file names
  2015-01-25 12:37 [PATCH 00/21] nd/list-files updates Nguyễn Thái Ngọc Duy
                   ` (4 preceding siblings ...)
  2015-01-25 12:37 ` [PATCH 05/21] ls-files: buffer full item in strbuf before printing Nguyễn Thái Ngọc Duy
@ 2015-01-25 12:37 ` Nguyễn Thái Ngọc Duy
  2015-01-25 12:37 ` [PATCH 07/21] ls-files: add --column Nguyễn Thái Ngọc Duy
                   ` (14 subsequent siblings)
  20 siblings, 0 replies; 31+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-01-25 12:37 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy, Junio C Hamano

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.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 b6f0d9f..0ee4f19 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.84.ge9c7a8a

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

* [PATCH 07/21] ls-files: add --column
  2015-01-25 12:37 [PATCH 00/21] nd/list-files updates Nguyễn Thái Ngọc Duy
                   ` (5 preceding siblings ...)
  2015-01-25 12:37 ` [PATCH 06/21] ls-files: add --color to highlight file names Nguyễn Thái Ngọc Duy
@ 2015-01-25 12:37 ` Nguyễn Thái Ngọc Duy
  2015-01-25 12:37 ` [PATCH 08/21] ls-files: support --max-depth Nguyễn Thái Ngọc Duy
                   ` (13 subsequent siblings)
  20 siblings, 0 replies; 31+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-01-25 12:37 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy, Junio C Hamano

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.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 0ee4f19..44e5628 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.84.ge9c7a8a

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

* [PATCH 08/21] ls-files: support --max-depth
  2015-01-25 12:37 [PATCH 00/21] nd/list-files updates Nguyễn Thái Ngọc Duy
                   ` (6 preceding siblings ...)
  2015-01-25 12:37 ` [PATCH 07/21] ls-files: add --column Nguyễn Thái Ngọc Duy
@ 2015-01-25 12:37 ` Nguyễn Thái Ngọc Duy
  2015-01-25 12:37 ` [PATCH 09/21] 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; 31+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-01-25 12:37 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy, Junio C Hamano

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.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 44e5628..09a6b8d 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.84.ge9c7a8a

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

* [PATCH 09/21] list-files: a user friendly version of ls-files and more
  2015-01-25 12:37 [PATCH 00/21] nd/list-files updates Nguyễn Thái Ngọc Duy
                   ` (7 preceding siblings ...)
  2015-01-25 12:37 ` [PATCH 08/21] ls-files: support --max-depth Nguyễn Thái Ngọc Duy
@ 2015-01-25 12:37 ` Nguyễn Thái Ngọc Duy
  2015-01-27 20:30   ` Junio C Hamano
  2015-01-25 12:37 ` [PATCH 10/21] list-files: make alias 'ls' default to 'list-files' Nguyễn Thái Ngọc Duy
                   ` (11 subsequent siblings)
  20 siblings, 1 reply; 31+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-01-25 12:37 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 09a6b8d..eca9407 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 | REFRESH_UNMERGED, &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.84.ge9c7a8a

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

* [PATCH 10/21] list-files: make alias 'ls' default to 'list-files'
  2015-01-25 12:37 [PATCH 00/21] nd/list-files updates Nguyễn Thái Ngọc Duy
                   ` (8 preceding siblings ...)
  2015-01-25 12:37 ` [PATCH 09/21] list-files: a user friendly version of ls-files and more Nguyễn Thái Ngọc Duy
@ 2015-01-25 12:37 ` Nguyễn Thái Ngọc Duy
  2015-01-25 12:37 ` [PATCH 11/21] list-files: -u does not imply showing stages Nguyễn Thái Ngọc Duy
                   ` (10 subsequent siblings)
  20 siblings, 0 replies; 31+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-01-25 12:37 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 ++-
 config.c                         | 8 ++++++++
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/Documentation/git-list-files.txt b/Documentation/git-list-files.txt
index 3039e1e..2182a38 100644
--- a/Documentation/git-list-files.txt
+++ b/Documentation/git-list-files.txt
@@ -14,7 +14,8 @@ 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...
+working tree are shown, or untracked files... The builtin alias "ls"
+is set to "list-files".
 
 OPTIONS
 -------
diff --git a/config.c b/config.c
index 15a2983..16209c6 100644
--- a/config.c
+++ b/config.c
@@ -40,6 +40,10 @@ static struct config_source *cf;
 
 static int zlib_compression_seen;
 
+static const char *builtin_config =
+	"[alias]\n"
+	"	ls = list-files\n";
+
 /*
  * Default config_set that contains key-value pairs from the usual set of config
  * config files (i.e repo specific .git/config, user wide ~/.gitconfig, XDG
@@ -1175,6 +1179,10 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
 
 	home_config_paths(&user_config, &xdg_config, "config");
 
+	if (git_config_system())
+		git_config_from_buf(fn, "<builtin>", builtin_config,
+				    strlen(builtin_config), data);
+
 	if (git_config_system() && !access_or_die(git_etc_gitconfig(), R_OK, 0)) {
 		ret += git_config_from_file(fn, git_etc_gitconfig(),
 					    data);
-- 
2.2.0.84.ge9c7a8a

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

* [PATCH 11/21] list-files: -u does not imply showing stages
  2015-01-25 12:37 [PATCH 00/21] nd/list-files updates Nguyễn Thái Ngọc Duy
                   ` (9 preceding siblings ...)
  2015-01-25 12:37 ` [PATCH 10/21] list-files: make alias 'ls' default to 'list-files' Nguyễn Thái Ngọc Duy
@ 2015-01-25 12:37 ` Nguyễn Thái Ngọc Duy
  2015-01-25 12:37 ` [PATCH 12/21] list-files: add -R/--recursive short for --max-depth=-1 Nguyễn Thái Ngọc Duy
                   ` (9 subsequent siblings)
  20 siblings, 0 replies; 31+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-01-25 12:37 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy, Junio C Hamano

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>
Signed-off-by: Junio C Hamano <gitster@pobox.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 eca9407..f2c29ce 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.84.ge9c7a8a

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

* [PATCH 12/21] list-files: add -R/--recursive short for --max-depth=-1
  2015-01-25 12:37 [PATCH 00/21] nd/list-files updates Nguyễn Thái Ngọc Duy
                   ` (10 preceding siblings ...)
  2015-01-25 12:37 ` [PATCH 11/21] list-files: -u does not imply showing stages Nguyễn Thái Ngọc Duy
@ 2015-01-25 12:37 ` Nguyễn Thái Ngọc Duy
  2015-01-25 12:37 ` [PATCH 13/21] list-files: add -1 short for --no-column Nguyễn Thái Ngọc Duy
                   ` (8 subsequent siblings)
  20 siblings, 0 replies; 31+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-01-25 12:37 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy, Junio C Hamano

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.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 2182a38..8d285c1 100644
--- a/Documentation/git-list-files.txt
+++ b/Documentation/git-list-files.txt
@@ -46,6 +46,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 f2c29ce..010291c 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.84.ge9c7a8a

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

* [PATCH 13/21] list-files: add -1 short for --no-column
  2015-01-25 12:37 [PATCH 00/21] nd/list-files updates Nguyễn Thái Ngọc Duy
                   ` (11 preceding siblings ...)
  2015-01-25 12:37 ` [PATCH 12/21] list-files: add -R/--recursive short for --max-depth=-1 Nguyễn Thái Ngọc Duy
@ 2015-01-25 12:37 ` Nguyễn Thái Ngọc Duy
  2015-01-25 12:37 ` [PATCH 14/21] list-files: add -t back Nguyễn Thái Ngọc Duy
                   ` (7 subsequent siblings)
  20 siblings, 0 replies; 31+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-01-25 12:37 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy, Junio C Hamano

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.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 8d285c1..1c0c877 100644
--- a/Documentation/git-list-files.txt
+++ b/Documentation/git-list-files.txt
@@ -50,6 +50,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 010291c..a80ac6a 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.84.ge9c7a8a

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

* [PATCH 14/21] list-files: add -t back
  2015-01-25 12:37 [PATCH 00/21] nd/list-files updates Nguyễn Thái Ngọc Duy
                   ` (12 preceding siblings ...)
  2015-01-25 12:37 ` [PATCH 13/21] list-files: add -1 short for --no-column Nguyễn Thái Ngọc Duy
@ 2015-01-25 12:37 ` Nguyễn Thái Ngọc Duy
  2015-01-25 12:37 ` [PATCH 15/21] list-files: sort output and remove duplicates Nguyễn Thái Ngọc Duy
                   ` (6 subsequent siblings)
  20 siblings, 0 replies; 31+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-01-25 12:37 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy, Junio C Hamano

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>
Signed-off-by: Junio C Hamano <gitster@pobox.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 1c0c877..9d4c127 100644
--- a/Documentation/git-list-files.txt
+++ b/Documentation/git-list-files.txt
@@ -46,6 +46,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 a80ac6a..b4b24ef 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.84.ge9c7a8a

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

* [PATCH 15/21] list-files: sort output and remove duplicates
  2015-01-25 12:37 [PATCH 00/21] nd/list-files updates Nguyễn Thái Ngọc Duy
                   ` (13 preceding siblings ...)
  2015-01-25 12:37 ` [PATCH 14/21] list-files: add -t back Nguyễn Thái Ngọc Duy
@ 2015-01-25 12:37 ` Nguyễn Thái Ngọc Duy
  2015-01-25 12:37 ` [PATCH 16/21] list-files: do not show duplicate cached entries Nguyễn Thái Ngọc Duy
                   ` (5 subsequent siblings)
  20 siblings, 0 replies; 31+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-01-25 12:37 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy, Junio C Hamano

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>
Signed-off-by: Junio C Hamano <gitster@pobox.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 b4b24ef..154dd9d 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.84.ge9c7a8a

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

* [PATCH 16/21] list-files: do not show duplicate cached entries
  2015-01-25 12:37 [PATCH 00/21] nd/list-files updates Nguyễn Thái Ngọc Duy
                   ` (14 preceding siblings ...)
  2015-01-25 12:37 ` [PATCH 15/21] list-files: sort output and remove duplicates Nguyễn Thái Ngọc Duy
@ 2015-01-25 12:37 ` Nguyễn Thái Ngọc Duy
  2015-01-25 12:37 ` [PATCH 17/21] list-files: show directories as well as files Nguyễn Thái Ngọc Duy
                   ` (4 subsequent siblings)
  20 siblings, 0 replies; 31+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-01-25 12:37 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 154dd9d..1a1c9c8 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_unmerged || 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 | REFRESH_UNMERGED, &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.84.ge9c7a8a

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

* [PATCH 17/21] list-files: show directories as well as files
  2015-01-25 12:37 [PATCH 00/21] nd/list-files updates Nguyễn Thái Ngọc Duy
                   ` (15 preceding siblings ...)
  2015-01-25 12:37 ` [PATCH 16/21] list-files: do not show duplicate cached entries Nguyễn Thái Ngọc Duy
@ 2015-01-25 12:37 ` Nguyễn Thái Ngọc Duy
  2015-01-25 19:16   ` Eric Sunshine
  2015-01-27 21:51   ` Junio C Hamano
  2015-01-25 12:37 ` [PATCH 18/21] list-files: add -F/--classify Nguyễn Thái Ngọc Duy
                   ` (3 subsequent siblings)
  20 siblings, 2 replies; 31+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-01-25 12:37 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 when output lis depth-limited.

The function show_as_directory() 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 | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 50 insertions(+), 2 deletions(-)

diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 1a1c9c8..29b5c2e 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;
@@ -179,6 +181,35 @@ static void show_killed_files(struct dir_struct *dir)
 	}
 }
 
+static int show_as_directory(const struct cache_entry *ce)
+{
+	struct strbuf sb = STRBUF_INIT;
+	const char *p;
+
+	strbuf_add(&sb, ce->name, ce_namelen(ce));
+	while (sb.len && (p = strrchr(sb.buf, '/')) != NULL) {
+		struct strbuf sb2 = STRBUF_INIT;
+		strbuf_setlen(&sb, p - sb.buf);
+		if (!match_pathspec(&pathspec, sb.buf, sb.len,
+				    max_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));
+		strbuf_fputs(&sb2, strbuf_detach(&sb, NULL), NULL);
+		strbuf_release(&sb2);
+		return 1;
+	}
+	strbuf_release(&sb);
+	return 0;
+}
+
 static void write_ce_name(struct strbuf *sb, const struct cache_entry *ce)
 {
 	struct strbuf quoted = STRBUF_INIT;
@@ -194,16 +225,31 @@ static void write_ce_name(struct strbuf *sb, const struct cache_entry *ce)
 static void show_ce_entry(const char *tag, const struct cache_entry *ce)
 {
 	static struct strbuf sb = STRBUF_INIT;
-	int len = max_prefix_len;
+	int len = max_prefix_len, saved_max_depth;
 
 	if (len >= ce_namelen(ce))
 		die("git ls-files: internal error - cache entry not superset of prefix");
 
+	if (show_dirs) {
+		/* ignore depth to catch dirs that contain matched entries */
+		saved_max_depth = pathspec.max_depth;
+		pathspec.max_depth = -1;
+	}
+
 	if (!match_pathspec(&pathspec, ce->name, ce_namelen(ce),
 			    len, ps_matched,
 			    S_ISDIR(ce->ce_mode) || S_ISGITLINK(ce->ce_mode)))
 		return;
 
+	if (show_dirs) {
+		pathspec.max_depth = saved_max_depth;
+		if (strchr(ce->name, '/') &&
+		    !match_pathspec(&pathspec, ce->name, ce_namelen(ce),
+				    prefix_len, NULL, 1) &&
+		    show_as_directory(ce))
+			return;
+	}
+
 	if (tag && *tag && show_valid_bit &&
 	    (ce->ce_flags & CE_VALID)) {
 		static char alttag[4];
@@ -575,7 +621,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;
@@ -744,6 +790,8 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 		       prefix, argv);
 	pathspec.max_depth = max_depth;
 	pathspec.recursive = 1;
+	show_dirs = porcelain && max_depth != -1;
+
 
 	/* Find common prefix for all pathspec's */
 	max_prefix = common_prefix(&pathspec);
-- 
2.2.0.84.ge9c7a8a

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

* [PATCH 18/21] list-files: add -F/--classify
  2015-01-25 12:37 [PATCH 00/21] nd/list-files updates Nguyễn Thái Ngọc Duy
                   ` (16 preceding siblings ...)
  2015-01-25 12:37 ` [PATCH 17/21] list-files: show directories as well as files Nguyễn Thái Ngọc Duy
@ 2015-01-25 12:37 ` Nguyễn Thái Ngọc Duy
  2015-01-25 12:37 ` [PATCH 19/21] list-files -F: show submodules with the new indicator '&' Nguyễn Thái Ngọc Duy
                   ` (2 subsequent siblings)
  20 siblings, 0 replies; 31+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-01-25 12:37 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 9d4c127..475c6da 100644
--- a/Documentation/git-list-files.txt
+++ b/Documentation/git-list-files.txt
@@ -52,6 +52,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 29b5c2e..bbeb4ce 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);
 }
@@ -202,6 +227,8 @@ static int show_as_directory(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);
 		strbuf_fputs(&sb2, strbuf_detach(&sb, NULL), NULL);
 		strbuf_release(&sb2);
 		return 1;
@@ -218,6 +245,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);
 }
@@ -706,6 +735,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.84.ge9c7a8a

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

* [PATCH 19/21] list-files -F: show submodules with the new indicator '&'
  2015-01-25 12:37 [PATCH 00/21] nd/list-files updates Nguyễn Thái Ngọc Duy
                   ` (17 preceding siblings ...)
  2015-01-25 12:37 ` [PATCH 18/21] list-files: add -F/--classify Nguyễn Thái Ngọc Duy
@ 2015-01-25 12:37 ` Nguyễn Thái Ngọc Duy
  2015-01-25 12:37 ` [PATCH 20/21] list-files: -M aka diff-cached Nguyễn Thái Ngọc Duy
  2015-01-25 12:37 ` [PATCH 21/21] t3080: tests for git-list-files Nguyễn Thái Ngọc Duy
  20 siblings, 0 replies; 31+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-01-25 12:37 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy, Junio C Hamano

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.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 475c6da..223f6fd 100644
--- a/Documentation/git-list-files.txt
+++ b/Documentation/git-list-files.txt
@@ -54,8 +54,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 bbeb4ce..697a307 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.84.ge9c7a8a

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

* [PATCH 20/21] list-files: -M aka diff-cached
  2015-01-25 12:37 [PATCH 00/21] nd/list-files updates Nguyễn Thái Ngọc Duy
                   ` (18 preceding siblings ...)
  2015-01-25 12:37 ` [PATCH 19/21] list-files -F: show submodules with the new indicator '&' Nguyễn Thái Ngọc Duy
@ 2015-01-25 12:37 ` Nguyễn Thái Ngọc Duy
  2015-01-25 12:37 ` [PATCH 21/21] t3080: tests for git-list-files Nguyễn Thái Ngọc Duy
  20 siblings, 0 replies; 31+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-01-25 12:37 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 | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 64 insertions(+), 3 deletions(-)

diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 697a307..b04c712 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 = "";
 
@@ -404,7 +409,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);
 		}
 	}
@@ -424,7 +437,8 @@ static void show_files_compact(struct dir_struct *dir)
 		if (show_killed)
 			show_killed_files(dir);
 	}
-	if (!(show_cached || show_unmerged || show_deleted || show_modified))
+	if (!(show_cached || show_unmerged || show_deleted ||
+	      show_modified || show_diff_cached))
 		return;
 	for (i = 0; i < active_nr; i++) {
 		const struct cache_entry *ce = active_cache[i];
@@ -444,6 +458,15 @@ static void show_files_compact(struct dir_struct *dir)
 			show_ce_entry(tag_removed, ce);
 			shown = 1;
 		}
+		if (show_diff_cached && (ce->ce_flags & CE_MATCHED)) {
+			show_ce_entry(tag_diff_cached, ce);
+			shown = 1;
+			/*
+			 * 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);
 			shown = 1;
@@ -457,6 +480,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"
  */
@@ -726,6 +781,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,
@@ -839,11 +896,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 ";
@@ -851,6 +909,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 ";
@@ -871,6 +930,8 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
 		refresh_index(&the_index, REFRESH_QUIET | REFRESH_UNMERGED, &pathspec, NULL, NULL);
 		setup_pager();
 	}
+	if (show_diff_cached)
+		diff_cached(&pathspec);
 	if (porcelain)
 		show_files_compact(&dir);
 	else
-- 
2.2.0.84.ge9c7a8a

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

* [PATCH 21/21] t3080: tests for git-list-files
  2015-01-25 12:37 [PATCH 00/21] nd/list-files updates Nguyễn Thái Ngọc Duy
                   ` (19 preceding siblings ...)
  2015-01-25 12:37 ` [PATCH 20/21] list-files: -M aka diff-cached Nguyễn Thái Ngọc Duy
@ 2015-01-25 12:37 ` Nguyễn Thái Ngọc Duy
  2015-01-25 19:20   ` Eric Sunshine
  20 siblings, 1 reply; 31+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-01-25 12:37 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>
---
 t/t3080-list-files.sh (new +x) | 122 +++++++++++++++++++++++++++++++++++++++++
 t/t3080/color_ls (new)         |   3 +
 t/t3080/ls_colors (new)        |   2 +
 3 files changed, 127 insertions(+)
 create mode 100755 t/t3080-list-files.sh
 create mode 100644 t/t3080/color_ls
 create mode 100644 t/t3080/ls_colors

diff --git a/t/t3080-list-files.sh b/t/t3080-list-files.sh
new file mode 100755
index 0000000..6313dd9
--- /dev/null
+++ b/t/t3080-list-files.sh
@@ -0,0 +1,122 @@
+#!/bin/sh
+
+test_description='git list-files test'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+	mkdir dir &&
+	touch file dir/file &&
+	git init gitlink &&
+	( cd gitlink && test_commit foo ) &&
+	git add file dir/file gitlink &&
+	git commit -qm1
+'
+
+test_expect_success 'LS_COLORS env variable' '
+	LS_COLORS="rs=0:fi=31:di=32" \
+		git list-files --color=always | grep -v gitlink >actual &&
+	test_cmp "$TEST_DIRECTORY"/t3080/ls_colors actual
+'
+
+test_expect_success 'color.ls.*' '
+	test_config color.ls.file red &&
+	test_config color.ls.directory green &&
+	test_config color.ls.submodule yellow &&
+	git list-files --color=always >actual &&
+	test_cmp "$TEST_DIRECTORY"/t3080/color_ls actual
+'
+
+test_expect_success 'column output' '
+	COLUMNS=20 git list-files --column=always >actual &&
+	cat >expected <<-\EOF &&
+	dir      gitlink
+	file
+	EOF
+	test_cmp expected actual &&
+	git list-files -1 >actual &&
+	cat >expected <<-\EOF &&
+	dir
+	file
+	gitlink
+	EOF
+	test_cmp expected actual
+'
+
+test_expect_success '--max-depth' '
+	git list-files --max-depth=1 >actual &&
+	cat >expected <<-\EOF &&
+	dir/file
+	file
+	gitlink
+	EOF
+	test_cmp expected actual
+'
+
+test_expect_success 'recursive' '
+	git list-files -R >actual &&
+	cat >expected <<-\EOF &&
+	dir/file
+	file
+	gitlink
+	EOF
+	test_cmp expected actual
+'
+
+test_expect_success 'globbing' '
+	git list-files "f*" >actual &&
+	cat >expected <<-\EOF &&
+	file
+	EOF
+	test_cmp expected actual &&
+	git list-files "**/f*" >actual &&
+	cat >expected <<-\EOF &&
+	dir/file
+	file
+	EOF
+	test_cmp expected actual
+'
+
+test_expect_success 'no dups' '
+	echo dirty >>file &&
+	git list-files -m file >actual &&
+	echo "file" >expected &&
+	test_cmp expected actual &&
+	git list-files -cm file >actual &&
+	echo "C file" >expected &&
+	test_cmp expected actual &&
+	git list-files -tcm file >actual &&
+	test_cmp expected actual
+'
+
+test_expect_success '--classify' '
+	git list-files -F >actual &&
+	cat >expected <<-\EOF &&
+	dir/
+	file
+	gitlink&
+	EOF
+	test_cmp expected actual
+'
+
+test_expect_success 'diff-cached' '
+	echo dirty >>file &&
+	git add file &&
+	git list-files -M >actual &&
+	echo "file" >expected &&
+	test_cmp expected actual
+'
+
+test_expect_success 'unmerged files' '
+	git ls-files --stage file >index-info &&
+	sed "s/ 0/ 2/;s/file/unmerged/" index-info | git update-index --index-info &&
+	sed "s/ 0/ 3/;s,file,dir/unmerged," index-info | git update-index --index-info &&
+	git list-files -u >actual &&
+	cat >expected <<-\EOF &&
+	dir
+	unmerged
+	EOF
+	test_cmp expected actual
+'
+
+test_done
diff --git a/t/t3080/color_ls b/t/t3080/color_ls
new file mode 100644
index 0000000..47f77ad
--- /dev/null
+++ b/t/t3080/color_ls
@@ -0,0 +1,3 @@
+^[[32mdir^[[m
+^[[31mfile^[[m
+^[[33mgitlink^[[m
diff --git a/t/t3080/ls_colors b/t/t3080/ls_colors
new file mode 100644
index 0000000..423c016
--- /dev/null
+++ b/t/t3080/ls_colors
@@ -0,0 +1,2 @@
+^[[32mdir^[[m
+^[[31mfile^[[m
-- 
2.2.0.84.ge9c7a8a

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

* Re: [PATCH 17/21] list-files: show directories as well as files
  2015-01-25 12:37 ` [PATCH 17/21] list-files: show directories as well as files Nguyễn Thái Ngọc Duy
@ 2015-01-25 19:16   ` Eric Sunshine
  2015-01-27 21:51   ` Junio C Hamano
  1 sibling, 0 replies; 31+ messages in thread
From: Eric Sunshine @ 2015-01-25 19:16 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: Git List

On Sun, Jan 25, 2015 at 7:37 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:
> The index does not store directories explicitly (except submodules) so
> we have to figure them out from file list when output lis depth-limited.
>
> The function show_as_directory() 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>
> ---
> diff --git a/builtin/ls-files.c b/builtin/ls-files.c
> index 1a1c9c8..29b5c2e 100644
> --- a/builtin/ls-files.c
> +++ b/builtin/ls-files.c
> @@ -179,6 +181,35 @@ static void show_killed_files(struct dir_struct *dir)
>         }
>  }
>
> +static int show_as_directory(const struct cache_entry *ce)
> +{
> +       struct strbuf sb = STRBUF_INIT;
> +       const char *p;
> +
> +       strbuf_add(&sb, ce->name, ce_namelen(ce));
> +       while (sb.len && (p = strrchr(sb.buf, '/')) != NULL) {
> +               struct strbuf sb2 = STRBUF_INIT;
> +               strbuf_setlen(&sb, p - sb.buf);
> +               if (!match_pathspec(&pathspec, sb.buf, sb.len,
> +                                   max_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;

Although more expensive, would it be a bit more idiomatic and obvious
to phrase this as

    strbuf_swap(&sb2, &sb3);
    strbuf_release(&sb3);

or is it not worth it?

> +               }
> +               if (show_tag)
> +                       strbuf_insert(&sb2, 0, tag_cached, strlen(tag_cached));
> +               strbuf_fputs(&sb2, strbuf_detach(&sb, NULL), NULL);

The detached strbuf content gets assigned to the 'util' field of the
'struct string_list output' item and is eventually leaked, however,
the program exits soon after. Okay.

> +               strbuf_release(&sb2);
> +               return 1;
> +       }
> +       strbuf_release(&sb);
> +       return 0;
> +}
> +
>  static void write_ce_name(struct strbuf *sb, const struct cache_entry *ce)
>  {
>         struct strbuf quoted = STRBUF_INIT;

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

* Re: [PATCH 21/21] t3080: tests for git-list-files
  2015-01-25 12:37 ` [PATCH 21/21] t3080: tests for git-list-files Nguyễn Thái Ngọc Duy
@ 2015-01-25 19:20   ` Eric Sunshine
  2015-01-28  4:44     ` Michael Blume
  0 siblings, 1 reply; 31+ messages in thread
From: Eric Sunshine @ 2015-01-25 19:20 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: Git List

On Sun, Jan 25, 2015 at 7:37 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:
> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
> ---
> diff --git a/t/t3080-list-files.sh b/t/t3080-list-files.sh
> new file mode 100755
> index 0000000..6313dd9
> --- /dev/null
> +++ b/t/t3080-list-files.sh
> +test_expect_success 'no dups' '
> +       echo dirty >>file &&

To leave a clean slate for subsequent tests, would it make sense to
restore 'file' to a clean state via test_when_finished()?

> +       git list-files -m file >actual &&
> +       echo "file" >expected &&
> +       test_cmp expected actual &&
> +       git list-files -cm file >actual &&
> +       echo "C file" >expected &&
> +       test_cmp expected actual &&
> +       git list-files -tcm file >actual &&
> +       test_cmp expected actual
> +'
> +
> +test_expect_success 'diff-cached' '
> +       echo dirty >>file &&
> +       git add file &&

Ditto here?

> +       git list-files -M >actual &&
> +       echo "file" >expected &&
> +       test_cmp expected actual
> +'

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

* Re: [PATCH 09/21] list-files: a user friendly version of ls-files and more
  2015-01-25 12:37 ` [PATCH 09/21] list-files: a user friendly version of ls-files and more Nguyễn Thái Ngọc Duy
@ 2015-01-27 20:30   ` Junio C Hamano
  0 siblings, 0 replies; 31+ messages in thread
From: Junio C Hamano @ 2015-01-27 20:30 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: git

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

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

This violates the configuration variable naming rules; perhaps
rename it to color.listFiles or something?

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

* Re: [PATCH 17/21] list-files: show directories as well as files
  2015-01-25 12:37 ` [PATCH 17/21] list-files: show directories as well as files Nguyễn Thái Ngọc Duy
  2015-01-25 19:16   ` Eric Sunshine
@ 2015-01-27 21:51   ` Junio C Hamano
  1 sibling, 0 replies; 31+ messages in thread
From: Junio C Hamano @ 2015-01-27 21:51 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: git

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

> @@ -194,16 +225,31 @@ static void write_ce_name(struct strbuf *sb, const struct cache_entry *ce)
>  static void show_ce_entry(const char *tag, const struct cache_entry *ce)
>  {
>  	static struct strbuf sb = STRBUF_INIT;
> -	int len = max_prefix_len;
> +	int len = max_prefix_len, saved_max_depth;
>  
>  	if (len >= ce_namelen(ce))
>  		die("git ls-files: internal error - cache entry not superset of prefix");
>  
> +	if (show_dirs) {
> +		/* ignore depth to catch dirs that contain matched entries */
> +		saved_max_depth = pathspec.max_depth;
> +		pathspec.max_depth = -1;
> +	}
> +
>  	if (!match_pathspec(&pathspec, ce->name, ce_namelen(ce),
>  			    len, ps_matched,
>  			    S_ISDIR(ce->ce_mode) || S_ISGITLINK(ce->ce_mode)))
>  		return;
>  
> +	if (show_dirs) {
> +		pathspec.max_depth = saved_max_depth;
> +		if (strchr(ce->name, '/') &&
> +		    !match_pathspec(&pathspec, ce->name, ce_namelen(ce),
> +				    prefix_len, NULL, 1) &&
> +		    show_as_directory(ce))
> +			return;
> +	}
> +

My compiler seems to be too stupid to notice that saved_max_depth is
always set before it is used, if it gets used and complains.  Sigh.

For now I am tempted to squash this in.  Note that the original does
not seem to restore saved_max_depath when the pathspec does not match
and function returns in the call to match_pathspec() we have in the
code before your patch, which smells like a bug, and the attached
would fix it.

 builtin/ls-files.c | 33 ++++++++++++++++++++++-----------
 1 file changed, 22 insertions(+), 11 deletions(-)

diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 29b5c2e..f28b7e9 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -222,27 +222,38 @@ static void write_ce_name(struct strbuf *sb, const struct cache_entry *ce)
 	strbuf_release(&quoted);
 }
 
+static int match_pathspec_with_depth(struct pathspec *ps,
+				     const char *name, int namelen,
+				     int prefix, char *seen, int is_dir,
+				     const int *custom_depth)
+{
+	int saved_depth = ps->max_depth;
+	int result;
+
+	if (custom_depth)
+		ps->max_depth = *custom_depth;
+	result = match_pathspec(ps, name, namelen, prefix, seen, is_dir);
+	if (custom_depth)
+		ps->max_depth = saved_depth;
+	return result;
+}
+
 static void show_ce_entry(const char *tag, const struct cache_entry *ce)
 {
 	static struct strbuf sb = STRBUF_INIT;
-	int len = max_prefix_len, saved_max_depth;
+	int len = max_prefix_len;
+	static const int infinite_depth = -1;
 
 	if (len >= ce_namelen(ce))
 		die("git ls-files: internal error - cache entry not superset of prefix");
 
-	if (show_dirs) {
-		/* ignore depth to catch dirs that contain matched entries */
-		saved_max_depth = pathspec.max_depth;
-		pathspec.max_depth = -1;
-	}
-
-	if (!match_pathspec(&pathspec, ce->name, ce_namelen(ce),
-			    len, ps_matched,
-			    S_ISDIR(ce->ce_mode) || S_ISGITLINK(ce->ce_mode)))
+	if (!match_pathspec_with_depth(&pathspec, ce->name, ce_namelen(ce),
+				       len, ps_matched,
+				       S_ISDIR(ce->ce_mode) || S_ISGITLINK(ce->ce_mode),
+				       show_dirs ? &infinite_depth : NULL))
 		return;
 
 	if (show_dirs) {
-		pathspec.max_depth = saved_max_depth;
 		if (strchr(ce->name, '/') &&
 		    !match_pathspec(&pathspec, ce->name, ce_namelen(ce),
 				    prefix_len, NULL, 1) &&

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

* Re: [PATCH 21/21] t3080: tests for git-list-files
  2015-01-25 19:20   ` Eric Sunshine
@ 2015-01-28  4:44     ` Michael Blume
  2015-01-28 10:19       ` Duy Nguyen
  2015-01-28 19:03       ` Junio C Hamano
  0 siblings, 2 replies; 31+ messages in thread
From: Michael Blume @ 2015-01-28  4:44 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: Nguyễn Thái Ngọc Duy, Git List

Test 3 is failing on my mac:

expecting success:
test_config color.ls.file red &&
test_config color.ls.directory green &&
test_config color.ls.submodule yellow &&
git list-files --color=always >actual &&
test_cmp "$TEST_DIRECTORY"/t3080/color_ls actual

--- /Users/michael.blume/workspace/git/t/t3080/color_ls 2015-01-28
04:40:23.000000000 +0000
+++ actual 2015-01-28 04:42:59.000000000 +0000
@@ -1,3 +1,3 @@
-dir
-file
-gitlink
+dir
+file
+gitlink
not ok 3 - color.ls.*
#
# test_config color.ls.file red &&
# test_config color.ls.directory green &&
# test_config color.ls.submodule yellow &&
# git list-files --color=always >actual &&
# test_cmp "$TEST_DIRECTORY"/t3080/color_ls actual
#

On Sun, Jan 25, 2015 at 11:20 AM, Eric Sunshine <sunshine@sunshineco.com> wrote:
> On Sun, Jan 25, 2015 at 7:37 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:
>> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
>> ---
>> diff --git a/t/t3080-list-files.sh b/t/t3080-list-files.sh
>> new file mode 100755
>> index 0000000..6313dd9
>> --- /dev/null
>> +++ b/t/t3080-list-files.sh
>> +test_expect_success 'no dups' '
>> +       echo dirty >>file &&
>
> To leave a clean slate for subsequent tests, would it make sense to
> restore 'file' to a clean state via test_when_finished()?
>
>> +       git list-files -m file >actual &&
>> +       echo "file" >expected &&
>> +       test_cmp expected actual &&
>> +       git list-files -cm file >actual &&
>> +       echo "C file" >expected &&
>> +       test_cmp expected actual &&
>> +       git list-files -tcm file >actual &&
>> +       test_cmp expected actual
>> +'
>> +
>> +test_expect_success 'diff-cached' '
>> +       echo dirty >>file &&
>> +       git add file &&
>
> Ditto here?
>
>> +       git list-files -M >actual &&
>> +       echo "file" >expected &&
>> +       test_cmp expected actual
>> +'
> --
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* Re: [PATCH 21/21] t3080: tests for git-list-files
  2015-01-28  4:44     ` Michael Blume
@ 2015-01-28 10:19       ` Duy Nguyen
  2015-01-28 17:49         ` Michael Blume
  2015-01-28 19:03       ` Junio C Hamano
  1 sibling, 1 reply; 31+ messages in thread
From: Duy Nguyen @ 2015-01-28 10:19 UTC (permalink / raw)
  To: Michael Blume; +Cc: Eric Sunshine, Git List

On Wed, Jan 28, 2015 at 11:44 AM, Michael Blume <blume.mike@gmail.com> wrote:
> Test 3 is failing on my mac:
>
> expecting success:
> test_config color.ls.file red &&
> test_config color.ls.directory green &&
> test_config color.ls.submodule yellow &&
> git list-files --color=always >actual &&
> test_cmp "$TEST_DIRECTORY"/t3080/color_ls actual
>
> --- /Users/michael.blume/workspace/git/t/t3080/color_ls 2015-01-28
> 04:40:23.000000000 +0000
> +++ actual 2015-01-28 04:42:59.000000000 +0000
> @@ -1,3 +1,3 @@
> -dir
> -file
> -gitlink
> +dir
> +file
> +gitlink

Urgh.. colors do not send well over plain text.. I just realized we
have test_decode_color to convert colors to text descriptions.. will
fix..

Anyway, I think i may know why it fails. I suppose  the env variable
LS_COLORS is not defined, or defined as empty in your shell?
-- 
Duy

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

* Re: [PATCH 21/21] t3080: tests for git-list-files
  2015-01-28 10:19       ` Duy Nguyen
@ 2015-01-28 17:49         ` Michael Blume
  0 siblings, 0 replies; 31+ messages in thread
From: Michael Blume @ 2015-01-28 17:49 UTC (permalink / raw)
  To: Duy Nguyen; +Cc: Eric Sunshine, Git List

On Wed, Jan 28, 2015 at 2:19 AM, Duy Nguyen <pclouds@gmail.com> wrote:
> On Wed, Jan 28, 2015 at 11:44 AM, Michael Blume <blume.mike@gmail.com> wrote:
>> Test 3 is failing on my mac:
>>
>> expecting success:
>> test_config color.ls.file red &&
>> test_config color.ls.directory green &&
>> test_config color.ls.submodule yellow &&
>> git list-files --color=always >actual &&
>> test_cmp "$TEST_DIRECTORY"/t3080/color_ls actual
>>
>> --- /Users/michael.blume/workspace/git/t/t3080/color_ls 2015-01-28
>> 04:40:23.000000000 +0000
>> +++ actual 2015-01-28 04:42:59.000000000 +0000
>> @@ -1,3 +1,3 @@
>> -dir
>> -file
>> -gitlink
>> +dir
>> +file
>> +gitlink
>
> Urgh.. colors do not send well over plain text.. I just realized we
> have test_decode_color to convert colors to text descriptions.. will
> fix..
>
> Anyway, I think i may know why it fails. I suppose  the env variable
> LS_COLORS is not defined, or defined as empty in your shell?
> --
> Duy


In case it helps:
https://www.dropbox.com/s/zsm3xgulmsl3rqm/Screenshot%202015-01-28%2009.46.57.png?dl=0

Also no, LS_COLORS is not defined

$ echo $LS_COLORS

$

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

* Re: [PATCH 21/21] t3080: tests for git-list-files
  2015-01-28  4:44     ` Michael Blume
  2015-01-28 10:19       ` Duy Nguyen
@ 2015-01-28 19:03       ` Junio C Hamano
  1 sibling, 0 replies; 31+ messages in thread
From: Junio C Hamano @ 2015-01-28 19:03 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy
  Cc: Michael Blume, Eric Sunshine, Git List

Michael Blume <blume.mike@gmail.com> writes:

> Test 3 is failing on my mac:
>
> expecting success:
> test_config color.ls.file red &&
> test_config color.ls.directory green &&
> test_config color.ls.submodule yellow &&
> git list-files --color=always >actual &&
> test_cmp "$TEST_DIRECTORY"/t3080/color_ls actual
>
> --- /Users/michael.blume/workspace/git/t/t3080/color_ls 2015-01-28
> 04:40:23.000000000 +0000
> +++ actual 2015-01-28 04:42:59.000000000 +0000
> @@ -1,3 +1,3 @@
> -dir
> -file
> -gitlink
> +dir
> +file
> +gitlink
> not ok 3 - color.ls.*

Same here on Ubuntu.

Regardless of the breakage in the code that violates the expectation
of this test, I do not think you would want to have test_cmp compare
coloured output directly without using test_decode_color.

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

* [PATCH 00/21] nd/list-files updates
@ 2015-02-08  9:01 Nguyễn Thái Ngọc Duy
  0 siblings, 0 replies; 31+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2015-02-08  9:01 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy

- 02/21: fix a bug that ignores config keys if $LS_COLORS is not defined
- 09/21: use listFiles instead of list-files in config keys
- 17/21: incorporate match_pathspec changes from Junio,
    use strbuf_swap in show_as_directory()
- 21/21: use test_decode_color and test_when_finished in t3080

Full diff of changes is

-- 8< --
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 74da715..2dc4788 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -940,7 +940,7 @@ color.status.<slot>::
 	to red). The values of these variables may be specified as in
 	color.branch.<slot>.
 
-color.list-files::
+color.listFiles::
 	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
@@ -1018,7 +1018,7 @@ 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::
+column.listFiles::
 	Specify whether to output tag listing in `git list-files` in columns.
 	See `column.ui` for details.
 
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index b04c712..b5e1a59 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -229,8 +229,8 @@ static int show_as_directory(const struct cache_entry *ce)
 		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;
+			strbuf_swap(&sb2, &sb3);
+			strbuf_release(&sb3);
 		}
 		if (show_tag)
 			strbuf_insert(&sb2, 0, tag_cached, strlen(tag_cached));
@@ -258,33 +258,41 @@ static void write_ce_name(struct strbuf *sb, const struct cache_entry *ce)
 	strbuf_release(&quoted);
 }
 
+static int match_pathspec_with_depth(struct pathspec *ps,
+				     const char *name, int namelen,
+				     int prefix, char *seen, int is_dir,
+				     const int *custom_depth)
+{
+	int saved_depth = ps->max_depth;
+	int result;
+
+	if (custom_depth)
+		ps->max_depth = *custom_depth;
+	result = match_pathspec(ps, name, namelen, prefix, seen, is_dir);
+	if (custom_depth)
+		ps->max_depth = saved_depth;
+	return result;
+}
+
 static void show_ce_entry(const char *tag, const struct cache_entry *ce)
 {
 	static struct strbuf sb = STRBUF_INIT;
-	int len = max_prefix_len, saved_max_depth;
+	static const int infinite_depth = -1;
+	int len = max_prefix_len;
 
 	if (len >= ce_namelen(ce))
 		die("git ls-files: internal error - cache entry not superset of prefix");
 
-	if (show_dirs) {
-		/* ignore depth to catch dirs that contain matched entries */
-		saved_max_depth = pathspec.max_depth;
-		pathspec.max_depth = -1;
-	}
-
-	if (!match_pathspec(&pathspec, ce->name, ce_namelen(ce),
-			    len, ps_matched,
-			    S_ISDIR(ce->ce_mode) || S_ISGITLINK(ce->ce_mode)))
+	if (!match_pathspec_with_depth(&pathspec, ce->name, ce_namelen(ce),
+				       len, ps_matched,
+				       S_ISDIR(ce->ce_mode) || S_ISGITLINK(ce->ce_mode),
+				       show_dirs ? &infinite_depth : NULL))
 		return;
 
-	if (show_dirs) {
-		pathspec.max_depth = saved_max_depth;
-		if (strchr(ce->name, '/') &&
-		    !match_pathspec(&pathspec, ce->name, ce_namelen(ce),
-				    prefix_len, NULL, 1) &&
-		    show_as_directory(ce))
-			return;
-	}
+	if (show_dirs &&strchr(ce->name, '/') &&
+	    !match_pathspec(&pathspec, ce->name, ce_namelen(ce), prefix_len, NULL, 1) &&
+	    show_as_directory(ce))
+		return;
 
 	if (tag && *tag && show_valid_bit &&
 	    (ce->ce_flags & CE_VALID)) {
@@ -697,8 +705,8 @@ static int option_parse_exclude_standard(const struct option *opt,
 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")) {
+		return git_column_config(var, value, "listfiles", &colopts);
+	if (!strcmp(var, "color.listfiles")) {
 		use_color = git_config_colorbool(var, value);
 		return 0;
 	}
diff --git a/ls_colors.c b/ls_colors.c
index 9259ad3..011a8b9 100644
--- a/ls_colors.c
+++ b/ls_colors.c
@@ -326,8 +326,10 @@ void parse_ls_color(void)
 	char *start;
 	size_t len;
 
-	if ((p = getenv("LS_COLORS")) == NULL || *p == '\0')
+	if ((p = getenv("LS_COLORS")) == NULL || *p == '\0') {
+		git_config(ls_colors_config, NULL);
 		return;
+	}
 
 	ext = NULL;
 	strcpy(label, "??");
diff --git a/t/t3080-list-files.sh b/t/t3080-list-files.sh
index 6313dd9..01b9662 100755
--- a/t/t3080-list-files.sh
+++ b/t/t3080-list-files.sh
@@ -15,16 +15,26 @@ test_expect_success 'setup' '
 
 test_expect_success 'LS_COLORS env variable' '
 	LS_COLORS="rs=0:fi=31:di=32" \
-		git list-files --color=always | grep -v gitlink >actual &&
-	test_cmp "$TEST_DIRECTORY"/t3080/ls_colors actual
+		git list-files --color=always | test_decode_color | \
+		grep -v gitlink >actual &&
+	cat >expected <<-\EOF &&
+	<GREEN>dir<RESET>
+	<RED>file<RESET>
+	EOF
+	test_cmp expected actual
 '
 
 test_expect_success 'color.ls.*' '
 	test_config color.ls.file red &&
 	test_config color.ls.directory green &&
 	test_config color.ls.submodule yellow &&
-	git list-files --color=always >actual &&
-	test_cmp "$TEST_DIRECTORY"/t3080/color_ls actual
+	git list-files --color=always | test_decode_color >actual &&
+	cat >expected <<-\EOF &&
+	<GREEN>dir<RESET>
+	<RED>file<RESET>
+	<YELLOW>gitlink<RESET>
+	EOF
+	test_cmp expected actual
 '
 
 test_expect_success 'column output' '
@@ -78,6 +88,7 @@ test_expect_success 'globbing' '
 '
 
 test_expect_success 'no dups' '
+	test_when_finished "git checkout file" &&
 	echo dirty >>file &&
 	git list-files -m file >actual &&
 	echo "file" >expected &&
@@ -100,6 +111,7 @@ test_expect_success '--classify' '
 '
 
 test_expect_success 'diff-cached' '
+	test_when_finished "git checkout file" &&
 	echo dirty >>file &&
 	git add file &&
 	git list-files -M >actual &&
diff --git a/t/t3080/color_ls b/t/t3080/color_ls
deleted file mode 100644
index 47f77ad..0000000
--- a/t/t3080/color_ls
+++ /dev/null
@@ -1,3 +0,0 @@
-^[[32mdir^[[m
-^[[31mfile^[[m
-^[[33mgitlink^[[m
diff --git a/t/t3080/ls_colors b/t/t3080/ls_colors
deleted file mode 100644
index 423c016..0000000
--- a/t/t3080/ls_colors
+++ /dev/null
@@ -1,2 +0,0 @@
-^[[32mdir^[[m
-^[[31mfile^[[m
-- 8< --
-- 
2.3.0.rc1.137.g477eb31

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

end of thread, other threads:[~2015-02-08  9:02 UTC | newest]

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

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.