plugins/README.md | 10 +++++++++-
src/nnn.c | 59 ++++++++++++++++++++++++++++++++++++-----------------
diff --git a/plugins/README.md b/plugins/README.md
index a9e928a721d2e33cb96b3606b234d5f4fc46e5ed..763aa43fb1d2b235ee832072ce5129e04df080c7 100644
--- a/plugins/README.md
+++ b/plugins/README.md
@@ -79,11 +79,19 @@ **Method 2:** Use the _pick plugin_ shortcut to visit the plugin directory and execute a plugin. Repeating the same shortcut cancels the operation and puts you back in the original directory.
## Running commands as plugin
-To assign keys to arbitrary non-background cli commands (non-shell-interpreted) and invoke like plugins, add `_` (underscore) before the command. For example:
+To assign keys to arbitrary non-background cli commands (non-shell-interpreted) and invoke like plugins, add `_` (underscore) before the command.
+
+For example:
export NNN_PLUG='x:_chmod +x $nnn;g:_git log;s:_smplayer $nnn;o:fzopen'
Now ;x can be used to make a file executable, ;g can be used to the git log of a git project directory, ;s can be used to preview a partially downloaded media file.
+
+`nnn` waits for user confirmation when it executes a command as plugin (unline plugins which can add a `read` to wait). If you do not need to wait for user confirmation after the command has executed, add a `*` after the command. For example:
+
+ export NNN_PLUG='x:_chmod +x $nnn;g:_git log;s:_smplayer $nnn*;o:fzopen'
+
+Now there will be no prompt after ;s.
Notes:
diff --git a/src/nnn.c b/src/nnn.c
index 378a86a41a357285e6ea3804746856a37d4b0b02..670eb469caa4fa4406de8b227572fa472e735356 100644
--- a/src/nnn.c
+++ b/src/nnn.c
@@ -3552,6 +3552,37 @@ spawn(pager, g_tmpfpath, NULL, NULL, F_CLI);
unlink(g_tmpfpath);
}
+static bool run_cmd_as_plugin(const char *path, char *file, char *newpath, char *runfile)
+{
+ uchar flags = F_CLI | F_CONFIRM;
+ size_t len;
+
+ DPRINTF_S(file);
+
+ /* Get rid of preceding _ */
+ ++file;
+
+ if (!*file)
+ return FALSE;
+
+ len = strlen(file);
+ if (len > 1 && file[len - 1] == '*') {
+ flags &= ~F_CONFIRM; /* GUI case */
+ file[len - 1] = '\0'; /* Get rid of trailing nowait symbol */
+ --len;
+ }
+
+ xstrlcpy(newpath, file, PATH_MAX);
+ if (is_suffix(file, " $nnn")) {
+ /* Set `\0` to clear ' $nnn' suffix */
+ newpath[len - 5] = '\0';
+ } else
+ runfile = NULL;
+
+ spawn(newpath, runfile, NULL, path, flags);
+ return TRUE;
+}
+
static bool plctrl_init(void)
{
snprintf(g_buf, CMD_LEN_MAX, "nnn-pipe.%d", getpid());
@@ -3567,10 +3598,13 @@
return _SUCCESS;
}
-static bool run_selected_plugin(char **path, const char *file, char *newpath, char *runfile, char **lastname, char **lastdir)
+static bool run_selected_plugin(char **path, char *file, char *newpath, char *runfile, char **lastname, char **lastdir)
{
int fd;
size_t len;
+
+ if (*file == '_')
+ return run_cmd_as_plugin(*path, file, newpath, runfile);
if (!g_plinit) {
plctrl_init();
@@ -5214,24 +5248,11 @@ printwait(messages[MSG_INVALID_KEY], &presel);
goto nochange;
}
- if (tmp[0] == '_' && tmp[1]) {
- xstrlcpy(newpath, ++tmp, PATH_MAX);
- if (is_suffix(newpath, " $nnn")) {
- tmp = (ndents ? dents[cur].name : NULL);
- /* Set `\0` to clear ' $nnn' suffix */
- newpath[strlen(newpath) - 5] = '\0';
- } else
- tmp = NULL;
-
- spawn(newpath, tmp, NULL, path, F_CLI | F_CONFIRM);
- } else {
- if (!run_selected_plugin(&path, tmp, newpath,
- (ndents ? dents[cur].name : NULL),
- &lastname, &lastdir)) {
- printwait(messages[MSG_FAILED],
- &presel);
- goto nochange;
- }
+ if (!run_selected_plugin(&path, tmp, newpath,
+ (ndents ? dents[cur].name : NULL),
+ &lastname, &lastdir)) {
+ printwait(messages[MSG_FAILED], &presel);
+ goto nochange;
}
if (ndents)