mirror of
https://github.com/jarun/nnn.git
synced 2024-11-28 05:41:31 +00:00
Simplify batch rename
This commit is contained in:
parent
93a2d174f0
commit
6ce511cddb
|
@ -105,7 +105,7 @@ It runs on Linux, macOS, Raspberry Pi, BSD, Cygwin, Linux subsystem for Windows
|
||||||
- FreeDesktop compliant trash (needs trash-cli)
|
- FreeDesktop compliant trash (needs trash-cli)
|
||||||
- Plugin repository
|
- Plugin repository
|
||||||
- SSHFS mounts (needs sshfs)
|
- SSHFS mounts (needs sshfs)
|
||||||
- Batch rename
|
- Batch rename selection or dir entries
|
||||||
- Show copy, move progress on Linux (needs avdcpmv)
|
- Show copy, move progress on Linux (needs avdcpmv)
|
||||||
- Per-context directory color (default: blue)
|
- Per-context directory color (default: blue)
|
||||||
- Spawn a shell in the current directory
|
- Spawn a shell in the current directory
|
||||||
|
|
116
src/nnn.c
116
src/nnn.c
|
@ -769,12 +769,20 @@ static void appendfpath(const char *path, const size_t len)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write selected file paths to fd, linefeed separated */
|
/* Write selected file paths to fd, linefeed separated */
|
||||||
static ssize_t selectiontofd(int fd)
|
static ssize_t selectiontofd(int fd, uint *pcount)
|
||||||
{
|
{
|
||||||
uint lastpos = copybufpos - 1;
|
uint lastpos, count = 0;
|
||||||
char *pbuf = pcopybuf;
|
char *pbuf = pcopybuf;
|
||||||
ssize_t pos = 0, len, r;
|
ssize_t pos = 0, len, r;
|
||||||
|
|
||||||
|
if (pcount)
|
||||||
|
*pcount = 0;
|
||||||
|
|
||||||
|
if (!copybufpos)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
lastpos = copybufpos - 1;
|
||||||
|
|
||||||
while (pos <= lastpos) {
|
while (pos <= lastpos) {
|
||||||
len = strlen(pbuf);
|
len = strlen(pbuf);
|
||||||
pos += len;
|
pos += len;
|
||||||
|
@ -789,8 +797,12 @@ static ssize_t selectiontofd(int fd)
|
||||||
pbuf += len + 1;
|
pbuf += len + 1;
|
||||||
}
|
}
|
||||||
++pos;
|
++pos;
|
||||||
|
++count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pcount)
|
||||||
|
*pcount = count;
|
||||||
|
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -808,7 +820,7 @@ static void showcplist(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pos = selectiontofd(fd);
|
pos = selectiontofd(fd, NULL);
|
||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
if (pos && pos == copybufpos)
|
if (pos && pos == copybufpos)
|
||||||
|
@ -1121,78 +1133,79 @@ static void xrm(char *path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rename_selection(const char *path)
|
static bool batch_rename(const char *path)
|
||||||
{
|
{
|
||||||
const char renamecmd[] = "paste -d'\n' %s %s | xargs -d'\n' -n2 mv 2>/dev/null";
|
|
||||||
char buf[sizeof(renamecmd) + 2 * PATH_MAX];
|
|
||||||
char foriginal[TMP_LEN_MAX] = {0};
|
|
||||||
int fd1 = -1, fd2 = -1, i;
|
int fd1 = -1, fd2 = -1, i;
|
||||||
ssize_t len, len2;
|
uint count = 0, lines = 0;
|
||||||
|
bool dir = FALSE, ret = FALSE;
|
||||||
|
const char renamecmd[] = "paste -d'\n' %s %s | xargs -d'\n' -n2 mv 2>/dev/null";
|
||||||
|
char foriginal[TMP_LEN_MAX] = {0};
|
||||||
|
char buf[sizeof(renamecmd) + (PATH_MAX << 1)];
|
||||||
|
|
||||||
if ((fd1 = create_tmp_file()) == -1)
|
if ((fd1 = create_tmp_file()) == -1)
|
||||||
return;
|
return ret;
|
||||||
|
|
||||||
xstrlcpy(foriginal, g_tmpfpath, strlen(g_tmpfpath)+1);
|
xstrlcpy(foriginal, g_tmpfpath, strlen(g_tmpfpath)+1);
|
||||||
|
|
||||||
if ((fd2 = create_tmp_file()) == -1) {
|
if ((fd2 = create_tmp_file()) == -1) {
|
||||||
unlink(foriginal);
|
unlink(foriginal);
|
||||||
close(fd1);
|
close(fd1);
|
||||||
return;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (copybufpos > 0) {
|
if (!copybufpos) {
|
||||||
// Rename selected files with absolute paths:
|
if (!ndents)
|
||||||
selectiontofd(fd1);
|
return TRUE;
|
||||||
if (write(fd1, "\n", 1) < 1)
|
|
||||||
goto finished_renaming;
|
for (i = 0; i < ndents; ++i)
|
||||||
selectiontofd(fd2);
|
appendfpath(dents[i].name, NAME_MAX);
|
||||||
if (write(fd2, "\n", 1) < 1)
|
|
||||||
goto finished_renaming;
|
dir = TRUE;
|
||||||
} else {
|
|
||||||
// If nothing is selected, use the directory contents with relative paths:
|
|
||||||
for (i = 0; i < ndents; ++i) {
|
|
||||||
len = strlen(dents[i].name);
|
|
||||||
if (write(fd1, dents[i].name, len) != len || write(fd1, "\n", 1) != 1)
|
|
||||||
goto finished_renaming;
|
|
||||||
if (write(fd2, dents[i].name, len) != len || write(fd2, "\n", 1) != 1)
|
|
||||||
goto finished_renaming;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
selectiontofd(fd1, &count);
|
||||||
|
selectiontofd(fd2, NULL);
|
||||||
close(fd2);
|
close(fd2);
|
||||||
fd2 = -1;
|
|
||||||
|
if (dir)
|
||||||
|
copybufpos = 0;
|
||||||
|
|
||||||
spawn(editor, g_tmpfpath, NULL, path, F_CLI);
|
spawn(editor, g_tmpfpath, NULL, path, F_CLI);
|
||||||
|
|
||||||
// Check that the number of filenames is unchanged:
|
|
||||||
len = 0, len2 = 0;
|
|
||||||
lseek(fd1, 0, SEEK_SET);
|
|
||||||
while ((i = read(fd1, buf, sizeof(buf))) > 0) {
|
|
||||||
while (i) len += buf[--i] == '\n';
|
|
||||||
}
|
|
||||||
if (i < 0) goto finished_renaming;
|
|
||||||
|
|
||||||
// Reopen file descriptor to get updated contents:
|
// Reopen file descriptor to get updated contents:
|
||||||
if ((fd2 = open(g_tmpfpath, O_RDONLY)) == -1)
|
if ((fd2 = open(g_tmpfpath, O_RDONLY)) == -1)
|
||||||
goto finished_renaming;
|
goto finish;
|
||||||
while ((i = read(fd2, buf, sizeof(buf))) > 0) {
|
|
||||||
while (i) len2 += buf[--i] == '\n';
|
|
||||||
}
|
|
||||||
if (i < 0) goto finished_renaming;
|
|
||||||
|
|
||||||
if (len2 != len) {
|
while ((i = read(fd2, buf, sizeof(buf))) > 0) {
|
||||||
get_input("Error: wrong number of filenames. Press any key to continue...");
|
while (i)
|
||||||
goto finished_renaming;
|
lines += (buf[--i] == '\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < 0)
|
||||||
|
goto finish;
|
||||||
|
|
||||||
|
DPRINTF_U(count);
|
||||||
|
DPRINTF_U(lines);
|
||||||
|
|
||||||
|
if (count != lines) {
|
||||||
|
DPRINTF_S("cannot delete files");
|
||||||
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf), renamecmd, foriginal, g_tmpfpath);
|
snprintf(buf, sizeof(buf), renamecmd, foriginal, g_tmpfpath);
|
||||||
spawn("sh", "-c", buf, path, F_NORMAL);
|
spawn("sh", "-c", buf, path, F_NORMAL);
|
||||||
|
ret = TRUE;
|
||||||
|
|
||||||
finished_renaming:
|
finish:
|
||||||
if (fd2 >= 0) close(fd1);
|
if (fd1 >= 0)
|
||||||
|
close(fd1);
|
||||||
unlink(foriginal);
|
unlink(foriginal);
|
||||||
if (fd2 >= 0) close(fd2);
|
|
||||||
|
if (fd2 >= 0)
|
||||||
|
close(fd2);
|
||||||
unlink(g_tmpfpath);
|
unlink(g_tmpfpath);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void archive_selection(const char *cmd, const char *archive, const char *curpath)
|
static void archive_selection(const char *cmd, const char *archive, const char *curpath)
|
||||||
|
@ -3659,12 +3672,12 @@ nochange:
|
||||||
case SEL_FMEDIA: // fallthrough
|
case SEL_FMEDIA: // fallthrough
|
||||||
case SEL_ARCHIVELS: // fallthrough
|
case SEL_ARCHIVELS: // fallthrough
|
||||||
case SEL_EXTRACT: // fallthrough
|
case SEL_EXTRACT: // fallthrough
|
||||||
case SEL_RENAMEALL: // fallthrough
|
|
||||||
case SEL_RUNEDIT: // fallthrough
|
case SEL_RUNEDIT: // fallthrough
|
||||||
case SEL_RUNPAGE:
|
case SEL_RUNPAGE:
|
||||||
if (!ndents)
|
if (!ndents)
|
||||||
break; // fallthrough
|
break; // fallthrough
|
||||||
case SEL_REDRAW: // fallthrough
|
case SEL_REDRAW: // fallthrough
|
||||||
|
case SEL_RENAMEALL: // fallthrough
|
||||||
case SEL_HELP: // fallthrough
|
case SEL_HELP: // fallthrough
|
||||||
case SEL_NOTE: // fallthrough
|
case SEL_NOTE: // fallthrough
|
||||||
case SEL_LOCK:
|
case SEL_LOCK:
|
||||||
|
@ -3691,7 +3704,10 @@ nochange:
|
||||||
copycurname();
|
copycurname();
|
||||||
goto begin;
|
goto begin;
|
||||||
case SEL_RENAMEALL:
|
case SEL_RENAMEALL:
|
||||||
rename_selection(path);
|
if (!batch_rename(path)) {
|
||||||
|
printwait("batch rename failed", &presel);
|
||||||
|
goto nochange;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case SEL_HELP:
|
case SEL_HELP:
|
||||||
r = show_help(path);
|
r = show_help(path);
|
||||||
|
@ -4635,7 +4651,7 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
if (cfg.pickraw) {
|
if (cfg.pickraw) {
|
||||||
if (copybufpos) {
|
if (copybufpos) {
|
||||||
opt = selectiontofd(1);
|
opt = selectiontofd(1, NULL);
|
||||||
if (opt != (int)(copybufpos))
|
if (opt != (int)(copybufpos))
|
||||||
xerror();
|
xerror();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue