]> Sergey Matveev's repositories - nnn.git/commitdiff
Plugin fzdirs: fuzzy search multiple directories
authorArun Prakash Jana <engineerarun@gmail.com>
Fri, 28 May 2021 13:34:14 +0000 (19:04 +0530)
committerArun Prakash Jana <engineerarun@gmail.com>
Fri, 28 May 2021 13:47:08 +0000 (19:17 +0530)
plugins/README.md
plugins/fzcd
plugins/fzdirs [new file with mode: 0755]
src/nnn.c

index 2ab729dea9173de1b4b70e89fe7d9c12e52f8e4e..4cd176bcf69813854dd8da8a577f152826a1ac4a 100644 (file)
@@ -26,6 +26,7 @@ Plugins extend the capabilities of `nnn`. They are _executable_ scripts (or bina
 | [finder](finder) | Run custom find command and list | sh | - |
 | [fixname](fixname) | Clean filename to be more shell-friendly [✓] | bash | sed |
 | [fzcd](fzcd) | Change to the directory of a fuzzy-selected file/dir | sh | fzf |
+| [fzdirs](fzdirs) | Fuzzy search multiple directories [✓] | sh | fzf, fd |
 | [fzhist](fzhist) | Fuzzy-select a cmd from history, edit in `$EDITOR` and run | sh | fzf, mktemp |
 | [fzopen](fzopen) | Fuzzy find file(s) in subtree to edit/open/pick | sh | fzf, xdg-open |
 | [fzplug](fzplug) | Fuzzy find, preview and run other plugins | sh | fzf |
@@ -189,9 +190,9 @@ Notes:
 When `nnn` executes a plugin, it does the following:
 - Changes to the directory where the plugin is to be run (`$PWD` pointing to the active directory)
 - Passes three arguments to the script:
-    1. The hovered file's name.
-    2. The working directory (might differ from `$PWD` in case of symlinked paths; non-canonical).
-    3. The picker mode output file (`-` for stdout) if `nnn` is executed as a file picker.
+    1. `$1`: The hovered file's name.
+    2. `$2`: The working directory (might differ from `$PWD` in case of symlinked paths; non-canonical).
+    3. `$3`: The picker mode output file (`-` for stdout) if `nnn` is executed as a file picker.
 - Sets the environment variable `NNN_PIPE` used to control `nnn` active directory.
 
 Plugins can also read the `.selection` file in the config directory.
@@ -200,21 +201,24 @@ Plugins can also read the `.selection` file in the config directory.
 
 Plugins can be written in any scripting language. However, POSIX-compliant shell scripts runnable in `sh` are preferred.
 
-Drop the plugin in `${XDG_CONFIG_HOME:-$HOME/.config}/nnn/plugins` and make it executable. Optionally add a hotkey in `$NNN_PLUG` for frequent usage.
+Make the file executable and drop it in the plugin install directory. Optionally add a hotkey in `$NNN_PLUG` for frequent usage.
 
 #### Send data to `nnn`
 `nnn` provides a mechanism for plugins to send data to `nnn` to control its active directory or invoke the list mode.
 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 `<ctxcode><opcode><data>` without a newline at the end. For example, `1c/etc`.
+The plugin should write a single string in the format `(<->)<ctxcode><opcode><data>` without a newline at the end. For example, `1c/etc`.
+
+The optional `-` at the **beginning of the stream** instructs `nnn` to clear the selection.
+In cases where the data transfer to `nnn` has to happen while the selection file is being read (e.g. in a loop), the plugin should
+create a tmp copy of the selection file, inform `nnn` to clear the selection and then do the subsequent processing with the tmp file.
 
 The `ctxcode` indicates the context to change the active directory of.
 
 | Context code | Meaning |
 |:---:| --- |
-| `1`-`4` | context number |
-| `0` | current context |
 | `+` | smart context (next inactive else current) |
-| `-` | clear the selection |
+| `0` | current context |
+| `1`-`4` | context number |
 
 The `opcode` indicates the operation type.
 
index 907f4f9406396600f9650007534a3b9a3492415d..537e50e867fd77138a91eec8ea30a1a204c618ee 100755 (executable)
@@ -9,7 +9,7 @@
 
 if [ "$(cmd_exists fzf)" -eq "0" ]; then
        sel=$(fzf)
-    # Show only the file ane parent dir
+    # Show only the file and parent dir
     # sel=$(fzf --delimiter / --with-nth=-2,-1 --tiebreak=begin --info=hidden)
 else
        exit 1
diff --git a/plugins/fzdirs b/plugins/fzdirs
new file mode 100755 (executable)
index 0000000..57748a6
--- /dev/null
@@ -0,0 +1,70 @@
+#!/usr/bin/env sh
+
+# Description: Fuzzy search multiple locations read-in from a path-list
+#              file and open the selected file's directory in a smart context.
+# Dependencies: fzf, fd
+#
+# Details: Paths in list file should be newline-separated absolute paths.
+#          Paths can be file paths; the script will scan the parent dirs.
+#
+#          The path-list file can be generated easily:
+#          - pick the (file)paths in picker mode to path-list file
+#          - OR, edit selection in nnn and save as path-list file
+#
+#          The plugin clears nnn selection as the user can be tempted to delete
+#          duplicate files after finding copies and remove selection by mistake.
+#
+# Shell: POSIX compliant
+# Author: Arun Prakash Jana
+
+IFS="$(printf '\n\r')"
+
+. "$(dirname "$0")"/.nnn-plugin-helper
+
+CTX=+
+
+if [ "$(cmd_exists fzf)" -eq "0" ] && [ -s "$1" ]; then
+
+    tmpfile=$(mktemp /tmp/abc-script.XXXXXX)
+
+    for entry in $(tr '\0' '\n' < "$1")
+    do
+        if [ -d "$entry" ]; then
+            printf "%s\n" "$entry" >> "$tmpfile"
+        elif [ -f "$entry" ]; then
+            printf "%s\n" "$(dirname "$entry")" >> "$tmpfile"
+        fi
+    done
+
+    # Clear selection
+    if [ -p "$NNN_PIPE" ]; then
+        printf "-" >"$NNN_PIPE"
+    fi
+
+    sel=$(xargs -d '\n' -a "$tmpfile" fd -H . | fzf --delimiter / --tiebreak=begin --info=hidden)
+
+    rm "$tmpfile"
+else
+       exit 1
+fi
+
+if [ -n "$sel" ]; then
+    if [ "$sel" = "." ] || { ! [ -d "$sel" ] && ! [ -f "$sel" ]; }; then
+        exit 0
+    fi
+
+    # Check if selected path returned
+    # by fzf command is absolute
+    case $sel in
+    /*) nnn_cd "$sel" "$CTX" ;;
+    *)
+        # Remove "./" prefix if it exists
+        sel="${sel#./}"
+
+        if [ "$PWD" = "/" ]; then
+            nnn_cd "/$sel" "$CTX"
+        else
+            nnn_cd "$PWD/$sel" "$CTX"
+        fi;;
+    esac
+fi
index e13750e1434f6179979bb1a8c69eecf34dc7b3aa..6faca85dd9b17dd7d392ee1eb91f5caace938e5d 100644 (file)
--- a/src/nnn.c
+++ b/src/nnn.c
@@ -4758,17 +4758,19 @@ static void readpipe(int fd, char **path, char **lastname, char **lastdir)
 {
        int r;
        char ctx, *nextpath = NULL;
-       ssize_t len = read_nointr(fd, g_buf, 1);
 
-       if (len != 1)
+       if (read_nointr(fd, g_buf, 1) != 1)
                return;
 
+       if (g_buf[0] == '-') { /* Clear selection on '-' */
+               clearselection();
+               if (read_nointr(fd, g_buf, 1) != 1)
+                       return;
+       }
+
        if (g_buf[0] == '+')
                ctx = (char)(get_free_ctx() + 1);
-       else if (g_buf[0] == '-') { /* Clear selection on '-' */
-               clearselection();
-               return;
-       } else if (g_buf[0] < '0')
+       else if (g_buf[0] < '0')
                return;
        else {
                ctx = g_buf[0] - '0';
@@ -4776,14 +4778,14 @@ static void readpipe(int fd, char **path, char **lastname, char **lastdir)
                        return;
        }
 
-       len = read_nointr(fd, g_buf, 1);
-       if (len != 1)
+       if (read_nointr(fd, g_buf, 1) != 1)
                return;
 
        char op = g_buf[0];
 
        if (op == 'c') {
-               len = read_nointr(fd, g_buf, PATH_MAX);
+               ssize_t len = read_nointr(fd, g_buf, PATH_MAX);
+
                if (len <= 0)
                        return;