From 9e974be3ddb42fd0b00d12b82610f5828fd2fd3a Mon Sep 17 00:00:00 2001
From: Arun Prakash Jana <engineerarun@gmail.com>
Date: Fri, 23 Nov 2018 22:41:47 +0530
Subject: [PATCH] Add option -p for file picker

---
 README.md |  3 ++-
 nnn.1     |  4 ++++
 src/nnn.c | 38 ++++++++++++++++++++++++++++++--------
 3 files changed, 36 insertions(+), 9 deletions(-)

diff --git a/README.md b/README.md
index 9b1e1a1a..6c256fea 100644
--- a/README.md
+++ b/README.md
@@ -184,7 +184,7 @@ Search keyword and option completion scripts for Bash, Fish and Zsh can be found
 
 ```
 usage: nnn [-b key] [-c N] [-e] [-i] [-l]
-           [-S] [-v] [-h] [PATH]
+           [-p file] [-S] [-v] [-h] [PATH]
 
 The missing terminal file manager for X.
 
@@ -197,6 +197,7 @@ optional args:
  -e      use exiftool instead of mediainfo
  -i      start in navigate-as-you-type mode
  -l      start in light mode
+ -p file copy selection to file (stdout if '-')
  -S      start in disk usage analyser mode
  -v      show program version
  -h      show this help
diff --git a/nnn.1 b/nnn.1
index 5775046f..aef323fa 100644
--- a/nnn.1
+++ b/nnn.1
@@ -11,6 +11,7 @@
 .Op Ar -e
 .Op Ar -i
 .Op Ar -l
+.Op Ar -p file
 .Op Ar -S
 .Op Ar -v
 .Op Ar -h
@@ -178,6 +179,9 @@ supports the following options:
 .Fl l
         start in light mode (fewer details)
 .Pp
+.Fl "p file"
+        copy (or \fIpick\fR) selection to file, or stdout if file='-'
+.Pp
 .Fl S
         start in disk usage analyzer mode
 .Pp
diff --git a/src/nnn.c b/src/nnn.c
index e8cd7d0d..c92621bd 100644
--- a/src/nnn.c
+++ b/src/nnn.c
@@ -261,9 +261,11 @@ typedef struct {
 	uint quote      : 1;  /* Copy paths within quotes */
 	uint color      : 3;  /* Color code for directories */
 	uint ctxactive  : 1;  /* Context active or not */
-	uint reserved   : 13;
+	uint reserved   : 11;
 	/* The following settings are global */
 	uint curctx     : 2;  /* Current context number */
+	uint picker     : 1;  /* Write selection to user-specified file */
+	uint pickraw    : 1;  /* Write selection to sdtout before exit */
 } settings;
 
 /* Contexts or workspaces */
@@ -279,7 +281,7 @@ typedef struct {
 /* GLOBALS */
 
 /* Configuration, contexts */
-static settings cfg = {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 4, 1, 0, 0};
+static settings cfg = {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 4, 1, 0, 0, 0, 0};
 static context g_ctx[MAX_CTX] __attribute__ ((aligned));
 
 static struct entry *dents;
@@ -305,7 +307,7 @@ static uchar crc8table[CRC8_TABLE_LEN] __attribute__ ((aligned));
 static char g_buf[MAX_CMD_LEN] __attribute__ ((aligned));
 
 /* Buffer for file path copy file */
-static char g_cppath[MAX_HOME_LEN] __attribute__ ((aligned));
+static char g_cppath[PATH_MAX] __attribute__ ((aligned));
 
 /* Buffer to store tmp file path */
 static char g_tmpfpath[MAX_HOME_LEN] __attribute__ ((aligned));
@@ -432,7 +434,7 @@ static void printerr(int linenum)
 {
 	exitcurses();
 	fprintf(stderr, "line %d: (%d) %s\n", linenum, errno, strerror(errno));
-	if (g_cppath[0])
+	if (!cfg.picker && g_cppath[0])
 		unlink(g_cppath);
 	exit(1);
 }
@@ -651,6 +653,10 @@ static char *xbasename(char *path)
 /* Writes buflen char(s) from buf to a file */
 static void writecp(const char *buf, const size_t buflen)
 {
+	if (cfg.pickraw) {
+		return;
+	}
+
 	if (!g_cppath[0]) {
 		printmsg(messages[STR_COPY_ID]);
 		return;
@@ -3393,7 +3399,7 @@ static void usage(void)
 {
 	fprintf(stdout,
 		"usage: nnn [-b key] [-c N] [-e] [-i] [-l]\n"
-		"           [-S] [-v] [-h] [PATH]\n\n"
+		"           [-p file] [-S] [-v] [-h] [PATH]\n\n"
 		"The missing terminal file manager for X.\n\n"
 		"positional args:\n"
 		"  PATH   start dir [default: current dir]\n\n"
@@ -3403,6 +3409,7 @@ static void usage(void)
 		" -e      use exiftool instead of mediainfo\n"
 		" -i      start in navigate-as-you-type mode\n"
 		" -l      start in light mode\n"
+		" -p file copy selection to file (stdout if '-')\n"
 		" -S      start in disk usage analyser mode\n"
 		" -v      show program version\n"
 		" -h      show this help\n\n"
@@ -3422,7 +3429,7 @@ int main(int argc, char *argv[])
 		exit(1);
 	}
 
-	while ((opt = getopt(argc, argv, "Slib:c:evh")) != -1) {
+	while ((opt = getopt(argc, argv, "Slib:c:ep:vh")) != -1) {
 		switch (opt) {
 		case 'S':
 			cfg.blkorder = 1;
@@ -3448,6 +3455,19 @@ int main(int argc, char *argv[])
 		case 'e':
 			cfg.metaviewer = EXIFTOOL;
 			break;
+		case 'p':
+			cfg.picker = 1;
+			if (optarg[0] == '-' && optarg[1] == '\0')
+				cfg.pickraw = 1;
+			else {
+				/* copier used as tmp var */
+				copier = realpath(optarg, g_cppath);
+				if (!g_cppath[0]) {
+					fprintf(stderr, "%s\n", strerror(errno));
+					exit(1);
+				}
+			}
+			break;
 		case 'v':
 			fprintf(stdout, "%s\n", VERSION);
 			return 0;
@@ -3532,7 +3552,7 @@ int main(int argc, char *argv[])
 	else if (xdiraccess("/tmp"))
 		g_tmpfplen = xstrlcpy(g_tmpfpath, "/tmp", MAX_HOME_LEN);
 
-	if (g_tmpfplen) {
+	if (!cfg.picker && g_tmpfplen) {
 		xstrlcpy(g_cppath, g_tmpfpath, MAX_HOME_LEN);
 		xstrlcpy(g_cppath + g_tmpfplen - 1, "/.nnncp", MAX_HOME_LEN - g_tmpfplen);
 	}
@@ -3561,7 +3581,9 @@ int main(int argc, char *argv[])
 	browse(ipath);
 	exitcurses();
 
-	if (g_cppath[0])
+	if (cfg.pickraw)
+		opt = write(1, pcopybuf, copybufpos - 1);
+	else if (!cfg.picker && g_cppath[0])
 		unlink(g_cppath);
 
 #ifdef LINUX_INOTIFY
-- 
2.51.0