mirror of
https://github.com/jarun/nnn.git
synced 2024-11-28 05:41:31 +00:00
Add rclone support for remote access
This commit is contained in:
parent
c4483a8956
commit
e6f9d6d2d0
|
@ -52,7 +52,7 @@ Add to that an awesome [Wiki](https://github.com/jarun/nnn/wiki)!
|
|||
- Convenience
|
||||
- Run plugins and commands with custom keybinds
|
||||
- FreeDesktop compliant trash (needs trash-cli)
|
||||
- SSHFS mounts (needs sshfs)
|
||||
- Remote mounts (needs sshfs, rclone)
|
||||
- Cross-dir file/all/range selection
|
||||
- Batch rename selection or dir entries
|
||||
- Copy (as), move (as), delete, archive, link selection
|
||||
|
@ -92,7 +92,7 @@ A curses library with wide char support (e.g. ncursesw), libreadline (`make O_NO
|
|||
| file, coreutils (cp, mv, rm), xargs | base | file type, copy, move and remove |
|
||||
| tar, (un)zip [atool/bsdtar for more formats] | base | create, list, extract tar, gzip, bzip2, zip |
|
||||
| archivemount, fusermount(3) | optional | mount, unmount archives |
|
||||
| sshfs, fusermount(3) | optional | mount, unmount remotes |
|
||||
| sshfs, [rclone](https://rclone.org/), fusermount(3) | optional | mount, unmount remotes |
|
||||
| trash-cli | optional | trash files (default action: rm) |
|
||||
| vlock (Linux), bashlock (macOS), lock(1) (BSD) | optional | terminal locker (fallback: [cmatrix](https://github.com/abishekvashok/cmatrix)) |
|
||||
| advcpmv (Linux) ([integration](https://github.com/jarun/nnn/wiki/Advanced-use-cases#show-cp-mv-progress)) | optional | copy, move progress |
|
||||
|
@ -153,6 +153,7 @@ There is no config file. Associated files are stored under `${XDG_CONFIG_HOME:-$
|
|||
| `NNN_USE_EDITOR=1` | open text files in `$VISUAL` (else `$EDITOR`, fallback vi) |
|
||||
| `NNN_CONTEXT_COLORS='1234'` | specify per context color [default: '4444' (all blue)] |
|
||||
| `NNN_SSHFS_OPTS='sshfs -o reconnect,idmap=user'` | specify SSHFS options |
|
||||
| `NNN_RCLONE_OPTS='rclone mount --read-only'` | specify rclone options |
|
||||
| `NNN_IDLE_TIMEOUT=300` | idle seconds to lock terminal [default: disabled] |
|
||||
| `NNN_COPIER=copier` | clipboard copier script [default: none] |
|
||||
| `NNN_TRASH=1` | trash files to the desktop Trash [default: delete] |
|
||||
|
@ -225,7 +226,7 @@ The list below is from the **dev branch**. Press <kbd>?</kbd> in `nnn` to see th
|
|||
! ^] Shell ;K :K xK Execute plugin K
|
||||
C Execute entry R ^V Pick plugin
|
||||
U Manage session = Launch
|
||||
c SSHFS mount u Unmount
|
||||
c Remote mount u Unmount
|
||||
] ^P Prompt/run cmd L Lock
|
||||
```
|
||||
|
||||
|
|
7
nnn.1
7
nnn.1
|
@ -223,6 +223,13 @@ when dealing with the !, e and p commands respectively. A single combination to
|
|||
NOTE: The options must be preceded by `sshfs` and comma-separated without any space between them.
|
||||
.Ed
|
||||
.Pp
|
||||
\fBNNN_RCLONE_OPTS:\fR pass additional options to rclone command:
|
||||
.Bd -literal
|
||||
export NNN_RCLONE_OPTS='rclone mount --read-only --no-checksum'
|
||||
|
||||
NOTE: The options must be preceded by `rclone` and max 5 flags are supported.
|
||||
.Ed
|
||||
.Pp
|
||||
\fBNNN_OPENER:\fR specify a custom file opener.
|
||||
.Bd -literal
|
||||
export NNN_OPENER=mimeopen
|
||||
|
|
83
src/nnn.c
83
src/nnn.c
|
@ -112,7 +112,8 @@
|
|||
#endif
|
||||
|
||||
#define _ABSSUB(N, M) (((N) <= (M)) ? ((M) - (N)) : ((N) - (M)))
|
||||
#define DOUBLECLICK_INTERVAL_NS 400000000
|
||||
#define DOUBLECLICK_INTERVAL_NS (400000000)
|
||||
#define XDELAY_INTERVAL_US (350000) /* 350 ms delay */
|
||||
#define LEN(x) (sizeof(x) / sizeof(*(x)))
|
||||
#undef MIN
|
||||
#define MIN(x, y) ((x) < (y) ? (x) : (y))
|
||||
|
@ -370,6 +371,7 @@ static bool g_plinit = FALSE;
|
|||
#define UTIL_SH_EXEC 8
|
||||
#define UTIL_ARCHIVEMOUNT 9
|
||||
#define UTIL_SSHFS 10
|
||||
#define UTIL_RCLONE 11
|
||||
|
||||
/* Utilities to open files, run actions */
|
||||
static char * const utils[] = {
|
||||
|
@ -396,6 +398,7 @@ static char * const utils[] = {
|
|||
"sh -c",
|
||||
"archivemount",
|
||||
"sshfs",
|
||||
"rclone",
|
||||
};
|
||||
|
||||
/* Common strings */
|
||||
|
@ -438,6 +441,8 @@ static char * const utils[] = {
|
|||
#define MSG_0_FILES 36
|
||||
#define MSG_EXISTS 37
|
||||
#define MSG_FEW_COLOUMNS 38
|
||||
#define MSG_REMOTE_OPTS 39
|
||||
#define MSG_RCLONE_DELAY 40
|
||||
|
||||
static const char * const messages[] = {
|
||||
"no traversal",
|
||||
|
@ -453,12 +458,12 @@ static const char * const messages[] = {
|
|||
"forcibly remove %s file%s (unrecoverable)?",
|
||||
"Create context %d?",
|
||||
"archive sel?",
|
||||
"'f'(ile) / 'd'(ir) / 's'(ym) / 'h'(ard)?",
|
||||
"'f'ile / 'd'ir / 's'ym / 'h'ard?",
|
||||
"cli mode?",
|
||||
"overwrite?",
|
||||
"'s'(ave) / 'l'(oad) / 'r'(estore)?",
|
||||
"'s'ave / 'l'oad / 'r'estore?",
|
||||
"Quit all contexts?",
|
||||
"host: ",
|
||||
"remote name: ",
|
||||
"archive name: ",
|
||||
"open with: ",
|
||||
"relative path: ",
|
||||
|
@ -479,6 +484,8 @@ static const char * const messages[] = {
|
|||
"0 files",
|
||||
"entry exists",
|
||||
"too few columns!",
|
||||
"'s'shfs / 'r'clone?",
|
||||
"rclone mount may take a while"
|
||||
};
|
||||
|
||||
/* Supported configuration environment variables */
|
||||
|
@ -677,10 +684,10 @@ static int get_input(const char *prompt)
|
|||
return r;
|
||||
}
|
||||
|
||||
static void xdelay(void)
|
||||
static void xdelay(useconds_t delay)
|
||||
{
|
||||
refresh();
|
||||
usleep(350000); /* 350 ms delay */
|
||||
usleep(delay);
|
||||
}
|
||||
|
||||
static char confirm_force(bool selection)
|
||||
|
@ -2865,7 +2872,7 @@ static bool load_session(const char *sname, char **path, char **lastdir, char **
|
|||
fsession = fopen(spath, "rb");
|
||||
if (!fsession) {
|
||||
printmsg(messages[MSG_SSN_MISSING]);
|
||||
xdelay();
|
||||
xdelay(XDELAY_INTERVAL_US);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@ -2896,7 +2903,7 @@ END:
|
|||
|
||||
if (!status) {
|
||||
printmsg(messages[MSG_FAILED]);
|
||||
xdelay();
|
||||
xdelay(XDELAY_INTERVAL_US);
|
||||
}
|
||||
|
||||
return status;
|
||||
|
@ -3139,7 +3146,7 @@ static void find_accessible_parent(char *path, char *newpath, char *lastname, in
|
|||
xstrlcpy(path, dir, PATH_MAX);
|
||||
|
||||
printmsg(messages[MSG_DIR_ACCESS]);
|
||||
xdelay();
|
||||
xdelay(XDELAY_INTERVAL_US);
|
||||
}
|
||||
|
||||
static bool execute_file(int cur, char *path, char *newpath, int *presel)
|
||||
|
@ -3263,11 +3270,23 @@ static bool archive_mount(char *name, char *path, char *newpath, int *presel)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static bool sshfs_mount(char *newpath, int *presel)
|
||||
static bool remote_mount(char *newpath, int *presel)
|
||||
{
|
||||
uchar flag = F_NORMAL;
|
||||
int r;
|
||||
char *tmp, *env, *cmd = utils[UTIL_SSHFS];
|
||||
uchar flag = F_CLI;
|
||||
int r, opt = get_input(messages[MSG_REMOTE_OPTS]);
|
||||
char *tmp, *env, *cmd;
|
||||
|
||||
if (opt == 's') {
|
||||
cmd = utils[UTIL_SSHFS];
|
||||
env = xgetenv("NNN_SSHFS_OPTS", cmd);
|
||||
} else if (opt == 'r') {
|
||||
flag |= F_NOWAIT;
|
||||
cmd = utils[UTIL_RCLONE];
|
||||
env = xgetenv("NNN_RCLONE_OPTS", "rclone mount");
|
||||
} else {
|
||||
printwait(messages[MSG_FAILED], presel);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!getutil(cmd)) {
|
||||
printwait(messages[MSG_UTIL_MISSING], presel);
|
||||
|
@ -3287,19 +3306,21 @@ static bool sshfs_mount(char *newpath, int *presel)
|
|||
|
||||
/* Convert "Host" to "Host:" */
|
||||
r = strlen(tmp);
|
||||
tmp[r] = ':';
|
||||
tmp[r + 1] = '\0';
|
||||
|
||||
env = getenv("NNN_SSHFS_OPTS");
|
||||
if (env)
|
||||
flag |= F_MULTI;
|
||||
else
|
||||
env = cmd;
|
||||
if (tmp[r - 1] != ':') { /* Append ':' if missing */
|
||||
tmp[r] = ':';
|
||||
tmp[r + 1] = '\0';
|
||||
}
|
||||
|
||||
/* Connect to remote */
|
||||
if (spawn(env, tmp, newpath, NULL, flag)) {
|
||||
printwait(messages[MSG_FAILED], presel);
|
||||
return FALSE;
|
||||
if (opt == 's') {
|
||||
if (spawn(env, tmp, newpath, NULL, flag)) {
|
||||
printwait(messages[MSG_FAILED], presel);
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
spawn(env, tmp, newpath, NULL, flag);
|
||||
printmsg(messages[MSG_RCLONE_DELAY]);
|
||||
xdelay(XDELAY_INTERVAL_US * 10);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
@ -3311,12 +3332,12 @@ static bool sshfs_mount(char *newpath, int *presel)
|
|||
*/
|
||||
static bool unmount(char *name, char *newpath, int *presel, char *currentpath)
|
||||
{
|
||||
char cmd[] = "fusermount3"; /* Arch Linux utility */
|
||||
static char cmd[] = "fusermount3"; /* Arch Linux utility */
|
||||
static bool found = FALSE;
|
||||
char *tmp = name;
|
||||
struct stat sb, psb;
|
||||
bool child = false;
|
||||
bool parent = false;
|
||||
bool child = FALSE;
|
||||
bool parent = FALSE;
|
||||
|
||||
/* On Ubuntu it's fusermount */
|
||||
if (!found && !getutil(cmd)) {
|
||||
|
@ -4770,7 +4791,7 @@ nochange:
|
|||
inode = sb.st_ino;
|
||||
selstartid = cur;
|
||||
printmsg(messages[MSG_RANGE_SEL_ON]);
|
||||
xdelay();
|
||||
xdelay(XDELAY_INTERVAL_US);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -4815,7 +4836,7 @@ nochange:
|
|||
/* Show the range count */
|
||||
//r = selendid - selstartid + 1;
|
||||
//mvprintw(xlines - 1, 0, "+%d\n", r);
|
||||
//xdelay();
|
||||
//xdelay(XDELAY_INTERVAL_US);
|
||||
|
||||
//writesel(pselbuf, selbufpos - 1); /* Truncate NULL from end */
|
||||
//spawn(copier, NULL, NULL, NULL, F_NOTRACE);
|
||||
|
@ -5167,8 +5188,8 @@ nochange:
|
|||
case SEL_ARCHIVEMNT:
|
||||
if (!ndents || !archive_mount(dents[cur].name, path, newpath, &presel))
|
||||
goto nochange; // fallthrough
|
||||
case SEL_SSHFS:
|
||||
if (sel == SEL_SSHFS && !sshfs_mount(newpath, &presel))
|
||||
case SEL_REMOTE:
|
||||
if (sel == SEL_REMOTE && !remote_mount(newpath, &presel))
|
||||
goto nochange;
|
||||
|
||||
lastname[0] = '\0';
|
||||
|
|
|
@ -90,7 +90,7 @@ enum action {
|
|||
SEL_RENAME,
|
||||
SEL_RENAMEMUL,
|
||||
SEL_ARCHIVEMNT,
|
||||
SEL_SSHFS,
|
||||
SEL_REMOTE,
|
||||
SEL_UMOUNT,
|
||||
SEL_HELP,
|
||||
SEL_EXEC,
|
||||
|
@ -237,7 +237,7 @@ static struct key bindings[] = {
|
|||
/* Mount an archive */
|
||||
{ 'T', SEL_ARCHIVEMNT },
|
||||
/* Connect to server over SSHFS */
|
||||
{ 'c', SEL_SSHFS },
|
||||
{ 'c', SEL_REMOTE },
|
||||
/* Disconnect a SSHFS mount point */
|
||||
{ 'u', SEL_UMOUNT },
|
||||
/* Show help */
|
||||
|
|
Loading…
Reference in a new issue