]> Sergey Matveev's repositories - nnn.git/commitdiff
Support config dir ~/.config/nnn
authorArun Prakash Jana <engineerarun@gmail.com>
Sun, 21 Apr 2019 18:29:51 +0000 (23:59 +0530)
committerArun Prakash Jana <engineerarun@gmail.com>
Sun, 21 Apr 2019 18:29:51 +0000 (23:59 +0530)
README.md
nnn.1
plugins/README.md
plugins/kdeconnect
plugins/ndiff
scripts/clipboard-copier/copier
src/nnn.c

index 98b02d9e979dc9698c0dbd8cf47a9b6f7c46cf41..1aa4e8ebffef5305da76183fd71ad151a57711c3 100644 (file)
--- a/README.md
+++ b/README.md
@@ -320,11 +320,7 @@ Selected files are visually indicated by a `+`.
 
 The selection can now be listed, copied, moved, removed, archived or linked.
 
-File paths are copied to the temporary file `DIR/.nnncp`, where `DIR` (by priority) is:
-
-    $HOME or,
-    /tmp
-    $TMPDIR or,
+File paths are copied to the temporary file `~/.config/nnn/.selection`.
 
 The path is shown in the help and configuration screen.
 
@@ -379,7 +375,6 @@ The following indicators are used in the detail view:
 | `NNN_CONTEXT_COLORS='1234'` | specify per context color [default: '4444' (all blue)] |
 | `NNN_IDLE_TIMEOUT=300` | idle seconds before locking terminal [default: disabled] |
 | `NNN_COPIER='/absolute/path/to/copier'` | system clipboard copier script [default: none] |
-| `NNN_PLUGIN_DIR=/home/user/nnn-plugins` | absolute path to plugins dir |
 | `NNN_NOTE=/home/user/Dropbox/notes` | path to note file [default: none] |
 | `NNN_TMPFILE=/tmp/nnn` | file to write current open dir path to for cd on quit |
 | `NNN_SSHFS_MNT_ROOT=/home/user/.netmnt` | absolute path to SSHFS mount point root |
@@ -426,11 +421,9 @@ To lookup keyboard shortcuts at runtime, press <kbd>?</kbd>.
 
 `nnn` can invoke plugins in the current directory (`$PWD` for the plugin) with the currently selected file name as the argument.
 
-Copy the plugins of your interest from the [plugins](https://github.com/jarun/nnn/tree/master/plugins) directory and let `nnn` know the location:
-
-    export NNN_PLUGIN_DIR=/absolute/path/to/plugins_dir
+Copy the [plugins](https://github.com/jarun/nnn/tree/master/plugins) of your interest to `~/.config/nnn/plugins`.
 
-Use the pick plugin shortcut to visit the plugin directory and pick a plugin. Repeating the same shortcut cancels the operation and puts you back in the original directory.
+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.
 
 If you have an interesting plugin feel free to raise a PR.
 
diff --git a/nnn.1 b/nnn.1
index f21ea14a6ee624d5b7dffafd45a279d63629c376..cc283063ee014617e08a6d9a232bf62d212c43d2 100644 (file)
--- a/nnn.1
+++ b/nnn.1
@@ -169,16 +169,10 @@ when dealing with the !, e and p commands respectively. A single combination to
 .Pp
 \fBNNN_COPIER:\fR system clipboard copier script.
 .Bd -literal
-    NOTE: File paths are copied to the tmp file \fBDIR/.nnncp\fR, where 'DIR' (by priority) is:
-    \fI$HOME\fR or, \fI$TMPDIR\fR or, \fI/tmp\fR.
+    NOTE: File paths are copied to the tmp file \fB~/.config/nnn/.selection\fR.
     The path is shown in the help and configuration screen.
 .Ed
 .Pp
-\fBNNN_PLUGIN_DIR:\fR \fIabsolute\fR path to plugin directory. Selected plugin is invoked with currently selected file name as argument 1.
-.Bd -literal
-    export NNN_PLUGIN_DIR=/absolute/path/to/plugins_dir
-.Ed
-.Pp
 \fBNNN_NOTE:\fR \fIabsolute\fR path to a note file.
 .Bd -literal
     export NNN_NOTE='/home/user/.mynotes'
index 236ab00b81012dd772d7377014858683c09b1d76..14541033c82c212b80cc216d5bb29b923c2f4972 100644 (file)
@@ -24,7 +24,7 @@
 Plugins can access:
 - all files in the directory (`nnn` switches to the dir where the plugin is to be run so the dir is `$PWD` for the plugin)
 - the currently highlighted file (the file name is passed as the argument to a plugin)
-- the current selection (by reading the file .nnncp, see the plugin `ndiff`)
+- the current selection (by reading the file `~/.config/nnn/.selection`, see the plugin `ndiff`)
 
 Each script has a _Description_ section which provides more details on what the script does, if applicable.
 
index 0fbafbbd074296c25f072161b379d922f81bf657..a209f55d31c2e61a963b860a8ac9297c6284467f 100755 (executable)
@@ -5,11 +5,13 @@
 # Shell: POSIX compliant
 # Author: juacq97
 
+SELECTION=~/.config/nnn/.selection
+
 id=$(kdeconnect-cli -a --id-only | awk '{print $1}')
-if [ "$(find ~/.nnncp)" ]; then
-    kdeconnect-cli -d "$id" --share "$(cat ~/.nnncp)"
+if [ "$(find "$SELECTION")" ]; then
+    kdeconnect-cli -d "$id" --share "$(cat "$SELECTION")"
 # If you want a system notification, uncomment the next 3 lines.
-#    notify-send -a "Kdeconnect" "Sending $(cat ~/.nnncp)"
+#    notify-send -a "Kdeconnect" "Sending $(cat "$SELECTION")"
 #else
 #    notify-send -a "Kdeconnect" "No file selected"
 fi
index e2f112565d453c195334f5509ffbaa957924c6fb..fad28adbc66c84e9534bdc46a94080a3428c7080 100755 (executable)
@@ -5,4 +5,4 @@
 # Shell: POSIX compliant
 # Author: Arun Prakash Jana
 
-vimdiff $(cat ~/.nnncp | tr '\0' '\n')
+vimdiff $(cat ~/.config/nnn/.selection | tr '\0' '\n')
index 2aec8201203b17d9132fc99483bdbb37f3751d64..e20dcf4706191f795c4a23da0a252e8d935431d4 100755 (executable)
@@ -5,14 +5,16 @@
 # Shell: POSIX compliant
 # Author: Arun Prakash Jana
 
+SELECTION=~/.config/nnn/.selection
+
 # Linux
-cat ~/.nnncp | xargs -0 | xsel -bi
+cat "$SELECTION" | xargs -0 | xsel -bi
 
 # macOS
-# cat ~/.nnncp | xargs -0 | pbcopy
+# cat "$SELECTION" | xargs -0 | pbcopy
 
 # Termux
-# cat /data/data/com.termux/files/home/.nnncp | xargs -0 | termux-clipboard-set
+# cat "$SELECTION" | xargs -0 | termux-clipboard-set
 
 # Cygwin
-# cat ~/.nnncp | xargs -0 | clip
+# cat "$SELECTION" | xargs -0 | clip
index ff2ce82497ec066aa62848a30c8823dc6ab60e3c..91947b6660e7e1c12bb57519bdc22613d90d226c 100644 (file)
--- a/src/nnn.c
+++ b/src/nnn.c
@@ -1,4 +1,5 @@
 /*
+
  * BSD 2-Clause License
  *
  * Copyright (C) 2014-2016, Lazaros Koromilas <lostd@2f30.org>
 #define DESCRIPTOR_LEN 32
 #define _ALIGNMENT 0x10 /* 16-byte alignment */
 #define _ALIGNMENT_MASK 0xF
-#define HOME_LEN_MAX 64
+#define TMP_LEN_MAX 64
 #define CTX_MAX 4
 #define DOT_FILTER_LEN 7
 #define ASCII_MAX 128
@@ -279,6 +280,9 @@ static char *editor;
 static char *pager;
 static char *shell;
 static char *home;
+static char *cfgdir;
+static char *g_cppath;
+static char *plugindir;
 static char *sshfsmnt;
 static blkcnt_t ent_blocks;
 static blkcnt_t dir_blocks;
@@ -302,11 +306,8 @@ static sig_t oldsigtstp;
 /* For use in functions which are isolated and don't return the buffer */
 static char g_buf[CMD_LEN_MAX] __attribute__ ((aligned));
 
-/* Buffer for file path copy file */
-static char g_cppath[PATH_MAX] __attribute__ ((aligned));
-
-/* Buffer to store tmp file path */
-static char g_tmpfpath[HOME_LEN_MAX] __attribute__ ((aligned));
+/* Buffer to store tmp file path to show selection, file stats and help */
+static char g_tmpfpath[TMP_LEN_MAX] __attribute__ ((aligned));
 
 /* Replace-str for xargs on different platforms */
 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
@@ -386,19 +387,18 @@ static const char * const messages[] = {
 #define NNN_CONTEXT_COLORS 2
 #define NNN_IDLE_TIMEOUT 3
 #define NNN_COPIER 4
-#define NNN_PLUGIN_DIR 5
-#define NNN_NOTE 6
-#define NNN_TMPFILE 7
-#define NNN_SSHFS_MNT_ROOT 8
-#define NNNLVL 9 /* strings end here */
-#define NNN_USE_EDITOR 10 /* flags begin here */
-#define NNN_NO_AUTOSELECT 11
-#define NNN_RESTRICT_NAV_OPEN 12
-#define NNN_RESTRICT_0B 13
-#define NNN_OPENER_DETACH 14
-#define NNN_TRASH 15
+#define NNN_NOTE 5
+#define NNN_TMPFILE 6
+#define NNN_SSHFS_MNT_ROOT 7
+#define NNNLVL 8 /* strings end here */
+#define NNN_USE_EDITOR 9 /* flags begin here */
+#define NNN_NO_AUTOSELECT 10
+#define NNN_RESTRICT_NAV_OPEN 11
+#define NNN_RESTRICT_0B 12
+#define NNN_OPENER_DETACH 13
+#define NNN_TRASH 14
 #ifdef __linux__
-#define NNN_OPS_PROG 16
+#define NNN_OPS_PROG 15
 #endif
 
 static const char * const env_cfg[] = {
@@ -407,7 +407,6 @@ static const char * const env_cfg[] = {
        "NNN_CONTEXT_COLORS",
        "NNN_IDLE_TIMEOUT",
        "NNN_COPIER",
-       "NNN_PLUGIN_DIR",
        "NNN_NOTE",
        "NNN_TMPFILE",
        "NNN_SSHFS_MNT_ROOT",
@@ -566,7 +565,7 @@ static void printerr(int linenum)
 {
        exitcurses();
        perror(xitoa(linenum));
-       if (!cfg.picker && g_cppath[0])
+       if (!cfg.picker && g_cppath)
                unlink(g_cppath);
        free(pcopybuf);
        exit(1);
@@ -739,7 +738,7 @@ static char *xbasename(char *path)
 /* Writes buflen char(s) from buf to a file */
 static void writecp(const char *buf, const size_t buflen)
 {
-       if (cfg.pickraw || !*g_cppath)
+       if (cfg.pickraw || !g_cppath)
                return;
 
        FILE *fp = fopen(g_cppath, "w");
@@ -799,7 +798,7 @@ static void showcplist(void)
 
        if (g_tmpfpath[0])
                xstrlcpy(g_tmpfpath + g_tmpfplen - 1, messages[STR_TMPFILE],
-                        HOME_LEN_MAX - g_tmpfplen);
+                        TMP_LEN_MAX - g_tmpfplen);
        else {
                DPRINTF_S(messages[STR_NOHOME_ID]);
                return;
@@ -821,9 +820,9 @@ static void showcplist(void)
 
 static bool cpsafe(void)
 {
-       /* Fail if copy file path not generated */
-       if (!g_cppath[0]) {
-               printmsg("copy file not found");
+       /* Fail if selection file path not generated */
+       if (!g_cppath) {
+               printmsg("selection file not found");
                return FALSE;
        }
 
@@ -833,9 +832,9 @@ static bool cpsafe(void)
                return FALSE;
        }
 
-       /* Fail if copy file path isn't accessible */
+       /* Fail if selection file path isn't accessible */
        if (access(g_cppath, R_OK | W_OK) == -1) {
-               printmsg("check copyfile permission");
+               printmsg("check selection file permission");
                return FALSE;
        }
 
@@ -2263,7 +2262,7 @@ static bool show_stats(const char *fpath, const char *fname, const struct stat *
 
        if (g_tmpfpath[0])
                xstrlcpy(g_tmpfpath + g_tmpfplen - 1, messages[STR_TMPFILE],
-                        HOME_LEN_MAX - g_tmpfplen);
+                        TMP_LEN_MAX - g_tmpfplen);
        else
                return FALSE;
 
@@ -2513,7 +2512,7 @@ static bool show_help(const char *path)
 
        if (g_tmpfpath[0])
                xstrlcpy(g_tmpfpath + g_tmpfplen - 1, messages[STR_TMPFILE],
-                        HOME_LEN_MAX - g_tmpfplen);
+                        TMP_LEN_MAX - g_tmpfplen);
        else {
                printmsg(messages[STR_NOHOME_ID]);
                return FALSE;
@@ -2557,8 +2556,8 @@ static bool show_help(const char *path)
                }
        }
 
-       if (g_cppath[0])
-               dprintf(fd, "COPY FILE: %s\n", g_cppath);
+       if (g_cppath)
+               dprintf(fd, "SELECTION FILE: %s\n", g_cppath);
 
        dprintf(fd, "\nv%s\n%s\n", VERSION, GENERAL_INFO);
        close(fd);
@@ -2713,7 +2712,7 @@ static int dentfill(char *path, struct entry **dents)
 
                dentp = *dents + n;
 
-               /* Copy file name */
+               /* Selection file name */
                dentp->name = (char *)((size_t)pnamebuf + off);
                dentp->nlen = xstrlcpy(dentp->name, namep, NAME_MAX + 1);
                off += dentp->nlen;
@@ -2965,7 +2964,7 @@ static void browse(char *ipath)
        enum action sel;
        bool dir_changed = FALSE;
        struct stat sb;
-       char *path, *lastdir, *lastname, *dir, *tmp, *pluginpath = getenv(env_cfg[NNN_PLUGIN_DIR]);
+       char *path, *lastdir, *lastname, *dir, *tmp;
 
        atexit(dentfree);
 
@@ -3110,9 +3109,9 @@ nochange:
 
                                /* Handle plugin selection mode */
                                if (cfg.runplugin) {
-                                       if (!pluginpath || (cfg.runctx != cfg.curctx)
+                                       if (!plugindir || (cfg.runctx != cfg.curctx)
                                            /* Must be in plugin directory to select plugin */
-                                           || (strcmp(path, pluginpath) != 0))
+                                           || (strcmp(path, plugindir) != 0))
                                                continue;
 
                                        mkpath(path, dents[cur].name, newpath);
@@ -3534,7 +3533,7 @@ nochange:
 
                        if (cfg.copymode) {
                                /*
-                                * Clear the tmp copy path file on first copy.
+                                * Clear the selection file on first copy.
                                 *
                                 * This ensures that when the first file path is
                                 * copied into memory (but not written to tmp file
@@ -3843,8 +3842,9 @@ nochange:
 
                                /* Check if file creation failed */
                                if (r == -1) {
-                                       close(fd);
                                        printwarn();
+                                       presel = MSGWAIT;
+                                       close(fd);
                                        goto nochange;
                                }
                        }
@@ -3867,12 +3867,12 @@ nochange:
                                spawn(shell, NULL, NULL, path, F_CLI);
                                break;
                        case SEL_PLUGIN:
-                               if (!pluginpath) {
-                                       printwait("set NNN_PLUGIN_DIR", &presel);
+                               if (!plugindir) {
+                                       printwait("plugins dir missing", &presel);
                                        goto nochange;
                                }
 
-                               if (stat(pluginpath, &sb) == -1) {
+                               if (stat(plugindir, &sb) == -1) {
                                        printwarn();
                                        presel = MSGWAIT;
                                        goto nochange;
@@ -3888,7 +3888,7 @@ nochange:
                                         * If toggled, and still in the plugin dir,
                                         * switch to original directory
                                         */
-                                       if (strcmp(path, pluginpath) == 0) {
+                                       if (strcmp(path, plugindir) == 0) {
                                                xstrlcpy(path, rundir, PATH_MAX);
                                                xstrlcpy(lastname, runfile, NAME_MAX);
                                                rundir[0] = runfile[0] = '\0';
@@ -3899,11 +3899,11 @@ nochange:
                                }
 
                                /* Check if directory is accessible */
-                               if (!xdiraccess(pluginpath))
+                               if (!xdiraccess(plugindir))
                                        goto nochange;
 
                                xstrlcpy(rundir, path, PATH_MAX);
-                               xstrlcpy(path, pluginpath, PATH_MAX);
+                               xstrlcpy(path, plugindir, PATH_MAX);
                                if (ndents)
                                        xstrlcpy(runfile, dents[cur].name, NAME_MAX);
                                cfg.runctx = cfg.curctx;
@@ -4082,6 +4082,103 @@ static void usage(void)
                "v%s\n%s\n", __func__, VERSION, GENERAL_INFO);
 }
 
+static bool create_dir(const char *path)
+{
+       if (!xdiraccess(path)) {
+               if (errno != ENOENT)
+                       return FALSE;
+
+               if (mkdir(path, 0777) == -1)
+                       return FALSE;
+       }
+
+       return TRUE;
+}
+
+static bool setup_config(void)
+{
+       size_t r, len;
+
+       /* Set up configuration file paths */
+       len = strlen(home) + 1 + 20; /* add length of "/.config/nnn/plugins" */
+       cfgdir = (char *)malloc(len);
+       plugindir = (char *)malloc(len);
+       if (!cfgdir || !plugindir) {
+               xerror();
+               return FALSE;
+       }
+       r = xstrlcpy(cfgdir, home, len);
+       xstrlcpy(cfgdir + r - 1, "/.config/nnn", len - r);
+       DPRINTF_S(cfgdir);
+
+       /* TODO: remove in next release */
+       if (access(cfgdir, F_OK) == -1)
+               fprintf(stdout, "WARNING: selection file is ~/.config/nnn/.selection (see CHANGELOG)\n");
+
+       /* Create ~/.config/nnn */
+       if (!create_dir(cfgdir)) {
+               xerror();
+               return FALSE;
+       }
+
+       xstrlcpy(cfgdir + r + 12 - 1, "/plugins", 9);
+       DPRINTF_S(cfgdir);
+
+       xstrlcpy(plugindir, cfgdir, len);
+       DPRINTF_S(plugindir);
+
+       /* Create ~/.config/nnn/plugins */
+       if (!create_dir(cfgdir)) {
+               xerror();
+               return FALSE;
+       }
+
+       /* Reset to config path */
+       cfgdir[r + 11] = '\0';
+       DPRINTF_S(cfgdir);
+
+       /* Set selection file path */
+       if (!cfg.picker) {
+               /* Length of "/.config/nnn/.selection" */
+               g_cppath = (char *)malloc(len + 3);
+               r = xstrlcpy(g_cppath, cfgdir, len + 3);
+               xstrlcpy(g_cppath + r - 1, "/.selection", 12);
+               DPRINTF_S(g_cppath);
+       }
+
+       return TRUE;
+}
+
+static bool set_tmp_path()
+{
+       char *path;
+
+       if (xdiraccess("/tmp"))
+               g_tmpfplen = xstrlcpy(g_tmpfpath, "/tmp", TMP_LEN_MAX);
+       else {
+               path = getenv("TMPDIR");
+               if (path)
+                       g_tmpfplen = xstrlcpy(g_tmpfpath, path, TMP_LEN_MAX);
+               else {
+                       fprintf(stderr, "set TMPDIR\n");
+                       return FALSE;
+               }
+       }
+
+       return TRUE;
+}
+
+static void cleanup(void)
+{
+       free(g_cppath);
+       free(plugindir);
+       free(cfgdir);
+
+#ifdef DBGMODE
+       disabledbg();
+#endif
+}
+
 int main(int argc, char *argv[])
 {
        char cwd[PATH_MAX] __attribute__ ((aligned));
@@ -4121,7 +4218,7 @@ int main(int argc, char *argv[])
                        else {
                                /* copier used as tmp var */
                                copier = realpath(optarg, g_cppath);
-                               if (!g_cppath[0]) {
+                               if (!g_cppath) {
                                        xerror();
                                        return 1;
                                }
@@ -4170,12 +4267,20 @@ int main(int argc, char *argv[])
 
 #ifdef DBGMODE
        enabledbg();
-       atexit(disabledbg);
 #endif
 
+       atexit(cleanup);
+
        home = getenv("HOME");
+       if (!home) {
+               fprintf(stderr, "set HOME\n");
+               return 1;
+       }
        DPRINTF_S(home);
 
+       if (!setup_config())
+               return 1;
+
        /* Get custom opener, if set */
        opener = xgetenv(env_cfg[NNN_OPENER], utils[OPENER]);
        if (getenv(env_cfg[NNN_OPENER_DETACH]))
@@ -4276,21 +4381,9 @@ int main(int argc, char *argv[])
        if (getenv(env_cfg[NNN_TRASH]))
                cfg.trash = 1;
 
-       /* Prefix for other temporary ops */
-       if (home)
-               g_tmpfplen = xstrlcpy(g_tmpfpath, home, HOME_LEN_MAX);
-       else if (xdiraccess("/tmp"))
-               g_tmpfplen = xstrlcpy(g_tmpfpath, "/tmp", HOME_LEN_MAX);
-       else {
-               copier = getenv("TMPDIR");
-               if (copier)
-                       g_tmpfplen = xstrlcpy(g_tmpfpath, copier, HOME_LEN_MAX);
-       }
-
-       if (!cfg.picker && g_tmpfplen) {
-               xstrlcpy(g_cppath, g_tmpfpath, PATH_MAX);
-               xstrlcpy(g_cppath + g_tmpfplen - 1, "/.nnncp", PATH_MAX - g_tmpfplen);
-       }
+       /* Prefix for temporary files */
+       if (!set_tmp_path())
+               return 1;
 
        /* Get SSHFS mountpoint */
        sshfsmnt = getenv("NNN_SSHFS_MNT_ROOT");
@@ -4365,7 +4458,7 @@ int main(int argc, char *argv[])
                        if (opt != (int)(copybufpos))
                                xerror();
                }
-       } else if (!cfg.picker && g_cppath[0])
+       } else if (!cfg.picker && g_cppath)
                unlink(g_cppath);
 
        /* Free the copy buffer */