mirror of
https://github.com/jarun/nnn.git
synced 2024-11-28 05:41:31 +00:00
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()
This commit is contained in:
parent
04cba31128
commit
b9d183db26
|
@ -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
|
||||
|
|
100
src/nnn.c
100
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;
|
||||
}
|
||||
|
||||
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 */
|
||||
|
|
Loading…
Reference in a new issue