Last time I tried this was more than two years ago [1]. It's time for
another try and see if the community has any interest in it.
The command is straight forward, it's a ls-like version for listing
things in git. It respects $LS_COLORS and does column output like GNU
ls. "ls" shows cached entries (but no recursion), "ls -o"
show untracked files. I want ls-tree, "diff --name-only" and "diff
--name-only --cached" too, but they are not implemented yet.
WIP quality, this is to gather comments on the idea.
[1] http://thread.gmane.org/gmane.comp.version-control.git/166405
Nguyễn Thái Ngọc Duy (8):
Import $LS_COLORS parsing code from coreutils
ls_colors.c: a bit of document on print_color_indicator input
ls_colors.c: enable coloring on u+x files
ls_colors.c: new color descriptors
ls-files: add --color to highlight based on $LS_COLORS
ls-files: add --column
ls-files: support --max-depth
Add git-ls, a user friendly version of ls-files and more
Makefile | 1 +
builtin.h | 1 +
builtin/ls-files.c | 80 ++++++++-
git.c | 1 +
ls_colors.c (new) | 487 +++++++++++++++++++++++++++++++++++++++++++++++++++++
ls_colors.h (new) | 20 +++
6 files changed, 588 insertions(+), 2 deletions(-)
create mode 100644 ls_colors.c
create mode 100644 ls_colors.h
--
1.9.0.40.gaa8c3ea
This could could help highlight files in ls-files or status output, or
even diff --name-only (but that's questionable).
This code is from coreutils.git commit
7326d1f1a67edf21947ae98194f98c38b6e9e527 file src/ls.c. This is the
last GPL-2 commit before coreutils turns to GPL-3.
The code is reformatted to fit Git coding style, which is more than
just adding and removing spaces. For example, "bool" is replaced with
"int", or true/false replaced with 1/0, or the use of git's error()
instead of error(3). There are also two "#if 0" to make it build with
git-compat-util.h.
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
---
Makefile | 1 +
ls_colors.c (new) | 477 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
ls_colors.h (new) | 20 +++
3 files changed, 498 insertions(+)
create mode 100644 ls_colors.c
create mode 100644 ls_colors.h
@@ -0,0 +1,477 @@+#include"git-compat-util.h"+#include"gettext.h"+#include"ls_colors.h"++#define STREQ(a, b) (strcmp(a, b) == 0)++enumindicator_no{+C_LEFT,C_RIGHT,C_END,C_NORM,C_FILE,C_DIR,C_LINK,C_FIFO,C_SOCK,+C_BLK,C_CHR,C_MISSING,C_ORPHAN,C_EXEC,C_DOOR,C_SETUID,C_SETGID,+C_STICKY,C_OTHER_WRITABLE,C_STICKY_OTHER_WRITABLE+};++#define FILETYPE_INDICATORS \+{\+C_ORPHAN,C_FIFO,C_CHR,C_DIR,C_BLK,C_FILE,\+C_LINK,C_SOCK,C_FILE,C_DIR\+}++structbin_str{+size_tlen;/* Number of bytes */+constchar*string;/* Pointer to the same */+};++structcolor_ext_type{+structbin_strext;/* The extension we're looking for */+structbin_strseq;/* The sequence to output when we do */+structcolor_ext_type*next;/* Next in list */+};++staticconstchar*constindicator_name[]={+"lc","rc","ec","no","fi","di","ln","pi","so",+"bd","cd","mi","or","ex","do","su","sg","st",+"ow","tw",NULL+};++#define LEN_STR_PAIR(s) sizeof(s) - 1, s+staticstructbin_strcolor_indicator[]={+{LEN_STR_PAIR("\033[")},/* lc: Left of color sequence */+{LEN_STR_PAIR("m")},/* rc: Right of color sequence */+{0,NULL},/* ec: End color (replaces lc+no+rc) */+{LEN_STR_PAIR("0")},/* no: Normal */+{LEN_STR_PAIR("0")},/* fi: File: default */+{LEN_STR_PAIR("01;34")},/* di: Directory: bright blue */+{LEN_STR_PAIR("01;36")},/* ln: Symlink: bright cyan */+{LEN_STR_PAIR("33")},/* pi: Pipe: yellow/brown */+{LEN_STR_PAIR("01;35")},/* so: Socket: bright magenta */+{LEN_STR_PAIR("01;33")},/* bd: Block device: bright yellow */+{LEN_STR_PAIR("01;33")},/* cd: Char device: bright yellow */+{0,NULL},/* mi: Missing file: undefined */+{0,NULL},/* or: Orphaned symlink: undefined */+{LEN_STR_PAIR("01;32")},/* ex: Executable: bright green */+{LEN_STR_PAIR("01;35")},/* do: Door: bright magenta */+{LEN_STR_PAIR("37;41")},/* su: setuid: white on red */+{LEN_STR_PAIR("30;43")},/* sg: setgid: black on yellow */+{LEN_STR_PAIR("37;44")},/* st: sticky: black on blue */+{LEN_STR_PAIR("34;42")},/* ow: other-writable: blue on green */+{LEN_STR_PAIR("30;42")},/* tw: ow w/ sticky: black on green */+};++staticstructcolor_ext_type*color_ext_list=NULL;+/* Buffer for color sequences */+staticchar*color_buf;++/*+*Truemeansusecolorstomarktypes.Alsodefinethedifferent+*colorsaswellasthestufffortheLS_COLORSenvironmentvariable.+*TheLS_COLORSvariableisnowinatermcap-likeformat.+*/+staticintprint_with_color;++/*+*Whentrue,inacolorlisting,coloreachsymlinknameaccordingtothe+*typeoffileitpointsto.Otherwise,colorthemaccordingtothe`ln'+*directiveinLS_COLORS.Dangling(orphan)symlinksaretreatedspecially,+*regardless.Thisissetwhen`ln=target'appearsinLS_COLORS.+*/+staticintcolor_symlink_as_referent;++/*+*ParseastringaspartoftheLS_COLORSvariable;thismayinvolve+*decodingallkindsofescapecharacters.Ifequals_endissetan+*unescapedequalsignendsthestring,otherwiseonlya:or\0+*does.Set*OUTPUT_COUNTtothenumberofbytesoutput.Return+*trueifsuccessful.+*+*Theresultingstringis*not*null-terminated,butmaycontain+*embeddednulls.+*+*Notethatbothdestandsrcarechar**;onreturntheypointto+*thefirstfreebyteafterthearrayandthecharacterthatended+*theinputstring,respectively.+*/+staticintget_funky_string(char**dest,constchar**src,intequals_end,+size_t*output_count)+{+charnum;/* For numerical codes */+size_tcount;/* Something to count with */+enum{+ST_GND,ST_BACKSLASH,ST_OCTAL,ST_HEX,+ST_CARET,ST_END,ST_ERROR+}state;+constchar*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){+caseST_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;++caseST_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;++caseST_OCTAL:/* Octal sequence */+if(*p<'0'||*p>'7'){+*(q++)=num;+++count;+state=ST_GND;+}else+num=(num<<3)+(*(p++)-'0');+break;++caseST_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;++caseST_CARET:/* Caret escape */+state=ST_GND;/* Should be the next state... */+if(*p>='@'&&*p<='~'){+*(q++)=*(p++)&037;+++count;+}elseif(*p=='?'){+*(q++)=127;+++count;+}else+state=ST_ERROR;+break;++default:+abort();+}+}++*dest=q;+*src=p;+*output_count=count;++returnstate!=ST_ERROR;+}++voidparse_ls_color(void)+{+constchar*p;/* Pointer to character being parsed */+char*buf;/* color_buf buffer pointer */+intstate;/* State of parser */+intind_no;/* Indicator number */+charlabel[3];/* Indicator label */+structcolor_ext_type*ext;/* Extension we are working on */++if((p=getenv("LS_COLORS"))==NULL||*p=='\0')+return;++ext=NULL;+strcpy(label,"??");++/*+*Thisisanoverlyconservativeestimate,butanypossible+*LS_COLORSstringwill*not*generateacolor_buflonger+*thanitself,soitisasafewayofallocatingabufferin+*advance.+*/+buf=color_buf=xstrdup(p);++state=1;+while(state>0){+switch(state){+case1:/* First label character */+switch(*p){+case':':+++p;+break;++case'*':+/*+*Allocatenewextensionblockandaddtoheadof+*linkedlist(thiswayalaterdefinitionwill+*overrideanearlierone,whichcanbeusefulfor+*havingterminal-specificdefsoverrideglobal).+*/++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;++case2:/* Second label character */+if(*p){+label[1]=*(p++);+state=3;+}else+state=-1;/* Error */+break;++case3:/* Equal sign after indicator label */+state=-1;/* Assume failure... */+if(*(p++)=='='){/* It *should* be... */+for(ind_no=0;indicator_name[ind_no]!=NULL;++ind_no){+if(STREQ(label,indicator_name[ind_no])){+color_indicator[ind_no].string=buf;+state=(get_funky_string(&buf,&p,0,+&color_indicator[ind_no].len)+?1:-1);+break;+}+}+if(state==-1)+error(_("unrecognized prefix: %s"),label);+}+break;++case4:/* 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(state<0){+structcolor_ext_type*e;+structcolor_ext_type*e2;++error(_("unparsable value for LS_COLORS environment variable"));+free(color_buf);+for(e=color_ext_list;e!=NULL;/* empty */){+e2=e;+e=e->next;+free(e2);+}+print_with_color=0;+}++if(color_indicator[C_LINK].len==6&&+!strncmp(color_indicator[C_LINK].string,"target",6))+color_symlink_as_referent=1;+}++/* Output a color indicator (which may contain nulls). */+staticvoidput_indicator(conststructbin_str*ind)+{+size_ti;+constchar*p;++p=ind->string;++for(i=ind->len;i!=0;--i)+putchar(*(p++));+}++voidprint_color_indicator(constchar*name,mode_tmode,intlinkok,+intstat_ok,enumfiletypefiletype)+{+inttype;+structcolor_ext_type*ext;/* Color extension */+size_tlen;/* Length of name */++/* Is this a nonexistent file? If so, linkok == -1. */++if(linkok==-1&&color_indicator[C_MISSING].string!=NULL)+type=C_MISSING;+elseif(!stat_ok){+staticenumindicator_nofiletype_indicator[]=FILETYPE_INDICATORS;+type=filetype_indicator[filetype];+}else{+if(S_ISREG(mode)){+type=C_FILE;+if((mode&S_ISUID)!=0)+type=C_SETUID;+elseif((mode&S_ISGID)!=0)+type=C_SETGID;+#if 0+elseif((mode&S_IXUGO)!=0)+type=C_EXEC;+#endif+}elseif(S_ISDIR(mode)){+if((mode&S_ISVTX)&&(mode&S_IWOTH))+type=C_STICKY_OTHER_WRITABLE;+elseif((mode&S_IWOTH)!=0)+type=C_OTHER_WRITABLE;+elseif((mode&S_ISVTX)!=0)+type=C_STICKY;+else+type=C_DIR;+}elseif(S_ISLNK(mode))+type=((!linkok&&color_indicator[C_ORPHAN].string)+?C_ORPHAN:C_LINK);+elseif(S_ISFIFO(mode))+type=C_FIFO;+elseif(S_ISSOCK(mode))+type=C_SOCK;+elseif(S_ISBLK(mode))+type=C_BLK;+elseif(S_ISCHR(mode))+type=C_CHR;+#if 0+elseif(S_ISDOOR(mode))+type=C_DOOR;+#endif+else{+/* Classify a file of some other type as C_ORPHAN. */+type=C_ORPHAN;+}+}++/* Check the file's suffix only if still classified as C_FILE. */+ext=NULL;+if(type==C_FILE){+/* Test if NAME has a recognized suffix. */++len=strlen(name);+name+=len;/* Pointer to final \0. */+for(ext=color_ext_list;ext!=NULL;ext=ext->next){+if(ext->ext.len<=len+&&strncmp(name-ext->ext.len,ext->ext.string,+ext->ext.len)==0)+break;+}+}++put_indicator(&color_indicator[C_LEFT]);+put_indicator(ext?&(ext->seq):&color_indicator[type]);+put_indicator(&color_indicator[C_RIGHT]);+}
git-compat-util.h does not seem to carry S_IXUGO. Anyway as far as Git
is concerned, we only care one executable bit. Hard code it.
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
---
ls_colors.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
@@ -501,6 +531,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()
After coreutils moved to GPL-3 a couple more color descriptors were
added. parse_ls_color() will abort if it finds any of these so just
add them recognized (but never actually use them).
Reference commits (in coreutils.git)
0df338f (ls --color: do not colorize files with multiple hard links by default - 2009-06-10)
adc62b5 (ls: clean up after wrapped+colored file names with clear-to-EOL - 2008-12-31)
1e48b1f (ls: --color now highlights hard linked files, too - 2008-10-27)
84f6abf (ls: --color now highlights files with capabilities, too - 2008-08-01)
483297d (ls --color no longer outputs unnecessary escape sequences - 2008-02-12)
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
---
ls_colors.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
@@ -38,6 +41,7 @@ static struct bin_str color_indicator[] = {{LEN_STR_PAIR("\033[")},/* lc: Left of color sequence */{LEN_STR_PAIR("m")},/* rc: Right of color sequence */{0,NULL},/* ec: End color (replaces lc+no+rc) */+{0,NULL},/* rs: Reset to ordinary colors */{LEN_STR_PAIR("0")},/* no: Normal */{LEN_STR_PAIR("0")},/* fi: File: default */{LEN_STR_PAIR("01;34")},/* di: Directory: bright blue */
@@ -55,6 +59,9 @@ static struct bin_str color_indicator[] = {{LEN_STR_PAIR("37;44")},/* st: sticky: black on blue */{LEN_STR_PAIR("34;42")},/* ow: other-writable: blue on green */{LEN_STR_PAIR("30;42")},/* tw: ow w/ sticky: black on green */+{0,NULL},/* ca: black on red */+{0,NULL},/* mh: disabled by default */+{0,NULL},/* cl: clear to end of line */};staticstructcolor_ext_type*color_ext_list=NULL;
Default pathspec behavior is recursive which includes too many files
for effective column output. But if you can do
git ls-files --column ':(glob)*'
to limit to one level only. It's not exactly the same as GNU ls
(e.g. directories are never shown) but much closer.
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
---
builtin/ls-files.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
@@ -476,6 +477,7 @@ static int option_parse_exclude_standard(const struct option *opt,intcmd_ls_files(intargc,constchar**argv,constchar*cmd_prefix){intrequire_work_tree=0,show_tag=0,i;+unsignedintcolopts=0;constchar*max_prefix;structdir_structdir;structexclude_list*el;
@@ -532,6 +534,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()
@@ -576,6 +579,10 @@ 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(!line_terminator&&explicitly_enable_column(colopts))+die(_("--column and -z are incompatible"));+if(require_work_tree&&!is_inside_work_tree())setup_work_tree();
@@ -614,10 +621,19 @@ 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(column_active(colopts)){+structcolumn_optionscopts;+memset(&copts,0,sizeof(copts));+run_column_filter(colopts,&copts);+}show_files(&dir);if(show_resolve_undo)show_ru_info();+if(column_active(colopts))+stop_column_filter();+if(ps_matched){intbad;bad=report_path_error(ps_matched,&pathspec,prefix);
The use case in mind is --max-depth=0 to stop recursion. With this we can do
git config --global alias.ls 'ls-files --column --color --max-depth=0'
and have "git ls" with an output very similar to GNU ls. Another
interesting one is
git config --global alias.lso 'ls-files --column --color --max-depth=0 -o --exclude-standard'
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
---
builtin/ls-files.c | 7 +++++++
1 file changed, 7 insertions(+)
@@ -535,6 +536,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()
@@ -591,8 +595,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);
For now it's simply a wrapper of ls-files with some default
goodies. But I want it to be the UI for ls-tree and perhaps git diff
--name-only [--cached] too.
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
---
builtin.h | 1 +
builtin/ls-files.c | 19 +++++++++++++++++++
git.c | 1 +
3 files changed, 21 insertions(+)
This could could help highlight files in ls-files or status output, or
even diff --name-only (but that's questionable).
This code is from coreutils.git commit
7326d1f1a67edf21947ae98194f98c38b6e9e527 file src/ls.c. This is the
last GPL-2 commit before coreutils turns to GPL-3.
I don't know if this is something to consider but for my mac, I have another
variable CLICOLOR which shows the colors if it is set. This is also true with
FreeBSD[1] as well. I don't know if that should be checked if you're on those
systems.
I think it would be nice to have --color flag as well if you want to enable
color output for just that one output.
[1]: https://unix.stackexchange.com/questions/2897/clicolor-and-ls-colors-in-
bash
This could could help highlight files in ls-files or status output, or
even diff --name-only (but that's questionable).
This code is from coreutils.git commit
7326d1f1a67edf21947ae98194f98c38b6e9e527 file src/ls.c. This is the
last GPL-2 commit before coreutils turns to GPL-3.
I don't know if this is something to consider but for my mac, I have another
variable CLICOLOR which shows the colors if it is set. This is also true with
FreeBSD[1] as well. I don't know if that should be checked if you're on those
systems.
I think it would be nice to have --color flag as well if you want to enable
color output for just that one output.
My plan is stick to how git handles colors (e.g. --color and color.*
config variables). Is that enough or do you think git CLICOLOR should
override --color and color.*?
This could could help highlight files in ls-files or status output, or
even diff --name-only (but that's questionable).
This code is from coreutils.git commit
7326d1f1a67edf21947ae98194f98c38b6e9e527 file src/ls.c. This is the
last GPL-2 commit before coreutils turns to GPL-3.
I don't know if this is something to consider but for my mac, I have another
variable CLICOLOR which shows the colors if it is set. This is also true
with
quoted
FreeBSD[1] as well. I don't know if that should be checked if you're on
those
quoted
systems.
I think it would be nice to have --color flag as well if you want to enable
color output for just that one output.
My plan is stick to how git handles colors (e.g. --color and color.*
config variables). Is that enough or do you think git CLICOLOR should
override --color and color.*?
I would say it is not an essential feature to have but something that might
be looked into once the color is implemented. If its not set, ignore it. If
it is set, check if it is truthy, is what I would do.
The use case in mind is --max-depth=0 to stop recursion. With this we can do
git config --global alias.ls 'ls-files --column --color --max-depth=0'
and have "git ls" with an output very similar to GNU ls.
One big difference though: your "git ls" does not show directories. I understand that this is easier to implement, but from the user point of view it resulted in a "wtf" from me running "git ls" in a repository containing essentially directories, and seeing just a README file in the output.
Ideally (for me), directories should be shown with a trailing / like "ls -F" does.
--
Matthieu Moy
http://www-verimag.imag.fr/~moy/
On Tue, Mar 25, 2014 at 3:55 PM, Matthieu Moy
[off-list ref] wrote:
----- Original Message -----
quoted
The use case in mind is --max-depth=0 to stop recursion. With this we can do
git config --global alias.ls 'ls-files --column --color --max-depth=0'
and have "git ls" with an output very similar to GNU ls.
One big difference though: your "git ls" does not show directories. I understand that this is easier to implement, but from the user point of view it resulted in a "wtf" from me running "git ls" in a repository containing essentially directories, and seeing just a README file in the output.
I was hoping you didn't notice :) It'll be more difficult but not impossible.
Ideally (for me), directories should be shown with a trailing / like "ls -F" does.
I'd rather go with no trailing slash by default and add -F (which
seems to be more than just '/')
--
Duy
Compared to v1, git-ls now does not accept ls-files options (previous
git-ls is more like an alias of ls-files). I want this because ls may
take a different set of options than ls-files. Most functionality is
shared so if you're not happy with ls, you can fall back to ls-files.
New alias options are supported, -1 == --no-column, -R ==
--max-depth=-1. If more than one file criteria is chosen (e.g. "ls -cmo")
then --tag is implied. File order is fixed ("ls-files -cmo" actually
shows two or three separate listings, "ls -cmo" shows one sorted
listing). It also shows directories from the index.
Documentation is there. No tests yet because the behavior may still
need some polishing.
Nguyễn Thái Ngọc Duy (17):
ls_colors.c: add $LS_COLORS parsing code
ls_colors.c: parse color.ls.* from config file
ls_colors.c: add 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
ls-files: split main ls-files logic into ls_files() function
Add git-ls, a user friendly version of ls-files and more
ls: -u does not imply showing stages
ls: add -R/--recursive short for --max-depth=-1
ls: add -1 short for --no-column in the spirit of GNU ls
ls: add -t back
ls: sort output and remove duplicates
ls: do not show duplicate cached entries
ls: show directories as well as files
.gitignore | 1 +
Documentation/config.txt | 22 ++
Documentation/git-ls-files.txt | 22 ++
Documentation/git-ls.txt (new) | 95 ++++++++
Makefile | 2 +
builtin.h | 1 +
builtin/ls-files.c | 446 +++++++++++++++++++++++++++++-------
color.h | 10 +
command-list.txt | 1 +
git.c | 1 +
ls_colors.c (new) | 496 +++++++++++++++++++++++++++++++++++++++++
11 files changed, 1012 insertions(+), 85 deletions(-)
create mode 100644 Documentation/git-ls.txt
create mode 100644 ls_colors.c
--
1.9.1.345.ga1a145c
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 <redacted>
---
Makefile | 1 +
color.h | 8 ++
ls_colors.c (new) | 398 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 407 insertions(+)
create mode 100644 ls_colors.c
@@ -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"
@@ -0,0 +1,398 @@+#include"cache.h"+#include"color.h"++enumcolor_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+};++staticcharls_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,+"",+"",+""+};++staticconstchar*constindicator_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+};++structbin_str{+size_tlen;/* Number of bytes */+constchar*string;/* Pointer to the same */+};++structcolor_ext_type{+structbin_strext;/* The extension we're looking for */+structbin_strseq;/* The sequence to output when we do */+structcolor_ext_type*next;/* Next in list */+};++staticstructcolor_ext_type*color_ext_list=NULL;++/*+*Whentrue,inacolorlisting,coloreachsymlinknameaccordingtothe+*typeoffileitpointsto.Otherwise,colorthemaccordingtothe`ln'+*directiveinLS_COLORS.Dangling(orphan)symlinksaretreatedspecially,+*regardless.Thisissetwhen`ln=target'appearsinLS_COLORS.+*/+staticintcolor_symlink_as_referent;++/*+*ParseastringaspartoftheLS_COLORSvariable;thismayinvolve+*decodingallkindsofescapecharacters.Ifequals_endissetan+*unescapedequalsignendsthestring,otherwiseonlya:or\0+*does.Set*OUTPUT_COUNTtothenumberofbytesoutput.Return+*trueifsuccessful.+*+*Theresultingstringis*not*null-terminated,butmaycontain+*embeddednulls.+*+*Notethatbothdestandsrcarechar**;onreturntheypointto+*thefirstfreebyteafterthearrayandthecharacterthatended+*theinputstring,respectively.+*/+staticintget_funky_string(char**dest,constchar**src,intequals_end,+size_t*output_count)+{+charnum;/* For numerical codes */+size_tcount;/* Something to count with */+enum{+ST_GND,ST_BACKSLASH,ST_OCTAL,ST_HEX,+ST_CARET,ST_END,ST_ERROR+}state;+constchar*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){+caseST_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;++caseST_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;++caseST_OCTAL:/* Octal sequence */+if(*p<'0'||*p>'7'){+*(q++)=num;+++count;+state=ST_GND;+}else+num=(num<<3)+(*(p++)-'0');+break;++caseST_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;++caseST_CARET:/* Caret escape */+state=ST_GND;/* Should be the next state... */+if(*p>='@'&&*p<='~'){+*(q++)=*(p++)&037;+++count;+}elseif(*p=='?'){+*(q++)=127;+++count;+}else+state=ST_ERROR;+break;++default:+abort();+}+}++*dest=q;+*src=p;+*output_count=count;++returnstate!=ST_ERROR;+}++voidparse_ls_color(void)+{+constchar*p;/* Pointer to character being parsed */+char*buf;/* color_buf buffer pointer */+intstate;/* State of parser */+intind_no;/* Indicator number */+charlabel[3];/* Indicator label */+structcolor_ext_type*ext;/* Extension we are working on */+staticchar*color_buf;+char*start;+size_tlen;++if((p=getenv("LS_COLORS"))==NULL||*p=='\0')+return;++ext=NULL;+strcpy(label,"??");++/*+*Thisisanoverlyconservativeestimate,butanypossible+*LS_COLORSstringwill*not*generateacolor_buflonger+*thanitself,soitisasafewayofallocatingabufferin+*advance.+*/+buf=color_buf=xstrdup(p);++state=1;+while(state>0){+switch(state){+case1:/* First label character */+switch(*p){+case':':+++p;+break;++case'*':+/*+*Allocatenewextensionblockandaddtoheadof+*linkedlist(thiswayalaterdefinitionwill+*overrideanearlierone,whichcanbeusefulfor+*havingterminal-specificdefsoverrideglobal).+*/++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;++case2:/* Second label character */+if(*p){+label[1]=*(p++);+state=3;+}else+state=-1;/* Error */+break;++case3:/* 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);+elseif(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;++case4:/* 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;+}
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 <redacted>
---
Documentation/config.txt | 11 +++++++++++
ls_colors.c | 26 ++++++++++++++++++++++++++
2 files changed, 37 insertions(+)
@@ -909,6 +909,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
@@ -68,6 +68,14 @@ static const char *const indicator_name[] = {NULL};+staticconstchar*constconfig_name[]={+"","","","","normal","file","directory","symlink",+"fifo","socket","block","char","missing","orphan","executable",+"door","setuid","setgid","sticky","otherwritable",+"stickyotherwritable","cap","multihardlink","",+NULL+};+structbin_str{size_tlen;/* Number of bytes */constchar*string;/* Pointer to the same */
@@ -285,6 +293,23 @@ static int get_funky_string(char **dest, const char **src, int equals_end,returnstate!=ST_ERROR;}+staticintls_colors_config(constchar*var,constchar*value,void*cb)+{+intslot;+if(!starts_with(var,"color.ls."))+return0;+var+=9;+for(slot=0;config_name[slot];slot++)+if(!strcasecmp(var,config_name[slot]))+break;+if(!config_name[slot])+return0;+if(!value)+returnconfig_error_nonbool(var);+color_parse(value,var,ls_colors[slot]);+return0;+}+voidparse_ls_color(void){constchar*p;/* Pointer to character being parsed */
Tthe new function is based on print_color_indicator() from commit
7326d1f1a67edf21947ae98194f98c38b6e9e527 in coreutils.git.
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
---
color.h | 2 ++
ls_colors.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 68 insertions(+)
@@ -422,3 +422,69 @@ void parse_ls_color(void)color_symlink_as_referent=1;git_config(ls_colors_config,NULL);}++voidcolor_filename(structstrbuf*sb,constchar*name,+constchar*display_name,mode_tmode,intlinkok)+{+inttype;+structcolor_ext_type*ext;/* Color extension */++if(S_ISREG(mode)){+type=LS_FL;+if((mode&S_ISUID)!=0)+type=LS_SU;+elseif((mode&S_ISGID)!=0)+type=LS_SG;+elseif((mode&(S_IXUSR|S_IXGRP|S_IXOTH))!=0)+type=LS_EX;+}elseif(S_ISDIR(mode)){+if((mode&S_ISVTX)&&(mode&S_IWOTH))+type=LS_TW;+elseif((mode&S_IWOTH)!=0)+type=LS_OW;+elseif((mode&S_ISVTX)!=0)+type=LS_ST;+else+type=LS_DI;+}elseif(S_ISLNK(mode))+type=(!linkok&&*ls_colors[LS_OR])?LS_OR:LS_LN;+elseif(S_ISFIFO(mode))+type=LS_PI;+elseif(S_ISSOCK(mode))+type=LS_SO;+elseif(S_ISBLK(mode))+type=LS_BD;+elseif(S_ISCHR(mode))+type=LS_CD;+#ifdef S_ISDOOR+elseif(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_tlen=strlen(name);+constchar*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);+elseif(*ls_colors[type])+strbuf_addf(sb,"%s%s%s",ls_colors[type],name,GIT_COLOR_RESET);+else+strbuf_addstr(sb,name);+}
@@ -913,7 +913,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
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 <redacted>
---
builtin/ls-files.c | 48 +++++++++++++++++++++++++++++++++++-------------
1 file changed, 35 insertions(+), 13 deletions(-)
@@ -147,6 +147,15 @@ a space) at the start of each line: possible for manual inspection; the exact format may change at any time.+--color[=<when>]::+ Color file names. The value must be always (default), never,+ or auto.++--no-color::+ Turn off coloring, even when the configuration file gives the+ default to color output, same as `--color=never`. This is the+ default.+ \--:: Do not interpret any more arguments as options.
@@ -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()
@@ -156,6 +156,12 @@ a space) at the start of each line: default to color output, same as `--color=never`. This is the default.+--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.
@@ -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();
@@ -162,6 +162,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.+ 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.
@@ -503,6 +503,7 @@ static int option_parse_exclude_standard(const struct option *opt,intcmd_ls_files(intargc,constchar**argv,constchar*cmd_prefix){intrequire_work_tree=0,show_tag=0,i;+intmax_depth=-1;constchar*max_prefix;structdir_structdir;structexclude_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);
This is a preparation step for the introduction of git-ls. "git ls"
has a different set of command line options, but it will eventually
call ls_files().
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
---
builtin/ls-files.c | 164 +++++++++++++++++++++++++++--------------------------
1 file changed, 85 insertions(+), 79 deletions(-)
@@ -500,89 +504,12 @@ static int option_parse_exclude_standard(const struct option *opt,return0;}-intcmd_ls_files(intargc,constchar**argv,constchar*cmd_prefix)+staticintls_files(constchar**argv,constchar*prefix){-intrequire_work_tree=0,show_tag=0,i;-intmax_depth=-1;+intrequire_work_tree=0,i;constchar*max_prefix;-structdir_structdir;structexclude_list*el;-structstring_listexclude_list=STRING_LIST_INIT_NODUP;-structoptionbuiltin_ls_files_options[]={-{OPTION_CALLBACK,'z',NULL,NULL,NULL,-N_("paths are separated with NUL character"),-PARSE_OPT_NOARG,option_parse_z},-OPT_BOOL('t',NULL,&show_tag,-N_("identify the file status with tags")),-OPT_BOOL('v',NULL,&show_valid_bit,-N_("use lowercase letters for 'assume unchanged' files")),-OPT_BOOL('c',"cached",&show_cached,-N_("show cached files in the output (default)")),-OPT_BOOL('d',"deleted",&show_deleted,-N_("show deleted files in the output")),-OPT_BOOL('m',"modified",&show_modified,-N_("show modified files in the output")),-OPT_BOOL('o',"others",&show_others,-N_("show other files in the output")),-OPT_BIT('i',"ignored",&dir.flags,-N_("show ignored files in the output"),-DIR_SHOW_IGNORED),-OPT_BOOL('s',"stage",&show_stage,-N_("show staged contents' object name in the output")),-OPT_BOOL('k',"killed",&show_killed,-N_("show files on the filesystem that need to be removed")),-OPT_BIT(0,"directory",&dir.flags,-N_("show 'other' directories' name only"),-DIR_SHOW_OTHER_DIRECTORIES),-OPT_NEGBIT(0,"empty-directory",&dir.flags,-N_("don't show empty directories"),-DIR_HIDE_EMPTY_DIRECTORIES),-OPT_BOOL('u',"unmerged",&show_unmerged,-N_("show unmerged files in the output")),-OPT_BOOL(0,"resolve-undo",&show_resolve_undo,-N_("show resolve-undo information")),-{OPTION_CALLBACK,'x',"exclude",&exclude_list,N_("pattern"),-N_("skip files matching pattern"),-0,option_parse_exclude},-{OPTION_CALLBACK,'X',"exclude-from",&dir,N_("file"),-N_("exclude patterns are read from <file>"),-0,option_parse_exclude_from},-OPT_STRING(0,"exclude-per-directory",&dir.exclude_per_dir,N_("file"),-N_("read additional per-directory exclude patterns in <file>")),-{OPTION_CALLBACK,0,"exclude-standard",&dir,NULL,-N_("add the standard git exclusions"),-PARSE_OPT_NOARG,option_parse_exclude_standard},-{OPTION_SET_INT,0,"full-name",&prefix_len,NULL,-N_("make the output relative to the project top directory"),-PARSE_OPT_NOARG|PARSE_OPT_NONEG,NULL},-OPT_BOOL(0,"error-unmatch",&error_unmatch,-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_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()-};--if(argc==2&&!strcmp(argv[1],"-h"))-usage_with_options(ls_files_usage,builtin_ls_files_options);-memset(&dir,0,sizeof(dir));-prefix=cmd_prefix;-if(prefix)-prefix_len=strlen(prefix);-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);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);
@@ -681,3 +608,82 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)return0;}++intcmd_ls_files(intargc,constchar**argv,constchar*cmd_prefix)+{+structoptionbuiltin_ls_files_options[]={+{OPTION_CALLBACK,'z',NULL,NULL,NULL,+N_("paths are separated with NUL character"),+PARSE_OPT_NOARG,option_parse_z},+OPT_BOOL('t',NULL,&show_tag,+N_("identify the file status with tags")),+OPT_BOOL('v',NULL,&show_valid_bit,+N_("use lowercase letters for 'assume unchanged' files")),+OPT_BOOL('c',"cached",&show_cached,+N_("show cached files in the output (default)")),+OPT_BOOL('d',"deleted",&show_deleted,+N_("show deleted files in the output")),+OPT_BOOL('m',"modified",&show_modified,+N_("show modified files in the output")),+OPT_BOOL('o',"others",&show_others,+N_("show other files in the output")),+OPT_BIT('i',"ignored",&dir.flags,+N_("show ignored files in the output"),+DIR_SHOW_IGNORED),+OPT_BOOL('s',"stage",&show_stage,+N_("show staged contents' object name in the output")),+OPT_BOOL('k',"killed",&show_killed,+N_("show files on the filesystem that need to be removed")),+OPT_BIT(0,"directory",&dir.flags,+N_("show 'other' directories' name only"),+DIR_SHOW_OTHER_DIRECTORIES),+OPT_NEGBIT(0,"empty-directory",&dir.flags,+N_("don't show empty directories"),+DIR_HIDE_EMPTY_DIRECTORIES),+OPT_BOOL('u',"unmerged",&show_unmerged,+N_("show unmerged files in the output")),+OPT_BOOL(0,"resolve-undo",&show_resolve_undo,+N_("show resolve-undo information")),+{OPTION_CALLBACK,'x',"exclude",&exclude_list,N_("pattern"),+N_("skip files matching pattern"),+0,option_parse_exclude},+{OPTION_CALLBACK,'X',"exclude-from",&dir,N_("file"),+N_("exclude patterns are read from <file>"),+0,option_parse_exclude_from},+OPT_STRING(0,"exclude-per-directory",&dir.exclude_per_dir,N_("file"),+N_("read additional per-directory exclude patterns in <file>")),+{OPTION_CALLBACK,0,"exclude-standard",&dir,NULL,+N_("add the standard git exclusions"),+PARSE_OPT_NOARG,option_parse_exclude_standard},+{OPTION_SET_INT,0,"full-name",&prefix_len,NULL,+N_("make the output relative to the project top directory"),+PARSE_OPT_NOARG|PARSE_OPT_NONEG,NULL},+OPT_BOOL(0,"error-unmatch",&error_unmatch,+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_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()+};++if(argc==2&&!strcmp(argv[1],"-h"))+usage_with_options(ls_files_usage,builtin_ls_files_options);++prefix=cmd_prefix;+if(prefix)+prefix_len=strlen(prefix);+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);+returnls_files(argv,prefix);+}
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
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
---
.gitignore | 1 +
Documentation/config.txt | 10 ++++++
Documentation/git-ls.txt (new) | 82 ++++++++++++++++++++++++++++++++++++++++++
Makefile | 1 +
builtin.h | 1 +
builtin/ls-files.c | 70 ++++++++++++++++++++++++++++++++++++
command-list.txt | 1 +
git.c | 1 +
8 files changed, 167 insertions(+)
create mode 100644 Documentation/git-ls.txt
@@ -909,6 +909,12 @@ color.status.<slot>:: to red). The values of these variables may be specified as in color.branch.<slot>.+color.ls::+ A boolean to enable/disable color in the output of+ linkgit:git-ls[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
@@ -981,6 +987,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.ls::+ Specify whether to output tag listing in `git ls` 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.
@@ -0,0 +1,82 @@+git-ls(1)+===============++NAME+----+git-ls - List files++SYNOPSIS+--------+[verse]+'git ls' (--[cached|deleted|others|ignored|unmerged|modified])*+ (-[c|d|o|i|s|u|m])*+ [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 in the output (default)++-d::+--deleted::+ Show deleted files in the output++-m::+--modified::+ Show modified files in the output++-o::+--others::+ Show other (i.e. untracked) files in the output++-i::+--ignored::+ Show only ignored files in the output. 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 in the output (forces --stage)++--color[=<when>]::+ Color file names. The value must be always (default), never,+ or auto.++--no-color::+ Turn off coloring, even when the configuration file gives the+ default to color output, same as `--color=never`. This is the+ default.++--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.++<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
@@ -33,6 +33,7 @@ static int use_color;staticunsignedintcolopts;staticintmax_depth=-1;staticintshow_tag;+staticintporcelain;staticconstchar*prefix;staticintmax_prefix_len;
@@ -588,6 +589,10 @@ static int ls_files(const char **argv, const char *prefix)die("ls-files --with-tree is incompatible with -s or -u");overlay_tree_on_cache(with_tree,max_prefix);}+if(porcelain){+refresh_index(&the_index,REFRESH_QUIET,&pathspec,NULL,NULL);+setup_pager();+}show_files(&dir);if(show_resolve_undo)show_ru_info();
@@ -687,3 +692,68 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)ls_files_usage,0);returnls_files(argv,prefix);}++staticconstchar*constls_usage[]={+N_("git ls [options] [<file>...]"),+NULL+};++staticintgit_ls_config(constchar*var,constchar*value,void*cb)+{+if(starts_with(var,"column."))+returngit_column_config(var,value,"ls",&colopts);+if(!strcmp(var,"color.ls")){+use_color=git_config_colorbool(var,value);+return0;+}+returngit_color_default_config(var,value,cb);+}++intcmd_ls(intargc,constchar**argv,constchar*cmd_prefix)+{+structoptionbuiltin_ls_options[]={+OPT_BOOL('c',"cached",&show_cached,+N_("show cached files in the output (default)")),+OPT_BOOL('d',"deleted",&show_deleted,+N_("show deleted files in the output")),+OPT_BOOL('m',"modified",&show_modified,+N_("show modified files in the output")),+OPT_BOOL('o',"others",&show_others,+N_("show other files in the output")),+OPT_BIT('i',"ignored",&dir.flags,+N_("show ignored files in the output"),+DIR_SHOW_IGNORED),+OPT_BOOL('u',"unmerged",&show_unmerged,+N_("show unmerged files in the output")),+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()+};++if(argc==2&&!strcmp(argv[1],"-h"))+usage_with_options(ls_usage,builtin_ls_options);++prefix=cmd_prefix;+if(prefix)+prefix_len=strlen(prefix);+git_config(git_ls_config,NULL);++if(read_cache()<0)+die("index file corrupt");++/* default setup */+porcelain=1;+setenv(GIT_GLOB_PATHSPECS_ENVIRONMENT,"1",1);+exc_given=1;+setup_standard_excludes(&dir);+use_color=-1;+max_depth=0;++argc=parse_options(argc,argv,prefix,builtin_ls_options,+ls_usage,0);+returnls_files(argv,prefix);+}
Showing full index entry information is something for ls-files
only. The users of "git ls" may just want to know what entries are not
unmerged.
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
---
builtin/ls-files.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
@@ -47,6 +47,10 @@ OPTIONS --unmerged:: Show unmerged files in the output (forces --stage)+-R::+--recursive::+ Equivalent of --max-depth=-1 (infinite recursion).+ --color[=<when>]:: Color file names. The value must be always (default), never, or auto.
@@ -725,6 +725,8 @@ int cmd_ls(int argc, const char **argv, const char *cmd_prefix)DIR_SHOW_IGNORED),OPT_BOOL('u',"unmerged",&show_unmerged,N_("show unmerged files in the output")),+OPT_SET_INT('R',"recursive",&max_depth,+N_("shortcut for --max-depth=-1"),-1),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"),
@@ -51,6 +51,9 @@ OPTIONS --recursive:: Equivalent of --max-depth=-1 (infinite recursion).+-1::+ Equivalent of --no-column.+ --color[=<when>]:: Color file names. The value must be always (default), never, or auto.
@@ -729,6 +729,8 @@ int cmd_ls(int argc, const char **argv, const char *cmd_prefix)N_("shortcut for --max-depth=-1"),-1),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},
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 <redacted>
---
Documentation/git-ls.txt | 6 ++++++
builtin/ls-files.c | 27 +++++++++++++++++----------
2 files changed, 23 insertions(+), 10 deletions(-)
@@ -47,6 +47,12 @@ OPTIONS --unmerged:: Show unmerged files in the output (forces --stage)+-t::+--tag::+ Show a tag to indicate file type, helpful when multiple file+ selections are used. See linkgit::git-ls-files[1] option `-t`+ for more information.+ -R:: --recursive:: Equivalent of --max-depth=-1 (infinite recursion).
@@ -727,6 +731,8 @@ int cmd_ls(int argc, const char **argv, const char *cmd_prefix)N_("show unmerged files in the output")),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__COLOR(&use_color,N_("show color")),OPT_COLUMN(0,"column",&colopts,N_("show files in columns")),OPT_SET_INT('1',NULL,&colopts,
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 <redacted>
---
builtin/ls-files.c | 30 +++++++++++++++++++++---------
1 file changed, 21 insertions(+), 9 deletions(-)
With the current show_files() "ls -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 <redacted>
---
builtin/ls-files.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 51 insertions(+), 1 deletion(-)
@@ -337,6 +337,53 @@ static void show_files(struct dir_struct *dir)}}+staticvoidshow_files_compact(structdir_struct*dir)+{+inti;++/* For cached/deleted files we don't need to even do the readdir */+if(show_others||show_killed){+if(!show_others)+dir->flags|=DIR_COLLECT_KILLED_ONLY;+fill_directory(dir,&pathspec);+if(show_others)+show_other_files(dir);+if(show_killed)+show_killed_files(dir);+}+if(!(show_cached||show_stage||show_deleted||show_modified))+return;+for(i=0;i<active_nr;i++){+conststructcache_entry*ce=active_cache[i];+structstatst;+interr,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&&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);+}+}+/**Prunetheindextoonlycontainstuffstartingwith"prefix"*/
The index does not store directories explicitly (except submodules) so
we have to figure them out from file list. The function
show_directories() deliberately generates duplicate directories and
expects the previous patch to remove duplicates.
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
---
builtin/ls-files.c | 41 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 41 insertions(+)
@@ -147,6 +147,15 @@ a space) at the start of each line: possible for manual inspection; the exact format may change at any time.+--color[=<when>]::+ Color file names. The value must be always (default), never,+ or auto.
Here, the default is "always"...
+--no-color::
+ Turn off coloring, even when the configuration file gives the
+ default to color output, same as `--color=never`. This is the
+ default.
But, here the default is "never".
quoted hunk
+
\--::
Do not interpret any more arguments as options.
@@ -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()
1.9.1.345.ga1a145c
--
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
@@ -422,3 +422,69 @@ void parse_ls_color(void)color_symlink_as_referent=1;git_config(ls_colors_config,NULL);}++voidcolor_filename(structstrbuf*sb,constchar*name,+constchar*display_name,mode_tmode,intlinkok)+{+inttype;+structcolor_ext_type*ext;/* Color extension */++if(S_ISREG(mode)){+type=LS_FL;+if((mode&S_ISUID)!=0)+type=LS_SU;+elseif((mode&S_ISGID)!=0)+type=LS_SG;+elseif((mode&(S_IXUSR|S_IXGRP|S_IXOTH))!=0)+type=LS_EX;+}elseif(S_ISDIR(mode)){+if((mode&S_ISVTX)&&(mode&S_IWOTH))+type=LS_TW;+elseif((mode&S_IWOTH)!=0)+type=LS_OW;+elseif((mode&S_ISVTX)!=0)+type=LS_ST;+else+type=LS_DI;+}elseif(S_ISLNK(mode))+type=(!linkok&&*ls_colors[LS_OR])?LS_OR:LS_LN;+elseif(S_ISFIFO(mode))+type=LS_PI;+elseif(S_ISSOCK(mode))+type=LS_SO;+elseif(S_ISBLK(mode))+type=LS_BD;+elseif(S_ISCHR(mode))+type=LS_CD;+#ifdef S_ISDOOR+elseif(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_tlen=strlen(name);+constchar*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);+elseif(*ls_colors[type])+strbuf_addf(sb,"%s%s%s",ls_colors[type],name,GIT_COLOR_RESET);+else+strbuf_addstr(sb,name);+}--
1.9.1.345.ga1a145c
--
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
From: Eric Sunshine <hidden> Date: 2016-06-15 23:00:33
On Wed, Mar 26, 2014 at 9:48 AM, Nguyễn Thái Ngọc Duy [off-list ref] wrote:
quoted hunk
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 <redacted>
---
builtin/ls-files.c | 48 +++++++++++++++++++++++++++++++++++-------------
1 file changed, 35 insertions(+), 13 deletions(-)
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); } } }--
@@ -156,6 +156,12 @@ a space) at the start of each line: default to color output, same as `--color=never`. This is the default.+--column[=<options>]::+--no-column::+ Display files in columns. See configuration variable column.ui+ for option syntax.`--column` and `--no-column` without options
Missing space after period.
quoted hunk
+ are equivalent to 'always' and 'never' respectively.
+
\--::
Do not interpret any more arguments as options.
@@ -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();
1.9.1.345.ga1a145c
--
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
@@ -162,6 +162,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>::
Other options in this file are documented as:
--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.
Would it be worthwhile to mention the default?
quoted hunk
+
\--::
Do not interpret any more arguments as options.
@@ -503,6 +503,7 @@ static int option_parse_exclude_standard(const struct option *opt,intcmd_ls_files(intargc,constchar**argv,constchar*cmd_prefix){intrequire_work_tree=0,show_tag=0,i;+intmax_depth=-1;constchar*max_prefix;structdir_structdir;structexclude_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);--
From: Eric Sunshine <hidden> Date: 2016-06-15 23:00:33
On Wed, Mar 26, 2014 at 9:48 AM, Nguyễn Thái Ngọc Duy [off-list ref] wrote:
quoted hunk
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
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
---
.gitignore | 1 +
Documentation/config.txt | 10 ++++++
Documentation/git-ls.txt (new) | 82 ++++++++++++++++++++++++++++++++++++++++++
Makefile | 1 +
builtin.h | 1 +
builtin/ls-files.c | 70 ++++++++++++++++++++++++++++++++++++
command-list.txt | 1 +
git.c | 1 +
8 files changed, 167 insertions(+)
create mode 100644 Documentation/git-ls.txt
@@ -909,6 +909,12 @@ color.status.<slot>:: to red). The values of these variables may be specified as in color.branch.<slot>.+color.ls::+ A boolean to enable/disable color in the output of+ linkgit:git-ls[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
@@ -981,6 +987,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.ls::+ Specify whether to output tag listing in `git ls` 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.
@@ -0,0 +1,82 @@+git-ls(1)+===============++NAME+----+git-ls - List files++SYNOPSIS+--------+[verse]+'git ls' (--[cached|deleted|others|ignored|unmerged|modified])*+ (-[c|d|o|i|s|u|m])*
Don't you have [...] and (...) transposed? The way it's written, "-"
and "--" are valid optional arguments. You probably meant:
[--(cached|deleted|x|y|z)]...
[-(c|d|x|y|z)]...
+ [options] [<pathspec>...]
However, you also have the generic [options] here, which covers all of
the above. It probably would make sense to just use [options] and drop
the enumerated list.
+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 in the output (default)
"in the output" is superfluous. Perhaps drop it from each of the descriptions.
+-d::
+--deleted::
+ Show deleted files in the output
Is this showing only deleted file or including them in the list of
files otherwise displayed? It's not clear from the description. Same
question for the other options.
+-m::
+--modified::
+ Show modified files in the output
+
+-o::
+--others::
+ Show other (i.e. untracked) files in the output
+
+-i::
+--ignored::
+ Show only ignored files in the output. 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 in the output (forces --stage)
This is the only mention of --stage in this document. Not sure what
it's trying to say.
+--color[=<when>]::
+ Color file names. The value must be always (default), never,
+ or auto.
Same problem mentioned in the other patch. Default is "always"...
+
+--no-color::
+ Turn off coloring, even when the configuration file gives the
+ default to color output, same as `--color=never`. This is the
+ default.
But default is also "never".
+
+--column[=<options>]::
+--no-column::
+ Display files in columns. See configuration variable column.ui
+ for option syntax.`--column` and `--no-column` without options
Missing space after period.
More below.
quoted hunk
+ 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.
+
+<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
@@ -33,6 +33,7 @@ static int use_color;staticunsignedintcolopts;staticintmax_depth=-1;staticintshow_tag;+staticintporcelain;staticconstchar*prefix;staticintmax_prefix_len;
@@ -588,6 +589,10 @@ static int ls_files(const char **argv, const char *prefix)die("ls-files --with-tree is incompatible with -s or -u");overlay_tree_on_cache(with_tree,max_prefix);}+if(porcelain){+refresh_index(&the_index,REFRESH_QUIET,&pathspec,NULL,NULL);+setup_pager();+}show_files(&dir);if(show_resolve_undo)show_ru_info();
@@ -687,3 +692,68 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)ls_files_usage,0);returnls_files(argv,prefix);}++staticconstchar*constls_usage[]={+N_("git ls [options] [<file>...]"),+NULL+};++staticintgit_ls_config(constchar*var,constchar*value,void*cb)+{+if(starts_with(var,"column."))+returngit_column_config(var,value,"ls",&colopts);+if(!strcmp(var,"color.ls")){+use_color=git_config_colorbool(var,value);+return0;+}+returngit_color_default_config(var,value,cb);+}++intcmd_ls(intargc,constchar**argv,constchar*cmd_prefix)+{+structoptionbuiltin_ls_options[]={+OPT_BOOL('c',"cached",&show_cached,+N_("show cached files in the output (default)")),
Ditto regarding the unnecessary and repetitive "in the output".
@@ -147,6 +147,15 @@ a space) at the start of each line: possible for manual inspection; the exact format may change at any time.+--color[=<when>]::+ Color file names. The value must be always (default), never,+ or auto.
Here, the default is "always"...
These (.txt changes in other patches as well) are mostly copy and
paste from existing .txt files. You may want to grep through and fix
other places as well, in a separate series.
quoted
+--no-color::
+ Turn off coloring, even when the configuration file gives the
+ default to color output, same as `--color=never`. This is the
+ default.
But, here the default is "never".
What I mean is color is turned off by default for ls-files (in
contrast, ls has color on by default). The default 'always' means that
if you write --color without the <when> part, then it's
--color=always. How do I phrase to make it clear?
--
Duy
Not strictly necessary because sb is static and will be reset at the
next call. I just want to lower the number of allocation (write_name
allocates some more). It may be a premature optimization though.
The same for changes in show_ce_entry().
--
Duy
Not strictly necessary because sb is static and will be reset at the
next call. I just want to lower the number of allocation (write_name
allocates some more). It may be a premature optimization though.
Ah, yes. I noted the 'static' on my initial read-through but had
forgotten about it by the time I finally got to a computer with which
I could send plain-text email. Sorry for the noise.
On Tue, Mar 25, 2014 at 6:15 PM, Duy Nguyen [off-list ref] wrote:
On Tue, Mar 25, 2014 at 3:55 PM, Matthieu Moy
[off-list ref] wrote:
quoted
----- Original Message -----
quoted
The use case in mind is --max-depth=0 to stop recursion. With this we can do
git config --global alias.ls 'ls-files --column --color --max-depth=0'
and have "git ls" with an output very similar to GNU ls.
One big difference though: your "git ls" does not show directories. I understand that this is easier to implement, but from the user point of view it resulted in a "wtf" from me running "git ls" in a repository containing essentially directories, and seeing just a README file in the output.
I was hoping you didn't notice :) It'll be more difficult but not impossible.
quoted
Ideally (for me), directories should be shown with a trailing / like "ls -F" does.
I'd rather go with no trailing slash by default and add -F (which
seems to be more than just '/')
And we need a new indicator for submodules when -F is used. I think it
should be different than '/'. I randomly picked '&' for now. Any
suggestions welcome.
--
Duy
@@ -147,6 +147,15 @@ a space) at the start of each line: possible for manual inspection; the exact format may change at any time.+--color[=<when>]::+ Color file names. The value must be always (default), never,+ or auto.
Here, the default is "always"...
These (.txt changes in other patches as well) are mostly copy and
paste from existing .txt files. You may want to grep through and fix
other places as well, in a separate series.
quoted
quoted
+--no-color::
+ Turn off coloring, even when the configuration file gives the
+ default to color output, same as `--color=never`. This is the
+ default.
But, here the default is "never".
What I mean is color is turned off by default for ls-files (in
contrast, ls has color on by default). The default 'always' means that
if you write --color without the <when> part, then it's
--color=always. How do I phrase to make it clear?
Perhaps:
Color file names. The value must be always, never, or auto.
`--color` by itself is the same as `--color=always`.
@@ -51,6 +51,9 @@ OPTIONS --recursive:: Equivalent of --max-depth=-1 (infinite recursion).+-1::+ Equivalent of --no-column.+ --color[=<when>]:: Color file names. The value must be always (default), never, or auto.
@@ -729,6 +729,8 @@ int cmd_ls(int argc, const char **argv, const char *cmd_prefix)N_("shortcut for --max-depth=-1"),-1),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},--
From: Eric Sunshine <hidden> Date: 2016-06-15 23:00:34
On Wed, Mar 26, 2014 at 9:48 AM, Nguyễn Thái Ngọc Duy [off-list ref] wrote:
quoted hunk
With the current show_files() "ls -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 <redacted>
---
builtin/ls-files.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 51 insertions(+), 1 deletion(-)
@@ -337,6 +337,53 @@ static void show_files(struct dir_struct *dir)}}+staticvoidshow_files_compact(structdir_struct*dir)+{+inti;++/* For cached/deleted files we don't need to even do the readdir */+if(show_others||show_killed){+if(!show_others)+dir->flags|=DIR_COLLECT_KILLED_ONLY;+fill_directory(dir,&pathspec);+if(show_others)+show_other_files(dir);+if(show_killed)+show_killed_files(dir);+}+if(!(show_cached||show_stage||show_deleted||show_modified))+return;+for(i=0;i<active_nr;i++){+conststructcache_entry*ce=active_cache[i];+structstatst;+interr,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&&ce_modified(ce,&st,0)){
Is it possible for the lstat() to have failed for some reason when we
get here? If so, relying upon 'st' is unsafe, isn't it?
quoted hunk
+ 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"
*/
@@ -606,7 +653,10 @@ static int ls_files(const char **argv, const char *prefix) refresh_index(&the_index, REFRESH_QUIET, &pathspec, NULL, NULL); setup_pager(); }- show_files(&dir);+ if (porcelain)+ show_files_compact(&dir);+ else+ show_files(&dir); if (show_resolve_undo) show_ru_info();--
1.9.1.345.ga1a145c
--
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
If 'err' is non-zero, lstat() has failed. Consider the entry modified
without passing the (unreliable) stat info to ce_modified() in this
case.
Noticed-by: Eric Sunshine [off-list ref]
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
---
On Fri, Mar 28, 2014 at 11:04 AM, Eric Sunshine [off-list ref] wrote:
> On Wed, Mar 26, 2014 at 9:48 AM, Nguyễn Thái Ngọc Duy [off-list ref] wrote:
>> + err = lstat(ce->name, &st);
>> + if (show_deleted && err) {
>> + show_ce_entry(tag_removed, ce);
>> + shown = 1;
>> + }
>> + if (show_modified && ce_modified(ce, &st, 0)) {
>
> Is it possible for the lstat() to have failed for some reason when we
> get here? If so, relying upon 'st' is unsafe, isn't it?
The chance of random stat making ce_modified() return false is pretty
low, but you're right. This code is a copy from the old show_files().
I'll fix it in the git-ls series. Meanwhile a patch for maint to fix
the original function.
builtin/ls-files.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
All comments by Eric are fixed in v3. -F is added. And the command
name is now list-files, not ls. 'ls' is saved for the user to make
an alias with better default options.
Nguyễn Thái Ngọc Duy (18):
ls_colors.c: add $LS_COLORS parsing code
ls_colors.c: parse color.ls.* from config file
ls_colors.c: add a function to color a file name
ls_colors.c: highlight submodules like directories
ls-files: buffer full item in strbuf before printing
ls-files: add --color to highlight file names
ls-files: add --column
ls-files: support --max-depth
Add git-list-files, a user friendly version of ls-files and more
list-files: -u does not imply showing stages
list-files: add -R/--recursive short for --max-depth=-1
list-files: add -1 short for --no-column
list-files: add -t back
list-files: sort output and remove duplicates
list-files: do not show duplicate cached entries
list-files: show directories as well as files
list-files: add -F/--classify
list-files -F: show submodules with the new indicator '&'
.gitignore | 1 +
Documentation/config.txt | 22 ++
Documentation/git-list-files.txt (new) | 99 +++++++
Documentation/git-ls-files.txt | 20 ++
Makefile | 2 +
builtin/ls-files.c | 358 ++++++++++++++++++++++--
color.h | 10 +
command-list.txt | 1 +
git.c | 1 +
ls_colors.c (new) | 496 +++++++++++++++++++++++++++++++++
10 files changed, 980 insertions(+), 30 deletions(-)
create mode 100644 Documentation/git-list-files.txt
create mode 100644 ls_colors.c
--
1.9.1.345.ga1a145c
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 <redacted>
---
Documentation/config.txt | 11 +++++++++++
ls_colors.c | 26 ++++++++++++++++++++++++++
2 files changed, 37 insertions(+)
@@ -909,6 +909,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
@@ -68,6 +68,14 @@ static const char *const indicator_name[] = {NULL};+staticconstchar*constconfig_name[]={+"","","","","normal","file","directory","symlink",+"fifo","socket","block","char","missing","orphan","executable",+"door","setuid","setgid","sticky","otherwritable",+"stickyotherwritable","cap","multihardlink","",+NULL+};+structbin_str{size_tlen;/* Number of bytes */constchar*string;/* Pointer to the same */
@@ -285,6 +293,23 @@ static int get_funky_string(char **dest, const char **src, int equals_end,returnstate!=ST_ERROR;}+staticintls_colors_config(constchar*var,constchar*value,void*cb)+{+intslot;+if(!starts_with(var,"color.ls."))+return0;+var+=9;+for(slot=0;config_name[slot];slot++)+if(!strcasecmp(var,config_name[slot]))+break;+if(!config_name[slot])+return0;+if(!value)+returnconfig_error_nonbool(var);+color_parse(value,var,ls_colors[slot]);+return0;+}+voidparse_ls_color(void){constchar*p;/* Pointer to character being parsed */
@@ -913,7 +913,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
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 <redacted>
---
color.h | 2 ++
ls_colors.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 68 insertions(+)
@@ -422,3 +422,69 @@ void parse_ls_color(void)color_symlink_as_referent=1;git_config(ls_colors_config,NULL);}++voidcolor_filename(structstrbuf*sb,constchar*name,+constchar*display_name,mode_tmode,intlinkok)+{+inttype;+structcolor_ext_type*ext;/* Color extension */++if(S_ISREG(mode)){+type=LS_FL;+if((mode&S_ISUID)!=0)+type=LS_SU;+elseif((mode&S_ISGID)!=0)+type=LS_SG;+elseif((mode&(S_IXUSR|S_IXGRP|S_IXOTH))!=0)+type=LS_EX;+}elseif(S_ISDIR(mode)){+if((mode&S_ISVTX)&&(mode&S_IWOTH))+type=LS_TW;+elseif((mode&S_IWOTH)!=0)+type=LS_OW;+elseif((mode&S_ISVTX)!=0)+type=LS_ST;+else+type=LS_DI;+}elseif(S_ISLNK(mode))+type=(!linkok&&*ls_colors[LS_OR])?LS_OR:LS_LN;+elseif(S_ISFIFO(mode))+type=LS_PI;+elseif(S_ISSOCK(mode))+type=LS_SO;+elseif(S_ISBLK(mode))+type=LS_BD;+elseif(S_ISCHR(mode))+type=LS_CD;+#ifdef S_ISDOOR+elseif(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_tlen=strlen(name);+constchar*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);+elseif(*ls_colors[type])+strbuf_addf(sb,"%s%s%s",ls_colors[type],name,GIT_COLOR_RESET);+else+strbuf_addstr(sb,name);+}
@@ -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.
@@ -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()
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 <redacted>
---
builtin/ls-files.c | 48 +++++++++++++++++++++++++++++++++++-------------
1 file changed, 35 insertions(+), 13 deletions(-)
@@ -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.
@@ -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();
@@ -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.
@@ -503,6 +503,7 @@ static int option_parse_exclude_standard(const struct option *opt,intcmd_ls_files(intargc,constchar**argv,constchar*cmd_prefix){intrequire_work_tree=0,show_tag=0,i;+intmax_depth=-1;constchar*max_prefix;structdir_structdir;structexclude_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);
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 <redacted>
---
.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
@@ -909,6 +909,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
@@ -981,6 +987,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.
@@ -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
@@ -500,6 +506,17 @@ static int option_parse_exclude_standard(const struct option *opt,return0;}+staticintgit_ls_config(constchar*var,constchar*value,void*cb)+{+if(starts_with(var,"column."))+returngit_column_config(var,value,"list-files",&colopts);+if(!strcmp(var,"color.list-files")){+use_color=git_config_colorbool(var,value);+return0;+}+returngit_color_default_config(var,value,cb);+}+intcmd_ls_files(intargc,constchar**argv,constchar*cmd_prefix){intrequire_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()};+structoptionbuiltin_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()+};+structoption*options;+constchar*const*help_usage;+if(!strcmp(argv[0],"list-files")){+help_usage=ls_usage;+options=builtin_ls_options;+porcelain=1;+}else{+help_usage=ls_files_usage;+options=builtin_ls_files_options;+}if(argc==2&&!strcmp(argv[1],"-h"))-usage_with_options(ls_files_usage,builtin_ls_files_options);+usage_with_options(help_usage,options);memset(&dir,0,sizeof(dir));prefix=cmd_prefix;if(prefix)prefix_len=strlen(prefix);-git_config(git_default_config,NULL);++if(porcelain){+setenv(GIT_GLOB_PATHSPECS_ENVIRONMENT,"1",1);+exc_given=1;+setup_standard_excludes(&dir);+use_color=-1;+max_depth=0;+git_config(git_ls_config,NULL);+}else+git_config(git_default_config,NULL);if(read_cache()<0)die("index file corrupt");-argc=parse_options(argc,argv,prefix,builtin_ls_files_options,-ls_files_usage,0);+argc=parse_options(argc,argv,prefix,options,help_usage,0);el=add_exclude_list(&dir,EXC_CMDL,"--exclude option");for(i=0;i<exclude_list.nr;i++){add_exclude(exclude_list.items[i].string,"",0,el,--exclude_args);
@@ -661,6 +718,10 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)die("ls-files --with-tree is incompatible with -s or -u");overlay_tree_on_cache(with_tree,max_prefix);}+if(porcelain){+refresh_index(&the_index,REFRESH_QUIET,&pathspec,NULL,NULL);+setup_pager();+}show_files(&dir);if(show_resolve_undo)show_ru_info();
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 <redacted>
---
Makefile | 1 +
color.h | 8 ++
ls_colors.c (new) | 398 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 407 insertions(+)
create mode 100644 ls_colors.c
@@ -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"
@@ -0,0 +1,398 @@+#include"cache.h"+#include"color.h"++enumcolor_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+};++staticcharls_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,+"",+"",+""+};++staticconstchar*constindicator_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+};++structbin_str{+size_tlen;/* Number of bytes */+constchar*string;/* Pointer to the same */+};++structcolor_ext_type{+structbin_strext;/* The extension we're looking for */+structbin_strseq;/* The sequence to output when we do */+structcolor_ext_type*next;/* Next in list */+};++staticstructcolor_ext_type*color_ext_list=NULL;++/*+*Whentrue,inacolorlisting,coloreachsymlinknameaccordingtothe+*typeoffileitpointsto.Otherwise,colorthemaccordingtothe`ln'+*directiveinLS_COLORS.Dangling(orphan)symlinksaretreatedspecially,+*regardless.Thisissetwhen`ln=target'appearsinLS_COLORS.+*/+staticintcolor_symlink_as_referent;++/*+*ParseastringaspartoftheLS_COLORSvariable;thismayinvolve+*decodingallkindsofescapecharacters.Ifequals_endissetan+*unescapedequalsignendsthestring,otherwiseonlya:or\0+*does.Set*OUTPUT_COUNTtothenumberofbytesoutput.Return+*trueifsuccessful.+*+*Theresultingstringis*not*null-terminated,butmaycontain+*embeddednulls.+*+*Notethatbothdestandsrcarechar**;onreturntheypointto+*thefirstfreebyteafterthearrayandthecharacterthatended+*theinputstring,respectively.+*/+staticintget_funky_string(char**dest,constchar**src,intequals_end,+size_t*output_count)+{+charnum;/* For numerical codes */+size_tcount;/* Something to count with */+enum{+ST_GND,ST_BACKSLASH,ST_OCTAL,ST_HEX,+ST_CARET,ST_END,ST_ERROR+}state;+constchar*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){+caseST_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;++caseST_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;++caseST_OCTAL:/* Octal sequence */+if(*p<'0'||*p>'7'){+*(q++)=num;+++count;+state=ST_GND;+}else+num=(num<<3)+(*(p++)-'0');+break;++caseST_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;++caseST_CARET:/* Caret escape */+state=ST_GND;/* Should be the next state... */+if(*p>='@'&&*p<='~'){+*(q++)=*(p++)&037;+++count;+}elseif(*p=='?'){+*(q++)=127;+++count;+}else+state=ST_ERROR;+break;++default:+abort();+}+}++*dest=q;+*src=p;+*output_count=count;++returnstate!=ST_ERROR;+}++voidparse_ls_color(void)+{+constchar*p;/* Pointer to character being parsed */+char*buf;/* color_buf buffer pointer */+intstate;/* State of parser */+intind_no;/* Indicator number */+charlabel[3];/* Indicator label */+structcolor_ext_type*ext;/* Extension we are working on */+staticchar*color_buf;+char*start;+size_tlen;++if((p=getenv("LS_COLORS"))==NULL||*p=='\0')+return;++ext=NULL;+strcpy(label,"??");++/*+*Thisisanoverlyconservativeestimate,butanypossible+*LS_COLORSstringwill*not*generateacolor_buflonger+*thanitself,soitisasafewayofallocatingabufferin+*advance.+*/+buf=color_buf=xstrdup(p);++state=1;+while(state>0){+switch(state){+case1:/* First label character */+switch(*p){+case':':+++p;+break;++case'*':+/*+*Allocatenewextensionblockandaddtoheadof+*linkedlist(thiswayalaterdefinitionwill+*overrideanearlierone,whichcanbeusefulfor+*havingterminal-specificdefsoverrideglobal).+*/++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;++case2:/* Second label character */+if(*p){+label[1]=*(p++);+state=3;+}else+state=-1;/* Error */+break;++case3:/* 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);+elseif(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;++case4:/* 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;+}
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 <redacted>
---
builtin/ls-files.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
@@ -45,6 +45,10 @@ OPTIONS --unmerged:: Show unmerged files+-R::+--recursive::+ Equivalent of `--max-depth=-1` (infinite recursion).+ --color[=<when>]:: --no-color:: Color file names. The value must be `always`, `never`, or
@@ -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),
@@ -49,6 +49,9 @@ OPTIONS --recursive:: Equivalent of `--max-depth=-1` (infinite recursion).+-1::+ Equivalent of --no-column.+ --color[=<when>]:: --no-color:: Color file names. The value must be `always`, `never`, or
@@ -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},
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 <redacted>
---
Documentation/git-list-files.txt | 6 ++++++
builtin/ls-files.c | 27 +++++++++++++++++----------
2 files changed, 23 insertions(+), 10 deletions(-)
@@ -45,6 +45,12 @@ OPTIONS --unmerged:: Show unmerged files+-t::+--[no-]tag::+ Show a tag to indicate file type. Automatically turned on with+ multiple file selections. See linkgit::git-ls-files[1] option+ `-t` for more information.+ -R:: --recursive:: Equivalent of `--max-depth=-1` (infinite recursion).
@@ -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),
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 <redacted>
---
builtin/ls-files.c | 36 ++++++++++++++++++++++++------------
1 file changed, 24 insertions(+), 12 deletions(-)
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 <redacted>
---
builtin/ls-files.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 51 insertions(+), 1 deletion(-)
@@ -333,6 +333,53 @@ static void show_files(struct dir_struct *dir)}}+staticvoidshow_files_compact(structdir_struct*dir)+{+inti;++/* For cached/deleted files we don't need to even do the readdir */+if(show_others||show_killed){+if(!show_others)+dir->flags|=DIR_COLLECT_KILLED_ONLY;+fill_directory(dir,&pathspec);+if(show_others)+show_other_files(dir);+if(show_killed)+show_killed_files(dir);+}+if(!(show_cached||show_stage||show_deleted||show_modified))+return;+for(i=0;i<active_nr;i++){+conststructcache_entry*ce=active_cache[i];+structstatst;+interr,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);+}+}+/**Prunetheindextoonlycontainstuffstartingwith"prefix"*/
The index does not store directories explicitly (except submodules) so
we have to figure them out from file list. The function
show_directories() deliberately generates duplicate directories and
expects the previous patch to remove duplicates.
Signed-off-by: Nguyễn Thái Ngọc Duy <redacted>
---
builtin/ls-files.c | 44 +++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 43 insertions(+), 1 deletion(-)
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 <redacted>
---
Documentation/git-list-files.txt | 6 ++++++
builtin/ls-files.c | 31 +++++++++++++++++++++++++++++++
2 files changed, 37 insertions(+)
@@ -51,6 +51,12 @@ OPTIONS multiple file selections. See linkgit::git-ls-files[1] option `-t` for more information.+-F::+--classify::+ Append indicator (one of `*/=>@|`, which is executable,+ directory, socket, Solaris door, symlink, or fifo+ respectively) to entries.+ -R:: --recursive:: Equivalent of `--max-depth=-1` (infinite recursion).
@@ -53,8 +53,8 @@ OPTIONS -F:: --classify::- Append indicator (one of `*/=>@|`, which is executable,- directory, socket, Solaris door, symlink, or fifo+ Append indicator (one of `*/=>@|&`, which is executable,+ directory, socket, Solaris door, symlink, fifo, or submodule respectively) to entries. -R::