diff options
| author | 2019-10-14 18:36:45 +0200 | |
|---|---|---|
| committer | 2019-10-14 22:06:45 +0530 | |
| commit | b9d183db26956cc1a3e1260dabd5c40d9ad2e8b4 (patch) | |
| tree | 1eded00dad28feae173a8b3d49f9571d90a3e97a /src | |
| parent | 04cba311284be91990057242409443159bd3a77c (diff) | |
| download | nnn-b9d183db26956cc1a3e1260dabd5c40d9ad2e8b4.tar.gz | |
Added copy/move-as (copy/move and rename) (#356)
* Added copy/move-as (copy/move and rename)
* Little refactorings
* Also handle selection file for cpmv_rename()
Diffstat (limited to 'src')
| -rw-r--r-- | src/nnn.c | 102 | ||||
| -rw-r--r-- | src/nnn.h | 6 |
2 files changed, 97 insertions, 11 deletions
@@ -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); @@ -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 */ |