* Add an option to print hovered files to a FIFO This adds an env variable, `NNN_FIFO`, that can be set to a path that `nnn` will open/create as a FIFO, and where every hovered file's path is printed. This allows creating external perview/quick open plugins, ... It can be compiled out with the make variable `O_NOFIFO`. * Check filename ptr instead of full path (for FIFO) * Add documentation to use NNN_FIFO in plugins * Fix path sent to FIFO in empty dirsmaster
@@ -57,6 +57,10 @@ ifeq ($(O_NOBATCH),1) | |||
CPPFLAGS += -DNOBATCH | |||
endif | |||
ifeq ($(O_NOFIFO),1) | |||
CPPFLAGS += -DNOFIFO | |||
endif | |||
ifeq ($(shell $(PKG_CONFIG) ncursesw && echo 1),1) | |||
CFLAGS_CURSES ?= $(shell $(PKG_CONFIG) --cflags ncursesw) | |||
LDLIBS_CURSES ?= $(shell $(PKG_CONFIG) --libs ncursesw) | |||
@@ -423,6 +423,13 @@ separated by \fI;\fR: | |||
.Pp | |||
\fBNNN_SEL:\fR absolute path to custom selection file. | |||
.Pp | |||
\fBNNN_FIFO:\fR path of a named pipe to write current file path: | |||
.Bd -literal | |||
export NNN_FIFO='/tmp/nnn.fifo' | |||
NOTE: If the FIFO file doesn't exist it will be created, but it will never be removed. | |||
.Ed | |||
.Pp | |||
\fBnnn:\fR this is a special variable set to the hovered entry before executing | |||
a command from the command prompt or spawning a shell. | |||
.Pp | |||
@@ -190,7 +190,7 @@ Usage examples can be found in the Examples section below. | |||
There are many plugins provided by `nnn` which can be used as examples. Here are a few simple selected examples. | |||
- Show the git log of changes to the particular file along with the code for a quick and easy review. | |||
```sh | |||
```sh | |||
#!/usr/bin/env sh | |||
git log -p -- "$1" | |||
``` | |||
@@ -220,6 +220,40 @@ There are many plugins provided by `nnn` which can be used as examples. Here are | |||
printf "%s" "0c$dir" > "$NNN_PIPE" | |||
``` | |||
#### Get notified on file hover | |||
If `NNN_FIFO` is set, `nnn` will open it and write every hovered files. | |||
This can be used in plugins, e.g. to implement file previews. | |||
If a `NNN_FIFO` is set globally, each `nnn` instance will write to it, and a process reading from the pipe will get hovered path from every instance, interleaved. | |||
If you want to prevent this and be sure to have a private pipe to one `nnn` instance, you can unlink (remove) the FIFO file. | |||
If you opened the FIFO before and you have read from it (so that `nnn` have it opened too), you can still read from it while you don't close it. | |||
But new `nnn` instances will recreate a new FIFO not linked to the previous one. | |||
Don't forget to fork in the background to avoid blocking `nnn`. | |||
Example (send every hovered file to X selection): | |||
```sh | |||
#!/usr/bin/env sh | |||
if [ -z "$NNN_FIFO" ] ; then | |||
exit 1 | |||
fi | |||
while read FILE ; do | |||
if [ -n "$NNN_FIFO" ] ; then | |||
# If you want to remove the FIFO, | |||
# don't do it before first read, | |||
# nnn won't have it opened yet | |||
rm "$NNN_FIFO" | |||
NNN_FIFO= | |||
fi | |||
printf "%s" "$FILE" | xsel | |||
done < "$NNN_FIFO" & | |||
disown | |||
``` | |||
## Contributing plugins | |||
1. Add informative sections like _Description_, _Notes_, _Dependencies_, _Shell_, _Author_ etc. in the plugin. | |||
@@ -330,6 +330,9 @@ static context g_ctx[CTX_MAX] __attribute__ ((aligned)); | |||
static int ndents, cur, last, curscroll, last_curscroll, total_dents = ENTRY_INCR; | |||
static int nselected; | |||
#ifndef NOFIFO | |||
static int fifofd = -1; | |||
#endif | |||
static uint idletimeout, selbufpos, lastappendpos, selbuflen; | |||
static ushort xlines, xcols; | |||
static ushort idle; | |||
@@ -350,6 +353,9 @@ static char *prefixpath; | |||
static char *plugindir; | |||
static char *sessiondir; | |||
static char *pnamebuf, *pselbuf; | |||
#ifndef NOFIFO | |||
static char *fifopath; | |||
#endif | |||
static ull *ihashbmp; | |||
static struct entry *dents; | |||
static blkcnt_t ent_blocks; | |||
@@ -4667,6 +4673,40 @@ static void populate(char *path, char *lastname) | |||
last_curscroll = -1; | |||
} | |||
#ifndef NOFIFO | |||
static void notify_fifo() | |||
{ | |||
if (fifofd == -1) { | |||
fifofd = open(fifopath, O_WRONLY|O_NONBLOCK); | |||
if (fifofd == -1) { | |||
if (errno != ENXIO) | |||
/* Unexpected error, the FIFO file might have been removed */ | |||
/* We give up FIFO notification */ | |||
fifopath = NULL; | |||
return; | |||
} | |||
} | |||
static char *name = NULL; | |||
if (dents[cur].name == name) | |||
return; | |||
name = dents[cur].name; | |||
char path[PATH_MAX]; | |||
size_t len = mkpath(g_ctx[cfg.curctx].c_path, ndents ? name : "", path); | |||
path[len - 1] = '\n'; | |||
ssize_t ret = write(fifofd, path, len); | |||
if (ret != (ssize_t)len && !(ret == -1 && (errno == EAGAIN || errno == EPIPE))) { | |||
DPRINTF_S(strerror(errno)); | |||
} | |||
} | |||
#endif | |||
static void move_cursor(int target, int ignore_scrolloff) | |||
{ | |||
int onscreen = xlines - 4; /* Leave top 2 and bottom 2 lines */ | |||
@@ -4693,6 +4733,11 @@ static void move_cursor(int target, int ignore_scrolloff) | |||
} | |||
curscroll = MIN(curscroll, MIN(cur, ndents - onscreen)); | |||
curscroll = MAX(curscroll, MAX(cur - (onscreen - 1), 0)); | |||
#ifndef NOFIFO | |||
if (fifopath) | |||
notify_fifo(); | |||
#endif | |||
} | |||
static void handle_screen_move(enum action sel) | |||
@@ -7022,6 +7067,19 @@ int main(int argc, char *argv[]) | |||
DPRINTF_S(getenv("PWD")); | |||
#ifndef NOFIFO | |||
/* Create fifo */ | |||
fifopath = getenv("NNN_FIFO"); | |||
if (fifopath) { | |||
if (mkfifo(fifopath, 0600) != 0 && !(errno == EEXIST && access(fifopath, W_OK) == 0)) { | |||
xerror(); | |||
return _FAILURE; | |||
} | |||
signal(SIGPIPE, SIG_IGN); | |||
} | |||
#endif | |||
#ifdef LINUX_INOTIFY | |||
/* Initialize inotify */ | |||
inotify_fd = inotify_init1(IN_NONBLOCK); | |||
@@ -7145,5 +7203,10 @@ int main(int argc, char *argv[]) | |||
haiku_close_nm(haiku_hnd); | |||
#endif | |||
#ifndef NOFIFO | |||
if (fifofd != -1) | |||
close(fifofd); | |||
#endif | |||
return opt; | |||
} |