From 9afd7cf3bf8badb7e704fb1e1fbdb8031572c722 Mon Sep 17 00:00:00 2001 From: Anna Arad <4895022+annagrram@users.noreply.github.com> Date: Wed, 23 Oct 2019 13:04:12 +0300 Subject: Implement plugins control of nnn + plugins (#364) * Implement plugins control of nnn + plugins * Refactor plugins control code and fix getplugs to recognize hidden files * Fix bug when going to dir on non-current context from plugin * Fix some plugins to work on openbsd and freebsd * Renamings * Switch to -R flag in cp instead of -r; BSDs complain * Change braces of function location * Rewrite plugin creation in README and add new plugins to the table * Update the fzcd script to include fzy or fzf * Change plugin name resolve-link-dir -> lncd * Fixing plugins README table * Remove some cd plugins but add them as examples to plugins README --- plugins/.nnn-plugin-helper | 33 +++++++++++++++++++++++ plugins/README.md | 65 +++++++++++++++++++++++++++++++++++++--------- plugins/fzcd | 32 +++++++++++++++++++++++ plugins/getplugs | 24 ++++++++++++----- 4 files changed, 136 insertions(+), 18 deletions(-) create mode 100644 plugins/.nnn-plugin-helper create mode 100755 plugins/fzcd (limited to 'plugins') diff --git a/plugins/.nnn-plugin-helper b/plugins/.nnn-plugin-helper new file mode 100644 index 0000000..ec66a29 --- /dev/null +++ b/plugins/.nnn-plugin-helper @@ -0,0 +1,33 @@ +#!/usr/bin/env sh + +# Description: Helper script for plugins +# +# Shell: POSIX compliant +# Author: Anna Arad + +selection=${XDG_CONFIG_HOME:-$HOME/.config}/nnn/.selection + +## Ask nnn to switch to directory $1 in context $2. +## If $2 is not provided, the function asks explicitly. +nnn_cd () { + dir=$1 + + if [ -z "$NNN_PIPE" ]; then + echo "No pipe file found" 1>&2 + return + fi + + if [ -n "$2" ]; then + context=$2 + else + echo -n "Choose context 1-4 (blank for current): " + read context + fi + + echo -n ${context:-0}$dir > $NNN_PIPE +} + +cmd_exists () { + which "$1" > /dev/null 2>&1 + echo $? +} diff --git a/plugins/README.md b/plugins/README.md index 85550ca..9d48ec3 100644 --- a/plugins/README.md +++ b/plugins/README.md @@ -14,6 +14,7 @@ The currently available plugins are listed below. | checksum | sh | md5sum,
sha256sum | Create and verify checksums | | drag-file | sh | [dragon](https://github.com/mwh/dragon) | Drag and drop files from nnn | | drop-file | sh | [dragon](https://github.com/mwh/dragon) | Drag and drop files into nnn | +| fzcd | sh | fzy/fzf
(optional fd) | Change to the directory of a file/directory selected by fzy/fzf | | fzy-open | sh | fzy, xdg-open | Fuzzy find a file in dir subtree and edit or xdg-open | | getplugs | sh | curl | Update plugins | | gutenread | sh | curl, unzip, w3m
[epr](https://github.com/wustho/epr) (optional)| Browse, download, read from Project Gutenberg | @@ -67,28 +68,68 @@ With this, plugin `fzy-open` can be run with the keybind :o, `mocplay **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. -## File access from plugins +## Create your own plugins + +Plugins are a powerful yet easy way to extend the capabilities of `nnn`. -Plugins can access: -- all files in the directory (`nnn` switches to the dir where the plugin is to be run so the dir is `$PWD` for the plugin) -- the current file under the cursor (the file name is passed as the first argument to a plugin) -- the traversed path where plugin is invoked (this is the second argument to the plugin; for all practical purposes this is the same as `$PWD` except paths with symlinks) -- the current selection (by reading the file `.selection` in config dir, see the plugin `ndiff`) +Plugins are scripts that can be written in any scripting language. However, POSIX-compliant shell scripts runnable in `sh` are preferred. Each script has a _Description_ section which provides more details on what the script does, if applicable. -## Create your own plugins +The plugins reside in `${XDG_CONFIG_HOME:-$HOME/.config}/nnn/plugins`. + +When `nnn` executes a plugin, it does the following: +- Change to the directory where the plugin is to be run (`$PWD` pointing to the active directory) +- Passes two 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) +- Sets the environment variable `NNN_PIPE` used to control `nnn` active directory. + +Plugins can also access the current selections by reading the `.selections` file in the config directory (See the `ndiff` plugin for example). -Plugins are scripts and all scripting languages should work. However, POSIX-compliant shell scripts runnable in `sh` are preferred. If that's too rudimentary for your use case, use Python, Perl or Ruby. +#### 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). -You can create your own plugins by putting them in `${XDG_CONFIG_HOME:-$HOME/.config}/nnn/plugins`. +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. +Usage examples can be found in the Examples section below. -For example, you could create a executable shell script `git-changes`: +#### Examples +There are many plugins provided by `nnn` which can be used as examples. Here are a few simple selected examples. +- Show the git log of changes to the particular file along with the code for a quick and easy review. + ```sh #!/usr/bin/env sh - git log -p -- "$@" + git log -p -- "$1" + ``` + +- Change to directory in clipboard using helper script + ```sh + #!/usr/bin/env sh + . $(dirname $0/.nnn-plugin-helper) + + nnn_cd "$(xsel -ob)" + ``` -And then trigger it by hitting the pick plugin key and selecting `git-changes` which will conveniently show the git log of changes to the particular file along with the code for a quick and easy review. +- Change direcory to the location of a link using helper script with specific context (current) + ```sh + #!/usr/bin/env sh + . $(dirname $0/.nnn-plugin-helper) + + nnn_cd "$(dirname $(readlink -fn $1))" 0 + ``` + +- Change to arbitrary directory without helper script + ```sh + #!/usr/bin/env sh + echo -n "cd to: " + read dir + + echo -n "0$dir" > $NNN_PIPE + ``` ## Contributing plugins diff --git a/plugins/fzcd b/plugins/fzcd new file mode 100755 index 0000000..443ac2d --- /dev/null +++ b/plugins/fzcd @@ -0,0 +1,32 @@ +#!/usr/bin/env sh + +# Description: Run fzf and go to the directory of the file selected +# +# Shell: POSIX compliant +# Author: Anna Arad + +. $(dirname $0)/.nnn-plugin-helper + +if [ "$(cmd_exists fzy)" -eq "0" ]; then + if [ "$(cmd_exists fd)" -eq "0" ]; then + fd=fd + elif [ "$(cmd_exists fdfind)" -eq "0" ]; then + fd=fdfind + else + fd=find + fi + + sel=$($fd | fzy) +elif [ "$(cmd_exists fzf)" -eq "0" ]; then + sel=$(fzf --print0) +else + exit 1 +fi + +if [ "$?" -eq "0" ]; then + case "$(file -bi "$sel")" in + *directory*) ;; + *) sel=$(dirname $sel) ;; + esac + nnn_cd "$PWD/$sel" +fi diff --git a/plugins/getplugs b/plugins/getplugs index e144be3..42d5400 100755 --- a/plugins/getplugs +++ b/plugins/getplugs @@ -8,15 +8,27 @@ CONFIG_DIR=${XDG_CONFIG_HOME:-$HOME/.config}/nnn/ PLUGIN_DIR=${XDG_CONFIG_HOME:-$HOME/.config}/nnn/plugins +is_cmd_exists () { + which "$1" > /dev/null 2>&1 + echo $? +} + +if [ "$(is_cmd_exists sudo)" == "0" ]; then + sucmd=sudo +elif [ "$(is_cmd_exists doas)" == "0" ]; then + sucmd=doas +else + sucmd=: # noop +fi + # backup any earlier plugins if [ -d $PLUGIN_DIR ]; then - tar -C $CONFIG_DIR -cf $CONFIG_DIR"plugins-$(date '+%Y%m%d%H%M').tar.bz2" plugins/ + tar -C $CONFIG_DIR -czf $CONFIG_DIR"plugins-$(date '+%Y%m%d%H%M').tar.gz" plugins/ fi -mkdir -p $PLUGIN_DIR -cd $PLUGIN_DIR +cd $CONFIG_DIR curl -Ls -O https://github.com/jarun/nnn/archive/master.tar.gz -tar -xf master.tar.gz -cp -vf nnn-master/plugins/* . -sudo mv -vf nnn-master/misc/nlaunch/nlaunch /usr/local/bin/ +tar -zxf master.tar.gz +cp -vRf nnn-master/plugins . +$sucmd mv -vf nnn-master/misc/nlaunch/nlaunch /usr/local/bin/ rm -rf nnn-master/ master.tar.gz README.md -- cgit v1.2.3-70-g09d2