From eee5057da5d5063f5a5c3e0059e98ad8f6ba179e Mon Sep 17 00:00:00 2001 From: Arun Prakash Jana Date: Sun, 3 May 2020 14:55:33 +0530 Subject: [PATCH] Plugin mimelist: support reading file list from (cmd as) plugin --- plugins/.nnn-plugin-helper | 2 +- plugins/README.md | 13 +++- plugins/autojump | 2 +- plugins/fzz | 2 +- plugins/mimelist | 21 +++++++ src/nnn.c | 120 ++++++++++++++++++++++++++----------- 6 files changed, 120 insertions(+), 40 deletions(-) create mode 100755 plugins/mimelist diff --git a/plugins/.nnn-plugin-helper b/plugins/.nnn-plugin-helper index 06b3bcbe..0f74fc74 100644 --- a/plugins/.nnn-plugin-helper +++ b/plugins/.nnn-plugin-helper @@ -29,7 +29,7 @@ nnn_cd () { read -r context fi - printf "%s" "${context:-0}$dir" > "$NNN_PIPE" + printf "%s" "${context:-0}c$dir" > "$NNN_PIPE" } cmd_exists () { diff --git a/plugins/README.md b/plugins/README.md index 9cafd3e3..b16ef9ee 100644 --- a/plugins/README.md +++ b/plugins/README.md @@ -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 | | launch | GUI application launcher | sh | fzf/fzy | | 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/) | | 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 | @@ -163,8 +164,14 @@ Drop the plugin in `${XDG_CONFIG_HOME:-$HOME/.config}/nnn/plugins` and make it e #### Controlling `nnn`'s 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 plugin should write a single string in the format `` without a newline at the end. For example, `1/etc`. -The number indicates the context to change the active directory of (0 is used to indicate the current context). +The plugin should write a single string in the format `` without a newline at the end. For example, `1c/etc`. +The context number indicates the context to change the active directory of (0 is used to indicate the current context). +The `` 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. 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: " read -r dir - printf "%s" "0$dir" > "$NNN_PIPE" + printf "%s" "0c$dir" > "$NNN_PIPE" ``` ## Contributing plugins diff --git a/plugins/autojump b/plugins/autojump index ef39dd91..db221f37 100755 --- a/plugins/autojump +++ b/plugins/autojump @@ -13,7 +13,7 @@ if which autojump >/dev/null 2>&1; then printf "jump to: " read -r dir odir="$(autojump "$dir")" - printf "%s" "0$odir" > "$NNN_PIPE" + printf "%s" "0c$odir" > "$NNN_PIPE" else printf "autojump missing" read -r _ diff --git a/plugins/fzz b/plugins/fzz index fa432c10..5b402698 100755 --- a/plugins/fzz +++ b/plugins/fzz @@ -25,4 +25,4 @@ else exit 1 fi -printf "%s" "0$sel" > "$NNN_PIPE" +printf "%s" "0c$sel" > "$NNN_PIPE" diff --git a/plugins/mimelist b/plugins/mimelist new file mode 100755 index 00000000..0ec7c0f3 --- /dev/null +++ b/plugins/mimelist @@ -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" diff --git a/src/nnn.c b/src/nnn.c index 59dacd2e..277673ac 100644 --- a/src/nnn.c +++ b/src/nnn.c @@ -514,8 +514,9 @@ static char * const utils[] = { #define MSG_RM_TMP 40 #define MSG_NOCHNAGE 41 #define MSG_CANCEL 42 +#define MSG_0_ENTRIES 43 #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 static const char * const messages[] = { @@ -562,6 +563,7 @@ static const char * const messages[] = { "unchanged", "cancelled", "first file (\')/char?", + "0 entries", #ifndef DIR_LIMITED_SELECTION "dir changed, range sel off", /* Must be the last entry */ #endif @@ -691,6 +693,7 @@ static inline bool getutil(char *util); static size_t mkpath(const char *dir, const char *name, char *out); static char *xgetenv(const char *name, char *fallback); static bool plugscript(const char *plugin, const char *path, uchar flags); +static char *load_input(int fd, char *path); /* Functions */ @@ -4218,11 +4221,72 @@ static bool plctrl_init(void) 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) { int fd; - size_t len; - if (!(g_states & STATE_PLUGIN_INIT)) { plctrl_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); } - len = read(fd, g_buf, PATH_MAX); - g_buf[len] = '\0'; + readpipe(fd, path, lastname, lastdir); + 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; } @@ -6318,7 +6364,7 @@ static char *make_tmp_tree(char **paths, ssize_t entries, const char *prefix) struct stat sb; char *slash, *tmp; ssize_t len = xstrlen(prefix); - char *tmpdir = malloc(sizeof(char) * (PATH_MAX + TMP_LEN_MAX)); + char *tmpdir = malloc(PATH_MAX); if (!tmpdir) { DPRINTF_S(strerror(errno)); @@ -6377,7 +6423,7 @@ static char *make_tmp_tree(char **paths, ssize_t entries, const char *prefix) return tmpdir; } -static char *load_input() +static char *load_input(int fd, char *path) { /* 512 KiB chunk size */ ssize_t i, chunk_count = 1, chunk = 512 * 1024, entries = 0; @@ -6392,13 +6438,16 @@ static char *load_input() return NULL; } - if (!getcwd(cwd, PATH_MAX)) { - free(input); - return NULL; - } + if (!path) { + if (!getcwd(cwd, PATH_MAX)) { + free(input); + return NULL; + } + } else + xstrsncpy(cwd, path, PATH_MAX); 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) { DPRINTF_S(strerror(errno)); goto malloc_1; @@ -6461,7 +6510,11 @@ static char *load_input() DPRINTF_D(chunk_count); 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; } @@ -6842,7 +6895,7 @@ int main(int argc, char *argv[]) /* Check if we are in path list mode */ if (!isatty(STDIN_FILENO)) { /* This is the same as listpath */ - initpath = load_input(); + initpath = load_input(STDIN_FILENO, NULL); if (!initpath) return _FAILURE; @@ -7054,8 +7107,7 @@ int main(int argc, char *argv[]) unlink(selpath); /* Remove tmp dir in list mode */ - if (listpath) - spawn("rm -rf", initpath, NULL, NULL, F_NOTRACE | F_MULTI); + rmlistpath(); /* Free the regex */ #ifdef PCRE