Subject: [PATCH 15/16] ls: strip common directory prefix from output

From: Nguyễn Thái Ngọc Duy <[email-masked]>
Date: Wed, 9 Feb 2011 19:24:43 +0700

In GNU ls, files are printed relative to their parent directory.
We don't have such thing, so stay as close as we can.

The result is quite good. If the given pathspec is a directory prefix,
it will be stripped, strictly following GNU ls behavior. If the pathspec
has wildcards, then the command part is stripped. Usually this is the
prefix part in the pathspec.

Signed-off-by: Nguyễn Thái Ngọc Duy <[email-masked]>
---
 builtin/ls-files.c |   37 +++++++++++++++++++++++++++++++++++++
 1 files changed, 37 insertions(+), 0 deletions(-)

diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 22e0c87..bc438b2 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -710,6 +710,41 @@ static int one_match_pathspec(const char *pathspec)
 	return 0;
 }
 
+static void remove_common_prefix()
+{
+	int i, len = -1;
+	const char *s1, *s2;
+
+	if (output.nr <= 1)
+		return;
+
+	/*
+	 * Eliminate common prefix. This is caused by a prefix
+	 * pathspec like "ls builtin" or even "ls 't/t*.sh'"
+	 */
+
+	s1 = output.items[output.nr-1].string;
+	len = strlen(s1);
+	for (i = 1; i < output.nr; i++) {
+		int j = 0;
+		s1 = output.items[i-1].string;
+		s2 = output.items[i].string;
+		while (j < len && s1[j] == s2[j])
+			j++;
+		len = j;
+	}
+	while (len && s1[len] != '/')
+		len--;
+	if (len && s1[len] == '/')
+		len++;
+	if (len) {
+		for (i = 0; i < output.nr; i++) {
+			char *s = output.items[i].string;
+			memcpy(s, s+len, strlen(s) - len + 1);
+		}
+	}
+}
+
 int cmd_ls(int argc, const char **argv, const char *cmd_prefix)
 {
 	int show_pathspec;
@@ -801,6 +836,7 @@ int cmd_ls(int argc, const char **argv, const char *cmd_prefix)
 		one_matches[len] = NULL;
 		pathspec = one_matches;
 		show_files(&dir);
+		remove_common_prefix();
 		display_columns(&output, column_mode, term_columns(), 2, NULL);
 		string_list_clear(&output, 0);
 		if (dst)
@@ -821,6 +857,7 @@ int cmd_ls(int argc, const char **argv, const char *cmd_prefix)
 		if (output.nr && show_pathspec)
 			printf("%s:\n", pathspec[0]);
 
+		remove_common_prefix();
 		display_columns(&output, column_mode, term_columns(), 2, NULL);
 		string_list_clear(&output, 0);
 		if (show_pathspec && pathspecs[0])
-- 
1.7.2.2