mirror of
https://github.com/jarun/nnn.git
synced 2024-11-24 11:51:27 +00:00
Show file details
We closely follow the output for stat(1).
This commit is contained in:
parent
87e0891b8d
commit
f466ba543c
|
@ -54,6 +54,7 @@ I chose to fork because:
|
||||||
- current item in reverse video
|
- current item in reverse video
|
||||||
- number of items in current directory
|
- number of items in current directory
|
||||||
- full name of currently selected file
|
- full name of currently selected file
|
||||||
|
- Show details of the currently selected file
|
||||||
- Directories first
|
- Directories first
|
||||||
- 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
|
||||||
|
@ -120,6 +121,7 @@ Start nnn (default: current directory):
|
||||||
| `/`, `&` | filter dir contents |
|
| `/`, `&` | filter dir contents |
|
||||||
| `c` | show change dir prompt |
|
| `c` | show change dir prompt |
|
||||||
| `d` | toggle detail view |
|
| `d` | toggle detail view |
|
||||||
|
| `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 |
|
||||||
| `t` | toggle sort by modified time |
|
| `t` | toggle sort by modified time |
|
||||||
|
|
|
@ -66,6 +66,8 @@ struct key bindings[] = {
|
||||||
{ '.', SEL_TOGGLEDOT, "\0", "\0" },
|
{ '.', SEL_TOGGLEDOT, "\0", "\0" },
|
||||||
/* Detailed listing */
|
/* Detailed listing */
|
||||||
{ 'd', SEL_DETAIL, "\0", "\0" },
|
{ 'd', SEL_DETAIL, "\0", "\0" },
|
||||||
|
/* File details */
|
||||||
|
{ 'D', SEL_STATS, "\0", "\0" },
|
||||||
/* Toggle sort by size */
|
/* Toggle sort by size */
|
||||||
{ 's', SEL_FSIZE, "\0", "\0" },
|
{ 's', SEL_FSIZE, "\0", "\0" },
|
||||||
/* Toggle sort by time */
|
/* Toggle sort by time */
|
||||||
|
|
2
nnn.1
2
nnn.1
|
@ -46,6 +46,8 @@ Change filter (more information below)
|
||||||
Change into the given directory
|
Change into the given directory
|
||||||
.It Ic d
|
.It Ic d
|
||||||
Toggle detail view
|
Toggle detail view
|
||||||
|
.It Ic D
|
||||||
|
Show details of selected file
|
||||||
.It Ic \&.
|
.It Ic \&.
|
||||||
Toggle hide .dot files
|
Toggle hide .dot files
|
||||||
.It Ic s
|
.It Ic s
|
||||||
|
|
161
nnn.c
161
nnn.c
|
@ -17,6 +17,8 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <grp.h>
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
#define DEBUG_FD 8
|
#define DEBUG_FD 8
|
||||||
|
@ -62,6 +64,7 @@ enum action {
|
||||||
SEL_CDHOME,
|
SEL_CDHOME,
|
||||||
SEL_TOGGLEDOT,
|
SEL_TOGGLEDOT,
|
||||||
SEL_DETAIL,
|
SEL_DETAIL,
|
||||||
|
SEL_STATS,
|
||||||
SEL_FSIZE,
|
SEL_FSIZE,
|
||||||
SEL_MTIME,
|
SEL_MTIME,
|
||||||
SEL_REDRAW,
|
SEL_REDRAW,
|
||||||
|
@ -164,7 +167,7 @@ xstrlcpy(char *dest, const char *src, size_t n)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The poor man's implementation of memrchr().
|
* The poor man's implementation of memrchr(3).
|
||||||
* We are only looking for '/' in this program.
|
* We are only looking for '/' in this program.
|
||||||
*/
|
*/
|
||||||
static void *
|
static void *
|
||||||
|
@ -204,7 +207,7 @@ xdirname(const char *path)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The following dirname() implementation does not
|
* The following dirname(3) implementation does not
|
||||||
* change the input. We use a copy of the original.
|
* change the input. We use a copy of the original.
|
||||||
*
|
*
|
||||||
* Modified from the glibc (GNU LGPL) version.
|
* Modified from the glibc (GNU LGPL) version.
|
||||||
|
@ -594,10 +597,7 @@ static void
|
||||||
printent_long(struct entry *ent, int active)
|
printent_long(struct entry *ent, int active)
|
||||||
{
|
{
|
||||||
static char buf[18];
|
static char buf[18];
|
||||||
static const struct tm *p;
|
strftime(buf, 18, "%b %d %H:%M %Y", localtime(&ent->t));
|
||||||
|
|
||||||
p = localtime(&ent->t);
|
|
||||||
strftime(buf, 18, "%b %d %H:%M %Y", p);
|
|
||||||
|
|
||||||
if (active)
|
if (active)
|
||||||
attron(A_REVERSE);
|
attron(A_REVERSE);
|
||||||
|
@ -631,6 +631,140 @@ printent_long(struct entry *ent, int active)
|
||||||
attroff(A_REVERSE);
|
attroff(A_REVERSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char
|
||||||
|
get_fileind(mode_t mode, char *desc)
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
|
||||||
|
if (S_ISREG(mode)) {
|
||||||
|
c = '-';
|
||||||
|
sprintf(desc, "%s", "regular file");
|
||||||
|
} else if (S_ISDIR(mode)) {
|
||||||
|
c = 'd';
|
||||||
|
sprintf(desc, "%s", "directory");
|
||||||
|
} else if (S_ISBLK(mode)) {
|
||||||
|
c = 'b';
|
||||||
|
sprintf(desc, "%s", "block special device");
|
||||||
|
} else if (S_ISCHR(mode)) {
|
||||||
|
c = 'c';
|
||||||
|
sprintf(desc, "%s", "character special device");
|
||||||
|
#ifdef S_ISFIFO
|
||||||
|
} else if (S_ISFIFO(mode)) {
|
||||||
|
c = 'p';
|
||||||
|
sprintf(desc, "%s", "FIFO");
|
||||||
|
#endif /* S_ISFIFO */
|
||||||
|
#ifdef S_ISLNK
|
||||||
|
} else if (S_ISLNK(mode)) {
|
||||||
|
c = 'l';
|
||||||
|
sprintf(desc, "%s", "symbolic link");
|
||||||
|
#endif /* S_ISLNK */
|
||||||
|
#ifdef S_ISSOCK
|
||||||
|
} else if (S_ISSOCK(mode)) {
|
||||||
|
c = 's';
|
||||||
|
sprintf(desc, "%s", "socket");
|
||||||
|
#endif /* S_ISSOCK */
|
||||||
|
#ifdef S_ISDOOR
|
||||||
|
/* Solaris 2.6, etc. */
|
||||||
|
} else if (S_ISDOOR(mode)) {
|
||||||
|
c = 'D';
|
||||||
|
desc[0] = '\0';
|
||||||
|
#endif /* S_ISDOOR */
|
||||||
|
} else {
|
||||||
|
/* Unknown type -- possibly a regular file? */
|
||||||
|
c = '?';
|
||||||
|
desc[0] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert a mode field into "ls -l" type perms field. */
|
||||||
|
static char *
|
||||||
|
get_lsperms(mode_t mode, char *desc)
|
||||||
|
{
|
||||||
|
static const char *rwx[] = {"---", "--x", "-w-", "-wx",
|
||||||
|
"r--", "r-x", "rw-", "rwx"};
|
||||||
|
static char bits[11];
|
||||||
|
|
||||||
|
bits[0] = get_fileind(mode, desc);
|
||||||
|
strcpy(&bits[1], rwx[(mode >> 6) & 7]);
|
||||||
|
strcpy(&bits[4], rwx[(mode >> 3) & 7]);
|
||||||
|
strcpy(&bits[7], rwx[(mode & 7)]);
|
||||||
|
|
||||||
|
if (mode & S_ISUID)
|
||||||
|
bits[3] = (mode & S_IXUSR) ? 's' : 'S';
|
||||||
|
if (mode & S_ISGID)
|
||||||
|
bits[6] = (mode & S_IXGRP) ? 's' : 'l';
|
||||||
|
if (mode & S_ISVTX)
|
||||||
|
bits[9] = (mode & S_IXOTH) ? 't' : 'T';
|
||||||
|
|
||||||
|
bits[10] = '\0';
|
||||||
|
|
||||||
|
return(bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Follows the stat(1) output closely
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
show_stats(char* fpath, char* fname, struct stat *sb)
|
||||||
|
{
|
||||||
|
char buf[40];
|
||||||
|
char *perms = get_lsperms(sb->st_mode, buf);
|
||||||
|
|
||||||
|
clear();
|
||||||
|
|
||||||
|
/* Show file name or 'symlink' -> 'target' */
|
||||||
|
if (perms[0] == 'l') {
|
||||||
|
char symtgt[PATH_MAX];
|
||||||
|
ssize_t len = readlink(fpath, symtgt, PATH_MAX);
|
||||||
|
if (len == -1)
|
||||||
|
printerr(1, "readlink");
|
||||||
|
printw("\n\n File: '%s' -> '%s'", fname, symtgt);
|
||||||
|
} else
|
||||||
|
printw("\n\n File: '%s'", fname);
|
||||||
|
|
||||||
|
/* Show size, blocks, file type */
|
||||||
|
printw("\n Size: %-15llu Blocks: %-10llu IO Block: %-6llu %s",
|
||||||
|
sb->st_size, sb->st_blocks, sb->st_blksize, buf);
|
||||||
|
|
||||||
|
/* Show containing device, inode, hardlink count */
|
||||||
|
sprintf(buf, "%lxh/%lud", sb->st_dev, sb->st_dev);
|
||||||
|
printw("\n Device: %-15s Inode: %-11lu Links: %-9lu",
|
||||||
|
buf, sb->st_ino, sb->st_nlink);
|
||||||
|
|
||||||
|
/* Show major, minor number for block or char device */
|
||||||
|
if (perms[0] == 'b' || perms[0] == 'c')
|
||||||
|
printw(" Device type: %lx,%lx",
|
||||||
|
major(sb->st_rdev), minor(sb->st_rdev));
|
||||||
|
|
||||||
|
/* Show permissions, owner, group */
|
||||||
|
printw("\n Access: 0%d%d%d/%s Uid: (%lu/%s) Gid: (%lu/%s)",
|
||||||
|
(sb->st_mode >> 6) & 7, (sb->st_mode >> 3) & 7, sb->st_mode & 7,
|
||||||
|
perms,
|
||||||
|
sb->st_uid, (getpwuid(sb->st_uid))->pw_name,
|
||||||
|
sb->st_gid, (getgrgid(sb->st_gid))->gr_name);
|
||||||
|
|
||||||
|
/* Show last access time */
|
||||||
|
strftime(buf, 40, "%a %d-%b-%Y %T %z,%Z", localtime(&sb->st_atime));
|
||||||
|
printw("\n\n Access: %s", buf);
|
||||||
|
|
||||||
|
/* Show last modification time */
|
||||||
|
strftime(buf, 40, "%a %d-%b-%Y %T %z,%Z", localtime(&sb->st_mtime));
|
||||||
|
printw("\n Modify: %s", buf);
|
||||||
|
|
||||||
|
/* Show last status change time */
|
||||||
|
strftime(buf, 40, "%a %d-%b-%Y %T %z,%Z", localtime(&sb->st_ctime));
|
||||||
|
printw("\n Change: %s", buf);
|
||||||
|
|
||||||
|
/* Show exit keys */
|
||||||
|
printw("\n\n\n\n < (q/Esc)");
|
||||||
|
|
||||||
|
while (*buf = getch())
|
||||||
|
if (*buf == 'q' || *buf == 27)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
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)
|
||||||
|
@ -1036,6 +1170,21 @@ nochange:
|
||||||
if (ndents > 0)
|
if (ndents > 0)
|
||||||
mkpath(path, dents[cur].name, oldpath, sizeof(oldpath));
|
mkpath(path, dents[cur].name, oldpath, sizeof(oldpath));
|
||||||
goto begin;
|
goto begin;
|
||||||
|
case SEL_STATS:
|
||||||
|
{
|
||||||
|
struct stat sb;
|
||||||
|
|
||||||
|
if (ndents > 0)
|
||||||
|
mkpath(path, dents[cur].name, oldpath, sizeof(oldpath));
|
||||||
|
|
||||||
|
r = lstat(oldpath, &sb);
|
||||||
|
if (r == -1)
|
||||||
|
printerr(1, "lstat");
|
||||||
|
else
|
||||||
|
show_stats(oldpath, dents[cur].name, &sb);
|
||||||
|
|
||||||
|
goto begin;
|
||||||
|
}
|
||||||
case SEL_FSIZE:
|
case SEL_FSIZE:
|
||||||
sizeorder = !sizeorder;
|
sizeorder = !sizeorder;
|
||||||
mtimeorder = 0;
|
mtimeorder = 0;
|
||||||
|
|
Loading…
Reference in a new issue