@@ -66,12 +66,23 @@ Plugins are installed to `${XDG_CONFIG_HOME:-$HOME/.config}/nnn/plugins`. You ca | |||||
With this, plugin `fzy-open` can be run with the keybind <kbd>:o</kbd>, `mocplay` can be run with <kbd>:p</kbd> and so on... The key vs. plugin pairs are shown in the help and config screen. Up to 10 plugins can have such keybinds. | With this, plugin `fzy-open` can be run with the keybind <kbd>:o</kbd>, `mocplay` can be run with <kbd>:p</kbd> and so on... The key vs. plugin pairs are shown in the help and config screen. Up to 10 plugins can have such keybinds. | ||||
To assign keys to arbitrary commands (non-shell-interpreted) and invoke like plugins, add `_` (underscore) before the command. For example: | To assign keys to arbitrary cli commands (non-shell-interpreted) and invoke like plugins, add `_` (underscore) before the command. For example: | ||||
export NNN_PLUG='x:_chmod +x;o:fzy-open' | export NNN_PLUG='x:_chmod +x;o:fzy-open' | ||||
**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. | **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. | ||||
## Access level of 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). Note that the second argument is not passed in case of commands starting with `_`. | |||||
- 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). | |||||
## Create your own plugins | ## Create your own plugins | ||||
Plugins are a powerful yet easy way to extend the capabilities of `nnn`. | Plugins are a powerful yet easy way to extend the capabilities of `nnn`. | ||||
@@ -82,15 +93,6 @@ Each script has a _Description_ section which provides more details on what the | |||||
The plugins reside in `${XDG_CONFIG_HOME:-$HOME/.config}/nnn/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). | |||||
#### 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`. | ||||
@@ -120,8 +120,7 @@ | |||||
#define MAX(x, y) ((x) > (y) ? (x) : (y)) | #define MAX(x, y) ((x) > (y) ? (x) : (y)) | ||||
#define ISODD(x) ((x) & 1) | #define ISODD(x) ((x) & 1) | ||||
#define ISBLANK(x) ((x) == ' ' || (x) == '\t') | #define ISBLANK(x) ((x) == ' ' || (x) == '\t') | ||||
#define TOUPPER(ch) \ | #define TOUPPER(ch) (((ch) >= 'a' && (ch) <= 'z') ? ((ch) - 'a' + 'A') : (ch)) | ||||
(((ch) >= 'a' && (ch) <= 'z') ? ((ch) - 'a' + 'A') : (ch)) | |||||
#define CMD_LEN_MAX (PATH_MAX + ((NAME_MAX + 1) << 1)) | #define CMD_LEN_MAX (PATH_MAX + ((NAME_MAX + 1) << 1)) | ||||
#define READLINE_MAX 128 | #define READLINE_MAX 128 | ||||
#define FILTER '/' | #define FILTER '/' | ||||
@@ -345,6 +344,7 @@ static char g_tmpfpath[TMP_LEN_MAX] __attribute__ ((aligned)); | |||||
/* Buffer to store plugins control pipe location */ | /* Buffer to store plugins control pipe location */ | ||||
static char g_pipepath[TMP_LEN_MAX] __attribute__ ((aligned)); | static char g_pipepath[TMP_LEN_MAX] __attribute__ ((aligned)); | ||||
/* Plugin control initialization status */ | |||||
static bool g_plinit = FALSE; | static bool g_plinit = FALSE; | ||||
/* Replace-str for xargs on different platforms */ | /* Replace-str for xargs on different platforms */ | ||||
@@ -3798,14 +3798,12 @@ static void redraw(char *path) | |||||
xcols = COLS; | xcols = COLS; | ||||
int ncols = (xcols <= PATH_MAX) ? xcols : PATH_MAX; | int ncols = (xcols <= PATH_MAX) ? xcols : PATH_MAX; | ||||
int lastln = xlines, onscreen = xlines - 4; | int lastln = xlines - 1, onscreen = xlines - 4; | ||||
int i, attrs; | int i, attrs; | ||||
char buf[24]; | char buf[24]; | ||||
char c; | char c; | ||||
char *ptr = path, *base; | char *ptr = path, *base; | ||||
--lastln; | |||||
/* Clear screen */ | /* Clear screen */ | ||||
erase(); | erase(); | ||||
@@ -3840,7 +3838,6 @@ static void redraw(char *path) | |||||
addch(' '); | addch(' '); | ||||
} | } | ||||
} | } | ||||
addstr("\b] "); /* 10 chars printed for contexts - "[1 2 3 4] " */ | addstr("\b] "); /* 10 chars printed for contexts - "[1 2 3 4] " */ | ||||
attron(A_UNDERLINE); | attron(A_UNDERLINE); | ||||
@@ -4951,11 +4948,14 @@ nochange: | |||||
if (tmp[0] == '_' && tmp[1]) { | if (tmp[0] == '_' && tmp[1]) { | ||||
xstrlcpy(newpath, ++tmp, PATH_MAX); | xstrlcpy(newpath, ++tmp, PATH_MAX); | ||||
flag = F_CLI | F_CONFIRM; | flag = F_CLI | F_CONFIRM; | ||||
} else | tmp = NULL; | ||||
} else { | |||||
mkpath(plugindir, tmp, newpath); | mkpath(plugindir, tmp, newpath); | ||||
tmp = path; | |||||
} | |||||
spawn(newpath, (ndents ? dents[cur].name : NULL), | spawn(newpath, (ndents ? dents[cur].name : NULL), | ||||
path, path, flag); | tmp, path, flag); | ||||
if (cfg.filtermode) | if (cfg.filtermode) | ||||
presel = FILTER; | presel = FILTER; | ||||