Initial path: support sort by disk usage

This commit is contained in:
Arun Prakash Jana 2017-04-10 00:11:29 +05:30
parent e54ed037bd
commit cbefcfd67b
No known key found for this signature in database
GPG key ID: A75979F35C080412
4 changed files with 134 additions and 35 deletions

View file

@ -66,7 +66,8 @@ I chose to fork because:
- number of items in current directory - number of items in current directory
- full name of currently selected file in 'bar' - full name of currently selected file in 'bar'
- Show details of the currently selected file (stat, file) - Show details of the currently selected file (stat, file)
- Directories first - Disk usage analyzer mode
- Directories first (even with sorting)
- Sort numeric names in numeric order - Sort numeric names in numeric order
- Case-insensitive alphabetic content listing instead of upper case first - Case-insensitive alphabetic content listing instead of upper case first
- Key `-` to jump to last visited directory - Key `-` to jump to last visited directory
@ -139,6 +140,7 @@ Start nnn (default: current directory):
| `D` | Show details of selected file | | `D` | Show details of selected file |
| `.` | Toggle hide .dot files | | `.` | Toggle hide .dot files |
| `s` | Toggle sort by file size | | `s` | Toggle sort by file size |
| `S` | Toggle disk usage analyzer mode |
| `t` | Toggle sort by modified time | | `t` | Toggle sort by modified time |
| `!` | Spawn `SHELL` in `PWD` (fallback sh) | | `!` | Spawn `SHELL` in `PWD` (fallback sh) |
| `z` | Run `top` | | `z` | Run `top` |

View file

@ -5,6 +5,7 @@
static int mtimeorder = 0; /* Set to 1 to sort by time modified */ static int mtimeorder = 0; /* Set to 1 to sort by time modified */
static int sizeorder = 0; /* Set to 1 to sort by file size */ static int sizeorder = 0; /* Set to 1 to sort by file size */
static int bsizeorder = 0; /* Set to 1 to sort by blocks used including content */
static int idletimeout = 0; /* Screensaver timeout in seconds, 0 to disable */ static int idletimeout = 0; /* Screensaver timeout in seconds, 0 to disable */
static int showhidden = 0; /* Set to 1 to show hidden files by default */ static int showhidden = 0; /* Set to 1 to show hidden files by default */
static int showdetail = 0; /* Set to show additional file info */ static int showdetail = 0; /* Set to show additional file info */
@ -75,6 +76,8 @@ struct key bindings[] = {
{ 'D', SEL_STATS, "", "" }, { 'D', SEL_STATS, "", "" },
/* Toggle sort by size */ /* Toggle sort by size */
{ 's', SEL_FSIZE, "", "" }, { 's', SEL_FSIZE, "", "" },
/* Sort by total block size including dir contents */
{ 'S', SEL_BSIZE, "", "" },
/* Toggle sort by time */ /* Toggle sort by time */
{ 't', SEL_MTIME, "", "" }, { 't', SEL_MTIME, "", "" },
{ CONTROL('L'), SEL_REDRAW, "", "" }, { CONTROL('L'), SEL_REDRAW, "", "" },

4
nnn.1
View file

@ -10,7 +10,7 @@
.Op Ar dir .Op Ar dir
.Sh DESCRIPTION .Sh DESCRIPTION
.Nm .Nm
(Noice is Not Noice) is a fork of the noice terminal file browser with improved desktop integration, file associations and navigation. It remains a simple and efficient file browser that stays out of your way. (Noice is Not Noice) is a fork of the noice terminal file browser with improved desktop integration, file associations, navigation and disk usage analyzer mode. It remains a simple and efficient file browser that stays out of your way.
.Pp .Pp
.Nm .Nm
defaults to the current directory if defaults to the current directory if
@ -54,6 +54,8 @@ Show details of selected file
Toggle hide .dot files Toggle hide .dot files
.It Ic s .It Ic s
Toggle sort by file size Toggle sort by file size
.It Ic S
Toggle disk usage analyzer mode
.It Ic t .It Ic t
Toggle sort by time modified Toggle sort by time modified
.It Ic \&! .It Ic \&!

158
nnn.c
View file

@ -20,6 +20,9 @@
#include <pwd.h> #include <pwd.h>
#include <grp.h> #include <grp.h>
#define __USE_XOPEN_EXTENDED
#include <ftw.h>
#ifdef DEBUG #ifdef DEBUG
static int static int
xprintf(int fd, const char *fmt, ...) xprintf(int fd, const char *fmt, ...)
@ -82,6 +85,7 @@ enum action {
SEL_DETAIL, SEL_DETAIL,
SEL_STATS, SEL_STATS,
SEL_FSIZE, SEL_FSIZE,
SEL_BSIZE,
SEL_MTIME, SEL_MTIME,
SEL_REDRAW, SEL_REDRAW,
SEL_COPY, SEL_COPY,
@ -104,6 +108,7 @@ typedef struct entry {
mode_t mode; mode_t mode;
time_t t; time_t t;
off_t size; off_t size;
off_t bsize;
} *pEntry; } *pEntry;
typedef unsigned long ulong; typedef unsigned long ulong;
@ -422,9 +427,19 @@ entrycmp(const void *va, const void *vb)
if (mtimeorder) if (mtimeorder)
return pb->t - pa->t; return pb->t - pa->t;
if (sizeorder) if (sizeorder) {
if (pb->size != pa->size) if (pb->size > pa->size)
return pb->size - pa->size; return 1;
else if (pb->size < pa->size)
return -1;
}
if (bsizeorder) {
if (pb->bsize > pa->bsize)
return 1;
else if (pb->bsize < pa->bsize)
return -1;
}
return xstricmp(pa->name, pb->name); return xstricmp(pa->name, pb->name);
} }
@ -582,20 +597,25 @@ printent(struct entry *ent, int active)
} }
static void (*printptr)(struct entry *ent, int active) = &printent; static void (*printptr)(struct entry *ent, int active) = &printent;
static const double div_2_pow_10 = 1.0 / 1024.0;
static char* static char*
coolsize(off_t size) coolsize(off_t size)
{ {
static char size_buf[12]; /* Buffer to hold human readable size */ static char size_buf[12]; /* Buffer to hold human readable size */
int i = 0; int i = 0;
long double fsize = (double)size; off_t fsize = size, tmp;
long double rem = 0;
while (fsize > 1024) { while (fsize > 1024) {
fsize /= 1024; tmp = fsize;
//fsize *= div_2_pow_10;
fsize >>= 10;
rem = tmp - (fsize << 10);
i++; i++;
} }
snprintf(size_buf, 12, "%.*Lf%s", i, fsize, size_units[i]); snprintf(size_buf, 12, "%.*Lf%s", i, fsize + rem * div_2_pow_10, size_units[i]);
return size_buf; return size_buf;
} }
@ -608,30 +628,57 @@ printent_long(struct entry *ent, int active)
if (active) if (active)
attron(A_REVERSE); attron(A_REVERSE);
if (S_ISDIR(ent->mode)) if (!bsizeorder) {
printw("%s%-17.17s / %s/\n", if (S_ISDIR(ent->mode))
CURSYM(active), buf, ent->name); printw("%s%-17.17s / %s/\n",
else if (S_ISLNK(ent->mode)) CURSYM(active), buf, ent->name);
printw("%s%-17.17s @ %s@\n", else if (S_ISLNK(ent->mode))
CURSYM(active), buf, ent->name); printw("%s%-17.17s @ %s@\n",
else if (S_ISSOCK(ent->mode)) CURSYM(active), buf, ent->name);
printw("%s%-17.17s = %s=\n", else if (S_ISSOCK(ent->mode))
CURSYM(active), buf, ent->name); printw("%s%-17.17s = %s=\n",
else if (S_ISFIFO(ent->mode)) CURSYM(active), buf, ent->name);
printw("%s%-17.17s | %s|\n", else if (S_ISFIFO(ent->mode))
CURSYM(active), buf, ent->name); printw("%s%-17.17s | %s|\n",
else if (S_ISBLK(ent->mode)) CURSYM(active), buf, ent->name);
printw("%s%-17.17s b %s\n", else if (S_ISBLK(ent->mode))
CURSYM(active), buf, ent->name); printw("%s%-17.17s b %s\n",
else if (S_ISCHR(ent->mode)) CURSYM(active), buf, ent->name);
printw("%s%-17.17s c %s\n", else if (S_ISCHR(ent->mode))
CURSYM(active), buf, ent->name); printw("%s%-17.17s c %s\n",
else if (ent->mode & S_IXUSR) CURSYM(active), buf, ent->name);
printw("%s%-17.17s %8.8s* %s*\n", CURSYM(active), else if (ent->mode & S_IXUSR)
buf, coolsize(ent->size), ent->name); printw("%s%-17.17s %8.8s* %s*\n", CURSYM(active),
else buf, coolsize(ent->size), ent->name);
printw("%s%-17.17s %8.8s %s\n", CURSYM(active), else
buf, coolsize(ent->size), ent->name); printw("%s%-17.17s %8.8s %s\n", CURSYM(active),
buf, coolsize(ent->size), ent->name);
} else {
if (S_ISDIR(ent->mode))
printw("%s%-17.17s %8.8s/ %s/\n", CURSYM(active),
buf, coolsize(ent->bsize << 9), ent->name);
else if (S_ISLNK(ent->mode))
printw("%s%-17.17s @ %s@\n",
CURSYM(active), buf, ent->name);
else if (S_ISSOCK(ent->mode))
printw("%s%-17.17s = %s=\n",
CURSYM(active), buf, ent->name);
else if (S_ISFIFO(ent->mode))
printw("%s%-17.17s | %s|\n",
CURSYM(active), buf, ent->name);
else if (S_ISBLK(ent->mode))
printw("%s%-17.17s b %s\n",
CURSYM(active), buf, ent->name);
else if (S_ISCHR(ent->mode))
printw("%s%-17.17s c %s\n",
CURSYM(active), buf, ent->name);
else if (ent->mode & S_IXUSR)
printw("%s%-17.17s %8.8s* %s*\n", CURSYM(active),
buf, coolsize(ent->bsize << 9), ent->name);
else
printw("%s%-17.17s %8.8s %s\n", CURSYM(active),
buf, coolsize(ent->bsize << 9), ent->name);
}
if (active) if (active)
attroff(A_REVERSE); attroff(A_REVERSE);
@ -862,6 +909,7 @@ show_help(void)
D Show details of selected file\n\ D Show details of selected file\n\
. Toggle hide .dot files\n\ . Toggle hide .dot files\n\
s Toggle sort by file size\n\ s Toggle sort by file size\n\
S Toggle disk usage analyzer mode\n\
t Toggle sort by modified time\n\ t Toggle sort by modified time\n\
! Spawn SHELL in PWD (fallback sh)\n\ ! Spawn SHELL in PWD (fallback sh)\n\
z Run top\n\ z Run top\n\
@ -880,11 +928,30 @@ show_help(void)
return; return;
} }
off_t blk_size;
static int
sum_sizes(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf)
{
if (!fpath || !ftwbuf)
printmsg("fpath or ftwbuf NULL"); /* TODO: on %s", fpath); */
/* Handle permission problems */
if(typeflag == FTW_NS) {
printmsg("No stats (permissions ?)"); /* TODO: on %s", fpath); */
return 0;
}
blk_size += sb->st_blocks;
return 0;
}
static int static int
dentfill(char *path, struct entry **dents, dentfill(char *path, struct entry **dents,
int (*filter)(regex_t *, char *), regex_t *re) int (*filter)(regex_t *, char *), regex_t *re)
{ {
char newpath[PATH_MAX]; static char newpath[PATH_MAX];
DIR *dirp; DIR *dirp;
struct dirent *dp; struct dirent *dp;
struct stat sb; struct stat sb;
@ -911,6 +978,19 @@ dentfill(char *path, struct entry **dents,
(*dents)[n].mode = sb.st_mode; (*dents)[n].mode = sb.st_mode;
(*dents)[n].t = sb.st_mtime; (*dents)[n].t = sb.st_mtime;
(*dents)[n].size = sb.st_size; (*dents)[n].size = sb.st_size;
if (bsizeorder) {
if (S_ISDIR(sb.st_mode)) {
blk_size = 0;
if (nftw(newpath, sum_sizes, 128, FTW_MOUNT | FTW_PHYS) == -1) {
printmsg("nftw(3) failed"); /* TODO: , newpath); */
(*dents)[n].bsize = sb.st_blocks;
} else
(*dents)[n].bsize = blk_size;
} else
(*dents)[n].bsize = sb.st_blocks;
}
n++; n++;
} }
@ -1028,12 +1108,14 @@ redraw(char *path)
if (showdetail) { if (showdetail) {
if (ndents) { if (ndents) {
static char ind[2] = "\0\0"; static char ind[2] = "\0\0";
static char sort[9]; static char sort[17];
if (mtimeorder) if (mtimeorder)
sprintf(sort, "by time "); sprintf(sort, "by time ");
else if (sizeorder) else if (sizeorder)
sprintf(sort, "by size "); sprintf(sort, "by size ");
else if (bsizeorder)
sprintf(sort, "by content size ");
else else
sort[0] = '\0'; sort[0] = '\0';
@ -1345,6 +1427,15 @@ nochange:
case SEL_FSIZE: case SEL_FSIZE:
sizeorder = !sizeorder; sizeorder = !sizeorder;
mtimeorder = 0; mtimeorder = 0;
bsizeorder = 0;
/* Save current */
if (ndents > 0)
mkpath(path, dents[cur].name, oldpath, sizeof(oldpath));
goto begin;
case SEL_BSIZE:
bsizeorder = !bsizeorder;
mtimeorder = 0;
sizeorder = 0;
/* Save current */ /* Save current */
if (ndents > 0) if (ndents > 0)
mkpath(path, dents[cur].name, oldpath, sizeof(oldpath)); mkpath(path, dents[cur].name, oldpath, sizeof(oldpath));
@ -1352,6 +1443,7 @@ nochange:
case SEL_MTIME: case SEL_MTIME:
mtimeorder = !mtimeorder; mtimeorder = !mtimeorder;
sizeorder = 0; sizeorder = 0;
bsizeorder = 0;
/* Save current */ /* Save current */
if (ndents > 0) if (ndents > 0)
mkpath(path, dents[cur].name, oldpath, sizeof(oldpath)); mkpath(path, dents[cur].name, oldpath, sizeof(oldpath));
@ -1387,7 +1479,7 @@ nochange:
exitcurses(); exitcurses();
spawn(run, NULL, path, 1); spawn(run, NULL, path, 1);
initcurses(); initcurses();
/* Re-populate as directory content may have changed */ /* Repopulate as directory content may have changed */
goto begin; goto begin;
case SEL_RUNARG: case SEL_RUNARG:
run = xgetenv(env, run); run = xgetenv(env, run);