Plugin mimelist: support reading file list from (cmd as) plugin

This commit is contained in:
Arun Prakash Jana 2020-05-03 14:55:33 +05:30
parent e8e87f6ba2
commit eee5057da5
No known key found for this signature in database
GPG key ID: A75979F35C080412
6 changed files with 120 additions and 40 deletions

View file

@ -29,7 +29,7 @@ nnn_cd () {
read -r context read -r context
fi fi
printf "%s" "${context:-0}$dir" > "$NNN_PIPE" printf "%s" "${context:-0}c$dir" > "$NNN_PIPE"
} }
cmd_exists () { cmd_exists () {

View file

@ -47,6 +47,7 @@ Plugins are installed to `${XDG_CONFIG_HOME:-$HOME/.config}/nnn/plugins`.
| kdeconnect | Send selected files to an Android device | sh | kdeconnect-cli | | kdeconnect | Send selected files to an Android device | sh | kdeconnect-cli |
| launch | GUI application launcher | sh | fzf/fzy | | launch | GUI application launcher | sh | fzf/fzy |
| mediainf | Show media information | sh | mediainfo | | mediainf | Show media information | sh | mediainfo |
| mimelist | List files by mime in subtree | sh | fd/find |
| moclyrics | Show lyrics of the track playing in moc | sh | [ddgr](https://github.com/jarun/ddgr), [moc](http://moc.daper.net/) | | moclyrics | Show lyrics of the track playing in moc | sh | [ddgr](https://github.com/jarun/ddgr), [moc](http://moc.daper.net/) |
| mocplay | Append (and/or play) selection/dir/file in moc | sh | [moc](http://moc.daper.net/) | | mocplay | Append (and/or play) selection/dir/file in moc | sh | [moc](http://moc.daper.net/) |
| mp3conv | Extract audio from multimedia as mp3 | sh | ffmpeg | | mp3conv | Extract audio from multimedia as mp3 | sh | ffmpeg |
@ -163,8 +164,14 @@ Drop the plugin in `${XDG_CONFIG_HOME:-$HOME/.config}/nnn/plugins` and make it e
#### Controlling `nnn`'s active directory #### Controlling `nnn`'s active directory
`nnn` provides a mechanism for plugins to control its active directory. `nnn` provides a mechanism for plugins to control its active directory.
The way to do so is by writing to the pipe pointed by the environment variable `NNN_PIPE`. The way to do so is by writing to the pipe pointed by the environment variable `NNN_PIPE`.
The plugin should write a single string in the format `<number><path>` without a newline at the end. For example, `1/etc`. The plugin should write a single string in the format `<context number><char><path>` without a newline at the end. For example, `1c/etc`.
The number indicates the context to change the active directory of (0 is used to indicate the current context). The context number indicates the context to change the active directory of (0 is used to indicate the current context).
The `<char>` indicates the operation type.
: Char : Operation :
|:---:| --- |
| c | cd |
| l | list files in list mode |
For convenience, we provided a helper script named `.nnn-plugin-helper` and a function named `nnn_cd` to ease this process. `nnn_cd` receives the path to change to as the first argument, and the context as an optional second argument. For convenience, we provided a helper script named `.nnn-plugin-helper` and a function named `nnn_cd` to ease this process. `nnn_cd` receives the path to change to as the first argument, and the context as an optional second argument.
If a context is not provided, it is asked for explicitly. To skip this and choose the current context, set the `CUR_CTX` variable in `.nnn-plugin-helper` to `1`. If a context is not provided, it is asked for explicitly. To skip this and choose the current context, set the `CUR_CTX` variable in `.nnn-plugin-helper` to `1`.
@ -201,7 +208,7 @@ There are many plugins provided by `nnn` which can be used as examples. Here are
printf "cd to: " printf "cd to: "
read -r dir read -r dir
printf "%s" "0$dir" > "$NNN_PIPE" printf "%s" "0c$dir" > "$NNN_PIPE"
``` ```
## Contributing plugins ## Contributing plugins

View file

@ -13,7 +13,7 @@ if which autojump >/dev/null 2>&1; then
printf "jump to: " printf "jump to: "
read -r dir read -r dir
odir="$(autojump "$dir")" odir="$(autojump "$dir")"
printf "%s" "0$odir" > "$NNN_PIPE" printf "%s" "0c$odir" > "$NNN_PIPE"
else else
printf "autojump missing" printf "autojump missing"
read -r _ read -r _

View file

@ -25,4 +25,4 @@ else
exit 1 exit 1
fi fi
printf "%s" "0$sel" > "$NNN_PIPE" printf "%s" "0c$sel" > "$NNN_PIPE"

21
plugins/mimelist Executable file
View file

@ -0,0 +1,21 @@
#!/usr/bin/env sh
# Description: Run fd/find in subtree and list files by mime type in current context
# Requires: fd/find
#
# Shell: POSIX compliant
# Author: Arun Prakash jana
. "$(dirname "$0")"/.nnn-plugin-helper
if [ "$(cmd_exists fd)" -eq "0" ]; then
fd=fd
else
fd=find
fi
printf "mime: "
read -r mime
printf "%s" "0l" > "$NNN_PIPE"
$fd | file -if- | grep "$mime" | awk -F: '{printf "%s\0", $1}' > "$NNN_PIPE"

120
src/nnn.c
View file

@ -514,8 +514,9 @@ static char * const utils[] = {
#define MSG_RM_TMP 40 #define MSG_RM_TMP 40
#define MSG_NOCHNAGE 41 #define MSG_NOCHNAGE 41
#define MSG_CANCEL 42 #define MSG_CANCEL 42
#define MSG_0_ENTRIES 43
#ifndef DIR_LIMITED_SELECTION #ifndef DIR_LIMITED_SELECTION
#define MSG_DIR_CHANGED 43 /* Must be the last entry */ #define MSG_DIR_CHANGED 44 /* Must be the last entry */
#endif #endif
static const char * const messages[] = { static const char * const messages[] = {
@ -562,6 +563,7 @@ static const char * const messages[] = {
"unchanged", "unchanged",
"cancelled", "cancelled",
"first file (\')/char?", "first file (\')/char?",
"0 entries",
#ifndef DIR_LIMITED_SELECTION #ifndef DIR_LIMITED_SELECTION
"dir changed, range sel off", /* Must be the last entry */ "dir changed, range sel off", /* Must be the last entry */
#endif #endif
@ -691,6 +693,7 @@ static inline bool getutil(char *util);
static size_t mkpath(const char *dir, const char *name, char *out); static size_t mkpath(const char *dir, const char *name, char *out);
static char *xgetenv(const char *name, char *fallback); static char *xgetenv(const char *name, char *fallback);
static bool plugscript(const char *plugin, const char *path, uchar flags); static bool plugscript(const char *plugin, const char *path, uchar flags);
static char *load_input(int fd, char *path);
/* Functions */ /* Functions */
@ -4218,11 +4221,72 @@ static bool plctrl_init(void)
return _SUCCESS; return _SUCCESS;
} }
static void rmlistpath()
{
if (listpath) {
DPRINTF_S(__FUNCTION__);
DPRINTF_S(initpath);
spawn("rm -rf", initpath, NULL, NULL, F_NOTRACE | F_MULTI);
listpath = NULL;
}
}
static void readpipe(int fd, char **path, char **lastname, char **lastdir)
{
char *nextpath = NULL;
ssize_t len = read(fd, g_buf, 1);
if (len != 1)
return;
char ctx = g_buf[0] - '0';
if (ctx > CTX_MAX)
return;
len = read(fd, g_buf, 1);
if (len != 1)
return;
char op = g_buf[0];
if (op == 'c') {
len = read(fd, g_buf, PATH_MAX);
if (len <= 0)
return;
nextpath = g_buf;
} else if (op == 'l') {
/* Remove last list mode path, if any */
rmlistpath();
nextpath = load_input(fd, *path);
if (nextpath) {
free(initpath);
initpath = nextpath;
DPRINTF_S(initpath);
}
}
if (nextpath) {
if (ctx == 0 || ctx == cfg.curctx + 1) {
xstrsncpy(*lastdir, *path, PATH_MAX);
xstrsncpy(*path, nextpath, PATH_MAX);
} else {
int r = ctx - 1;
g_ctx[r].c_cfg.ctxactive = 0;
savecurctx(&cfg, nextpath, dents[cur].name, r);
*path = g_ctx[r].c_path;
*lastdir = g_ctx[r].c_last;
*lastname = g_ctx[r].c_name;
}
}
}
static bool run_selected_plugin(char **path, const char *file, char *runfile, char **lastname, char **lastdir) static bool run_selected_plugin(char **path, const char *file, char *runfile, char **lastname, char **lastdir)
{ {
int fd; int fd;
size_t len;
if (!(g_states & STATE_PLUGIN_INIT)) { if (!(g_states & STATE_PLUGIN_INIT)) {
plctrl_init(); plctrl_init();
g_states |= STATE_PLUGIN_INIT; g_states |= STATE_PLUGIN_INIT;
@ -4248,27 +4312,9 @@ static bool run_selected_plugin(char **path, const char *file, char *runfile, ch
spawn(g_buf, NULL, *path, *path, F_NORMAL); spawn(g_buf, NULL, *path, *path, F_NORMAL);
} }
len = read(fd, g_buf, PATH_MAX); readpipe(fd, path, lastname, lastdir);
g_buf[len] = '\0';
close(fd); close(fd);
if (len > 1) {
int ctx = g_buf[0] - '0';
if (ctx == 0 || ctx == cfg.curctx + 1) {
xstrsncpy(*lastdir, *path, PATH_MAX);
xstrsncpy(*path, g_buf + 1, PATH_MAX);
} else if (ctx >= 1 && ctx <= CTX_MAX) {
int r = ctx - 1;
g_ctx[r].c_cfg.ctxactive = 0;
savecurctx(&cfg, g_buf + 1, dents[cur].name, r);
*path = g_ctx[r].c_path;
*lastdir = g_ctx[r].c_last;
*lastname = g_ctx[r].c_name;
}
}
return TRUE; return TRUE;
} }
@ -6318,7 +6364,7 @@ static char *make_tmp_tree(char **paths, ssize_t entries, const char *prefix)
struct stat sb; struct stat sb;
char *slash, *tmp; char *slash, *tmp;
ssize_t len = xstrlen(prefix); ssize_t len = xstrlen(prefix);
char *tmpdir = malloc(sizeof(char) * (PATH_MAX + TMP_LEN_MAX)); char *tmpdir = malloc(PATH_MAX);
if (!tmpdir) { if (!tmpdir) {
DPRINTF_S(strerror(errno)); DPRINTF_S(strerror(errno));
@ -6377,7 +6423,7 @@ static char *make_tmp_tree(char **paths, ssize_t entries, const char *prefix)
return tmpdir; return tmpdir;
} }
static char *load_input() static char *load_input(int fd, char *path)
{ {
/* 512 KiB chunk size */ /* 512 KiB chunk size */
ssize_t i, chunk_count = 1, chunk = 512 * 1024, entries = 0; ssize_t i, chunk_count = 1, chunk = 512 * 1024, entries = 0;
@ -6392,13 +6438,16 @@ static char *load_input()
return NULL; return NULL;
} }
if (!getcwd(cwd, PATH_MAX)) { if (!path) {
free(input); if (!getcwd(cwd, PATH_MAX)) {
return NULL; free(input);
} return NULL;
}
} else
xstrsncpy(cwd, path, PATH_MAX);
while (chunk_count < 512) { while (chunk_count < 512) {
input_read = read(STDIN_FILENO, input + total_read, chunk); input_read = read(fd, input + total_read, chunk);
if (input_read < 0) { if (input_read < 0) {
DPRINTF_S(strerror(errno)); DPRINTF_S(strerror(errno));
goto malloc_1; goto malloc_1;
@ -6461,7 +6510,11 @@ static char *load_input()
DPRINTF_D(chunk_count); DPRINTF_D(chunk_count);
if (!entries) { if (!entries) {
fprintf(stderr, "0 entries\n"); if (g_states & STATE_PLUGIN_INIT) {
printmsg(messages[MSG_0_ENTRIES]);
xdelay(XDELAY_INTERVAL_MS);
} else
fprintf(stderr, "%s\n", messages[MSG_0_ENTRIES]);
goto malloc_1; goto malloc_1;
} }
@ -6842,7 +6895,7 @@ int main(int argc, char *argv[])
/* Check if we are in path list mode */ /* Check if we are in path list mode */
if (!isatty(STDIN_FILENO)) { if (!isatty(STDIN_FILENO)) {
/* This is the same as listpath */ /* This is the same as listpath */
initpath = load_input(); initpath = load_input(STDIN_FILENO, NULL);
if (!initpath) if (!initpath)
return _FAILURE; return _FAILURE;
@ -7054,8 +7107,7 @@ int main(int argc, char *argv[])
unlink(selpath); unlink(selpath);
/* Remove tmp dir in list mode */ /* Remove tmp dir in list mode */
if (listpath) rmlistpath();
spawn("rm -rf", initpath, NULL, NULL, F_NOTRACE | F_MULTI);
/* Free the regex */ /* Free the regex */
#ifdef PCRE #ifdef PCRE