@@ -62,6 +62,7 @@ Add to that an awesome [Wiki](https://github.com/jarun/nnn/wiki)! | |||
- Batch renamer (feature-limited) for selection or dir | |||
- Copy (as), move (as), delete, archive, link selection | |||
- Notification on cp, mv, rm completion | |||
- Copy file paths to system clipboard on select | |||
- Create (with parents), rename, duplicate (anywhere) files and dirs | |||
- Launch GUI apps, run commands, execute file, spawn a shell | |||
- Hovered file set as `$nnn` at prompt and spawned shell | |||
@@ -162,7 +163,6 @@ There is no config file. Associated files are stored under `${XDG_CONFIG_HOME:-$ | |||
| `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] | | |||
#### Cmdline options | |||
@@ -195,6 +195,7 @@ optional args: | |||
-S du mode | |||
-t disable dir auto-select | |||
-v show version | |||
-x notis, sel to system clipboard | |||
-h show help | |||
``` | |||
@@ -31,6 +31,7 @@ _nnn () | |||
-S | |||
-t | |||
-v | |||
-x | |||
-h | |||
) | |||
if [[ $prev == -b ]]; then | |||
@@ -30,4 +30,5 @@ complete -c nnn -s s -d 'use substring match for filters' | |||
complete -c nnn -s S -d 'start in disk usage analyzer mode' | |||
complete -c nnn -s t -d 'disable dir auto-select' | |||
complete -c nnn -s v -d 'show program version and exit' | |||
complete -c nnn -s x -d 'notis, sel to system clipboard' | |||
complete -c nnn -s h -d 'show program help' |
@@ -28,6 +28,7 @@ args=( | |||
'(-S)-S[start in disk usage analyzer mode]' | |||
'(-t)-t[disable dir auto-select]' | |||
'(-v)-v[show program version and exit]' | |||
'(-x)-x[notis, sel to system clipboard]' | |||
'(-h)-h[show program help]' | |||
'*:filename:_files' | |||
) | |||
@@ -1,23 +0,0 @@ | |||
#!/usr/bin/env sh | |||
# Description: Copy selection to clipboard | |||
# | |||
# Shell: POSIX compliant | |||
# Author: Arun Prakash Jana | |||
SELECTION=${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection | |||
# Linux | |||
xargs -0 < "$SELECTION" | xsel -bi | |||
# macOS | |||
# xargs -0 < "$SELECTION" | pbcopy | |||
# Termux | |||
# xargs -0 < "$SELECTION" | termux-clipboard-set | |||
# Cygwin | |||
# xargs -0 < "$SELECTION" | clip | |||
# Wayland | |||
# xargs -0 < "$SELECTION" | wl-copy |
@@ -23,6 +23,7 @@ | |||
.Op Ar -s | |||
.Op Ar -S | |||
.Op Ar -v | |||
.Op Ar -x | |||
.Op Ar -h | |||
.Op Ar PATH | |||
.Sh DESCRIPTION | |||
@@ -100,6 +101,9 @@ supports the following options: | |||
.Fl v | |||
show version and exit | |||
.Pp | |||
.Fl x | |||
show notis on selection cp, mv, rm completion; copy path to system clipboard on select | |||
.Pp | |||
.Fl h | |||
show program help and exit | |||
.Sh CONFIGURATION | |||
@@ -166,7 +170,7 @@ There are 3 groups of shortcuts to add files to selection: | |||
.Pp | |||
The selection can now be listed, copied, moved, removed, archived or linked. | |||
.Pp | |||
Absolute paths of the selected files are copied to the temporary file \fB.selection\fR in the config directory. The path is shown in the help and configuration screen. If \fB$NNN_COPIER\fR is set (see ENVIRONMENT section below) the file paths are also copied to the system clipboard. | |||
Absolute paths of the selected files are copied to the temporary file \fB.selection\fR in the config directory. The path is shown in the help and configuration screen. | |||
.Pp | |||
To flush the selection without running any operation use the _edit, flush selection_ key. The list is flushed even if unchanged. Use this key to remove a file from selection after you navigate away from its directory. Flushing doesn't end the selection mode. You can add more files to the selection and edit/flush the list again. Flushing doesn't end the selection mode. You can add more files to the selection and edit/flush the list again. | |||
.Pp | |||
@@ -239,8 +243,6 @@ when dealing with the !, e and p commands respectively. A single combination to | |||
.Pp | |||
\fBNNN_IDLE_TIMEOUT:\fR set idle timeout (in seconds) to invoke terminal locker (default: disabled). | |||
.Pp | |||
\fBNNN_COPIER:\fR system clipboard copier script. The project page has some sample copier scripts. | |||
.Pp | |||
\fBNNN_TRASH:\fR trash (instead of \fIdelete\fR) files to desktop Trash. | |||
.Bd -literal | |||
export NNN_TRASH=1 | |||
@@ -0,0 +1,45 @@ | |||
#!/usr/bin/env sh | |||
# Description: Copy selection to system clipboard as newline-separated entries | |||
# Requires: tr and | |||
# xclip/xsel (Linux) | |||
# pbcopy (macOS) | |||
# termux-clipboard-set (Termux) | |||
# clip.exe (WSL) | |||
# clip (Cygwin) | |||
# wl-copy (Wayland) | |||
# | |||
# LIMITATION: breaks if a filename has newline in it | |||
# | |||
# Note: For a space-separated list: | |||
# xargs -0 < "$SELECTION" | |||
# | |||
# Shell: POSIX compliant | |||
# Author: Arun Prakash Jana | |||
IFS="$(printf '%b_' '\n')"; IFS="${IFS%_}" # protect trailing \n | |||
SELECTION=${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection | |||
if which xsel >/dev/null 2>&1; then | |||
# Linux | |||
tr '\0' '\n' < "$SELECTION" | xsel -bi | |||
elif which xclip >/dev/null 2>&1; then | |||
# Linux | |||
tr '\0' '\n' < "$SELECTION" | xclip -sel clip | |||
elif which pbcopy >/dev/null 2>&1; then | |||
# macOS | |||
tr '\0' '\n' < "$SELECTION" | pbcopy | |||
elif which termux-clipboard-set >/dev/null 2>&1; then | |||
# Termux | |||
tr '\0' '\n' < "$SELECTION" | termux-clipboard-set | |||
elif which clip.exe >/dev/null 2>&1; then | |||
# WSL | |||
tr '\0' '\n' < "$SELECTION" | clip.exe | |||
elif which clip >/dev/null 2>&1; then | |||
# Cygwin | |||
tr '\0' '\n' < "$SELECTION" | clip | |||
elif which wl-copy >/dev/null 2>&1; then | |||
# Wayland | |||
tr '\0' '\n' < "$SELECTION" | wl-copy | |||
fi |
@@ -227,8 +227,9 @@ typedef struct { | |||
uint selmode : 1; /* Set when selecting files */ | |||
uint showdetail : 1; /* Clear to show fewer file info */ | |||
uint ctxactive : 1; /* Context active or not */ | |||
uint reserved : 3; | |||
uint reserved : 2; | |||
/* The following settings are global */ | |||
uint x11 : 1; /* Copy to system clipboard and show notis */ | |||
uint curctx : 2; /* Current context number */ | |||
uint dircolor : 1; /* Current status of dir color */ | |||
uint picker : 1; /* Write selection to user-specified file */ | |||
@@ -281,6 +282,7 @@ static settings cfg = { | |||
0, /* showdetail */ | |||
1, /* ctxactive */ | |||
0, /* reserved */ | |||
0, /* x11 */ | |||
0, /* curctx */ | |||
0, /* dircolor */ | |||
0, /* picker */ | |||
@@ -310,7 +312,6 @@ static uint idletimeout, selbufpos, lastappendpos, selbuflen; | |||
static char *bmstr; | |||
static char *pluginstr; | |||
static char *opener; | |||
static char *copier; | |||
static char *editor; | |||
static char *enveditor; | |||
static char *pager; | |||
@@ -379,7 +380,8 @@ static bool g_plinit = FALSE; | |||
#define UTIL_SH 14 | |||
#define UTIL_FZF 15 | |||
#define UTIL_FZY 16 | |||
#define UTIL_NOTIFY 17 | |||
#define UTIL_NTFY 17 | |||
#define UTIL_CBCP 18 | |||
/* Utilities to open files, run actions */ | |||
static char * const utils[] = { | |||
@@ -412,7 +414,8 @@ static char * const utils[] = { | |||
"sh", | |||
"fzf", | |||
"fzy", | |||
".notify", | |||
".ntfy", | |||
".cbcp", | |||
}; | |||
/* Common strings */ | |||
@@ -507,18 +510,16 @@ static const char * const messages[] = { | |||
#define NNN_OPENER 1 | |||
#define NNN_CONTEXT_COLORS 2 | |||
#define NNN_IDLE_TIMEOUT 3 | |||
#define NNN_COPIER 4 | |||
#define NNNLVL 5 | |||
#define NNN_PIPE 6 /* strings end here */ | |||
#define NNN_USE_EDITOR 7 /* flags begin here */ | |||
#define NNN_TRASH 8 | |||
#define NNNLVL 4 | |||
#define NNN_PIPE 5 /* strings end here */ | |||
#define NNN_USE_EDITOR 6 /* flags begin here */ | |||
#define NNN_TRASH 7 | |||
static const char * const env_cfg[] = { | |||
"NNN_BMS", | |||
"NNN_OPENER", | |||
"NNN_CONTEXT_COLORS", | |||
"NNN_IDLE_TIMEOUT", | |||
"NNN_COPIER", | |||
"NNNLVL", | |||
"NNN_PIPE", | |||
"NNN_USE_EDITOR", | |||
@@ -597,6 +598,7 @@ static inline bool getutil(char *util); | |||
static size_t mkpath(const char *dir, const char *name, char *out); | |||
static void updateselbuf(const char *path, char *newpath); | |||
static char *xgetenv(const char *name, char *fallback); | |||
static void run_plugin(const char *plugin, char *newpath, const uchar flags); | |||
/* Functions */ | |||
@@ -1040,7 +1042,8 @@ static void endselection(const char *path, char *newpath) | |||
if (selbufpos) { /* File path(s) written to the buffer */ | |||
writesel(pselbuf, selbufpos - 1); /* Truncate NULL from end */ | |||
spawn(copier, NULL, NULL, NULL, F_NOTRACE); | |||
if (cfg.x11) | |||
run_plugin(utils[UTIL_CBCP], newpath, F_NOWAIT | F_NOTRACE); | |||
} | |||
} | |||
} | |||
@@ -1127,7 +1130,6 @@ static int editselection(void) | |||
nselected = lines; | |||
writesel(pselbuf, selbufpos - 1); | |||
spawn(copier, NULL, NULL, NULL, F_NOTRACE); | |||
return 1; | |||
@@ -3631,6 +3633,13 @@ static bool run_selected_plugin(char **path, const char *file, char *newpath, ch | |||
return TRUE; | |||
} | |||
static void run_plugin(const char *plugin, char *newpath, const uchar flags) | |||
{ | |||
mkpath(plugindir, plugin, newpath); | |||
if (!access(newpath, X_OK)) | |||
spawn(newpath, NULL, NULL, NULL, flags); | |||
} | |||
static void launch_app(const char *path, char *newpath) | |||
{ | |||
int r = F_NORMAL; | |||
@@ -4854,7 +4863,8 @@ nochange: | |||
selbufpos = lastappendpos; | |||
appendfpath(newpath, mkpath(path, dents[cur].name, newpath)); | |||
writesel(pselbuf, selbufpos - 1); /* Truncate NULL from end */ | |||
spawn(copier, NULL, NULL, NULL, F_NOTRACE); | |||
if (cfg.x11) | |||
run_plugin(utils[UTIL_CBCP], newpath, F_NOWAIT | F_NOTRACE); | |||
lastappendpos = selbufpos; | |||
selbufpos = utmp; | |||
} | |||
@@ -4938,7 +4948,8 @@ nochange: | |||
if (selbufpos != utmp) { | |||
writesel(pselbuf, selbufpos - 1); /* Truncate NULL from end */ | |||
spawn(copier, NULL, NULL, NULL, F_NOTRACE); | |||
if (cfg.x11) | |||
run_plugin(utils[UTIL_CBCP], newpath, F_NOWAIT | F_NOTRACE); | |||
/* Restore current selection buffer position */ | |||
lastappendpos = selbufpos; | |||
selbufpos = utmp; | |||
@@ -4962,7 +4973,8 @@ nochange: | |||
= (!r ? messages[MSG_0_SELECTED] : messages[MSG_FAILED]); | |||
printwait(msg, &presel); | |||
goto nochange; | |||
} | |||
} else if (cfg.x11) | |||
run_plugin(utils[UTIL_CBCP], newpath, F_NOWAIT | F_NOTRACE); | |||
break; | |||
case SEL_CP: // fallthrough | |||
case SEL_MV: // fallthrough | |||
@@ -4975,8 +4987,8 @@ nochange: | |||
goto nochange; | |||
/* Show notification on operation complete */ | |||
mkpath(plugindir, utils[UTIL_NOTIFY], newpath); | |||
spawn(newpath, NULL, NULL, NULL, F_NOWAIT | F_NOTRACE); | |||
if (cfg.x11) | |||
run_plugin(utils[UTIL_NTFY], newpath, F_NOWAIT | F_NOTRACE); | |||
if (ndents) | |||
copycurname(); | |||
@@ -5479,6 +5491,7 @@ static void usage(void) | |||
" -S du mode\n" | |||
" -t disable dir auto-select\n" | |||
" -v show version\n" | |||
" -x notis, sel to system clipboard\n" | |||
" -h show help\n\n" | |||
"v%s\n%s\n", __func__, VERSION, GENERAL_INFO); | |||
} | |||
@@ -5621,7 +5634,7 @@ int main(int argc, char *argv[]) | |||
bool progress = FALSE; | |||
#endif | |||
while ((opt = getopt(argc, argv, "HSKiab:cde:Efnop:rRstvh")) != -1) { | |||
while ((opt = getopt(argc, argv, "HSKiab:cde:Efnop:rRstvxh")) != -1) { | |||
switch (opt) { | |||
case 'S': | |||
cfg.blkorder = 1; | |||
@@ -5699,6 +5712,9 @@ int main(int argc, char *argv[]) | |||
case 'v': | |||
fprintf(stdout, "%s\n", VERSION); | |||
return _SUCCESS; | |||
case 'x': | |||
cfg.x11 = 1; | |||
break; | |||
case 'h': | |||
usage(); | |||
return _SUCCESS; | |||
@@ -5837,9 +5853,6 @@ int main(int argc, char *argv[]) | |||
if (!set_tmp_path()) | |||
return _FAILURE; | |||
/* Get the clipboard copier, if set */ | |||
copier = getenv(env_cfg[NNN_COPIER]); | |||
#ifdef __linux__ | |||
if (!progress) { | |||
cp[5] = cp[4]; | |||