"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/nnn.c" between
nnn-v4.3.tar.gz and nnn-v4.4.tar.gz

About: nnn is a full-featured terminal file manager.

nnn.c  (nnn-v4.3):nnn.c  (nnn-v4.4)
skipping to change at line 137 skipping to change at line 137
#if defined(ICONS) || defined(NERD) #if defined(ICONS) || defined(NERD)
#include "icons.h" #include "icons.h"
#define ICONS_ENABLED #define ICONS_ENABLED
#endif #endif
#ifdef TOURBIN_QSORT #ifdef TOURBIN_QSORT
#include "qsort.h" #include "qsort.h"
#endif #endif
/* Macro definitions */ /* Macro definitions */
#define VERSION "4.3" #define VERSION "4.4"
#define GENERAL_INFO "BSD 2-Clause\nhttps://github.com/jarun/nnn" #define GENERAL_INFO "BSD 2-Clause\nhttps://github.com/jarun/nnn"
#ifndef NOSSN #ifndef NOSSN
#define SESSIONS_VERSION 1 #define SESSIONS_VERSION 1
#endif #endif
#ifndef S_BLKSIZE #ifndef S_BLKSIZE
#define S_BLKSIZE 512 /* S_BLKSIZE is missing on Android NDK (Termux) */ #define S_BLKSIZE 512 /* S_BLKSIZE is missing on Android NDK (Termux) */
#endif #endif
skipping to change at line 170 skipping to change at line 170
#define _ABSSUB(N, M) (((N) <= (M)) ? ((M) - (N)) : ((N) - (M))) #define _ABSSUB(N, M) (((N) <= (M)) ? ((M) - (N)) : ((N) - (M)))
#define ELEMENTS(x) (sizeof(x) / sizeof(*(x))) #define ELEMENTS(x) (sizeof(x) / sizeof(*(x)))
#undef MIN #undef MIN
#define MIN(x, y) ((x) < (y) ? (x) : (y)) #define MIN(x, y) ((x) < (y) ? (x) : (y))
#undef MAX #undef MAX
#define MAX(x, y) ((x) > (y) ? (x) : (y)) #define MAX(x, y) ((x) > (y) ? (x) : (y))
#define ISODD(x) ((x) & 1) #define ISODD(x) ((x) & 1)
#define ISBLANK(x) ((x) == ' ' || (x) == '\t') #define ISBLANK(x) ((x) == ' ' || (x) == '\t')
#define TOUPPER(ch) (((ch) >= 'a' && (ch) <= 'z') ? ((ch) - 'a' + 'A') : (ch )) #define TOUPPER(ch) (((ch) >= 'a' && (ch) <= 'z') ? ((ch) - 'a' + 'A') : (ch ))
#define TOLOWER(ch) (((ch) >= 'A' && (ch) <= 'Z') ? ((ch) - 'A' + 'a') : (ch )) #define TOLOWER(ch) (((ch) >= 'A' && (ch) <= 'Z') ? ((ch) - 'A' + 'a') : (ch ))
#define ISUPPER_(ch) ((ch) >= 'A' && (ch) <= 'Z') #define ISUPPER_(ch) ((ch) >= 'A' && (ch) <= 'Z')
#define ISLOWER_(ch) ((ch) >= 'a' && (ch) <= 'z') #define ISLOWER_(ch) ((ch) >= 'a' && (ch) <= 'z')
#define CMD_LEN_MAX (PATH_MAX + ((NAME_MAX + 1) << 1)) #define CMD_LEN_MAX (PATH_MAX + ((NAME_MAX + 1) << 1))
#define ALIGN_UP(x, A) ((((x) + (A) - 1) / (A)) * (A)) #define ALIGN_UP(x, A) ((((x) + (A) - 1) / (A)) * (A))
#define READLINE_MAX 256 #define READLINE_MAX 256
#define FILTER '/' #define FILTER '/'
#define RFILTER '\\' #define RFILTER '\\'
#define CASE ':' #define CASE ':'
#define MSGWAIT '$' #define MSGWAIT '$'
#define SELECT ' ' #define SELECT ' '
#define PROMPT ">>> " #define PROMPT ">>> "
#define REGEX_MAX 48 #define REGEX_MAX 48
skipping to change at line 205 skipping to change at line 205
/* Time intervals */ /* Time intervals */
#define DBLCLK_INTERVAL_NS (400000000) #define DBLCLK_INTERVAL_NS (400000000)
#define XDELAY_INTERVAL_MS (350000) /* 350 ms delay */ #define XDELAY_INTERVAL_MS (350000) /* 350 ms delay */
#ifndef CTX8 #ifndef CTX8
#define CTX_MAX 4 #define CTX_MAX 4
#else #else
#define CTX_MAX 8 #define CTX_MAX 8
#endif #endif
#ifdef __APPLE__ /* BSDs or Solaris or SunOS */
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defin
ed(__APPLE__) || defined(sun) || defined(__sun)
#define SED "gsed" #define SED "gsed"
#else #else
#define SED "sed" #define SED "sed"
#endif #endif
/* Large selection threshold */ /* Large selection threshold */
#ifndef LARGESEL #ifndef LARGESEL
#define LARGESEL 1000 #define LARGESEL 1000
#endif #endif
skipping to change at line 332 skipping to change at line 333
uint_t showhidden : 1; /* Set to show hidden files */ uint_t showhidden : 1; /* Set to show hidden files */
uint_t reserved0 : 1; uint_t reserved0 : 1;
uint_t showdetail : 1; /* Clear to show lesser file info */ uint_t showdetail : 1; /* Clear to show lesser file info */
uint_t ctxactive : 1; /* Context active or not */ uint_t ctxactive : 1; /* Context active or not */
uint_t reverse : 1; /* Reverse sort */ uint_t reverse : 1; /* Reverse sort */
uint_t version : 1; /* Version sort */ uint_t version : 1; /* Version sort */
uint_t reserved1 : 1; uint_t reserved1 : 1;
/* The following settings are global */ /* The following settings are global */
uint_t curctx : 3; /* Current context number */ uint_t curctx : 3; /* Current context number */
uint_t prefersel : 1; /* Prefer selection over current, if exists */ uint_t prefersel : 1; /* Prefer selection over current, if exists */
uint_t reserved2 : 1; uint_t fileinfo : 1; /* Show file information on hover */
uint_t nonavopen : 1; /* Open file on right arrow or `l` */ uint_t nonavopen : 1; /* Open file on right arrow or `l` */
uint_t autoselect : 1; /* Auto-select dir in type-to-nav mode */ uint_t autoselect : 1; /* Auto-select dir in type-to-nav mode */
uint_t cursormode : 1; /* Move hardware cursor with selection */ uint_t reserved2 : 1;
uint_t useeditor : 1; /* Use VISUAL to open text files */ uint_t useeditor : 1; /* Use VISUAL to open text files */
uint_t reserved3 : 3; uint_t reserved3 : 3;
uint_t regex : 1; /* Use regex filters */ uint_t regex : 1; /* Use regex filters */
uint_t x11 : 1; /* Copy to system clipboard, show notis, xterm ti tle */ uint_t x11 : 1; /* Copy to system clipboard, show notis, xterm ti tle */
uint_t timetype : 2; /* Time sort type (0: access, 1: change, 2: modif ication) */ uint_t timetype : 2; /* Time sort type (0: access, 1: change, 2: modif ication) */
uint_t cliopener : 1; /* All-CLI app opener */ uint_t cliopener : 1; /* All-CLI app opener */
uint_t waitedit : 1; /* For ops that can't be detached, used EDITOR */ uint_t waitedit : 1; /* For ops that can't be detached, used EDITOR */
uint_t rollover : 1; /* Roll over at edges */ uint_t rollover : 1; /* Roll over at edges */
} settings; } settings;
skipping to change at line 368 skipping to change at line 369
uint_t oldcolor : 1; /* Use older colorscheme */ uint_t oldcolor : 1; /* Use older colorscheme */
uint_t picked : 1; /* Plugin has picked files */ uint_t picked : 1; /* Plugin has picked files */
uint_t picker : 1; /* Write selection to user-specified file */ uint_t picker : 1; /* Write selection to user-specified file */
uint_t pluginit : 1; /* Plugin framework initialized */ uint_t pluginit : 1; /* Plugin framework initialized */
uint_t prstssn : 1; /* Persistent session */ uint_t prstssn : 1; /* Persistent session */
uint_t rangesel : 1; /* Range selection on */ uint_t rangesel : 1; /* Range selection on */
uint_t runctx : 3; /* The context in which plugin is to be run */ uint_t runctx : 3; /* The context in which plugin is to be run */
uint_t runplugin : 1; /* Choose plugin mode */ uint_t runplugin : 1; /* Choose plugin mode */
uint_t selmode : 1; /* Set when selecting files */ uint_t selmode : 1; /* Set when selecting files */
uint_t stayonsel : 1; /* Disable auto-proceed on select */ uint_t stayonsel : 1; /* Disable auto-proceed on select */
uint_t trash : 2; /* Use trash to delete files 1: trash-cli, 2: gio trash */ uint_t trash : 2; /* Trash method 0: rm -rf, 1: trash-cli, 2: gio t rash */
uint_t uidgid : 1; /* Show owner and group info */ uint_t uidgid : 1; /* Show owner and group info */
uint_t reserved : 7; /* Adjust when adding/removing a field */ uint_t reserved : 7; /* Adjust when adding/removing a field */
} runstate; } runstate;
/* Contexts or workspaces */ /* Contexts or workspaces */
typedef struct { typedef struct {
char c_path[PATH_MAX]; /* Current dir */ char c_path[PATH_MAX]; /* Current dir */
char c_last[PATH_MAX]; /* Last visited dir */ char c_last[PATH_MAX]; /* Last visited dir */
char c_name[NAME_MAX + 1]; /* Current file name */ char c_name[NAME_MAX + 1]; /* Current file name */
char c_fltr[REGEX_MAX]; /* Current filter */ char c_fltr[REGEX_MAX]; /* Current filter */
skipping to change at line 412 skipping to change at line 413
0, /* extnorder */ 0, /* extnorder */
0, /* showhidden */ 0, /* showhidden */
0, /* reserved0 */ 0, /* reserved0 */
0, /* showdetail */ 0, /* showdetail */
1, /* ctxactive */ 1, /* ctxactive */
0, /* reverse */ 0, /* reverse */
0, /* version */ 0, /* version */
0, /* reserved1 */ 0, /* reserved1 */
0, /* curctx */ 0, /* curctx */
0, /* prefersel */ 0, /* prefersel */
0, /* reserved2 */ 0, /* fileinfo */
0, /* nonavopen */ 0, /* nonavopen */
1, /* autoselect */ 1, /* autoselect */
0, /* cursormode */ 0, /* reserved2 */
0, /* useeditor */ 0, /* useeditor */
0, /* reserved3 */ 0, /* reserved3 */
0, /* regex */ 0, /* regex */
0, /* x11 */ 0, /* x11 */
2, /* timetype (T_MOD) */ 2, /* timetype (T_MOD) */
0, /* cliopener */ 0, /* cliopener */
0, /* waitedit */ 0, /* waitedit */
1, /* rollover */ 1, /* rollover */
}; };
skipping to change at line 850 skipping to change at line 851
#define ENTSORT(pdents, ndents, entrycmpfn) qsort((pdents), (ndents), sizeof(*(p dents)), (entrycmpfn)) #define ENTSORT(pdents, ndents, entrycmpfn) qsort((pdents), (ndents), sizeof(*(p dents)), (entrycmpfn))
#endif #endif
/* Forward declarations */ /* Forward declarations */
static void redraw(char *path); static void redraw(char *path);
static int spawn(char *file, char *arg1, char *arg2, char *arg3, ushort_t flag); static int spawn(char *file, char *arg1, char *arg2, char *arg3, ushort_t flag);
static void move_cursor(int target, int ignore_scrolloff); static void move_cursor(int target, int ignore_scrolloff);
static char *load_input(int fd, const char *path); static char *load_input(int fd, const char *path);
static int set_sort_flags(int r); static int set_sort_flags(int r);
static void statusbar(char *path); static void statusbar(char *path);
static bool get_output(char *file, char *arg1, char *arg2, int fdout, bool multi , bool page);
#ifndef NOFIFO #ifndef NOFIFO
static void notify_fifo(bool force); static void notify_fifo(bool force);
#endif #endif
/* Functions */ /* Functions */
static void sigint_handler(int sig) static void sigint_handler(int sig)
{ {
(void) sig; (void) sig;
g_state.interrupt = 1; g_state.interrupt = 1;
skipping to change at line 1018 skipping to change at line 1020
size_t lenstr = xstrlen(str); size_t lenstr = xstrlen(str);
size_t lensuffix = xstrlen(suffix); size_t lensuffix = xstrlen(suffix);
if (lensuffix > lenstr) if (lensuffix > lenstr)
return FALSE; return FALSE;
return (xstrcmp(str + (lenstr - lensuffix), suffix) == 0); return (xstrcmp(str + (lenstr - lensuffix), suffix) == 0);
} }
static bool is_prefix(const char *restrict str, const char *restrict prefix, siz e_t len) static inline bool is_prefix(const char *restrict str, const char *restrict pref ix, size_t len)
{ {
return !strncmp(str, prefix, len); return !strncmp(str, prefix, len);
} }
/* /*
* The poor man's implementation of memrchr(3). * The poor man's implementation of memrchr(3).
* We are only looking for '/' in this program. * We are only looking for '/' in this program.
* And we are NOT expecting a '/' at the end. * And we are NOT expecting a '/' at the end.
* Ideally 0 < n <= xstrlen(s). * Ideally 0 < n <= xstrlen(s).
*/ */
skipping to change at line 1270 skipping to change at line 1272
return FALSE; return FALSE;
} }
static void reset_tilde_in_path(char *path) static void reset_tilde_in_path(char *path)
{ {
path[homelen - 1] = home[homelen]; path[homelen - 1] = home[homelen];
home[homelen] = '\0'; home[homelen] = '\0';
} }
#ifndef NOX11
static void xterm_cfg(char *path)
{
if (cfg.x11 && !g_state.picker) {
/* Signal CWD change to terminal */
printf("\033]7;file://%s%s\033\\", hostname, path);
/* Set terminal window title */
bool r = set_tilde_in_path(path);
printf("\033]2;%s\007", r ? &path[homelen - 1] : path);
fflush(stdout);
if (r)
reset_tilde_in_path(path);
}
}
#endif
static void convert_tilde(const char *path, char *buf) static void convert_tilde(const char *path, char *buf)
{ {
if (path[0] == '~') { if (path[0] == '~') {
ssize_t len = xstrlen(home); ssize_t len = xstrlen(home);
ssize_t loclen = xstrlen(path); ssize_t loclen = xstrlen(path);
xstrsncpy(buf, home, len + 1); xstrsncpy(buf, home, len + 1);
xstrsncpy(buf + len, path + 1, loclen); xstrsncpy(buf + len, path + 1, loclen);
} }
} }
skipping to change at line 1299 skipping to change at line 1320
} }
return fd; return fd;
} }
static void msg(const char *message) static void msg(const char *message)
{ {
dprintf(STDERR_FILENO, "%s\n", message); dprintf(STDERR_FILENO, "%s\n", message);
} }
static void clearinfoln(void)
{
move(xlines - 2, 0);
clrtoeol();
}
#ifdef KEY_RESIZE #ifdef KEY_RESIZE
static void handle_key_resize() static void handle_key_resize()
{ {
endwin(); endwin();
refresh(); refresh();
} }
/* Clear the old prompt */ /* Clear the old prompt */
static void clearoldprompt(void) static void clearoldprompt(void)
{ {
clearinfoln(); // clear info line
move(xlines - 2, 0);
clrtoeol();
tolastln(); tolastln();
clrtoeol(); clrtoeol();
handle_key_resize(); handle_key_resize();
} }
#endif #endif
/* Messages show up at the bottom */ /* Messages show up at the bottom */
static inline void printmsg_nc(const char *msg) static inline void printmsg_nc(const char *msg)
{ {
tolastln(); tolastln();
skipping to change at line 3158 skipping to change at line 3176
{ {
int i = 0; int i = 0;
char info[REGEX_MAX] = "\0\0\0\0\0"; char info[REGEX_MAX] = "\0\0\0\0\0";
i = getorderstr(info); i = getorderstr(info);
snprintf(info + i, REGEX_MAX - i - 1, " %s [/], %s [:]", snprintf(info + i, REGEX_MAX - i - 1, " %s [/], %s [:]",
(cfg.regex ? "reg" : "str"), (cfg.regex ? "reg" : "str"),
((fnstrstr == &strcasestr) ? "ic" : "noic")); ((fnstrstr == &strcasestr) ? "ic" : "noic"));
clearinfoln(); if (cfg.fileinfo && ndents && get_output("file", "-b", pdents[cur].name,
-1, FALSE, FALSE))
mvaddstr(xlines - 2, 2, g_buf);
mvaddstr(xlines - 2, xcols - xstrlen(info), info); mvaddstr(xlines - 2, xcols - xstrlen(info), info);
} }
static void showfilter(char *str) static void showfilter(char *str)
{ {
attron(COLOR_PAIR(cfg.curctx + 1)); attron(COLOR_PAIR(cfg.curctx + 1));
showfilterinfo(); showfilterinfo();
printmsg(str); printmsg(str);
// printmsg calls attroff() // printmsg calls attroff()
} }
skipping to change at line 3440 skipping to change at line 3460
* redraw() should be above the auto-select optimization, for * redraw() should be above the auto-select optimization, for
* the case where there's an issue with dir auto-select, say, * the case where there's an issue with dir auto-select, say,
* due to a permission problem. The transition is _jumpy_ in * due to a permission problem. The transition is _jumpy_ in
* case of such an error. However, we optimize for successful * case of such an error. However, we optimize for successful
* cases where the dir has permissions. This skips a redraw(). * cases where the dir has permissions. This skips a redraw().
*/ */
redraw(path); redraw(path);
showfilter(ln); showfilter(ln);
} }
end: end:
clearinfoln();
/* Save last working filter in-filter */ /* Save last working filter in-filter */
if (ln[1]) if (ln[1])
ln[REGEX_MAX - 1] = ln[1]; ln[REGEX_MAX - 1] = ln[1];
/* Save current */ /* Save current */
copycurname(); copycurname();
curs_set(FALSE); curs_set(FALSE);
settimeout(); settimeout();
skipping to change at line 3488 skipping to change at line 3507
buf[0] = '\0'; buf[0] = '\0';
len = pos = 0; len = pos = 0;
} }
x = getcurx(stdscr); x = getcurx(stdscr);
curs_set(TRUE); curs_set(TRUE);
while (1) { while (1) {
buf[len] = ' '; buf[len] = ' ';
attron(COLOR_PAIR(cfg.curctx + 1)); attron(COLOR_PAIR(cfg.curctx + 1));
mvaddnwstr(xlines - 1, x, buf, len + 1); if (pos > (size_t)(xcols - x)) {
move(xlines - 1, x + wcswidth(buf, pos)); mvaddnwstr(xlines - 1, x, buf + (pos - (xcols - x) + 1),
xcols - x);
move(xlines - 1, xcols - 1);
} else {
mvaddnwstr(xlines - 1, x, buf, len + 1);
move(xlines - 1, x + wcswidth(buf, pos));
}
attroff(COLOR_PAIR(cfg.curctx + 1)); attroff(COLOR_PAIR(cfg.curctx + 1));
r = get_wch(ch); r = get_wch(ch);
if (r == ERR) if (r == ERR)
continue; continue;
if (r == OK) { if (r == OK) {
switch (*ch) { switch (*ch) {
case KEY_ENTER: // fallthrough case KEY_ENTER: // fallthrough
case '\n': // fallthrough case '\n': // fallthrough
skipping to change at line 3689 skipping to change at line 3713
choice = get_cur_or_sel(); choice = get_cur_or_sel();
if (!choice) if (!choice)
return -1; return -1;
if (type == 's') /* symbolic link */ if (type == 's') /* symbolic link */
link_fn = &symlink; link_fn = &symlink;
else /* hard link */ else /* hard link */
link_fn = &link; link_fn = &link;
if (choice == 'c') { if (choice == 'c' || (nselected == 1)) {
r = xstrsncpy(buf, prefix, NAME_MAX + 1); /* Copy prefix */ mkpath(path, prefix, lnpath); /* Generate link path */
xstrsncpy(buf + r - 1, curfname, NAME_MAX - r); /* Suffix target mkpath(path, (choice == 'c') ? curfname : pselbuf, buf); /* Gener
file name */ ate target file path */
mkpath(path, buf, lnpath); /* Generate link path */
mkpath(path, curfname, buf); /* Generate target file path */
if (!link_fn(buf, lnpath)) if (!link_fn(buf, lnpath)) {
if (choice == 's')
clearselection();
return 1; /* One link created */ return 1; /* One link created */
}
printwarn(presel); printwarn(presel);
return -1; return -1;
} }
while (pos < selbufpos) { while (pos < selbufpos) {
len = xstrlen(psel); len = xstrlen(psel);
fname = xbasename(psel); fname = xbasename(psel);
r = xstrsncpy(buf, prefix, NAME_MAX + 1); /* Copy prefix */ r = xstrsncpy(buf, prefix, NAME_MAX + 1); /* Copy prefix */
skipping to change at line 5352 skipping to change at line 5377
if (tmp && *tmp) // NOLINT if (tmp && *tmp) // NOLINT
spawn(tmp, (r == F_NORMAL) ? "0" : NULL, NULL, NULL, r); spawn(tmp, (r == F_NORMAL) ? "0" : NULL, NULL, NULL, r);
return FALSE; return FALSE;
} }
/* Returns TRUE if at least one command was run */ /* Returns TRUE if at least one command was run */
static bool prompt_run(void) static bool prompt_run(void)
{ {
bool ret = FALSE; bool ret = FALSE;
char *tmp; char *cmdline, *next;
int cnt_j, cnt_J;
size_t len;
const char *xargs_j = "xargs -0 -I{} %s < %s";
const char *xargs_J = "xargs -0 %s < %s";
char cmd[CMD_LEN_MAX + 32]; // 32 for xargs format strings
while (1) { while (1) {
#ifndef NORL #ifndef NORL
if (g_state.picker) { if (g_state.picker) {
#endif #endif
tmp = xreadline(NULL, PROMPT); cmdline = xreadline(NULL, PROMPT);
#ifndef NORL #ifndef NORL
} else } else
tmp = getreadline("\n"PROMPT); cmdline = getreadline("\n"PROMPT);
#endif #endif
if (tmp && *tmp) { // NOLINT // Check for an empty command
free(lastcmd); if (!cmdline || !cmdline[0])
lastcmd = xstrdup(tmp);
ret = TRUE;
spawn(shell, "-c", tmp, NULL, F_CLI | F_CONFIRM);
} else
break; break;
free(lastcmd);
lastcmd = xstrdup(cmdline);
ret = TRUE;
len = xstrlen(cmdline);
cnt_j = 0;
next = cmdline;
while ((next = strstr(next, "%j"))) {
++cnt_j;
// replace %j with {} for xargs later
next[0] = '{';
next[1] = '}';
++next;
}
cnt_J = 0;
next = cmdline;
while ((next = strstr(next, "%J"))) {
++cnt_J;
// %J should be the last thing in the command
if (next == cmdline + len - 2) {
cmdline[len - 2] = '\0';
}
++next;
}
// We can't handle both %j and %J in a single command
if (cnt_j && cnt_J)
break;
if (cnt_j)
snprintf(cmd, CMD_LEN_MAX + 32, xargs_j, cmdline, selpath
);
else if (cnt_J)
snprintf(cmd, CMD_LEN_MAX + 32, xargs_J, cmdline, selpath
);
spawn(shell, "-c", (cnt_j || cnt_J) ? cmd : cmdline, NULL, F_CLI
| F_CONFIRM);
} }
return ret; return ret;
} }
static bool handle_cmd(enum action sel, char *newpath) static bool handle_cmd(enum action sel, char *newpath)
{ {
endselection(FALSE); endselection(FALSE);
if (sel == SEL_LAUNCH) if (sel == SEL_LAUNCH)
skipping to change at line 5420 skipping to change at line 5489
{ {
thread_data *pdata = (thread_data *)p_data; thread_data *pdata = (thread_data *)p_data;
char *path[2] = {pdata->path, NULL}; char *path[2] = {pdata->path, NULL};
ullong_t tfiles = 0; ullong_t tfiles = 0;
blkcnt_t tblocks = 0; blkcnt_t tblocks = 0;
struct stat *sb; struct stat *sb;
FTS *tree = fts_open(path, FTS_PHYSICAL | FTS_XDEV | FTS_NOCHDIR, 0); FTS *tree = fts_open(path, FTS_PHYSICAL | FTS_XDEV | FTS_NOCHDIR, 0);
FTSENT *node; FTSENT *node;
while ((node = fts_read(tree))) { while ((node = fts_read(tree))) {
if (node->fts_info & FTS_D) if (node->fts_info & FTS_D) {
if (g_state.interrupt)
break;
continue; continue;
}
sb = node->fts_statp; sb = node->fts_statp;
if (cfg.apparentsz) { if (cfg.apparentsz) {
if (sb->st_size && DU_TEST) if (sb->st_size && DU_TEST)
tblocks += sb->st_size; tblocks += sb->st_size;
} else if (sb->st_blocks && DU_TEST) } else if (sb->st_blocks && DU_TEST)
tblocks += sb->st_blocks; tblocks += sb->st_blocks;
++tfiles; ++tfiles;
skipping to change at line 5832 skipping to change at line 5904
size_t len = mkpath(g_ctx[cfg.curctx].c_path, ndents ? pdents[cur].name : "", path); size_t len = mkpath(g_ctx[cfg.curctx].c_path, ndents ? pdents[cur].name : "", path);
path[len - 1] = '\n'; path[len - 1] = '\n';
ssize_t ret = write(fifofd, path, len); ssize_t ret = write(fifofd, path, len);
if (ret != (ssize_t)len && !(ret == -1 && (errno == EAGAIN || errno == EP IPE))) { if (ret != (ssize_t)len && !(ret == -1 && (errno == EAGAIN || errno == EP IPE))) {
DPRINTF_S(strerror(errno)); DPRINTF_S(strerror(errno));
} }
} }
static void send_to_explorer(int *presel)
{
if (nselected) {
int fd = open(fifopath, O_WRONLY|O_NONBLOCK|O_CLOEXEC, 0600);
if ((fd == -1) || (seltofile(fd, NULL) != (size_t)(selbufpos)))
printwarn(presel);
else {
resetselind();
clearselection();
}
if (fd > 1)
close(fd);
} else
notify_fifo(TRUE); /* Send opened path to NNN_FIFO */
}
#endif #endif
static void move_cursor(int target, int ignore_scrolloff) static void move_cursor(int target, int ignore_scrolloff)
{ {
int onscreen = xlines - 4; /* Leave top 2 and bottom 2 lines */ int onscreen = xlines - 4; /* Leave top 2 and bottom 2 lines */
target = MAX(0, MIN(ndents - 1, target)); target = MAX(0, MIN(ndents - 1, target));
last_curscroll = curscroll; last_curscroll = curscroll;
last = cur; last = cur;
cur = target; cur = target;
skipping to change at line 6170 skipping to change at line 6258
if (S_ISREG(pent->mode)) { if (S_ISREG(pent->mode)) {
i = (int)(pent->nlen - 1); i = (int)(pent->nlen - 1);
ptr = xextension(pent->name, i); ptr = xextension(pent->name, i);
if (ptr) if (ptr)
len = i - (ptr - pent->name); len = i - (ptr - pent->name);
if (!ptr || len > 5 || len < 2) if (!ptr || len > 5 || len < 2)
ptr = "\b"; ptr = "\b";
} else } else
ptr = "\b"; ptr = "\b";
tolastln();
attron(COLOR_PAIR(cfg.curctx + 1)); attron(COLOR_PAIR(cfg.curctx + 1));
if (cfg.fileinfo && get_output("file", "-b", pdents[cur].name, -1, FALSE,
FALSE))
mvaddstr(xlines - 2, 2, g_buf);
tolastln();
printw("%d/%s ", cur + 1, xitoa(ndents)); printw("%d/%s ", cur + 1, xitoa(ndents));
if (g_state.selmode || nselected) { if (g_state.selmode || nselected) {
attron(A_REVERSE); attron(A_REVERSE);
addch(' '); addch(' ');
if (g_state.rangesel) if (g_state.rangesel)
addch('*'); addch('*');
else if (g_state.selmode) else if (g_state.selmode)
addch('+'); addch('+');
if (nselected) if (nselected)
skipping to change at line 6218 skipping to change at line 6310
addch(' '); addch(' ');
#ifndef NOUG #ifndef NOUG
if (g_state.uidgid) { if (g_state.uidgid) {
addstr(getpwname(pent->uid)); addstr(getpwname(pent->uid));
addch(':'); addch(':');
addstr(getgrname(pent->gid)); addstr(getgrname(pent->gid));
addch(' '); addch(' ');
} }
#endif #endif
if (S_ISLNK(pent->mode)) { if (S_ISLNK(pent->mode)) {
i = readlink(pent->name, g_buf, PATH_MAX); if (!cfg.fileinfo) {
addstr(coolsize(i >= 0 ? i : pent->size)); /* Show symlin i = readlink(pent->name, g_buf, PATH_MAX);
k size */ addstr(coolsize(i >= 0 ? i : pent->size)); /* Sho
if (i > 1) { /* Show symlink target */ w symlink size */
int y; if (i > 1) { /* Show symlink target */
int y;
addstr(" ->");
getyx(stdscr, len, y); addstr(" ->");
i = MIN(i, xcols - y); getyx(stdscr, len, y);
g_buf[i] = '\0'; i = MIN(i, xcols - y);
addstr(g_buf); g_buf[i] = '\0';
addstr(g_buf);
}
} }
} else { } else {
addstr(coolsize(pent->size)); addstr(coolsize(pent->size));
addch(' '); addch(' ');
addstr(ptr); addstr(ptr);
if (pent->flags & HARD_LINK) { if (pent->flags & HARD_LINK) {
struct stat sb; struct stat sb;
if (stat(pent->name, &sb) != -1) { if (stat(pent->name, &sb) != -1) {
addch(' '); addch(' ');
addstr(xitoa((int)sb.st_nlink)); /* Show number of links */ addstr(xitoa((int)sb.st_nlink)); /* Show number of links */
addch('-'); addch('-');
addstr(xitoa((int)sb.st_ino)); /* Show in ode number */ addstr(xitoa((int)sb.st_ino)); /* Show in ode number */
} }
} }
} }
clrtoeol(); clrtoeol();
} }
attroff(COLOR_PAIR(cfg.curctx + 1)); attroff(COLOR_PAIR(cfg.curctx + 1));
/* Plase HW cursor on current for Braille systems */
if (cfg.cursormode) tocursor();
tocursor();
} }
static inline void markhovered(void) static inline void markhovered(void)
{ {
if (cfg.showdetail && ndents) { /* Reversed block for hovered entry */ if (cfg.showdetail && ndents) { /* Reversed block for hovered entry */
tocursor(); tocursor();
#ifdef ICONS_ENABLED #ifdef ICONS_ENABLED
addstr(MD_ARROW_FORWARD); addstr(MD_ARROW_FORWARD);
#else #else
addch(' ' | A_REVERSE); addch(' ' | A_REVERSE);
skipping to change at line 6482 skipping to change at line 6575
{ {
char newpath[PATH_MAX] __attribute__ ((aligned)), char newpath[PATH_MAX] __attribute__ ((aligned)),
rundir[PATH_MAX] __attribute__ ((aligned)), rundir[PATH_MAX] __attribute__ ((aligned)),
runfile[NAME_MAX + 1] __attribute__ ((aligned)); runfile[NAME_MAX + 1] __attribute__ ((aligned));
char *path, *lastdir, *lastname, *dir, *tmp; char *path, *lastdir, *lastname, *dir, *tmp;
pEntry pent; pEntry pent;
enum action sel; enum action sel;
struct stat sb; struct stat sb;
int r = -1, presel, selstartid = 0, selendid = 0; int r = -1, presel, selstartid = 0, selendid = 0;
const uchar_t opener_flags = (cfg.cliopener ? F_CLI : (F_NOTRACE | F_NOST DIN | F_NOWAIT)); const uchar_t opener_flags = (cfg.cliopener ? F_CLI : (F_NOTRACE | F_NOST DIN | F_NOWAIT));
bool watch = FALSE; bool watch = FALSE, cd = TRUE;
ino_t inode = 0; ino_t inode = 0;
#ifndef NOMOUSE #ifndef NOMOUSE
MEVENT event = {0}; MEVENT event = {0};
struct timespec mousetimings[2] = {{.tv_sec = 0, .tv_nsec = 0}, {.tv_sec = 0, .tv_nsec = 0} }; struct timespec mousetimings[2] = {{.tv_sec = 0, .tv_nsec = 0}, {.tv_sec = 0, .tv_nsec = 0} };
int mousedent[2] = {-1, -1}; int mousedent[2] = {-1, -1};
bool currentmouse = 1, rightclicksel = 0; bool currentmouse = 1, rightclicksel = 0;
#endif #endif
atexit(dentfree); atexit(dentfree);
skipping to change at line 6555 skipping to change at line 6648
* Can fail when permissions change while browsing. * Can fail when permissions change while browsing.
* It's assumed that path IS a directory when we are here. * It's assumed that path IS a directory when we are here.
*/ */
if (chdir(path) == -1) { if (chdir(path) == -1) {
DPRINTF_S("directory inaccessible"); DPRINTF_S("directory inaccessible");
valid_parent(path, lastname); valid_parent(path, lastname);
setdirwatch(); setdirwatch();
} }
#ifndef NOX11 #ifndef NOX11
if (cfg.x11 && !g_state.picker) { xterm_cfg(path);
/* Signal CWD change to terminal */
printf("\033]7;file://%s%s\033\\", hostname, path);
/* Set terminal window title */
r = set_tilde_in_path(path);
printf("\033]2;%s\007", r ? &path[homelen - 1] : path);
fflush(stdout);
if (r)
reset_tilde_in_path(path);
}
#endif #endif
#ifdef LINUX_INOTIFY #ifdef LINUX_INOTIFY
if ((presel == FILTER || watch) && inotify_wd >= 0) { if ((presel == FILTER || watch) && inotify_wd >= 0) {
inotify_rm_watch(inotify_fd, inotify_wd); inotify_rm_watch(inotify_fd, inotify_wd);
inotify_wd = -1; inotify_wd = -1;
watch = FALSE; watch = FALSE;
} }
#elif defined(BSD_KQUEUE) #elif defined(BSD_KQUEUE)
if ((presel == FILTER || watch) && event_fd >= 0) { if ((presel == FILTER || watch) && event_fd >= 0) {
skipping to change at line 6590 skipping to change at line 6671
watch = FALSE; watch = FALSE;
} }
#elif defined(HAIKU_NM) #elif defined(HAIKU_NM)
if ((presel == FILTER || watch) && haiku_hnd != NULL) { if ((presel == FILTER || watch) && haiku_hnd != NULL) {
haiku_stop_watch(haiku_hnd); haiku_stop_watch(haiku_hnd);
haiku_nm_active = FALSE; haiku_nm_active = FALSE;
watch = FALSE; watch = FALSE;
} }
#endif #endif
if (order) { if (order && cd) {
if (cfgsort[cfg.curctx] != '0') { if (cfgsort[cfg.curctx] != '0') {
if (cfgsort[cfg.curctx] == 'z') if (cfgsort[cfg.curctx] == 'z')
set_sort_flags('c'); set_sort_flags('c');
if ((!cfgsort[cfg.curctx] || (cfgsort[cfg.curctx] == 'c') ) if ((!cfgsort[cfg.curctx] || (cfgsort[cfg.curctx] == 'c') )
&& ((r = get_kv_key(order, path, maxorder, NNN_ORDER) ) > 0)) { && ((r = get_kv_key(order, path, maxorder, NNN_ORDER) ) > 0)) {
set_sort_flags(r); set_sort_flags(r);
cfgsort[cfg.curctx] = 'z'; cfgsort[cfg.curctx] = 'z';
} }
} else } else
cfgsort[cfg.curctx] = cfgsort[CTX_MAX]; cfgsort[cfg.curctx] = cfgsort[CTX_MAX];
} }
cd = TRUE;
populate(path, lastname); populate(path, lastname);
if (g_state.interrupt) { if (g_state.interrupt) {
g_state.interrupt = cfg.apparentsz = cfg.blkorder = 0; g_state.interrupt = cfg.apparentsz = cfg.blkorder = 0;
blk_shift = BLK_SHIFT_512; blk_shift = BLK_SHIFT_512;
presel = CONTROL('L'); presel = CONTROL('L');
} }
#ifdef LINUX_INOTIFY #ifdef LINUX_INOTIFY
if (presel != FILTER && inotify_wd == -1) if (presel != FILTER && inotify_wd == -1)
skipping to change at line 6714 skipping to change at line 6796
/* Scroll up */ /* Scroll up */
if (event.bstate == BUTTON4_PRESSED && ndents && (cfg.rol lover || cur)) { if (event.bstate == BUTTON4_PRESSED && ndents && (cfg.rol lover || cur)) {
move_cursor((!cfg.rollover && cur < scroll_lines move_cursor((!cfg.rollover && cur < scroll_lines
? 0 : (cur + ndents - scroll_line s) % ndents), 0); ? 0 : (cur + ndents - scroll_line s) % ndents), 0);
break; break;
} }
/* Scroll down */ /* Scroll down */
if (event.bstate == BUTTON5_PRESSED && ndents if (event.bstate == BUTTON5_PRESSED && ndents
&& (cfg.rollover || (cur != ndents - 1))) { && (cfg.rollover || (cur != ndents - 1))) {
if (!cfg.rollover && cur >= ndents - scroll_lines move_cursor((!cfg.rollover && cur >= ndents - scr
) oll_lines)
move_cursor(ndents-1, 0); ? (ndents - 1) : ((cur + scroll_l
else ines) % ndents), 0);
move_cursor((cur + scroll_lines) % ndents
, 0);
break; break;
} }
#endif #endif
/* Toggle filter mode on left click on last 2 lines */ /* Toggle filter mode on left click on last 2 lines */
if (event.y >= xlines - 2 && event.bstate == BUTTON1_PRES SED) { if (event.y >= xlines - 2 && event.bstate == BUTTON1_PRES SED) {
clearfilter(); clearfilter();
cfg.filtermode ^= 1; cfg.filtermode ^= 1;
if (cfg.filtermode) { if (cfg.filtermode) {
presel = FILTER; presel = FILTER;
goto nochange; goto nochange;
} }
/* Start watching the directory */ /* Start watching the directory */
watch = TRUE; watch = TRUE;
copycurname(); copycurname();
cd = FALSE;
goto begin; goto begin;
} }
/* Handle clicking on a file */ /* Handle clicking on a file */
if (event.y >= 2 && event.y <= ndents + 1 && if (event.y >= 2 && event.y <= ndents + 1 &&
(event.bstate == BUTTON1_PRESSED || (event.bstate == BUTTON1_PRESSED ||
event.bstate == BUTTON3_PRESSED)) { event.bstate == BUTTON3_PRESSED)) {
r = curscroll + (event.y - 2); r = curscroll + (event.y - 2);
if (r != cur) if (r != cur)
move_cursor(r, 1); move_cursor(r, 1);
skipping to change at line 6773 skipping to change at line 6854
#endif #endif
&mousetimings[currentmouse]); &mousetimings[currentmouse]);
mousedent[currentmouse] = cur; mousedent[currentmouse] = cur;
/* Single click just selects, double click falls through to SEL_OPEN */ /* Single click just selects, double click falls through to SEL_OPEN */
if ((mousedent[0] != mousedent[1]) || if ((mousedent[0] != mousedent[1]) ||
(((_ABSSUB(mousetimings[0].tv_sec, mousetimings [1].tv_sec) << 30) (((_ABSSUB(mousetimings[0].tv_sec, mousetimings [1].tv_sec) << 30)
+ (_ABSSUB(mousetimings[0].tv_nsec, mousetiming s[1].tv_nsec))) + (_ABSSUB(mousetimings[0].tv_nsec, mousetiming s[1].tv_nsec)))
> DBLCLK_INTERVAL_NS)) > DBLCLK_INTERVAL_NS))
break; break;
/* Double click */
mousetimings[currentmouse].tv_sec = 0; mousetimings[currentmouse].tv_sec = 0;
mousedent[currentmouse] = -1; mousedent[currentmouse] = -1;
sel = SEL_OPEN;
} else { } else {
if (cfg.filtermode || filterset()) if (cfg.filtermode || filterset())
presel = FILTER; presel = FILTER;
copycurname(); copycurname();
goto nochange; goto nochange;
} }
#endif #endif
// fallthrough // fallthrough
case SEL_NAV_IN: // fallthrough case SEL_NAV_IN: // fallthrough
case SEL_OPEN: case SEL_OPEN:
/* Cannot descend in empty directories */ /* Cannot descend in empty directories */
if (!ndents) if (!ndents) {
cd = FALSE;
goto begin; goto begin;
}
pent = &pdents[cur]; pent = &pdents[cur];
mkpath(path, pent->name, newpath); mkpath(path, pent->name, newpath);
DPRINTF_S(newpath); DPRINTF_S(newpath);
/* Visit directory */ /* Visit directory */
if (pent->flags & DIR_OR_DIRLNK) { if (pent->flags & DIR_OR_DIRLNK) {
if (chdir(newpath) == -1) { if (chdir(newpath) == -1) {
printwarn(&presel); printwarn(&presel);
goto nochange; goto nochange;
skipping to change at line 6817 skipping to change at line 6902
printwarn(&presel); printwarn(&presel);
goto nochange; goto nochange;
} }
DPRINTF_U(sb.st_mode); DPRINTF_U(sb.st_mode);
/* Do not open non-regular files */ /* Do not open non-regular files */
if (!S_ISREG(sb.st_mode)) { if (!S_ISREG(sb.st_mode)) {
printwait(messages[MSG_UNSUPPORTED], &presel); printwait(messages[MSG_UNSUPPORTED], &presel);
goto nochange; goto nochange;
} }
/* Handle plugin selection mode */
if (g_state.runplugin) {
g_state.runplugin = 0;
/* Must be in plugin dir and same context to sele
ct plugin */
if ((g_state.runctx == cfg.curctx) && !strcmp(pat
h, plgpath)) {
endselection(FALSE);
/* Copy path so we can return back to ear
lier dir */
xstrsncpy(path, rundir, PATH_MAX);
rundir[0] = '\0';
clearfilter();
if (chdir(path) == -1
|| !run_plugin(&path, pent->name,
runfile, &las
tname, &lastdir)) {
DPRINTF_S("plugin failed!");
}
if (g_state.picked)
return EXIT_SUCCESS;
if (runfile[0]) {
xstrsncpy(lastname, runfile, NAME
_MAX + 1);
runfile[0] = '\0';
}
setdirwatch();
goto begin;
}
}
#ifndef NOFIFO #ifndef NOFIFO
if (g_state.fifomode && (sel == SEL_OPEN)) { if (g_state.fifomode && (sel == SEL_OPEN)) {
notify_fifo(TRUE); /* Send opened path to NNN_FIF send_to_explorer(&presel); /* Write selection to
O */ explorer fifo */
goto nochange; break;
} }
#endif #endif
/* If opened as vim plugin and Enter/^M pressed, pick */ /* If opened as vim plugin and Enter/^M pressed, pick */
if (g_state.picker && (sel == SEL_OPEN)) { if (g_state.picker && (sel == SEL_OPEN)) {
if (!(pdents[cur].flags & FILE_SELECTED)) if (nselected == 0) /* Pick if none selected */
appendfpath(newpath, mkpath(path, pent->n ame, newpath)); appendfpath(newpath, mkpath(path, pent->n ame, newpath));
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
if (sel == SEL_NAV_IN) { if (sel == SEL_NAV_IN) {
/* If in listing dir, go to target on `l` or Righ t on symlink */ /* If in listing dir, go to target on `l` or Righ t on symlink */
if (listpath && S_ISLNK(pent->mode) if (listpath && S_ISLNK(pent->mode)
&& is_prefix(path, listpath, xstrlen(listpath ))) { && is_prefix(path, listpath, xstrlen(listpath ))) {
if (!realpath(pent->name, newpath)) { if (!realpath(pent->name, newpath)) {
printwarn(&presel); printwarn(&presel);
skipping to change at line 6857 skipping to change at line 6972
? (presel = FILTER) : (watch = TRU E); ? (presel = FILTER) : (watch = TRU E);
xstrsncpy(lastname, pent->name, NAME_MAX + 1); xstrsncpy(lastname, pent->name, NAME_MAX + 1);
goto begin; goto begin;
} }
/* Open file disabled on right arrow or `l` */ /* Open file disabled on right arrow or `l` */
if (cfg.nonavopen) if (cfg.nonavopen)
goto nochange; goto nochange;
} }
/* Handle plugin selection mode */
if (g_state.runplugin) {
g_state.runplugin = 0;
/* Must be in plugin dir and same context to sele
ct plugin */
if ((g_state.runctx == cfg.curctx) && !strcmp(pat
h, plgpath)) {
endselection(FALSE);
/* Copy path so we can return back to ear
lier dir */
xstrsncpy(path, rundir, PATH_MAX);
rundir[0] = '\0';
clearfilter();
if (chdir(path) == -1
|| !run_plugin(&path, pent->name,
runfile, &las
tname, &lastdir)) {
DPRINTF_S("plugin failed!");
}
if (g_state.picked)
return EXIT_SUCCESS;
if (runfile[0]) {
xstrsncpy(lastname, runfile, NAME
_MAX + 1);
runfile[0] = '\0';
}
setdirwatch();
goto begin;
}
}
if (!sb.st_size) { if (!sb.st_size) {
printwait(messages[MSG_EMPTY_FILE], &presel); printwait(messages[MSG_EMPTY_FILE], &presel);
goto nochange; goto nochange;
} }
if (cfg.useeditor if (cfg.useeditor
#ifdef FILE_MIME_OPTS #ifdef FILE_MIME_OPTS
&& get_output("file", FILE_MIME_OPTS, newpath, -1, FA LSE, FALSE) && get_output("file", FILE_MIME_OPTS, newpath, -1, FA LSE, FALSE)
&& is_prefix(g_buf, "text/", 5) && is_prefix(g_buf, "text/", 5)
#else #else
skipping to change at line 7095 skipping to change at line 7181
if (haiku_nm_active) { if (haiku_nm_active) {
haiku_stop_watch(haiku_hnd); haiku_stop_watch(haiku_hnd);
haiku_nm_active = FALSE; haiku_nm_active = FALSE;
} }
#endif #endif
presel = filterentries(path, lastname); presel = filterentries(path, lastname);
if (presel == ESC) { if (presel == ESC) {
presel = 0; presel = 0;
break; break;
} }
if (presel == FILTER) /* Refresh dir and filter again */ if (presel == FILTER) { /* Refresh dir and filter again *
/
cd = FALSE;
goto begin; goto begin;
}
goto nochange; goto nochange;
case SEL_MFLTR: // fallthrough case SEL_MFLTR: // fallthrough
case SEL_HIDDEN: // fallthrough case SEL_HIDDEN: // fallthrough
case SEL_DETAIL: // fallthrough case SEL_DETAIL: // fallthrough
case SEL_SORT: case SEL_SORT:
switch (sel) { switch (sel) {
case SEL_MFLTR: case SEL_MFLTR:
cfg.filtermode ^= 1; cfg.filtermode ^= 1;
if (cfg.filtermode) { if (cfg.filtermode) {
presel = FILTER; presel = FILTER;
skipping to change at line 7120 skipping to change at line 7208
watch = TRUE; // fallthrough watch = TRUE; // fallthrough
case SEL_HIDDEN: case SEL_HIDDEN:
if (sel == SEL_HIDDEN) { if (sel == SEL_HIDDEN) {
cfg.showhidden ^= 1; cfg.showhidden ^= 1;
if (cfg.filtermode) if (cfg.filtermode)
presel = FILTER; presel = FILTER;
clearfilter(); clearfilter();
} }
copycurname(); copycurname();
cd = FALSE;
goto begin; goto begin;
case SEL_DETAIL: case SEL_DETAIL:
cfg.showdetail ^= 1; cfg.showdetail ^= 1;
cfg.blkorder = 0; cfg.blkorder = 0;
continue; continue;
default: /* SEL_SORT */ default: /* SEL_SORT */
r = set_sort_flags(get_input(messages[MSG_ORDER]) ); r = set_sort_flags(get_input(messages[MSG_ORDER]) );
if (!r) { if (!r) {
printwait(messages[MSG_INVALID_KEY], &pre sel); printwait(messages[MSG_INVALID_KEY], &pre sel);
goto nochange; goto nochange;
skipping to change at line 7186 skipping to change at line 7275
else if (sel == SEL_EDIT) /* Avoid trying to edit a non-e xisting file */ else if (sel == SEL_EDIT) /* Avoid trying to edit a non-e xisting file */
goto nochange; goto nochange;
switch (sel) { switch (sel) {
case SEL_REDRAW: case SEL_REDRAW:
refresh = TRUE; refresh = TRUE;
break; break;
case SEL_RENAMEMUL: case SEL_RENAMEMUL:
endselection(TRUE); endselection(TRUE);
setenv("INCLUDE_HIDDEN", xitoa(cfg.showhidden), 1 ); setenv("INCLUDE_HIDDEN", xitoa(cfg.showhidden), 1 );
setenv("NNN_LIST", listpath ? listroot : "", 1);
if (!(getutil(utils[UTIL_BASH]) if (!(getutil(utils[UTIL_BASH])
&& plugscript(utils[UTIL_NMV], F_CLI)) && plugscript(utils[UTIL_NMV], F_CLI))
#ifndef NOBATCH #ifndef NOBATCH
&& !batch_rename() && !batch_rename()
#endif #endif
) { ) {
printwait(messages[MSG_FAILED], &presel); printwait(messages[MSG_FAILED], &presel);
goto nochange; goto nochange;
} }
skipping to change at line 7209 skipping to change at line 7299
case SEL_HELP: case SEL_HELP:
show_help(path); // fallthrough show_help(path); // fallthrough
case SEL_AUTONEXT: case SEL_AUTONEXT:
if (sel == SEL_AUTONEXT) if (sel == SEL_AUTONEXT)
g_state.autonext ^= 1; g_state.autonext ^= 1;
if (cfg.filtermode) if (cfg.filtermode)
presel = FILTER; presel = FILTER;
copycurname(); copycurname();
goto nochange; goto nochange;
case SEL_EDIT: case SEL_EDIT:
spawn(editor, newpath, NULL, NULL, F_CLI); if (!g_state.picker)
spawn(editor, newpath, NULL, NULL, F_CLI)
;
continue; continue;
default: /* SEL_LOCK */ default: /* SEL_LOCK */
lock_terminal(); lock_terminal();
break; break;
} }
/* In case of successful operation, reload contents */ /* In case of successful operation, reload contents */
/* Continue in type-to-nav mode, if enabled */ /* Continue in type-to-nav mode, if enabled */
if ((cfg.filtermode || filterset()) && !refresh) { if ((cfg.filtermode || filterset()) && !refresh) {
presel = FILTER; presel = FILTER;
goto nochange; goto nochange;
} }
/* Save current */ /* Save current */
copycurname(); copycurname();
/* Repopulate as directory content may have changed */ /* Repopulate as directory content may have changed */
cd = FALSE;
goto begin; goto begin;
} }
case SEL_SEL: case SEL_SEL:
if (!ndents) if (!ndents)
goto nochange; goto nochange;
startselection(); startselection();
if (g_state.rangesel) if (g_state.rangesel)
g_state.rangesel = 0; g_state.rangesel = 0;
skipping to change at line 7259 skipping to change at line 7351
#ifndef NOX11 #ifndef NOX11
if (cfg.x11) if (cfg.x11)
plugscript(utils[UTIL_CBCP], F_NOWAIT | F_NOTRACE ); plugscript(utils[UTIL_CBCP], F_NOWAIT | F_NOTRACE );
#endif #endif
#ifndef NOMOUSE #ifndef NOMOUSE
if (rightclicksel) if (rightclicksel)
rightclicksel = 0; rightclicksel = 0;
else else
#endif #endif
/* move cursor to the next entry if this is not t he last entry */ /* move cursor to the next entry if this is not t he last entry */
if (!g_state.stayonsel && !g_state.picker && cur != ndents - 1) if (!g_state.stayonsel && (cur != ndents - 1))
move_cursor((cur + 1) % ndents, 0); move_cursor((cur + 1) % ndents, 0);
break; break;
case SEL_SELMUL: case SEL_SELMUL:
if (!ndents) if (!ndents)
goto nochange; goto nochange;
startselection(); startselection();
g_state.rangesel ^= 1; g_state.rangesel ^= 1;
if (stat(path, &sb) == -1) { if (stat(path, &sb) == -1) {
skipping to change at line 7363 skipping to change at line 7455
mkpath(tmp, pdents[cur].name, newpath); mkpath(tmp, pdents[cur].name, newpath);
if (!xrm(newpath)) if (!xrm(newpath))
continue; continue;
xrmfromsel(tmp, newpath); xrmfromsel(tmp, newpath);
copynextname(lastname); copynextname(lastname);
if (cfg.filtermode || filterset()) if (cfg.filtermode || filterset())
presel = FILTER; presel = FILTER;
cd = FALSE;
goto begin; goto begin;
} }
} }
(nselected == 1 && (sel == SEL_CP || sel == SEL_MV)) (nselected == 1 && (sel == SEL_CP || sel == SEL_MV))
? mkpath(path, xbasename(pselbuf), newpath) ? mkpath(path, xbasename(pselbuf), newpath)
: (newpath[0] = '\0'); : (newpath[0] = '\0');
endselection(TRUE); endselection(TRUE);
skipping to change at line 7392 skipping to change at line 7485
#ifndef NOX11 #ifndef NOX11
/* Show notification on operation complete */ /* Show notification on operation complete */
if (cfg.x11) if (cfg.x11)
plugscript(utils[UTIL_NTFY], F_NOWAIT | F_NOTRACE ); plugscript(utils[UTIL_NTFY], F_NOWAIT | F_NOTRACE );
#endif #endif
if (newpath[0] && !access(newpath, F_OK)) if (newpath[0] && !access(newpath, F_OK))
xstrsncpy(lastname, xbasename(newpath), NAME_MAX+ 1); xstrsncpy(lastname, xbasename(newpath), NAME_MAX+ 1);
else else
copycurname(); copycurname();
cd = FALSE;
goto begin; goto begin;
} }
case SEL_ARCHIVE: // fallthrough case SEL_ARCHIVE: // fallthrough
case SEL_OPENWITH: // fallthrough case SEL_OPENWITH: // fallthrough
case SEL_NEW: // fallthrough case SEL_NEW: // fallthrough
case SEL_RENAME: case SEL_RENAME:
{ {
int fd, ret = 'n'; int fd, ret = 'n';
if (!ndents && (sel == SEL_OPENWITH || sel == SEL_RENAME) ) if (!ndents && (sel == SEL_OPENWITH || sel == SEL_RENAME) )
skipping to change at line 7428 skipping to change at line 7522
goto nochange; goto nochange;
} }
tmp = NULL; tmp = NULL;
} else } else
tmp = pdents[cur].name; tmp = pdents[cur].name;
tmp = xreadline(tmp, messages[MSG_ARCHIVE_NAME]); tmp = xreadline(tmp, messages[MSG_ARCHIVE_NAME]);
break; break;
case SEL_OPENWITH: case SEL_OPENWITH:
#ifdef NORL #ifndef NORL
tmp = xreadline(NULL, messages[MSG_OPEN_WITH]); if (g_state.picker) {
#else #endif
tmp = getreadline(messages[MSG_OPEN_WITH]); tmp = xreadline(NULL, messages[MSG_OPEN_W
ITH]);
#ifndef NORL
} else
tmp = getreadline(messages[MSG_OPEN_WITH]
);
#endif #endif
break; break;
case SEL_NEW: case SEL_NEW:
r = get_input(messages[MSG_NEW_OPTS]); r = get_input(messages[MSG_NEW_OPTS]);
if (r == 'f' || r == 'd') if (r == 'f' || r == 'd')
tmp = xreadline(NULL, messages[MSG_NEW_PA TH]); tmp = xreadline(NULL, messages[MSG_NEW_PA TH]);
else if (r == 's' || r == 'h') else if (r == 's' || r == 'h')
tmp = xreadline(NULL, messages[MSG_LINK_P tmp = xreadline(NULL,
REFIX]); messages[nselected <= 1?MSG_NEW_P
ATH:MSG_LINK_PREFIX]);
else else
tmp = NULL; tmp = NULL;
break; break;
default: /* SEL_RENAME */ default: /* SEL_RENAME */
tmp = xreadline(pdents[cur].name, ""); tmp = xreadline(pdents[cur].name, "");
break; break;
} }
if (!tmp || !*tmp) if (!tmp || !*tmp)
break; break;
skipping to change at line 7473 skipping to change at line 7571
get_archive_cmd(newpath, tmp); get_archive_cmd(newpath, tmp);
(r == 's') ? archive_selection(newpath, tmp, path ) (r == 's') ? archive_selection(newpath, tmp, path )
: spawn(newpath, tmp, pdents[cur].name , : spawn(newpath, tmp, pdents[cur].name ,
NULL, F_CLI | F_CONFIRM); NULL, F_CLI | F_CONFIRM);
mkpath(path, tmp, newpath); mkpath(path, tmp, newpath);
if (access(newpath, F_OK) == 0) { /* File created */ if (access(newpath, F_OK) == 0) { /* File created */
xstrsncpy(lastname, tmp, NAME_MAX + 1); xstrsncpy(lastname, tmp, NAME_MAX + 1);
clearfilter(); /* Archive name may not ma tch */ clearfilter(); /* Archive name may not ma tch */
clearselection(); /* Archive operation co mplete */ clearselection(); /* Archive operation co mplete */
cd = FALSE;
goto begin; goto begin;
} }
continue; continue;
case SEL_OPENWITH: case SEL_OPENWITH:
handle_openwith(path, pdents[cur].name, newpath, tmp); handle_openwith(path, pdents[cur].name, newpath, tmp);
cfg.filtermode ? presel = FILTER : statusbar(pat h); cfg.filtermode ? presel = FILTER : statusbar(pat h);
copycurname(); copycurname();
goto nochange; goto nochange;
case SEL_RENAME: case SEL_RENAME:
skipping to change at line 7567 skipping to change at line 7666
if (r == 'f' || r == 'd') if (r == 'f' || r == 'd')
xstrsncpy(lastname, tmp, NAME_MAX + 1); xstrsncpy(lastname, tmp, NAME_MAX + 1);
else if (ndents) { else if (ndents) {
if (cfg.filtermode) if (cfg.filtermode)
presel = FILTER; presel = FILTER;
copycurname(); copycurname();
} }
clearfilter(); clearfilter();
} }
cd = FALSE;
goto begin; goto begin;
} }
case SEL_PLUGIN: case SEL_PLUGIN:
/* Check if directory is accessible */ /* Check if directory is accessible */
if (!xdiraccess(plgpath)) { if (!xdiraccess(plgpath)) {
printwarn(&presel); printwarn(&presel);
goto nochange; goto nochange;
} }
if (!pkey) { if (!pkey) {
skipping to change at line 7661 skipping to change at line 7761
if (cfg.filtermode) if (cfg.filtermode)
presel = FILTER; presel = FILTER;
/* Save current */ /* Save current */
copycurname(); copycurname();
if (!r) if (!r)
goto nochange; goto nochange;
/* Repopulate as directory content may have changed */ /* Repopulate as directory content may have changed */
cd = FALSE;
goto begin; goto begin;
case SEL_UMOUNT: case SEL_UMOUNT:
presel = MSG_ZERO; presel = MSG_ZERO;
if (!unmount((ndents ? pdents[cur].name : NULL), newpath, &presel, path)) { if (!unmount((ndents ? pdents[cur].name : NULL), newpath, &presel, path)) {
if (presel == MSG_ZERO) if (presel == MSG_ZERO)
statusbar(path); statusbar(path);
goto nochange; goto nochange;
} }
/* Dir removed, go to next entry */ /* Dir removed, go to next entry */
copynextname(lastname); copynextname(lastname);
cd = FALSE;
goto begin; goto begin;
#ifndef NOSSN #ifndef NOSSN
case SEL_SESSIONS: case SEL_SESSIONS:
r = get_input(messages[MSG_SSN_OPTS]); r = get_input(messages[MSG_SSN_OPTS]);
if (r == 's') { if (r == 's') {
tmp = xreadline(NULL, messages[MSG_SSN_NAME]); tmp = xreadline(NULL, messages[MSG_SSN_NAME]);
if (tmp && *tmp) if (tmp && *tmp)
save_session(tmp, &presel); save_session(tmp, &presel);
} else if (r == 'l' || r == 'r') { } else if (r == 'l' || r == 'r') {
skipping to change at line 7698 skipping to change at line 7800
statusbar(path); statusbar(path);
goto nochange; goto nochange;
#endif #endif
case SEL_EXPORT: case SEL_EXPORT:
export_file_list(); export_file_list();
cfg.filtermode ? presel = FILTER : statusbar(path); cfg.filtermode ? presel = FILTER : statusbar(path);
goto nochange; goto nochange;
case SEL_TIMETYPE: case SEL_TIMETYPE:
if (!set_time_type(&presel)) if (!set_time_type(&presel))
goto nochange; goto nochange;
cd = FALSE;
goto begin; goto begin;
case SEL_QUITCTX: // fallthrough case SEL_QUITCTX: // fallthrough
case SEL_QUITCD: // fallthrough case SEL_QUITCD: // fallthrough
case SEL_QUIT: case SEL_QUIT:
case SEL_QUITERR: case SEL_QUITERR:
if (sel == SEL_QUITCTX) { if (sel == SEL_QUITCTX) {
int ctx = cfg.curctx; int ctx = cfg.curctx;
for (r = (ctx + 1) & ~CTX_MAX; for (r = (ctx + 1) & ~CTX_MAX;
(r != ctx) && !g_ctx[r].c_cfg.ctxactive; (r != ctx) && !g_ctx[r].c_cfg.ctxactive;
skipping to change at line 7736 skipping to change at line 7839
for (r = 0; r < CTX_MAX; ++r) for (r = 0; r < CTX_MAX; ++r)
if (r != cfg.curctx && g_ctx[r].c_cfg.ctx active) { if (r != cfg.curctx && g_ctx[r].c_cfg.ctx active) {
r = get_input(messages[MSG_QUIT_A LL]); r = get_input(messages[MSG_QUIT_A LL]);
break; break;
} }
if (!(r == CTX_MAX || xconfirm(r))) if (!(r == CTX_MAX || xconfirm(r)))
break; // fallthrough break; // fallthrough
} }
#ifndef NOSSN
if (session && g_state.prstssn)
save_session(session, NULL);
#endif
/* CD on Quit */ /* CD on Quit */
tmp = getenv("NNN_TMPFILE"); tmp = getenv("NNN_TMPFILE");
if ((sel == SEL_QUITCD) || tmp) { if ((sel == SEL_QUITCD) || tmp) {
write_lastdir(path, tmp); write_lastdir(path, tmp);
/* ^G is a way to quit picker mode without pickin g anything */ /* ^G is a way to quit picker mode without pickin g anything */
if ((sel == SEL_QUITCD) && g_state.picker) if ((sel == SEL_QUITCD) && g_state.picker)
selbufpos = 0; selbufpos = 0;
} }
if (sel != SEL_QUITERR) if (sel != SEL_QUITERR)
skipping to change at line 7846 skipping to change at line 7944
} }
} }
/* Get the dir in which to start */ /* Get the dir in which to start */
*tmp = '\0'; *tmp = '\0';
return tmpdir; return tmpdir;
} }
static char *load_input(int fd, const char *path) static char *load_input(int fd, const char *path)
{ {
ssize_t i, chunk_count = 1, chunk = 512 * 1024 /* 512 KiB chunk size */, entries = 0; ssize_t i, chunk_count = 1, chunk = (ssize_t)(512 * 1024) /* 512 KiB chun k size */, entries = 0;
char *input = malloc(sizeof(char) * chunk), *tmpdir = NULL; char *input = malloc(sizeof(char) * chunk), *tmpdir = NULL;
char cwd[PATH_MAX], *next; char cwd[PATH_MAX], *next;
size_t offsets[LIST_FILES_MAX]; size_t offsets[LIST_FILES_MAX];
char **paths = NULL; char **paths = NULL;
ssize_t input_read, total_read = 0, off = 0; ssize_t input_read, total_read = 0, off = 0;
int msgnum = 0; int msgnum = 0;
if (!input) { if (!input) {
DPRINTF_S(strerror(errno)); DPRINTF_S(strerror(errno));
return NULL; return NULL;
skipping to change at line 8038 skipping to change at line 8136
" -e text in $VISUAL/$EDITOR/vi\n" " -e text in $VISUAL/$EDITOR/vi\n"
" -E internal edits in EDITOR\n" " -E internal edits in EDITOR\n"
#ifndef NORL #ifndef NORL
" -f use readline history file\n" " -f use readline history file\n"
#endif #endif
#ifndef NOFIFO #ifndef NOFIFO
" -F val fifo mode [0:preview 1:explore]\n" " -F val fifo mode [0:preview 1:explore]\n"
#endif #endif
" -g regex filters\n" " -g regex filters\n"
" -H show hidden files\n" " -H show hidden files\n"
" -i show current file info\n"
" -J no auto-proceed on select\n" " -J no auto-proceed on select\n"
" -K detect key collision\n" " -K detect key collision\n"
" -l val set scroll lines\n" " -l val set scroll lines\n"
" -n type-to-nav mode\n" " -n type-to-nav mode\n"
" -o open files only on Enter\n" " -o open files only on Enter\n"
" -p file selection file [-:stdout]\n" " -p file selection file [-:stdout]\n"
" -P key run plugin key\n" " -P key run plugin key\n"
" -Q no quit confirmation\n" " -Q no quit confirmation\n"
" -r use advcpmv patched cp, mv\n" " -r use advcpmv patched cp, mv\n"
" -R no rollover at edges\n" " -R no rollover at edges\n"
skipping to change at line 8059 skipping to change at line 8158
" -s name load session by name\n" " -s name load session by name\n"
" -S persistent session\n" " -S persistent session\n"
#endif #endif
" -t secs timeout to lock\n" " -t secs timeout to lock\n"
" -T key sort order [a/d/e/r/s/t/v]\n" " -T key sort order [a/d/e/r/s/t/v]\n"
" -u use selection (no prompt)\n" " -u use selection (no prompt)\n"
#ifndef NOUG #ifndef NOUG
" -U show user and group\n" " -U show user and group\n"
#endif #endif
" -V show version\n" " -V show version\n"
" -w place HW cursor on hovered\n"
#ifndef NOX11 #ifndef NOX11
" -x notis, selection sync, xterm title\n" " -x notis, selection sync, xterm title\n"
#endif #endif
" -h show help\n\n" " -h show help\n\n"
"v%s\n%s\n", __func__, VERSION, GENERAL_INFO); "v%s\n%s\n", __func__, VERSION, GENERAL_INFO);
} }
static bool setup_config(void) static bool setup_config(void)
{ {
size_t r, len; size_t r, len;
skipping to change at line 8221 skipping to change at line 8319
#endif #endif
const char * const env_opts = xgetenv(env_cfg[NNN_OPTS], NULL); const char * const env_opts = xgetenv(env_cfg[NNN_OPTS], NULL);
int env_opts_id = env_opts ? (int)xstrlen(env_opts) : -1; int env_opts_id = env_opts ? (int)xstrlen(env_opts) : -1;
#ifndef NORL #ifndef NORL
bool rlhist = FALSE; bool rlhist = FALSE;
#endif #endif
while ((opt = (env_opts_id > 0 while ((opt = (env_opts_id > 0
? env_opts[--env_opts_id] ? env_opts[--env_opts_id]
: getopt(argc, argv, "aAb:cCdDeEfF:gHJKl:nop:P:QrRs:St:T:u UVwxh"))) != -1) { : getopt(argc, argv, "aAb:cCdDeEfF:gHiJKl:nop:P:QrRs:St:T: uUVxh"))) != -1) {
switch (opt) { switch (opt) {
#ifndef NOFIFO #ifndef NOFIFO
case 'a': case 'a':
g_state.autofifo = 1; g_state.autofifo = 1;
break; break;
#endif #endif
case 'A': case 'A':
cfg.autoselect = 0; cfg.autoselect = 0;
break; break;
case 'b': case 'b':
skipping to change at line 8275 skipping to change at line 8373
} }
break; break;
#endif #endif
case 'g': case 'g':
cfg.regex = 1; cfg.regex = 1;
filterfn = &visible_re; filterfn = &visible_re;
break; break;
case 'H': case 'H':
cfg.showhidden = 1; cfg.showhidden = 1;
break; break;
case 'i':
cfg.fileinfo = 1;
break;
case 'J': case 'J':
g_state.stayonsel = 1; g_state.stayonsel = 1;
break; break;
case 'K': case 'K':
check_key_collision(); check_key_collision();
return EXIT_SUCCESS; return EXIT_SUCCESS;
case 'l': case 'l':
if (env_opts_id < 0) if (env_opts_id < 0)
scroll_lines = atoi(optarg); scroll_lines = atoi(optarg);
break; break;
skipping to change at line 8352 skipping to change at line 8453
break; break;
case 'u': case 'u':
cfg.prefersel = 1; cfg.prefersel = 1;
break; break;
case 'U': case 'U':
g_state.uidgid = 1; g_state.uidgid = 1;
break; break;
case 'V': case 'V':
dprintf(STDOUT_FILENO, "%s\n", VERSION); dprintf(STDOUT_FILENO, "%s\n", VERSION);
return EXIT_SUCCESS; return EXIT_SUCCESS;
case 'w':
cfg.cursormode = 1;
break;
case 'x': case 'x':
cfg.x11 = 1; cfg.x11 = 1;
break; break;
case 'h': case 'h':
usage(); usage();
return EXIT_SUCCESS; return EXIT_SUCCESS;
default: default:
usage(); usage();
return EXIT_FAILURE; return EXIT_FAILURE;
} }
skipping to change at line 8639 skipping to change at line 8737
#else #else
if (!initcurses(NULL)) if (!initcurses(NULL))
#endif #endif
return EXIT_FAILURE; return EXIT_FAILURE;
if (sort) if (sort)
set_sort_flags(sort); set_sort_flags(sort);
opt = browse(initpath, session, pkey); opt = browse(initpath, session, pkey);
#ifndef NOSSN
if (session && g_state.prstssn)
save_session(session, NULL);
#endif
#ifndef NOMOUSE #ifndef NOMOUSE
mousemask(mask, NULL); mousemask(mask, NULL);
#endif #endif
exitcurses(); exitcurses();
#ifndef NORL #ifndef NORL
if (rlhist) { if (rlhist) {
mkpath(cfgpath, ".history", g_buf); mkpath(cfgpath, ".history", g_buf);
write_history(g_buf); write_history(g_buf);
 End of changes. 69 change blocks. 
133 lines changed or deleted 247 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)