]> Sergey Matveev's repositories - nnn.git/commitdiff
Initial path: support sort by disk usage
authorArun Prakash Jana <engineerarun@gmail.com>
Sun, 9 Apr 2017 18:41:29 +0000 (00:11 +0530)
committerArun Prakash Jana <engineerarun@gmail.com>
Mon, 10 Apr 2017 04:58:25 +0000 (10:28 +0530)
README.md
config.def.h
nnn.1
nnn.c

index e398aba9586b20e90da50402fd11735a4c06f973..505d653864d1176609c4940d225d7b2b1ada5adc 100644 (file)
--- a/README.md
+++ b/README.md
@@ -66,7 +66,8 @@ I chose to fork because:
     - number of items in current directory
     - full name of currently selected file in 'bar'
   - 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
   - Case-insensitive alphabetic content listing instead of upper case first
   - Key `-` to jump to last visited directory
@@ -139,6 +140,7 @@ Start nnn (default: current directory):
 | `D` | Show details of selected file |
 | `.` | Toggle hide .dot files |
 | `s` | Toggle sort by file size |
+| `S` | Toggle disk usage analyzer mode |
 | `t` | Toggle sort by modified time |
 | `!` | Spawn `SHELL` in `PWD` (fallback sh) |
 | `z` | Run `top` |
index 7fb03fc4c46dbb76d40272bd4b89474beeb548ba..2e51675840599adfc5239a5c9b84d1f5063f1200 100644 (file)
@@ -5,6 +5,7 @@
 
 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 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 showhidden  = 0; /* Set to 1 to show hidden files by default */
 static int showdetail  = 0; /* Set to show additional file info */
@@ -75,6 +76,8 @@ struct key bindings[] = {
        { 'D',            SEL_STATS,     "",     "" },
        /* Toggle sort by size */
        { 's',            SEL_FSIZE,     "",     "" },
+       /* Sort by total block size including dir contents */
+       { 'S',            SEL_BSIZE,    "",     "" },
        /* Toggle sort by time */
        { 't',            SEL_MTIME,     "",     "" },
        { CONTROL('L'),   SEL_REDRAW,    "",     "" },
diff --git a/nnn.1 b/nnn.1
index f6790365baf96d66f5a8587d725be8d427a08a78..a15513c4c24ded24fe1021a6faede6692aeab1ec 100644 (file)
--- a/nnn.1
+++ b/nnn.1
@@ -10,7 +10,7 @@
 .Op Ar dir
 .Sh DESCRIPTION
 .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
 .Nm
 defaults to the current directory if
@@ -54,6 +54,8 @@ Show details of selected file
 Toggle hide .dot files
 .It Ic s
 Toggle sort by file size
+.It Ic S
+Toggle disk usage analyzer mode
 .It Ic t
 Toggle sort by time modified
 .It Ic \&!
diff --git a/nnn.c b/nnn.c
index 387525f5634e7d17dc7651e64b5c23a0d34b34c0..5eec8d5ec027f76d99947b0698d6a5bc09b0699d 100644 (file)
--- a/nnn.c
+++ b/nnn.c
@@ -20,6 +20,9 @@
 #include <pwd.h>
 #include <grp.h>
 
+#define __USE_XOPEN_EXTENDED
+#include <ftw.h>
+
 #ifdef DEBUG
 static int
 xprintf(int fd, const char *fmt, ...)
@@ -82,6 +85,7 @@ enum action {
        SEL_DETAIL,
        SEL_STATS,
        SEL_FSIZE,
+       SEL_BSIZE,
        SEL_MTIME,
        SEL_REDRAW,
        SEL_COPY,
@@ -104,6 +108,7 @@ typedef struct entry {
        mode_t mode;
        time_t t;
        off_t size;
+       off_t bsize;
 } *pEntry;
 
 typedef unsigned long ulong;
@@ -422,9 +427,19 @@ entrycmp(const void *va, const void *vb)
        if (mtimeorder)
                return pb->t - pa->t;
 
-       if (sizeorder)
-               if (pb->size != pa->size)
-                       return pb->size - pa->size;
+       if (sizeorder) {
+               if (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);
 }
@@ -582,20 +597,25 @@ printent(struct entry *ent, int active)
 }
 
 static void (*printptr)(struct entry *ent, int active) = &printent;
+static const double div_2_pow_10 = 1.0 / 1024.0;
 
 static char*
 coolsize(off_t size)
 {
        static char size_buf[12]; /* Buffer to hold human readable size */
        int i = 0;
-       long double fsize = (double)size;
+       off_t fsize = size, tmp;
+       long double rem = 0;
 
        while (fsize > 1024) {
-               fsize /= 1024;
+               tmp = fsize;
+               //fsize *= div_2_pow_10;
+               fsize >>= 10;
+               rem = tmp - (fsize << 10);
                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;
 }
 
@@ -608,30 +628,57 @@ printent_long(struct entry *ent, int active)
        if (active)
                attron(A_REVERSE);
 
-       if (S_ISDIR(ent->mode))
-               printw("%s%-17.17s        /  %s/\n",
-                      CURSYM(active), buf, 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->size), ent->name);
-       else
-               printw("%s%-17.17s %8.8s  %s\n", CURSYM(active),
-                      buf, coolsize(ent->size), ent->name);
+       if (!bsizeorder) {
+               if (S_ISDIR(ent->mode))
+                       printw("%s%-17.17s        /  %s/\n",
+                              CURSYM(active), buf, 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->size), ent->name);
+               else
+                       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)
                attroff(A_REVERSE);
@@ -862,6 +909,7 @@ show_help(void)
     D                           Show details of selected file\n\
     .                           Toggle hide .dot files\n\
     s                           Toggle sort by file size\n\
+    S                           Toggle disk usage analyzer mode\n\
     t                           Toggle sort by modified time\n\
     !                           Spawn SHELL in PWD (fallback sh)\n\
     z                           Run top\n\
@@ -880,11 +928,30 @@ show_help(void)
                        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
 dentfill(char *path, struct entry **dents,
         int (*filter)(regex_t *, char *), regex_t *re)
 {
-       char newpath[PATH_MAX];
+       static char newpath[PATH_MAX];
        DIR *dirp;
        struct dirent *dp;
        struct stat sb;
@@ -911,6 +978,19 @@ dentfill(char *path, struct entry **dents,
                (*dents)[n].mode = sb.st_mode;
                (*dents)[n].t = sb.st_mtime;
                (*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++;
        }
 
@@ -1028,12 +1108,14 @@ redraw(char *path)
        if (showdetail) {
                if (ndents) {
                        static char ind[2] = "\0\0";
-                       static char sort[9];
+                       static char sort[17];
 
                        if (mtimeorder)
                                sprintf(sort, "by time ");
                        else if (sizeorder)
                                sprintf(sort, "by size ");
+                       else if (bsizeorder)
+                               sprintf(sort, "by content size ");
                        else
                                sort[0] = '\0';
 
@@ -1345,6 +1427,15 @@ nochange:
                case SEL_FSIZE:
                        sizeorder = !sizeorder;
                        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 */
                        if (ndents > 0)
                                mkpath(path, dents[cur].name, oldpath, sizeof(oldpath));
@@ -1352,6 +1443,7 @@ nochange:
                case SEL_MTIME:
                        mtimeorder = !mtimeorder;
                        sizeorder = 0;
+                       bsizeorder = 0;
                        /* Save current */
                        if (ndents > 0)
                                mkpath(path, dents[cur].name, oldpath, sizeof(oldpath));
@@ -1387,7 +1479,7 @@ nochange:
                        exitcurses();
                        spawn(run, NULL, path, 1);
                        initcurses();
-                       /* Re-populate as directory content may have changed */
+                       /* Repopulate as directory content may have changed */
                        goto begin;
                case SEL_RUNARG:
                        run = xgetenv(env, run);