Re: [PATCH 17/21] list-files: show directories as well as files
Nguyễn Thái Ngọc Duy pclo...@gmail.com writes: + if (show_dirs strchr(ce-name, '/') Oops. Will fix it up locally. -- To unsubscribe from this list: send the line unsubscribe git in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 17/21] list-files: show directories as well as files
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. Helped-by: Eric Sunshine sunsh...@sunshineco.com Helped-by: Junio C Hamano gits...@pobox.com Signed-off-by: Nguyễn Thái Ngọc Duy pclo...@gmail.com --- builtin/ls-files.c | 64 ++ 1 file changed, 60 insertions(+), 4 deletions(-) diff --git a/builtin/ls-files.c b/builtin/ls-files.c index 457d067..6be08fb 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_swap(sb2, sb3); + strbuf_release(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; @@ -191,17 +222,40 @@ 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; + 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 (!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 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 @@ -575,7 +629,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 +798,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.3.0.rc1.137.g477eb31 -- To unsubscribe from this list: send the line unsubscribe git in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 17/21] list-files: show directories as well as files
Nguyễn Thái Ngọc Duy pclo...@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) -- To unsubscribe from this list: send the line unsubscribe git in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 17/21] list-files: show directories as well as files
On Sun, Jan 25, 2015 at 7:37 AM, Nguyễn Thái Ngọc Duy pclo...@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 pclo...@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; -- To unsubscribe from this list: send the line unsubscribe git in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 17/21] list-files: show directories as well as files
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 pclo...@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 -- To unsubscribe from this list: send the line unsubscribe git in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html