* 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 | CPPFLAGS += -DNOBATCH | ||||
endif | endif | ||||
ifeq ($(O_NOFIFO),1) | |||||
CPPFLAGS += -DNOFIFO | |||||
endif | |||||
ifeq ($(shell $(PKG_CONFIG) ncursesw && echo 1),1) | ifeq ($(shell $(PKG_CONFIG) ncursesw && echo 1),1) | ||||
CFLAGS_CURSES ?= $(shell $(PKG_CONFIG) --cflags ncursesw) | CFLAGS_CURSES ?= $(shell $(PKG_CONFIG) --cflags ncursesw) | ||||
LDLIBS_CURSES ?= $(shell $(PKG_CONFIG) --libs ncursesw) | LDLIBS_CURSES ?= $(shell $(PKG_CONFIG) --libs ncursesw) | ||||
@@ -423,6 +423,13 @@ separated by \fI;\fR: | |||||
.Pp | .Pp | ||||
\fBNNN_SEL:\fR absolute path to custom selection file. | \fBNNN_SEL:\fR absolute path to custom selection file. | ||||
.Pp | .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 | \fBnnn:\fR this is a special variable set to the hovered entry before executing | ||||
a command from the command prompt or spawning a shell. | a command from the command prompt or spawning a shell. | ||||
.Pp | .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. | 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. | - 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 | #!/usr/bin/env sh | ||||
git log -p -- "$1" | 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" | 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 | ## Contributing plugins | ||||
1. Add informative sections like _Description_, _Notes_, _Dependencies_, _Shell_, _Author_ etc. in the plugin. | 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 ndents, cur, last, curscroll, last_curscroll, total_dents = ENTRY_INCR; | ||||
static int nselected; | static int nselected; | ||||
#ifndef NOFIFO | |||||
static int fifofd = -1; | |||||
#endif | |||||
static uint idletimeout, selbufpos, lastappendpos, selbuflen; | static uint idletimeout, selbufpos, lastappendpos, selbuflen; | ||||
static ushort xlines, xcols; | static ushort xlines, xcols; | ||||
static ushort idle; | static ushort idle; | ||||
@@ -350,6 +353,9 @@ static char *prefixpath; | |||||
static char *plugindir; | static char *plugindir; | ||||
static char *sessiondir; | static char *sessiondir; | ||||
static char *pnamebuf, *pselbuf; | static char *pnamebuf, *pselbuf; | ||||
#ifndef NOFIFO | |||||
static char *fifopath; | |||||
#endif | |||||
static ull *ihashbmp; | static ull *ihashbmp; | ||||
static struct entry *dents; | static struct entry *dents; | ||||
static blkcnt_t ent_blocks; | static blkcnt_t ent_blocks; | ||||
@@ -4667,6 +4673,40 @@ static void populate(char *path, char *lastname) | |||||
last_curscroll = -1; | 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) | static void move_cursor(int target, int ignore_scrolloff) | ||||
{ | { | ||||
int onscreen = xlines - 4; /* Leave top 2 and bottom 2 lines */ | 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 = MIN(curscroll, MIN(cur, ndents - onscreen)); | ||||
curscroll = MAX(curscroll, MAX(cur - (onscreen - 1), 0)); | curscroll = MAX(curscroll, MAX(cur - (onscreen - 1), 0)); | ||||
#ifndef NOFIFO | |||||
if (fifopath) | |||||
notify_fifo(); | |||||
#endif | |||||
} | } | ||||
static void handle_screen_move(enum action sel) | static void handle_screen_move(enum action sel) | ||||
@@ -7022,6 +7067,19 @@ int main(int argc, char *argv[]) | |||||
DPRINTF_S(getenv("PWD")); | 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 | #ifdef LINUX_INOTIFY | ||||
/* Initialize inotify */ | /* Initialize inotify */ | ||||
inotify_fd = inotify_init1(IN_NONBLOCK); | inotify_fd = inotify_init1(IN_NONBLOCK); | ||||
@@ -7145,5 +7203,10 @@ int main(int argc, char *argv[]) | |||||
haiku_close_nm(haiku_hnd); | haiku_close_nm(haiku_hnd); | ||||
#endif | #endif | ||||
#ifndef NOFIFO | |||||
if (fifofd != -1) | |||||
close(fifofd); | |||||
#endif | |||||
return opt; | return opt; | ||||
} | } |