]> Sergey Matveev's repositories - nnn.git/commitdiff
Added copy/move-as (copy/move and rename) (#356)
authorKlzXS <azszwymmvqdi@yahoo.com>
Mon, 14 Oct 2019 16:36:45 +0000 (18:36 +0200)
committerMischievous Meerkat <engineerarun@gmail.com>
Mon, 14 Oct 2019 16:36:45 +0000 (22:06 +0530)
* Added copy/move-as (copy/move and rename)

* Little refactorings

* Also handle selection file for cpmv_rename()

README.md
src/nnn.c
src/nnn.h

index 4dc47363068d821efd85665215a409d2a03ff51c..67ce1430b62007e96c00c7d4adc95c86af661d92 100644 (file)
--- a/README.md
+++ b/README.md
@@ -211,8 +211,9 @@ The list below is from the **dev branch**. Press <kbd>?</kbd> in `nnn` to see th
          ⎵ ^J  Select entry      r  Batch rename
          m ^K  Sel range, clear  M  List selection
             a  Select all        K  Edit selection
-            P  Copy selection    X  Delete selection
-            V  Move selection   ^X  Delete entry
+            P  Copy selection    w  Copy selection as
+            V  Move selection    W  Move selection as
+            X  Delete selection ^X  Delete entry
             f  Create archive    T  Mount archive
            ^F  Extract archive   F  List archive
             e  Edit in EDITOR    p  Open in PAGER
index b18f3d79164c15e2409c3e963d1c791676d054da..093cc37e9e52b0c05c4571345e6cc8bcbc004f4f 100644 (file)
--- a/src/nnn.c
+++ b/src/nnn.c
@@ -390,7 +390,7 @@ static char mv[] = "mvg -gi";
 #define STR_TMPFILE 3
 #define NONE_SELECTED 4
 #define UTIL_MISSING 5
-#define MOUNT_FAILED 6
+#define OPERATION_FAILED 6
 
 static const char * const messages[] = {
        "no traversal",
@@ -399,7 +399,7 @@ static const char * const messages[] = {
        "/.nnnXXXXXX",
        "0 selected",
        "missing dep",
-       "mount failed",
+       "failed!",
 };
 
 /* Supported configuration environment variables */
@@ -1280,6 +1280,70 @@ static void xrm(char *path)
        }
 }
 
+static bool cpmv_rename(const char *path, const char *cmd)
+{
+       int fd, i;
+       uint count = 0, lines = 0;
+       bool ret = FALSE;
+       const char formatcmd[] = "sed -i 's|^\\(\\(.*/\\)\\(.*\\)$\\)|#\\1\\n\\3|' %s";
+       const char renamecmd[] =
+               "sed 's|^\\([^#][^/]\\?.*\\)$|%s/\\1|;s|^#\\(/.*\\)$|\\1|' %s | tr '\\n' '\\0' | xargs -0 -o -n2 %s";
+       char buf[sizeof(renamecmd) + sizeof(cmd) + (PATH_MAX << 1)];
+
+       if ((fd = create_tmp_file()) == -1)
+               return ret;
+
+       /* selsafe() returned TRUE for this to be called */
+       if (!selbufpos) {
+               snprintf(buf, sizeof(buf), "cat %s | tr '\\0' '\\n' > %s", g_selpath, g_tmpfpath);
+               spawn("sh", "-c", buf, NULL, F_NORMAL | F_CMD);
+
+               while ((i = read(fd, buf, sizeof(buf))) > 0)
+                       while(i)
+                               count += (buf[--i] == '\n');
+
+               if (!count)
+                       goto finish;
+       } else {
+               seltofile(fd, &count);
+       }
+
+       close(fd);
+
+       snprintf(buf, sizeof(buf), formatcmd, g_tmpfpath);
+       spawn("sh", "-c", buf, path, F_NORMAL);
+
+       spawn(editor, g_tmpfpath, NULL, path, F_CLI);
+
+       if ((fd = open(g_tmpfpath, O_RDONLY)) == -1)
+               goto finish;
+
+       while ((i = read(fd, buf, sizeof(buf))) > 0)
+               while (i)
+                       lines += (buf[--i] == '\n');
+
+       if (i < 0)
+               goto finish;
+
+       DPRINTF_U(count);
+       DPRINTF_U(lines);
+
+       if (2 * count != lines) {
+               DPRINTF_S("cannot delete files");
+               goto finish;
+       }
+
+       snprintf(buf, sizeof(buf), renamecmd, path, g_tmpfpath, cmd);
+       spawn("sh", "-c", buf, path, F_NORMAL);
+       ret = TRUE;
+
+finish:
+       if (fd >= 0)
+               close(fd);
+
+       return ret;
+}
+
 static bool batch_rename(const char *path)
 {
        int fd1, fd2, i;
@@ -2847,7 +2911,7 @@ static bool archive_mount(char *name, char *path, char *newpath, int *presel)
        DPRINTF_S(name);
        DPRINTF_S(newpath);
        if (spawn(cmd, name, newpath, path, F_NORMAL)) {
-               printwait(messages[MOUNT_FAILED], presel);
+               printwait(messages[OPERATION_FAILED], presel);
                return FALSE;
        }
 
@@ -2889,7 +2953,7 @@ static bool sshfs_mount(char *newpath, int *presel)
 
        /* Connect to remote */
        if (spawn(env, tmp, newpath, NULL, flag)) {
-               printwait(messages[MOUNT_FAILED], presel);
+               printwait(messages[OPERATION_FAILED], presel);
                return FALSE;
        }
 
@@ -2939,7 +3003,7 @@ static bool unmount(char *name, char *newpath, int *presel, char *currentpath)
        }
 
        if (spawn(cmd, "-u", newpath, NULL, F_NORMAL)) {
-               printwait("unmount failed", presel);
+               printwait(messages[OPERATION_FAILED], presel);
                return FALSE;
        }
 
@@ -2997,8 +3061,9 @@ static void show_help(const char *path)
               "9⎵ ^J  Select entry      r  Batch rename\n"
               "9m ^K  Sel range, clear  M  List selection\n"
                  "ca  Select all        K  Edit selection\n"
-                 "cP  Copy selection    X  Delete selection\n"
-                 "cV  Move selection   ^X  Delete entry\n"
+                 "cP Copy selection     w  Copy selection as\n"
+                 "cV Move selection     W  Move selection as\n"
+                 "cX Delete selection  ^X  Delete entry\n"
                  "cf  Create archive    T  Mount archive\n"
                 "b^F  Extract archive   F  List archive\n"
                  "ce  Edit in EDITOR    p  Open in PAGER\n"
@@ -4187,7 +4252,7 @@ nochange:
                                endselection();
 
                                if (!batch_rename(path)) {
-                                       printwait("batch rename failed", &presel);
+                                       printwait(messages[OPERATION_FAILED], &presel);
                                        goto nochange;
                                }
                                break;
@@ -4319,12 +4384,14 @@ nochange:
                        goto nochange;
                case SEL_SELEDIT:
                        if (!seledit()){
-                               printwait("edit failed!", &presel);
+                               printwait(messages[OPERATION_FAILED], &presel);
                                goto nochange;
                        }
                        break;
                case SEL_CP:
                case SEL_MV:
+               case SEL_CPAS:
+               case SEL_MVAS:
                case SEL_RMMUL:
                {
                        endselection();
@@ -4341,15 +4408,28 @@ nochange:
                        case SEL_MV:
                                mvstr(g_buf);
                                break;
+                       case SEL_CPAS:
+                               if (!cpmv_rename(path, cp)) {
+                                       printwait(messages[OPERATION_FAILED], &presel);
+                                       goto nochange;
+                               }
+                               break;
+                       case SEL_MVAS:
+                               if (!cpmv_rename(path, mv)) {
+                                       printwait(messages[OPERATION_FAILED], &presel);
+                                       goto nochange;
+                               }
+                               break;
                        default: /* SEL_RMMUL */
                                rmmulstr(g_buf);
                                break;
                        }
 
-                       spawn("sh", "-c", g_buf, path, F_NORMAL);
+                       if (sel != SEL_CPAS && sel != SEL_MVAS)
+                               spawn("sh", "-c", g_buf, path, F_NORMAL);
 
                        /* Clear selection on move or delete */
-                       if (sel == SEL_MV || sel == SEL_RMMUL) {
+                       if (sel == SEL_MV || sel == SEL_MVAS || sel == SEL_RMMUL) {
                                nselected = 0;
                                selbufpos = 0;
                                writesel(NULL, 0);
index 2933d26437bf46eeb27a16a5dc7a6934e85de644..b6f4886fc7cbe39ad7b5d368a32f018966de7900 100644 (file)
--- a/src/nnn.h
+++ b/src/nnn.h
@@ -82,6 +82,8 @@ enum action {
        SEL_SELEDIT,
        SEL_CP,
        SEL_MV,
+       SEL_CPAS,
+       SEL_MVAS,
        SEL_RMMUL,
        SEL_RM,
        SEL_OPENWITH,
@@ -217,6 +219,10 @@ static struct key bindings[] = {
        { 'P',            SEL_CP },
        /* Move from selection buffer */
        { 'V',            SEL_MV },
+       /* Copyfrom selection buffer and rename */
+       { 'w',            SEL_CPAS },
+       /* Movefrom selection buffer and rename */
+       { 'W',            SEL_MVAS },
        /* Delete from selection buffer */
        { 'X',            SEL_RMMUL },
        /* Delete currently selected */