From 359d7bc29c9555b18bad16cbb78bd44875abc9dc Mon Sep 17 00:00:00 2001 From: Arun Prakash Jana Date: Wed, 8 Sep 2021 19:14:05 +0530 Subject: [PATCH] Directory-specific sort order --- README.md | 1 + nnn.1 | 10 ++++++++ src/nnn.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 78 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 52d8d3b5..baa3c4cb 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,7 @@ It runs smoothly on the Pi, [Termux](https://www.youtube.com/embed/AbaauM7gUJw) - Case-insensitive version (_aka_ natural) sort - By name, access/change/mod (default) time, size, extn - Reverse sort + - Directory-specific ordering - Mimes - Preview hovered files in FIFO-based previewer - Open with desktop opener or specify a custom opener diff --git a/nnn.1 b/nnn.1 index a172f39c..d0502c2e 100644 --- a/nnn.1 +++ b/nnn.1 @@ -127,6 +127,7 @@ supports the following options: .Fl "T key" sort order keys: 'a'u / 'd'u / 'e'xtension / 'r'everse / 's'ize / 't'ime / 'v'ersion + capitalize to reverse (except 'r') .Pp .Fl u use selection if available, don't prompt to choose between selection and hovered entry @@ -429,6 +430,15 @@ separated by \fI;\fR: Online docs: https://github.com/jarun/nnn/tree/master/plugins .Ed .Pp +\fBNNN_ORDER:\fR directory-specific sort key. +.Bd -literal + export NNN_ORDER='t:/home/user/Downloads;S:/tmp' + + NOTE: Sort keys can be a/d/e/r/s/t/v (see program option -T). + Capitalize to reverse (except 'r'). + Path must be absolute. +.Ed +.Pp \fBNNN_COLORS:\fR string of color numbers for each context, e.g.: .Bd -literal # 8 color numbers: diff --git a/src/nnn.c b/src/nnn.c index 167fdf3a..82b3fcf8 100644 --- a/src/nnn.c +++ b/src/nnn.c @@ -166,6 +166,9 @@ #define ISODD(x) ((x) & 1) #define ISBLANK(x) ((x) == ' ' || (x) == '\t') #define TOUPPER(ch) (((ch) >= 'a' && (ch) <= 'z') ? ((ch) - 'a' + 'A') : (ch)) +#define TOLOWER(ch) (((ch) >= 'A' && (ch) <= 'Z') ? ((ch) - 'A' + 'a') : (ch)) +#define ISUPPER_(ch) ((ch) >= 'A' && (ch) <= 'Z') +#define ISLOWER_(ch) ((ch) >= 'a' && (ch) <= 'z') #define CMD_LEN_MAX (PATH_MAX + ((NAME_MAX + 1) << 1)) #define ALIGN_UP(x, A) ((((x) + (A) - 1) / (A)) * (A)) #define READLINE_MAX 256 @@ -430,9 +433,11 @@ static int fifofd = -1; static uint_t idletimeout, selbufpos, selbuflen; static ushort_t xlines, xcols; static ushort_t idle; -static uchar_t maxbm, maxplug; +static uchar_t maxbm, maxplug, maxorder; +static uchar_t cfgsort[CTX_MAX + 1]; static char *bmstr; static char *pluginstr; +static char *orderstr; static char *opener; static char *editor; static char *enveditor; @@ -457,6 +462,7 @@ static struct entry *pdents; static blkcnt_t dir_blocks; static kv *bookmark; static kv *plug; +static kv *order; static uchar_t tmpfplen, homelen; static uchar_t blk_shift = BLK_SHIFT_512; #ifndef NOMOUSE @@ -684,8 +690,9 @@ static const char * const messages[] = { #define NNN_MCLICK 8 #define NNN_SEL 9 #define NNN_ARCHIVE 10 -#define NNN_HELP 11 /* strings end here */ -#define NNN_TRASH 12 /* flags begin here */ +#define NNN_ORDER 11 +#define NNN_HELP 12 /* strings end here */ +#define NNN_TRASH 13 /* flags begin here */ static const char * const env_cfg[] = { "NNN_OPTS", @@ -699,6 +706,7 @@ static const char * const env_cfg[] = { "NNN_MCLICK", "NNN_SEL", "NNN_ARCHIVE", + "NNN_ORDER", "NNN_HELP", "NNN_TRASH", }; @@ -3788,6 +3796,22 @@ static char *get_kv_val(kv *kvarr, char *buf, int key, uchar_t max, uchar_t id) return NULL; } +static int get_kv_key(kv *kvarr, char *val, uchar_t max, uchar_t id) +{ + if (!kvarr) + return -1; + + if (id != NNN_ORDER) /* For now this function supports only order string */ + return -1; + + for (int r = 0; kvarr[r].key && r < max; ++r) { + if (xstrcmp((orderstr + kvarr[r].off), val) == 0) + return kvarr[r].key; + } + + return -1; +} + static void resetdircolor(int flags) { /* Directories are always shown on top, clear the color when moving to first file */ @@ -4171,13 +4195,19 @@ static void savecurctx(char *path, char *curname, int nextctx) g_ctx[tmpcfg.curctx].c_cfg = tmpcfg; - if (ctxr->c_cfg.ctxactive) /* Switch to saved context */ + if (ctxr->c_cfg.ctxactive) { /* Switch to saved context */ tmpcfg = ctxr->c_cfg; - else { /* Set up a new context from current context */ + /* Skip ordering an open context */ + cfgsort[CTX_MAX] = cfgsort[nextctx]; + cfgsort[nextctx] = '0'; + } else { /* Set up a new context from current context */ ctxr->c_cfg.ctxactive = 1; xstrsncpy(ctxr->c_path, path, PATH_MAX); ctxr->c_last[0] = ctxr->c_name[0] = ctxr->c_fltr[0] = ctxr->c_fltr[1] = '\0'; ctxr->c_cfg = tmpcfg; + /* If already in an ordered dir, clear ordering for the new context and let it order */ + if (cfgsort[cfg.curctx] == 'z') + cfgsort[nextctx] = 'z'; } tmpcfg.curctx = nextctx; @@ -5950,7 +5980,13 @@ static int handle_context_switch(enum action sel) static int set_sort_flags(int r) { - bool session = !r; + bool session = (r == '\0'); + bool reverse = FALSE; + + if (ISUPPER_(r) && (r != 'R') && (r != 'C')) { + reverse = TRUE; + r = TOLOWER(r); + } /* Set the correct input in case of a session load */ if (session) { @@ -6060,6 +6096,13 @@ static int set_sort_flags(int r) return 0; } + if (reverse) { + cfg.reverse = 1; + entrycmpfn = &reventrycmp; + } + + cfgsort[cfg.curctx] = (uchar_t)r; + return r; } @@ -6488,7 +6531,8 @@ static bool browse(char *ipath, const char *session, int pkey) errexit(); begin: - /* Can fail when permissions change while browsing. + /* + * Can fail when permissions change while browsing. * It's assumed that path IS a directory when we are here. */ if (chdir(path) == -1) { @@ -6533,6 +6577,16 @@ begin: } #endif + if (cfgsort[cfg.curctx] == 'z') + set_sort_flags('c'); + if (order && (!cfgsort[cfg.curctx] || (cfgsort[cfg.curctx] == 'c')) + && ((r = get_kv_key(order, path, maxorder, NNN_ORDER)) > 0)) { + set_sort_flags(r); + cfgsort[cfg.curctx] = 'z'; + } + if (cfgsort[cfg.curctx] == '0') + cfgsort[cfg.curctx] = cfgsort[CTX_MAX]; + populate(path, lastname); if (g_state.interrupt) { g_state.interrupt = cfg.apparentsz = cfg.blkorder = 0; @@ -8356,6 +8410,12 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; } + /* Parse order string */ + if (!parsekvpair(&order, &orderstr, NNN_ORDER, &maxorder)) { + msg(env_cfg[NNN_ORDER]); + return EXIT_FAILURE; + } + if (!initpath) { if (arg) { /* Open a bookmark directly */ if (!arg[1]) /* Bookmarks keys are single char */ -- 2.48.1