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 },