<p align="center"><i>nnn in action! (click to play video)</i></a></p>
-`nnn` is probably the [fastest and most resource-sensitive](#performance) file manager you have ever used. It integrates seamlessly with your DE and favourite GUI utilities, has a unique [navigate-as-you-type](#navigate-as-you-type-mode) mode with auto-select, disk usage analyzer mode, bookmarks, familiar navigation shortcuts, subshell spawning and much more.
+`nnn` is probably the [fastest and most resource-sensitive](#performance) file manager you have ever used. It integrates seamlessly with your DE and favourite GUI utilities, has a unique [navigate-as-you-type](#navigate-as-you-type-mode) mode with auto-select, disk usage analyzer mode, bookmarks, contexts, familiar navigation shortcuts, subshell spawning and much more.
[Integrate utilities](https://github.com/jarun/nnn#sample-scripts) like sxiv or fzy easily; `nnn` supports as many scripts as you need!
- [Quickstart](#quickstart)
- [How to](#how-to)
- [add bookmarks](#add-bookmarks)
+ - [contexts](#contexts)
- [copy file paths](#copy-file-paths)
- [selection shortcuts](#selection-shortcuts)
- [default copy](#default-copy)
- [cd on quit](#cd-on-quit)
- [run custom scripts](#run-custom-scripts)
- [sample scripts](#sample-scripts)
- - [dual-pane or multi-pane](#dual-pane-or-multi-pane)
- [change dir color](#change-dir-color)
- [integrate patool](#integrate-patool)
- [work faster at rename prompt](#work-faster-at-rename-prompt)
- Familiar, easy shortcuts (arrows, `~`, `-`, `&`)
- *Navigate-as-you-type* mode with dir auto-select for the maverick
- Handy bookmarks, start at bookmark, pin and visit directory
+ - Multiple contexts
- Roll-over at edges, page through entries
- Show directories in custom color (default: enabled in blue)
- Sorting
The bookmark prompt also understands the <kbd>~</kbd> (HOME), <kbd>-</kbd> (last visited directory) and <kbd>&</kbd> (start directory) shortcuts.
+#### contexts
+
+Contexts (aka _tabs_ aka _workspaces_) serve the purpose of exploring multiple directories in parallel. `nnn` provides 4 contexts simultaneously. The status of the contexts are shown in the top left corner:
+
+- the current context is in reverse
+- other used contexts are underlined
+- rest are unused
+
+The bookmark prompt understands contexts. To switch contexts press `^B` and enter the context number (1-4).
+
+The first time a context is entered, it copies the state of the last visited context. Each context remembers its start directory and last visited directory.
+
#### copy file paths
##### selection shortcuts
xdg-open $(find -type f | fzy) >/dev/null 2>&1
-#### dual-pane or multi-pane
-
-`nnn` doesn't have a native dual-pane or multi-pane mode. On most modern DEs the default terminal emulator handles that. Other options are tmux, GNU Screen, Terminator, Tilix, AltYo and Byobu.
-
#### change dir color
The default color for directories is blue. Option `-c` accepts color codes from 0 to 7 to use a different color:
#define _ALIGNMENT_MASK 0xF
#define SYMLINK_TO_DIR 0x1
#define MAX_HOME_LEN 64
+#define MAX_CTX 4
/* Macros to define process spawn behaviour as flags */
#define F_NONE 0x00 /* no flag set */
/* Settings */
typedef struct {
- ushort filtermode : 1; /* Set to enter filter mode */
- ushort mtimeorder : 1; /* Set to sort by time modified */
- ushort sizeorder : 1; /* Set to sort by file size */
- ushort apparentsz : 1; /* Set to sort by apparent size (disk usage) */
- ushort blkorder : 1; /* Set to sort by blocks used (disk usage) */
- ushort showhidden : 1; /* Set to show hidden files */
- ushort copymode : 1; /* Set when copying files */
- ushort autoselect : 1; /* Auto-select dir in nav-as-you-type mode */
- ushort showdetail : 1; /* Clear to show fewer file info */
- ushort showcolor : 1; /* Set to show dirs in blue */
- ushort dircolor : 1; /* Current status of dir color */
- ushort metaviewer : 1; /* Index of metadata viewer in utils[] */
- ushort quote : 1; /* Copy paths within quotes */
- ushort color : 3; /* Color code for directories */
+ uint filtermode : 1; /* Set to enter filter mode */
+ uint mtimeorder : 1; /* Set to sort by time modified */
+ uint sizeorder : 1; /* Set to sort by file size */
+ uint apparentsz : 1; /* Set to sort by apparent size (disk usage) */
+ uint blkorder : 1; /* Set to sort by blocks used (disk usage) */
+ uint showhidden : 1; /* Set to show hidden files */
+ uint copymode : 1; /* Set when copying files */
+ uint autoselect : 1; /* Auto-select dir in nav-as-you-type mode */
+ uint showdetail : 1; /* Clear to show fewer file info */
+ uint showcolor : 1; /* Set to show dirs in blue */
+ uint dircolor : 1; /* Current status of dir color */
+ uint metaviewer : 1; /* Index of metadata viewer in utils[] */
+ uint quote : 1; /* Copy paths within quotes */
+ uint color : 3; /* Color code for directories */
+ uint ctxactive : 1; /* Context active or not */
+ uint reserved : 15;
} settings;
+/* Contexts or workspaces */
+typedef struct {
+ char c_name[NAME_MAX + 1];
+ char c_fltr[NAME_MAX + 1];
+ char c_path[PATH_MAX];
+ char c_init[PATH_MAX];
+ char c_last[PATH_MAX];
+ settings c_cfg;
+} context;
+
/* GLOBALS */
-/* Configuration */
-static settings cfg = {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 4};
+/* Configuration, contexts */
+static settings cfg = {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 4, 1, 0};
+static context g_ctx[MAX_CTX] __attribute__ ((aligned));
+static uchar g_curctx;
static struct entry *dents;
static char *pnamebuf, *pcopybuf;
DPRINTF_S("copymode off");
}
- /* Fail redraw if < than 10 columns */
- if (COLS < 10) {
+ /* Fail redraw if < than 11 columns, context info prints 10 chars */
+ if (COLS < 11) {
printmsg("too few columns!");
return;
}
if (ncols > PATH_MAX)
ncols = PATH_MAX;
+ printw("[");
+ for (i = 0; i < MAX_CTX; ++i) {
+ /* Print current context in reverse */
+ if (g_curctx == i) {
+ attron(A_REVERSE);
+ printw("%d", i + 1);
+ attroff(A_REVERSE);
+ printw(" ");
+ } else if (g_ctx[i].c_cfg.ctxactive) {
+ attron(A_UNDERLINE);
+ printw("%d", i + 1);
+ attroff(A_UNDERLINE);
+ printw(" ");
+ } else
+ printw("%d ", i + 1);
+ }
+ printw("\b] "); /* 10 chars printed in total for contexts - "[1 2 3 4] " */
+
attron(A_UNDERLINE);
/* No text wrapping in cwd line */
- g_buf[ncols - 1] = '\0';
+ g_buf[ncols - 11] = '\0';
printw("%s\n\n", g_buf);
attroff(A_UNDERLINE);
enum action sel = SEL_RUNARG + 1;
bool dir_changed = FALSE;
+ /* setup first context */
+ g_curctx = 0;
+ xstrlcpy(g_ctx[0].c_init, ipath, PATH_MAX);
+
xstrlcpy(path, ipath, PATH_MAX);
copyfilter();
oldname[0] = newpath[0] = lastdir[0] = mark[0] = '\0';
break;
/* Interpret ~, - and & keys */
- if ((tmp[1] == '\0') && (tmp[0] == '~' || tmp[0] == '-' || tmp[0] == '&')) {
- presel = tmp[0];
- goto begin;
+ if (tmp[1] == '\0') {
+ switch (tmp[0]) {
+ case '~': //fallthrough
+ case '-': //fallthrough
+ case '&':
+ presel = tmp[0];
+ goto begin;
+ case '1': //fallthrough
+ case '2': //fallthrough
+ case '3': //fallthrough
+ case '4':
+ {
+ uint nextctx = tmp[0] - '1';
+ if (g_curctx == nextctx)
+ continue;
+
+ g_crc = 0;
+
+ /* Save current context */
+ xstrlcpy(g_ctx[g_curctx].c_name, oldname, NAME_MAX + 1);
+ xstrlcpy(g_ctx[g_curctx].c_fltr, fltr, NAME_MAX + 1);
+ xstrlcpy(g_ctx[g_curctx].c_path, path, PATH_MAX);
+ xstrlcpy(g_ctx[g_curctx].c_last, lastdir, PATH_MAX);
+ g_ctx[g_curctx].c_cfg = cfg;
+
+ if (!g_ctx[nextctx].c_cfg.ctxactive) {
+ /* Setup a new context from current context */
+ g_ctx[nextctx].c_cfg.ctxactive = 1;
+ xstrlcpy(g_ctx[nextctx].c_name, oldname, NAME_MAX + 1);
+ xstrlcpy(g_ctx[nextctx].c_fltr, fltr, NAME_MAX + 1);
+ xstrlcpy(g_ctx[nextctx].c_path, path, PATH_MAX);
+ xstrlcpy(g_ctx[nextctx].c_init, path, PATH_MAX);
+ ipath = g_ctx[nextctx].c_init;
+ g_ctx[nextctx].c_last[0] = lastdir[0] = '\0';
+ g_ctx[nextctx].c_cfg = cfg;
+ } else {
+ /* Switch to saved context */
+ xstrlcpy(oldname, g_ctx[nextctx].c_name, NAME_MAX + 1);
+ xstrlcpy(fltr, g_ctx[nextctx].c_fltr, NAME_MAX + 1);
+ xstrlcpy(path, g_ctx[nextctx].c_path, PATH_MAX);
+ ipath = g_ctx[nextctx].c_init;
+ xstrlcpy(lastdir, g_ctx[nextctx].c_last, PATH_MAX);
+ cfg = g_ctx[nextctx].c_cfg;
+ }
+
+ g_curctx = nextctx;
+ goto begin;
+ }
+ }
}
if (get_bm_loc(tmp, newpath) == NULL) {