]> Sergey Matveev's repositories - nnn.git/commitdiff
Automagically handle archives
authorArun Prakash Jana <engineerarun@gmail.com>
Sun, 29 Dec 2019 17:51:18 +0000 (23:21 +0530)
committerArun Prakash Jana <engineerarun@gmail.com>
Sun, 29 Dec 2019 17:51:18 +0000 (23:21 +0530)
README.md
nnn.1
plugins/README.md
src/nnn.c
src/nnn.h

index 4c06ef7b6a49aaf836dbfaf6396d7dd33f28d03d..16ccd8bd9841e134d96ed9c7facb769302a94623 100644 (file)
--- a/README.md
+++ b/README.md
@@ -93,7 +93,7 @@ A curses library with wide char support (e.g. ncursesw), libreadline (optional)
 | --- | --- | --- |
 | xdg-open (Linux), open(1) (macOS), cygstart (Cygwin) | base | desktop opener |
 | file, coreutils (cp, mv, rm), xargs | base | file type, copy, move and remove |
-| tar, (un)zip [atool/bsdtar for more formats] | base | create, list, extract tar, gzip, bzip2, zip |
+| tar, (un)zip [atool/bsdtar for more formats] | base | create, list, extract bzip2, (g)zip, tar |
 | archivemount, fusermount(3) | optional | mount, unmount archives |
 | sshfs, [rclone](https://rclone.org/), fusermount(3) | optional | mount, unmount remotes |
 | trash-cli | optional | trash files (default action: rm) |
diff --git a/nnn.1 b/nnn.1
index d4a58e19b0ad30a4705fd738377bf10b8b97f00d..ccf2a9d9aec9fe8d3bce9afefc01582f91453713 100644 (file)
--- a/nnn.1
+++ b/nnn.1
@@ -174,6 +174,13 @@ The minimum file size unit is byte (B). The rest are K, M, G, T, P, E, Z, Y (pow
 The SHELL, EDITOR (VISUAL, if defined) and PAGER environment variables take precedence
 when dealing with the !, e and p commands respectively. A single combination to arguments is supported for SHELL and PAGER.
 .Pp
+\fBNNN_OPENER:\fR specify a custom file opener.
+.Bd -literal
+    export NNN_OPENER=nuke
+
+    NOTE: `nuke` is a file opener available in plugin repository
+.Ed
+.Pp
 \fBNNN_BMS:\fR bookmark string as \fIkey_char:location\fR pairs (max 10) separated by
 \fI;\fR:
 .Bd -literal
@@ -187,7 +194,11 @@ when dealing with the !, e and p commands respectively. A single combination to
 .Bd -literal
     export NNN_PLUG='o:fzopen;p:mocplay;d:diffs;m:nmount;t:imgthumb;i:mediainf'
 
-    NOTE: To run a plugin directly, press \fI:\fR followed by the plugin key.
+    NOTES:
+    1. To run a plugin directly, press \fI;\fR followed by the plugin key
+    2. To skip directory refresh after running a plugin,prefix with \fB-\fR
+
+    export NNN_PLUG='m:-mediainfo'
 .Ed
 .Pp
     To assign keys to arbitrary non-background non-shell-interpreted cli
@@ -198,7 +209,11 @@ when dealing with the !, e and p commands respectively. A single combination to
     NOTES:
     1. Use single quotes for $NNN_PLUG so $nnn is not interpreted
     2. $nnn should be the last argument (IF you want to pass the hovered file name)
-    3. (Again) add \fI_\fR before the command
+    3. (Again) add \fB_\fR before the command
+    4. To disable directory refresh after running a \fIcommand as plugin\fR, prefix the command with \fB-_\fR
+    5. To skip user confirmation after command execution, suffix with \fB*\fR
+
+    export NNN_PLUG='y:-_sync*'
 .Ed
 .Pp
 \fBNNN_USE_EDITOR:\fR use VISUAL (else EDITOR, preferably CLI, fallback vi) to handle text files.
@@ -227,13 +242,6 @@ when dealing with the !, e and p commands respectively. A single combination to
     NOTE: The options must be preceded by `rclone` and max 5 flags are supported.
 .Ed
 .Pp
-\fBNNN_OPENER:\fR specify a custom file opener.
-.Bd -literal
-    export NNN_OPENER=nuke
-
-    NOTE: `nuke` is a file opener available in plugin repository
-.Ed
-.Pp
 \fBNNN_IDLE_TIMEOUT:\fR set idle timeout (in seconds) to invoke terminal locker (default: disabled).
 .Pp
 \fBNNN_TRASH:\fR trash (instead of \fIdelete\fR) files to desktop Trash.
@@ -241,7 +249,7 @@ when dealing with the !, e and p commands respectively. A single combination to
     export NNN_TRASH=1
 .Ed
 .Pp
-\fBNNN:\fR this is a special variable set to the current entry before executing a command from the command prompt or spawning a shell.
+\fBNNN:\fR this is a special variable set to the hovered entry before executing a command from the command prompt or spawning a shell.
 .Sh KNOWN ISSUES
 .Nm
 may not handle keypresses correctly when used with tmux (see issue #104 for more details). Set \fBTERM=xterm-256color\fR to address it.
index 2a1aa5a8addf44bc3a437cce2b200e377e7b3767..2dd02c25065df03a86caeb9b6313472258fe760a 100644 (file)
@@ -81,7 +81,7 @@ Plugins are installed to `${XDG_CONFIG_HOME:-$HOME/.config}/nnn/plugins`. You ca
 
 `nnn` refreshes a directory after running a plugin by key (method 1 above) to reflect any changes by the plugin. To disable this (say while running the `mediainfo` plugin on some filtered files), add a `-` before the plugin name:
 
-    export NNN_PLUG='o:fzopen;m:-mediainfo;p:mocplay;
+    export NNN_PLUG='m:-mediainfo'
 
 Now `nnn` will not refresh the directory after running the `mediainfo` plugin.
 
@@ -99,7 +99,7 @@ Now <kbd>;x</kbd> can be used to make a file executable, <kbd>;g</kbd> can be us
 
 `nnn` waits for user confirmation (the prompt `Press Enter to continue`) after it executes a command as plugin (unlike plugins which can add a `read` to wait). To skip this, add a `*` after the command. For example:
 
-    export NNN_PLUG='x:_chmod +x $nnn;g:_git log;s:_smplayer $nnn*;o:fzopen'
+    export NNN_PLUG='s:_smplayer $nnn*'
 
 Now there will be no prompt after <kbd>;s</kbd>.
 
@@ -108,7 +108,7 @@ Notes:
 1. Use single quotes for `$NNN_PLUG` so `$nnn` is not interpreted
 2. `$nnn` should be the last argument (IF you want to pass the hovered file name)
 3. (_Again_) add `_` before the command
-4. To disable directory refresh after running a command as plugin prefix the command with `-_`
+4. To disable directory refresh after running a _command as plugin_, prefix the command with `-_`
 
 ## Access level of plugins
 
index 250d43ec93fa76f589172959fb10a43f32133d50..57e8fe75d468719890b54553e8cf15c44dfa309c 100644 (file)
--- a/src/nnn.c
+++ b/src/nnn.c
@@ -334,6 +334,7 @@ static kv bookmark[BM_MAX];
 static kv plug[PLUGIN_MAX];
 static uchar g_tmpfplen;
 static uchar blk_shift = BLK_SHIFT_512;
+static regex_t archive_re;
 
 /* Retain old signal handlers */
 #ifdef __linux__
@@ -464,6 +465,7 @@ static char * const utils[] = {
 #define MSG_ARCHIVE_OPTS 34
 #define MSG_PLUGIN_KEYS 35
 #define MSG_BOOKMARK_KEYS 36
+#define MSG_INVALID_REG 37
 
 static const char * const messages[] = {
        "no traversal",
@@ -500,9 +502,10 @@ static const char * const messages[] = {
        "'s'shfs / 'r'clone?",
        "may take a while, try refresh",
        "app name: ",
-       "e'x'tract / 'l'ist / 'm'ount?",
+       "'d'efault, e'x'tract / 'l'ist / 'm'ount?",
        "plugin keys:",
        "bookmark keys:",
+       "invalid regex",
 };
 
 /* Supported configuration environment variables */
@@ -511,9 +514,10 @@ static const char * const messages[] = {
 #define NNN_CONTEXT_COLORS 2
 #define NNN_IDLE_TIMEOUT 3
 #define NNNLVL 4
-#define NNN_PIPE 5 /* strings end here */
-#define NNN_USE_EDITOR 6 /* flags begin here */
-#define NNN_TRASH 7
+#define NNN_PIPE 5
+#define NNN_ARCHIVE 6 /* strings end here */
+#define NNN_USE_EDITOR 7 /* flags begin here */
+#define NNN_TRASH 8
 
 static const char * const env_cfg[] = {
        "NNN_BMS",
@@ -522,6 +526,7 @@ static const char * const env_cfg[] = {
        "NNN_IDLE_TIMEOUT",
        "NNNLVL",
        "NNN_PIPE",
+       "NNN_ARCHIVE",
        "NNN_USE_EDITOR",
        "NNN_TRASH",
 };
@@ -552,6 +557,7 @@ static char mv[] = "mv -i";
 static const char cpmvformatcmd[] = "sed -i 's|^\\(\\(.*/\\)\\(.*\\)$\\)|#\\1\\n\\3|' %s";
 static const char cpmvrenamecmd[] = "sed 's|^\\([^#][^/]\\?.*\\)$|%s/\\1|;s|^#\\(/.*\\)$|\\1|' %s | tr '\\n' '\\0' | xargs -0 -n2 sh -c '%s \"$0\" \"$@\" < /dev/tty'";
 static const char batchrenamecmd[] = "paste -d'\n' %s %s | sed 'N; /^\\(.*\\)\\n\\1$/!p;d' | tr '\n' '\\0' | xargs -0 -n2 mv 2>/dev/null";
+static const char archive_regex[] ="\\.(bz|bz2|gz|tar|taz|tbz|tbz2|tgz|z|zip)$";
 
 /* Event handling */
 #ifdef LINUX_INOTIFY
@@ -599,7 +605,7 @@ static int dentfind(const char *fname, int n);
 static void move_cursor(int target, int ignore_scrolloff);
 static inline bool getutil(char *util);
 static size_t mkpath(const char *dir, const char *name, char *out);
-static char *xgetenv(const char *name, char *fallback);
+static char *xgetenv(const char * const name, char *fallback);
 static void plugscript(const char *plugin, char *newpath, uchar flags);
 
 /* Functions */
@@ -1372,7 +1378,7 @@ static void prompt_run(char *cmd, const char *cur, const char *path)
 }
 
 /* Get program name from env var, else return fallback program */
-static char *xgetenv(const char *name, char *fallback)
+static char *xgetenv(const char * const name, char *fallback)
 {
        char *value = getenv(name);
 
@@ -2090,7 +2096,7 @@ static int filterentries(char *path, char *lastname)
                        case '=': // fallthrough /* Launch app */
                        case ']': // fallthorugh /*Prompt key */
                        case ';': // fallthrough /* Run plugin key */
-                       case ',': // falltrough /* Pin CWD */
+                       case ',': // fallthrough /* Pin CWD */
                        case '?': /* Help and config key, '?' is an invalid regex */
                                if (len == 1)
                                        goto end;
@@ -3480,8 +3486,8 @@ static void show_help(const char *path)
                  "cP  Copy sel here%-10c^Y  Edit sel\n"
                  "cV  Move sel here%-10c^V  Copy/move sel as\n"
                  "cX  Delete sel%-13c^X  Delete entry\n"
-                 "cf  Archive%-16c^F  Archive ops\n"
                  "ce  Edit in EDITOR%-10cp  Open in PAGER\n"
+                 "ci  Archive entry%-0c\n"
                "1ORDER TOGGLES\n"
                  "cS  Disk usage%-14cA  Apparent du\n"
                  "cz  Size%-20ct  Time\n"
@@ -4560,6 +4566,28 @@ nochange:
                                        continue;
                                }
 
+                               if (!regexec(&archive_re, dents[cur].name, 0, NULL, 0)) {
+                                       r = get_input(messages[MSG_ARCHIVE_OPTS]);
+                                       if (r == 'l' || r == 'x') {
+                                               mkpath(path, dents[cur].name, newpath);
+                                               handle_archive(newpath, path, r);
+                                               copycurname();
+                                               goto begin;
+                                       }
+
+                                       fd = FALSE;
+                                       if (r == 'm') {
+                                               if (!archive_mount(dents[cur].name, path, newpath, &presel))
+                                                       fd = MSG_FAILED;
+                                       } else if (r != 'd')
+                                               fd = MSG_INVALID_KEY;
+
+                                       if (r != 'd') {
+                                               fd ? printwait(messages[fd], &presel) : clearprompt();
+                                               goto nochange;
+                                       }
+                               }
+
                                if (!sb.st_size) {
                                        printwait(messages[MSG_EMPTY_FILE], &presel);
                                        goto nochange;
@@ -5324,28 +5352,6 @@ nochange:
                                copycurname();
                        /* Repopulate as directory content may have changed */
                        goto begin;
-               case SEL_ARCHIVEOPS:
-                       if (!ndents)
-                               goto nochange;
-
-                       r = get_input(messages[MSG_ARCHIVE_OPTS]);
-                       if (r == 'l' || r == 'x') {
-                               mkpath(path, dents[cur].name, newpath);
-                               handle_archive(newpath, path, r);
-                               copycurname();
-                               goto begin;
-                       }
-
-                       if (r != 'm') {
-                               printwait(messages[MSG_INVALID_KEY], &presel);
-                               goto nochange;
-                       }
-
-                       if (!archive_mount(dents[cur].name, path, newpath, &presel)) {
-                               printwait(messages[MSG_FAILED], &presel);
-                               goto nochange;
-                       }
-                       // fallthrough
                case SEL_REMOTE:
                        if (sel == SEL_REMOTE && !remote_mount(newpath, &presel))
                                goto nochange;
@@ -5802,6 +5808,13 @@ int main(int argc, char *argv[])
                }
        }
 
+       /* Set archive handling (enveditor used as tmp var) */
+       enveditor = getenv(env_cfg[NNN_ARCHIVE]);
+       if (setfilter(&archive_re, (enveditor ? enveditor : archive_regex))) {
+               fprintf(stderr, "%s\n", messages[MSG_INVALID_REG]);
+               return _FAILURE;
+       }
+
        /* Edit text in EDITOR if opted (and opener is not all-CLI) */
        if (!cfg.cliopener && xgetenv_set(env_cfg[NNN_USE_EDITOR]))
                cfg.useeditor = 1;
@@ -5928,6 +5941,9 @@ int main(int argc, char *argv[])
        } else if (!cfg.picker && g_selpath)
                unlink(g_selpath);
 
+       /* Free the regex */
+       regfree(&archive_re);
+
        /* Free the selection buffer */
        free(pselbuf);
 
index 020c257528b4a58bf2583f187d789cd878c3a95a..17bcb214ce3367dce894e2f4577748b22d607826 100644 (file)
--- a/src/nnn.h
+++ b/src/nnn.h
@@ -87,7 +87,6 @@ enum action {
        SEL_NEW,
        SEL_RENAME,
        SEL_RENAMEMUL,
-       SEL_ARCHIVEOPS,
        SEL_REMOTE,
        SEL_UMOUNT,
        SEL_HELP,
@@ -179,7 +178,7 @@ static struct key bindings[] = {
        /* File details */
        { 'D',            SEL_STATS },
        /* Create archive */
-       { 'f',            SEL_ARCHIVE },
+       { 'i',            SEL_ARCHIVE },
        /* Toggle sort by size */
        { 'z',            SEL_FSIZE },
        /* Sort by apparent size including dir contents */
@@ -226,8 +225,6 @@ static struct key bindings[] = {
        { KEY_F(2),       SEL_RENAME },
        /* Rename contents of current dir */
        { 'r',            SEL_RENAMEMUL },
-       /* Mount an archive */
-       { CONTROL('F'),   SEL_ARCHIVEOPS },
        /* Connect to server over SSHFS */
        { 'c',            SEL_REMOTE },
        /* Disconnect a SSHFS mount point */