JREP 0.1
A CLI tool based on GREP designed for the modern world
Requires Python: >=3.6

# JREP

JREP is a general-purpose command line utility that takes the basic concept of GREP and transforms it into an infinitely more versatile tool fit for the modern world.

Basically I couldn't find a good GREP for windows and GREP itself kinda sucks so I did it myself. Excpect dumb bodges and messy code despite my efforts to keep both to a minimum.

Check [here](#compatibility) for compatibility info

The current output of `jrep --help`:  
For details, [check below](#extended-help-messages)

<!--<HELP MSG>-->
```
usage: jrep.py [--help [topic]] [--string] [--enhanced-engine]
               [--file FILE [FILE ...]] [--glob GLOB [GLOB ...]]
               [--include-dirs]
               [--stdin-files | --stdin-globs | --stdin-anti-match-strings]
               [--no-duplicates] [--no-name-duplicates]
               [--name-regex Regex [Regex ...]]
               [--name-anti-regex Regex [Regex ...]]
               [--name-ignore-regex Regex [Regex ...]]
               [--full-name-regex Regex [Regex ...]]
               [--full-name-anti-regex Regex [Regex ...]]
               [--full-name-ignore-regex Regex [Regex ...]]
               [--name-glob Glob [Glob ...]]
               [--name-anti-glob Glob [Glob ...]]
               [--name-ignore-glob Glob [Glob ...]]
               [--full-name-glob Glob [Glob ...]]
               [--full-name-anti-glob Glob [Glob ...]]
               [--full-name-ignore-glob Glob [Glob ...]]
               [--dir-name-regex Regex [Regex ...]]
               [--dir-name-anti-regex Regex [Regex ...]]
               [--dir-name-ignore-regex Regex [Regex ...]]
               [--dir-full-name-regex Regex [Regex ...]]
               [--dir-full-name-anti-regex Regex [Regex ...]]
               [--dir-full-name-ignore-regex Regex [Regex ...]]
               [--file-regex Regex [Regex ...]]
               [--file-anti-regex Regex [Regex ...]]
               [--file-ignore-regex Regex [Regex ...]]
               [--match-regex Regex [Regex ...]]
               [--match-anti-regex Regex [Regex ...]]
               [--match-ignore-regex Regex [Regex ...]] [--sort SORT]
               [--sort-regex Regex [Regex ...]] [--sort-dir SORT_DIR]
               [--no-headers] [--print-dir-names] [--print-file-names]
               [--print-full-paths] [--print-posix-paths]
               [--dont-print-matches] [--print-match-offset]
               [--print-match-range] [--replace Regex [Regex ...]]
               [--sub Regex [Regex ...]] [--name-sub Regex [Regex ...]]
               [--dir-name-sub Regex [Regex ...]] [--escape]
               [--count COUNT [COUNT ...]] [--limit LIMIT [LIMIT ...]]
               [--depth-first] [--glob-root-dir GLOB_ROOT_DIR]
               [--match-whole-lines] [--print-failed-files] [--no-warn]
               [--hard-warn] [--weave-matches] [--strict-weave]
               [--pre-match-exec cmd] [--match-exec cmd]
               [--if-match-exec-before cmd] [--if-match-exec-after cmd]
               [--if-no-match-exec-after cmd] [--pre-file-exec cmd]
               [--file-exec cmd] [--if-file-exec-before cmd]
               [--if-file-exec-after cmd] [--if-no-file-exec-after cmd]
               [--pre-dir-exec cmd] [--dir-exec cmd]
               [--if-dir-exec-before cmd] [--if-dir-exec-after cmd]
               [--if-no-dir-exec-after cmd] [--order ORDER [ORDER ...]]
               [--no-flush] [--force-flush] [--print-rundata] [--verbose]
               [Regex ...]

options:
  --help [topic], -h [topic]            show this help message and exit OR use
                                        `--help [topic]` for help with [topic]

Files and regexes:
  Regex                                 Regex(es) to process matches for
                                        (reffered to as "get regexes")
                                        
  --string, -s                          Treat get regexes as strings. Doesn't
                                        apply to any other options.
  --enhanced-engine, -E                 Use alternate regex engine from
                                        https://pypi.org/project/regex/
                                        
  --file FILE [FILE ...], -f FILE [FILE ...]
                                        A list of files to check
  --glob GLOB [GLOB ...], -g GLOB [GLOB ...]
                                        A list of globs to check
  --include-dirs                        Process directories as files
                                        
  --stdin-files, -F                     Treat STDIN as a list of files
  --stdin-globs, -G                     Treat STDIN as a list of globs
  --stdin-anti-match-strings            Treat STDIN as a list of strings to
                                        not match

Filters:
  --no-duplicates, -D                   Don't print duplicate matches (See
                                        also: --order)
  --no-name-duplicates                  Don't process files whose names have
                                        already been processed (takes --name-
                                        sub, --print-full-paths and --print-
                                        posix-paths)
                                        
  --name-regex Regex [Regex ...], -t Regex [Regex ...]
                                        If a file name matches all supplied
                                        regexes, keep going. Otherwise
                                        continue
  --name-anti-regex Regex [Regex ...], -T Regex [Regex ...]
                                        Like --name-regex but excludes file
                                        names that match any of the supplied
                                        regexes
  --name-ignore-regex Regex [Regex ...]
                                        Like --name-anti-regex but doesn't
                                        contribute to --count *-failed-files
  --full-name-regex Regex [Regex ...]   Like --name-regex but for absolute
                                        file paths (C:/xyz instead of xyz)
  --full-name-anti-regex Regex [Regex ...]
                                        Like --name-anti-regex but applied to
                                        full file paths
  --full-name-ignore-regex Regex [Regex ...]
                                        Like --full-name-anti-regex but
                                        doesn't contribute to --count
                                        *-failed-files
                                        
  --name-glob Glob [Glob ...]           If a file name matches all supplied
                                        globs, keep going. Otherwise continue
  --name-anti-glob Glob [Glob ...]      Like --name-glob but excludes file
                                        names that match any of the supplied
                                        globs
  --name-ignore-glob Glob [Glob ...]    Like --name-anti-glob but doesn't
                                        contribute to --count *-failed-files
  --full-name-glob Glob [Glob ...]      Like --name-glob but for absolute file
                                        paths (C:/xyz instead of xyz)
  --full-name-anti-glob Glob [Glob ...]
                                        Like --name-anti-glob but applied to
                                        full file paths
  --full-name-ignore-glob Glob [Glob ...]
                                        Like --full-name-anti-glob but doesn't
                                        contribute to --count *-failed-files
                                        
  --dir-name-regex Regex [Regex ...]    If a directory name matches all
                                        supplied regexes, enter it. Otherwise
                                        continue
  --dir-name-anti-regex Regex [Regex ...]
                                        Like --dir-name-regex but excludes
                                        directories that match any of the
                                        supplied regexes
  --dir-name-ignore-regex Regex [Regex ...]
                                        Like --dir-name-anti-regex but doesn't
                                        contribute to --count total-failed-
                                        dirs
  --dir-full-name-regex Regex [Regex ...]
                                        Like --dir-name-regex but for absolute
                                        directory paths (C:/xyz instead of
                                        xyz)
  --dir-full-name-anti-regex Regex [Regex ...]
                                        Like --dir-name-anti-regex but applied
                                        to full directory paths
  --dir-full-name-ignore-regex Regex [Regex ...]
                                        Like --dir-full-name-anti-regex but
                                        doesn't contribute to --count total-
                                        failed-dirs
                                        
  --file-regex Regex [Regex ...]        Regexes to test file contents for
  --file-anti-regex Regex [Regex ...]   Like --file-regex but excludes files
                                        that match of the supplied regexes
  --file-ignore-regex Regex [Regex ...]
                                        Like --file-anti-regex but doesn't
                                        contribute to --count *-failed-files
                                        
  --match-regex Regex [Regex ...]       Groups are split along lone *. Matches
                                        from the Nth get regex are tested with
                                        the Nth group
  --match-anti-regex Regex [Regex ...]  Like --match-regex but excludes
                                        matches that match any of the supplied
                                        regexes
  --match-ignore-regex Regex [Regex ...]
                                        Like --match-anti-regex but doesn't
                                        contribute to --count *-failed-matches

Sorting:
  --sort SORT, -S SORT                  Sort files by ctime, mtime, atime,
                                        name, or size. Prefix key with "r" to
                                        reverse. A windows-esque "blockwise"
                                        sort is also available. Run jrep
                                        --help blockwise for more info
  --sort-regex Regex [Regex ...]        Regexes to apply to file names keys
                                        (like --replace) for purposes of
                                        sorting (EXPERIMENTAL)
  --sort-dir SORT_DIR                   --sort on a per-directory basis

Output:
  --no-headers, -H                      Don't print match: or file: before
                                        lines
                                        
  --print-dir-names, -d                 Print names of explored directories
  --print-file-names, -n                Print file names as well as matches
  --print-full-paths, -p                Print full file paths
  --print-posix-paths, -P               Replace \ with / when printing file
                                        paths
  --dont-print-matches, -N              Don't print matches (use with --print-
                                        file-names to only print names)
  --print-match-offset, -o              Print where the match starts in the
                                        file as a hexadecimal number (ignores
                                        -H)
  --print-match-range, -O               Print where the match starts and ends
                                        in the file as a hexadecimal number
                                        (implies -o)

Replace/Sub:
  --replace Regex [Regex ...], -r Regex [Regex ...]
                                        Regex replacement
  --sub Regex [Regex ...], -R Regex [Regex ...]
                                        re.sub argument pairs after --replace
                                        is applied. Run jrep.py --help sub for
                                        more info
  --name-sub Regex [Regex ...]          Applies --sub to file names. A lone *
                                        separates subsitutions for y/z and
                                        C:/x/y/z
  --dir-name-sub Regex [Regex ...]      --name-sub but for directory names
  --escape, -e                          Escape back slashes, newlines,
                                        carriage returns, and non-printable
                                        characters

Misc.:
  --count COUNT [COUNT ...], -c COUNT [COUNT ...]
                                        Count match/file/dir per file, dir,
                                        and/or total (Ex: --count fm dir-
                                        files)
  --limit LIMIT [LIMIT ...], -l LIMIT [LIMIT ...]
                                        Limit match/file/dir per file, dir,
                                        and/or total (Ex: --limit filematch=1
                                        total_dirs=5)
                                        
  --depth-first                         Enter subdirectories before processing
                                        files
  --glob-root-dir GLOB_ROOT_DIR         Root dir to run globs in (JANK)
                                        
  --match-whole-lines, -L               Match whole lines like FINDSTR
  --print-failed-files                  Print file names even if they fail
                                        (Partially broken)
  --no-warn                             Don't print warning messages
  --hard-warn                           Throw errors instead of warnings
  --weave-matches, -w                   Weave regex matchdes (print first
                                        results for each get regex, then
                                        second results, etc.)
  --strict-weave, -W                    Only print full weave sets

Exec:
  --pre-match-exec cmd                  Command to run before printing each
                                        match
  --match-exec cmd                      Command to run after printing each
                                        match
  --if-match-exec-before cmd            Command to run as soon as least one
                                        match passes
  --if-match-exec-after cmd             Command to run at the end if at least
                                        one match passed
  --if-no-match-exec-after cmd          Command to run at the end if at no
                                        matches passed
                                        
  --pre-file-exec cmd                   Command to run before printing each
                                        file name
  --file-exec cmd                       Command to run after printing each
                                        file name
  --if-file-exec-before cmd             Command to run as soon as least one
                                        file passes
  --if-file-exec-after cmd              Command to run at the end if at least
                                        one file passed
  --if-no-file-exec-after cmd           Command to run at the end if at no
                                        files passed
                                        
  --pre-dir-exec cmd                    Command to run before printing each
                                        dir name
  --dir-exec cmd                        Command to run after printing each dir
                                        name
  --if-dir-exec-before cmd              Command to run as soon as least one
                                        dir passes
  --if-dir-exec-after cmd               Command to run at the end if at least
                                        one dir passed
  --if-no-dir-exec-after cmd            Command to run at the end if at no
                                        dirs passed

Debugging/Advanced:
  --order ORDER [ORDER ...]             The order in which modifications to
                                        matches are applied. Run jrep --help
                                        order for more info
  --no-flush                            Improves speed by disabling manually
                                        flushing the stdout buffer (ideal for
                                        chaining commands)
  --force-flush                         Always flush STDOUT (slow)
  --print-rundata                       Print raw runData JSON at the end
                                        (used for debugging)
  --verbose, -v                         Verbose info
The following have extended help that can be seen with --help [topic]: sub, blockwise, order, exec
```
<!--</HELP MSG>-->

# Extended help messages

These can be accessed by doing `jrep --help [topic]` where `[topic]` is the part in parenthesis

<!--<EXTHELP MSGS>-->
## (`sub`) --sub advanced usage
The easiest way to explain advanced uses of `--sub` is to give an example. So take `--sub a ? b ? c d e f + x ? y z * ? t ? e d * abc xyz` as an example.    
What it means is the following
  
- `a ? b ? c d e f`: If a match from get regex 0 matches `a` and not `b`, replace `c` with `d` and `e` with `f`  
- `+`: New conditions but stay on the same get regex  
- `x ? y z`: If a match from get regex 0 matches `x`, replace `y` with `z`  
- `*`: Move on to the next get regex  
- `? t ? e d`: If a match from get regex 1 does't match `t`, replace `e` with `d`  
- `*`: Move on to the next get regex  
- `abc xyz`: Replace `abc` with `xyz` without any conditions  
  
Obviously 99% of use cases don't need conditionals at all so just doing `--sub abc def * uvw xyz` is sufficient

## (`blockwise`) Blockwise sorting
A generic sort function will think "file10.jpg" comes before "file2.jpg"  
Windows, on the other hand, has code that treats the number part as a number  
Blockwise sort mimics this behaviour by  
1. Splitting filenames into groups of number and non-number characters. Ex. `abc123def456.jpg` -> `["abc", "123", "def", "456", ".jpg"]`  
2. When comparing 2 filenames, compare the first element ("block") of both name's lists according to the following two rules
	1. If either block is made of non-number characters, compare the two blocks as strings  
	2. If both blocks are numbers, compare them as numbers  
  
The end result is that file2.jpg is correctly placed before file10.jpg

## (`order`) `--order` usage
`--order` determines the order of functions that process matches  
- The default value for `--order` is replace, match-whole-lines, sub, stdin-anti-match-strings, match-regex, no-name-duplicates, no-duplicates, print-dir-name, print-name, print-match  
- Changing the order of `sub`, `replace`, and `match-whole-lines` will mostly "work" but the output will make next to no sense  
- The main purpose of this is to move `match-regex` and `no-duplicates` to earlier in the chain

## (`exec`) Using the `--exec` family of options
Usage looks like `--exec "echo {}"` or just `--exec "echo"`  
`--match-exec`/`--exec`: after  printing matches  
`--pre-match-exec`: before printing matches  
`--match-exec`: after  printing file names  
`--pre-match-exec`: before printing file names  
`--dir-exec`: after  printing directory names  
`--pre-dir-exec`: before printing directory names
<!--</EXTHELP MSGS>-->

# Compatibility

&nbsp;|Python 3.6|3.7|3.8|3.9|3.10
|:-:|:-:|:-:|:-:|:-:|:-:|
Windows 10  |? |? |? |? |Y 
Ubuntu 20.04|? |? |Y?|? |? 

- I primarily develop JREP on a Windows 10 machine running Python 3.10
- Due to how I override some internal stuff I'll need to test each version of python individually
- I don't have a Mac machine or the $1000 required to get one. It *probably* works but don't count on it

The end goal is for JREP to 100% work on
- Windows 7 through 11
- The second latest LTS releases of every major Linux distro
- The past decade of Mac machines

I don't think there's much (if any) platform-specific jank in JREP but it'll take a while to confirm that