Scan for selection status on redraw()

This commit is contained in:
Arun Prakash Jana 2021-07-13 01:07:11 +05:30
parent 60f310160a
commit 96f2dfa8a5
No known key found for this signature in database
GPG key ID: A75979F35C080412

102
src/nnn.c
View file

@ -217,6 +217,7 @@
#define SYM_ORPHAN 0x04 #define SYM_ORPHAN 0x04
#define FILE_MISSING 0x08 #define FILE_MISSING 0x08
#define FILE_SELECTED 0x10 #define FILE_SELECTED 0x10
#define FILE_SCANNED 0x20
/* Macros to define process spawn behaviour as flags */ /* Macros to define process spawn behaviour as flags */
#define F_NONE 0x00 /* no flag set */ #define F_NONE 0x00 /* no flag set */
@ -820,7 +821,6 @@ 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 editselection(void);
static int set_sort_flags(int r); static int set_sort_flags(int r);
#ifndef NOFIFO #ifndef NOFIFO
static void notify_fifo(bool force); static void notify_fifo(bool force);
@ -1406,16 +1406,20 @@ static void writesel(const char *buf, const size_t buflen)
printwarn(NULL); printwarn(NULL);
} }
static void appendfpath(const char *path, const size_t len) static bool appendfpath(const char *path, const size_t len)
{ {
bool ret = FALSE;
if ((selbufpos >= selbuflen) || ((len + 3) > (selbuflen - selbufpos))) { if ((selbufpos >= selbuflen) || ((len + 3) > (selbuflen - selbufpos))) {
selbuflen += PATH_MAX; selbuflen += PATH_MAX;
pselbuf = xrealloc(pselbuf, selbuflen); pselbuf = xrealloc(pselbuf, selbuflen);
ret = TRUE;
if (!pselbuf) if (!pselbuf)
errexit(); errexit();
} }
selbufpos += xstrsncpy(pselbuf + selbufpos, path, len); selbufpos += xstrsncpy(pselbuf + selbufpos, path, len);
return ret;
} }
/* Write selected file paths to fd, linefeed separated */ /* Write selected file paths to fd, linefeed separated */
@ -1544,10 +1548,8 @@ static char *findinsel(char *startpos, int len)
found = memmem(found, buflen - (found - startpos), g_buf, len); found = memmem(found, buflen - (found - startpos), g_buf, len);
if (!found) if (!found)
return NULL; return NULL;
if (found == startpos || *(found - 1) == '\0') if (found == startpos || *(found - 1) == '\0')
return found; return found;
/* We found g_buf as a substring of a path, move forward */ /* We found g_buf as a substring of a path, move forward */
found += len; found += len;
if (found >= startpos + buflen) if (found >= startpos + buflen)
@ -1563,11 +1565,21 @@ static int markcmp(const void *va, const void *vb)
return ma->startpos - mb->startpos; return ma->startpos - mb->startpos;
} }
static void findmarkentry(char *path, struct entry *dentp)
{
if (!(dentp->flags & FILE_SCANNED)) {
if (findinsel(findselpos, mkpath(path, dentp->name, g_buf)))
dentp->flags |= FILE_SELECTED;
dentp->flags |= FILE_SCANNED;
}
}
static void invertselbuf(char *path) static void invertselbuf(char *path)
{ {
size_t len, endpos, offset = 0; size_t len, endpos, offset = 0;
char *found; char *found;
int nmarked = 0, prev = 0; int nmarked = 0, prev = 0;
struct entry *dentp;
selmark *marked = malloc(nselected * sizeof(selmark)); selmark *marked = malloc(nselected * sizeof(selmark));
if (nselected > LARGESEL) { if (nselected > LARGESEL) {
@ -1577,12 +1589,15 @@ static void invertselbuf(char *path)
/* First pass: inversion */ /* First pass: inversion */
for (int i = 0; i < ndents; ++i) { for (int i = 0; i < ndents; ++i) {
dentp = &pdents[i];
findmarkentry(path, dentp);
/* Toggle selection status */ /* Toggle selection status */
pdents[i].flags ^= FILE_SELECTED; dentp->flags ^= FILE_SELECTED;
/* Find where the files marked for deselection are in selection buffer */ /* Find where the files marked for deselection are in selection buffer */
if (!(pdents[i].flags & FILE_SELECTED)) { if (!(dentp->flags & FILE_SELECTED)) {
len = mkpath(path, pdents[i].name, g_buf); len = mkpath(path, dentp->name, g_buf);
found = findinsel(findselpos, len); found = findinsel(findselpos, len);
marked[nmarked].startpos = found; marked[nmarked].startpos = found;
@ -1658,7 +1673,7 @@ static void invertselbuf(char *path)
nselected ? writesel(pselbuf, selbufpos - 1) : clearselection(); nselected ? writesel(pselbuf, selbufpos - 1) : clearselection();
} }
/* removes g_buf from selbuf */ /* Removes g_buf from selbuf */
static void rmfromselbuf(size_t len) static void rmfromselbuf(size_t len)
{ {
char *found = findinsel(findselpos, len); char *found = findinsel(findselpos, len);
@ -1671,17 +1686,42 @@ static void rmfromselbuf(size_t len)
nselected ? writesel(pselbuf, selbufpos - 1) : clearselection(); nselected ? writesel(pselbuf, selbufpos - 1) : clearselection();
} }
static bool scanselforpath(const char *path)
{
if (!path[1]) { /* path should always be at least two bytes (including NULL) */
findselpos = pselbuf;
return TRUE;
}
size_t off = xstrsncpy(g_buf, path, PATH_MAX);
g_buf[off - 1] = '/';
/*
* We set findselpos only here. Directories can be listed in arbitrary order.
* This is the best best we can do for remembering position.
*/
findselpos = findinsel(NULL, off);
return (findselpos != NULL);
}
static void addtoselbuf(char *path, int startid, int endid) static void addtoselbuf(char *path, int startid, int endid)
{ {
size_t len = appendslash(path); size_t len = appendslash(path);
struct entry *dentp;
/* Remember current selection buffer position */ /* Remember current selection buffer position */
for (int i = startid; i <= endid; ++i) { for (int i = startid; i <= endid; ++i) {
if (!(pdents[i].flags & FILE_SELECTED)) { dentp = &pdents[i];
/* Write the path to selection file to avoid flush */ if (findselpos)
appendfpath(path, len + xstrsncpy(path + len, pdents[i].name, PATH_MAX - len)); findmarkentry(path, dentp);
else
dentp->flags |= FILE_SCANNED;
pdents[i].flags |= FILE_SELECTED; if (!(dentp->flags & FILE_SELECTED)) {
/* Write the path to selection file to avoid flush */
if (appendfpath(path, len + xstrsncpy(path + len, dentp->name, PATH_MAX - len)))
scanselforpath(path);
dentp->flags |= FILE_SELECTED;
++nselected; ++nselected;
} }
} }
@ -5263,10 +5303,9 @@ static int dentfill(char *path, struct entry **ppdents)
uchar_t entflags = 0; uchar_t entflags = 0;
int flags = 0; int flags = 0;
struct dirent *dp; struct dirent *dp;
bool found; char *namep, *pnb, *buf;
char *namep, *pnb, *buf = g_buf;
struct entry *dentp; struct entry *dentp;
size_t off, namebuflen = NAMEBUF_INCR; size_t off = 0, namebuflen = NAMEBUF_INCR;
struct stat sb_path, sb; struct stat sb_path, sb;
DIR *dirp = opendir(path); DIR *dirp = opendir(path);
@ -5282,6 +5321,7 @@ static int dentfill(char *path, struct entry **ppdents)
if (cfg.blkorder) { if (cfg.blkorder) {
num_files = 0; num_files = 0;
dir_blocks = 0; dir_blocks = 0;
buf = g_buf;
if (fstatat(fd, path, &sb_path, 0) == -1) if (fstatat(fd, path, &sb_path, 0) == -1)
goto exit; goto exit;
@ -5321,21 +5361,6 @@ static int dentfill(char *path, struct entry **ppdents)
} }
#endif #endif
if (path[1]) { /* path should always be at least two bytes (including NULL) */
off = xstrsncpy(buf, path, PATH_MAX);
buf[off - 1] = '/';
/*
* We set findselpos only here. Directories can be listed in arbitrary order.
* This is the best best we can do for remembering position.
*/
found = (findselpos = findinsel(NULL, off)) != NULL;
} else {
findselpos = NULL;
found = TRUE;
}
off = 0;
do { do {
namep = dp->d_name; namep = dp->d_name;
@ -5351,7 +5376,7 @@ static int dentfill(char *path, struct entry **ppdents)
if (S_ISDIR(sb.st_mode)) { if (S_ISDIR(sb.st_mode)) {
if (sb_path.st_dev == sb.st_dev) { // NOLINT if (sb_path.st_dev == sb.st_dev) { // NOLINT
mkpath(path, namep, buf); mkpath(path, namep, buf); // NOLINT
dirwalk(path, buf, -1, FALSE); dirwalk(path, buf, -1, FALSE);
if (g_state.interrupt) if (g_state.interrupt)
@ -5477,12 +5502,9 @@ static int dentfill(char *path, struct entry **ppdents)
entflags = 0; entflags = 0;
} }
if (found && findinsel(findselpos, mkpath(path, dentp->name, buf)) != NULL)
dentp->flags |= FILE_SELECTED;
if (cfg.blkorder) { if (cfg.blkorder) {
if (S_ISDIR(sb.st_mode)) { if (S_ISDIR(sb.st_mode)) {
mkpath(path, namep, buf); mkpath(path, namep, buf); // NOLINT
/* Need to show the disk usage of this dir */ /* Need to show the disk usage of this dir */
dirwalk(path, buf, ndents, (sb_path.st_dev != sb.st_dev)); // NOLINT dirwalk(path, buf, ndents, (sb_path.st_dev != sb.st_dev)); // NOLINT
@ -6180,9 +6202,15 @@ static void redraw(char *path)
ncols = adjust_cols(ncols); ncols = adjust_cols(ncols);
bool found = scanselforpath(path);
/* Print listing */ /* Print listing */
for (i = curscroll; i < onscreen; ++i) { for (i = curscroll; i < onscreen; ++i) {
move(++j, 0); move(++j, 0);
if (found)
findmarkentry(path, &pdents[i]);
printent(&pdents[i], ncols, i == cur); printent(&pdents[i], ncols, i == cur);
} }
@ -7041,9 +7069,11 @@ nochange:
selstartid = 0; selstartid = 0;
selendid = ndents - 1; selendid = ndents - 1;
scanselforpath(path);
} }
(sel == SEL_SELINV) ((sel == SEL_SELINV) && findselpos)
? invertselbuf(path) : addtoselbuf(path, selstartid, selendid); ? invertselbuf(path) : addtoselbuf(path, selstartid, selendid);
#ifndef NOX11 #ifndef NOX11