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
This commit is contained in:
Arun Prakash Jana 2017-04-25 10:01:52 +05:30
parent febda38c14
commit 3096dfefde
No known key found for this signature in database
GPG key ID: A75979F35C080412
3 changed files with 91 additions and 43 deletions

View file

@ -33,6 +33,7 @@ Noice is Not Noice, a noicer fork...
- [How to](#how-to) - [How to](#how-to)
- [cd on quit](#cd-on-quit) - [cd on quit](#cd-on-quit)
- [Copy current file path to clipboard](#copy-current-file-path-to-clipboard) - [Copy current file path to clipboard](#copy-current-file-path-to-clipboard)
- [Boost chdir prompt](#boost-chdir-prompt)
- [Change file associations](#change-file-associations) - [Change file associations](#change-file-associations)
- [Why fork?](#why-fork) - [Why fork?](#why-fork)
- [Developers](#developers) - [Developers](#developers)
@ -54,12 +55,12 @@ Have fun with it! PRs are welcome. Check out [#1](https://github.com/jarun/nnn/i
### Features ### Features
- Super-easy navigation with roll-over at edges - 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 - Desktop opener integration to handle mime types
- Customizable bash script nlay to handle known file types - Customizable bash script nlay to handle known file types
- Disk usage analyzer mode - Disk usage analyzer mode
- Basic and detail views - Basic and detail view (with stat and file information)
- Show stat and file information
- Show media information (needs mediainfo) - Show media information (needs mediainfo)
- Sort by modification time, size - Sort by modification time, size
- Sort numeric names in numeric order (1, 2, ... 10, 11, ...) - 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. 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 #### 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. 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.

View file

@ -66,7 +66,7 @@ static struct key bindings[] = {
/* Initial directory */ /* Initial directory */
{ '&', SEL_CDBEGIN, "", "" }, { '&', SEL_CDBEGIN, "", "" },
/* Last visited dir */ /* Last visited dir */
{ '-', SEL_LAST, "", "" }, { '-', SEL_CDLAST, "", "" },
/* Toggle hide .dot files */ /* Toggle hide .dot files */
{ '.', SEL_TOGGLEDOT, "", "" }, { '.', SEL_TOGGLEDOT, "", "" },
/* Detailed listing */ /* Detailed listing */

121
nnn.c
View file

@ -90,7 +90,7 @@ enum action {
SEL_CD, SEL_CD,
SEL_CDHOME, SEL_CDHOME,
SEL_CDBEGIN, SEL_CDBEGIN,
SEL_LAST, SEL_CDLAST,
SEL_TOGGLEDOT, SEL_TOGGLEDOT,
SEL_DETAIL, SEL_DETAIL,
SEL_STATS, SEL_STATS,
@ -386,22 +386,18 @@ xstricmp(const char *s1, const char *s2)
return (int) (TOUPPER(*s1) - TOUPPER(*s2)); return (int) (TOUPPER(*s1) - TOUPPER(*s2));
} }
/* Trim all white space from both ends */ /* Trim all whitespace from both ends, / from end */
static char * static char *
strstrip(char *s) strstrip(char *s)
{ {
size_t size; if (!s || !*s)
char *end;
size = strlen(s);
if (!size)
return s; return s;
end = s + size - 1; size_t len = strlen(s) - 1;
while (end >= s && isspace(*end))
end--; while (len != 0 && (isspace(s[len]) || s[len] == '/'))
*(end + 1) = '\0'; len--;
s[len + 1] = '\0';
while (*s && isspace(*s)) while (*s && isspace(*s))
s++; s++;
@ -1281,10 +1277,10 @@ browse(char *ipath, char *ifilter)
enum action sel = SEL_RUNARG + 1; enum action sel = SEL_RUNARG + 1;
xstrlcpy(path, ipath, sizeof(path)); xstrlcpy(path, ipath, sizeof(path));
xstrlcpy(lastdir, ipath, sizeof(lastdir));
xstrlcpy(fltr, ifilter, sizeof(fltr)); xstrlcpy(fltr, ifilter, sizeof(fltr));
oldpath[0] = '\0'; oldpath[0] = '\0';
newpath[0] = '\0'; newpath[0] = '\0';
lastdir[0] = '\0'; /* Can't move back from initial directory */
begin: begin:
if (sel == SEL_GOIN && S_ISDIR(sb.st_mode)) if (sel == SEL_GOIN && S_ISDIR(sb.st_mode))
@ -1471,56 +1467,66 @@ nochange:
break; break;
case SEL_CD: case SEL_CD:
{ {
/* Read target dir */ static char *tmp, *input;
static int truecd;
/* Save the program start dir */
tmp = getcwd(newpath, PATH_MAX); tmp = getcwd(newpath, PATH_MAX);
if (tmp == NULL) { if (tmp == NULL) {
printwarn(); printwarn();
goto nochange; goto nochange;
} }
/* Switch to current path for readline(3) */
if (chdir(path) == -1) { if (chdir(path) == -1) {
printwarn(); printwarn();
goto nochange; goto nochange;
} }
exitcurses(); exitcurses();
char *tmp = readline("chdir: "); tmp = readline("chdir: ");
initcurses(); initcurses();
/* Change back to program start dir */
if (chdir(newpath) == -1) if (chdir(newpath) == -1)
printwarn(); printwarn();
/* Save current */
if (ndents > 0)
mkpath(path, dents[cur].name, oldpath, sizeof(oldpath));
if (tmp[0] == '\0') if (tmp[0] == '\0')
break; break;
else else
/* Add to readline(3) history */
add_history(tmp); add_history(tmp);
char *input = tmp; input = tmp;
tmp = strstrip(tmp); tmp = strstrip(tmp);
if (tmp[0] == '\0') { if (tmp[0] == '\0') {
free(input); free(input);
break; break;
} }
truecd = 0;
if (tmp[0] == '~') { if (tmp[0] == '~') {
/* Expand ~ to HOME absolute path */
char *home = getenv("HOME"); char *home = getenv("HOME");
if (home) if (home)
snprintf(newpath, PATH_MAX, snprintf(newpath, PATH_MAX, "%s%s", home, tmp + 1);
"%s%s", home, tmp + 1); else {
else free(input);
mkpath(path, tmp, newpath, sizeof(newpath)); break;
}
oldpath[0] = '\0';
} else if (tmp[0] == '-' && tmp[1] == '\0') { } else if (tmp[0] == '-' && tmp[1] == '\0') {
xstrlcpy(newpath, lastdir, sizeof(newpath)); if (lastdir[0] == '\0') {
oldpath[0] = '\0'; free(input);
break;
}
/* Switch to last visited dir */
xstrlcpy(newpath, lastdir, sizeof(newpath));
truecd = 1;
} else if ((r = all_dots(tmp))) { } else if ((r = all_dots(tmp))) {
if (r == 1) { if (r == 1) {
/* Always in the current dir */
free(input); free(input);
break; break;
} }
@ -1529,15 +1535,17 @@ nochange:
dir = path; dir = path;
for (fd = 0; fd < r; fd++) { for (fd = 0; fd < r; fd++) {
/* There is no going back */ /* Reached / ? */
if (strcmp(path, "/") == 0 || if (strcmp(path, "/") == 0 ||
strchr(path, '/') == NULL) { strchr(path, '/') == NULL) {
/* If it's a cd .. at / */
if (fd == 0) { if (fd == 0) {
printmsg("You are at /"); printmsg("You are at /");
free(input); free(input);
goto nochange; goto nochange;
} }
/* Can't cd beyond / anyway */
break; break;
} else { } else {
dir = xdirname(dir); dir = xdirname(dir);
@ -1549,28 +1557,44 @@ nochange:
} }
} }
/* Save history */ 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)); xstrlcpy(oldpath, path, sizeof(oldpath));
xstrlcpy(newpath, dir, sizeof(newpath)); truecd = 2;
} else {
mkpath(path, tmp, newpath, sizeof(newpath));
oldpath[0] = '\0';
} }
if (canopendir(newpath) == 0) { xstrlcpy(newpath, dir, sizeof(newpath));
/* Save current */ } else
if (ndents > 0) mkpath(path, tmp, newpath, sizeof(newpath));
mkpath(path, dents[cur].name, oldpath, sizeof(oldpath));
if (canopendir(newpath) == 0) {
printwarn(); printwarn();
free(input); free(input);
break; 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 */ /* Save last working directory */
xstrlcpy(lastdir, path, sizeof(lastdir)); xstrlcpy(lastdir, path, sizeof(lastdir));
/* Save the newly opted dir in path */
xstrlcpy(path, newpath, sizeof(path)); xstrlcpy(path, newpath, sizeof(path));
/* Reset filter */ /* Reset filter */
xstrlcpy(fltr, ifilter, sizeof(fltr)); xstrlcpy(fltr, ifilter, sizeof(fltr));
DPRINTF_S(path); DPRINTF_S(path);
@ -1583,15 +1607,20 @@ nochange:
clearprompt(); clearprompt();
goto nochange; goto nochange;
} }
if (canopendir(tmp) == 0) { if (canopendir(tmp) == 0) {
printwarn(); printwarn();
goto nochange; goto nochange;
} }
if (strcmp(path, tmp) == 0)
break;
/* Save last working directory */ /* Save last working directory */
xstrlcpy(lastdir, path, sizeof(lastdir)); xstrlcpy(lastdir, path, sizeof(lastdir));
xstrlcpy(path, tmp, sizeof(path)); xstrlcpy(path, tmp, sizeof(path));
oldpath[0] = '\0';
/* Reset filter */ /* Reset filter */
xstrlcpy(fltr, ifilter, sizeof(fltr)); xstrlcpy(fltr, ifilter, sizeof(fltr));
DPRINTF_S(path); DPRINTF_S(path);
@ -1602,19 +1631,33 @@ nochange:
goto nochange; goto nochange;
} }
if (strcmp(path, ipath) == 0)
break;
/* Save last working directory */ /* Save last working directory */
xstrlcpy(lastdir, path, sizeof(lastdir)); xstrlcpy(lastdir, path, sizeof(lastdir));
xstrlcpy(path, ipath, sizeof(path)); xstrlcpy(path, ipath, sizeof(path));
oldpath[0] = '\0';
/* Reset filter */ /* Reset filter */
xstrlcpy(fltr, ifilter, sizeof(fltr)); xstrlcpy(fltr, ifilter, sizeof(fltr));
DPRINTF_S(path); DPRINTF_S(path);
goto begin; 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(newpath, lastdir, sizeof(newpath));
xstrlcpy(lastdir, path, sizeof(lastdir)); xstrlcpy(lastdir, path, sizeof(lastdir));
xstrlcpy(path, newpath, sizeof(path)); xstrlcpy(path, newpath, sizeof(path));
oldpath[0] = '\0'; oldpath[0] = '\0';
/* Reset filter */
xstrlcpy(fltr, ifilter, sizeof(fltr));
DPRINTF_S(path); DPRINTF_S(path);
goto begin; goto begin;
case SEL_TOGGLEDOT: case SEL_TOGGLEDOT: