--- /dev/null
+# Description: Adds preview pipe to enable closing and re-opening
+# the preview pane when running an undetached editor.
+#
+# Authors: Luuk van Baal
+
+diff --git a/src/nnn.c b/src/nnn.c
+index 44f297f4..f15b3bc1 100644
+--- a/src/nnn.c
++++ b/src/nnn.c
+@@ -367,7 +367,8 @@ typedef struct {
+ 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 uidgid : 1; /* Show owner and group info */
+- uint_t reserved : 7; /* Adjust when adding/removing a field */
++ uint_t previewer : 1; /* Run state of previewer */
++ uint_t reserved : 6; /* Adjust when adding/removing a field */
+ } runstate;
+
+ /* Contexts or workspaces */
+@@ -513,6 +514,9 @@ static char g_tmpfpath[TMP_LEN_MAX] __attribute__ ((aligned));
+ /* Buffer to store plugins control pipe location */
+ static char g_pipepath[TMP_LEN_MAX] __attribute__ ((aligned));
+
++/* Buffer to store preview plugins control pipe location */
++static char g_ppipepath[TMP_LEN_MAX] __attribute__ ((aligned));
++
+ /* Non-persistent runtime states */
+ static runstate g_state;
+
+@@ -687,12 +691,13 @@ static const char * const messages[] = {
+ #define NNN_FCOLORS 5
+ #define NNNLVL 6
+ #define NNN_PIPE 7
+-#define NNN_MCLICK 8
+-#define NNN_SEL 9
+-#define NNN_ARCHIVE 10
+-#define NNN_ORDER 11
+-#define NNN_HELP 12 /* strings end here */
+-#define NNN_TRASH 13 /* flags begin here */
++#define NNN_PPIPE 8
++#define NNN_MCLICK 9
++#define NNN_SEL 10
++#define NNN_ARCHIVE 11
++#define NNN_ORDER 12
++#define NNN_HELP 13 /* strings end here */
++#define NNN_TRASH 14 /* flags begin here */
+
+ static const char * const env_cfg[] = {
+ "NNN_OPTS",
+@@ -703,6 +708,7 @@ static const char * const env_cfg[] = {
+ "NNN_FCOLORS",
+ "NNNLVL",
+ "NNN_PIPE",
++ "NNN_PPIPE",
+ "NNN_MCLICK",
+ "NNN_SEL",
+ "NNN_ARCHIVE",
+@@ -846,7 +852,7 @@ static char *load_input(int fd, const char *path);
+ static int set_sort_flags(int r);
+ static void statusbar(char *path);
+ #ifndef NOFIFO
+-static void notify_fifo(bool force);
++static void notify_fifo(bool force, bool closepreview);
+ #endif
+
+ /* Functions */
+@@ -3045,7 +3051,7 @@ try_quit:
+ } else {
+ #ifndef NOFIFO
+ if (!g_state.fifomode)
+- notify_fifo(TRUE); /* Send hovered path to NNN_FIFO */
++ notify_fifo(TRUE, FALSE); /* Send hovered path to NNN_FIFO */
+ #endif
+ escaped = TRUE;
+ settimeout();
+@@ -5131,15 +5137,20 @@ static bool run_cmd_as_plugin(const char *file, uchar_t flags)
+
+ static bool plctrl_init(void)
+ {
+- size_t len;
++ size_t len, lenbuf;
++ pid_t pid = getpid();
+
+ /* g_tmpfpath is used to generate tmp file names */
+ g_tmpfpath[tmpfplen - 1] = '\0';
+- len = xstrsncpy(g_pipepath, g_tmpfpath, TMP_LEN_MAX);
++ len = lenbuf = xstrsncpy(g_pipepath, g_tmpfpath, TMP_LEN_MAX);
+ g_pipepath[len - 1] = '/';
+- len = xstrsncpy(g_pipepath + len, "nnn-pipe.", TMP_LEN_MAX - len) + len;
+- xstrsncpy(g_pipepath + len - 1, xitoa(getpid()), TMP_LEN_MAX - len);
++ xstrsncpy(g_ppipepath, g_pipepath, TMP_LEN_MAX);
++ len += xstrsncpy(g_pipepath + len, "nnn-pipe.", TMP_LEN_MAX - len);
++ xstrsncpy(g_pipepath + len - 1, xitoa(pid), TMP_LEN_MAX - len);
++ len = xstrsncpy(g_ppipepath + lenbuf, "nnn-ppipe.", TMP_LEN_MAX - lenbuf) + lenbuf;
++ xstrsncpy(g_ppipepath + len - 1, xitoa(pid), TMP_LEN_MAX - len);
+ setenv(env_cfg[NNN_PIPE], g_pipepath, TRUE);
++ setenv(env_cfg[NNN_PPIPE], g_ppipepath, TRUE);
+
+ return EXIT_SUCCESS;
+ }
+@@ -5168,6 +5179,21 @@ static ssize_t read_nointr(int fd, void *buf, size_t count)
+ return len;
+ }
+
++void *previewpipe(void *arg __attribute__ ((unused)))
++{
++ int fd, buf;
++
++ mkfifo(g_ppipepath, 0600);
++ fd = open(g_ppipepath, O_RDONLY);
++
++ if (read(fd, &buf, 1) == 1)
++ g_state.previewer = buf;
++
++ close(fd);
++ unlink(g_ppipepath);
++ return NULL;
++}
++
+ static char *readpipe(int fd, char *ctxnum, char **path)
+ {
+ char ctx, *nextpath = NULL;
+@@ -5787,7 +5813,7 @@ static void populate(char *path, char *lastname)
+ }
+
+ #ifndef NOFIFO
+-static void notify_fifo(bool force)
++static void notify_fifo(bool force, bool closepreview)
+ {
+ if (!fifopath)
+ return;
+@@ -5803,6 +5829,12 @@ static void notify_fifo(bool force)
+ }
+ }
+
++ if (closepreview) {
++ if (write(fifofd, "close\n", 6) != 6)
++ xerror();
++ return;
++ }
++
+ static struct entry lastentry;
+
+ if (!force && !memcmp(&lastentry, &pdents[cur], sizeof(struct entry)))
+@@ -5852,7 +5884,7 @@ static void move_cursor(int target, int ignore_scrolloff)
+
+ #ifndef NOFIFO
+ if (!g_state.fifomode)
+- notify_fifo(FALSE); /* Send hovered path to NNN_FIFO */
++ notify_fifo(FALSE, FALSE); /* Send hovered path to NNN_FIFO */
+ #endif
+ }
+
+@@ -6473,6 +6505,7 @@ static bool browse(char *ipath, const char *session, int pkey)
+ const uchar_t opener_flags = (cfg.cliopener ? F_CLI : (F_NOTRACE | F_NOSTDIN | F_NOWAIT));
+ bool watch = FALSE;
+ ino_t inode = 0;
++ static int previewkey;
+
+ #ifndef NOMOUSE
+ MEVENT event = {0};
+@@ -6735,7 +6768,7 @@ nochange:
+ move_cursor(r, 1);
+ #ifndef NOFIFO
+ else if ((event.bstate == BUTTON1_PRESSED) && !g_state.fifomode)
+- notify_fifo(TRUE); /* Send clicked path to NNN_FIFO */
++ notify_fifo(TRUE, FALSE); /* Send clicked path to NNN_FIFO */
+ #endif
+ /* Handle right click selection */
+ if (event.bstate == BUTTON3_PRESSED) {
+@@ -6808,7 +6841,7 @@ nochange:
+ }
+ #ifndef NOFIFO
+ if (g_state.fifomode && (sel == SEL_OPEN)) {
+- notify_fifo(TRUE); /* Send opened path to NNN_FIFO */
++ notify_fifo(TRUE, FALSE); /* Send opened path to NNN_FIFO */
+ goto nochange;
+ }
+ #endif
+@@ -6890,7 +6923,17 @@ nochange:
+ && strstr(g_buf, "text")
+ #endif
+ ) {
++
++ if (g_state.previewer)
++ notify_fifo(FALSE, TRUE);
++
+ spawn(editor, newpath, NULL, NULL, F_CLI);
++
++ if (g_state.previewer) {
++ pkey = previewkey;
++ goto run_plugin;
++ }
++
+ if (cfg.filtermode) {
+ presel = FILTER;
+ clearfilter();
+@@ -7198,7 +7241,17 @@ nochange:
+ copycurname();
+ goto nochange;
+ case SEL_EDIT:
++
++ if (g_state.previewer)
++ notify_fifo(FALSE, TRUE);
++
+ spawn(editor, newpath, NULL, NULL, F_CLI);
++
++ if (g_state.previewer) {
++ pkey = previewkey;
++ goto run_plugin;
++ }
++
+ continue;
+ default: /* SEL_LOCK */
+ lock_terminal();
+@@ -7558,6 +7611,7 @@ nochange:
+
+ goto begin;
+ }
++run_plugin:
+ case SEL_PLUGIN:
+ /* Check if directory is accessible */
+ if (!xdiraccess(plgpath)) {
+@@ -7583,6 +7637,12 @@ nochange:
+ goto nochange;
+ }
+
++ if (xstrcmp(tmp, "preview-tui") == 0) {
++ previewkey = r;
++ pthread_t tid;
++ pthread_create(&tid, NULL, previewpipe, NULL);
++ }
++
+ if (tmp[0] == '-' && tmp[1]) {
+ ++tmp;
+ r = FALSE; /* Do not refresh dir after completion */
+@@ -8181,8 +8241,10 @@ static void cleanup(void)
+ if (g_state.autofifo)
+ unlink(fifopath);
+ #endif
+- if (g_state.pluginit)
++ if (g_state.pluginit){
+ unlink(g_pipepath);
++ unlink(g_ppipepath);
++ }
+ #ifdef DEBUG
+ disabledbg();
+ #endif
+@@ -8681,7 +8743,7 @@ int main(int argc, char *argv[])
+
+ #ifndef NOFIFO
+ if (!g_state.fifomode)
+- notify_fifo(FALSE);
++ notify_fifo(FALSE, FALSE);
+ if (fifofd != -1)
+ close(fifofd);
+ #endif