The rules are currently hardcoded (the first item has highest priority)
- If it's a modified entry, it's bold red.
- If it's an executable, it's bold green.
- If it's a directory, it's bold blue.
Personally I'm happy with just that. But people might want to separate other entries from cached ones in "ls -co", anyone?
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
Bad bad bad hard coding.
builtin/ls-files.c | 59 ++++++++++++++++++++++++++++++++++++++++++++--------
1 files changed, 50 insertions(+), 9 deletions(-)
Show changes to builtin/ls-files.c +51 −10
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index bc438b2..9c8179a 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -14,6 +14,7 @@
#include "resolve-undo.h"
#include "string-list.h"
#include "column.h"
+#include "color.h"
static int abbrev;
static int show_deleted;
@@ -37,6 +38,7 @@ static int error_unmatch;
static char *ps_matched;
static const char *with_tree;
static int exc_given;
+static int use_color;
static const char *tag_cached = "";
static const char *tag_unmerged = "";
@@ -50,12 +52,18 @@ static const char *tag_resolve_undo = "";
static struct string_list output;
static int column_mode;
-static void write_name(const char* name, size_t len)
+static void write_name(const char* name, size_t len, const char *color)
{
/* No quoting in column layout. It will be done by the end. */
if (column_mode & COL_MODE) {
struct strbuf sb = STRBUF_INIT;
- strbuf_add(&sb, name, len);
+ if (color && use_color) {
+ strbuf_addstr(&sb, color);
+ strbuf_add(&sb, name, len);
+ strbuf_addstr(&sb, GIT_COLOR_RESET);
+ }
+ else
+ strbuf_add(&sb, name, len);
string_list_append(&output, strbuf_detach(&sb, NULL));
return;
}
@@ -81,16 +89,29 @@ static const char *path_too_deep(const char *name)
return strchr(name + common, '/');
}
+static int ansi_length(const char *s)
+{
+ const char *p = s;
+ while (p[0] == '\033')
+ p += strspn(p + 2, "0123456789;") + 3;
+ return p - s;
+}
+
static int already_shown(const char *name)
{
const char *last_item;
- int len;
+ int len, ansi_len;
if (!output.nr)
return 0;
last_item = output.items[output.nr-1].string;
len = strlen(last_item);
+ ansi_len = ansi_length(last_item);
+ if (ansi_len) {
+ last_item += ansi_len;
+ len -= ansi_len + strlen(GIT_COLOR_RESET);
+ }
return !strncmp(last_item, name, len) && name[len] == '/';
}
@@ -98,6 +119,7 @@ static void show_dir_entry(const char *tag, struct dir_entry *ent)
{
int len = max_prefix_len;
const char *too_deep;
+ struct stat st;
if (len >= ent->len)
die("git ls-files: internal error - directory entry not superset of prefix");
@@ -111,7 +133,9 @@ static void show_dir_entry(const char *tag, struct dir_entry *ent)
len = too_deep ? too_deep - ent->name : ent->len;
fputs(tag, stdout);
- write_name(ent->name, len);
+ write_name(ent->name, len,
+ len < ent->len ? GIT_COLOR_BOLD_BLUE :
+ (!stat(ent->name, &st) && st.st_mode & S_IXUSR ? GIT_COLOR_BOLD_GREEN : NULL));
}
static void show_other_files(struct dir_struct *dir)
@@ -179,6 +203,7 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce)
{
int len = max_prefix_len;
const char *too_deep;
+ struct stat st;
int namelen;
if (len >= ce_namelen(ce))
@@ -218,7 +243,10 @@ static void show_ce_entry(const char *tag, struct cache_entry *ce)
find_unique_abbrev(ce->sha1,abbrev),
ce_stage(ce));
}
- write_name(ce->name, namelen);
+ write_name(ce->name, namelen,
+ namelen < ce_namelen(ce) ? GIT_COLOR_BOLD_BLUE :
+ (!stat(ce->name, &st) && ce_modified(ce, &st, 0) ? GIT_COLOR_BOLD_RED :
+ (ce_permissions(ce->ce_mode) == 0755 ? GIT_COLOR_BOLD_GREEN : NULL)));
if (debug_mode) {
printf(" ctime: %d:%d\n", ce->ce_ctime.sec, ce->ce_ctime.nsec);
printf(" mtime: %d:%d\n", ce->ce_mtime.sec, ce->ce_mtime.nsec);
@@ -251,7 +279,7 @@ 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, len);
+ write_name(path, len, NULL);
}
}
}
@@ -676,6 +704,16 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix)
return 0;
}
+static int ls_config(const char *var, const char *value, void *cb)
+{
+ if (!strcmp(var, "color.ls"))
+ use_color = git_config_colorbool(var, value, -1);
+ else
+ return git_color_default_config(var, value, cb);
+
+ return 0;
+}
+
static int one_match_pathspec(const char *pathspec)
{
struct stat st;
@@ -724,11 +762,13 @@ static void remove_common_prefix()
*/
s1 = output.items[output.nr-1].string;
- len = strlen(s1);
+ len = strlen(s1) - ansi_length(s1);
for (i = 1; i < output.nr; i++) {
int j = 0;
s1 = output.items[i-1].string;
+ s1 += ansi_length(s1);
s2 = output.items[i].string;
+ s2 += ansi_length(s2);
while (j < len && s1[j] == s2[j])
j++;
len = j;
@@ -740,6 +780,7 @@ static void remove_common_prefix()
if (len) {
for (i = 0; i < output.nr; i++) {
char *s = output.items[i].string;
+ s += ansi_length(s);
memcpy(s, s+len, strlen(s) - len + 1);
}
}
@@ -778,12 +819,12 @@ int cmd_ls(int argc, const char **argv, const char *cmd_prefix)
prefix = cmd_prefix;
if (prefix)
prefix_len = strlen(prefix);
- git_config(git_default_config, NULL);
+ git_config(ls_config, NULL);
if (read_cache() < 0)
die("index file corrupt");
- column_mode = core_column;
+ column_mode = core_column | COL_ANSI;
argc = parse_options(argc, argv, prefix, builtin_ls_files_options,
ls_files_usage, 0);
@@ -793,7 +834,7 @@ int cmd_ls(int argc, const char **argv, const char *cmd_prefix)
pathspecs = get_pathspec(prefix, argv);
- if (show_modified)
+ if (show_modified || use_color)
refresh_index(&the_index, REFRESH_QUIET, pathspecs, NULL, NULL);
if (!pathspecs) {