README.md | 6 ++++--
plugins/README.md | 6 ++++++
src/nnn.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++------
src/nnn.h | 3 +++
diff --git a/README.md b/README.md
index 7219b6f54a4a400f41f0b9991ee79c3c79007236..f069ff3801dfd29b5d32bccb987c1acff694553a 100644
--- a/README.md
+++ b/README.md
@@ -113,6 +113,7 @@ - Hex viewer
- and more...
- Convenience
- Needs minimal configuration
+ - Plugin keybinds
- Select files across dirs; all/range selection
- Copy, move, delete, archive, link selection
- Batch rename selection or dir entries
@@ -216,6 +217,7 @@
| Example `export` | Description |
| --- | --- |
| `NNN_BMS='d:~/Documents;D:~/Docs archive/'` | specify bookmarks (max 10) |
+| `NNN_PLUG='fzy-open;mocplay;nmount;thumb'` | plugins to run with xN |
| `NNN_USE_EDITOR=1` | open text files in `$VISUAL` (else `$EDITOR`, fallback vi) |
| `NNN_CONTEXT_COLORS='1234'` | specify per context color [default: '4444' (all blue)] |
| `NNN_SSHFS_OPTS='sshfs -o reconnect,idmap=user'` | specify SSHFS options |
@@ -286,8 +288,8 @@ ORDER TOGGLES
^J du E Extn S Apparent du
^W Random s Size t Time modified
MISC
- ! ^] Spawn SHELL C Execute entry
- R ^V Pick plugin L Lock terminal
+ ! ^] Shell L Lock C Execute entry
+ R ^V Pick plugin xN Run plugin N
c SSHFS mount u Unmount
^P Prompt ^N Note = Launcher
```
diff --git a/plugins/README.md b/plugins/README.md
index 10b7830a46872d5950baced7d4899ebbdb14a9f2..2e7d3b076a1db644408df6d4f3600e6fea3810bb 100644
--- a/plugins/README.md
+++ b/plugins/README.md
@@ -50,6 +50,12 @@ #### Usage
Use the _pick plugin_ shortcut to visit the plugin directory and execute a plugin. Repeating the same shortcut cancels the operation and puts you back in the original directory.
+To run (up to 8) plugins directly with xN:
+
+ export NNN_PLUG='fzy-open;mocplay;ndiff;nmount;viuimg;pdfview'
+
+With this, plugin `fzy-open` can be run with the keybind x1, `mocplay` can be run with x2 and so on...
+
#### Contributing plugins
Plugins are scripts and all scripting languages should work. However, POSIX-compliant shell scripts runnable in `sh` are preferred. If that's too rudimentary for your use case, use Python, Perl or Ruby. Please keep non-portable commands (like `notify-send`) commented so users from any other OS/DE aren't surprised.
diff --git a/src/nnn.c b/src/nnn.c
index 017ebe3eb437713637af83d04de064984b1e16ab..ccdda8ab001acff5862ed754c8bfd4d44b34cee8 100644
--- a/src/nnn.c
+++ b/src/nnn.c
@@ -120,6 +120,7 @@ #define FILTER '/'
#define MSGWAIT '$'
#define REGEX_MAX 48
#define BM_MAX 10
+#define PLUGIN_MAX 8
#define ENTRY_INCR 64 /* Number of dir 'entry' structures to allocate per shot */
#define NAMEBUF_INCR 0x800 /* 64 dir entries at once, avg. 32 chars per filename = 64*32B = 2KB */
#define DESCRIPTOR_LEN 32
@@ -200,6 +201,9 @@ int key;
char *loc;
} bm;
+/* Plugins */
+static char *plug[PLUGIN_MAX] = {NULL};
+
/*
* Settings
* NOTE: update default values if changing order
@@ -279,6 +283,7 @@ static int xlines, xcols;
static uint idle;
static uint idletimeout, copybufpos, copybuflen;
static char *bmstr;
+static char *pluginstr;
static char *opener;
static char *copier;
static char *editor;
@@ -2185,6 +2190,32 @@ DPRINTF_S("Invalid key");
return NULL;
}
+static void parseplugins(void)
+{
+ int i = 0;
+ char *nextplug;
+ char *plugins = getenv("NNN_PLUG");
+
+ if (!plugins || !*plugins)
+ return;
+
+ pluginstr = strdup(plugins);
+ plugins = pluginstr;
+ nextplug = plugins;
+
+ while (*plugins && i < PLUGIN_MAX) {
+ if (plugins == nextplug) {
+ plug[i] = nextplug;
+ ++i;
+ } else if (*plugins == ';') {
+ *plugins = '\0';
+ nextplug = plugins + 1;
+ }
+
+ ++plugins;
+ }
+}
+
static inline void resetdircolor(int flags)
{
if (cfg.dircolor && !(flags & DIR_OR_LINK_TO_DIR)) {
@@ -2804,7 +2835,7 @@ * have increased as we keep adding new options.
*/
static bool show_help(const char *path)
{
- int i = 0, fd;
+ int i, fd;
const char *start, *end;
const char helpstr[] = {
"0\n"
@@ -2835,8 +2866,8 @@ "1ORDER TOGGLES\n"
"b^J du E Extn S Apparent du\n"
"b^W Random s Size t Time modified\n"
"1MISC\n"
- "9! ^] Spawn SHELL C Execute entry\n"
- "9R ^V Pick plugin L Lock terminal\n"
+ "9! ^] Shell L Lock C Execute entry\n"
+ "9R ^V Pick plugin xN Run plugin N\n"
"cc SSHFS mount u Unmount\n"
"b^P Prompt ^N Note = Launcher\n"};
@@ -2860,11 +2891,15 @@ dprintf(fd, "%s free\n\n", coolsize(get_fs_info(path, CAPACITY)));
if (bookmark[0].loc) {
dprintf(fd, "BOOKMARKS\n");
- for (; i < BM_MAX; ++i)
- if (bookmark[i].key)
- dprintf(fd, " %c: %s\n", (char)bookmark[i].key, bookmark[i].loc);
- else
- break;
+ for (i = 0; i < BM_MAX && bookmark[i].key; ++i)
+ dprintf(fd, " %c: %s\n", (char)bookmark[i].key, bookmark[i].loc);
+ dprintf(fd, "\n");
+ }
+
+ if (plug[0]) {
+ dprintf(fd, "PLUGIN KEYS\n");
+ for (i = 0; i < PLUGIN_MAX && plug[i]; ++i)
+ dprintf(fd, " %d: %s\n", i + 1, plug[i]);
dprintf(fd, "\n");
}
@@ -4359,6 +4394,7 @@ goto begin;
}
case SEL_EXEC: // fallthrough
case SEL_SHELL: // fallthrough
+ case SEL_PLUGKEY: // fallthrough
case SEL_PLUGIN: // fallthrough
case SEL_LAUNCH: // fallthrough
case SEL_RUNCMD:
@@ -4370,6 +4406,7 @@ break;
case SEL_SHELL:
spawn(shell, NULL, NULL, path, F_CLI);
break;
+ case SEL_PLUGKEY: // fallthrough
case SEL_PLUGIN:
if (!plugindir) {
printwait("plugins dir missing", &presel);
@@ -4384,6 +4421,20 @@
/* Must be a directory */
if (!S_ISDIR(sb.st_mode))
break;
+
+ if (sel == SEL_PLUGKEY)
+ {
+ r = get_input("") - '0';
+ if ((r < 1 || r > PLUGIN_MAX) || !plug[r - 1])
+ goto nochange;
+
+ mkpath(plugindir, plug[r - 1], newpath);
+ if (ndents)
+ spawn(newpath, dents[cur].name, NULL, path, F_NORMAL);
+ else
+ spawn(newpath, NULL, NULL, path, F_NORMAL);
+ break;
+ }
cfg.runplugin ^= 1;
if (!cfg.runplugin && rundir[0]) {
@@ -4677,6 +4728,7 @@ free(plugindir);
free(cfgdir);
free(initpath);
free(bmstr);
+ free(pluginstr);
#ifdef DBGMODE
disabledbg();
@@ -4797,6 +4849,8 @@ if (!parsebmstr()) {
fprintf(stderr, "%s\n", env_cfg[NNN_BMS]);
return _FAILURE;
}
+
+ parseplugins();
if (arg) { /* Open a bookmark directly */
if (arg[1] || (initpath = get_bm_loc(NULL, *arg)) == NULL) {
diff --git a/src/nnn.h b/src/nnn.h
index 262cc4e578f194ffeb3898accf104a41a5c56b42..75143741cb944319bf2ffff115a257ee4732bfd8 100644
--- a/src/nnn.h
+++ b/src/nnn.h
@@ -93,6 +93,7 @@ SEL_UMOUNT,
SEL_HELP,
SEL_EXEC,
SEL_SHELL,
+ SEL_PLUGKEY,
SEL_PLUGIN,
SEL_LAUNCH,
SEL_RUNCMD,
@@ -240,6 +241,8 @@ { 'C', SEL_EXEC },
/* Run command */
{ '!', SEL_SHELL },
{ CONTROL(']'), SEL_SHELL },
+ /* Plugin key */
+ { 'x', SEL_PLUGKEY },
/* Run a plugin */
{ 'R', SEL_PLUGIN },
{ CONTROL('V'), SEL_PLUGIN },