diff --git a/README.md b/README.md index 793ccced..88b36c81 100644 --- a/README.md +++ b/README.md @@ -320,13 +320,17 @@ The path is shown in the help and configuration screen. #### Filters -Filters support regexes to instantly (search-as-you-type) list the matching entries in the current directory. +Filters support regexes by default to instantly (search-as-you-type) list the matching entries in the current directory. Common use cases: - to list all matches starting with the filter expression, start the expression with a `^` (caret) symbol - type `\.mkv` to list all MKV files - use `.*` to match any character (_sort of_ fuzzy search) +To filter entries by substring match: + + export NNN_PLAIN_FILTER=1 + If `nnn` is invoked as root or the environment variable `NNN_SHOW_HIDDEN` is set the default filter will also match hidden files. #### Navigate-as-you-type mode diff --git a/nnn.1 b/nnn.1 index afefc08f..d3e97e0f 100644 --- a/nnn.1 +++ b/nnn.1 @@ -219,7 +219,7 @@ The first time a context is entered, it copies the state of the last visited con .Pp When a context is quit, the next active context is selected. If the last active context is quit, the program quits. .Sh FILTERS -Filters support regexes to instantly (search-as-you-type) list the matching +Filters support regexes by default to instantly (search-as-you-type) list the matching entries in the current directory. .Pp Common use cases: @@ -231,6 +231,8 @@ with a '^' (caret) symbol. .br (3) Use '.*' to match any character (\fIsort of\fR fuzzy search). .Pp +To filter entries by substring match export the environment variable \fBNNN_PLAIN_FILTER\fR. +.Pp If .Nm is invoked as root or the environment variable \fBNNN_SHOW_HIDDEN\fR is set the default filter will also match hidden files. @@ -314,6 +316,11 @@ files. .Bd -literal export NNN_RESTRICT_0B=1 .Ed +.Pp +\fBNNN_PLAIN_FILTER:\fR use substring match in filter mode. +.Bd -literal + export NNN_PLAIN_FILTER=1 +.Ed .Sh KNOWN ISSUES If you are using urxvt you might have to set backspace key to DEC. .Sh AUTHORS diff --git a/src/nnn.c b/src/nnn.c index 76e448e7..723a636b 100644 --- a/src/nnn.c +++ b/src/nnn.c @@ -260,7 +260,7 @@ typedef struct { uint dircolor : 1; /* Current status of dir color */ uint metaviewer : 1; /* Index of metadata viewer in utils[] */ uint ctxactive : 1; /* Context active or not */ - uint reserved : 9; + uint reserved : 8; /* The following settings are global */ uint curctx : 2; /* Current context number */ uint picker : 1; /* Write selection to user-specified file */ @@ -270,6 +270,7 @@ typedef struct { uint runscript : 1; /* Choose script to run mode */ uint runctx : 2; /* The context in which script is to be run */ uint restrict0b : 1; /* Restrict 0-byte file opening */ + uint filter_re : 1; /* Use regex filters */ } settings; /* Contexts or workspaces */ @@ -285,7 +286,7 @@ typedef struct { /* GLOBALS */ /* Configuration, contexts */ -static settings cfg = {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static settings cfg = {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; static context g_ctx[CTX_MAX] __attribute__ ((aligned)); static struct entry *dents; @@ -1065,11 +1066,18 @@ static int setfilter(regex_t *regex, char *filter) return r; } -static int visible(regex_t *regex, char *file) +static int visible_re(regex_t *regex, char *fname, char *fltr) { - return regexec(regex, file, 0, NULL, 0) == 0; + return regexec(regex, fname, 0, NULL, 0) == 0; } +static int visible_str(regex_t *regex, char *fname, char *fltr) +{ + return strcasestr(fname, fltr) != NULL; +} + +static int (*filterfn)(regex_t *regex, char *fname, char *fltr) = &visible_re; + static int entrycmp(const void *va, const void *vb) { static pEntry pa, pb; @@ -1172,16 +1180,16 @@ static int nextsel(int *presel) /* * Move non-matching entries to the end */ -static int fill(struct entry **dents, int (*filter)(regex_t *, char *), regex_t *re) +static int fill(char* fltr, regex_t *re) { static int count; static struct entry _dent, *pdent1, *pdent2; for (count = 0; count < ndents; ++count) { - if (filter(re, (*dents)[count].name) == 0) { + if (filterfn(re, dents[count].name, fltr) == 0) { if (count != --ndents) { - pdent1 = &(*dents)[count]; - pdent2 = &(*dents)[ndents]; + pdent1 = &dents[count]; + pdent2 = &dents[ndents]; *(&_dent) = *pdent1; *pdent1 = *pdent2; @@ -1201,11 +1209,12 @@ static int matches(char *fltr) static regex_t re; /* Search filter */ - if (setfilter(&re, fltr) != 0) + if (cfg.filter_re && setfilter(&re, fltr) != 0) return -1; - ndents = fill(&dents, visible, &re); - regfree(&re); + ndents = fill(fltr, &re); + if (cfg.filter_re) + regfree(&re); if (!ndents) return 0; @@ -2159,10 +2168,14 @@ static bool show_help(char *path) dprintf(fd, "NNN_SCRIPT: %s\n", runpath); if (getenv("NNN_SHOW_HIDDEN")) dprintf(fd, "NNN_SHOW_HIDDEN: 1\n"); - if (getenv("NNN_NO_AUTOSELECT")) + if (cfg.autoselect) dprintf(fd, "NNN_NO_AUTOSELECT: 1\n"); - if (getenv("NNN_NO_FILE_OPEN_ON_NAV")) + if (cfg.nonavopen) dprintf(fd, "NNN_NO_FILE_OPEN_ON_NAV: 1\n"); + if (cfg.restrict0b) + dprintf(fd, "NNN_RESTRICT_0B: 1\n"); + if (!cfg.filter_re) + dprintf(fd, "NNN_PLAIN_FILTER: 1\n"); dprintf(fd, "\n"); @@ -2373,7 +2386,7 @@ static int dentfill(char *path, struct entry **dents) } /* Return the position of the matching entry or 0 otherwise */ -static int dentfind(struct entry *dents, const char *fname, int n) +static int dentfind(const char *fname, int n) { static int i; @@ -2420,7 +2433,7 @@ static bool populate(char *path, char *lastname) #endif /* Find cur from history */ - cur = dentfind(dents, lastname, ndents); + cur = dentfind(lastname, ndents); return TRUE; } @@ -3785,6 +3798,12 @@ int main(int argc, char *argv[]) if (getenv("NNN_RESTRICT_0B")) cfg.restrict0b = 1; + /* Use string-comparison in filter mode */ + if (getenv("NNN_PLAIN_FILTER")) { + cfg.filter_re = 0; + filterfn = &visible_str; + } + signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN);