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
|
⎵ ^J Select entry r Batch rename
|
||||||
m ^K Sel range, clear M List selection
|
m ^K Sel range, clear M List selection
|
||||||
a Select all K Edit selection
|
a Select all K Edit selection
|
||||||
P Copy selection X Delete selection
|
P Copy selection w Copy selection as
|
||||||
V Move selection ^X Delete entry
|
V Move selection W Move selection as
|
||||||
|
X Delete selection ^X Delete entry
|
||||||
f Create archive T Mount archive
|
f Create archive T Mount archive
|
||||||
^F Extract archive F List archive
|
^F Extract archive F List archive
|
||||||
e Edit in EDITOR p Open in PAGER
|
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 STR_TMPFILE 3
|
||||||
#define NONE_SELECTED 4
|
#define NONE_SELECTED 4
|
||||||
#define UTIL_MISSING 5
|
#define UTIL_MISSING 5
|
||||||
#define MOUNT_FAILED 6
|
#define OPERATION_FAILED 6
|
||||||
|
|
||||||
static const char * const messages[] = {
|
static const char * const messages[] = {
|
||||||
"no traversal",
|
"no traversal",
|
||||||
|
@ -399,7 +399,7 @@ static const char * const messages[] = {
|
||||||
"/.nnnXXXXXX",
|
"/.nnnXXXXXX",
|
||||||
"0 selected",
|
"0 selected",
|
||||||
"missing dep",
|
"missing dep",
|
||||||
"mount failed",
|
"failed!",
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Supported configuration environment variables */
|
/* 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)
|
static bool batch_rename(const char *path)
|
||||||
{
|
{
|
||||||
int fd1, fd2, i;
|
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(name);
|
||||||
DPRINTF_S(newpath);
|
DPRINTF_S(newpath);
|
||||||
if (spawn(cmd, name, newpath, path, F_NORMAL)) {
|
if (spawn(cmd, name, newpath, path, F_NORMAL)) {
|
||||||
printwait(messages[MOUNT_FAILED], presel);
|
printwait(messages[OPERATION_FAILED], presel);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2889,7 +2953,7 @@ static bool sshfs_mount(char *newpath, int *presel)
|
||||||
|
|
||||||
/* Connect to remote */
|
/* Connect to remote */
|
||||||
if (spawn(env, tmp, newpath, NULL, flag)) {
|
if (spawn(env, tmp, newpath, NULL, flag)) {
|
||||||
printwait(messages[MOUNT_FAILED], presel);
|
printwait(messages[OPERATION_FAILED], presel);
|
||||||
return FALSE;
|
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)) {
|
if (spawn(cmd, "-u", newpath, NULL, F_NORMAL)) {
|
||||||
printwait("unmount failed", presel);
|
printwait(messages[OPERATION_FAILED], presel);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2997,8 +3061,9 @@ static void show_help(const char *path)
|
||||||
"9⎵ ^J Select entry r Batch rename\n"
|
"9⎵ ^J Select entry r Batch rename\n"
|
||||||
"9m ^K Sel range, clear M List selection\n"
|
"9m ^K Sel range, clear M List selection\n"
|
||||||
"ca Select all K Edit selection\n"
|
"ca Select all K Edit selection\n"
|
||||||
"cP Copy selection X Delete selection\n"
|
"cP Copy selection w Copy selection as\n"
|
||||||
"cV Move selection ^X Delete entry\n"
|
"cV Move selection W Move selection as\n"
|
||||||
|
"cX Delete selection ^X Delete entry\n"
|
||||||
"cf Create archive T Mount archive\n"
|
"cf Create archive T Mount archive\n"
|
||||||
"b^F Extract archive F List archive\n"
|
"b^F Extract archive F List archive\n"
|
||||||
"ce Edit in EDITOR p Open in PAGER\n"
|
"ce Edit in EDITOR p Open in PAGER\n"
|
||||||
|
@ -4187,7 +4252,7 @@ nochange:
|
||||||
endselection();
|
endselection();
|
||||||
|
|
||||||
if (!batch_rename(path)) {
|
if (!batch_rename(path)) {
|
||||||
printwait("batch rename failed", &presel);
|
printwait(messages[OPERATION_FAILED], &presel);
|
||||||
goto nochange;
|
goto nochange;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -4319,12 +4384,14 @@ nochange:
|
||||||
goto nochange;
|
goto nochange;
|
||||||
case SEL_SELEDIT:
|
case SEL_SELEDIT:
|
||||||
if (!seledit()){
|
if (!seledit()){
|
||||||
printwait("edit failed!", &presel);
|
printwait(messages[OPERATION_FAILED], &presel);
|
||||||
goto nochange;
|
goto nochange;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SEL_CP:
|
case SEL_CP:
|
||||||
case SEL_MV:
|
case SEL_MV:
|
||||||
|
case SEL_CPAS:
|
||||||
|
case SEL_MVAS:
|
||||||
case SEL_RMMUL:
|
case SEL_RMMUL:
|
||||||
{
|
{
|
||||||
endselection();
|
endselection();
|
||||||
|
@ -4341,15 +4408,28 @@ nochange:
|
||||||
case SEL_MV:
|
case SEL_MV:
|
||||||
mvstr(g_buf);
|
mvstr(g_buf);
|
||||||
break;
|
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 */
|
default: /* SEL_RMMUL */
|
||||||
rmmulstr(g_buf);
|
rmmulstr(g_buf);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sel != SEL_CPAS && sel != SEL_MVAS)
|
||||||
spawn("sh", "-c", g_buf, path, F_NORMAL);
|
spawn("sh", "-c", g_buf, path, F_NORMAL);
|
||||||
|
|
||||||
/* Clear selection on move or delete */
|
/* 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;
|
nselected = 0;
|
||||||
selbufpos = 0;
|
selbufpos = 0;
|
||||||
writesel(NULL, 0);
|
writesel(NULL, 0);
|
||||||
|
|
|
@ -82,6 +82,8 @@ enum action {
|
||||||
SEL_SELEDIT,
|
SEL_SELEDIT,
|
||||||
SEL_CP,
|
SEL_CP,
|
||||||
SEL_MV,
|
SEL_MV,
|
||||||
|
SEL_CPAS,
|
||||||
|
SEL_MVAS,
|
||||||
SEL_RMMUL,
|
SEL_RMMUL,
|
||||||
SEL_RM,
|
SEL_RM,
|
||||||
SEL_OPENWITH,
|
SEL_OPENWITH,
|
||||||
|
@ -217,6 +219,10 @@ static struct key bindings[] = {
|
||||||
{ 'P', SEL_CP },
|
{ 'P', SEL_CP },
|
||||||
/* Move from selection buffer */
|
/* Move from selection buffer */
|
||||||
{ 'V', SEL_MV },
|
{ 'V', SEL_MV },
|
||||||
|
/* Copyfrom selection buffer and rename */
|
||||||
|
{ 'w', SEL_CPAS },
|
||||||
|
/* Movefrom selection buffer and rename */
|
||||||
|
{ 'W', SEL_MVAS },
|
||||||
/* Delete from selection buffer */
|
/* Delete from selection buffer */
|
||||||
{ 'X', SEL_RMMUL },
|
{ 'X', SEL_RMMUL },
|
||||||
/* Delete currently selected */
|
/* Delete currently selected */
|
||||||
|
|
Loading…
Reference in a new issue