Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/alexpasmantier/grip-grab

Hold on tight
https://github.com/alexpasmantier/grip-grab

ag cli grep json regex ripgrep rust search speed terminal

Last synced: 1 day ago
JSON representation

Hold on tight

Awesome Lists containing this project

README

        

![Crates.io Total Downloads](https://img.shields.io/crates/d/grip-grab) ![Crates.io Version](https://img.shields.io/crates/v/grip-grab) ![GitHub License](https://img.shields.io/github/license/alexpasmantier/grip-grab)

# grip-grab (`gg`) 🧤

A fast, more lightweight ripgrep alternative for daily use cases.

```sh
❯ gg "\b(Read|Write)Half[^<]" tokio/src
```

https://github.com/user-attachments/assets/13406bea-b6f2-4629-b814-366713a8d90d

## Installation
### Using Cargo
```bash
cargo install grip-grab
```

**NOTE:** if using zsh with the `git` plugin, you might need to unalias `gg` in order for grip-grab's `gg` to work:
```sh
echo 'unalias gg' >> ~/.zshrc
source ~/.zshrc
```

## Benchmarks

### The general idea
_With default settings for both tools, `gg` will typically be faster than `rg` on small to moderatly sized codebases (<= a couple milion lines) running on everyday machines because of its default thread heuristic. `rg` will typically be faster out of the box on larger corpora (think a checkout of the linux kernel) and machines with more logical cpus. Note that you still can tweak `gg` with the `-T` argument to achieve similar performance in those cases._

_[The following discussion with ripgrep's author on HackerNews](https://news.ycombinator.com/item?id=41380065) might also provide more insights regarding this tool's performance (including more benchmarks across different machines and corpora)._

*NOTE*: _The following benchmarks were run on an M3 Macbook Pro with 16GB of RAM and 8 logical CPUs._

### The `curl` codebase (approx. half a milion lines)
https://github.com/curl/curl

```sh
hyperfine -m 200 "gg '[A-Z]+_NOBODY' ." "rg '[A-Z]+_NOBODY' ." "ggrep -rE '[A-Z]+_NOBODY' ."
```
```
Benchmark 1: gg '[A-Z]+_NOBODY' .
Time (mean ± σ): 18.5 ms ± 0.7 ms [User: 10.5 ms, System: 47.9 ms]
Range (min … max): 17.0 ms … 19.9 ms 200 runs

Benchmark 2: rg '[A-Z]+_NOBODY' .
Time (mean ± σ): 37.0 ms ± 4.6 ms [User: 15.1 ms, System: 201.0 ms]
Range (min … max): 23.3 ms … 60.5 ms 200 runs

Benchmark 3: ggrep -rE '[A-Z]+_NOBODY' .
Time (mean ± σ): 68.5 ms ± 0.6 ms [User: 27.2 ms, System: 40.4 ms]
Range (min … max): 64.6 ms … 70.4 ms 200 runs

Summary
gg '[A-Z]+_NOBODY' . ran
2.00 ± 0.26 times faster than rg '[A-Z]+_NOBODY' .
3.71 ± 0.14 times faster than ggrep -rE '[A-Z]+_NOBODY' .
```

**Plaintext searches**
```sh
hyperfine -m 100 "gg 'test'" "rg 'test'" "ggrep -rE 'test'"
```
```
Benchmark 1: gg 'test'
Time (mean ± σ): 22.3 ms ± 1.1 ms [User: 16.5 ms, System: 51.0 ms]
Range (min … max): 20.4 ms … 27.7 ms 100 runs

Benchmark 2: rg 'test'
Time (mean ± σ): 49.7 ms ± 2.7 ms [User: 23.4 ms, System: 298.3 ms]
Range (min … max): 42.0 ms … 55.5 ms 100 runs

Benchmark 3: ggrep -rE 'test'
Time (mean ± σ): 52.3 ms ± 0.9 ms [User: 14.6 ms, System: 37.0 ms]
Range (min … max): 50.1 ms … 56.9 ms 100 runs

Summary
gg 'test' ran
2.23 ± 0.16 times faster than rg 'test'
2.34 ± 0.12 times faster than ggrep -rE 'test'
```

### The `tokio` codebase (approx. 160k lines)
https://github.com/tokio-rs/tokio

```sh
hyperfine -m 200 "gg 'in<\w, W>'" "rg 'in<\w, W>'" "ggrep -r 'in<[[:alnum:]], W>'"
```
```
Benchmark 1: gg 'in<\w, W>'
Time (mean ± σ): 7.4 ms ± 0.7 ms [User: 4.5 ms, System: 6.8 ms]
Range (min … max): 6.0 ms … 10.3 ms 208 runs

Benchmark 2: rg 'in<\w, W>'
Time (mean ± σ): 8.8 ms ± 0.8 ms [User: 5.9 ms, System: 16.5 ms]
Range (min … max): 6.7 ms … 10.7 ms 200 runs

Benchmark 3: ggrep -r 'in<[[:alnum:]], W>'
Time (mean ± σ): 118.3 ms ± 2.1 ms [User: 100.8 ms, System: 16.5 ms]
Range (min … max): 114.3 ms … 127.4 ms 200 runs

Summary
gg 'in<\w, W>' ran
1.19 ± 0.15 times faster than rg 'in<\w, W>'
15.92 ± 1.54 times faster than ggrep -r 'in<[[:alnum:]], W>'
```

**Plaintext searches**
These typically take <5ms on the tokio repository which is too low to benchmark with a tool like hyperfine.

### The `neovim` codebase (approx. 1.3 milion lines)
https://github.com/neovim/neovim

```sh
hyperfine --warmup 100 "gg '[a-z]+_buf\b'" "rg '[a-z]+_buf\b'" "ggrep -rE '[a-z]+_buf\b'"
```
```
Benchmark 1: gg '[a-z]+_buf\b'
Time (mean ± σ): 19.0 ms ± 1.2 ms [User: 12.4 ms, System: 54.4 ms]
Range (min … max): 16.8 ms … 22.6 ms 113 runs

Benchmark 2: rg '[a-z]+_buf\b'
Time (mean ± σ): 36.0 ms ± 4.9 ms [User: 14.8 ms, System: 200.5 ms]
Range (min … max): 23.9 ms … 46.2 ms 75 runs

Benchmark 3: ggrep -rE '[a-z]+_buf\b'
Time (mean ± σ): 75.7 ms ± 0.9 ms [User: 36.3 ms, System: 39.4 ms]
Range (min … max): 74.1 ms … 78.1 ms 36 runs

Summary
gg '[a-z]+_buf\b' ran
1.89 ± 0.29 times faster than rg '[a-z]+_buf\b'
3.99 ± 0.26 times faster than ggrep -rE '[a-z]+_buf\b'
```

**Plaintext searches**
```sh
hyperfine --warmup 100 -m 100 "gg 'test'" "rg 'test'" "ggrep -rE 'test'"
```
```
Benchmark 1: gg 'test'
Time (mean ± σ): 21.0 ms ± 0.8 ms [User: 15.3 ms, System: 48.1 ms]
Range (min … max): 18.9 ms … 23.2 ms 114 runs

Benchmark 2: rg 'test'
Time (mean ± σ): 42.4 ms ± 3.6 ms [User: 19.5 ms, System: 253.3 ms]
Range (min … max): 34.9 ms … 63.4 ms 100 runs

Benchmark 3: ggrep -rE 'test'
Time (mean ± σ): 65.3 ms ± 1.6 ms [User: 27.8 ms, System: 36.7 ms]
Range (min … max): 63.2 ms … 78.4 ms 100 runs

Summary
gg 'test' ran
2.02 ± 0.19 times faster than rg 'test'
3.11 ± 0.15 times faster than ggrep -rE 'test'
```

## Usage
```sh
❯ gg --help
```

```plaintext
A faster, more lightweight ripgrep alternative for day to day usecases.

Usage: gg [OPTIONS] [PATTERN] [PATHS]... [COMMAND]

Commands:
upgrade Upgrade the crate to its latest version
help Print this message or the help of the given subcommand(s)

Arguments:
[PATTERN] a regex pattern to search for
[PATHS]... path in which to search recursively

Options:
-e, --patterns
you can specify multiple patterns using -e "pattern1" -e "pattern2" etc
-I, --ignore-paths
paths to ignore when recursively walking target directory
-G, --disregard-gitignore
disregard .gitignore rules when recursively walking directory (defaults to false)
-T, --n-threads
number of threads to use [default: 4]
-U, --multiline
enable multiline matching
--json
output in JSON format
-f, --file-paths-only
output file paths only
-A, --absolute-paths
output absolute paths (defaults to relative)
-C, --disable-colored-output
disable colored output (colored by default)
-t, --filter-filetypes
filter on filetype (defaults to all filetypes)
-H, --disable-hyperlinks
disable hyperlinks in output (defaults to false)
-D, --disable-devicons
disable devicons in output (defaults to false)
-h, --help
Print help
-V, --version
Print version
```

## Upgrading `gg`
You may upgrade `gg` to its latest version by running:
```sh
gg upgrade
```
```
Upgrade the crate to its latest version

Usage: gg upgrade [OPTIONS]

Options:
-f, --force Optional flag for force upgrade
-h, --help Print help
```

https://github.com/user-attachments/assets/8620a805-4b2a-498e-a0a0-e8b6835bc9cd

## Examples
### Basic usage
```sh
❯ gg "\b(Read|Write)Half[^<]" tokio/src
```
Screenshot 2024-10-04 at 14 48 44

### JSON output
```sh
❯ gg --json unsplit tokio/src | jq
```
Screenshot 2024-07-24 at 13 25 29

### Filenames only
```sh
❯ gg -f "\b(Read|Write)Half[^<]" tokio/src
```
Screenshot 2024-10-04 at 14 49 44

## Notes
This lightweight utility is largely based on a couple of crates from the extraordinary [ripgrep](https://github.com/BurntSushi/ripgrep) tool.
Its aim is to provide a minimal and lightweight version that can be easily integrated in other programs for search-related purproses.