mirror of
https://github.com/jarun/nnn.git
synced 2024-11-24 11:51:27 +00:00
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:
parent
febda38c14
commit
3096dfefde
11
README.md
11
README.md
|
@ -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.
|
||||||
|
|
|
@ -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
121
nnn.c
|
@ -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;
|
||||||
xstrlcpy(oldpath, path, sizeof(oldpath));
|
|
||||||
|
/* 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));
|
xstrlcpy(newpath, dir, sizeof(newpath));
|
||||||
} else {
|
} else
|
||||||
mkpath(path, tmp, newpath, sizeof(newpath));
|
mkpath(path, tmp, newpath, sizeof(newpath));
|
||||||
oldpath[0] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (canopendir(newpath) == 0) {
|
if (canopendir(newpath) == 0) {
|
||||||
/* Save current */
|
|
||||||
if (ndents > 0)
|
|
||||||
mkpath(path, dents[cur].name, oldpath, sizeof(oldpath));
|
|
||||||
|
|
||||||
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:
|
||||||
|
|
Loading…
Reference in a new issue