add support for custom trash command

this makes it so that if $NNN_TRASH is set to a string other
than "1" or "2" then it is accepted as the trash command to run.

this allows us to support arbritary trashing utilities while
also maintaining backwards compatibility for older "1" & "2"
values.

Fixes: https://github.com/jarun/nnn/issues/1168
Fixes: https://github.com/jarun/nnn/discussions/1963
Fixes: https://github.com/jarun/nnn/discussions/1960
Fixes: https://github.com/jarun/nnn/discussions/1761
This commit is contained in:
NRK 2025-01-04 14:19:28 +00:00
parent 5522292014
commit e787ae4501
3 changed files with 26 additions and 26 deletions

10
nnn.1
View file

@ -564,8 +564,14 @@ separated by \fI;\fR:
.Pp .Pp
\fBNNN_TRASH:\fR trash (instead of \fIrm -rf\fR) files to desktop Trash. \fBNNN_TRASH:\fR trash (instead of \fIrm -rf\fR) files to desktop Trash.
.Bd -literal .Bd -literal
export NNN_TRASH=n export NNN_TRASH=cmd
# n=1: trash-cli, n=2: gio trash
NOTES:
1. \fBcmd\fR is the name/path of the binary that nnn will call for
trashing files. E.g to use macOS's native `trash' command:
export NNN_TRASH="trash"
2. Special value "1" and "2" for cmd will use trash-cli and
gio trash respectively.
.Ed .Ed
.Pp .Pp
\fBNNN_SEL:\fR absolute path to custom selection file. \fBNNN_SEL:\fR absolute path to custom selection file.

View file

@ -31,8 +31,10 @@ case "$NNN_TRASH" in
RM_UTIL="trash-put" ;; RM_UTIL="trash-put" ;;
2) 2)
RM_UTIL="gio trash" ;; RM_UTIL="gio trash" ;;
*) "")
RM_UTIL="rm -ri --" ;; RM_UTIL="rm -ri --" ;;
*)
RM_UTIL="$NNN_TRASH" ;;
esac esac
exit_status=0 exit_status=0

View file

@ -392,12 +392,11 @@ typedef struct {
uint_t selbm : 1; /* Select a bookmark from bookmarks directory */ uint_t selbm : 1; /* Select a bookmark from bookmarks directory */
uint_t selmode : 1; /* Set when selecting files */ uint_t selmode : 1; /* Set when selecting files */
uint_t stayonsel : 1; /* Disable auto-advance on selection */ uint_t stayonsel : 1; /* Disable auto-advance on selection */
uint_t trash : 2; /* Trash method 0: rm -rf, 1: trash-cli, 2: gio trash */
uint_t uidgid : 1; /* Show owner and group info */ uint_t uidgid : 1; /* Show owner and group info */
uint_t usebsdtar : 1; /* Use bsdtar as default archive utility */ uint_t usebsdtar : 1; /* Use bsdtar as default archive utility */
uint_t xprompt : 1; /* Use native prompt instead of readline prompt */ uint_t xprompt : 1; /* Use native prompt instead of readline prompt */
uint_t showlines : 1; /* Show line numbers */ uint_t showlines : 1; /* Show line numbers */
uint_t reserved : 3; /* Adjust when adding/removing a field */ uint_t reserved : 5; /* Adjust when adding/removing a field */
} runstate; } runstate;
/* Contexts or workspaces */ /* Contexts or workspaces */
@ -462,6 +461,7 @@ static char *listroot;
static char *plgpath; static char *plgpath;
static char *pnamebuf, *pselbuf, *findselpos; static char *pnamebuf, *pselbuf, *findselpos;
static char *mark; static char *mark;
static char *trashcmd;
#ifndef NOX11 #ifndef NOX11
static char hostname[_POSIX_HOST_NAME_MAX + 1]; static char hostname[_POSIX_HOST_NAME_MAX + 1];
#endif #endif
@ -709,8 +709,8 @@ static const char * const messages[] = {
#define NNN_SEL 9 #define NNN_SEL 9
#define NNN_ARCHIVE 10 #define NNN_ARCHIVE 10
#define NNN_ORDER 11 #define NNN_ORDER 11
#define NNN_HELP 12 /* strings end here */ #define NNN_HELP 12
#define NNN_TRASH 13 /* flags begin here */ #define NNN_TRASH 13
static const char * const env_cfg[] = { static const char * const env_cfg[] = {
"NNN_OPTS", "NNN_OPTS",
@ -2527,17 +2527,6 @@ static char *xgetenv(const char * const name, char *fallback)
return value && value[0] ? value : fallback; return value && value[0] ? value : fallback;
} }
/* Checks if an env variable is set to 1 */
static inline uint_t xgetenv_val(const char *name)
{
char *str = getenv(name);
if (str && str[0])
return atoi(str);
return 0;
}
/* Check if a dir exists, IS a dir, and is readable */ /* Check if a dir exists, IS a dir, and is readable */
static bool xdiraccess(const char *path) static bool xdiraccess(const char *path)
{ {
@ -2579,7 +2568,7 @@ static bool rmmulstr(char *buf, bool use_trash)
r, selpath); r, selpath);
else else
snprintf(buf, CMD_LEN_MAX, "xargs -0 %s < %s", snprintf(buf, CMD_LEN_MAX, "xargs -0 %s < %s",
utils[(g_state.trash == 1) ? UTIL_TRASH_CLI : UTIL_GIO_TRASH], selpath); trashcmd, selpath);
return TRUE; return TRUE;
} }
@ -2597,8 +2586,7 @@ static bool xrm(char * const fpath, bool use_trash)
rm_opts[3] = r; rm_opts[3] = r;
spawn("rm", rm_opts, "--", fpath, F_NORMAL | F_CHKRTN); spawn("rm", rm_opts, "--", fpath, F_NORMAL | F_CHKRTN);
} else } else
spawn(utils[(g_state.trash == 1) ? UTIL_TRASH_CLI : UTIL_GIO_TRASH], spawn(trashcmd, fpath, NULL, NULL, F_NORMAL | F_MULTI);
fpath, NULL, NULL, F_NORMAL | F_MULTI);
return (access(fpath, F_OK) == -1); /* File is removed */ return (access(fpath, F_OK) == -1); /* File is removed */
} }
@ -2723,7 +2711,7 @@ static bool cpmvrm_selection(enum action sel, char *path)
} }
break; break;
default: /* SEL_TRASH, SEL_RM_ONLY */ default: /* SEL_TRASH, SEL_RM_ONLY */
if (!rmmulstr(g_buf, g_state.trash && sel == SEL_TRASH)) { if (!rmmulstr(g_buf, trashcmd && sel == SEL_TRASH)) {
printmsg(messages[MSG_CANCEL]); printmsg(messages[MSG_CANCEL]);
return FALSE; return FALSE;
} }
@ -7757,7 +7745,7 @@ nochange:
tmp = (listpath && xstrcmp(path, listpath) == 0) tmp = (listpath && xstrcmp(path, listpath) == 0)
? listroot : path; ? listroot : path;
mkpath(tmp, pdents[cur].name, newpath); mkpath(tmp, pdents[cur].name, newpath);
if (!xrm(newpath, g_state.trash && sel == SEL_TRASH)) if (!xrm(newpath, trashcmd && sel == SEL_TRASH))
continue; continue;
xrmfromsel(tmp, newpath); xrmfromsel(tmp, newpath);
@ -9045,9 +9033,13 @@ int main(int argc, char *argv[])
#endif #endif
/* Configure trash preference */ /* Configure trash preference */
opt = xgetenv_val(env_cfg[NNN_TRASH]); trashcmd = getenv(env_cfg[NNN_TRASH]);
if (opt && opt <= 2) if (trashcmd) {
g_state.trash = opt; if (strcmp(trashcmd, "1") == 0)
trashcmd = utils[UTIL_TRASH_CLI];
else if (strcmp(trashcmd, "2") == 0)
trashcmd = utils[UTIL_GIO_TRASH];
}
/* Ignore/handle certain signals */ /* Ignore/handle certain signals */
struct sigaction act = {.sa_handler = sigint_handler}; struct sigaction act = {.sa_handler = sigint_handler};