From 3096dfefded84ea28d988faa5e14bec62bd7fa7c Mon Sep 17 00:00:00 2001 From: Arun Prakash Jana Date: Tue, 25 Apr 2017 10:01:52 +0530 Subject: [PATCH] Polish change directory logic 1. Strip end spaces and slashes 2. Do NOT change dir if in the same dir 3. Don't go back beyond startup dir with '-' 4. Reset oldpath on cd (other than cd . and ..) 5. Reset filter 6. Update features in README --- README.md | 11 +++-- config.def.h | 2 +- nnn.c | 121 ++++++++++++++++++++++++++++++++++----------------- 3 files changed, 91 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index 47f35fff..c6d40673 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ Noice is Not Noice, a noicer fork... - [How to](#how-to) - [cd on quit](#cd-on-quit) - [Copy current file path to clipboard](#copy-current-file-path-to-clipboard) + - [Boost chdir prompt](#boost-chdir-prompt) - [Change file associations](#change-file-associations) - [Why fork?](#why-fork) - [Developers](#developers) @@ -54,12 +55,12 @@ Have fun with it! PRs are welcome. Check out [#1](https://github.com/jarun/nnn/i ### Features - Super-easy navigation with roll-over at edges -- Jump HOME or back to the last visited directory (as you normally do!) +- Jump HOME or back to the last visited directory (as usual!) +- Jump to initial dir, chdir prompt, cd ..... (with . as PWD) - Desktop opener integration to handle mime types - Customizable bash script nlay to handle known file types - Disk usage analyzer mode -- Basic and detail views -- Show stat and file information +- Basic and detail view (with stat and file information) - Show media information (needs mediainfo) - Sort by modification time, size - Sort numeric names in numeric order (1, 2, ... 10, 11, ...) @@ -260,6 +261,10 @@ export `NNN_OPENER`: Start nnn and use `^K` to copy the absolute path (from `/`) of the file under the cursor to clipboard. +#### Boost chdir prompt + +nnn uses libreadline for the chdir prompt input. So all the fantastic features of readline (e.g. case insensitive tab completion, history, reverse-i-search) is available to you based on your readline [configuration](https://cnswww.cns.cwru.edu/php/chet/readline/readline.html#SEC9). + #### Change file associations If `NNN_OPENER` is not set, nnn tries to recognize a file by the file extension and invokes nlay. To change the extensions recognized by nnn, modify the `assocs` structure in [config.def.h](https://github.com/jarun/nnn/blob/master/config.def.h) (it's easy). Then re-compile and install. diff --git a/config.def.h b/config.def.h index 1b53f6b7..e23fe3c3 100644 --- a/config.def.h +++ b/config.def.h @@ -66,7 +66,7 @@ static struct key bindings[] = { /* Initial directory */ { '&', SEL_CDBEGIN, "", "" }, /* Last visited dir */ - { '-', SEL_LAST, "", "" }, + { '-', SEL_CDLAST, "", "" }, /* Toggle hide .dot files */ { '.', SEL_TOGGLEDOT, "", "" }, /* Detailed listing */ diff --git a/nnn.c b/nnn.c index 00f7d987..031ffe2d 100644 --- a/nnn.c +++ b/nnn.c @@ -90,7 +90,7 @@ enum action { SEL_CD, SEL_CDHOME, SEL_CDBEGIN, - SEL_LAST, + SEL_CDLAST, SEL_TOGGLEDOT, SEL_DETAIL, SEL_STATS, @@ -386,22 +386,18 @@ xstricmp(const char *s1, const char *s2) return (int) (TOUPPER(*s1) - TOUPPER(*s2)); } -/* Trim all white space from both ends */ +/* Trim all whitespace from both ends, / from end */ static char * strstrip(char *s) { - size_t size; - char *end; - - size = strlen(s); - - if (!size) + if (!s || !*s) return s; - end = s + size - 1; - while (end >= s && isspace(*end)) - end--; - *(end + 1) = '\0'; + size_t len = strlen(s) - 1; + + while (len != 0 && (isspace(s[len]) || s[len] == '/')) + len--; + s[len + 1] = '\0'; while (*s && isspace(*s)) s++; @@ -1281,10 +1277,10 @@ browse(char *ipath, char *ifilter) enum action sel = SEL_RUNARG + 1; xstrlcpy(path, ipath, sizeof(path)); - xstrlcpy(lastdir, ipath, sizeof(lastdir)); xstrlcpy(fltr, ifilter, sizeof(fltr)); oldpath[0] = '\0'; newpath[0] = '\0'; + lastdir[0] = '\0'; /* Can't move back from initial directory */ begin: if (sel == SEL_GOIN && S_ISDIR(sb.st_mode)) @@ -1471,56 +1467,66 @@ nochange: break; case SEL_CD: { - /* Read target dir */ + static char *tmp, *input; + static int truecd; + + /* Save the program start dir */ tmp = getcwd(newpath, PATH_MAX); if (tmp == NULL) { printwarn(); goto nochange; } + /* Switch to current path for readline(3) */ if (chdir(path) == -1) { printwarn(); goto nochange; } exitcurses(); - char *tmp = readline("chdir: "); + tmp = readline("chdir: "); initcurses(); + /* Change back to program start dir */ if (chdir(newpath) == -1) printwarn(); - /* Save current */ - if (ndents > 0) - mkpath(path, dents[cur].name, oldpath, sizeof(oldpath)); - if (tmp[0] == '\0') break; else + /* Add to readline(3) history */ add_history(tmp); - char *input = tmp; + input = tmp; tmp = strstrip(tmp); if (tmp[0] == '\0') { free(input); break; } + truecd = 0; + if (tmp[0] == '~') { + /* Expand ~ to HOME absolute path */ char *home = getenv("HOME"); if (home) - snprintf(newpath, PATH_MAX, - "%s%s", home, tmp + 1); - else - mkpath(path, tmp, newpath, sizeof(newpath)); - - oldpath[0] = '\0'; + snprintf(newpath, PATH_MAX, "%s%s", home, tmp + 1); + else { + free(input); + break; + } } else if (tmp[0] == '-' && tmp[1] == '\0') { - xstrlcpy(newpath, lastdir, sizeof(newpath)); - oldpath[0] = '\0'; + if (lastdir[0] == '\0') { + free(input); + break; + } + /* Switch to last visited dir */ + xstrlcpy(newpath, lastdir, sizeof(newpath)); + truecd = 1; } else if ((r = all_dots(tmp))) { if (r == 1) { + /* Always in the current dir */ free(input); break; } @@ -1529,15 +1535,17 @@ nochange: dir = path; for (fd = 0; fd < r; fd++) { - /* There is no going back */ + /* Reached / ? */ if (strcmp(path, "/") == 0 || strchr(path, '/') == NULL) { + /* If it's a cd .. at / */ if (fd == 0) { printmsg("You are at /"); free(input); goto nochange; } + /* Can't cd beyond / anyway */ break; } else { dir = xdirname(dir); @@ -1549,28 +1557,44 @@ nochange: } } - /* Save history */ - xstrlcpy(oldpath, path, sizeof(oldpath)); + truecd = 1; + + /* Save the path in case of cd .. + We mark the current dir in parent dir */ + if (r == 1) { + xstrlcpy(oldpath, path, sizeof(oldpath)); + truecd = 2; + } + xstrlcpy(newpath, dir, sizeof(newpath)); - } else { + } else mkpath(path, tmp, newpath, sizeof(newpath)); - oldpath[0] = '\0'; - } if (canopendir(newpath) == 0) { - /* Save current */ - if (ndents > 0) - mkpath(path, dents[cur].name, oldpath, sizeof(oldpath)); - printwarn(); free(input); break; } + if (truecd == 0) { + /* Probable change in dir */ + /* No-op if it's the same directory */ + if (strcmp(path, newpath) == 0) { + free(input); + break; + } + + oldpath[0] = '\0'; + } else if (truecd == 1) + /* Sure change in dir */ + oldpath[0] = '\0'; + /* Save last working directory */ xstrlcpy(lastdir, path, sizeof(lastdir)); + /* Save the newly opted dir in path */ xstrlcpy(path, newpath, sizeof(path)); + /* Reset filter */ xstrlcpy(fltr, ifilter, sizeof(fltr)); DPRINTF_S(path); @@ -1583,15 +1607,20 @@ nochange: clearprompt(); goto nochange; } + if (canopendir(tmp) == 0) { printwarn(); goto nochange; } + if (strcmp(path, tmp) == 0) + break; + /* Save last working directory */ xstrlcpy(lastdir, path, sizeof(lastdir)); xstrlcpy(path, tmp, sizeof(path)); + oldpath[0] = '\0'; /* Reset filter */ xstrlcpy(fltr, ifilter, sizeof(fltr)); DPRINTF_S(path); @@ -1602,19 +1631,33 @@ nochange: goto nochange; } + if (strcmp(path, ipath) == 0) + break; + /* Save last working directory */ xstrlcpy(lastdir, path, sizeof(lastdir)); xstrlcpy(path, ipath, sizeof(path)); + oldpath[0] = '\0'; /* Reset filter */ xstrlcpy(fltr, ifilter, sizeof(fltr)); DPRINTF_S(path); goto begin; - case SEL_LAST: + case SEL_CDLAST: + if (lastdir[0] == '\0') + break; + + if (canopendir(lastdir) == 0) { + printwarn(); + goto nochange; + } + xstrlcpy(newpath, lastdir, sizeof(newpath)); xstrlcpy(lastdir, path, sizeof(lastdir)); xstrlcpy(path, newpath, sizeof(path)); oldpath[0] = '\0'; + /* Reset filter */ + xstrlcpy(fltr, ifilter, sizeof(fltr)); DPRINTF_S(path); goto begin; case SEL_TOGGLEDOT: