]> Sergey Matveev's repositories - nnn.git/commitdiff
Use key-plugin pairs for running plugins
authorArun Prakash Jana <engineerarun@gmail.com>
Wed, 14 Aug 2019 14:27:44 +0000 (19:57 +0530)
committerArun Prakash Jana <engineerarun@gmail.com>
Wed, 14 Aug 2019 16:28:18 +0000 (21:58 +0530)
README.md
nnn.1
plugins/README.md
src/nnn.c

index 23b8b44d3542129ca687607dd183f7a58f038b29..22cfcb42ccdaae1088cdc59f1743967cd0fffd58 100644 (file)
--- a/README.md
+++ b/README.md
@@ -62,7 +62,9 @@
 
 `nnn` is a full-featured file manager for low-end devices and the regular desktop. It's extremely light and fast (**[performance](https://github.com/jarun/nnn/wiki/performance)**).
 
-`nnn` is also a disk usage analyzer, a fuzzy app launcher, a batch file renamer and a file picker. Many **[plugins](https://github.com/jarun/nnn/tree/master/plugins)** are available to extend its power. Custom plugins are easy to add. There's an independent [(neo)vim picker plugin](https://github.com/mcchrish/nnn.vim) project.
+`nnn` is also a disk usage analyzer, a fuzzy app launcher, a batch file renamer and a file picker.
+
+Many **[plugins](https://github.com/jarun/nnn/tree/master/plugins)** are available to extend its power. Plugins can be run directly with custom keybinds. There's an independent [(neo)vim picker plugin](https://github.com/mcchrish/nnn.vim) project. Custom plugins are easy to add.
 
 It runs on Linux, macOS, Raspberry Pi, BSD, Cygwin, Linux subsystem for Windows and Termux on Android. `nnn` works seamlessly with DEs and GUI utilities. It's nearly zero-config (with sensible defaults) and can be setup in less than 5 minutes.
 
@@ -216,8 +218,8 @@ Option completion scripts for Bash, Fish and Zsh can be found in respective subd
 
 | 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 <kbd>xN</kbd> |
+| `NNN_BMS='d:~/Documents;D:~/Docs archive/'` | key-bookmark pairs [max 10] |
+| `NNN_PLUG='o:fzy-open;p:mocplay;m:nmount;t:thumb'` | key-plugin pairs (<kbd>x-key</kbd> to run) [max 10] |
 | `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 |
@@ -289,7 +291,7 @@ Press <kbd>?</kbd> in `nnn` to see the list anytime.
            ^W  Random  s  Size   t  Time modified
  MISC
          ! ^]  Shell   L  Lock   C  Execute entry
-         R ^V  Pick plugin      xN  Run plugin N
+         R ^V  Pick plugin      xK  Run plugin key K
             c  SSHFS mount       u  Unmount
            ^P  Prompt  ^N  Note  =  Launcher
 ```
diff --git a/nnn.1 b/nnn.1
index 05f754fe042dab19e104baf13217fcb9ce5810d1..eae9f6d7ecc0f1b461392cdff721a7a675341b3a 100644 (file)
--- a/nnn.1
+++ b/nnn.1
@@ -146,7 +146,15 @@ when dealing with the !, e and p commands respectively. A single combination to
 .Bd -literal
     export NNN_BMS='d:~/Documents;u:/home/user/Cam Uploads;D:~/Downloads/'
 
-    NOTE: Bookmark keys should be single-character to use them in combination with the Leader key.
+    NOTE: To go to a bookmark, press the leader key followed by the bookmark key.
+.Ed
+.Pp
+\fBNNN_PLUG:\fR directly executable plugins as \fIkey_char:location\fR pairs (max 10) separated by
+\fI;\fR:
+.Bd -literal
+    export NNN_PLUG='o:fzy-open;p:mocplay;d:ndiff;m:nmount;t:thumb'
+
+    NOTE: To run a plugin directly, press 'x' followed by the plugin key.
 .Ed
 .Pp
 \fBNNN_USE_EDITOR:\fR use VISUAL (else EDITOR, preferably CLI, fallback vi) to handle text
@@ -201,6 +209,8 @@ files.
 \fBNNN_CP_MV_PROG:\fR show progress of copy, move operations (Linux-only, needs advcpmv).
 .Bd -literal
     export NNN_CP_MV_PROG=1
+
+    NOTE: BSD and macOS users can press '^T' to check the progress.
 .Ed
 .Sh KNOWN ISSUES
 If you are using urxvt you might have to set backspace key to DEC.
index 2e7d3b076a1db644408df6d4f3600e6fea3810bb..182e248511fd91745c88a67ebec46f0a571ad8e0 100644 (file)
@@ -48,13 +48,15 @@ Each script has a _Description_ section which provides more details on what the
 
 #### 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.
+There are 2 ways to run plugins:
 
-To run (up to 8) plugins directly with <kbd>xN</kbd>:
+1. 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.
 
-    export NNN_PLUG='fzy-open;mocplay;ndiff;nmount;viuimg;pdfview'
+2. To run (up to 10) plugins directly with <kbd>x-key</kbd>:
 
-With this, plugin `fzy-open` can be run with the keybind <kbd>x1</kbd>, `mocplay` can be run with <kbd>x2</kbd> and so on...
+       export NNN_PLUG='o:fzy-open;p:mocplay;d:ndiff;m:nmount;t:thumb'
+
+   With this, plugin `fzy-open` can be run with the keybind <kbd>xo</kbd>, `mocplay` can be run with <kbd>xp</kbd> and so on... The key vs. plugin pairs are shown in the help and config screen.
 
 #### Contributing plugins
 
index 1d35f95ac81b5584f56616cfe159ccd3822a3ea4..3c730d45be7813b8b570410414208aa7bdec87e3 100644 (file)
--- a/src/nnn.c
+++ b/src/nnn.c
 #define MSGWAIT '$'
 #define REGEX_MAX 48
 #define BM_MAX 10
-#define PLUGIN_MAX 8
+#define PLUGIN_MAX 10
 #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
@@ -195,14 +195,11 @@ typedef struct entry {
        uchar flags; /* Flags specific to the file */
 } __attribute__ ((aligned(_ALIGNMENT))) *pEntry;
 
-/* Bookmark */
+/* Key-value pairs from env */
 typedef struct {
        int key;
-       char *loc;
-} bm;
-
-/* Plugins */
-static char *plug[PLUGIN_MAX] = {NULL};
+       char *val;
+} kv;
 
 /*
  * Settings
@@ -299,7 +296,8 @@ static struct entry *dents;
 static blkcnt_t ent_blocks;
 static blkcnt_t dir_blocks;
 static ulong num_files;
-static bm bookmark[BM_MAX];
+static kv bookmark[BM_MAX];
+static kv plug[PLUGIN_MAX];
 static size_t g_tmpfplen;
 static uchar g_crc;
 static uchar BLK_SHIFT = 9;
@@ -2113,76 +2111,79 @@ static int xlink(char *suffix, char *path, char *buf, int *presel, int type)
        return count;
 }
 
-static bool parsebmstr(void)
+static bool parsekvpair(kv *kvarr, char **envcpy, const char *cfgstr, uchar maxitems)
 {
        int i = 0;
        char *nextkey;
-       char *bms = getenv(env_cfg[NNN_BMS]);
+       char *ptr = getenv(cfgstr);
 
-       if (!bms || !*bms)
+       if (!ptr || !*ptr)
                return TRUE;
 
-       bmstr = strdup(bms);
-       bms = bmstr;
-       nextkey = bms;
+       *envcpy = strdup(ptr);
+       ptr = *envcpy;
+       nextkey = ptr;
 
-       while (*bms && i < BM_MAX) {
-               if (bms == nextkey) {
-                       bookmark[i].key = *bms;
-                       if (*++bms != ':')
+       while (*ptr && i < maxitems) {
+               if (ptr == nextkey) {
+                       kvarr[i].key = *ptr;
+                       if (*++ptr != ':')
                                return FALSE;
-                       if (*++bms == '\0')
+                       if (*++ptr == '\0')
                                return FALSE;
-                       bookmark[i].loc = bms;
+                       kvarr[i].val = ptr;
                        ++i;
                }
 
-               if (*bms == ';') {
+               if (*ptr == ';') {
                        /* Remove trailing space */
-                       if (i > 0 && *(bms - 1) == '/')
-                               *(bms - 1) = '\0';
+                       if (i > 0 && *(ptr - 1) == '/')
+                               *(ptr - 1) = '\0';
 
-                       *bms = '\0';
-                       nextkey = bms + 1;
+                       *ptr = '\0';
+                       nextkey = ptr + 1;
                }
 
-               ++bms;
+               ++ptr;
        }
 
-       if (i < BM_MAX) {
-               if (*bookmark[i - 1].loc == '\0')
+       if (i < maxitems) {
+               if (*kvarr[i - 1].val == '\0')
                        return FALSE;
-               bookmark[i].key = '\0';
+               kvarr[i].key = '\0';
        }
 
        return TRUE;
 }
 
 /*
- * Get the real path to a bookmark
+ * Get the value corresponding to a key
  *
  * NULL is returned in case of no match, path resolution failure etc.
  * buf would be modified, so check return value before access
  */
-static char *get_bm_loc(char *buf, int key)
+static char *get_kv_val(kv *kvarr, char *buf, int key, uchar max, bool path)
 {
        int r = 0;
 
-       for (; bookmark[r].key && r < BM_MAX; ++r) {
-               if (bookmark[r].key == key) {
-                       if (bookmark[r].loc[0] == '~') {
+       for (; kvarr[r].key && r < max; ++r) {
+               if (kvarr[r].key == key) {
+                       if (!path)
+                               return kvarr[r].val;
+
+                       if (kvarr[r].val[0] == '~') {
                                ssize_t len = strlen(home);
-                               ssize_t loclen = strlen(bookmark[r].loc);
+                               ssize_t loclen = strlen(kvarr[r].val);
 
                                if (!buf)
                                        buf = (char *)malloc(len + loclen);
 
                                xstrlcpy(buf, home, len + 1);
-                               xstrlcpy(buf + len, bookmark[r].loc + 1, loclen);
+                               xstrlcpy(buf + len, kvarr[r].val + 1, loclen);
                                return buf;
                        }
 
-                       return realpath(bookmark[r].loc, buf);
+                       return realpath(kvarr[r].val, buf);
                }
        }
 
@@ -2190,32 +2191,6 @@ static char *get_bm_loc(char *buf, int 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)) {
@@ -2825,6 +2800,14 @@ static void lock_terminal(void)
        spawn(tmp, NULL, NULL, NULL, F_NORMAL);
 }
 
+static void printkv(kv *kvarr, int fd, uchar max)
+{
+       uchar i = 0;
+
+       for (; i < max && kvarr[i].key; ++i)
+               dprintf(fd, " %c: %s\n", (char)kvarr[i].key, kvarr[i].val);
+}
+
 /*
  * The help string tokens (each line) start with a HEX value
  * which indicates the number of spaces to print before the
@@ -2867,7 +2850,7 @@ static bool show_help(const char *path)
                 "b^W  Random  s  Size   t  Time modified\n"
                "1MISC\n"
               "9! ^]  Shell   L  Lock   C  Execute entry\n"
-              "9R ^V  Pick plugin      xN  Run plugin N\n"
+              "9R ^V  Pick plugin      xK  Run plugin key K\n"
                  "cc  SSHFS mount       u  Unmount\n"
                 "b^P  Prompt  ^N  Note  =  Launcher\n"};
 
@@ -2889,24 +2872,22 @@ static bool show_help(const char *path)
        dprintf(fd, "\nVOLUME: %s of ", coolsize(get_fs_info(path, FREE)));
        dprintf(fd, "%s free\n\n", coolsize(get_fs_info(path, CAPACITY)));
 
-       if (bookmark[0].loc) {
+       if (bookmark[0].val) {
                dprintf(fd, "BOOKMARKS\n");
-               for (i = 0; i < BM_MAX && bookmark[i].key; ++i)
-                       dprintf(fd, " %c: %s\n", (char)bookmark[i].key, bookmark[i].loc);
+               printkv(bookmark, fd, BM_MAX);
                dprintf(fd, "\n");
        }
 
-       if (plug[0]) {
+       if (plug[0].val) {
                dprintf(fd, "PLUGIN KEYS\n");
-               for (i = 0; i < PLUGIN_MAX && plug[i]; ++i)
-                       dprintf(fd, " %d: %s\n", i + 1, plug[i]);
+               printkv(plug, fd, PLUGIN_MAX);
                dprintf(fd, "\n");
        }
 
        for (i = NNN_OPENER; i <= NNN_TRASH; ++i) {
                start = getenv(env_cfg[i]);
                if (start)
-                               dprintf(fd, "%s: %s\n", env_cfg[i], start);
+                       dprintf(fd, "%s: %s\n", env_cfg[i], start);
        }
 
        if (g_cppath)
@@ -3801,7 +3782,7 @@ nochange:
                                goto begin;
                        }
 
-                       if (!get_bm_loc(newpath, fd)) {
+                       if (!get_kv_val(bookmark, newpath, fd, BM_MAX, TRUE)) {
                                printwait(messages[STR_INVBM_KEY], &presel);
                                goto nochange;
                        }
@@ -4424,11 +4405,12 @@ nochange:
 
                                if (sel == SEL_PLUGKEY)
                                {
-                                       r = get_input("") - '0';
-                                       if ((r < 1 || r > PLUGIN_MAX) || !plug[r - 1])
+                                       r = get_input("");
+                                       tmp = get_kv_val(plug, NULL, r, PLUGIN_MAX, FALSE);
+                                       if (!tmp)
                                                goto nochange;
 
-                                       mkpath(plugindir, plug[r - 1], newpath);
+                                       mkpath(plugindir, tmp, newpath);
                                        if (ndents)
                                                spawn(newpath, dents[cur].name, NULL, path, F_NORMAL);
                                        else
@@ -4845,15 +4827,19 @@ int main(int argc, char *argv[])
        DPRINTF_S(opener);
 
        /* Parse bookmarks string */
-       if (!parsebmstr()) {
+       if (!parsekvpair(bookmark, &bmstr, env_cfg[NNN_BMS], BM_MAX)) {
                fprintf(stderr, "%s\n", env_cfg[NNN_BMS]);
                return _FAILURE;
        }
 
-       parseplugins();
+       /* Parse plugins string */
+       if (!parsekvpair(plug, &pluginstr, "NNN_PLUG", PLUGIN_MAX)) {
+               fprintf(stderr, "%s\n", "NNN_PLUG");
+               return _FAILURE;
+       }
 
        if (arg) { /* Open a bookmark directly */
-               if (arg[1] || (initpath = get_bm_loc(NULL, *arg)) == NULL) {
+               if (arg[1] || (initpath = get_kv_val(bookmark, NULL, *arg, BM_MAX, TRUE)) == NULL) {
                        fprintf(stderr, "%s\n", messages[STR_INVBM_KEY]);
                        return _FAILURE;
                }