nimgrep: add --inContext and --notinContext options (#19528)

* nimgrep: add `--matchContext` and `--noMatchContext` options

* Rename options for uniformity

* Revise option names, add `--parentPath` options

* Revert --bin deprecation

* Copy-paste an original test from quantimnot

The origin was:
https://gist.githubusercontent.com/quantimnot/5d23b32fe0936ffc453220d20a87b9e2/raw/96544656d52332118295e55aa73718c389e5d194/tnimgrep.nim

* Change ! to n

* Attempt to fix test

* Fix test on Windows

* Change --contentsFile -> --inFile, add more tests

* Bump

* Change --parentPath to --dirpath
This commit is contained in:
Andrey Makarov 2022-09-14 19:28:01 +03:00 • committed by GitHub
commit 2140d05f34
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 683 additions and 104 deletions

View file

@ -34,6 +34,66 @@ Command line switches
.. include:: nimgrep_cmdline.txt
Path filter options
-------------------
Let us assume we have file `dirA/dirB/dirC/file.nim`.
Filesystem path options will match for these parts of the path:
| option | matches for |
| :------------------ | :-------------------------------- |
| `--[not]extensions` | ``nim`` |
| `--[not]filename` | ``file.nim`` |
| `--[not]dirname` | ``dirA`` and ``dirB`` and ``dirC`` |
| `--[not]dirpath` | ``dirA/dirB/dirC`` |
Combining multiple filter options together and negating them
------------------------------------------------------------
Options for filtering can be provided multiple times so they form a list,
which works as:
* positive filters
`--filename`, `--dirname`, `--dirpath`, `--inContext`,
`--inFile` accept files/matches if *any* pattern from the list is hit
* negative filters
`--notfilename`, `--notdirname`, `--notdirpath`, `--notinContext`,
`--notinFile` accept files/matches if *no* pattern from the list is hit.
In other words the same filtering option repeated many times means logical OR.
.. Important::
Different filtering options are related by logical AND: they all must
be true for a match to be accepted.
E.g. `--filename:F --dirname:D1 --notdirname:D2` means
`filename(F) AND dirname(D1) AND (NOT dirname(D2))`.
So negative filtering patterns are effectively related by logical OR also:
`(NOT PAT1) AND (NOT PAT2) == NOT (PAT1 OR PAT2)`:literal: in pseudo-code.
That means you can always use only 1 such an option with logical OR, e.g.
`--notdirname:PAT1 --notdirname:PAT2` is fully equivalent to
`--notdirname:'PAT1|PAT2'`.
.. Note::
If you want logical AND on patterns you should compose 1 appropriate pattern,
possibly combined with multi-line mode `(?s)`:literal:.
E.g. to require that multi-line context of matches has occurences of
**both** PAT1 and PAT2 use positive lookaheads (`(?=PAT)`:literal:):
```cmd
nimgrep --inContext:'(?s)(?=.*PAT1)(?=.*PAT2)'
```
Meaning of `^`:literal: and `$`:literal:
========================================
`nimgrep`:cmd: PCRE engine is run in a single-line mode so
`^`:literal: matches the beginning of whole input *file* and
`$`:literal: matches the end of *file* (or whole input *string* for
options like `--filename`).
Add the `(?m)`:literal: modifier to the beginning of your pattern for
`^`:literal: and `$`:literal: to match the beginnings and ends of *lines*.
Examples
========
@ -51,23 +111,18 @@ All examples below use default PCRE Regex patterns:
+ To exclude version control directories (Git, Mercurial=hg, Subversion=svn)
from the search:
```cmd
nimgrep --excludeDir:'^\.git$' --excludeDir:'^\.hg$' --excludeDir:'^\.svn$'
# short: --ed:'^\.git$' --ed:'^\.hg$' --ed:'^\.svn$'
nimgrep --notdirname:'^\.git$' --notdirname:'^\.hg$' --notdirname:'^\.svn$'
# short: --ndi:'^\.git$' --ndi:'^\.hg$' --ndi:'^\.svn$'
```
+ To search only in paths containing the `tests` sub-directory recursively:
+ To search only in paths containing the `tests`:literal: sub-directory
recursively:
```cmd
nimgrep --recursive --includeDir:'(^|/)tests($|/)'
# short: -r --id:'(^|/)tests($|/)'
nimgrep --recursive --dirname:'^tests$'
# short: -r --di:'^tests$'
# or using --dirpath:
nimgrep --recursive --dirpath:'(^|/)tests($|/)'
# short: -r --pa:'(^|/)tests($|/)'
```
.. Attention:: note the subtle difference between `--excludeDir`:option: and
`--includeDir`:option:\: the former is applied to relative directory entries
and the latter is applied to the whole paths
+ Nimgrep can search multi-line, e.g. to find files containing `import`
and then `strutils` use pattern `'import(.|\n)*?strutils'`:option:.
+ Nimgrep can search multi-line, e.g. to find files containing `import`:literal:
and then `strutils`:literal: use pattern `'import(.|\n)*?strutils'`:literal:.