diff --git a/README.md b/README.md index 9df00db3..fe82d1c9 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ I chose to fork noice because: - Jump to home directory - Filter contents in current directory - Show/hide hidden files -- Sort entries by time modified +- Sort entries by time modified (newest to oldest) - Spawn a shell in current directory - Run `top` - Open a file with `vim` or `less` @@ -43,8 +43,10 @@ I chose to fork noice because: ### Fork toppings - Behaviour and navigation - - Case-insensitive alphabetic content listing instead of upper case first. - - Roll over at the first and last entries of a directory (with Up/Down keys). + - Optional detailed view with file type and size (default: disabled) + - Case-insensitive alphabetic content listing instead of upper case first + - Roll over at the first and last entries of a directory (with Up/Down keys) + - Sort entries by file size (largest to smallest) - File associations - Environment variable `NOICE_OPENER` to override all associations and open all files with your desktop environments default file opener. Examples: @@ -95,7 +97,9 @@ Start noice (default: current directory): | `~` | jump to home dir | | `/`, `&` | filter dir contents | | `c` | show change dir prompt | +| 'd' | toggle detail view | | `.` | toggle hide dot files | +| `s` | toggle sort by file size | | `t` | toggle sort by modified time | | `!` | spawn a shell in current dir | | `e` | edit entry in `vim` | diff --git a/config.def.h b/config.def.h index bffc69d5..9c6ae7e8 100644 --- a/config.def.h +++ b/config.def.h @@ -4,8 +4,10 @@ #define EMPTY " " int mtimeorder = 0; /* Set to 1 to sort by time modified */ +int sizeorder = 0; /* Set to 1 to sort by file size */ int idletimeout = 0; /* Screensaver timeout in seconds, 0 to disable */ int showhidden = 0; /* Set to 1 to show hidden files by default */ +int showdetail = 0; /* Set to show additional file info */ char *idlecmd = "rain"; /* The screensaver program */ struct assoc assocs[] = { @@ -62,6 +64,10 @@ struct key bindings[] = { { '~', SEL_CDHOME }, /* Toggle hide .dot files */ { '.', SEL_TOGGLEDOT }, + /* Detailed listing */ + { 'd', SEL_DETAIL }, + /* Toggle sort by size */ + { 's', SEL_FSIZE }, /* Toggle sort by time */ { 't', SEL_MTIME }, { CONTROL('L'), SEL_REDRAW }, diff --git a/noice.c b/noice.c index 25f2f951..a3e7617c 100644 --- a/noice.c +++ b/noice.c @@ -62,6 +62,8 @@ enum action { SEL_CD, SEL_CDHOME, SEL_TOGGLEDOT, + SEL_DETAIL, + SEL_FSIZE, SEL_MTIME, SEL_REDRAW, SEL_RUN, @@ -81,6 +83,7 @@ struct entry { char name[PATH_MAX]; mode_t mode; time_t t; + off_t size; }; /* Global context */ @@ -89,6 +92,8 @@ int ndents, cur; int idle; char *opener = NULL; char *fallback_opener = NULL; +char size_buf[12]; /* Buffer to hold human readable size */ +const char* size_units[] = {"B", "K", "M", "G", "T", "P", "E", "Z", "Y"}; /* * Layout: @@ -107,6 +112,7 @@ char *fallback_opener = NULL; * '------ */ +void (*printptr)(struct entry *ent, int active); void printmsg(char *); void printwarn(void); void printerr(int, char *); @@ -271,11 +277,13 @@ visible(regex_t *regex, char *file) int entrycmp(const void *va, const void *vb) { - const struct entry *a = va, *b = vb; - if (mtimeorder) - return b->t - a->t; - return xstricmp(a->name, b->name); + return ((struct entry *)vb)->t - ((struct entry *)va)->t; + + if (sizeorder) + return ((struct entry *)vb)->size - ((struct entry *)va)->size; + + return xstricmp(((struct entry *)va)->name, ((struct entry *)vb)->name); } void @@ -446,6 +454,42 @@ printent(struct entry *ent, int active) printw("%s%s%c\n", active ? CURSR : EMPTY, name, cm); } +char* +coolsize(off_t size) +{ + int i = 0; + long double fsize = (double)size; + + while (fsize > 1024) { + fsize /= 1024; + i++; + } + + snprintf(size_buf, 12, "%.*Lf%s", i, fsize, size_units[i]); + return size_buf; +} + +void +printent_long(struct entry *ent, int active) +{ + if (S_ISDIR(ent->mode)) + printw("%s%-32.32s DIR\n", active ? CURSR : EMPTY, ent->name); + else if (S_ISLNK(ent->mode)) + printw("%s%-32.32s SYM\n", active ? CURSR : EMPTY, ent->name); + else if (S_ISSOCK(ent->mode)) + printw("%s%-32.32s SOCK\n", active ? CURSR : EMPTY, ent->name); + else if (S_ISFIFO(ent->mode)) + printw("%s%-32.32s FIFO\n", active ? CURSR : EMPTY, ent->name); + else if (S_ISBLK(ent->mode)) + printw("%s%-32.32s BLK\n", active ? CURSR : EMPTY, ent->name); + else if (S_ISCHR(ent->mode)) + printw("%s%-32.32s CHR\n", active ? CURSR : EMPTY, ent->name); + else if (ent->mode & S_IXUSR) + printw("%s%-32.32s EXE %s\n", active ? CURSR : EMPTY, ent->name, coolsize(ent->size)); + else + printw("%s%-32.32s REG %s\n", active ? CURSR : EMPTY, ent->name, coolsize(ent->size)); +} + int dentfill(char *path, struct entry **dents, int (*filter)(regex_t *, char *), regex_t *re) @@ -476,6 +520,7 @@ dentfill(char *path, struct entry **dents, printerr(1, "lstat"); (*dents)[n].mode = sb.st_mode; (*dents)[n].t = sb.st_mtime; + (*dents)[n].size = sb.st_size; n++; } @@ -580,14 +625,14 @@ redraw(char *path) odd = ISODD(nlines); if (cur < (nlines >> 1)) { for (i = 0; i < nlines; i++) - printent(&dents[i], i == cur); + printptr(&dents[i], i == cur); } else if (cur >= ndents - (nlines >> 1)) { for (i = ndents - nlines; i < ndents; i++) - printent(&dents[i], i == cur); + printptr(&dents[i], i == cur); } else { nlines >>= 1; for (i = cur - nlines; i < cur + nlines + odd; i++) - printent(&dents[i], i == cur); + printptr(&dents[i], i == cur); } } @@ -803,8 +848,20 @@ nochange: initfilter(showhidden, &ifilter); strlcpy(fltr, ifilter, sizeof(fltr)); goto begin; + case SEL_DETAIL: + showdetail = !showdetail; + showdetail ? (printptr = &printent_long) : (printptr = &printent); + goto begin; + case SEL_FSIZE: + sizeorder = !sizeorder; + mtimeorder = 0; + /* Save current */ + if (ndents > 0) + mkpath(path, dents[cur].name, oldpath, sizeof(oldpath)); + goto begin; case SEL_MTIME: mtimeorder = !mtimeorder; + sizeorder = 0; /* Save current */ if (ndents > 0) mkpath(path, dents[cur].name, oldpath, sizeof(oldpath)); @@ -864,6 +921,8 @@ main(int argc, char *argv[]) showhidden = 1; initfilter(showhidden, &ifilter); + printptr = &printent; + if (argv[1] != NULL) { ipath = argv[1]; } else {