superwhich 3.0.1

Cross-platform smart which alternative
Documentation

superwhich

usage-windows usage-linux

superwhich is a cross-platform CLI tool and library that uses Jaro-Winkler distance to calculate the similarity between the strings, printing only the executables in the PATH environment variable that match the search pattern with the provided threshold.

MSRV

Version Edition MSRV
3.x.y 2024 1.85
2.x.y 2021 1.80
1.x.y 2021 N/A

Installation

CLI

  • From crates.io: cargo install superwhich --features cli
  • From GitHub: cargo install --git https://github.com/DarkCeptor44/superwhich --features cli
  • Manually (after cloning the repo locally): cargo install --path . --features cli
  • From releases.

Library

cargo add superwhich

Or you can add this to your Cargo.toml file:

[dependencies]

superwhich = "3.0.1"

Usage

CLI

$ swhich -h

Cross-platform smart which alternative


Usage: swhich [OPTIONS] <PATTERN>

Arguments:

  <PATTERN>  The search pattern


Options:

  -c, --color <COLOR>          Color of the highlighted text (off or set `NO_COLOR` env var to disable) [default: blue]

  -t, --threads <THREADS>      Number of threads to use (0 for auto) [default: 75% of CPU cores]

  -T, --threshold <THRESHOLD>  String similarity threshold (0.0 to 1.0) [default: 0.7]

  -h, --help                   Print help

  -V, --version                Print version

Library

use rayon::iter::{ParallelBridge, ParallelIterator};
use std::{
    env::{split_paths, var_os},
    path::Path,
    sync::Arc,
};
use superwhich::{
    SearchCtx, colored::Color, crossbeam::channel::unbounded, find_files, par_find_files,
};

// construct the context needed for the search
let ctx = Arc::new(
    SearchCtx::new("GURE".to_string())
        .threshold(0.7)
        .color(Color::Red),
);
let (tx, rx) = unbounded(); // channel to send found paths in

// run the search directly with a singular path
let path = Path::new("path/to/search");
par_find_files(path, &ctx, &tx);

// or run the search inside a parallel iterator
split_paths(&var_os("PATH").expect("PATH is not set"))
    .par_bridge()
    .for_each(|path| {
        find_files(&path, &ctx, &tx);
    });

// DO NOT run the parallel function inside a parallel iterator, it actually slows down the search considerably

// print the found paths (they're String)
while let Ok(path) = rx.try_recv() {
    println!("{}", path);
}

Tests

You can run the tests with cargo test.

Benchmarks

Library

Timer precision: 100 ns
str                fastest       │ slowest       │ median        │ mean          │ samples │ iters
├─ fast lowercase  2.554 ms      │ 3.497 ms      │ 2.666 ms      │ 2.74 ms       │ 100     │ 100
│                  39.14 Mitem/s │ 28.59 Mitem/s │ 37.5 Mitem/s  │ 36.49 Mitem/s │         │
│                  max alloc:    │               │               │               │         │
│                    1           │ 1             │ 1             │ 1             │         │
│                    2.4 MB      │ 2.4 MB        │ 2.4 MB        │ 2.4 MB        │         │
│                  alloc:        │               │               │               │         │
│                    1           │ 1             │ 1             │ 1             │         │
│                    2.4 MB      │ 2.4 MB        │ 2.4 MB        │ 2.4 MB        │         │
╰─ std lowercase   4.877 ms      │ 7.723 ms      │ 5.288 ms      │ 5.456 ms      │ 100     │ 100
                   20.5 Mitem/s  │ 12.94 Mitem/s │ 18.91 Mitem/s │ 18.32 Mitem/s │         │
                   max alloc:    │               │               │               │         │
                     100001      │ 100001        │ 100001        │ 100001        │         │
                     4.9 MB      │ 4.9 MB        │ 4.9 MB        │ 4.9 MB        │         │
                   alloc:        │               │               │               │         │
                     100001      │ 100001        │ 100001        │ 100001        │         │
                     4.9 MB      │ 4.9 MB        │ 4.9 MB        │ 4.9 MB        │         │
Timer precision: 100 ns
swhich                          fastest       │ slowest       │ median        │ mean          │ samples │ iters
├─ find_files (1000 files)      505.7 µs      │ 1.263 ms      │ 514.7 µs      │ 548.2 µs      │ 100     │ 100
│                               1.977 Mitem/s │ 791.4 Kitem/s │ 1.942 Mitem/s │ 1.824 Mitem/s │         │
│                               max alloc:    │               │               │               │         │
│                                 4           │ 4             │ 4             │ 4             │         │
│                                 289 B       │ 289 B         │ 289 B         │ 289 B         │         │
│                               alloc:        │               │               │               │         │
│                                 1004        │ 1004          │ 1004          │ 1004          │         │
│                                 12.13 KB    │ 12.13 KB      │ 12.13 KB      │ 12.13 KB      │         │
│                               dealloc:      │               │               │               │         │
│                                 1004        │ 1004          │ 1004          │ 1004          │         │
│                                 12.18 KB    │ 12.18 KB      │ 12.18 KB      │ 12.18 KB      │         │
│                               grow:         │               │               │               │         │
│                                 1           │ 1             │ 1             │ 1             │         │
│                                 47 B        │ 47 B          │ 47 B          │ 47 B          │         │
╰─ par_find_files (1000 files)  1.007 ms      │ 2.26 ms       │ 1.266 ms      │ 1.321 ms      │ 100     │ 100
                                992.1 Kitem/s │ 442.4 Kitem/s │ 789.6 Kitem/s │ 756.6 Kitem/s │         │
                                max alloc:    │               │               │               │         │
                                  4           │ 4             │ 4             │ 5.49          │         │
                                  289 B       │ 289 B         │ 289 B         │ 852 B         │         │
                                alloc:        │               │               │               │         │
                                  5           │ 5             │ 5             │ 6.56          │         │
                                  258 B       │ 258 B         │ 258 B         │ 828.3 B       │         │
                                dealloc:      │               │               │               │         │
                                  3           │ 3             │ 3             │ 3.06          │         │
                                  210 B       │ 210 B         │ 210 B         │ 221.2 B       │         │
                                grow:         │               │               │               │         │
                                  1           │ 1             │ 1             │ 1             │         │
                                  47 B        │ 47 B          │ 47 B          │ 47 B          │         │

CLI

The CLI was benchmarked using Hyperfine.

  • Windows: AMD64, 32GB RAM, Ryzen 7 3800X, Windows 11
Command Mean [ms] Min [ms] Max [ms] Relative
swhich grep -T0.8 (v3) 19.2 ± 1.8 15.5 25.1 1.00
where grep 65.8 ± 3.7 61.1 81.9 3.43 ± 0.37
swhich pnpm (v2) 221.8 ± 3.5 215.7 229.2 11.55
  • Linux: ARM64, 1GB RAM, Orange Pi Zero2, Debian 12
Command Mean [ms] Min [ms] Max [ms] Relative
which grep 3.3 ± 0.7 2.8 7.2 1.00
swhich gurep -T0.9 (v3) 8.5 ± 0.2 8.1 9.4 2.55 ± 0.54
swhich lookfor (v2) 17.6 ± 0.3 17.0 19.8 5.33 ± 1.13

License

This project is licensed under the terms of the GNU General Public License v3.0.