README.md | 3 ++- misc/auto-completion/bash/nnn-completion.bash | 1 + misc/auto-completion/fish/nnn.fish | 1 + misc/auto-completion/zsh/_nnn | 1 + misc/clipboard-copier/copier | 23 ----------------------- nnn.1 | 8 +++++--- plugins/.cbcp | 45 +++++++++++++++++++++++++++++++++++++++++++++ plugins/.notify => plugins/.ntfy | 0 src/nnn.c | 55 +++++++++++++++++++++++++++++++++-------------------- diff --git a/README.md b/README.md index 34ba51d14584487e10a3470b04a503869f2fd7ed..e5bc4c4934b15dbbb1ea4cee5507b0d4e0193337 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,7 @@ - Cross-dir file/all/range selection - 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 @@ | `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] | #### Cmdline options @@ -195,6 +195,7 @@ -s string filters [default: regex] -S du mode -t disable dir auto-select -v show version + -x notis, sel to system clipboard -h show help ``` diff --git a/misc/auto-completion/bash/nnn-completion.bash b/misc/auto-completion/bash/nnn-completion.bash index bddf84f88b46dee7b09afc9d8b3ec6fb391a5368..00e34d5a8027635d859af868bb387ef4010eb9ba 100644 --- a/misc/auto-completion/bash/nnn-completion.bash +++ b/misc/auto-completion/bash/nnn-completion.bash @@ -31,6 +31,7 @@ -s -S -t -v + -x -h ) if [[ $prev == -b ]]; then diff --git a/misc/auto-completion/fish/nnn.fish b/misc/auto-completion/fish/nnn.fish index 36133437143b9bd7ff362f8e563b22dc0cdb7afc..c1f2facc30c163c4ea082a58f0240d962d1cd112 100644 --- a/misc/auto-completion/fish/nnn.fish +++ b/misc/auto-completion/fish/nnn.fish @@ -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' diff --git a/misc/auto-completion/zsh/_nnn b/misc/auto-completion/zsh/_nnn index d5d5c1dc1de5e5f637f0ef90b3ca886b182add61..34db851e430b494b6ab564d5d72fb497b86f1818 100644 --- a/misc/auto-completion/zsh/_nnn +++ b/misc/auto-completion/zsh/_nnn @@ -28,6 +28,7 @@ '(-s)-s[use substring match for filters]' '(-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' ) diff --git a/misc/clipboard-copier/copier b/misc/clipboard-copier/copier deleted file mode 100755 index 6ac3ba6b2fe28ef8055b44ed0ece0f051f5877ed..0000000000000000000000000000000000000000 --- a/misc/clipboard-copier/copier +++ /dev/null @@ -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 diff --git a/nnn.1 b/nnn.1 index cb0f29982d5234161c41e5b108d05182cbb0eaef..a9fd662987e3a3cf95e1cbf7c695ebaadb740a98 100644 --- a/nnn.1 +++ b/nnn.1 @@ -23,6 +23,7 @@ .Op Ar -R .Op Ar -s .Op Ar -S .Op Ar -v +.Op Ar -x .Op Ar -h .Op Ar PATH .Sh DESCRIPTION @@ -99,6 +100,9 @@ disable directory auto-select in navigate-as-you-type mode .Pp .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 @@ -166,7 +170,7 @@ (3) add all files in the current directory 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 @@ -238,8 +242,6 @@ NOTE: `nuke` is a file opener available in plugin repository .Ed .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 diff --git a/plugins/.cbcp b/plugins/.cbcp new file mode 100755 index 0000000000000000000000000000000000000000..022e88a362bb573b9abd9e3d87012e766e95e34a --- /dev/null +++ b/plugins/.cbcp @@ -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 diff --git a/plugins/.notify b/plugins/.ntfy rename from plugins/.notify rename to plugins/.ntfy diff --git a/src/nnn.c b/src/nnn.c index 7500d01abb0602e90d15b2b82ca11271c87e5f96..c398179667b1a426c39c5eaa749193d4bff135ae 100644 --- a/src/nnn.c +++ b/src/nnn.c @@ -227,8 +227,9 @@ uint showhidden : 1; /* Set to show hidden files */ 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 @@ 0, /* selmode */ 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 @@ #define UTIL_LESS 13 #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 @@ "less", "sh", "fzf", "fzy", - ".notify", + ".ntfy", + ".cbcp", }; /* Common strings */ @@ -507,18 +510,16 @@ #define NNN_BMS 0 #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 @@ updateselbuf(path, 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 @@ } nselected = lines; writesel(pselbuf, selbufpos - 1); - spawn(copier, NULL, NULL, NULL, F_NOTRACE); return 1; @@ -3631,6 +3633,13 @@ 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 @@ utmp = selbufpos; 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 @@ } 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 @@ const char * msg = (!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 @@ if (!cpmvrm_selection(sel, path, &presel)) 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 @@ " -s string filters [default: regex]\n" " -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 @@ #ifdef __linux__ 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 @@ return _SUCCESS; case 'v': fprintf(stdout, "%s\n", VERSION); return _SUCCESS; + case 'x': + cfg.x11 = 1; + break; case 'h': usage(); return _SUCCESS; @@ -5836,9 +5852,6 @@ /* Prefix for temporary files */ if (!set_tmp_path()) return _FAILURE; - - /* Get the clipboard copier, if set */ - copier = getenv(env_cfg[NNN_COPIER]); #ifdef __linux__ if (!progress) {