mirror of
https://github.com/jarun/nnn.git
synced 2024-11-28 05:41:31 +00:00
Support link creation
This commit is contained in:
parent
90597f0e41
commit
8ff56d2c74
|
@ -96,6 +96,7 @@ It runs on Linux, macOS, Raspberry Pi, BSD, Cygwin, Linux subsystem for Windows
|
||||||
- Create, rename files and directories
|
- Create, rename files and directories
|
||||||
- Select files across directories
|
- Select files across directories
|
||||||
- Copy, move, delete selection
|
- Copy, move, delete selection
|
||||||
|
- Create sym/hard link(s) to selection
|
||||||
- Transfer files using lftp
|
- Transfer files using lftp
|
||||||
- Batch rename/move/delete (needs vidir)
|
- Batch rename/move/delete (needs vidir)
|
||||||
- Show directories in custom color (default: blue)
|
- Show directories in custom color (default: blue)
|
||||||
|
@ -226,7 +227,7 @@ Press <kbd>?</kbd> in `nnn` to see the list anytime.
|
||||||
^G Quit and cd q Quit context
|
^G Quit and cd q Quit context
|
||||||
Q, ^Q Quit ? Help, config
|
Q, ^Q Quit ? Help, config
|
||||||
FILES
|
FILES
|
||||||
^O Open with... n Create new
|
^O Open with... n Create new/link
|
||||||
D File details ^R Rename entry
|
D File details ^R Rename entry
|
||||||
⎵, ^K Copy entry path r Open dir in vidir
|
⎵, ^K Copy entry path r Open dir in vidir
|
||||||
Y, ^Y Toggle selection y List selection
|
Y, ^Y Toggle selection y List selection
|
||||||
|
|
2
nnn.1
2
nnn.1
|
@ -89,7 +89,7 @@ FILES
|
||||||
.It Ic ^O
|
.It Ic ^O
|
||||||
Open with an application (takes 1 combined argument)
|
Open with an application (takes 1 combined argument)
|
||||||
.It Ic n
|
.It Ic n
|
||||||
Create a new file or directory
|
Create a new file, directory or link(s) to selection
|
||||||
.It Ic D
|
.It Ic D
|
||||||
Show entry details
|
Show entry details
|
||||||
.It Ic ^R
|
.It Ic ^R
|
||||||
|
|
57
src/nnn.c
57
src/nnn.c
|
@ -1469,7 +1469,6 @@ END:
|
||||||
clearprompt();
|
clearprompt();
|
||||||
|
|
||||||
buf[len] = '\0';
|
buf[len] = '\0';
|
||||||
DPRINTF_S(buf);
|
|
||||||
wcstombs(g_buf + ((NAME_MAX + 1) << 2), buf, NAME_MAX);
|
wcstombs(g_buf + ((NAME_MAX + 1) << 2), buf, NAME_MAX);
|
||||||
return g_buf + ((NAME_MAX + 1) << 2);
|
return g_buf + ((NAME_MAX + 1) << 2);
|
||||||
}
|
}
|
||||||
|
@ -1496,6 +1495,42 @@ static size_t mkpath(char *dir, char *name, char *out, size_t n)
|
||||||
return (xstrlcpy(out + len, name, n - len) + len);
|
return (xstrlcpy(out + len, name, n - len) + len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Create symbolic/hard link(s) to file(s) in selection list */
|
||||||
|
static int xlink(char *suffix, char *path, char *buf, int type)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
char *pbuf = pcopybuf, *fname;
|
||||||
|
ssize_t pos = 0, len, r;
|
||||||
|
int (*link_fn)(const char *, const char *) = NULL;
|
||||||
|
|
||||||
|
/* Check if selection is empty */
|
||||||
|
if (!copybufpos)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (type == 's') /* symbolic link */
|
||||||
|
link_fn = &symlink;
|
||||||
|
else if (type == 'h') /* hard link */
|
||||||
|
link_fn = &link;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
while (pos < copybufpos) {
|
||||||
|
len = strlen(pbuf);
|
||||||
|
fname = xbasename(pbuf);
|
||||||
|
r = mkpath(path, fname, buf, PATH_MAX);
|
||||||
|
xstrlcpy(buf + r - 1, suffix, PATH_MAX - r - 1);
|
||||||
|
|
||||||
|
r = link_fn(pbuf, buf);
|
||||||
|
if (!r)
|
||||||
|
++count;
|
||||||
|
|
||||||
|
pos += len + 1;
|
||||||
|
pbuf += len + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
static bool parsebmstr()
|
static bool parsebmstr()
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
@ -2105,7 +2140,7 @@ static bool show_help(char *path)
|
||||||
"d^G Quit and cd q Quit context\n"
|
"d^G Quit and cd q Quit context\n"
|
||||||
"aQ, ^Q Quit ? Help, config\n"
|
"aQ, ^Q Quit ? Help, config\n"
|
||||||
"1FILES\n"
|
"1FILES\n"
|
||||||
"d^O Open with... n Create new\n"
|
"d^O Open with... n Create new/link\n"
|
||||||
"eD File details ^R Rename entry\n"
|
"eD File details ^R Rename entry\n"
|
||||||
"a⎵, ^K Copy entry path r Open dir in vidir\n"
|
"a⎵, ^K Copy entry path r Open dir in vidir\n"
|
||||||
"aY, ^Y Toggle selection y List selection\n"
|
"aY, ^Y Toggle selection y List selection\n"
|
||||||
|
@ -3334,7 +3369,7 @@ nochange:
|
||||||
tmp = xreadline(NULL, "open with: ");
|
tmp = xreadline(NULL, "open with: ");
|
||||||
break;
|
break;
|
||||||
case SEL_NEW:
|
case SEL_NEW:
|
||||||
tmp = xreadline(NULL, "name: ");
|
tmp = xreadline(NULL, "name/link suffix: ");
|
||||||
break;
|
break;
|
||||||
default: /* SEL_RENAME */
|
default: /* SEL_RENAME */
|
||||||
tmp = xreadline(dents[cur].name, "");
|
tmp = xreadline(dents[cur].name, "");
|
||||||
|
@ -3426,12 +3461,26 @@ nochange:
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Check if it's a dir or file */
|
/* Check if it's a dir or file */
|
||||||
r = get_input("press 'f'(ile) or 'd'(ir)");
|
r = get_input("create 'f'(ile) / 'd'(ir) / 's'(ym) / 'h'(ard)?");
|
||||||
if (r == 'f') {
|
if (r == 'f') {
|
||||||
r = openat(fd, tmp, O_CREAT, 0666);
|
r = openat(fd, tmp, O_CREAT, 0666);
|
||||||
close(r);
|
close(r);
|
||||||
} else if (r == 'd') {
|
} else if (r == 'd') {
|
||||||
r = mkdirat(fd, tmp, 0777);
|
r = mkdirat(fd, tmp, 0777);
|
||||||
|
} else if (r == 's' || r == 'h') {
|
||||||
|
r = xlink(tmp, path, newpath, r);
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
if (r <= 0) {
|
||||||
|
printmsg("none created");
|
||||||
|
goto nochange;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cfg.filtermode)
|
||||||
|
presel = FILTER;
|
||||||
|
if (ndents)
|
||||||
|
copycurname();
|
||||||
|
goto begin;
|
||||||
} else {
|
} else {
|
||||||
close(fd);
|
close(fd);
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in a new issue