From 746e5d0d1f47d715a3068ac1e93fdb38fc4d2f78 Mon Sep 17 00:00:00 2001
From: Arun Prakash Jana <engineerarun@gmail.com>
Date: Fri, 1 Mar 2019 06:46:13 +0530
Subject: [PATCH] Fix #141, #196

---
 README.md |  4 +++-
 nnn.1     |  5 +++-
 src/nnn.c | 71 +++++++++++++++++++++++++++++++++++++++----------------
 3 files changed, 58 insertions(+), 22 deletions(-)

diff --git a/README.md b/README.md
index 3dbc27f1..bfba745b 100644
--- a/README.md
+++ b/README.md
@@ -318,7 +318,9 @@ To copy multiple absolute file paths:
 - press <kbd>^Y</kbd> (or <kbd>Y</kbd>) to enter selection mode. In this mode it's possible to
   - cherry-pick individual files one by one by pressing <kbd>^K</kbd> on each entry (works across directories and contexts); or,
   - navigate to another file in the same directory to select a range of files
-- press <kbd>^Y</kbd> (or <kbd>Y</kbd>) _again_ to copy the paths and exit the selection mode
+- press <kbd>^Y</kbd> again to save the selection and exit selection mode.
+
+Selected files are visually indicated by a `+`.
 
 The files in the list can now be copied (<kbd>P</kbd>), moved (<kbd>V</kbd>) or removed (<kbd>X</kbd>).
 
diff --git a/nnn.1 b/nnn.1
index 8bed5b1b..8617a4d4 100644
--- a/nnn.1
+++ b/nnn.1
@@ -265,7 +265,10 @@ In this mode it's possible to
 .br
 (2) navigate to another file in the same directory to select a range of files.
 .Pp
-Pressing \fI^Y\fR again saves the selection to the list and exits the selection mode.
+Press \fI^Y\fR again to save the selection and exit selection mode.
+.Pp
+Selected files are visually indicated by a \fB+\fR.
+.br
 The files in the list can now be copied, moved or removed using respective keyboard shortcuts.
 .Pp
 To list the selected files press \fIy\fR.
diff --git a/src/nnn.c b/src/nnn.c
index 4e208d6e..8951eb70 100644
--- a/src/nnn.c
+++ b/src/nnn.c
@@ -184,12 +184,15 @@ disabledbg()
 #define DESCRIPTOR_LEN 32
 #define _ALIGNMENT 0x10 /* 16-byte alignment */
 #define _ALIGNMENT_MASK 0xF
-#define DIR_OR_LINK_TO_DIR 0x1
 #define HOME_LEN_MAX 64
 #define CTX_MAX 4
 #define DOT_FILTER_LEN 7
 #define ASCII_MAX 128
 
+/* Entry flags */
+#define DIR_OR_LINK_TO_DIR 0x1
+#define FILE_COPIED 0x10
+
 /* Macros to define process spawn behaviour as flags */
 #define F_NONE     0x00  /* no flag set */
 #define F_MARKER   0x01  /* draw marker to indicate nnn spawned (e.g. shell) */
@@ -909,6 +912,17 @@ static bool cpsafe(void)
 	return TRUE;
 }
 
+/* Reset copy indicators */
+static void resetcpind()
+{
+	int r = 0;
+
+	/* Reset copy indicators */
+	for (; r < ndents; ++r)
+		if (dents[r].flags & FILE_COPIED)
+			dents[r].flags &= ~FILE_COPIED;
+}
+
 /* Initialize curses mode */
 static bool initcurses(void)
 {
@@ -1977,7 +1991,7 @@ static void printent(const struct entry *ent, int sel, uint namecols)
 
 static void printent_long(const struct entry *ent, int sel, uint namecols)
 {
-	char timebuf[18], permbuf[4];
+	char timebuf[18], permbuf[4], cp = ' ';
 
 	/* Timestamp */
 	strftime(timebuf, 18, "%F %R", localtime(&ent->t));
@@ -1985,6 +1999,10 @@ static void printent_long(const struct entry *ent, int sel, uint namecols)
 	/* Permissions */
 	snprintf(permbuf, 4, "%d%d%d", (ent->mode >> 6) & 7, (ent->mode >> 3) & 7, ent->mode & 7);
 
+	/* Add copy indicator */
+	if (ent->flags & FILE_COPIED)
+		cp = '+';
+
 	/* Trim escape chars from name */
 	const char *pname = unescape(ent->name, namecols);
 
@@ -1997,39 +2015,39 @@ static void printent_long(const struct entry *ent, int sel, uint namecols)
 	switch (ent->mode & S_IFMT) {
 	case S_IFREG:
 		if (ent->mode & 0100)
-			printw(" %-16.16s  0%s %8.8s* %s*\n", timebuf, permbuf,
+			printw("%c%-16.16s  0%s %8.8s* %s*\n", cp, timebuf, permbuf,
 			       coolsize(cfg.blkorder ? ent->blocks << BLK_SHIFT : ent->size), pname);
 		else
-			printw(" %-16.16s  0%s %8.8s  %s\n", timebuf, permbuf,
+			printw("%c%-16.16s  0%s %8.8s  %s\n", cp, timebuf, permbuf,
 			       coolsize(cfg.blkorder ? ent->blocks << BLK_SHIFT : ent->size), pname);
 		break;
 	case S_IFDIR:
 		if (cfg.blkorder)
-			printw(" %-16.16s  0%s %8.8s/ %s/\n",
-			       timebuf, permbuf, coolsize(ent->blocks << BLK_SHIFT), pname);
+			printw("%c%-16.16s  0%s %8.8s/ %s/\n",
+			       cp, timebuf, permbuf, coolsize(ent->blocks << BLK_SHIFT), pname);
 		else
-			printw(" %-16.16s  0%s        /  %s/\n", timebuf, permbuf, pname);
+			printw("%c%-16.16s  0%s        /  %s/\n", cp, timebuf, permbuf, pname);
 		break;
 	case S_IFLNK:
 		if (ent->flags & DIR_OR_LINK_TO_DIR)
-			printw(" %-16.16s  0%s       @/  %s@\n", timebuf, permbuf, pname);
+			printw("%c%-16.16s  0%s       @/  %s@\n", cp, timebuf, permbuf, pname);
 		else
-			printw(" %-16.16s  0%s        @  %s@\n", timebuf, permbuf, pname);
+			printw("%c%-16.16s  0%s        @  %s@\n", cp, timebuf, permbuf, pname);
 		break;
 	case S_IFSOCK:
-		printw(" %-16.16s  0%s        =  %s=\n", timebuf, permbuf, pname);
+		printw("%c%-16.16s  0%s        =  %s=\n", cp, timebuf, permbuf, pname);
 		break;
 	case S_IFIFO:
-		printw(" %-16.16s  0%s        |  %s|\n", timebuf, permbuf, pname);
+		printw("%c%-16.16s  0%s        |  %s|\n", cp, timebuf, permbuf, pname);
 		break;
 	case S_IFBLK:
-		printw(" %-16.16s  0%s        b  %s\n", timebuf, permbuf, pname);
+		printw("%c%-16.16s  0%s        b  %s\n", cp, timebuf, permbuf, pname);
 		break;
 	case S_IFCHR:
-		printw(" %-16.16s  0%s        c  %s\n", timebuf, permbuf, pname);
+		printw("%c%-16.16s  0%s        c  %s\n", cp, timebuf, permbuf, pname);
 		break;
 	default:
-		printw(" %-16.16s  0%s %8.8s? %s?\n", timebuf, permbuf,
+		printw("%c%-16.16s  0%s %8.8s? %s?\n", cp, timebuf, permbuf,
 		       coolsize(cfg.blkorder ? ent->blocks << BLK_SHIFT : ent->size), pname);
 		break;
 	}
@@ -2609,6 +2627,7 @@ static int dentfill(char *path, struct entry **dents)
 		dentp->mode = sb.st_mode;
 		dentp->t = sb.st_mtime;
 		dentp->size = sb.st_size;
+		dentp->flags = 0;
 
 		if (cfg.blkorder) {
 			if (S_ISDIR(sb.st_mode)) {
@@ -2646,8 +2665,6 @@ static int dentfill(char *path, struct entry **dents)
 
 		if (S_ISDIR(sb.st_mode))
 			dentp->flags |= DIR_OR_LINK_TO_DIR;
-		else if (dentp->flags & DIR_OR_LINK_TO_DIR)
-			dentp->flags &= ~DIR_OR_LINK_TO_DIR;
 
 		++n;
 	}
@@ -3463,8 +3480,13 @@ nochange:
 				++ncp;
 			} else {
 				r = mkpath(path, dents[cur].name, newpath);
-				/* Keep the copy buf in sync */
-				copybufpos = 0;
+
+				if (copybufpos) {
+					resetcpind();
+
+					/* Keep the copy buf in sync */
+					copybufpos = 0;
+				}
 				appendfpath(newpath, r);
 
 				writecp(newpath, r - 1); /* Truncate NULL from end */
@@ -3472,14 +3494,20 @@ nochange:
 					spawn(copier, NULL, NULL, NULL, F_NOTRACE);
 			}
 
+			dents[cur].flags |= FILE_COPIED;
+
 			printmsg(newpath);
 			goto nochange;
 		case SEL_COPYMUL:
 			cfg.copymode ^= 1;
 			if (cfg.copymode) {
+				if (copybufpos) {
+					resetcpind();
+					writecp(NULL, 0);
+					copybufpos = 0;
+				}
 				g_crc = crc8fast((uchar *)dents, ndents * sizeof(struct entry));
 				copystartid = cur;
-				copybufpos = 0;
 				ncp = 0;
 				printmsg("selection on");
 				DPRINTF_S("selection on");
@@ -3516,11 +3544,14 @@ nochange:
 			}
 
 			if ((!ncp && copystartid < copyendid) || sel == SEL_COPYALL) {
-				for (r = copystartid; r <= copyendid; ++r)
+				for (r = copystartid; r <= copyendid; ++r) {
 					if (!appendfpath(newpath, mkpath(path,
 							 dents[r].name, newpath)))
 						goto nochange;
 
+					dents[r].flags |= FILE_COPIED;
+				}
+
 				mvprintw(LINES - 1, 0, "%d files selected\n",
 					 copyendid - copystartid + 1);
 			}
-- 
2.51.0