mirror of
https://github.com/BurntSushi/ripgrep.git
synced 2025-08-07 23:52:00 -07:00
Compare commits
1 Commits
grep-regex
...
ag/ghactio
Author | SHA1 | Date | |
---|---|---|---|
|
535cd0d312 |
233
.github/workflows/ci.yml
vendored
233
.github/workflows/ci.yml
vendored
@@ -5,191 +5,94 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '00 01 * * *'
|
cron: '00 01 * * *'
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
name: test
|
name: test
|
||||||
env:
|
|
||||||
# For some builds, we use cross to test on 32-bit and big-endian
|
|
||||||
# systems.
|
|
||||||
CARGO: cargo
|
|
||||||
# When CARGO is set to CROSS, this is set to `--target matrix.target`.
|
|
||||||
TARGET_FLAGS:
|
|
||||||
# When CARGO is set to CROSS, TARGET_DIR includes matrix.target.
|
|
||||||
TARGET_DIR: ./target
|
|
||||||
# Emit backtraces on panics.
|
|
||||||
RUST_BACKTRACE: 1
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
|
# The docs seem to suggest that we can have a matrix with just an
|
||||||
|
# include directive, but it result in a "matrix must define at least
|
||||||
|
# one vector" error in the CI system.
|
||||||
build:
|
build:
|
||||||
# We test ripgrep on a pinned version of Rust, along with the moving
|
- pinned-glibc
|
||||||
# targets of 'stable' and 'beta' for good measure.
|
- pinned-musl
|
||||||
- pinned
|
|
||||||
- stable
|
- stable
|
||||||
- beta
|
- beta
|
||||||
# Our release builds are generated by a nightly compiler to take
|
# We test musl with nightly because every once in a while, this will
|
||||||
# advantage of the latest optimizations/compile time improvements. So
|
# catch an upstream regression.
|
||||||
# we test all of them here. (We don't do mips releases, but test on
|
- nightly-glibc
|
||||||
# mips for big-endian coverage.)
|
|
||||||
- nightly
|
|
||||||
- nightly-musl
|
- nightly-musl
|
||||||
- nightly-32
|
|
||||||
- nightly-mips
|
|
||||||
- nightly-arm
|
|
||||||
- macos
|
- macos
|
||||||
- win-msvc
|
- win-msvc-32
|
||||||
- win-gnu
|
- win-msvc-64
|
||||||
|
- win-gnu-32
|
||||||
|
- win-gnu-64
|
||||||
include:
|
include:
|
||||||
- build: pinned
|
# - build: pinned-glibc
|
||||||
|
# os: ubuntu-18.04
|
||||||
|
# rust: 1.34.0
|
||||||
|
# target: x86_64-unknown-linux-gnu
|
||||||
|
- build: pinned-musl
|
||||||
os: ubuntu-18.04
|
os: ubuntu-18.04
|
||||||
rust: 1.41.0
|
rust: 1.34.0
|
||||||
|
target: x86_64-unknown-linux-musl
|
||||||
- build: stable
|
- build: stable
|
||||||
os: ubuntu-18.04
|
os: ubuntu-18.04
|
||||||
rust: stable
|
rust: stable
|
||||||
- build: beta
|
target: x86_64-unknown-linux-gnu
|
||||||
os: ubuntu-18.04
|
# - build: beta
|
||||||
rust: beta
|
# os: ubuntu-18.04
|
||||||
- build: nightly
|
# rust: beta
|
||||||
os: ubuntu-18.04
|
# target: x86_64-unknown-linux-gnu
|
||||||
rust: nightly
|
# - build: nightly-glibc
|
||||||
- build: nightly-musl
|
# os: ubuntu-18.04
|
||||||
os: ubuntu-18.04
|
# rust: nightly
|
||||||
rust: nightly
|
# target: x86_64-unknown-linux-gnu
|
||||||
target: x86_64-unknown-linux-musl
|
# - build: nightly-musl
|
||||||
- build: nightly-32
|
# os: ubuntu-18.04
|
||||||
os: ubuntu-18.04
|
# rust: nightly
|
||||||
rust: nightly
|
# target: x86_64-unknown-linux-musl
|
||||||
target: i686-unknown-linux-gnu
|
# - build: macos
|
||||||
- build: nightly-mips
|
# os: macOS-10.14
|
||||||
os: ubuntu-18.04
|
# rust: stable
|
||||||
rust: nightly
|
# target: x86_64-apple-darwin
|
||||||
target: mips64-unknown-linux-gnuabi64
|
# - build: win-msvc-32
|
||||||
- build: nightly-arm
|
# os: windows-2019
|
||||||
os: ubuntu-18.04
|
# rust: stable
|
||||||
rust: nightly
|
# target: i686-pc-windows-msvc
|
||||||
# For stripping release binaries:
|
# - build: win-msvc-64
|
||||||
# docker run --rm -v $PWD/target:/target:Z \
|
# os: windows-2019
|
||||||
# rustembedded/cross:arm-unknown-linux-gnueabihf \
|
# rust: stable
|
||||||
# arm-linux-gnueabihf-strip \
|
# target: x86_64-pc-windows-msvc
|
||||||
# /target/arm-unknown-linux-gnueabihf/debug/rg
|
# - build: win-gnu-32
|
||||||
target: arm-unknown-linux-gnueabihf
|
# os: windows-2019
|
||||||
- build: macos
|
# rust: stable-i686-gnu
|
||||||
os: macos-latest
|
# target: i686-pc-windows-gnu
|
||||||
rust: nightly
|
# - build: win-gnu-64
|
||||||
- build: win-msvc
|
# os: windows-2019
|
||||||
os: windows-2019
|
# rust: stable-x86_64-gnu
|
||||||
rust: nightly
|
# target: x86_64-pc-windows-gnu
|
||||||
- build: win-gnu
|
|
||||||
os: windows-2019
|
|
||||||
rust: nightly-x86_64-gnu
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v1
|
uses: actions/checkout@v1
|
||||||
|
|
||||||
- name: Install packages (Ubuntu)
|
|
||||||
if: matrix.os == 'ubuntu-18.04'
|
|
||||||
run: |
|
|
||||||
ci/ubuntu-install-packages
|
|
||||||
|
|
||||||
- name: Install packages (macOS)
|
|
||||||
if: matrix.os == 'macos-latest'
|
|
||||||
run: |
|
|
||||||
ci/macos-install-packages
|
|
||||||
|
|
||||||
- name: Install Rust
|
|
||||||
uses: actions-rs/toolchain@v1
|
|
||||||
with:
|
with:
|
||||||
toolchain: ${{ matrix.rust }}
|
fetch-depth: 1
|
||||||
profile: minimal
|
|
||||||
override: true
|
|
||||||
|
|
||||||
- name: Use Cross
|
|
||||||
if: matrix.target != ''
|
|
||||||
run: |
|
|
||||||
# FIXME: to work around bugs in latest cross release, install master.
|
|
||||||
# See: https://github.com/rust-embedded/cross/issues/357
|
|
||||||
cargo install --git https://github.com/rust-embedded/cross
|
|
||||||
echo "::set-env name=CARGO::cross"
|
|
||||||
echo "::set-env name=TARGET_FLAGS::--target ${{ matrix.target }}"
|
|
||||||
echo "::set-env name=TARGET_DIR::./target/${{ matrix.target }}"
|
|
||||||
|
|
||||||
- name: Show command used for Cargo
|
|
||||||
run: |
|
|
||||||
echo "cargo command is: ${{ env.CARGO }}"
|
|
||||||
echo "target flag is: ${{ env.TARGET_FLAGS }}"
|
|
||||||
|
|
||||||
- name: Build ripgrep and all crates
|
|
||||||
run: ${{ env.CARGO }} build --verbose --all ${{ env.TARGET_FLAGS }}
|
|
||||||
|
|
||||||
- name: Build ripgrep with PCRE2
|
|
||||||
run: ${{ env.CARGO }} build --verbose --all --features pcre2 ${{ env.TARGET_FLAGS }}
|
|
||||||
|
|
||||||
# This is useful for debugging problems when the expected build artifacts
|
|
||||||
# (like shell completions and man pages) aren't generated.
|
|
||||||
- name: Show build.rs stderr
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
set +x
|
|
||||||
stderr="$(find "${{ env.TARGET_DIR }}/debug" -name stderr -print0 | xargs -0 ls -t | head -n1)"
|
|
||||||
if [ -s "$stderr" ]; then
|
|
||||||
echo "===== $stderr ===== "
|
|
||||||
cat "$stderr"
|
|
||||||
echo "====="
|
|
||||||
fi
|
|
||||||
set -x
|
|
||||||
|
|
||||||
- name: Run tests with PCRE2 (sans cross)
|
|
||||||
if: matrix.target == ''
|
|
||||||
run: ${{ env.CARGO }} test --verbose --all --features pcre2 ${{ env.TARGET_FLAGS }}
|
|
||||||
|
|
||||||
- name: Run tests without PCRE2 (with cross)
|
|
||||||
# These tests should actually work, but they almost double the runtime.
|
|
||||||
# Every integration test spins up qemu to run 'rg', and when PCRE2 is
|
|
||||||
# enabled, every integration test is run twice: one with the default
|
|
||||||
# regex engine and once with PCRE2.
|
|
||||||
if: matrix.target != ''
|
|
||||||
run: ${{ env.CARGO }} test --verbose --all ${{ env.TARGET_FLAGS }}
|
|
||||||
|
|
||||||
- name: Test for existence of build artifacts (Windows)
|
|
||||||
if: matrix.os == 'windows-2019'
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
outdir="$(ci/cargo-out-dir "${{ env.TARGET_DIR }}")"
|
|
||||||
ls "$outdir/_rg.ps1" && file "$outdir/_rg.ps1"
|
|
||||||
|
|
||||||
- name: Test for existence of build artifacts (Unix)
|
|
||||||
if: matrix.os != 'windows-2019'
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
outdir="$(ci/cargo-out-dir "${{ env.TARGET_DIR }}")"
|
|
||||||
for f in rg.bash rg.fish rg.1; do
|
|
||||||
# We could use file -E here, but it isn't supported on macOS.
|
|
||||||
ls "$outdir/$f" && file "$outdir/$f"
|
|
||||||
done
|
|
||||||
|
|
||||||
- name: Test zsh shell completions (Unix, sans cross)
|
|
||||||
# We could test this when using Cross, but we'd have to execute the
|
|
||||||
# 'rg' binary (done in test-complete) with qemu, which is a pain and
|
|
||||||
# doesn't really gain us much. If shell completion works in one place,
|
|
||||||
# it probably works everywhere.
|
|
||||||
if: matrix.target == '' && matrix.os != 'windows-2019'
|
|
||||||
shell: bash
|
|
||||||
run: ci/test-complete
|
|
||||||
|
|
||||||
rustfmt:
|
|
||||||
name: rustfmt
|
|
||||||
runs-on: ubuntu-18.04
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v1
|
|
||||||
- name: Install Rust
|
- name: Install Rust
|
||||||
uses: actions-rs/toolchain@v1
|
uses: hecrj/setup-rust-action@v1
|
||||||
with:
|
with:
|
||||||
toolchain: stable
|
rust-version: ${{ matrix.rust }}
|
||||||
override: true
|
- name: Install Rust Target
|
||||||
profile: minimal
|
run: rustup target add ${{ matrix.target }}
|
||||||
components: rustfmt
|
- name: Install musl-gcc
|
||||||
- name: Check formatting
|
if: contains(matrix.target, 'musl')
|
||||||
run: |
|
run: |
|
||||||
cargo fmt --all -- --check
|
apt-get install musl-tools
|
||||||
|
- name: Build everything
|
||||||
|
run: cargo build --verbose --target ${{ matrix.target }} --all --features pcre2
|
||||||
|
- name: Test zsh auto-completions
|
||||||
|
if: matrix.build == 'stable'
|
||||||
|
run: ./ci/test_complete.sh
|
||||||
|
- name: Run tests
|
||||||
|
run: cargo test --verbose --target ${{ matrix.target }} --all --features pcre2
|
||||||
|
211
.github/workflows/release.yml
vendored
211
.github/workflows/release.yml
vendored
@@ -1,211 +0,0 @@
|
|||||||
# The way this works is a little weird. But basically, the create-release job
|
|
||||||
# runs purely to initialize the GitHub release itself. Once done, the upload
|
|
||||||
# URL of the release is saved as an artifact.
|
|
||||||
#
|
|
||||||
# The build-release job runs only once create-release is finished. It gets
|
|
||||||
# the release upload URL by downloading the corresponding artifact (which was
|
|
||||||
# uploaded by create-release). It then builds the release executables for each
|
|
||||||
# supported platform and attaches them as release assets to the previously
|
|
||||||
# created release.
|
|
||||||
#
|
|
||||||
# The key here is that we create the release only once.
|
|
||||||
|
|
||||||
name: release
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
# Enable when testing release infrastructure on a branch.
|
|
||||||
# branches:
|
|
||||||
# - ag/release
|
|
||||||
tags:
|
|
||||||
- '[0-9]+.[0-9]+.[0-9]+'
|
|
||||||
jobs:
|
|
||||||
create-release:
|
|
||||||
name: create-release
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
# env:
|
|
||||||
# Set to force version number, e.g., when no tag exists.
|
|
||||||
# RG_VERSION: TEST-0.0.0
|
|
||||||
steps:
|
|
||||||
- name: Create artifacts directory
|
|
||||||
run: mkdir artifacts
|
|
||||||
|
|
||||||
- name: Get the release version from the tag
|
|
||||||
if: env.RG_VERSION == ''
|
|
||||||
run: |
|
|
||||||
# Apparently, this is the right way to get a tag name. Really?
|
|
||||||
#
|
|
||||||
# See: https://github.community/t5/GitHub-Actions/How-to-get-just-the-tag-name/m-p/32167/highlight/true#M1027
|
|
||||||
echo "::set-env name=RG_VERSION::${GITHUB_REF#refs/tags/}"
|
|
||||||
echo "version is: ${{ env.RG_VERSION }}"
|
|
||||||
|
|
||||||
- name: Create GitHub release
|
|
||||||
id: release
|
|
||||||
uses: actions/create-release@v1
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
|
||||||
tag_name: ${{ env.RG_VERSION }}
|
|
||||||
release_name: ${{ env.RG_VERSION }}
|
|
||||||
|
|
||||||
- name: Save release upload URL to artifact
|
|
||||||
run: echo "${{ steps.release.outputs.upload_url }}" > artifacts/release-upload-url
|
|
||||||
|
|
||||||
- name: Save version number to artifact
|
|
||||||
run: echo "${{ env.RG_VERSION }}" > artifacts/release-version
|
|
||||||
|
|
||||||
- name: Upload artifacts
|
|
||||||
uses: actions/upload-artifact@v1
|
|
||||||
with:
|
|
||||||
name: artifacts
|
|
||||||
path: artifacts
|
|
||||||
|
|
||||||
build-release:
|
|
||||||
name: build-release
|
|
||||||
needs: ['create-release']
|
|
||||||
runs-on: ${{ matrix.os }}
|
|
||||||
env:
|
|
||||||
# For some builds, we use cross to test on 32-bit and big-endian
|
|
||||||
# systems.
|
|
||||||
CARGO: cargo
|
|
||||||
# When CARGO is set to CROSS, this is set to `--target matrix.target`.
|
|
||||||
TARGET_FLAGS:
|
|
||||||
# When CARGO is set to CROSS, TARGET_DIR includes matrix.target.
|
|
||||||
TARGET_DIR: ./target
|
|
||||||
# Emit backtraces on panics.
|
|
||||||
RUST_BACKTRACE: 1
|
|
||||||
# Build static releases with PCRE2.
|
|
||||||
PCRE2_SYS_STATIC: 1
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
build: [linux, linux-arm, macos, win-msvc, win-gnu, win32-msvc]
|
|
||||||
include:
|
|
||||||
- build: linux
|
|
||||||
os: ubuntu-18.04
|
|
||||||
rust: nightly
|
|
||||||
target: x86_64-unknown-linux-musl
|
|
||||||
- build: linux-arm
|
|
||||||
os: ubuntu-18.04
|
|
||||||
rust: nightly
|
|
||||||
target: arm-unknown-linux-gnueabihf
|
|
||||||
- build: macos
|
|
||||||
os: macos-latest
|
|
||||||
rust: nightly
|
|
||||||
target: x86_64-apple-darwin
|
|
||||||
- build: win-msvc
|
|
||||||
os: windows-2019
|
|
||||||
rust: nightly
|
|
||||||
target: x86_64-pc-windows-msvc
|
|
||||||
- build: win-gnu
|
|
||||||
os: windows-2019
|
|
||||||
rust: nightly-x86_64-gnu
|
|
||||||
target: x86_64-pc-windows-gnu
|
|
||||||
- build: win32-msvc
|
|
||||||
os: windows-2019
|
|
||||||
rust: nightly
|
|
||||||
target: i686-pc-windows-msvc
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v1
|
|
||||||
with:
|
|
||||||
fetch-depth: 1
|
|
||||||
|
|
||||||
- name: Install packages (Ubuntu)
|
|
||||||
if: matrix.os == 'ubuntu-18.04'
|
|
||||||
run: |
|
|
||||||
ci/ubuntu-install-packages
|
|
||||||
|
|
||||||
- name: Install packages (macOS)
|
|
||||||
if: matrix.os == 'macos-latest'
|
|
||||||
run: |
|
|
||||||
ci/macos-install-packages
|
|
||||||
|
|
||||||
- name: Install Rust
|
|
||||||
uses: actions-rs/toolchain@v1
|
|
||||||
with:
|
|
||||||
toolchain: ${{ matrix.rust }}
|
|
||||||
profile: minimal
|
|
||||||
override: true
|
|
||||||
target: ${{ matrix.target }}
|
|
||||||
|
|
||||||
- name: Use Cross
|
|
||||||
# if: matrix.os != 'windows-2019'
|
|
||||||
run: |
|
|
||||||
# FIXME: to work around bugs in latest cross release, install master.
|
|
||||||
# See: https://github.com/rust-embedded/cross/issues/357
|
|
||||||
cargo install --git https://github.com/rust-embedded/cross
|
|
||||||
echo "::set-env name=CARGO::cross"
|
|
||||||
echo "::set-env name=TARGET_FLAGS::--target ${{ matrix.target }}"
|
|
||||||
echo "::set-env name=TARGET_DIR::./target/${{ matrix.target }}"
|
|
||||||
|
|
||||||
- name: Show command used for Cargo
|
|
||||||
run: |
|
|
||||||
echo "cargo command is: ${{ env.CARGO }}"
|
|
||||||
echo "target flag is: ${{ env.TARGET_FLAGS }}"
|
|
||||||
echo "target dir is: ${{ env.TARGET_DIR }}"
|
|
||||||
|
|
||||||
- name: Get release download URL
|
|
||||||
uses: actions/download-artifact@v1
|
|
||||||
with:
|
|
||||||
name: artifacts
|
|
||||||
path: artifacts
|
|
||||||
|
|
||||||
- name: Set release upload URL and release version
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
release_upload_url="$(cat artifacts/release-upload-url)"
|
|
||||||
echo "::set-env name=RELEASE_UPLOAD_URL::$release_upload_url"
|
|
||||||
echo "release upload url: $RELEASE_UPLOAD_URL"
|
|
||||||
release_version="$(cat artifacts/release-version)"
|
|
||||||
echo "::set-env name=RELEASE_VERSION::$release_version"
|
|
||||||
echo "release version: $RELEASE_VERSION"
|
|
||||||
|
|
||||||
- name: Build release binary
|
|
||||||
run: ${{ env.CARGO }} build --verbose --release --features pcre2 ${{ env.TARGET_FLAGS }}
|
|
||||||
|
|
||||||
- name: Strip release binary (linux and macos)
|
|
||||||
if: matrix.build == 'linux' || matrix.build == 'macos'
|
|
||||||
run: strip "target/${{ matrix.target }}/release/rg"
|
|
||||||
|
|
||||||
- name: Strip release binary (arm)
|
|
||||||
if: matrix.build == 'linux-arm'
|
|
||||||
run: |
|
|
||||||
docker run --rm -v \
|
|
||||||
"$PWD/target:/target:Z" \
|
|
||||||
rustembedded/cross:arm-unknown-linux-gnueabihf \
|
|
||||||
arm-linux-gnueabihf-strip \
|
|
||||||
/target/arm-unknown-linux-gnueabihf/release/rg
|
|
||||||
|
|
||||||
- name: Build archive
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
outdir="$(ci/cargo-out-dir "${{ env.TARGET_DIR }}")"
|
|
||||||
staging="ripgrep-${{ env.RELEASE_VERSION }}-${{ matrix.target }}"
|
|
||||||
mkdir -p "$staging"/{complete,doc}
|
|
||||||
|
|
||||||
cp {README.md,COPYING,UNLICENSE,LICENSE-MIT} "$staging/"
|
|
||||||
cp {CHANGELOG.md,FAQ.md,GUIDE.md} "$staging/doc/"
|
|
||||||
cp "$outdir"/{rg.bash,rg.fish,_rg.ps1} "$staging/complete/"
|
|
||||||
cp complete/_rg "$staging/complete/"
|
|
||||||
|
|
||||||
if [ "${{ matrix.os }}" = "windows-2019" ]; then
|
|
||||||
cp "target/${{ matrix.target }}/release/rg.exe" "$staging/"
|
|
||||||
7z a "$staging.zip" "$staging"
|
|
||||||
echo "::set-env name=ASSET::$staging.zip"
|
|
||||||
else
|
|
||||||
# The man page is only generated on Unix systems. ¯\_(ツ)_/¯
|
|
||||||
cp "$outdir"/rg.1 "$staging/doc/"
|
|
||||||
cp "target/${{ matrix.target }}/release/rg" "$staging/"
|
|
||||||
tar czf "$staging.tar.gz" "$staging"
|
|
||||||
echo "::set-env name=ASSET::$staging.tar.gz"
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Upload release archive
|
|
||||||
uses: actions/upload-release-asset@v1.0.1
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
|
||||||
upload_url: ${{ env.RELEASE_UPLOAD_URL }}
|
|
||||||
asset_path: ${{ env.ASSET }}
|
|
||||||
asset_name: ${{ env.ASSET }}
|
|
||||||
asset_content_type: application/octet-stream
|
|
110
.travis.yml
Normal file
110
.travis.yml
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
language: rust
|
||||||
|
dist: xenial
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
- PROJECT_NAME: ripgrep
|
||||||
|
- RUST_BACKTRACE: full
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
# For generating man page.
|
||||||
|
- libxslt1-dev
|
||||||
|
- asciidoc
|
||||||
|
- docbook-xsl
|
||||||
|
- xsltproc
|
||||||
|
- libxml2-utils
|
||||||
|
# Needed for completion-function test.
|
||||||
|
- zsh
|
||||||
|
# Needed for testing decompression search.
|
||||||
|
- xz-utils
|
||||||
|
- liblz4-tool
|
||||||
|
# For building MUSL static builds on Linux.
|
||||||
|
- musl-tools
|
||||||
|
matrix:
|
||||||
|
fast_finish: true
|
||||||
|
include:
|
||||||
|
# Nightly channel.
|
||||||
|
# All *nix releases are done on the nightly channel to take advantage
|
||||||
|
# of the regex library's multiple pattern SIMD search.
|
||||||
|
- os: linux
|
||||||
|
rust: nightly
|
||||||
|
env: TARGET=i686-unknown-linux-musl
|
||||||
|
- os: linux
|
||||||
|
rust: nightly
|
||||||
|
env: TARGET=x86_64-unknown-linux-musl
|
||||||
|
- os: osx
|
||||||
|
rust: nightly
|
||||||
|
# XML_CATALOG_FILES is apparently necessary for asciidoc on macOS.
|
||||||
|
env: TARGET=x86_64-apple-darwin XML_CATALOG_FILES=/usr/local/etc/xml/catalog
|
||||||
|
- os: linux
|
||||||
|
rust: nightly
|
||||||
|
env: TARGET=arm-unknown-linux-gnueabihf GCC_VERSION=4.8
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- gcc-4.8-arm-linux-gnueabihf
|
||||||
|
- binutils-arm-linux-gnueabihf
|
||||||
|
- libc6-armhf-cross
|
||||||
|
- libc6-dev-armhf-cross
|
||||||
|
# For generating man page.
|
||||||
|
- libxslt1-dev
|
||||||
|
- asciidoc
|
||||||
|
- docbook-xsl
|
||||||
|
- xsltproc
|
||||||
|
- libxml2-utils
|
||||||
|
# Beta channel. We enable these to make sure there are no regressions in
|
||||||
|
# Rust beta releases.
|
||||||
|
- os: linux
|
||||||
|
rust: beta
|
||||||
|
env: TARGET=x86_64-unknown-linux-musl
|
||||||
|
- os: linux
|
||||||
|
rust: beta
|
||||||
|
env: TARGET=x86_64-unknown-linux-gnu
|
||||||
|
# Minimum Rust supported channel. We enable these to make sure ripgrep
|
||||||
|
# continues to work on the advertised minimum Rust version.
|
||||||
|
- os: linux
|
||||||
|
rust: 1.34.0
|
||||||
|
env: TARGET=x86_64-unknown-linux-gnu
|
||||||
|
- os: linux
|
||||||
|
rust: 1.34.0
|
||||||
|
env: TARGET=x86_64-unknown-linux-musl
|
||||||
|
- os: linux
|
||||||
|
rust: 1.34.0
|
||||||
|
env: TARGET=arm-unknown-linux-gnueabihf GCC_VERSION=4.8
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- gcc-4.8-arm-linux-gnueabihf
|
||||||
|
- binutils-arm-linux-gnueabihf
|
||||||
|
- libc6-armhf-cross
|
||||||
|
- libc6-dev-armhf-cross
|
||||||
|
# For generating man page.
|
||||||
|
- libxslt1-dev
|
||||||
|
- asciidoc
|
||||||
|
- docbook-xsl
|
||||||
|
- xsltproc
|
||||||
|
- libxml2-utils
|
||||||
|
install: ci/install.sh
|
||||||
|
script: ci/script.sh
|
||||||
|
before_deploy: ci/before_deploy.sh
|
||||||
|
deploy:
|
||||||
|
provider: releases
|
||||||
|
file_glob: true
|
||||||
|
file: deployment/${PROJECT_NAME}-${TRAVIS_TAG}-${TARGET}.tar.gz
|
||||||
|
skip_cleanup: true
|
||||||
|
on:
|
||||||
|
condition: $TRAVIS_RUST_VERSION = nightly
|
||||||
|
branch: master # i guess we do need this after all?
|
||||||
|
tags: true
|
||||||
|
api_key:
|
||||||
|
secure: "IbSnsbGkxSydR/sozOf1/SRvHplzwRUHzcTjM7BKnr7GccL86gRPUrsrvD103KjQUGWIc1TnK1YTq5M0Onswg/ORDjqa1JEJPkPdPnVh9ipbF7M2De/7IlB4X4qXLKoApn8+bx2x/mfYXu4G+G1/2QdbaKK2yfXZKyjz0YFx+6CNrVCT2Nk8q7aHvOOzAL58vsG8iPDpupuhxlMDDn/UhyOWVInmPPQ0iJR1ZUJN8xJwXvKvBbfp3AhaBiAzkhXHNLgBR8QC5noWWMXnuVDMY3k4f3ic0V+p/qGUCN/nhptuceLxKFicMCYObSZeUzE5RAI0/OBW7l3z2iCoc+TbAnn+JrX/ObJCfzgAOXAU3tLaBFMiqQPGFKjKg1ltSYXomOFP/F7zALjpvFp4lYTBajRR+O3dqaxA9UQuRjw27vOeUpMcga4ZzL4VXFHzrxZKBHN//XIGjYAVhJ1NSSeGpeJV5/+jYzzWKfwSagRxQyVCzMooYFFXzn8Yxdm3PJlmp3GaAogNkdB9qKcrEvRINCelalzALPi0hD/HUDi8DD2PNTCLLMo6VSYtvc685Zbe+KgNzDV1YyTrRCUW6JotrS0r2ULLwnsh40hSB//nNv3XmwNmC/CmW5QAnIGj8cBMF4S2t6ohADIndojdAfNiptmaZOIT6owK7bWMgPMyopo="
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
# Pushes and PR to the master branch
|
||||||
|
- master
|
||||||
|
# Ruby regex to match tags. Required, or travis won't trigger deploys when
|
||||||
|
# a new tag is pushed.
|
||||||
|
- /^\d+\.\d+\.\d+.*$/
|
||||||
|
notifications:
|
||||||
|
email:
|
||||||
|
on_success: never
|
93
CHANGELOG.md
93
CHANGELOG.md
@@ -1,96 +1,11 @@
|
|||||||
12.0.1 (TBD)
|
TBD
|
||||||
============
|
===
|
||||||
ripgrep 12.0.1 is a small patch release that includes a couple minor bug fixes.
|
TODO
|
||||||
These bug fixes address regressions introduced in the 12.0.0 release.
|
|
||||||
|
|
||||||
Bug fixes:
|
Bug fixes:
|
||||||
|
|
||||||
* [BUG #1520](https://github.com/BurntSushi/ripgrep/issues/1520):
|
* [BUG #1335](https://github.com/BurntSushi/ripgrep/issues/1335):
|
||||||
Don't emit spurious error messages in git repositories with submodules.
|
|
||||||
|
|
||||||
|
|
||||||
12.0.0 (2020-03-15)
|
|
||||||
===================
|
|
||||||
ripgrep 12 is a new major version release of ripgrep that contains many bug
|
|
||||||
fixes, several important performance improvements and a few minor new features.
|
|
||||||
|
|
||||||
In a near future release, I am hoping to add an
|
|
||||||
[indexing feature](https://github.com/BurntSushi/ripgrep/issues/1497)
|
|
||||||
to ripgrep, which will dramatically speed up searching by building an index.
|
|
||||||
Feedback would very much be appreciated, especially on the user experience
|
|
||||||
which will be difficult to get right.
|
|
||||||
|
|
||||||
This release has no known breaking changes.
|
|
||||||
|
|
||||||
Deprecations:
|
|
||||||
|
|
||||||
* The `--no-pcre2-unicode` flag is deprecated. Instead, use the `--no-unicode`
|
|
||||||
flag, which applies to both the default regex engine and PCRE2. For now,
|
|
||||||
`--no-pcre2-unicode` and `--pcre2-unicode` are aliases to `--no-unicode`
|
|
||||||
and `--unicode`, respectively. The `--[no-]pcre2-unicode` flags may be
|
|
||||||
removed in a future release.
|
|
||||||
* The `--auto-hybrid-regex` flag is deprecated. Instead, use the new `--engine`
|
|
||||||
flag with the `auto` value.
|
|
||||||
|
|
||||||
Performance improvements:
|
|
||||||
|
|
||||||
* [PERF #1087](https://github.com/BurntSushi/ripgrep/pull/1087):
|
|
||||||
ripgrep is smarter when detected literals are whitespace.
|
|
||||||
* [PERF #1381](https://github.com/BurntSushi/ripgrep/pull/1381):
|
|
||||||
Directory traversal is sped up with speculative ignore-file existence checks.
|
|
||||||
* [PERF cd8ec38a](https://github.com/BurntSushi/ripgrep/commit/cd8ec38a):
|
|
||||||
Improve inner literal detection to cover more cases more effectively.
|
|
||||||
e.g., ` +Sherlock Holmes +` now has ` Sherlock Holmes ` extracted instead
|
|
||||||
of ` `.
|
|
||||||
* [PERF 6a0e0147](https://github.com/BurntSushi/ripgrep/commit/6a0e0147):
|
|
||||||
Improve literal detection when the `-w/--word-regexp` flag is used.
|
|
||||||
* [PERF ad97e9c9](https://github.com/BurntSushi/ripgrep/commit/ad97e9c9):
|
|
||||||
Improve overall performance of the `-w/--word-regexp` flag.
|
|
||||||
|
|
||||||
Feature enhancements:
|
|
||||||
|
|
||||||
* Added or improved file type filtering for erb, diff, Gradle, HAML, Org,
|
|
||||||
Postscript, Skim, Slim, Slime, RPM Spec files, Typoscript, xml.
|
|
||||||
* [FEATURE #1370](https://github.com/BurntSushi/ripgrep/pull/1370):
|
|
||||||
Add `--include-zero` flag that shows files searched without matches.
|
|
||||||
* [FEATURE #1390](https://github.com/BurntSushi/ripgrep/pull/1390):
|
|
||||||
Add `--no-context-separator` flag that always hides context separators.
|
|
||||||
* [FEATURE #1414](https://github.com/BurntSushi/ripgrep/pull/1414):
|
|
||||||
Add `--no-require-git` flag to allow ripgrep to respect gitignores anywhere.
|
|
||||||
* [FEATURE #1420](https://github.com/BurntSushi/ripgrep/pull/1420):
|
|
||||||
Add `--no-ignore-exclude` to disregard rules in `.git/info/exclude` files.
|
|
||||||
* [FEATURE #1466](https://github.com/BurntSushi/ripgrep/pull/1466):
|
|
||||||
Add `--no-ignore-files` flag to disable all `--ignore-file` flags.
|
|
||||||
* [FEATURE #1488](https://github.com/BurntSushi/ripgrep/pull/1488):
|
|
||||||
Add '--engine' flag for easier switching between regex engines.
|
|
||||||
* [FEATURE 75cbe88f](https://github.com/BurntSushi/ripgrep/commit/75cbe88f):
|
|
||||||
Add `--no-unicode` flag. This works on all supported regex engines.
|
|
||||||
|
|
||||||
Bug fixes:
|
|
||||||
|
|
||||||
* [BUG #1291](https://github.com/BurntSushi/ripgrep/issues/1291):
|
|
||||||
ripgrep now works in non-existent directories.
|
|
||||||
* [BUG #1319](https://github.com/BurntSushi/ripgrep/issues/1319):
|
|
||||||
Fix match bug due to errant literal detection.
|
|
||||||
* [**BUG #1335**](https://github.com/BurntSushi/ripgrep/issues/1335):
|
|
||||||
Fixes a performance bug when searching plain text files with very long lines.
|
Fixes a performance bug when searching plain text files with very long lines.
|
||||||
This was a serious performance regression in some cases.
|
|
||||||
* [BUG #1344](https://github.com/BurntSushi/ripgrep/issues/1344):
|
|
||||||
Document usage of `--type all`.
|
|
||||||
* [BUG #1389](https://github.com/BurntSushi/ripgrep/issues/1389):
|
|
||||||
Fixes a bug where ripgrep would panic when searching a symlinked directory.
|
|
||||||
* [BUG #1439](https://github.com/BurntSushi/ripgrep/issues/1439):
|
|
||||||
Improve documentation for ripgrep's automatic stdin detection.
|
|
||||||
* [BUG #1441](https://github.com/BurntSushi/ripgrep/issues/1441):
|
|
||||||
Remove CPU features from man page.
|
|
||||||
* [BUG #1442](https://github.com/BurntSushi/ripgrep/issues/1442),
|
|
||||||
[BUG #1478](https://github.com/BurntSushi/ripgrep/issues/1478):
|
|
||||||
Improve documentation of the `-g/--glob` flag.
|
|
||||||
* [BUG #1445](https://github.com/BurntSushi/ripgrep/issues/1445):
|
|
||||||
ripgrep now respects ignore rules from .git/info/exclude in worktrees.
|
|
||||||
* [BUG #1485](https://github.com/BurntSushi/ripgrep/issues/1485):
|
|
||||||
Fish shell completions from the release Debian package are now installed to
|
|
||||||
`/usr/share/fish/vendor_completions.d/rg.fish`.
|
|
||||||
|
|
||||||
|
|
||||||
11.0.2 (2019-08-01)
|
11.0.2 (2019-08-01)
|
||||||
|
406
Cargo.lock
generated
406
Cargo.lock
generated
@@ -2,65 +2,62 @@
|
|||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "0.7.10"
|
version = "0.7.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atty"
|
name = "atty"
|
||||||
version = "0.2.14"
|
version = "0.2.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "autocfg"
|
|
||||||
version = "1.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base64"
|
name = "base64"
|
||||||
version = "0.11.0"
|
version = "0.10.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.2.1"
|
version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bstr"
|
name = "bstr"
|
||||||
version = "0.2.12"
|
version = "0.2.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"regex-automata 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytecount"
|
name = "bytecount"
|
||||||
version = "0.6.0"
|
version = "0.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
version = "1.3.4"
|
version = "1.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.0.50"
|
version = "1.0.41"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "0.1.10"
|
version = "0.1.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -68,46 +65,44 @@ name = "clap"
|
|||||||
version = "2.33.0"
|
version = "2.33.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-channel"
|
name = "crossbeam-channel"
|
||||||
version = "0.4.2"
|
version = "0.3.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-utils"
|
name = "crossbeam-utils"
|
||||||
version = "0.7.2"
|
version = "0.6.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "encoding_rs"
|
name = "encoding_rs"
|
||||||
version = "0.8.22"
|
version = "0.8.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"packed_simd 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"packed_simd 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "encoding_rs_io"
|
name = "encoding_rs_io"
|
||||||
version = "0.1.7"
|
version = "0.1.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"encoding_rs 0.8.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
"encoding_rs 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -127,135 +122,122 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "globset"
|
name = "globset"
|
||||||
version = "0.4.5"
|
version = "0.4.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"bstr 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bstr 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"regex 1.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "grep"
|
name = "grep"
|
||||||
version = "0.2.5"
|
version = "0.2.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"grep-cli 0.1.4",
|
"grep-cli 0.1.3",
|
||||||
"grep-matcher 0.1.4",
|
"grep-matcher 0.1.3",
|
||||||
"grep-pcre2 0.1.4",
|
"grep-pcre2 0.1.3",
|
||||||
"grep-printer 0.1.4",
|
"grep-printer 0.1.3",
|
||||||
"grep-regex 0.1.7",
|
"grep-regex 0.1.5",
|
||||||
"grep-searcher 0.1.7",
|
"grep-searcher 0.1.6",
|
||||||
"termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "grep-cli"
|
name = "grep-cli"
|
||||||
version = "0.1.4"
|
version = "0.1.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"bstr 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bstr 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"globset 0.4.5",
|
"globset 0.4.4",
|
||||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"regex 1.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "grep-matcher"
|
name = "grep-matcher"
|
||||||
version = "0.1.4"
|
version = "0.1.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"regex 1.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "grep-pcre2"
|
name = "grep-pcre2"
|
||||||
version = "0.1.4"
|
version = "0.1.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"grep-matcher 0.1.4",
|
"grep-matcher 0.1.3",
|
||||||
"pcre2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"pcre2 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "grep-printer"
|
name = "grep-printer"
|
||||||
version = "0.1.4"
|
version = "0.1.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"bstr 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bstr 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"grep-matcher 0.1.4",
|
"grep-matcher 0.1.3",
|
||||||
"grep-regex 0.1.7",
|
"grep-regex 0.1.5",
|
||||||
"grep-searcher 0.1.7",
|
"grep-searcher 0.1.6",
|
||||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "grep-regex"
|
name = "grep-regex"
|
||||||
version = "0.1.7"
|
version = "0.1.5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"bstr 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
"grep-matcher 0.1.3",
|
||||||
"grep-matcher 0.1.4",
|
|
||||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"regex 1.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"regex-syntax 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
"regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "grep-searcher"
|
name = "grep-searcher"
|
||||||
version = "0.1.7"
|
version = "0.1.6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bstr 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bstr 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"bytecount 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bytecount 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"encoding_rs 0.8.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
"encoding_rs 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"encoding_rs_io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"encoding_rs_io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"grep-matcher 0.1.4",
|
"grep-matcher 0.1.3",
|
||||||
"grep-regex 0.1.7",
|
"grep-regex 0.1.5",
|
||||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"regex 1.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hermit-abi"
|
|
||||||
version = "0.1.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ignore"
|
name = "ignore"
|
||||||
version = "0.4.12"
|
version = "0.4.10"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"globset 0.4.4",
|
||||||
"globset 0.4.5",
|
|
||||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"regex 1.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "0.4.5"
|
version = "0.4.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -263,9 +245,9 @@ name = "jemalloc-sys"
|
|||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -274,7 +256,7 @@ version = "0.3.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jemalloc-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"jemalloc-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -284,7 +266,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.67"
|
version = "0.2.62"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -292,17 +274,12 @@ name = "log"
|
|||||||
version = "0.4.8"
|
version = "0.4.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "maybe-uninit"
|
|
||||||
version = "2.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.3.3"
|
version = "2.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -310,17 +287,16 @@ name = "memmap"
|
|||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num_cpus"
|
name = "num_cpus"
|
||||||
version = "1.12.0"
|
version = "1.10.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -328,18 +304,18 @@ name = "packed_simd"
|
|||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pcre2"
|
name = "pcre2"
|
||||||
version = "0.2.3"
|
version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"pcre2-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"pcre2-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -347,19 +323,19 @@ name = "pcre2-sys"
|
|||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
"pkg-config 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pkg-config"
|
name = "pkg-config"
|
||||||
version = "0.3.17"
|
version = "0.3.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.9"
|
version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -367,92 +343,91 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.3"
|
version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.3.5"
|
version = "1.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"regex-syntax 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
"regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-automata"
|
name = "regex-automata"
|
||||||
version = "0.1.9"
|
version = "0.1.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-syntax"
|
name = "regex-syntax"
|
||||||
version = "0.6.17"
|
version = "0.6.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ripgrep"
|
name = "ripgrep"
|
||||||
version = "12.0.0"
|
version = "11.0.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bstr 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bstr 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"grep 0.2.5",
|
"grep 0.2.4",
|
||||||
"ignore 0.4.12",
|
"ignore 0.4.10",
|
||||||
"jemallocator 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"jemallocator 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"regex 1.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.3"
|
version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "same-file"
|
name = "same-file"
|
||||||
version = "1.0.6"
|
version = "1.0.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.104"
|
version = "1.0.99"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.104"
|
version = "1.0.99"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.48"
|
version = "1.0.40"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ryu 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -462,20 +437,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.16"
|
version = "1.0.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "termcolor"
|
name = "termcolor"
|
||||||
version = "1.1.0"
|
version = "1.0.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -483,12 +458,12 @@ name = "textwrap"
|
|||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thread_local"
|
name = "thread_local"
|
||||||
version = "1.0.1"
|
version = "0.3.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -496,7 +471,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-width"
|
name = "unicode-width"
|
||||||
version = "0.1.7"
|
version = "0.1.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -506,12 +481,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "walkdir"
|
name = "walkdir"
|
||||||
version = "2.3.1"
|
version = "2.2.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -530,7 +505,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi-util"
|
name = "winapi-util"
|
||||||
version = "0.1.3"
|
version = "0.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -541,59 +516,66 @@ name = "winapi-x86_64-pc-windows-gnu"
|
|||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wincolor"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
"checksum aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada"
|
"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d"
|
||||||
"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90"
|
||||||
"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
|
"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
|
||||||
"checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7"
|
"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd"
|
||||||
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
"checksum bstr 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94cdf78eb7e94c566c1f5dbe2abf8fc70a548fc902942a48c4b3a98b48ca9ade"
|
||||||
"checksum bstr 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "2889e6d50f394968c8bf4240dc3f2a7eb4680844d27308f798229ac9d4725f41"
|
"checksum bytecount 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be0fdd54b507df8f22012890aadd099979befdba27713c767993f8380112ca7c"
|
||||||
"checksum bytecount 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b0017894339f586ccb943b01b9555de56770c11cda818e7e3d8bd93f4ed7f46e"
|
"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
|
||||||
"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
"checksum cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "8dae9c4b8fedcae85592ba623c4fd08cfdab3e3b72d6df780c6ead964a69bfff"
|
||||||
"checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd"
|
"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
|
||||||
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
|
||||||
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
|
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
|
||||||
"checksum crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cced8691919c02aac3cb0a1bc2e9b73d89e832bf9a06fc579d4e71b68a2da061"
|
"checksum crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c8ec7fcd21571dc78f96cc96243cab8d8f035247c3efd16c687be154c3fa9efa"
|
||||||
"checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6"
|
||||||
"checksum encoding_rs 0.8.22 (registry+https://github.com/rust-lang/crates.io-index)" = "cd8d03faa7fe0c1431609dfad7bbe827af30f82e1e2ae6f7ee4fca6bd764bc28"
|
"checksum encoding_rs 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)" = "4155785c79f2f6701f185eb2e6b4caf0555ec03477cb4c70db67b465311620ed"
|
||||||
"checksum encoding_rs_io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1cc3c5651fb62ab8aa3103998dade57efdd028544bd300516baa31840c252a83"
|
"checksum encoding_rs_io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9619ee7a2bf4e777e020b95c1439abaf008f8ea8041b78a0552c4f1bcf4df32c"
|
||||||
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
|
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
|
||||||
"checksum fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5f2a4a2034423744d2cc7ca2068453168dcdb82c438419e639a26bd87839c674"
|
"checksum fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5f2a4a2034423744d2cc7ca2068453168dcdb82c438419e639a26bd87839c674"
|
||||||
"checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
"checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||||
"checksum hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8"
|
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
|
||||||
"checksum itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e"
|
|
||||||
"checksum jemalloc-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0d3b9f3f5c9b31aa0f5ed3260385ac205db665baa41d49bb8338008ae94ede45"
|
"checksum jemalloc-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0d3b9f3f5c9b31aa0f5ed3260385ac205db665baa41d49bb8338008ae94ede45"
|
||||||
"checksum jemallocator 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "43ae63fcfc45e99ab3d1b29a46782ad679e98436c3169d15a167a1108a724b69"
|
"checksum jemallocator 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "43ae63fcfc45e99ab3d1b29a46782ad679e98436c3169d15a167a1108a724b69"
|
||||||
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
"checksum libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)" = "eb147597cdf94ed43ab7a9038716637d2d1bf2bc571da995d0028dec06bd3018"
|
"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba"
|
||||||
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
|
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
|
||||||
"checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
|
"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e"
|
||||||
"checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
|
|
||||||
"checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
|
"checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
|
||||||
"checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6"
|
"checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273"
|
||||||
"checksum packed_simd 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a85ea9fc0d4ac0deb6fe7911d38786b32fc11119afd9e9d38b84ff691ce64220"
|
"checksum packed_simd 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a85ea9fc0d4ac0deb6fe7911d38786b32fc11119afd9e9d38b84ff691ce64220"
|
||||||
"checksum pcre2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "85b30f2f69903b439dd9dc9e824119b82a55bf113b29af8d70948a03c1b11ab1"
|
"checksum pcre2 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "603da5e101220b9b306bf28e4f1f8703458ce2f64d2787b374e1a19494317180"
|
||||||
"checksum pcre2-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "876c72d05059d23a84bd9fcdc3b1d31c50ea7fe00fe1522b4e68cd3608db8d5b"
|
"checksum pcre2-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "876c72d05059d23a84bd9fcdc3b1d31c50ea7fe00fe1522b4e68cd3608db8d5b"
|
||||||
"checksum pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677"
|
"checksum pkg-config 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c1d2cfa5a714db3b5f24f0915e74fcdf91d09d496ba61329705dda7774d2af"
|
||||||
"checksum proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435"
|
"checksum proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c5c2380ae88876faae57698be9e9775e3544decad214599c3a6266cca6ac802"
|
||||||
"checksum quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f"
|
"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
|
||||||
"checksum regex 1.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8900ebc1363efa7ea1c399ccc32daed870b4002651e0bed86e72d501ebbe0048"
|
"checksum regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88c3d9193984285d544df4a30c23a4e62ead42edf70a4452ceb76dac1ce05c26"
|
||||||
"checksum regex-automata 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4"
|
"checksum regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "92b73c2a1770c255c240eaa4ee600df1704a38dc3feaa6e949e7fcd4f8dc09f9"
|
||||||
"checksum regex-syntax 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)" = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae"
|
"checksum regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b143cceb2ca5e56d5671988ef8b15615733e7ee16cd348e064333b251b89343f"
|
||||||
"checksum ryu 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535622e6be132bccd223f4bb2b8ac8d53cda3c7a6394944d3b2b33fb974f9d76"
|
"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997"
|
||||||
"checksum same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
"checksum same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "585e8ddcedc187886a30fa705c47985c3fa88d06624095856b36ca0b82ff4421"
|
||||||
"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449"
|
"checksum serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "fec2851eb56d010dc9a21b89ca53ee75e6528bab60c11e89d38390904982da9f"
|
||||||
"checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64"
|
"checksum serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "cb4dc18c61206b08dc98216c98faa0232f4337e1e1b8574551d5bad29ea1b425"
|
||||||
"checksum serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)" = "9371ade75d4c2d6cb154141b9752cf3781ec9c05e0e5cf35060e1e70ee7b9c25"
|
"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704"
|
||||||
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||||
"checksum syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)" = "123bd9499cfb380418d509322d7a6d52e5315f064fe4b3ad18a53d6b92c07859"
|
"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf"
|
||||||
"checksum termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f"
|
"checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e"
|
||||||
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||||
"checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
|
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
|
||||||
"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
|
"checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20"
|
||||||
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
||||||
"checksum walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d"
|
"checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e"
|
||||||
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
|
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
|
||||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
"checksum winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4ccfbf554c6ad11084fb7517daca16cfdcaccbdadba4fc336f032a8b12c2ad80"
|
"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9"
|
||||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
"checksum wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96f5016b18804d24db43cebf3c77269e7569b8954a8464501c216cc5e070eaa9"
|
||||||
|
45
Cargo.toml
45
Cargo.toml
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ripgrep"
|
name = "ripgrep"
|
||||||
version = "12.0.0" #:version
|
version = "11.0.2" #:version
|
||||||
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
||||||
description = """
|
description = """
|
||||||
ripgrep is a line-oriented search tool that recursively searches your current
|
ripgrep is a line-oriented search tool that recursively searches your current
|
||||||
@@ -20,12 +20,12 @@ autotests = false
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[badges]
|
[badges]
|
||||||
# I guess crates.io does not support GitHub Action badges yet.
|
travis-ci = { repository = "BurntSushi/ripgrep" }
|
||||||
# Tracking PR: https://github.com/rust-lang/crates.io/pull/1838
|
appveyor = { repository = "BurntSushi/ripgrep" }
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
bench = false
|
bench = false
|
||||||
path = "crates/core/main.rs"
|
path = "src/main.rs"
|
||||||
name = "rg"
|
name = "rg"
|
||||||
|
|
||||||
[[test]]
|
[[test]]
|
||||||
@@ -34,30 +34,30 @@ path = "tests/tests.rs"
|
|||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"crates/globset",
|
"globset",
|
||||||
"crates/grep",
|
"grep",
|
||||||
"crates/cli",
|
"grep-cli",
|
||||||
"crates/matcher",
|
"grep-matcher",
|
||||||
"crates/pcre2",
|
"grep-pcre2",
|
||||||
"crates/printer",
|
"grep-printer",
|
||||||
"crates/regex",
|
"grep-regex",
|
||||||
"crates/searcher",
|
"grep-searcher",
|
||||||
"crates/ignore",
|
"ignore",
|
||||||
]
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bstr = "0.2.12"
|
bstr = "0.2.0"
|
||||||
grep = { version = "0.2.5", path = "crates/grep" }
|
grep = { version = "0.2.4", path = "grep" }
|
||||||
ignore = { version = "0.4.12", path = "crates/ignore" }
|
ignore = { version = "0.4.7", path = "ignore" }
|
||||||
lazy_static = "1.1.0"
|
lazy_static = "1.1.0"
|
||||||
log = "0.4.5"
|
log = "0.4.5"
|
||||||
num_cpus = "1.8.0"
|
num_cpus = "1.8.0"
|
||||||
regex = "1.3.5"
|
regex = "1.0.5"
|
||||||
serde_json = "1.0.23"
|
serde_json = "1.0.23"
|
||||||
termcolor = "1.1.0"
|
termcolor = "1.0.3"
|
||||||
|
|
||||||
[dependencies.clap]
|
[dependencies.clap]
|
||||||
version = "2.33.0"
|
version = "2.32.0"
|
||||||
default-features = false
|
default-features = false
|
||||||
features = ["suggestions"]
|
features = ["suggestions"]
|
||||||
|
|
||||||
@@ -68,14 +68,13 @@ version = "0.3.0"
|
|||||||
lazy_static = "1.1.0"
|
lazy_static = "1.1.0"
|
||||||
|
|
||||||
[build-dependencies.clap]
|
[build-dependencies.clap]
|
||||||
version = "2.33.0"
|
version = "2.32.0"
|
||||||
default-features = false
|
default-features = false
|
||||||
features = ["suggestions"]
|
features = ["suggestions"]
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serde = "1.0.77"
|
serde = "1.0.77"
|
||||||
serde_derive = "1.0.77"
|
serde_derive = "1.0.77"
|
||||||
walkdir = "2"
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
simd-accel = ["grep/simd-accel"]
|
simd-accel = ["grep/simd-accel"]
|
||||||
@@ -98,11 +97,11 @@ assets = [
|
|||||||
# The man page is automatically generated by ripgrep's build process, so
|
# The man page is automatically generated by ripgrep's build process, so
|
||||||
# this file isn't actually commited. Instead, to create a dpkg, either
|
# this file isn't actually commited. Instead, to create a dpkg, either
|
||||||
# create a deployment/deb directory and copy the man page to it, or use the
|
# create a deployment/deb directory and copy the man page to it, or use the
|
||||||
# 'ci/build-deb' script.
|
# 'ci/build_deb.sh' script.
|
||||||
["deployment/deb/rg.1", "usr/share/man/man1/rg.1", "644"],
|
["deployment/deb/rg.1", "usr/share/man/man1/rg.1", "644"],
|
||||||
# Similarly for shell completions.
|
# Similarly for shell completions.
|
||||||
["deployment/deb/rg.bash", "usr/share/bash-completion/completions/rg", "644"],
|
["deployment/deb/rg.bash", "usr/share/bash-completion/completions/rg", "644"],
|
||||||
["deployment/deb/rg.fish", "usr/share/fish/vendor_completions.d/rg.fish", "644"],
|
["deployment/deb/rg.fish", "usr/share/fish/completions/rg.fish", "644"],
|
||||||
["deployment/deb/_rg", "usr/share/zsh/vendor-completions/", "644"],
|
["deployment/deb/_rg", "usr/share/zsh/vendor-completions/", "644"],
|
||||||
]
|
]
|
||||||
extended-description = """\
|
extended-description = """\
|
||||||
|
11
Cross.toml
11
Cross.toml
@@ -1,11 +1,2 @@
|
|||||||
[target.x86_64-unknown-linux-musl]
|
[target.x86_64-unknown-linux-musl]
|
||||||
image = "burntsushi/cross:x86_64-unknown-linux-musl"
|
image = "burntsushi/x86_64-unknown-linux-musl:v0.1.14"
|
||||||
|
|
||||||
[target.i686-unknown-linux-gnu]
|
|
||||||
image = "burntsushi/cross:i686-unknown-linux-gnu"
|
|
||||||
|
|
||||||
[target.mips64-unknown-linux-gnuabi64]
|
|
||||||
image = "burntsushi/cross:mips64-unknown-linux-gnuabi64"
|
|
||||||
|
|
||||||
[target.arm-unknown-linux-gnueabihf]
|
|
||||||
image = "burntsushi/cross:arm-unknown-linux-gnueabihf"
|
|
||||||
|
27
FAQ.md
27
FAQ.md
@@ -25,7 +25,6 @@
|
|||||||
* [How is ripgrep licensed?](#license)
|
* [How is ripgrep licensed?](#license)
|
||||||
* [Can ripgrep replace grep?](#posix4ever)
|
* [Can ripgrep replace grep?](#posix4ever)
|
||||||
* [What does the "rip" in ripgrep mean?](#intentcountsforsomething)
|
* [What does the "rip" in ripgrep mean?](#intentcountsforsomething)
|
||||||
* [How can I donate to ripgrep or its maintainers?](#donations)
|
|
||||||
|
|
||||||
|
|
||||||
<h3 name="config">
|
<h3 name="config">
|
||||||
@@ -51,9 +50,9 @@ ripgrep is a project whose contributors are volunteers. A release schedule
|
|||||||
adds undue stress to said volunteers. Therefore, releases are made on a best
|
adds undue stress to said volunteers. Therefore, releases are made on a best
|
||||||
effort basis and no dates **will ever be given**.
|
effort basis and no dates **will ever be given**.
|
||||||
|
|
||||||
An exception to this _can be_ high impact bugs. If a ripgrep release contains
|
One exception to this is high impact bugs. If a ripgrep release contains a
|
||||||
a significant regression, then there will generally be a strong push to get a
|
significant regression, then there will generally be a strong push to get a
|
||||||
patch release out with a fix. However, no promises are made.
|
patch release out with a fix.
|
||||||
|
|
||||||
|
|
||||||
<h3 name="manpage">
|
<h3 name="manpage">
|
||||||
@@ -935,7 +934,7 @@ Here are some cases where you might *not* want to use ripgrep. The same caveats
|
|||||||
for the previous section apply.
|
for the previous section apply.
|
||||||
|
|
||||||
* Are you writing portable shell scripts intended to work in a variety of
|
* Are you writing portable shell scripts intended to work in a variety of
|
||||||
environments? Great, probably not a good idea to use ripgrep! ripgrep has
|
environments? Great, probably not a good idea to use ripgrep! ripgrep is has
|
||||||
nowhere near the ubiquity of grep, so if you do use ripgrep, you might need
|
nowhere near the ubiquity of grep, so if you do use ripgrep, you might need
|
||||||
to futz with the installation process more than you would with grep.
|
to futz with the installation process more than you would with grep.
|
||||||
* Do you care about POSIX compatibility? If so, then you can't use ripgrep
|
* Do you care about POSIX compatibility? If so, then you can't use ripgrep
|
||||||
@@ -982,21 +981,3 @@ grep](#posix4ever),
|
|||||||
ripgrep is neither actually a "grep killer" nor was it ever intended to be. It
|
ripgrep is neither actually a "grep killer" nor was it ever intended to be. It
|
||||||
certainly does eat into some of its use cases, but that's nothing that other
|
certainly does eat into some of its use cases, but that's nothing that other
|
||||||
tools like ack or The Silver Searcher weren't already doing.
|
tools like ack or The Silver Searcher weren't already doing.
|
||||||
|
|
||||||
|
|
||||||
<h3 name="donations">
|
|
||||||
How can I donate to ripgrep or its maintainers?
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
As of now, you can't. While I believe the various efforts that are being
|
|
||||||
undertaken to help fund FOSS are extremely important, they aren't a good fit
|
|
||||||
for me. ripgrep is and I hope will remain a project of love that I develop in
|
|
||||||
my free time. As such, involving money---even in the form of donations given
|
|
||||||
without expectations---would severely change that dynamic for me personally.
|
|
||||||
|
|
||||||
Instead, I'd recommend donating to something else that is doing work that you
|
|
||||||
find meaningful. If you would like suggestions, then my favorites are:
|
|
||||||
|
|
||||||
* [The Internet Archive](https://archive.org/donate/)
|
|
||||||
* [Rails Girls](https://railsgirlssummerofcode.org/campaign/)
|
|
||||||
* [Wikipedia](https://wikimediafoundation.org/support/)
|
|
||||||
|
19
GUIDE.md
19
GUIDE.md
@@ -411,21 +411,6 @@ alias rg="rg --type-add 'web:*.{html,css,js}'"
|
|||||||
or add `--type-add=web:*.{html,css,js}` to your ripgrep configuration file.
|
or add `--type-add=web:*.{html,css,js}` to your ripgrep configuration file.
|
||||||
([Configuration files](#configuration-file) are covered in more detail later.)
|
([Configuration files](#configuration-file) are covered in more detail later.)
|
||||||
|
|
||||||
#### The special `all` file type
|
|
||||||
|
|
||||||
A special option supported by the `--type` flag is `all`. `--type all` looks
|
|
||||||
for a match in any of the supported file types listed by `--type-list`,
|
|
||||||
including those added on the command line using `--type-add`. It's equivalent
|
|
||||||
to the command `rg --type agda --type asciidoc --type asm ...`, where `...`
|
|
||||||
stands for a list of `--type` flags for the rest of the types in `--type-list`.
|
|
||||||
|
|
||||||
As an example, let's suppose you have a shell script in your current directory,
|
|
||||||
`my-shell-script`, which includes a shell library, `my-shell-library.bash`.
|
|
||||||
Both `rg --type sh` and `rg --type all` would only search for matches in
|
|
||||||
`my-shell-library.bash`, not `my-shell-script`, because the globs matched
|
|
||||||
by the `sh` file type don't include files without an extension. On the
|
|
||||||
other hand, `rg --type-not all` would search `my-shell-script` but not
|
|
||||||
`my-shell-library.bash`.
|
|
||||||
|
|
||||||
### Replacements
|
### Replacements
|
||||||
|
|
||||||
@@ -731,8 +716,8 @@ binary files:
|
|||||||
**only applies to files searched by ripgrep as a result of recursive
|
**only applies to files searched by ripgrep as a result of recursive
|
||||||
directory traversal**, which is consistent with ripgrep's other automatic
|
directory traversal**, which is consistent with ripgrep's other automatic
|
||||||
filtering. For example, `rg foo .file` will search `.file` even though it
|
filtering. For example, `rg foo .file` will search `.file` even though it
|
||||||
is hidden. Similarly, `rg foo binary-file` will search `binary-file` in
|
is hidden. Similarly, `rg foo binary-file` search `binary-file` in "binary"
|
||||||
"binary" mode automatically.
|
mode automatically.
|
||||||
2. Binary mode is similar to the default mode, except it will not always
|
2. Binary mode is similar to the default mode, except it will not always
|
||||||
stop searching after it sees a `NUL` byte. Namely, in this mode, ripgrep
|
stop searching after it sees a `NUL` byte. Namely, in this mode, ripgrep
|
||||||
will continue searching a file that is known to be binary until the first
|
will continue searching a file that is known to be binary until the first
|
||||||
|
105
README.md
105
README.md
@@ -8,11 +8,12 @@ available for [every release](https://github.com/BurntSushi/ripgrep/releases).
|
|||||||
ripgrep is similar to other popular search tools like The Silver Searcher, ack
|
ripgrep is similar to other popular search tools like The Silver Searcher, ack
|
||||||
and grep.
|
and grep.
|
||||||
|
|
||||||
[](https://github.com/BurntSushi/ripgrep/actions)
|
[](https://travis-ci.org/BurntSushi/ripgrep)
|
||||||
|
[](https://ci.appveyor.com/project/BurntSushi/ripgrep)
|
||||||
[](https://crates.io/crates/ripgrep)
|
[](https://crates.io/crates/ripgrep)
|
||||||
[](https://repology.org/project/ripgrep/badges)
|
[](https://repology.org/project/ripgrep/badges)
|
||||||
|
|
||||||
Dual-licensed under MIT or the [UNLICENSE](https://unlicense.org).
|
Dual-licensed under MIT or the [UNLICENSE](http://unlicense.org).
|
||||||
|
|
||||||
|
|
||||||
### CHANGELOG
|
### CHANGELOG
|
||||||
@@ -33,55 +34,56 @@ Please see the [CHANGELOG](CHANGELOG.md) for a release history.
|
|||||||
|
|
||||||
### Screenshot of search results
|
### Screenshot of search results
|
||||||
|
|
||||||
[](https://burntsushi.net/stuff/ripgrep1.png)
|
[](http://burntsushi.net/stuff/ripgrep1.png)
|
||||||
|
|
||||||
|
|
||||||
### Quick examples comparing tools
|
### Quick examples comparing tools
|
||||||
|
|
||||||
This example searches the entire
|
This example searches the entire Linux kernel source tree (after running
|
||||||
[Linux kernel source tree](https://github.com/BurntSushi/linux)
|
`make defconfig && make -j8`) for `[A-Z]+_SUSPEND`, where all matches must be
|
||||||
(after running `make defconfig && make -j8`) for `[A-Z]+_SUSPEND`, where
|
words. Timings were collected on a system with an Intel i7-6900K 3.2 GHz, and
|
||||||
all matches must be words. Timings were collected on a system with an Intel
|
ripgrep was compiled with SIMD enabled.
|
||||||
i7-6900K 3.2 GHz.
|
|
||||||
|
|
||||||
Please remember that a single benchmark is never enough! See my
|
Please remember that a single benchmark is never enough! See my
|
||||||
[blog post on ripgrep](https://blog.burntsushi.net/ripgrep/)
|
[blog post on ripgrep](http://blog.burntsushi.net/ripgrep/)
|
||||||
for a very detailed comparison with more benchmarks and analysis.
|
for a very detailed comparison with more benchmarks and analysis.
|
||||||
|
|
||||||
| Tool | Command | Line count | Time |
|
| Tool | Command | Line count | Time |
|
||||||
| ---- | ------- | ---------- | ---- |
|
| ---- | ------- | ---------- | ---- |
|
||||||
| ripgrep (Unicode) | `rg -n -w '[A-Z]+_SUSPEND'` | 452 | **0.136s** |
|
| ripgrep (Unicode) | `rg -n -w '[A-Z]+_SUSPEND'` | 450 | **0.106s** |
|
||||||
| [git grep](https://www.kernel.org/pub/software/scm/git/docs/git-grep.html) | `git grep -P -n -w '[A-Z]+_SUSPEND'` | 452 | 0.348s |
|
| [git grep](https://www.kernel.org/pub/software/scm/git/docs/git-grep.html) | `LC_ALL=C git grep -E -n -w '[A-Z]+_SUSPEND'` | 450 | 0.553s |
|
||||||
| [ugrep (Unicode)](https://github.com/Genivia/ugrep) | `ugrep -r --ignore-files --no-hidden -I -w '[A-Z]+_SUSPEND'` | 452 | 0.506s |
|
| [The Silver Searcher](https://github.com/ggreer/the_silver_searcher) | `ag -w '[A-Z]+_SUSPEND'` | 450 | 0.589s |
|
||||||
| [git grep](https://www.kernel.org/pub/software/scm/git/docs/git-grep.html) | `LC_ALL=C git grep -E -n -w '[A-Z]+_SUSPEND'` | 452 | 1.150s |
|
| [git grep (Unicode)](https://www.kernel.org/pub/software/scm/git/docs/git-grep.html) | `LC_ALL=en_US.UTF-8 git grep -E -n -w '[A-Z]+_SUSPEND'` | 450 | 2.266s |
|
||||||
| [The Silver Searcher](https://github.com/ggreer/the_silver_searcher) | `ag -w '[A-Z]+_SUSPEND'` | 452 | 0.654s |
|
| [sift](https://github.com/svent/sift) | `sift --git -n -w '[A-Z]+_SUSPEND'` | 450 | 3.505s |
|
||||||
| [ack](https://github.com/beyondgrep/ack3) | `ack -w '[A-Z]+_SUSPEND'` | 452 | 4.054s |
|
| [ack](https://github.com/petdance/ack2) | `ack -w '[A-Z]+_SUSPEND'` | 1878 | 6.823s |
|
||||||
| [git grep (Unicode)](https://www.kernel.org/pub/software/scm/git/docs/git-grep.html) | `LC_ALL=en_US.UTF-8 git grep -E -n -w '[A-Z]+_SUSPEND'` | 452 | 4.205s |
|
| [The Platinum Searcher](https://github.com/monochromegane/the_platinum_searcher) | `pt -w -e '[A-Z]+_SUSPEND'` | 450 | 14.208s |
|
||||||
|
|
||||||
Here's another benchmark on the same corpus as above that disregards gitignore
|
(Yes, `ack` [has](https://github.com/petdance/ack2/issues/445) a
|
||||||
files and searches with a whitelist instead. The corpus is the same as in the
|
[bug](https://github.com/petdance/ack2/issues/14).)
|
||||||
previous benchmark, and the flags passed to each command ensure that they are
|
|
||||||
doing equivalent work:
|
Here's another benchmark that disregards gitignore files and searches with a
|
||||||
|
whitelist instead. The corpus is the same as in the previous benchmark, and the
|
||||||
|
flags passed to each command ensure that they are doing equivalent work:
|
||||||
|
|
||||||
| Tool | Command | Line count | Time |
|
| Tool | Command | Line count | Time |
|
||||||
| ---- | ------- | ---------- | ---- |
|
| ---- | ------- | ---------- | ---- |
|
||||||
| ripgrep | `rg -uuu -tc -n -w '[A-Z]+_SUSPEND'` | 388 | **0.096s** |
|
| ripgrep | `rg -L -u -tc -n -w '[A-Z]+_SUSPEND'` | 404 | **0.079s** |
|
||||||
| [ugrep](https://github.com/Genivia/ugrep) | `ugrep -r -n --include='*.c' --include='*.h' -w '[A-Z]+_SUSPEND'` | 388 | 0.493s |
|
| [ucg](https://github.com/gvansickle/ucg) | `ucg --type=cc -w '[A-Z]+_SUSPEND'` | 390 | 0.163s |
|
||||||
| [GNU grep](https://www.gnu.org/software/grep/) | `egrep -r -n --include='*.c' --include='*.h' -w '[A-Z]+_SUSPEND'` | 388 | 0.806s |
|
| [GNU grep](https://www.gnu.org/software/grep/) | `egrep -R -n --include='*.c' --include='*.h' -w '[A-Z]+_SUSPEND'` | 404 | 0.611s |
|
||||||
|
|
||||||
And finally, a straight-up comparison between ripgrep, ugrep and GNU grep on a
|
(`ucg` [has slightly different behavior in the presence of symbolic links](https://github.com/gvansickle/ucg/issues/106).)
|
||||||
single large file cached in memory
|
|
||||||
(~13GB, [`OpenSubtitles.raw.en.gz`](http://opus.nlpl.eu/download.php?f=OpenSubtitles/v2018/mono/OpenSubtitles.raw.en.gz)):
|
And finally, a straight-up comparison between ripgrep and GNU grep on a single
|
||||||
|
large file (~9.3GB,
|
||||||
|
[`OpenSubtitles2016.raw.en.gz`](http://opus.lingfil.uu.se/OpenSubtitles2016/mono/OpenSubtitles2016.raw.en.gz)):
|
||||||
|
|
||||||
| Tool | Command | Line count | Time |
|
| Tool | Command | Line count | Time |
|
||||||
| ---- | ------- | ---------- | ---- |
|
| ---- | ------- | ---------- | ---- |
|
||||||
| ripgrep | `rg -w 'Sherlock [A-Z]\w+'` | 7882 | **2.769s** |
|
| ripgrep | `rg -w 'Sherlock [A-Z]\w+'` | 5268 | **2.108s** |
|
||||||
| [ugrep](https://github.com/Genivia/ugrep) | `ugrep -w 'Sherlock [A-Z]\w+'` | 7882 | 6.802s |
|
| [GNU grep](https://www.gnu.org/software/grep/) | `LC_ALL=C egrep -w 'Sherlock [A-Z]\w+'` | 5268 | 7.014s |
|
||||||
| [GNU grep](https://www.gnu.org/software/grep/) | `LC_ALL=en_US.UTF-8 egrep -w 'Sherlock [A-Z]\w+'` | 7882 | 9.027s |
|
|
||||||
|
|
||||||
In the above benchmark, passing the `-n` flag (for showing line numbers)
|
In the above benchmark, passing the `-n` flag (for showing line numbers)
|
||||||
increases the times to `3.423s` for ripgrep and `13.031s` for GNU grep. ugrep
|
increases the times to `2.640s` for ripgrep and `10.277s` for GNU grep.
|
||||||
times are unaffected by the presence or absence of `-n`.
|
|
||||||
|
|
||||||
|
|
||||||
### Why should I use ripgrep?
|
### Why should I use ripgrep?
|
||||||
@@ -108,8 +110,7 @@ times are unaffected by the presence or absence of `-n`.
|
|||||||
Among other things, this makes it possible to use look-around and
|
Among other things, this makes it possible to use look-around and
|
||||||
backreferences in your patterns, which are not supported in ripgrep's default
|
backreferences in your patterns, which are not supported in ripgrep's default
|
||||||
regex engine. PCRE2 support can be enabled with `-P/--pcre2` (use PCRE2
|
regex engine. PCRE2 support can be enabled with `-P/--pcre2` (use PCRE2
|
||||||
always) or `--auto-hybrid-regex` (use PCRE2 only if needed). An alternative
|
always) or `--auto-hybrid-regex` (use PCRE2 only if needed).
|
||||||
syntax is provided via the `--engine (default|pcre2|auto-hybrid)` option.
|
|
||||||
* ripgrep supports searching files in text encodings other than UTF-8, such
|
* ripgrep supports searching files in text encodings other than UTF-8, such
|
||||||
as UTF-16, latin-1, GBK, EUC-JP, Shift_JIS and more. (Some support for
|
as UTF-16, latin-1, GBK, EUC-JP, Shift_JIS and more. (Some support for
|
||||||
automatically detecting UTF-16 is provided. Other text encodings must be
|
automatically detecting UTF-16 is provided. Other text encodings must be
|
||||||
@@ -149,12 +150,12 @@ or more of the following:
|
|||||||
### Is it really faster than everything else?
|
### Is it really faster than everything else?
|
||||||
|
|
||||||
Generally, yes. A large number of benchmarks with detailed analysis for each is
|
Generally, yes. A large number of benchmarks with detailed analysis for each is
|
||||||
[available on my blog](https://blog.burntsushi.net/ripgrep/).
|
[available on my blog](http://blog.burntsushi.net/ripgrep/).
|
||||||
|
|
||||||
Summarizing, ripgrep is fast because:
|
Summarizing, ripgrep is fast because:
|
||||||
|
|
||||||
* It is built on top of
|
* It is built on top of
|
||||||
[Rust's regex engine](https://github.com/rust-lang/regex).
|
[Rust's regex engine](https://github.com/rust-lang-nursery/regex).
|
||||||
Rust's regex engine uses finite automata, SIMD and aggressive literal
|
Rust's regex engine uses finite automata, SIMD and aggressive literal
|
||||||
optimizations to make searching very fast. (PCRE2 support can be opted into
|
optimizations to make searching very fast. (PCRE2 support can be opted into
|
||||||
with the `-P/--pcre2` flag.)
|
with the `-P/--pcre2` flag.)
|
||||||
@@ -201,8 +202,9 @@ prefer MSVC over GNU, but you'll need to have the [Microsoft VC++ 2015
|
|||||||
redistributable](https://www.microsoft.com/en-us/download/details.aspx?id=48145)
|
redistributable](https://www.microsoft.com/en-us/download/details.aspx?id=48145)
|
||||||
installed.
|
installed.
|
||||||
|
|
||||||
If you're a **macOS Homebrew** or a **Linuxbrew** user, then you can install
|
If you're a **macOS Homebrew** or a **Linuxbrew** user,
|
||||||
ripgrep from homebrew-core:
|
then you can install ripgrep either
|
||||||
|
from homebrew-core, (compiled with rust stable, no SIMD):
|
||||||
|
|
||||||
```
|
```
|
||||||
$ brew install ripgrep
|
$ brew install ripgrep
|
||||||
@@ -249,14 +251,23 @@ repositories.
|
|||||||
$ sudo dnf install ripgrep
|
$ sudo dnf install ripgrep
|
||||||
```
|
```
|
||||||
|
|
||||||
If you're an **openSUSE** user, ripgrep is included in **openSUSE Tumbleweed**
|
If you're an **openSUSE Leap 15.0** user, you can install ripgrep from the
|
||||||
and **openSUSE Leap** since 15.1.
|
[utilities repo](https://build.opensuse.org/package/show/utilities/ripgrep):
|
||||||
|
|
||||||
|
```
|
||||||
|
$ sudo zypper ar https://download.opensuse.org/repositories/utilities/openSUSE_Leap_15.0/utilities.repo
|
||||||
|
$ sudo zypper install ripgrep
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
If you're an **openSUSE Tumbleweed** user, you can install ripgrep from the
|
||||||
|
[official repo](http://software.opensuse.org/package/ripgrep):
|
||||||
|
|
||||||
```
|
```
|
||||||
$ sudo zypper install ripgrep
|
$ sudo zypper install ripgrep
|
||||||
```
|
```
|
||||||
|
|
||||||
If you're a **RHEL/CentOS 7/8** user, you can install ripgrep from
|
If you're a **RHEL/CentOS 7** user, you can install ripgrep from
|
||||||
[copr](https://copr.fedorainfracloud.org/coprs/carlwgeorge/ripgrep/):
|
[copr](https://copr.fedorainfracloud.org/coprs/carlwgeorge/ripgrep/):
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -321,20 +332,6 @@ If you're a **NetBSD** user, then you can install ripgrep from
|
|||||||
# pkgin install ripgrep
|
# pkgin install ripgrep
|
||||||
```
|
```
|
||||||
|
|
||||||
If you're a **Haiku x86_64** user, then you can install ripgrep from the
|
|
||||||
[official ports](https://github.com/haikuports/haikuports/tree/master/sys-apps/ripgrep):
|
|
||||||
|
|
||||||
```
|
|
||||||
$ pkgman install ripgrep
|
|
||||||
```
|
|
||||||
|
|
||||||
If you're a **Haiku x86_gcc2** user, then you can install ripgrep from the
|
|
||||||
same port as Haiku x86_64 using the x86 secondary architecture build:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ pkgman install ripgrep_x86
|
|
||||||
```
|
|
||||||
|
|
||||||
If you're a **Rust programmer**, ripgrep can be installed with `cargo`.
|
If you're a **Rust programmer**, ripgrep can be installed with `cargo`.
|
||||||
|
|
||||||
* Note that the minimum supported version of Rust for ripgrep is **1.34.0**,
|
* Note that the minimum supported version of Rust for ripgrep is **1.34.0**,
|
||||||
|
81
appveyor.yml
Normal file
81
appveyor.yml
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
cache:
|
||||||
|
- c:\cargo\registry
|
||||||
|
- c:\cargo\git
|
||||||
|
|
||||||
|
init:
|
||||||
|
- mkdir c:\cargo
|
||||||
|
- mkdir c:\rustup
|
||||||
|
- SET PATH=c:\cargo\bin;%PATH%
|
||||||
|
|
||||||
|
clone_folder: c:\projects\ripgrep
|
||||||
|
|
||||||
|
environment:
|
||||||
|
CARGO_HOME: "c:\\cargo"
|
||||||
|
RUSTUP_HOME: "c:\\rustup"
|
||||||
|
CARGO_TARGET_DIR: "c:\\projects\\ripgrep\\target"
|
||||||
|
global:
|
||||||
|
PROJECT_NAME: ripgrep
|
||||||
|
RUST_BACKTRACE: full
|
||||||
|
matrix:
|
||||||
|
- TARGET: x86_64-pc-windows-gnu
|
||||||
|
CHANNEL: stable
|
||||||
|
BITS: 64
|
||||||
|
MSYS2: 1
|
||||||
|
- TARGET: x86_64-pc-windows-msvc
|
||||||
|
CHANNEL: stable
|
||||||
|
BITS: 64
|
||||||
|
- TARGET: i686-pc-windows-gnu
|
||||||
|
CHANNEL: stable
|
||||||
|
BITS: 32
|
||||||
|
MSYS2: 1
|
||||||
|
- TARGET: i686-pc-windows-msvc
|
||||||
|
CHANNEL: stable
|
||||||
|
BITS: 32
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
fast_finish: true
|
||||||
|
|
||||||
|
# Install Rust and Cargo
|
||||||
|
# (Based on from https://github.com/rust-lang/libc/blob/master/appveyor.yml)
|
||||||
|
install:
|
||||||
|
- curl -sSf -o rustup-init.exe https://win.rustup.rs/
|
||||||
|
- rustup-init.exe -y --default-host %TARGET%
|
||||||
|
- set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
|
||||||
|
- if defined MSYS2 set PATH=C:\msys64\mingw%BITS%\bin;%PATH%
|
||||||
|
- rustc -V
|
||||||
|
- cargo -V
|
||||||
|
|
||||||
|
# Hack to work around a harmless warning in Appveyor builds?
|
||||||
|
build: false
|
||||||
|
|
||||||
|
# Equivalent to Travis' `script` phase
|
||||||
|
test_script:
|
||||||
|
- cargo test --verbose --all --features pcre2
|
||||||
|
|
||||||
|
before_deploy:
|
||||||
|
# Generate artifacts for release
|
||||||
|
- cargo build --release --features pcre2
|
||||||
|
- mkdir staging
|
||||||
|
- copy target\release\rg.exe staging
|
||||||
|
- ps: copy target\release\build\ripgrep-*\out\_rg.ps1 staging
|
||||||
|
- cd staging
|
||||||
|
# release zipfile will look like 'ripgrep-1.2.3-x86_64-pc-windows-msvc'
|
||||||
|
- 7z a ../%PROJECT_NAME%-%APPVEYOR_REPO_TAG_NAME%-%TARGET%.zip *
|
||||||
|
- appveyor PushArtifact ../%PROJECT_NAME%-%APPVEYOR_REPO_TAG_NAME%-%TARGET%.zip
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
description: 'Automatically deployed release'
|
||||||
|
# All the zipped artifacts will be deployed
|
||||||
|
artifact: /.*\.zip/
|
||||||
|
auth_token:
|
||||||
|
secure: vv4vBCEosGlyQjaEC1+kraP2P6O4CQSa+Tw50oHWFTGcmuXxaWS0/yEXbxsIRLpw
|
||||||
|
provider: GitHub
|
||||||
|
# deploy when a new tag is pushed and only on the stable channel
|
||||||
|
on:
|
||||||
|
CHANNEL: stable
|
||||||
|
appveyor_repo_tag: true
|
||||||
|
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- /^\d+\.\d+\.\d+$/
|
||||||
|
- master
|
22
build.rs
22
build.rs
@@ -9,7 +9,7 @@ use clap::Shell;
|
|||||||
use app::{RGArg, RGArgKind};
|
use app::{RGArg, RGArgKind};
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[path = "crates/core/app.rs"]
|
#[path = "src/app.rs"]
|
||||||
mod app;
|
mod app;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@@ -21,8 +21,7 @@ fn main() {
|
|||||||
eprintln!(
|
eprintln!(
|
||||||
"OUT_DIR environment variable not defined. \
|
"OUT_DIR environment variable not defined. \
|
||||||
Please file a bug: \
|
Please file a bug: \
|
||||||
https://github.com/BurntSushi/ripgrep/issues/new"
|
https://github.com/BurntSushi/ripgrep/issues/new");
|
||||||
);
|
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -86,15 +85,13 @@ fn generate_man_page<P: AsRef<Path>>(outdir: P) -> io::Result<()> {
|
|||||||
|
|
||||||
let githash = git_revision_hash();
|
let githash = git_revision_hash();
|
||||||
let githash = githash.as_ref().map(|x| &**x);
|
let githash = githash.as_ref().map(|x| &**x);
|
||||||
tpl = tpl.replace("{VERSION}", &app::long_version(githash, false));
|
tpl = tpl.replace("{VERSION}", &app::long_version(githash));
|
||||||
|
|
||||||
File::create(&txt_path)?.write_all(tpl.as_bytes())?;
|
File::create(&txt_path)?.write_all(tpl.as_bytes())?;
|
||||||
let result = process::Command::new("a2x")
|
let result = process::Command::new("a2x")
|
||||||
.arg("--no-xmllint")
|
.arg("--no-xmllint")
|
||||||
.arg("--doctype")
|
.arg("--doctype").arg("manpage")
|
||||||
.arg("manpage")
|
.arg("--format").arg("manpage")
|
||||||
.arg("--format")
|
|
||||||
.arg("manpage")
|
|
||||||
.arg(&txt_path)
|
.arg(&txt_path)
|
||||||
.spawn()?
|
.spawn()?
|
||||||
.wait()?;
|
.wait()?;
|
||||||
@@ -117,7 +114,7 @@ fn formatted_options() -> io::Result<String> {
|
|||||||
// ripgrep only has two positional arguments, and probably will only
|
// ripgrep only has two positional arguments, and probably will only
|
||||||
// ever have two positional arguments, so we just hardcode them into
|
// ever have two positional arguments, so we just hardcode them into
|
||||||
// the template.
|
// the template.
|
||||||
if let app::RGArgKind::Positional { .. } = arg.kind {
|
if let app::RGArgKind::Positional{..} = arg.kind {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
formatted.push(formatted_arg(&arg)?);
|
formatted.push(formatted_arg(&arg)?);
|
||||||
@@ -127,9 +124,7 @@ fn formatted_options() -> io::Result<String> {
|
|||||||
|
|
||||||
fn formatted_arg(arg: &RGArg) -> io::Result<String> {
|
fn formatted_arg(arg: &RGArg) -> io::Result<String> {
|
||||||
match arg.kind {
|
match arg.kind {
|
||||||
RGArgKind::Positional { .. } => {
|
RGArgKind::Positional{..} => panic!("unexpected positional argument"),
|
||||||
panic!("unexpected positional argument")
|
|
||||||
}
|
|
||||||
RGArgKind::Switch { long, short, multiple } => {
|
RGArgKind::Switch { long, short, multiple } => {
|
||||||
let mut out = vec![];
|
let mut out = vec![];
|
||||||
|
|
||||||
@@ -168,8 +163,7 @@ fn formatted_arg(arg: &RGArg) -> io::Result<String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn formatted_doc_txt(arg: &RGArg) -> io::Result<String> {
|
fn formatted_doc_txt(arg: &RGArg) -> io::Result<String> {
|
||||||
let paragraphs: Vec<String> = arg
|
let paragraphs: Vec<String> = arg.doc_long
|
||||||
.doc_long
|
|
||||||
.replace("{", "{")
|
.replace("{", "{")
|
||||||
.replace("}", r"}")
|
.replace("}", r"}")
|
||||||
.split("\n\n")
|
.split("\n\n")
|
||||||
|
62
ci/before_deploy.sh
Executable file
62
ci/before_deploy.sh
Executable file
@@ -0,0 +1,62 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# package the build artifacts
|
||||||
|
|
||||||
|
set -ex
|
||||||
|
|
||||||
|
. "$(dirname $0)/utils.sh"
|
||||||
|
|
||||||
|
# Generate artifacts for release
|
||||||
|
mk_artifacts() {
|
||||||
|
CARGO="$(builder)"
|
||||||
|
if is_arm; then
|
||||||
|
"$CARGO" build --target "$TARGET" --release
|
||||||
|
else
|
||||||
|
# Technically, MUSL builds will force PCRE2 to get statically compiled,
|
||||||
|
# but we also want PCRE2 statically build for macOS binaries.
|
||||||
|
PCRE2_SYS_STATIC=1 "$CARGO" build --target "$TARGET" --release --features 'pcre2'
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
mk_tarball() {
|
||||||
|
# When cross-compiling, use the right `strip` tool on the binary.
|
||||||
|
local gcc_prefix="$(gcc_prefix)"
|
||||||
|
# Create a temporary dir that contains our staging area.
|
||||||
|
# $tmpdir/$name is what eventually ends up as the deployed archive.
|
||||||
|
local tmpdir="$(mktemp -d)"
|
||||||
|
local name="${PROJECT_NAME}-${TRAVIS_TAG}-${TARGET}"
|
||||||
|
local staging="$tmpdir/$name"
|
||||||
|
mkdir -p "$staging"/{complete,doc}
|
||||||
|
# The deployment directory is where the final archive will reside.
|
||||||
|
# This path is known by the .travis.yml configuration.
|
||||||
|
local out_dir="$(pwd)/deployment"
|
||||||
|
mkdir -p "$out_dir"
|
||||||
|
# Find the correct (most recent) Cargo "out" directory. The out directory
|
||||||
|
# contains shell completion files and the man page.
|
||||||
|
local cargo_out_dir="$(cargo_out_dir "target/$TARGET")"
|
||||||
|
|
||||||
|
# Copy the ripgrep binary and strip it.
|
||||||
|
cp "target/$TARGET/release/rg" "$staging/rg"
|
||||||
|
"${gcc_prefix}strip" "$staging/rg"
|
||||||
|
# Copy the licenses and README.
|
||||||
|
cp {README.md,UNLICENSE,COPYING,LICENSE-MIT} "$staging/"
|
||||||
|
# Copy documentation and man page.
|
||||||
|
cp {CHANGELOG.md,FAQ.md,GUIDE.md} "$staging/doc/"
|
||||||
|
if command -V a2x 2>&1 > /dev/null; then
|
||||||
|
# The man page should only exist if we have asciidoc installed.
|
||||||
|
cp "$cargo_out_dir/rg.1" "$staging/doc/"
|
||||||
|
fi
|
||||||
|
# Copy shell completion files.
|
||||||
|
cp "$cargo_out_dir"/{rg.bash,rg.fish,_rg.ps1} "$staging/complete/"
|
||||||
|
cp complete/_rg "$staging/complete/"
|
||||||
|
|
||||||
|
(cd "$tmpdir" && tar czf "$out_dir/$name.tar.gz" "$name")
|
||||||
|
rm -rf "$tmpdir"
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
mk_artifacts
|
||||||
|
mk_tarball
|
||||||
|
}
|
||||||
|
|
||||||
|
main
|
@@ -1,7 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
D="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
|
|
||||||
|
|
||||||
# This script builds a binary dpkg for Debian based distros. It does not
|
# This script builds a binary dpkg for Debian based distros. It does not
|
||||||
# currently run in CI, and is instead run manually and the resulting dpkg is
|
# currently run in CI, and is instead run manually and the resulting dpkg is
|
||||||
@@ -24,13 +23,20 @@ fi
|
|||||||
# the deb, which knows where to look.
|
# the deb, which knows where to look.
|
||||||
|
|
||||||
DEPLOY_DIR=deployment/deb
|
DEPLOY_DIR=deployment/deb
|
||||||
OUT_DIR="$("$D"/cargo-out-dir target/debug/)"
|
|
||||||
mkdir -p "$DEPLOY_DIR"
|
mkdir -p "$DEPLOY_DIR"
|
||||||
cargo build
|
cargo build
|
||||||
|
|
||||||
# Copy man page and shell completions.
|
# Find and copy man page.
|
||||||
cp "$OUT_DIR"/{rg.1,rg.bash,rg.fish} "$DEPLOY_DIR/"
|
manpage="$(find ./target/debug -name rg.1 -print0 | xargs -0 ls -t | head -n1)"
|
||||||
cp complete/_rg "$DEPLOY_DIR/"
|
cp "$manpage" "$DEPLOY_DIR/"
|
||||||
|
|
||||||
|
# Do the same for shell completions.
|
||||||
|
compbash="$(find ./target/debug -name rg.bash -print0 | xargs -0 ls -t | head -n1)"
|
||||||
|
cp "$compbash" "$DEPLOY_DIR/"
|
||||||
|
compfish="$(find ./target/debug -name rg.fish -print0 | xargs -0 ls -t | head -n1)"
|
||||||
|
cp "$compfish" "$DEPLOY_DIR/"
|
||||||
|
compzsh="complete/_rg"
|
||||||
|
cp "$compzsh" "$DEPLOY_DIR/"
|
||||||
|
|
||||||
# Since we're distributing the dpkg, we don't know whether the user will have
|
# Since we're distributing the dpkg, we don't know whether the user will have
|
||||||
# PCRE2 installed, so just do a static build.
|
# PCRE2 installed, so just do a static build.
|
@@ -1,19 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Finds Cargo's `OUT_DIR` directory from the most recent build.
|
|
||||||
#
|
|
||||||
# This requires one parameter corresponding to the target directory
|
|
||||||
# to search for the build output.
|
|
||||||
|
|
||||||
if [ $# != 1 ]; then
|
|
||||||
echo "Usage: $(basename "$0") <target-dir>" >&2
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
|
|
||||||
# This works by finding the most recent stamp file, which is produced by
|
|
||||||
# every ripgrep build.
|
|
||||||
target_dir="$1"
|
|
||||||
find "$target_dir" -name ripgrep-stamp -print0 \
|
|
||||||
| xargs -0 ls -t \
|
|
||||||
| head -n1 \
|
|
||||||
| xargs dirname
|
|
@@ -1,24 +0,0 @@
|
|||||||
These are Docker images used for cross compilation in CI builds (or locally)
|
|
||||||
via the [Cross](https://github.com/rust-embedded/cross) tool.
|
|
||||||
|
|
||||||
The Cross tool actually provides its own Docker images, and all Docker images
|
|
||||||
in this directory are derived from one of them. We provide our own in order
|
|
||||||
to customize the environment. For example, we need to install some things like
|
|
||||||
`asciidoc` in order to generate man pages. We also install compression tools
|
|
||||||
like `xz` so that tests for the `-z/--search-zip` flag are run.
|
|
||||||
|
|
||||||
If you make a change to a Docker image, then you can re-build it. `cd` into the
|
|
||||||
directory containing the `Dockerfile` and run:
|
|
||||||
|
|
||||||
$ cd x86_64-unknown-linux-musl
|
|
||||||
$ ./build
|
|
||||||
|
|
||||||
At this point, subsequent uses of `cross` will now use your built image since
|
|
||||||
Docker prefers local images over remote images. In order to make these changes
|
|
||||||
stick, they need to be pushed to Docker Hub:
|
|
||||||
|
|
||||||
$ docker push burntsushi/cross:x86_64-unknown-linux-musl
|
|
||||||
|
|
||||||
Of course, only I (BurntSushi) can push to that location. To make `cross` use
|
|
||||||
a different location, then edit `Cross.toml` in the root of this repo to use
|
|
||||||
a different image name for the desired target.
|
|
@@ -1,4 +0,0 @@
|
|||||||
FROM rustembedded/cross:arm-unknown-linux-gnueabihf
|
|
||||||
|
|
||||||
COPY stage/ubuntu-install-packages /
|
|
||||||
RUN /ubuntu-install-packages
|
|
@@ -1,5 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
mkdir -p stage
|
|
||||||
cp ../../ubuntu-install-packages ./stage/
|
|
||||||
docker build -t burntsushi/cross:arm-unknown-linux-gnueabihf .
|
|
@@ -1,4 +0,0 @@
|
|||||||
FROM rustembedded/cross:i686-unknown-linux-gnu
|
|
||||||
|
|
||||||
COPY stage/ubuntu-install-packages /
|
|
||||||
RUN /ubuntu-install-packages
|
|
@@ -1,5 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
mkdir -p stage
|
|
||||||
cp ../../ubuntu-install-packages ./stage/
|
|
||||||
docker build -t burntsushi/cross:i686-unknown-linux-gnu .
|
|
@@ -1,4 +0,0 @@
|
|||||||
FROM rustembedded/cross:mips64-unknown-linux-gnuabi64
|
|
||||||
|
|
||||||
COPY stage/ubuntu-install-packages /
|
|
||||||
RUN /ubuntu-install-packages
|
|
@@ -1,5 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
mkdir -p stage
|
|
||||||
cp ../../ubuntu-install-packages ./stage/
|
|
||||||
docker build -t burntsushi/cross:mips64-unknown-linux-gnuabi64 .
|
|
@@ -1,4 +1,5 @@
|
|||||||
FROM rustembedded/cross:x86_64-unknown-linux-musl
|
FROM japaric/x86_64-unknown-linux-musl:v0.1.14
|
||||||
|
|
||||||
COPY stage/ubuntu-install-packages /
|
RUN apt-get update \
|
||||||
RUN /ubuntu-install-packages
|
&& apt-get install -y --no-install-recommends \
|
||||||
|
libxslt1-dev asciidoc docbook-xsl xsltproc libxml2-utils
|
||||||
|
@@ -1,5 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
mkdir -p stage
|
|
||||||
cp ../../ubuntu-install-packages ./stage/
|
|
||||||
docker build -t burntsushi/cross:x86_64-unknown-linux-musl .
|
|
61
ci/install.sh
Executable file
61
ci/install.sh
Executable file
@@ -0,0 +1,61 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# install stuff needed for the `script` phase
|
||||||
|
|
||||||
|
# Where rustup gets installed.
|
||||||
|
export PATH="$PATH:$HOME/.cargo/bin"
|
||||||
|
|
||||||
|
set -ex
|
||||||
|
|
||||||
|
. "$(dirname $0)/utils.sh"
|
||||||
|
|
||||||
|
install_rustup() {
|
||||||
|
curl https://sh.rustup.rs -sSf \
|
||||||
|
| sh -s -- -y --default-toolchain="$TRAVIS_RUST_VERSION"
|
||||||
|
rustc -V
|
||||||
|
cargo -V
|
||||||
|
}
|
||||||
|
|
||||||
|
install_targets() {
|
||||||
|
if [ $(host) != "$TARGET" ]; then
|
||||||
|
rustup target add $TARGET
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
install_osx_dependencies() {
|
||||||
|
if ! is_osx; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
brew install asciidoc docbook-xsl
|
||||||
|
}
|
||||||
|
|
||||||
|
configure_cargo() {
|
||||||
|
local prefix=$(gcc_prefix)
|
||||||
|
if [ -n "${prefix}" ]; then
|
||||||
|
local gcc_suffix=
|
||||||
|
if [ -n "$GCC_VERSION" ]; then
|
||||||
|
gcc_suffix="-$GCC_VERSION"
|
||||||
|
fi
|
||||||
|
local gcc="${prefix}gcc${gcc_suffix}"
|
||||||
|
|
||||||
|
# information about the cross compiler
|
||||||
|
"${gcc}" -v
|
||||||
|
|
||||||
|
# tell cargo which linker to use for cross compilation
|
||||||
|
mkdir -p .cargo
|
||||||
|
cat >>.cargo/config <<EOF
|
||||||
|
[target.$TARGET]
|
||||||
|
linker = "${gcc}"
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
install_osx_dependencies
|
||||||
|
install_rustup
|
||||||
|
install_targets
|
||||||
|
configure_cargo
|
||||||
|
}
|
||||||
|
|
||||||
|
main
|
@@ -1,3 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
brew install asciidoc docbook-xsl
|
|
52
ci/script.sh
Executable file
52
ci/script.sh
Executable file
@@ -0,0 +1,52 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# build, test and generate docs in this phase
|
||||||
|
|
||||||
|
set -ex
|
||||||
|
|
||||||
|
. "$(dirname $0)/utils.sh"
|
||||||
|
|
||||||
|
main() {
|
||||||
|
CARGO="$(builder)"
|
||||||
|
|
||||||
|
# Test a normal debug build.
|
||||||
|
if is_arm; then
|
||||||
|
"$CARGO" build --target "$TARGET" --verbose
|
||||||
|
else
|
||||||
|
"$CARGO" build --target "$TARGET" --verbose --all --features 'pcre2'
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Show the output of the most recent build.rs stderr.
|
||||||
|
set +x
|
||||||
|
stderr="$(find "target/$TARGET/debug" -name stderr -print0 | xargs -0 ls -t | head -n1)"
|
||||||
|
if [ -s "$stderr" ]; then
|
||||||
|
echo "===== $stderr ====="
|
||||||
|
cat "$stderr"
|
||||||
|
echo "====="
|
||||||
|
fi
|
||||||
|
set -x
|
||||||
|
|
||||||
|
# sanity check the file type
|
||||||
|
file target/"$TARGET"/debug/rg
|
||||||
|
|
||||||
|
# Check that we've generated man page and other shell completions.
|
||||||
|
outdir="$(cargo_out_dir "target/$TARGET/debug")"
|
||||||
|
file "$outdir/rg.bash"
|
||||||
|
file "$outdir/rg.fish"
|
||||||
|
file "$outdir/_rg.ps1"
|
||||||
|
file "$outdir/rg.1"
|
||||||
|
|
||||||
|
# Apparently tests don't work on arm, so just bail now. I guess we provide
|
||||||
|
# ARM releases on a best effort basis?
|
||||||
|
if is_arm; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Test that zsh completions are in sync with ripgrep's actual args.
|
||||||
|
"$(dirname "${0}")/test_complete.sh"
|
||||||
|
|
||||||
|
# Run tests for ripgrep and all sub-crates.
|
||||||
|
"$CARGO" test --target "$TARGET" --verbose --all --features 'pcre2'
|
||||||
|
}
|
||||||
|
|
||||||
|
main
|
@@ -18,7 +18,7 @@ get_comp_args() {
|
|||||||
|
|
||||||
main() {
|
main() {
|
||||||
local diff
|
local diff
|
||||||
local rg="${0:a:h}/../${TARGET_DIR:-target}/release/rg"
|
local rg="${0:a:h}/../target/${TARGET:-}/release/rg"
|
||||||
local _rg="${0:a:h}/../complete/_rg"
|
local _rg="${0:a:h}/../complete/_rg"
|
||||||
local -a help_args comp_args
|
local -a help_args comp_args
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ main() {
|
|||||||
# Occasionally we may have to handle some manually, however
|
# Occasionally we may have to handle some manually, however
|
||||||
help_args=( ${(f)"$(
|
help_args=( ${(f)"$(
|
||||||
$rg --help |
|
$rg --help |
|
||||||
$rg -i -- '^\s+--?[a-z0-9]|--[a-z]' |
|
$rg -i -- '^\s+--?[a-z0-9]|--[imnp]' |
|
||||||
$rg -ior '$1' -- $'[\t /\"\'`.,](-[a-z0-9]|--[a-z0-9-]+)\\b' |
|
$rg -ior '$1' -- $'[\t /\"\'`.,](-[a-z0-9]|--[a-z0-9-]+)\\b' |
|
||||||
$rg -v -- --print0 | # False positives
|
$rg -v -- --print0 | # False positives
|
||||||
sort -u
|
sort -u
|
@@ -1,6 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install -y --no-install-recommends \
|
|
||||||
libxslt1-dev asciidoc docbook-xsl xsltproc libxml2-utils \
|
|
||||||
zsh xz-utils liblz4-tool musl-tools
|
|
@@ -99,9 +99,7 @@ is_osx() {
|
|||||||
|
|
||||||
builder() {
|
builder() {
|
||||||
if is_musl && is_x86_64; then
|
if is_musl && is_x86_64; then
|
||||||
# cargo install cross
|
cargo install cross
|
||||||
# To work around https://github.com/rust-embedded/cross/issues/357
|
|
||||||
cargo install --git https://github.com/rust-embedded/cross --force
|
|
||||||
echo "cross"
|
echo "cross"
|
||||||
else
|
else
|
||||||
echo "cargo"
|
echo "cargo"
|
||||||
|
32
complete/_rg
32
complete/_rg
@@ -3,7 +3,7 @@
|
|||||||
##
|
##
|
||||||
# zsh completion function for ripgrep
|
# zsh completion function for ripgrep
|
||||||
#
|
#
|
||||||
# Run ci/test-complete after building to ensure that the options supported by
|
# Run ci/test_complete.sh after building to ensure that the options supported by
|
||||||
# this function stay in synch with the `rg` binary.
|
# this function stay in synch with the `rg` binary.
|
||||||
#
|
#
|
||||||
# For convenience, a completion reference guide is included at the bottom of
|
# For convenience, a completion reference guide is included at the bottom of
|
||||||
@@ -72,19 +72,11 @@ _rg() {
|
|||||||
+ '(count)' # Counting options
|
+ '(count)' # Counting options
|
||||||
{-c,--count}'[only show count of matching lines for each file]'
|
{-c,--count}'[only show count of matching lines for each file]'
|
||||||
'--count-matches[only show count of individual matches for each file]'
|
'--count-matches[only show count of individual matches for each file]'
|
||||||
'--include-zero[include files with zero matches in summary]'
|
|
||||||
|
|
||||||
+ '(encoding)' # Encoding options
|
+ '(encoding)' # Encoding options
|
||||||
{-E+,--encoding=}'[specify text encoding of files to search]: :_rg_encodings'
|
{-E+,--encoding=}'[specify text encoding of files to search]: :_rg_encodings'
|
||||||
$no'--no-encoding[use default text encoding]'
|
$no'--no-encoding[use default text encoding]'
|
||||||
|
|
||||||
+ '(engine)' # Engine choice options
|
|
||||||
'--engine=[select which regex engine to use]:when:((
|
|
||||||
default\:"use default engine"
|
|
||||||
pcre2\:"identical to --pcre2"
|
|
||||||
auto\:"identical to --auto-hybrid-regex"
|
|
||||||
))'
|
|
||||||
|
|
||||||
+ file # File-input options
|
+ file # File-input options
|
||||||
'(1)*'{-f+,--file=}'[specify file containing patterns to search for]: :_files'
|
'(1)*'{-f+,--file=}'[specify file containing patterns to search for]: :_files'
|
||||||
|
|
||||||
@@ -136,10 +128,6 @@ _rg() {
|
|||||||
'--ignore-file-case-insensitive[process ignore files case insensitively]'
|
'--ignore-file-case-insensitive[process ignore files case insensitively]'
|
||||||
$no'--no-ignore-file-case-insensitive[process ignore files case sensitively]'
|
$no'--no-ignore-file-case-insensitive[process ignore files case sensitively]'
|
||||||
|
|
||||||
+ '(ignore-exclude)' # Local exclude (ignore)-file options
|
|
||||||
"--no-ignore-exclude[don't respect local exclude (ignore) files]"
|
|
||||||
$no'--ignore-exclude[respect local exclude (ignore) files]'
|
|
||||||
|
|
||||||
+ '(ignore-global)' # Global ignore-file options
|
+ '(ignore-global)' # Global ignore-file options
|
||||||
"--no-ignore-global[don't respect global ignore files]"
|
"--no-ignore-global[don't respect global ignore files]"
|
||||||
$no'--ignore-global[respect global ignore files]'
|
$no'--ignore-global[respect global ignore files]'
|
||||||
@@ -152,18 +140,10 @@ _rg() {
|
|||||||
"--no-ignore-vcs[don't respect version control ignore files]"
|
"--no-ignore-vcs[don't respect version control ignore files]"
|
||||||
$no'--ignore-vcs[respect version control ignore files]'
|
$no'--ignore-vcs[respect version control ignore files]'
|
||||||
|
|
||||||
+ '(require-git)' # git specific settings
|
+ '(ignore-dot)' # .ignore-file options
|
||||||
"--no-require-git[don't require git repository to respect gitignore rules]"
|
|
||||||
$no'--require-git[require git repository to respect gitignore rules]'
|
|
||||||
|
|
||||||
+ '(ignore-dot)' # .ignore options
|
|
||||||
"--no-ignore-dot[don't respect .ignore files]"
|
"--no-ignore-dot[don't respect .ignore files]"
|
||||||
$no'--ignore-dot[respect .ignore files]'
|
$no'--ignore-dot[respect .ignore files]'
|
||||||
|
|
||||||
+ '(ignore-files)' # custom global ignore file options
|
|
||||||
"--no-ignore-files[don't respect --ignore-file flags]"
|
|
||||||
$no'--ignore-files[respect --ignore-file files]'
|
|
||||||
|
|
||||||
+ '(json)' # JSON options
|
+ '(json)' # JSON options
|
||||||
'--json[output results in JSON Lines format]'
|
'--json[output results in JSON Lines format]'
|
||||||
$no"--no-json[don't output results in JSON Lines format]"
|
$no"--no-json[don't output results in JSON Lines format]"
|
||||||
@@ -283,10 +263,6 @@ _rg() {
|
|||||||
{-w,--word-regexp}'[only show matches surrounded by word boundaries]'
|
{-w,--word-regexp}'[only show matches surrounded by word boundaries]'
|
||||||
{-x,--line-regexp}'[only show matches surrounded by line boundaries]'
|
{-x,--line-regexp}'[only show matches surrounded by line boundaries]'
|
||||||
|
|
||||||
+ '(unicode)' # Unicode options
|
|
||||||
$no'--unicode[enable Unicode mode]'
|
|
||||||
'--no-unicode[disable Unicode mode]'
|
|
||||||
|
|
||||||
+ '(zip)' # Compression options
|
+ '(zip)' # Compression options
|
||||||
'(--pre)'{-z,--search-zip}'[search in compressed files]'
|
'(--pre)'{-z,--search-zip}'[search in compressed files]'
|
||||||
$no"--no-search-zip[don't search in compressed files]"
|
$no"--no-search-zip[don't search in compressed files]"
|
||||||
@@ -301,9 +277,7 @@ _rg() {
|
|||||||
))'
|
))'
|
||||||
'*--colors=[specify color and style settings]: :->colorspec'
|
'*--colors=[specify color and style settings]: :->colorspec'
|
||||||
'--context-separator=[specify string used to separate non-continuous context lines in output]:separator'
|
'--context-separator=[specify string used to separate non-continuous context lines in output]:separator'
|
||||||
$no"--no-context-separator[don't print context separators]"
|
|
||||||
'--debug[show debug messages]'
|
'--debug[show debug messages]'
|
||||||
'--trace[show more verbose debug messages]'
|
|
||||||
'--dfa-size-limit=[specify upper size limit of generated DFA]:DFA size (bytes)'
|
'--dfa-size-limit=[specify upper size limit of generated DFA]:DFA size (bytes)'
|
||||||
"(1 stats)--files[show each file that would be searched (but don't search)]"
|
"(1 stats)--files[show each file that would be searched (but don't search)]"
|
||||||
'*--ignore-file=[specify additional ignore file]:ignore file:_files'
|
'*--ignore-file=[specify additional ignore file]:ignore file:_files'
|
||||||
@@ -323,7 +297,7 @@ _rg() {
|
|||||||
'(--type-list)*: :_files'
|
'(--type-list)*: :_files'
|
||||||
)
|
)
|
||||||
|
|
||||||
# This is used with test-complete to verify that there are no options
|
# This is used with test_complete.sh to verify that there are no options
|
||||||
# listed in the help output that aren't also defined here
|
# listed in the help output that aren't also defined here
|
||||||
[[ $_RG_COMPLETE_LIST_ARGS == (1|t*|y*) ]] && {
|
[[ $_RG_COMPLETE_LIST_ARGS == (1|t*|y*) ]] && {
|
||||||
print -rl - $args
|
print -rl - $args
|
||||||
|
@@ -1,15 +0,0 @@
|
|||||||
ripgrep core
|
|
||||||
------------
|
|
||||||
This is the core ripgrep crate. In particular, `main.rs` is where the `main`
|
|
||||||
function lives.
|
|
||||||
|
|
||||||
Most of ripgrep core consists of two things:
|
|
||||||
|
|
||||||
* The definition of the CLI interface, including docs for every flag.
|
|
||||||
* Glue code that brings the `grep-matcher`, `grep-regex`, `grep-searcher` and
|
|
||||||
`grep-printer` crates together to actually execute the search.
|
|
||||||
|
|
||||||
Currently, there are no plans to make ripgrep core available as an independent
|
|
||||||
library. However, much of the heavy lifting of ripgrep is done via its
|
|
||||||
constituent crates, which can be reused independent of ripgrep. Unfortunately,
|
|
||||||
there is no guide or tutorial to teach folks how to do this yet.
|
|
@@ -1,38 +0,0 @@
|
|||||||
use serde::de::Error;
|
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
|
||||||
|
|
||||||
use Glob;
|
|
||||||
|
|
||||||
impl Serialize for Glob {
|
|
||||||
fn serialize<S: Serializer>(
|
|
||||||
&self,
|
|
||||||
serializer: S,
|
|
||||||
) -> Result<S::Ok, S::Error> {
|
|
||||||
serializer.serialize_str(self.glob())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for Glob {
|
|
||||||
fn deserialize<D: Deserializer<'de>>(
|
|
||||||
deserializer: D,
|
|
||||||
) -> Result<Self, D::Error> {
|
|
||||||
let glob = <&str as Deserialize>::deserialize(deserializer)?;
|
|
||||||
Glob::new(glob).map_err(D::Error::custom)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use Glob;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn glob_json_works() {
|
|
||||||
let test_glob = Glob::new("src/**/*.rs").unwrap();
|
|
||||||
|
|
||||||
let ser = serde_json::to_string(&test_glob).unwrap();
|
|
||||||
assert_eq!(ser, "\"src/**/*.rs\"");
|
|
||||||
|
|
||||||
let de: Glob = serde_json::from_str(&ser).unwrap();
|
|
||||||
assert_eq!(test_glob, de);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,246 +0,0 @@
|
|||||||
/// This list represents the default file types that ripgrep ships with. In
|
|
||||||
/// general, any file format is fair game, although it should generally be
|
|
||||||
/// limited to reasonably popular open formats. For other cases, you can add
|
|
||||||
/// types to each invocation of ripgrep with the '--type-add' flag.
|
|
||||||
///
|
|
||||||
/// If you would like to add or improve this list, please file a PR:
|
|
||||||
/// https://github.com/BurntSushi/ripgrep
|
|
||||||
///
|
|
||||||
/// Please try to keep this list sorted lexicographically and wrapped to 79
|
|
||||||
/// columns (inclusive).
|
|
||||||
#[rustfmt::skip]
|
|
||||||
pub const DEFAULT_TYPES: &[(&str, &[&str])] = &[
|
|
||||||
("agda", &["*.agda", "*.lagda"]),
|
|
||||||
("aidl", &["*.aidl"]),
|
|
||||||
("amake", &["*.mk", "*.bp"]),
|
|
||||||
("asciidoc", &["*.adoc", "*.asc", "*.asciidoc"]),
|
|
||||||
("asm", &["*.asm", "*.s", "*.S"]),
|
|
||||||
("asp", &[
|
|
||||||
"*.aspx", "*.aspx.cs", "*.aspx.cs", "*.ascx", "*.ascx.cs", "*.ascx.vb",
|
|
||||||
]),
|
|
||||||
("ats", &["*.ats", "*.dats", "*.sats", "*.hats"]),
|
|
||||||
("avro", &["*.avdl", "*.avpr", "*.avsc"]),
|
|
||||||
("awk", &["*.awk"]),
|
|
||||||
("bazel", &["*.bzl", "WORKSPACE", "BUILD", "BUILD.bazel"]),
|
|
||||||
("bitbake", &["*.bb", "*.bbappend", "*.bbclass", "*.conf", "*.inc"]),
|
|
||||||
("brotli", &["*.br"]),
|
|
||||||
("buildstream", &["*.bst"]),
|
|
||||||
("bzip2", &["*.bz2", "*.tbz2"]),
|
|
||||||
("c", &["*.[chH]", "*.[chH].in", "*.cats"]),
|
|
||||||
("cabal", &["*.cabal"]),
|
|
||||||
("cbor", &["*.cbor"]),
|
|
||||||
("ceylon", &["*.ceylon"]),
|
|
||||||
("clojure", &["*.clj", "*.cljc", "*.cljs", "*.cljx"]),
|
|
||||||
("cmake", &["*.cmake", "CMakeLists.txt"]),
|
|
||||||
("coffeescript", &["*.coffee"]),
|
|
||||||
("config", &["*.cfg", "*.conf", "*.config", "*.ini"]),
|
|
||||||
("coq", &["*.v"]),
|
|
||||||
("cpp", &[
|
|
||||||
"*.[ChH]", "*.cc", "*.[ch]pp", "*.[ch]xx", "*.hh", "*.inl",
|
|
||||||
"*.[ChH].in", "*.cc.in", "*.[ch]pp.in", "*.[ch]xx.in", "*.hh.in",
|
|
||||||
]),
|
|
||||||
("creole", &["*.creole"]),
|
|
||||||
("crystal", &["Projectfile", "*.cr"]),
|
|
||||||
("cs", &["*.cs"]),
|
|
||||||
("csharp", &["*.cs"]),
|
|
||||||
("cshtml", &["*.cshtml"]),
|
|
||||||
("css", &["*.css", "*.scss"]),
|
|
||||||
("csv", &["*.csv"]),
|
|
||||||
("cython", &["*.pyx", "*.pxi", "*.pxd"]),
|
|
||||||
("d", &["*.d"]),
|
|
||||||
("dart", &["*.dart"]),
|
|
||||||
("dhall", &["*.dhall"]),
|
|
||||||
("diff", &["*.patch", "*.diff"]),
|
|
||||||
("docker", &["*Dockerfile*"]),
|
|
||||||
("edn", &["*.edn"]),
|
|
||||||
("elisp", &["*.el"]),
|
|
||||||
("elixir", &["*.ex", "*.eex", "*.exs"]),
|
|
||||||
("elm", &["*.elm"]),
|
|
||||||
("erb", &["*.erb"]),
|
|
||||||
("erlang", &["*.erl", "*.hrl"]),
|
|
||||||
("fidl", &["*.fidl"]),
|
|
||||||
("fish", &["*.fish"]),
|
|
||||||
("fortran", &[
|
|
||||||
"*.f", "*.F", "*.f77", "*.F77", "*.pfo",
|
|
||||||
"*.f90", "*.F90", "*.f95", "*.F95",
|
|
||||||
]),
|
|
||||||
("fsharp", &["*.fs", "*.fsx", "*.fsi"]),
|
|
||||||
("gap", &["*.g", "*.gap", "*.gi", "*.gd", "*.tst"]),
|
|
||||||
("gn", &["*.gn", "*.gni"]),
|
|
||||||
("go", &["*.go"]),
|
|
||||||
("gradle", &["*.gradle"]),
|
|
||||||
("groovy", &["*.groovy", "*.gradle"]),
|
|
||||||
("gzip", &["*.gz", "*.tgz"]),
|
|
||||||
("h", &["*.h", "*.hpp"]),
|
|
||||||
("haml", &["*.haml"]),
|
|
||||||
("haskell", &["*.hs", "*.lhs", "*.cpphs", "*.c2hs", "*.hsc"]),
|
|
||||||
("hbs", &["*.hbs"]),
|
|
||||||
("hs", &["*.hs", "*.lhs"]),
|
|
||||||
("html", &["*.htm", "*.html", "*.ejs"]),
|
|
||||||
("idris", &["*.idr", "*.lidr"]),
|
|
||||||
("java", &["*.java", "*.jsp", "*.jspx", "*.properties"]),
|
|
||||||
("jinja", &["*.j2", "*.jinja", "*.jinja2"]),
|
|
||||||
("jl", &["*.jl"]),
|
|
||||||
("js", &["*.js", "*.jsx", "*.vue"]),
|
|
||||||
("json", &["*.json", "composer.lock"]),
|
|
||||||
("jsonl", &["*.jsonl"]),
|
|
||||||
("julia", &["*.jl"]),
|
|
||||||
("jupyter", &["*.ipynb", "*.jpynb"]),
|
|
||||||
("k", &["*.k"]),
|
|
||||||
("kotlin", &["*.kt", "*.kts"]),
|
|
||||||
("less", &["*.less"]),
|
|
||||||
("license", &[
|
|
||||||
// General
|
|
||||||
"COPYING", "COPYING[.-]*",
|
|
||||||
"COPYRIGHT", "COPYRIGHT[.-]*",
|
|
||||||
"EULA", "EULA[.-]*",
|
|
||||||
"licen[cs]e", "licen[cs]e.*",
|
|
||||||
"LICEN[CS]E", "LICEN[CS]E[.-]*", "*[.-]LICEN[CS]E*",
|
|
||||||
"NOTICE", "NOTICE[.-]*",
|
|
||||||
"PATENTS", "PATENTS[.-]*",
|
|
||||||
"UNLICEN[CS]E", "UNLICEN[CS]E[.-]*",
|
|
||||||
// GPL (gpl.txt, etc.)
|
|
||||||
"agpl[.-]*",
|
|
||||||
"gpl[.-]*",
|
|
||||||
"lgpl[.-]*",
|
|
||||||
// Other license-specific (APACHE-2.0.txt, etc.)
|
|
||||||
"AGPL-*[0-9]*",
|
|
||||||
"APACHE-*[0-9]*",
|
|
||||||
"BSD-*[0-9]*",
|
|
||||||
"CC-BY-*",
|
|
||||||
"GFDL-*[0-9]*",
|
|
||||||
"GNU-*[0-9]*",
|
|
||||||
"GPL-*[0-9]*",
|
|
||||||
"LGPL-*[0-9]*",
|
|
||||||
"MIT-*[0-9]*",
|
|
||||||
"MPL-*[0-9]*",
|
|
||||||
"OFL-*[0-9]*",
|
|
||||||
]),
|
|
||||||
("lisp", &["*.el", "*.jl", "*.lisp", "*.lsp", "*.sc", "*.scm"]),
|
|
||||||
("lock", &["*.lock", "package-lock.json"]),
|
|
||||||
("log", &["*.log"]),
|
|
||||||
("lua", &["*.lua"]),
|
|
||||||
("lz4", &["*.lz4"]),
|
|
||||||
("lzma", &["*.lzma"]),
|
|
||||||
("m4", &["*.ac", "*.m4"]),
|
|
||||||
("make", &[
|
|
||||||
"[Gg][Nn][Uu]makefile", "[Mm]akefile",
|
|
||||||
"[Gg][Nn][Uu]makefile.am", "[Mm]akefile.am",
|
|
||||||
"[Gg][Nn][Uu]makefile.in", "[Mm]akefile.in",
|
|
||||||
"*.mk", "*.mak"
|
|
||||||
]),
|
|
||||||
("mako", &["*.mako", "*.mao"]),
|
|
||||||
("man", &["*.[0-9lnpx]", "*.[0-9][cEFMmpSx]"]),
|
|
||||||
("markdown", &["*.markdown", "*.md", "*.mdown", "*.mkdn"]),
|
|
||||||
("matlab", &["*.m"]),
|
|
||||||
("md", &["*.markdown", "*.md", "*.mdown", "*.mkdn"]),
|
|
||||||
("mk", &["mkfile"]),
|
|
||||||
("ml", &["*.ml"]),
|
|
||||||
("msbuild", &[
|
|
||||||
"*.csproj", "*.fsproj", "*.vcxproj", "*.proj", "*.props", "*.targets",
|
|
||||||
]),
|
|
||||||
("nim", &["*.nim", "*.nimf", "*.nimble", "*.nims"]),
|
|
||||||
("nix", &["*.nix"]),
|
|
||||||
("objc", &["*.h", "*.m"]),
|
|
||||||
("objcpp", &["*.h", "*.mm"]),
|
|
||||||
("ocaml", &["*.ml", "*.mli", "*.mll", "*.mly"]),
|
|
||||||
("org", &["*.org", "*.org_archive"]),
|
|
||||||
("pascal", &["*.pas", "*.dpr", "*.lpr", "*.pp", "*.inc"]),
|
|
||||||
("pdf", &["*.pdf"]),
|
|
||||||
("perl", &["*.perl", "*.pl", "*.PL", "*.plh", "*.plx", "*.pm", "*.t"]),
|
|
||||||
("php", &["*.php", "*.php3", "*.php4", "*.php5", "*.phtml"]),
|
|
||||||
("pod", &["*.pod"]),
|
|
||||||
("postscript", &["*.eps", "*.ps"]),
|
|
||||||
("protobuf", &["*.proto"]),
|
|
||||||
("ps", &["*.cdxml", "*.ps1", "*.ps1xml", "*.psd1", "*.psm1"]),
|
|
||||||
("puppet", &["*.erb", "*.pp", "*.rb"]),
|
|
||||||
("purs", &["*.purs"]),
|
|
||||||
("py", &["*.py"]),
|
|
||||||
("qmake", &["*.pro", "*.pri", "*.prf"]),
|
|
||||||
("qml", &["*.qml"]),
|
|
||||||
("r", &["*.R", "*.r", "*.Rmd", "*.Rnw"]),
|
|
||||||
("rdoc", &["*.rdoc"]),
|
|
||||||
("readme", &["README*", "*README"]),
|
|
||||||
("robot", &["*.robot"]),
|
|
||||||
("rst", &["*.rst"]),
|
|
||||||
("ruby", &["Gemfile", "*.gemspec", ".irbrc", "Rakefile", "*.rb"]),
|
|
||||||
("rust", &["*.rs"]),
|
|
||||||
("sass", &["*.sass", "*.scss"]),
|
|
||||||
("scala", &["*.scala", "*.sbt"]),
|
|
||||||
("sh", &[
|
|
||||||
// Portable/misc. init files
|
|
||||||
".login", ".logout", ".profile", "profile",
|
|
||||||
// bash-specific init files
|
|
||||||
".bash_login", "bash_login",
|
|
||||||
".bash_logout", "bash_logout",
|
|
||||||
".bash_profile", "bash_profile",
|
|
||||||
".bashrc", "bashrc", "*.bashrc",
|
|
||||||
// csh-specific init files
|
|
||||||
".cshrc", "*.cshrc",
|
|
||||||
// ksh-specific init files
|
|
||||||
".kshrc", "*.kshrc",
|
|
||||||
// tcsh-specific init files
|
|
||||||
".tcshrc",
|
|
||||||
// zsh-specific init files
|
|
||||||
".zshenv", "zshenv",
|
|
||||||
".zlogin", "zlogin",
|
|
||||||
".zlogout", "zlogout",
|
|
||||||
".zprofile", "zprofile",
|
|
||||||
".zshrc", "zshrc",
|
|
||||||
// Extensions
|
|
||||||
"*.bash", "*.csh", "*.ksh", "*.sh", "*.tcsh", "*.zsh",
|
|
||||||
]),
|
|
||||||
("slim", &["*.skim", "*.slim", "*.slime"]),
|
|
||||||
("smarty", &["*.tpl"]),
|
|
||||||
("sml", &["*.sml", "*.sig"]),
|
|
||||||
("soy", &["*.soy"]),
|
|
||||||
("spark", &["*.spark"]),
|
|
||||||
("spec", &["*.spec"]),
|
|
||||||
("sql", &["*.sql", "*.psql"]),
|
|
||||||
("stylus", &["*.styl"]),
|
|
||||||
("sv", &["*.v", "*.vg", "*.sv", "*.svh", "*.h"]),
|
|
||||||
("svg", &["*.svg"]),
|
|
||||||
("swift", &["*.swift"]),
|
|
||||||
("swig", &["*.def", "*.i"]),
|
|
||||||
("systemd", &[
|
|
||||||
"*.automount", "*.conf", "*.device", "*.link", "*.mount", "*.path",
|
|
||||||
"*.scope", "*.service", "*.slice", "*.socket", "*.swap", "*.target",
|
|
||||||
"*.timer",
|
|
||||||
]),
|
|
||||||
("taskpaper", &["*.taskpaper"]),
|
|
||||||
("tcl", &["*.tcl"]),
|
|
||||||
("tex", &["*.tex", "*.ltx", "*.cls", "*.sty", "*.bib", "*.dtx", "*.ins"]),
|
|
||||||
("textile", &["*.textile"]),
|
|
||||||
("tf", &["*.tf"]),
|
|
||||||
("thrift", &["*.thrift"]),
|
|
||||||
("toml", &["*.toml", "Cargo.lock"]),
|
|
||||||
("ts", &["*.ts", "*.tsx"]),
|
|
||||||
("twig", &["*.twig"]),
|
|
||||||
("txt", &["*.txt"]),
|
|
||||||
("typoscript", &["*.typoscript", "*.ts"]),
|
|
||||||
("vala", &["*.vala"]),
|
|
||||||
("vb", &["*.vb"]),
|
|
||||||
("verilog", &["*.v", "*.vh", "*.sv", "*.svh"]),
|
|
||||||
("vhdl", &["*.vhd", "*.vhdl"]),
|
|
||||||
("vim", &["*.vim"]),
|
|
||||||
("vimscript", &["*.vim"]),
|
|
||||||
("webidl", &["*.idl", "*.webidl", "*.widl"]),
|
|
||||||
("wiki", &["*.mediawiki", "*.wiki"]),
|
|
||||||
("xml", &[
|
|
||||||
"*.xml", "*.xml.dist", "*.dtd", "*.xsl", "*.xslt", "*.xsd", "*.xjb",
|
|
||||||
"*.rng", "*.sch", "*.xhtml",
|
|
||||||
]),
|
|
||||||
("xz", &["*.xz", "*.txz"]),
|
|
||||||
("yacc", &["*.y"]),
|
|
||||||
("yaml", &["*.yaml", "*.yml"]),
|
|
||||||
("zig", &["*.zig"]),
|
|
||||||
("zsh", &[
|
|
||||||
".zshenv", "zshenv",
|
|
||||||
".zlogin", "zlogin",
|
|
||||||
".zlogout", "zlogout",
|
|
||||||
".zprofile", "zprofile",
|
|
||||||
".zshrc", "zshrc",
|
|
||||||
"*.zsh",
|
|
||||||
]),
|
|
||||||
("zstd", &["*.zst", "*.zstd"]),
|
|
||||||
];
|
|
@@ -41,11 +41,6 @@ configuration file. The file can specify one shell argument per line. Lines
|
|||||||
starting with *#* are ignored. For more details, see the man page or the
|
starting with *#* are ignored. For more details, see the man page or the
|
||||||
*README*.
|
*README*.
|
||||||
|
|
||||||
ripgrep will automatically detect if stdin exists and search stdin for a regex
|
|
||||||
pattern, e.g. *ls | rg foo*. In some environments, stdin may exist when it
|
|
||||||
shouldn't. To turn off stdin detection explicitly specify the directory to
|
|
||||||
search, e.g. *rg foo ./*.
|
|
||||||
|
|
||||||
Tip: to disable all smart filtering and make ripgrep behave a bit more like
|
Tip: to disable all smart filtering and make ripgrep behave a bit more like
|
||||||
classical grep, use *rg -uuu*.
|
classical grep, use *rg -uuu*.
|
||||||
|
|
||||||
@@ -109,76 +104,6 @@ was found. In summary:
|
|||||||
unable to read a file).
|
unable to read a file).
|
||||||
|
|
||||||
|
|
||||||
AUTOMATIC FILTERING
|
|
||||||
-------------------
|
|
||||||
TL;DR - To disable automatic filtering, use 'rg -uuu'.
|
|
||||||
|
|
||||||
One of ripgrep's most important features is its automatic smart filtering.
|
|
||||||
It is the most apparent differentiating feature between ripgrep and other tools
|
|
||||||
like 'grep'. As such, its behavior may be surprising to users that aren't
|
|
||||||
expecting it.
|
|
||||||
|
|
||||||
ripgrep does four types of filtering automatically:
|
|
||||||
|
|
||||||
1. Files and directories that match ignore rules are not searched.
|
|
||||||
2. Hidden files and directories are not searched.
|
|
||||||
3. Binary files (files with a 'NUL' byte) are not searched.
|
|
||||||
4. Symbolic links are not followed.
|
|
||||||
|
|
||||||
The first type of filtering is the most sophisticated. ripgrep will attempt to
|
|
||||||
respect your gitignore rules as faithfully as possible. In particular, this
|
|
||||||
includes the following:
|
|
||||||
|
|
||||||
* Any global rules, e.g., in '$HOME/.config/git/ignore'.
|
|
||||||
* Any rules in '.gitignore'.
|
|
||||||
* Any local rules, e.g., in '.git/info/exclude'.
|
|
||||||
|
|
||||||
In some cases, ripgrep and git will not always be in sync in terms of which
|
|
||||||
files are ignored. For example, a file that is ignored via '.gitignore' but is
|
|
||||||
tracked by git would not be searched by ripgrep even though git tracks it. This
|
|
||||||
is unlikely to ever be fixed. Instead, you should either make sure your exclude
|
|
||||||
rules match the files you track precisely, or otherwise use 'git grep' for
|
|
||||||
search.
|
|
||||||
|
|
||||||
Additional ignore rules can be provided outside of a git context:
|
|
||||||
|
|
||||||
* Any rules in '.ignore'.
|
|
||||||
* Any rules in '.rgignore'.
|
|
||||||
* Any rules in files specified with the '--ignore-file' flag.
|
|
||||||
|
|
||||||
The precedence of ignore rules is as follows, with later items overriding
|
|
||||||
earlier items:
|
|
||||||
|
|
||||||
* Files given by '--ignore-file'.
|
|
||||||
* Global gitignore rules, e.g., from '$HOME/.config/git/ignore'.
|
|
||||||
* Local rules from '.git/info/exclude'.
|
|
||||||
* Rules from '.gitignore'.
|
|
||||||
* Rules from '.ignore'.
|
|
||||||
* Rules from '.rgignore'.
|
|
||||||
|
|
||||||
So for example, if 'foo' were in a '.gitignore' and '!foo' were in an
|
|
||||||
'.rgignore', then 'foo' would not be ignored since '.rgignore' takes precedence
|
|
||||||
over '.gitignore'.
|
|
||||||
|
|
||||||
Each of the types of filtering can be configured via command line flags:
|
|
||||||
|
|
||||||
* There are several flags starting with '--no-ignore' that toggle which,
|
|
||||||
if any, ignore rules are respected. '--no-ignore' by itself will disable
|
|
||||||
all of them.
|
|
||||||
* '--hidden' will force ripgrep to search hidden files and directories.
|
|
||||||
* '--binary' will force ripgrep to search binary files.
|
|
||||||
* '-L/--follow' will force ripgrep to follow symlinks.
|
|
||||||
|
|
||||||
As a special short hand, the `-u` flag can be specified up to three times. Each
|
|
||||||
additional time incrementally decreases filtering:
|
|
||||||
|
|
||||||
* '-u' is equivalent to '--no-ignore'.
|
|
||||||
* '-uu' is equivalent to '--no-ignore --hidden'.
|
|
||||||
* '-uuu' is equivalent to '--no-ignore --hidden --binary'.
|
|
||||||
|
|
||||||
In particular, 'rg -uuu' should search the same exact content as 'grep -r'.
|
|
||||||
|
|
||||||
|
|
||||||
CONFIGURATION FILES
|
CONFIGURATION FILES
|
||||||
-------------------
|
-------------------
|
||||||
ripgrep supports reading configuration files that change ripgrep's default
|
ripgrep supports reading configuration files that change ripgrep's default
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "globset"
|
name = "globset"
|
||||||
version = "0.4.5" #:version
|
version = "0.4.4" #:version
|
||||||
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
||||||
description = """
|
description = """
|
||||||
Cross platform single glob and glob set matching. Glob set matching is the
|
Cross platform single glob and glob set matching. Glob set matching is the
|
||||||
@@ -8,8 +8,8 @@ process of matching one or more glob patterns against a single candidate path
|
|||||||
simultaneously, and returning all of the globs that matched.
|
simultaneously, and returning all of the globs that matched.
|
||||||
"""
|
"""
|
||||||
documentation = "https://docs.rs/globset"
|
documentation = "https://docs.rs/globset"
|
||||||
homepage = "https://github.com/BurntSushi/ripgrep/tree/master/crates/globset"
|
homepage = "https://github.com/BurntSushi/ripgrep/tree/master/globset"
|
||||||
repository = "https://github.com/BurntSushi/ripgrep/tree/master/crates/globset"
|
repository = "https://github.com/BurntSushi/ripgrep/tree/master/globset"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
keywords = ["regex", "glob", "multiple", "set", "pattern"]
|
keywords = ["regex", "glob", "multiple", "set", "pattern"]
|
||||||
license = "Unlicense/MIT"
|
license = "Unlicense/MIT"
|
||||||
@@ -24,13 +24,9 @@ bstr = { version = "0.2.0", default-features = false, features = ["std"] }
|
|||||||
fnv = "1.0.6"
|
fnv = "1.0.6"
|
||||||
log = "0.4.5"
|
log = "0.4.5"
|
||||||
regex = "1.1.5"
|
regex = "1.1.5"
|
||||||
serde = { version = "1.0.104", optional = true }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
glob = "0.3.0"
|
glob = "0.3.0"
|
||||||
lazy_static = "1"
|
|
||||||
serde_json = "1.0.45"
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
simd-accel = []
|
simd-accel = []
|
||||||
serde1 = ["serde"]
|
|
@@ -29,10 +29,6 @@ and this to your crate root:
|
|||||||
extern crate globset;
|
extern crate globset;
|
||||||
```
|
```
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
* `serde1`: Enables implementing Serde traits on the `Glob` type.
|
|
||||||
|
|
||||||
### Example: one glob
|
### Example: one glob
|
||||||
|
|
||||||
This example shows how to match a single glob against a single file path.
|
This example shows how to match a single glob against a single file path.
|
@@ -6,9 +6,14 @@ tool itself, see the benchsuite directory.
|
|||||||
|
|
||||||
extern crate glob;
|
extern crate glob;
|
||||||
extern crate globset;
|
extern crate globset;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate lazy_static;
|
||||||
extern crate regex;
|
extern crate regex;
|
||||||
extern crate test;
|
extern crate test;
|
||||||
|
|
||||||
|
use std::ffi::OsStr;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
use globset::{Candidate, Glob, GlobMatcher, GlobSet, GlobSetBuilder};
|
use globset::{Candidate, Glob, GlobMatcher, GlobSet, GlobSetBuilder};
|
||||||
|
|
||||||
const EXT: &'static str = "some/a/bigger/path/to/the/crazy/needle.txt";
|
const EXT: &'static str = "some/a/bigger/path/to/the/crazy/needle.txt";
|
@@ -2,13 +2,13 @@ use std::fmt;
|
|||||||
use std::hash;
|
use std::hash;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::path::{is_separator, Path};
|
use std::path::{Path, is_separator};
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
use regex;
|
use regex;
|
||||||
use regex::bytes::Regex;
|
use regex::bytes::Regex;
|
||||||
|
|
||||||
use {new_regex, Candidate, Error, ErrorKind};
|
use {Candidate, Error, ErrorKind, new_regex};
|
||||||
|
|
||||||
/// Describes a matching strategy for a particular pattern.
|
/// Describes a matching strategy for a particular pattern.
|
||||||
///
|
///
|
||||||
@@ -85,16 +85,16 @@ pub struct Glob {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for Glob {
|
impl PartialEq for Glob {
|
||||||
fn eq(&self, other: &Glob) -> bool {
|
fn eq(&self, other: &Glob) -> bool {
|
||||||
self.glob == other.glob && self.opts == other.opts
|
self.glob == other.glob && self.opts == other.opts
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl hash::Hash for Glob {
|
impl hash::Hash for Glob {
|
||||||
fn hash<H: hash::Hasher>(&self, state: &mut H) {
|
fn hash<H: hash::Hasher>(&self, state: &mut H) {
|
||||||
self.glob.hash(state);
|
self.glob.hash(state);
|
||||||
self.opts.hash(state);
|
self.opts.hash(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Glob {
|
impl fmt::Display for Glob {
|
||||||
@@ -103,14 +103,6 @@ impl fmt::Display for Glob {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl str::FromStr for Glob {
|
|
||||||
type Err = Error;
|
|
||||||
|
|
||||||
fn from_str(glob: &str) -> Result<Self, Self::Err> {
|
|
||||||
Self::new(glob)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A matcher for a single pattern.
|
/// A matcher for a single pattern.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct GlobMatcher {
|
pub struct GlobMatcher {
|
||||||
@@ -130,11 +122,6 @@ impl GlobMatcher {
|
|||||||
pub fn is_match_candidate(&self, path: &Candidate) -> bool {
|
pub fn is_match_candidate(&self, path: &Candidate) -> bool {
|
||||||
self.re.is_match(&path.path)
|
self.re.is_match(&path.path)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the `Glob` used to compile this matcher.
|
|
||||||
pub fn glob(&self) -> &Glob {
|
|
||||||
&self.pat
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A strategic matcher for a single pattern.
|
/// A strategic matcher for a single pattern.
|
||||||
@@ -227,15 +214,11 @@ struct Tokens(Vec<Token>);
|
|||||||
|
|
||||||
impl Deref for Tokens {
|
impl Deref for Tokens {
|
||||||
type Target = Vec<Token>;
|
type Target = Vec<Token>;
|
||||||
fn deref(&self) -> &Vec<Token> {
|
fn deref(&self) -> &Vec<Token> { &self.0 }
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DerefMut for Tokens {
|
impl DerefMut for Tokens {
|
||||||
fn deref_mut(&mut self) -> &mut Vec<Token> {
|
fn deref_mut(&mut self) -> &mut Vec<Token> { &mut self.0 }
|
||||||
&mut self.0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
@@ -246,7 +229,10 @@ enum Token {
|
|||||||
RecursivePrefix,
|
RecursivePrefix,
|
||||||
RecursiveSuffix,
|
RecursiveSuffix,
|
||||||
RecursiveZeroOrMore,
|
RecursiveZeroOrMore,
|
||||||
Class { negated: bool, ranges: Vec<(char, char)> },
|
Class {
|
||||||
|
negated: bool,
|
||||||
|
ranges: Vec<(char, char)>,
|
||||||
|
},
|
||||||
Alternates(Vec<Tokens>),
|
Alternates(Vec<Tokens>),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,9 +244,12 @@ impl Glob {
|
|||||||
|
|
||||||
/// Returns a matcher for this pattern.
|
/// Returns a matcher for this pattern.
|
||||||
pub fn compile_matcher(&self) -> GlobMatcher {
|
pub fn compile_matcher(&self) -> GlobMatcher {
|
||||||
let re =
|
let re = new_regex(&self.re)
|
||||||
new_regex(&self.re).expect("regex compilation shouldn't fail");
|
.expect("regex compilation shouldn't fail");
|
||||||
GlobMatcher { pat: self.clone(), re: re }
|
GlobMatcher {
|
||||||
|
pat: self.clone(),
|
||||||
|
re: re,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a strategic matcher.
|
/// Returns a strategic matcher.
|
||||||
@@ -271,9 +260,13 @@ impl Glob {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
fn compile_strategic_matcher(&self) -> GlobStrategic {
|
fn compile_strategic_matcher(&self) -> GlobStrategic {
|
||||||
let strategy = MatchStrategy::new(self);
|
let strategy = MatchStrategy::new(self);
|
||||||
let re =
|
let re = new_regex(&self.re)
|
||||||
new_regex(&self.re).expect("regex compilation shouldn't fail");
|
.expect("regex compilation shouldn't fail");
|
||||||
GlobStrategic { strategy: strategy, pat: self.clone(), re: re }
|
GlobStrategic {
|
||||||
|
strategy: strategy,
|
||||||
|
pat: self.clone(),
|
||||||
|
re: re,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the original glob pattern used to build this pattern.
|
/// Returns the original glob pattern used to build this pattern.
|
||||||
@@ -531,7 +524,7 @@ impl Glob {
|
|||||||
| Token::RecursiveZeroOrMore => {
|
| Token::RecursiveZeroOrMore => {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
Token::Class { .. } | Token::Alternates(..) => {
|
Token::Class{..} | Token::Alternates(..) => {
|
||||||
// We *could* be a little smarter here, but either one
|
// We *could* be a little smarter here, but either one
|
||||||
// of these is going to prevent our literal optimizations
|
// of these is going to prevent our literal optimizations
|
||||||
// anyway, so give up.
|
// anyway, so give up.
|
||||||
@@ -568,7 +561,10 @@ impl<'a> GlobBuilder<'a> {
|
|||||||
///
|
///
|
||||||
/// The pattern is not compiled until `build` is called.
|
/// The pattern is not compiled until `build` is called.
|
||||||
pub fn new(glob: &'a str) -> GlobBuilder<'a> {
|
pub fn new(glob: &'a str) -> GlobBuilder<'a> {
|
||||||
GlobBuilder { glob: glob, opts: GlobOptions::default() }
|
GlobBuilder {
|
||||||
|
glob: glob,
|
||||||
|
opts: GlobOptions::default(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses and builds the pattern.
|
/// Parses and builds the pattern.
|
||||||
@@ -866,22 +862,25 @@ impl<'a> Parser<'a> {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let is_suffix = match self.peek() {
|
let is_suffix =
|
||||||
None => {
|
match self.peek() {
|
||||||
assert!(self.bump().is_none());
|
None => {
|
||||||
true
|
assert!(self.bump().is_none());
|
||||||
}
|
true
|
||||||
Some(',') | Some('}') if self.stack.len() >= 2 => true,
|
}
|
||||||
Some(c) if is_separator(c) => {
|
Some(',') | Some('}') if self.stack.len() >= 2 => {
|
||||||
assert!(self.bump().map(is_separator).unwrap_or(false));
|
true
|
||||||
false
|
}
|
||||||
}
|
Some(c) if is_separator(c) => {
|
||||||
_ => {
|
assert!(self.bump().map(is_separator).unwrap_or(false));
|
||||||
self.push_token(Token::ZeroOrMore)?;
|
false
|
||||||
self.push_token(Token::ZeroOrMore)?;
|
}
|
||||||
return Ok(());
|
_ => {
|
||||||
}
|
self.push_token(Token::ZeroOrMore)?;
|
||||||
};
|
self.push_token(Token::ZeroOrMore)?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
};
|
||||||
match self.pop_token()? {
|
match self.pop_token()? {
|
||||||
Token::RecursivePrefix => {
|
Token::RecursivePrefix => {
|
||||||
self.push_token(Token::RecursivePrefix)?;
|
self.push_token(Token::RecursivePrefix)?;
|
||||||
@@ -961,10 +960,7 @@ impl<'a> Parser<'a> {
|
|||||||
// invariant: in_range is only set when there is
|
// invariant: in_range is only set when there is
|
||||||
// already at least one character seen.
|
// already at least one character seen.
|
||||||
add_to_last_range(
|
add_to_last_range(
|
||||||
&self.glob,
|
&self.glob, ranges.last_mut().unwrap(), c)?;
|
||||||
ranges.last_mut().unwrap(),
|
|
||||||
c,
|
|
||||||
)?;
|
|
||||||
} else {
|
} else {
|
||||||
ranges.push((c, c));
|
ranges.push((c, c));
|
||||||
}
|
}
|
||||||
@@ -978,7 +974,10 @@ impl<'a> Parser<'a> {
|
|||||||
// it as a literal.
|
// it as a literal.
|
||||||
ranges.push(('-', '-'));
|
ranges.push(('-', '-'));
|
||||||
}
|
}
|
||||||
self.push_token(Token::Class { negated: negated, ranges: ranges })
|
self.push_token(Token::Class {
|
||||||
|
negated: negated,
|
||||||
|
ranges: ranges,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bump(&mut self) -> Option<char> {
|
fn bump(&mut self) -> Option<char> {
|
||||||
@@ -1007,9 +1006,9 @@ fn ends_with(needle: &[u8], haystack: &[u8]) -> bool {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::Token::*;
|
use {GlobSetBuilder, ErrorKind};
|
||||||
use super::{Glob, GlobBuilder, Token};
|
use super::{Glob, GlobBuilder, Token};
|
||||||
use {ErrorKind, GlobSetBuilder};
|
use super::Token::*;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default)]
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
struct Options {
|
struct Options {
|
||||||
@@ -1025,7 +1024,7 @@ mod tests {
|
|||||||
let pat = Glob::new($pat).unwrap();
|
let pat = Glob::new($pat).unwrap();
|
||||||
assert_eq!($tokens, pat.tokens.0);
|
assert_eq!($tokens, pat.tokens.0);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! syntaxerr {
|
macro_rules! syntaxerr {
|
||||||
@@ -1035,7 +1034,7 @@ mod tests {
|
|||||||
let err = Glob::new($pat).unwrap_err();
|
let err = Glob::new($pat).unwrap_err();
|
||||||
assert_eq!(&$err, err.kind());
|
assert_eq!(&$err, err.kind());
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! toregex {
|
macro_rules! toregex {
|
||||||
@@ -1117,9 +1116,7 @@ mod tests {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn s(string: &str) -> String {
|
fn s(string: &str) -> String { string.to_string() }
|
||||||
string.to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn class(s: char, e: char) -> Token {
|
fn class(s: char, e: char) -> Token {
|
||||||
Class { negated: false, ranges: vec![(s, e)] }
|
Class { negated: false, ranges: vec![(s, e)] }
|
||||||
@@ -1143,20 +1140,16 @@ mod tests {
|
|||||||
syntax!(any2, "a?b", vec![Literal('a'), Any, Literal('b')]);
|
syntax!(any2, "a?b", vec![Literal('a'), Any, Literal('b')]);
|
||||||
syntax!(seq1, "*", vec![ZeroOrMore]);
|
syntax!(seq1, "*", vec![ZeroOrMore]);
|
||||||
syntax!(seq2, "a*b", vec![Literal('a'), ZeroOrMore, Literal('b')]);
|
syntax!(seq2, "a*b", vec![Literal('a'), ZeroOrMore, Literal('b')]);
|
||||||
syntax!(
|
syntax!(seq3, "*a*b*", vec![
|
||||||
seq3,
|
ZeroOrMore, Literal('a'), ZeroOrMore, Literal('b'), ZeroOrMore,
|
||||||
"*a*b*",
|
]);
|
||||||
vec![ZeroOrMore, Literal('a'), ZeroOrMore, Literal('b'), ZeroOrMore,]
|
|
||||||
);
|
|
||||||
syntax!(rseq1, "**", vec![RecursivePrefix]);
|
syntax!(rseq1, "**", vec![RecursivePrefix]);
|
||||||
syntax!(rseq2, "**/", vec![RecursivePrefix]);
|
syntax!(rseq2, "**/", vec![RecursivePrefix]);
|
||||||
syntax!(rseq3, "/**", vec![RecursiveSuffix]);
|
syntax!(rseq3, "/**", vec![RecursiveSuffix]);
|
||||||
syntax!(rseq4, "/**/", vec![RecursiveZeroOrMore]);
|
syntax!(rseq4, "/**/", vec![RecursiveZeroOrMore]);
|
||||||
syntax!(
|
syntax!(rseq5, "a/**/b", vec![
|
||||||
rseq5,
|
Literal('a'), RecursiveZeroOrMore, Literal('b'),
|
||||||
"a/**/b",
|
]);
|
||||||
vec![Literal('a'), RecursiveZeroOrMore, Literal('b'),]
|
|
||||||
);
|
|
||||||
syntax!(cls1, "[a]", vec![class('a', 'a')]);
|
syntax!(cls1, "[a]", vec![class('a', 'a')]);
|
||||||
syntax!(cls2, "[!a]", vec![classn('a', 'a')]);
|
syntax!(cls2, "[!a]", vec![classn('a', 'a')]);
|
||||||
syntax!(cls3, "[a-z]", vec![class('a', 'z')]);
|
syntax!(cls3, "[a-z]", vec![class('a', 'z')]);
|
||||||
@@ -1168,11 +1161,9 @@ mod tests {
|
|||||||
syntax!(cls9, "[a-]", vec![rclass(&[('a', 'a'), ('-', '-')])]);
|
syntax!(cls9, "[a-]", vec![rclass(&[('a', 'a'), ('-', '-')])]);
|
||||||
syntax!(cls10, "[-a-z]", vec![rclass(&[('-', '-'), ('a', 'z')])]);
|
syntax!(cls10, "[-a-z]", vec![rclass(&[('-', '-'), ('a', 'z')])]);
|
||||||
syntax!(cls11, "[a-z-]", vec![rclass(&[('a', 'z'), ('-', '-')])]);
|
syntax!(cls11, "[a-z-]", vec![rclass(&[('a', 'z'), ('-', '-')])]);
|
||||||
syntax!(
|
syntax!(cls12, "[-a-z-]", vec![
|
||||||
cls12,
|
rclass(&[('-', '-'), ('a', 'z'), ('-', '-')]),
|
||||||
"[-a-z-]",
|
]);
|
||||||
vec![rclass(&[('-', '-'), ('a', 'z'), ('-', '-')]),]
|
|
||||||
);
|
|
||||||
syntax!(cls13, "[]-z]", vec![class(']', 'z')]);
|
syntax!(cls13, "[]-z]", vec![class(']', 'z')]);
|
||||||
syntax!(cls14, "[--z]", vec![class('-', 'z')]);
|
syntax!(cls14, "[--z]", vec![class('-', 'z')]);
|
||||||
syntax!(cls15, "[ --]", vec![class(' ', '-')]);
|
syntax!(cls15, "[ --]", vec![class(' ', '-')]);
|
||||||
@@ -1190,14 +1181,26 @@ mod tests {
|
|||||||
syntaxerr!(err_range1, "[z-a]", ErrorKind::InvalidRange('z', 'a'));
|
syntaxerr!(err_range1, "[z-a]", ErrorKind::InvalidRange('z', 'a'));
|
||||||
syntaxerr!(err_range2, "[z--]", ErrorKind::InvalidRange('z', '-'));
|
syntaxerr!(err_range2, "[z--]", ErrorKind::InvalidRange('z', '-'));
|
||||||
|
|
||||||
const CASEI: Options =
|
const CASEI: Options = Options {
|
||||||
Options { casei: Some(true), litsep: None, bsesc: None };
|
casei: Some(true),
|
||||||
const SLASHLIT: Options =
|
litsep: None,
|
||||||
Options { casei: None, litsep: Some(true), bsesc: None };
|
bsesc: None,
|
||||||
const NOBSESC: Options =
|
};
|
||||||
Options { casei: None, litsep: None, bsesc: Some(false) };
|
const SLASHLIT: Options = Options {
|
||||||
const BSESC: Options =
|
casei: None,
|
||||||
Options { casei: None, litsep: None, bsesc: Some(true) };
|
litsep: Some(true),
|
||||||
|
bsesc: None,
|
||||||
|
};
|
||||||
|
const NOBSESC: Options = Options {
|
||||||
|
casei: None,
|
||||||
|
litsep: None,
|
||||||
|
bsesc: Some(false),
|
||||||
|
};
|
||||||
|
const BSESC: Options = Options {
|
||||||
|
casei: None,
|
||||||
|
litsep: None,
|
||||||
|
bsesc: Some(true),
|
||||||
|
};
|
||||||
|
|
||||||
toregex!(re_casei, "a", "(?i)^a$", &CASEI);
|
toregex!(re_casei, "a", "(?i)^a$", &CASEI);
|
||||||
|
|
||||||
@@ -1295,11 +1298,8 @@ mod tests {
|
|||||||
matches!(matchpat4, "*hello.txt", "some\\path\\to\\hello.txt");
|
matches!(matchpat4, "*hello.txt", "some\\path\\to\\hello.txt");
|
||||||
matches!(matchpat5, "*hello.txt", "/an/absolute/path/to/hello.txt");
|
matches!(matchpat5, "*hello.txt", "/an/absolute/path/to/hello.txt");
|
||||||
matches!(matchpat6, "*some/path/to/hello.txt", "some/path/to/hello.txt");
|
matches!(matchpat6, "*some/path/to/hello.txt", "some/path/to/hello.txt");
|
||||||
matches!(
|
matches!(matchpat7, "*some/path/to/hello.txt",
|
||||||
matchpat7,
|
"a/bigger/some/path/to/hello.txt");
|
||||||
"*some/path/to/hello.txt",
|
|
||||||
"a/bigger/some/path/to/hello.txt"
|
|
||||||
);
|
|
||||||
|
|
||||||
matches!(matchescape, "_[[]_[]]_[?]_[*]_!_", "_[_]_?_*_!_");
|
matches!(matchescape, "_[[]_[]]_[?]_[*]_!_", "_[_]_?_*_!_");
|
||||||
|
|
||||||
@@ -1362,44 +1362,28 @@ mod tests {
|
|||||||
nmatches!(matchnot15, "[!-]", "-");
|
nmatches!(matchnot15, "[!-]", "-");
|
||||||
nmatches!(matchnot16, "*hello.txt", "hello.txt-and-then-some");
|
nmatches!(matchnot16, "*hello.txt", "hello.txt-and-then-some");
|
||||||
nmatches!(matchnot17, "*hello.txt", "goodbye.txt");
|
nmatches!(matchnot17, "*hello.txt", "goodbye.txt");
|
||||||
nmatches!(
|
nmatches!(matchnot18, "*some/path/to/hello.txt",
|
||||||
matchnot18,
|
"some/path/to/hello.txt-and-then-some");
|
||||||
"*some/path/to/hello.txt",
|
nmatches!(matchnot19, "*some/path/to/hello.txt",
|
||||||
"some/path/to/hello.txt-and-then-some"
|
"some/other/path/to/hello.txt");
|
||||||
);
|
|
||||||
nmatches!(
|
|
||||||
matchnot19,
|
|
||||||
"*some/path/to/hello.txt",
|
|
||||||
"some/other/path/to/hello.txt"
|
|
||||||
);
|
|
||||||
nmatches!(matchnot20, "a", "foo/a");
|
nmatches!(matchnot20, "a", "foo/a");
|
||||||
nmatches!(matchnot21, "./foo", "foo");
|
nmatches!(matchnot21, "./foo", "foo");
|
||||||
nmatches!(matchnot22, "**/foo", "foofoo");
|
nmatches!(matchnot22, "**/foo", "foofoo");
|
||||||
nmatches!(matchnot23, "**/foo/bar", "foofoo/bar");
|
nmatches!(matchnot23, "**/foo/bar", "foofoo/bar");
|
||||||
nmatches!(matchnot24, "/*.c", "mozilla-sha1/sha1.c");
|
nmatches!(matchnot24, "/*.c", "mozilla-sha1/sha1.c");
|
||||||
nmatches!(matchnot25, "*.c", "mozilla-sha1/sha1.c", SLASHLIT);
|
nmatches!(matchnot25, "*.c", "mozilla-sha1/sha1.c", SLASHLIT);
|
||||||
nmatches!(
|
nmatches!(matchnot26, "**/m4/ltoptions.m4",
|
||||||
matchnot26,
|
"csharp/src/packages/repositories.config", SLASHLIT);
|
||||||
"**/m4/ltoptions.m4",
|
|
||||||
"csharp/src/packages/repositories.config",
|
|
||||||
SLASHLIT
|
|
||||||
);
|
|
||||||
nmatches!(matchnot27, "a[^0-9]b", "a0b");
|
nmatches!(matchnot27, "a[^0-9]b", "a0b");
|
||||||
nmatches!(matchnot28, "a[^0-9]b", "a9b");
|
nmatches!(matchnot28, "a[^0-9]b", "a9b");
|
||||||
nmatches!(matchnot29, "[^-]", "-");
|
nmatches!(matchnot29, "[^-]", "-");
|
||||||
nmatches!(matchnot30, "some/*/needle.txt", "some/needle.txt");
|
nmatches!(matchnot30, "some/*/needle.txt", "some/needle.txt");
|
||||||
nmatches!(
|
nmatches!(
|
||||||
matchrec31,
|
matchrec31,
|
||||||
"some/*/needle.txt",
|
"some/*/needle.txt", "some/one/two/needle.txt", SLASHLIT);
|
||||||
"some/one/two/needle.txt",
|
|
||||||
SLASHLIT
|
|
||||||
);
|
|
||||||
nmatches!(
|
nmatches!(
|
||||||
matchrec32,
|
matchrec32,
|
||||||
"some/*/needle.txt",
|
"some/*/needle.txt", "some/one/two/three/needle.txt", SLASHLIT);
|
||||||
"some/one/two/three/needle.txt",
|
|
||||||
SLASHLIT
|
|
||||||
);
|
|
||||||
|
|
||||||
macro_rules! extract {
|
macro_rules! extract {
|
||||||
($which:ident, $name:ident, $pat:expr, $expect:expr) => {
|
($which:ident, $name:ident, $pat:expr, $expect:expr) => {
|
||||||
@@ -1461,27 +1445,19 @@ mod tests {
|
|||||||
literal!(extract_lit7, "foo/bar", Some(s("foo/bar")));
|
literal!(extract_lit7, "foo/bar", Some(s("foo/bar")));
|
||||||
literal!(extract_lit8, "**/foo/bar", None);
|
literal!(extract_lit8, "**/foo/bar", None);
|
||||||
|
|
||||||
basetokens!(
|
basetokens!(extract_basetoks1, "**/foo", Some(&*vec![
|
||||||
extract_basetoks1,
|
Literal('f'), Literal('o'), Literal('o'),
|
||||||
"**/foo",
|
]));
|
||||||
Some(&*vec![Literal('f'), Literal('o'), Literal('o'),])
|
|
||||||
);
|
|
||||||
basetokens!(extract_basetoks2, "**/foo", None, CASEI);
|
basetokens!(extract_basetoks2, "**/foo", None, CASEI);
|
||||||
basetokens!(
|
basetokens!(extract_basetoks3, "**/foo", Some(&*vec![
|
||||||
extract_basetoks3,
|
Literal('f'), Literal('o'), Literal('o'),
|
||||||
"**/foo",
|
]), SLASHLIT);
|
||||||
Some(&*vec![Literal('f'), Literal('o'), Literal('o'),]),
|
|
||||||
SLASHLIT
|
|
||||||
);
|
|
||||||
basetokens!(extract_basetoks4, "*foo", None, SLASHLIT);
|
basetokens!(extract_basetoks4, "*foo", None, SLASHLIT);
|
||||||
basetokens!(extract_basetoks5, "*foo", None);
|
basetokens!(extract_basetoks5, "*foo", None);
|
||||||
basetokens!(extract_basetoks6, "**/fo*o", None);
|
basetokens!(extract_basetoks6, "**/fo*o", None);
|
||||||
basetokens!(
|
basetokens!(extract_basetoks7, "**/fo*o", Some(&*vec![
|
||||||
extract_basetoks7,
|
Literal('f'), Literal('o'), ZeroOrMore, Literal('o'),
|
||||||
"**/fo*o",
|
]), SLASHLIT);
|
||||||
Some(&*vec![Literal('f'), Literal('o'), ZeroOrMore, Literal('o'),]),
|
|
||||||
SLASHLIT
|
|
||||||
);
|
|
||||||
|
|
||||||
ext!(extract_ext1, "**/*.rs", Some(s(".rs")));
|
ext!(extract_ext1, "**/*.rs", Some(s(".rs")));
|
||||||
ext!(extract_ext2, "**/*.rs.bak", None);
|
ext!(extract_ext2, "**/*.rs.bak", None);
|
@@ -110,9 +110,6 @@ extern crate fnv;
|
|||||||
extern crate log;
|
extern crate log;
|
||||||
extern crate regex;
|
extern crate regex;
|
||||||
|
|
||||||
#[cfg(feature = "serde1")]
|
|
||||||
extern crate serde;
|
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::{BTreeMap, HashMap};
|
use std::collections::{BTreeMap, HashMap};
|
||||||
use std::error::Error as StdError;
|
use std::error::Error as StdError;
|
||||||
@@ -122,19 +119,16 @@ use std::path::Path;
|
|||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
use aho_corasick::AhoCorasick;
|
use aho_corasick::AhoCorasick;
|
||||||
use bstr::{ByteSlice, ByteVec, B};
|
use bstr::{B, ByteSlice, ByteVec};
|
||||||
use regex::bytes::{Regex, RegexBuilder, RegexSet};
|
use regex::bytes::{Regex, RegexBuilder, RegexSet};
|
||||||
|
|
||||||
|
use pathutil::{file_name, file_name_ext, normalize_path};
|
||||||
use glob::MatchStrategy;
|
use glob::MatchStrategy;
|
||||||
pub use glob::{Glob, GlobBuilder, GlobMatcher};
|
pub use glob::{Glob, GlobBuilder, GlobMatcher};
|
||||||
use pathutil::{file_name, file_name_ext, normalize_path};
|
|
||||||
|
|
||||||
mod glob;
|
mod glob;
|
||||||
mod pathutil;
|
mod pathutil;
|
||||||
|
|
||||||
#[cfg(feature = "serde1")]
|
|
||||||
mod serde_impl;
|
|
||||||
|
|
||||||
/// Represents an error that can occur when parsing a glob pattern.
|
/// Represents an error that can occur when parsing a glob pattern.
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub struct Error {
|
pub struct Error {
|
||||||
@@ -208,7 +202,9 @@ impl ErrorKind {
|
|||||||
ErrorKind::UnclosedClass => {
|
ErrorKind::UnclosedClass => {
|
||||||
"unclosed character class; missing ']'"
|
"unclosed character class; missing ']'"
|
||||||
}
|
}
|
||||||
ErrorKind::InvalidRange(_, _) => "invalid character range",
|
ErrorKind::InvalidRange(_, _) => {
|
||||||
|
"invalid character range"
|
||||||
|
}
|
||||||
ErrorKind::UnopenedAlternates => {
|
ErrorKind::UnopenedAlternates => {
|
||||||
"unopened alternate group; missing '{' \
|
"unopened alternate group; missing '{' \
|
||||||
(maybe escape '}' with '[}]'?)"
|
(maybe escape '}' with '[}]'?)"
|
||||||
@@ -220,7 +216,9 @@ impl ErrorKind {
|
|||||||
ErrorKind::NestedAlternates => {
|
ErrorKind::NestedAlternates => {
|
||||||
"nested alternate groups are not allowed"
|
"nested alternate groups are not allowed"
|
||||||
}
|
}
|
||||||
ErrorKind::DanglingEscape => "dangling '\\'",
|
ErrorKind::DanglingEscape => {
|
||||||
|
"dangling '\\'"
|
||||||
|
}
|
||||||
ErrorKind::Regex(ref err) => err,
|
ErrorKind::Regex(ref err) => err,
|
||||||
ErrorKind::__Nonexhaustive => unreachable!(),
|
ErrorKind::__Nonexhaustive => unreachable!(),
|
||||||
}
|
}
|
||||||
@@ -247,7 +245,9 @@ impl fmt::Display for ErrorKind {
|
|||||||
| ErrorKind::UnclosedAlternates
|
| ErrorKind::UnclosedAlternates
|
||||||
| ErrorKind::NestedAlternates
|
| ErrorKind::NestedAlternates
|
||||||
| ErrorKind::DanglingEscape
|
| ErrorKind::DanglingEscape
|
||||||
| ErrorKind::Regex(_) => write!(f, "{}", self.description()),
|
| ErrorKind::Regex(_) => {
|
||||||
|
write!(f, "{}", self.description())
|
||||||
|
}
|
||||||
ErrorKind::InvalidRange(s, e) => {
|
ErrorKind::InvalidRange(s, e) => {
|
||||||
write!(f, "invalid range; '{}' > '{}'", s, e)
|
write!(f, "invalid range; '{}' > '{}'", s, e)
|
||||||
}
|
}
|
||||||
@@ -262,20 +262,21 @@ fn new_regex(pat: &str) -> Result<Regex, Error> {
|
|||||||
.size_limit(10 * (1 << 20))
|
.size_limit(10 * (1 << 20))
|
||||||
.dfa_size_limit(10 * (1 << 20))
|
.dfa_size_limit(10 * (1 << 20))
|
||||||
.build()
|
.build()
|
||||||
.map_err(|err| Error {
|
.map_err(|err| {
|
||||||
glob: Some(pat.to_string()),
|
Error {
|
||||||
kind: ErrorKind::Regex(err.to_string()),
|
glob: Some(pat.to_string()),
|
||||||
|
kind: ErrorKind::Regex(err.to_string()),
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_regex_set<I, S>(pats: I) -> Result<RegexSet, Error>
|
fn new_regex_set<I, S>(pats: I) -> Result<RegexSet, Error>
|
||||||
where
|
where S: AsRef<str>, I: IntoIterator<Item=S> {
|
||||||
S: AsRef<str>,
|
RegexSet::new(pats).map_err(|err| {
|
||||||
I: IntoIterator<Item = S>,
|
Error {
|
||||||
{
|
glob: None,
|
||||||
RegexSet::new(pats).map_err(|err| Error {
|
kind: ErrorKind::Regex(err.to_string()),
|
||||||
glob: None,
|
}
|
||||||
kind: ErrorKind::Regex(err.to_string()),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,7 +294,10 @@ impl GlobSet {
|
|||||||
/// Create an empty `GlobSet`. An empty set matches nothing.
|
/// Create an empty `GlobSet`. An empty set matches nothing.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn empty() -> GlobSet {
|
pub fn empty() -> GlobSet {
|
||||||
GlobSet { len: 0, strats: vec![] }
|
GlobSet {
|
||||||
|
len: 0,
|
||||||
|
strats: vec![],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if this set is empty, and therefore matches nothing.
|
/// Returns true if this set is empty, and therefore matches nothing.
|
||||||
@@ -428,17 +432,11 @@ impl GlobSet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
debug!(
|
debug!("built glob set; {} literals, {} basenames, {} extensions, \
|
||||||
"built glob set; {} literals, {} basenames, {} extensions, \
|
|
||||||
{} prefixes, {} suffixes, {} required extensions, {} regexes",
|
{} prefixes, {} suffixes, {} required extensions, {} regexes",
|
||||||
lits.0.len(),
|
lits.0.len(), base_lits.0.len(), exts.0.len(),
|
||||||
base_lits.0.len(),
|
prefixes.literals.len(), suffixes.literals.len(),
|
||||||
exts.0.len(),
|
required_exts.0.len(), regexes.literals.len());
|
||||||
prefixes.literals.len(),
|
|
||||||
suffixes.literals.len(),
|
|
||||||
required_exts.0.len(),
|
|
||||||
regexes.literals.len()
|
|
||||||
);
|
|
||||||
Ok(GlobSet {
|
Ok(GlobSet {
|
||||||
len: pats.len(),
|
len: pats.len(),
|
||||||
strats: vec![
|
strats: vec![
|
||||||
@@ -448,8 +446,7 @@ impl GlobSet {
|
|||||||
GlobSetMatchStrategy::Suffix(suffixes.suffix()),
|
GlobSetMatchStrategy::Suffix(suffixes.suffix()),
|
||||||
GlobSetMatchStrategy::Prefix(prefixes.prefix()),
|
GlobSetMatchStrategy::Prefix(prefixes.prefix()),
|
||||||
GlobSetMatchStrategy::RequiredExtension(
|
GlobSetMatchStrategy::RequiredExtension(
|
||||||
required_exts.build()?,
|
required_exts.build()?),
|
||||||
),
|
|
||||||
GlobSetMatchStrategy::Regex(regexes.regex_set()?),
|
GlobSetMatchStrategy::Regex(regexes.regex_set()?),
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
@@ -504,7 +501,11 @@ impl<'a> Candidate<'a> {
|
|||||||
let path = normalize_path(Vec::from_path_lossy(path.as_ref()));
|
let path = normalize_path(Vec::from_path_lossy(path.as_ref()));
|
||||||
let basename = file_name(&path).unwrap_or(Cow::Borrowed(B("")));
|
let basename = file_name(&path).unwrap_or(Cow::Borrowed(B("")));
|
||||||
let ext = file_name_ext(&basename).unwrap_or(Cow::Borrowed(B("")));
|
let ext = file_name_ext(&basename).unwrap_or(Cow::Borrowed(B("")));
|
||||||
Candidate { path: path, basename: basename, ext: ext }
|
Candidate {
|
||||||
|
path: path,
|
||||||
|
basename: basename,
|
||||||
|
ext: ext,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn path_prefix(&self, max: usize) -> &[u8] {
|
fn path_prefix(&self, max: usize) -> &[u8] {
|
||||||
@@ -766,7 +767,11 @@ struct MultiStrategyBuilder {
|
|||||||
|
|
||||||
impl MultiStrategyBuilder {
|
impl MultiStrategyBuilder {
|
||||||
fn new() -> MultiStrategyBuilder {
|
fn new() -> MultiStrategyBuilder {
|
||||||
MultiStrategyBuilder { literals: vec![], map: vec![], longest: 0 }
|
MultiStrategyBuilder {
|
||||||
|
literals: vec![],
|
||||||
|
map: vec![],
|
||||||
|
longest: 0,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add(&mut self, global_index: usize, literal: String) {
|
fn add(&mut self, global_index: usize, literal: String) {
|
@@ -84,7 +84,7 @@ pub fn normalize_path(mut path: Cow<[u8]>) -> Cow<[u8]> {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use bstr::{ByteVec, B};
|
use bstr::{B, ByteVec};
|
||||||
|
|
||||||
use super::{file_name_ext, normalize_path};
|
use super::{file_name_ext, normalize_path};
|
||||||
|
|
@@ -1,13 +1,13 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "grep-cli"
|
name = "grep-cli"
|
||||||
version = "0.1.4" #:version
|
version = "0.1.3" #:version
|
||||||
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
||||||
description = """
|
description = """
|
||||||
Utilities for search oriented command line applications.
|
Utilities for search oriented command line applications.
|
||||||
"""
|
"""
|
||||||
documentation = "https://docs.rs/grep-cli"
|
documentation = "https://docs.rs/grep-cli"
|
||||||
homepage = "https://github.com/BurntSushi/ripgrep/tree/master/crates/cli"
|
homepage = "https://github.com/BurntSushi/ripgrep"
|
||||||
repository = "https://github.com/BurntSushi/ripgrep/tree/master/crates/cli"
|
repository = "https://github.com/BurntSushi/ripgrep"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
keywords = ["regex", "grep", "cli", "utility", "util"]
|
keywords = ["regex", "grep", "cli", "utility", "util"]
|
||||||
license = "Unlicense/MIT"
|
license = "Unlicense/MIT"
|
@@ -38,7 +38,10 @@ impl Default for DecompressionMatcherBuilder {
|
|||||||
impl DecompressionMatcherBuilder {
|
impl DecompressionMatcherBuilder {
|
||||||
/// Create a new builder for configuring a decompression matcher.
|
/// Create a new builder for configuring a decompression matcher.
|
||||||
pub fn new() -> DecompressionMatcherBuilder {
|
pub fn new() -> DecompressionMatcherBuilder {
|
||||||
DecompressionMatcherBuilder { commands: vec![], defaults: true }
|
DecompressionMatcherBuilder {
|
||||||
|
commands: vec![],
|
||||||
|
defaults: true,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build a matcher for determining how to decompress files.
|
/// Build a matcher for determining how to decompress files.
|
||||||
@@ -46,11 +49,12 @@ impl DecompressionMatcherBuilder {
|
|||||||
/// If there was a problem compiling the matcher, then an error is
|
/// If there was a problem compiling the matcher, then an error is
|
||||||
/// returned.
|
/// returned.
|
||||||
pub fn build(&self) -> Result<DecompressionMatcher, CommandError> {
|
pub fn build(&self) -> Result<DecompressionMatcher, CommandError> {
|
||||||
let defaults = if !self.defaults {
|
let defaults =
|
||||||
vec![]
|
if !self.defaults {
|
||||||
} else {
|
vec![]
|
||||||
default_decompression_commands()
|
} else {
|
||||||
};
|
default_decompression_commands()
|
||||||
|
};
|
||||||
let mut glob_builder = GlobSetBuilder::new();
|
let mut glob_builder = GlobSetBuilder::new();
|
||||||
let mut commands = vec![];
|
let mut commands = vec![];
|
||||||
for decomp_cmd in defaults.iter().chain(&self.commands) {
|
for decomp_cmd in defaults.iter().chain(&self.commands) {
|
||||||
@@ -89,15 +93,17 @@ impl DecompressionMatcherBuilder {
|
|||||||
program: P,
|
program: P,
|
||||||
args: I,
|
args: I,
|
||||||
) -> &mut DecompressionMatcherBuilder
|
) -> &mut DecompressionMatcherBuilder
|
||||||
where
|
where P: AsRef<OsStr>,
|
||||||
P: AsRef<OsStr>,
|
I: IntoIterator<Item=A>,
|
||||||
I: IntoIterator<Item = A>,
|
A: AsRef<OsStr>,
|
||||||
A: AsRef<OsStr>,
|
|
||||||
{
|
{
|
||||||
|
|
||||||
let glob = glob.to_string();
|
let glob = glob.to_string();
|
||||||
let bin = program.as_ref().to_os_string();
|
let bin = program.as_ref().to_os_string();
|
||||||
let args =
|
let args = args
|
||||||
args.into_iter().map(|a| a.as_ref().to_os_string()).collect();
|
.into_iter()
|
||||||
|
.map(|a| a.as_ref().to_os_string())
|
||||||
|
.collect();
|
||||||
self.commands.push(DecompressionCommand { glob, bin, args });
|
self.commands.push(DecompressionCommand { glob, bin, args });
|
||||||
self
|
self
|
||||||
}
|
}
|
@@ -95,61 +95,51 @@ pub fn unescape(s: &str) -> Vec<u8> {
|
|||||||
let mut state = Literal;
|
let mut state = Literal;
|
||||||
for c in s.chars() {
|
for c in s.chars() {
|
||||||
match state {
|
match state {
|
||||||
Escape => match c {
|
Escape => {
|
||||||
'\\' => {
|
match c {
|
||||||
bytes.push(b'\\');
|
'\\' => { bytes.push(b'\\'); state = Literal; }
|
||||||
state = Literal;
|
'n' => { bytes.push(b'\n'); state = Literal; }
|
||||||
|
'r' => { bytes.push(b'\r'); state = Literal; }
|
||||||
|
't' => { bytes.push(b'\t'); state = Literal; }
|
||||||
|
'x' => { state = HexFirst; }
|
||||||
|
c => {
|
||||||
|
bytes.extend(format!(r"\{}", c).into_bytes());
|
||||||
|
state = Literal;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
'n' => {
|
}
|
||||||
bytes.push(b'\n');
|
HexFirst => {
|
||||||
state = Literal;
|
match c {
|
||||||
|
'0'..='9' | 'A'..='F' | 'a'..='f' => {
|
||||||
|
state = HexSecond(c);
|
||||||
|
}
|
||||||
|
c => {
|
||||||
|
bytes.extend(format!(r"\x{}", c).into_bytes());
|
||||||
|
state = Literal;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
'r' => {
|
}
|
||||||
bytes.push(b'\r');
|
HexSecond(first) => {
|
||||||
state = Literal;
|
match c {
|
||||||
|
'0'..='9' | 'A'..='F' | 'a'..='f' => {
|
||||||
|
let ordinal = format!("{}{}", first, c);
|
||||||
|
let byte = u8::from_str_radix(&ordinal, 16).unwrap();
|
||||||
|
bytes.push(byte);
|
||||||
|
state = Literal;
|
||||||
|
}
|
||||||
|
c => {
|
||||||
|
let original = format!(r"\x{}{}", first, c);
|
||||||
|
bytes.extend(original.into_bytes());
|
||||||
|
state = Literal;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
't' => {
|
}
|
||||||
bytes.push(b'\t');
|
Literal => {
|
||||||
state = Literal;
|
match c {
|
||||||
|
'\\' => { state = Escape; }
|
||||||
|
c => { bytes.extend(c.to_string().as_bytes()); }
|
||||||
}
|
}
|
||||||
'x' => {
|
}
|
||||||
state = HexFirst;
|
|
||||||
}
|
|
||||||
c => {
|
|
||||||
bytes.extend(format!(r"\{}", c).into_bytes());
|
|
||||||
state = Literal;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
HexFirst => match c {
|
|
||||||
'0'..='9' | 'A'..='F' | 'a'..='f' => {
|
|
||||||
state = HexSecond(c);
|
|
||||||
}
|
|
||||||
c => {
|
|
||||||
bytes.extend(format!(r"\x{}", c).into_bytes());
|
|
||||||
state = Literal;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
HexSecond(first) => match c {
|
|
||||||
'0'..='9' | 'A'..='F' | 'a'..='f' => {
|
|
||||||
let ordinal = format!("{}{}", first, c);
|
|
||||||
let byte = u8::from_str_radix(&ordinal, 16).unwrap();
|
|
||||||
bytes.push(byte);
|
|
||||||
state = Literal;
|
|
||||||
}
|
|
||||||
c => {
|
|
||||||
let original = format!(r"\x{}{}", first, c);
|
|
||||||
bytes.extend(original.into_bytes());
|
|
||||||
state = Literal;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Literal => match c {
|
|
||||||
'\\' => {
|
|
||||||
state = Escape;
|
|
||||||
}
|
|
||||||
c => {
|
|
||||||
bytes.extend(c.to_string().as_bytes());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match state {
|
match state {
|
@@ -46,9 +46,7 @@ impl ParseSizeError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl error::Error for ParseSizeError {
|
impl error::Error for ParseSizeError {
|
||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str { "invalid size" }
|
||||||
"invalid size"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for ParseSizeError {
|
impl fmt::Display for ParseSizeError {
|
||||||
@@ -56,19 +54,26 @@ impl fmt::Display for ParseSizeError {
|
|||||||
use self::ParseSizeErrorKind::*;
|
use self::ParseSizeErrorKind::*;
|
||||||
|
|
||||||
match self.kind {
|
match self.kind {
|
||||||
InvalidFormat => write!(
|
InvalidFormat => {
|
||||||
f,
|
write!(
|
||||||
"invalid format for size '{}', which should be a sequence \
|
f,
|
||||||
|
"invalid format for size '{}', which should be a sequence \
|
||||||
of digits followed by an optional 'K', 'M' or 'G' \
|
of digits followed by an optional 'K', 'M' or 'G' \
|
||||||
suffix",
|
suffix",
|
||||||
self.original
|
self.original
|
||||||
),
|
)
|
||||||
InvalidInt(ref err) => write!(
|
}
|
||||||
f,
|
InvalidInt(ref err) => {
|
||||||
"invalid integer found in size '{}': {}",
|
write!(
|
||||||
self.original, err
|
f,
|
||||||
),
|
"invalid integer found in size '{}': {}",
|
||||||
Overflow => write!(f, "size too big in '{}'", self.original),
|
self.original,
|
||||||
|
err
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Overflow => {
|
||||||
|
write!(f, "size too big in '{}'", self.original)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -99,16 +104,17 @@ pub fn parse_human_readable_size(size: &str) -> Result<u64, ParseSizeError> {
|
|||||||
Some(caps) => caps,
|
Some(caps) => caps,
|
||||||
None => return Err(ParseSizeError::format(size)),
|
None => return Err(ParseSizeError::format(size)),
|
||||||
};
|
};
|
||||||
let value: u64 =
|
let value: u64 = caps[1].parse().map_err(|err| {
|
||||||
caps[1].parse().map_err(|err| ParseSizeError::int(size, err))?;
|
ParseSizeError::int(size, err)
|
||||||
|
})?;
|
||||||
let suffix = match caps.get(2) {
|
let suffix = match caps.get(2) {
|
||||||
None => return Ok(value),
|
None => return Ok(value),
|
||||||
Some(cap) => cap.as_str(),
|
Some(cap) => cap.as_str(),
|
||||||
};
|
};
|
||||||
let bytes = match suffix {
|
let bytes = match suffix {
|
||||||
"K" => value.checked_mul(1 << 10),
|
"K" => value.checked_mul(1<<10),
|
||||||
"M" => value.checked_mul(1 << 20),
|
"M" => value.checked_mul(1<<20),
|
||||||
"G" => value.checked_mul(1 << 30),
|
"G" => value.checked_mul(1<<30),
|
||||||
// Because if the regex matches this group, it must be [KMG].
|
// Because if the regex matches this group, it must be [KMG].
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
@@ -128,19 +134,19 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn suffix_k() {
|
fn suffix_k() {
|
||||||
let x = parse_human_readable_size("123K").unwrap();
|
let x = parse_human_readable_size("123K").unwrap();
|
||||||
assert_eq!(123 * (1 << 10), x);
|
assert_eq!(123 * (1<<10), x);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn suffix_m() {
|
fn suffix_m() {
|
||||||
let x = parse_human_readable_size("123M").unwrap();
|
let x = parse_human_readable_size("123M").unwrap();
|
||||||
assert_eq!(123 * (1 << 20), x);
|
assert_eq!(123 * (1<<20), x);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn suffix_g() {
|
fn suffix_g() {
|
||||||
let x = parse_human_readable_size("123G").unwrap();
|
let x = parse_human_readable_size("123G").unwrap();
|
||||||
assert_eq!(123 * (1 << 30), x);
|
assert_eq!(123 * (1<<30), x);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
@@ -179,18 +179,20 @@ mod process;
|
|||||||
mod wtr;
|
mod wtr;
|
||||||
|
|
||||||
pub use decompress::{
|
pub use decompress::{
|
||||||
DecompressionMatcher, DecompressionMatcherBuilder, DecompressionReader,
|
DecompressionMatcher, DecompressionMatcherBuilder,
|
||||||
DecompressionReaderBuilder,
|
DecompressionReader, DecompressionReaderBuilder,
|
||||||
};
|
};
|
||||||
pub use escape::{escape, escape_os, unescape, unescape_os};
|
pub use escape::{escape, escape_os, unescape, unescape_os};
|
||||||
pub use human::{parse_human_readable_size, ParseSizeError};
|
pub use human::{ParseSizeError, parse_human_readable_size};
|
||||||
pub use pattern::{
|
pub use pattern::{
|
||||||
pattern_from_bytes, pattern_from_os, patterns_from_path,
|
InvalidPatternError,
|
||||||
patterns_from_reader, patterns_from_stdin, InvalidPatternError,
|
pattern_from_os, pattern_from_bytes,
|
||||||
|
patterns_from_path, patterns_from_reader, patterns_from_stdin,
|
||||||
};
|
};
|
||||||
pub use process::{CommandError, CommandReader, CommandReaderBuilder};
|
pub use process::{CommandError, CommandReader, CommandReaderBuilder};
|
||||||
pub use wtr::{
|
pub use wtr::{
|
||||||
stdout, stdout_buffered_block, stdout_buffered_line, StandardStream,
|
StandardStream,
|
||||||
|
stdout, stdout_buffered_line, stdout_buffered_block,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Returns true if and only if stdin is believed to be readable.
|
/// Returns true if and only if stdin is believed to be readable.
|
||||||
@@ -203,8 +205,8 @@ pub use wtr::{
|
|||||||
pub fn is_readable_stdin() -> bool {
|
pub fn is_readable_stdin() -> bool {
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn imp() -> bool {
|
fn imp() -> bool {
|
||||||
use same_file::Handle;
|
|
||||||
use std::os::unix::fs::FileTypeExt;
|
use std::os::unix::fs::FileTypeExt;
|
||||||
|
use same_file::Handle;
|
||||||
|
|
||||||
let ft = match Handle::stdin().and_then(|h| h.as_file().metadata()) {
|
let ft = match Handle::stdin().and_then(|h| h.as_file().metadata()) {
|
||||||
Err(_) => return false,
|
Err(_) => return false,
|
@@ -29,9 +29,7 @@ impl InvalidPatternError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl error::Error for InvalidPatternError {
|
impl error::Error for InvalidPatternError {
|
||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str { "invalid pattern" }
|
||||||
"invalid pattern"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for InvalidPatternError {
|
impl fmt::Display for InvalidPatternError {
|
||||||
@@ -41,7 +39,8 @@ impl fmt::Display for InvalidPatternError {
|
|||||||
"found invalid UTF-8 in pattern at byte offset {} \
|
"found invalid UTF-8 in pattern at byte offset {} \
|
||||||
(use hex escape sequences to match arbitrary bytes \
|
(use hex escape sequences to match arbitrary bytes \
|
||||||
in a pattern, e.g., \\xFF): '{}'",
|
in a pattern, e.g., \\xFF): '{}'",
|
||||||
self.valid_up_to, self.original,
|
self.valid_up_to,
|
||||||
|
self.original,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -80,9 +79,11 @@ pub fn pattern_from_os(pattern: &OsStr) -> Result<&str, InvalidPatternError> {
|
|||||||
pub fn pattern_from_bytes(
|
pub fn pattern_from_bytes(
|
||||||
pattern: &[u8],
|
pattern: &[u8],
|
||||||
) -> Result<&str, InvalidPatternError> {
|
) -> Result<&str, InvalidPatternError> {
|
||||||
str::from_utf8(pattern).map_err(|err| InvalidPatternError {
|
str::from_utf8(pattern).map_err(|err| {
|
||||||
original: escape(pattern),
|
InvalidPatternError {
|
||||||
valid_up_to: err.valid_up_to(),
|
original: escape(pattern),
|
||||||
|
valid_up_to: err.valid_up_to(),
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,7 +119,10 @@ pub fn patterns_from_stdin() -> io::Result<Vec<String>> {
|
|||||||
let stdin = io::stdin();
|
let stdin = io::stdin();
|
||||||
let locked = stdin.lock();
|
let locked = stdin.lock();
|
||||||
patterns_from_reader(locked).map_err(|err| {
|
patterns_from_reader(locked).map_err(|err| {
|
||||||
io::Error::new(io::ErrorKind::Other, format!("<stdin>:{}", err))
|
io::Error::new(
|
||||||
|
io::ErrorKind::Other,
|
||||||
|
format!("<stdin>:{}", err),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,10 +166,12 @@ pub fn patterns_from_reader<R: io::Read>(rdr: R) -> io::Result<Vec<String>> {
|
|||||||
patterns.push(pattern.to_string());
|
patterns.push(pattern.to_string());
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
Err(err) => Err(io::Error::new(
|
Err(err) => {
|
||||||
io::ErrorKind::Other,
|
Err(io::Error::new(
|
||||||
format!("{}: {}", line_number, err),
|
io::ErrorKind::Other,
|
||||||
)),
|
format!("{}: {}", line_number, err),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
Ok(patterns)
|
Ok(patterns)
|
||||||
@@ -185,8 +191,8 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn os() {
|
fn os() {
|
||||||
use std::ffi::OsStr;
|
|
||||||
use std::os::unix::ffi::OsStrExt;
|
use std::os::unix::ffi::OsStrExt;
|
||||||
|
use std::ffi::OsStr;
|
||||||
|
|
||||||
let pat = OsStr::from_bytes(b"abc\xFFxyz");
|
let pat = OsStr::from_bytes(b"abc\xFFxyz");
|
||||||
let err = pattern_from_os(pat).unwrap_err();
|
let err = pattern_from_os(pat).unwrap_err();
|
@@ -33,9 +33,7 @@ impl CommandError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl error::Error for CommandError {
|
impl error::Error for CommandError {
|
||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str { "command error" }
|
||||||
"command error"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for CommandError {
|
impl fmt::Display for CommandError {
|
||||||
@@ -48,12 +46,7 @@ impl fmt::Display for CommandError {
|
|||||||
write!(f, "<stderr is empty>")
|
write!(f, "<stderr is empty>")
|
||||||
} else {
|
} else {
|
||||||
let div = iter::repeat('-').take(79).collect::<String>();
|
let div = iter::repeat('-').take(79).collect::<String>();
|
||||||
write!(
|
write!(f, "\n{div}\n{msg}\n{div}", div=div, msg=msg.trim())
|
||||||
f,
|
|
||||||
"\n{div}\n{msg}\n{div}",
|
|
||||||
div = div,
|
|
||||||
msg = msg.trim()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -108,11 +101,12 @@ impl CommandReaderBuilder {
|
|||||||
.stderr(process::Stdio::piped())
|
.stderr(process::Stdio::piped())
|
||||||
.spawn()?;
|
.spawn()?;
|
||||||
let stdout = child.stdout.take().unwrap();
|
let stdout = child.stdout.take().unwrap();
|
||||||
let stderr = if self.async_stderr {
|
let stderr =
|
||||||
StderrReader::async(child.stderr.take().unwrap())
|
if self.async_stderr {
|
||||||
} else {
|
StderrReader::async(child.stderr.take().unwrap())
|
||||||
StderrReader::sync(child.stderr.take().unwrap())
|
} else {
|
||||||
};
|
StderrReader::sync(child.stderr.take().unwrap())
|
||||||
|
};
|
||||||
Ok(CommandReader {
|
Ok(CommandReader {
|
||||||
child: child,
|
child: child,
|
||||||
stdout: stdout,
|
stdout: stdout,
|
||||||
@@ -232,8 +226,9 @@ enum StderrReader {
|
|||||||
impl StderrReader {
|
impl StderrReader {
|
||||||
/// Create a reader for stderr that reads contents asynchronously.
|
/// Create a reader for stderr that reads contents asynchronously.
|
||||||
fn async(mut stderr: process::ChildStderr) -> StderrReader {
|
fn async(mut stderr: process::ChildStderr) -> StderrReader {
|
||||||
let handle =
|
let handle = thread::spawn(move || {
|
||||||
thread::spawn(move || stderr_to_command_error(&mut stderr));
|
stderr_to_command_error(&mut stderr)
|
||||||
|
});
|
||||||
StderrReader::Async(Some(handle))
|
StderrReader::Async(Some(handle))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,7 +247,9 @@ impl StderrReader {
|
|||||||
let handle = handle
|
let handle = handle
|
||||||
.take()
|
.take()
|
||||||
.expect("read_to_end cannot be called more than once");
|
.expect("read_to_end cannot be called more than once");
|
||||||
handle.join().expect("stderr reading thread does not panic")
|
handle
|
||||||
|
.join()
|
||||||
|
.expect("stderr reading thread does not panic")
|
||||||
}
|
}
|
||||||
StderrReader::Sync(ref mut stderr) => {
|
StderrReader::Sync(ref mut stderr) => {
|
||||||
stderr_to_command_error(stderr)
|
stderr_to_command_error(stderr)
|
@@ -1,13 +1,13 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "grep-matcher"
|
name = "grep-matcher"
|
||||||
version = "0.1.4" #:version
|
version = "0.1.3" #:version
|
||||||
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
||||||
description = """
|
description = """
|
||||||
A trait for regular expressions, with a focus on line oriented search.
|
A trait for regular expressions, with a focus on line oriented search.
|
||||||
"""
|
"""
|
||||||
documentation = "https://docs.rs/grep-matcher"
|
documentation = "https://docs.rs/grep-matcher"
|
||||||
homepage = "https://github.com/BurntSushi/ripgrep/tree/master/crates/matcher"
|
homepage = "https://github.com/BurntSushi/ripgrep"
|
||||||
repository = "https://github.com/BurntSushi/ripgrep/tree/master/crates/matcher"
|
repository = "https://github.com/BurntSushi/ripgrep"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
keywords = ["regex", "pattern", "trait"]
|
keywords = ["regex", "pattern", "trait"]
|
||||||
license = "Unlicense/MIT"
|
license = "Unlicense/MIT"
|
@@ -19,7 +19,7 @@ pub fn interpolate<A, N>(
|
|||||||
dst: &mut Vec<u8>,
|
dst: &mut Vec<u8>,
|
||||||
) where
|
) where
|
||||||
A: FnMut(usize, &mut Vec<u8>),
|
A: FnMut(usize, &mut Vec<u8>),
|
||||||
N: FnMut(&str) -> Option<usize>,
|
N: FnMut(&str) -> Option<usize>
|
||||||
{
|
{
|
||||||
while !replacement.is_empty() {
|
while !replacement.is_empty() {
|
||||||
match memchr(b'$', replacement) {
|
match memchr(b'$', replacement) {
|
||||||
@@ -134,14 +134,14 @@ fn find_cap_ref(replacement: &[u8]) -> Option<CaptureRef> {
|
|||||||
/// Returns true if and only if the given byte is allowed in a capture name.
|
/// Returns true if and only if the given byte is allowed in a capture name.
|
||||||
fn is_valid_cap_letter(b: &u8) -> bool {
|
fn is_valid_cap_letter(b: &u8) -> bool {
|
||||||
match *b {
|
match *b {
|
||||||
b'0'..=b'9' | b'a'..=b'z' | b'A'..=b'Z' | b'_' => true,
|
b'0' ..= b'9' | b'a' ..= b'z' | b'A' ..= b'Z' | b'_' => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{find_cap_ref, interpolate, CaptureRef};
|
use super::{CaptureRef, find_cap_ref, interpolate};
|
||||||
|
|
||||||
macro_rules! find {
|
macro_rules! find {
|
||||||
($name:ident, $text:expr) => {
|
($name:ident, $text:expr) => {
|
||||||
@@ -211,7 +211,7 @@ mod tests {
|
|||||||
fn $name() {
|
fn $name() {
|
||||||
assert_eq!($expected, interpolate_string($map, $caps, $hay));
|
assert_eq!($expected, interpolate_string($map, $caps, $hay));
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interp!(
|
interp!(
|
@@ -278,7 +278,7 @@ impl LineTerminator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for LineTerminator {
|
impl Default for LineTerminator {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn default() -> LineTerminator {
|
fn default() -> LineTerminator {
|
||||||
LineTerminator::byte(b'\n')
|
LineTerminator::byte(b'\n')
|
||||||
@@ -439,8 +439,7 @@ pub trait Captures {
|
|||||||
haystack: &[u8],
|
haystack: &[u8],
|
||||||
replacement: &[u8],
|
replacement: &[u8],
|
||||||
dst: &mut Vec<u8>,
|
dst: &mut Vec<u8>,
|
||||||
) where
|
) where F: FnMut(&str) -> Option<usize>
|
||||||
F: FnMut(&str) -> Option<usize>,
|
|
||||||
{
|
{
|
||||||
interpolate(
|
interpolate(
|
||||||
replacement,
|
replacement,
|
||||||
@@ -464,18 +463,12 @@ pub struct NoCaptures(());
|
|||||||
|
|
||||||
impl NoCaptures {
|
impl NoCaptures {
|
||||||
/// Create an empty set of capturing groups.
|
/// Create an empty set of capturing groups.
|
||||||
pub fn new() -> NoCaptures {
|
pub fn new() -> NoCaptures { NoCaptures(()) }
|
||||||
NoCaptures(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Captures for NoCaptures {
|
impl Captures for NoCaptures {
|
||||||
fn len(&self) -> usize {
|
fn len(&self) -> usize { 0 }
|
||||||
0
|
fn get(&self, _: usize) -> Option<Match> { None }
|
||||||
}
|
|
||||||
fn get(&self, _: usize) -> Option<Match> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// NoError provides an error type for matchers that never produce errors.
|
/// NoError provides an error type for matchers that never produce errors.
|
||||||
@@ -488,9 +481,7 @@ impl Captures for NoCaptures {
|
|||||||
pub struct NoError(());
|
pub struct NoError(());
|
||||||
|
|
||||||
impl ::std::error::Error for NoError {
|
impl ::std::error::Error for NoError {
|
||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str { "no error" }
|
||||||
"no error"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for NoError {
|
impl fmt::Display for NoError {
|
||||||
@@ -608,7 +599,10 @@ pub trait Matcher {
|
|||||||
///
|
///
|
||||||
/// The text encoding of `haystack` is not strictly specified. Matchers are
|
/// The text encoding of `haystack` is not strictly specified. Matchers are
|
||||||
/// advised to assume UTF-8, or at worst, some ASCII compatible encoding.
|
/// advised to assume UTF-8, or at worst, some ASCII compatible encoding.
|
||||||
fn find(&self, haystack: &[u8]) -> Result<Option<Match>, Self::Error> {
|
fn find(
|
||||||
|
&self,
|
||||||
|
haystack: &[u8],
|
||||||
|
) -> Result<Option<Match>, Self::Error> {
|
||||||
self.find_at(haystack, 0)
|
self.find_at(haystack, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -620,8 +614,7 @@ pub trait Matcher {
|
|||||||
haystack: &[u8],
|
haystack: &[u8],
|
||||||
mut matched: F,
|
mut matched: F,
|
||||||
) -> Result<(), Self::Error>
|
) -> Result<(), Self::Error>
|
||||||
where
|
where F: FnMut(Match) -> bool
|
||||||
F: FnMut(Match) -> bool,
|
|
||||||
{
|
{
|
||||||
self.try_find_iter(haystack, |m| Ok(matched(m)))
|
self.try_find_iter(haystack, |m| Ok(matched(m)))
|
||||||
.map(|r: Result<(), ()>| r.unwrap())
|
.map(|r: Result<(), ()>| r.unwrap())
|
||||||
@@ -639,8 +632,7 @@ pub trait Matcher {
|
|||||||
haystack: &[u8],
|
haystack: &[u8],
|
||||||
mut matched: F,
|
mut matched: F,
|
||||||
) -> Result<Result<(), E>, Self::Error>
|
) -> Result<Result<(), E>, Self::Error>
|
||||||
where
|
where F: FnMut(Match) -> Result<bool, E>
|
||||||
F: FnMut(Match) -> Result<bool, E>,
|
|
||||||
{
|
{
|
||||||
let mut last_end = 0;
|
let mut last_end = 0;
|
||||||
let mut last_match = None;
|
let mut last_match = None;
|
||||||
@@ -698,8 +690,7 @@ pub trait Matcher {
|
|||||||
caps: &mut Self::Captures,
|
caps: &mut Self::Captures,
|
||||||
mut matched: F,
|
mut matched: F,
|
||||||
) -> Result<(), Self::Error>
|
) -> Result<(), Self::Error>
|
||||||
where
|
where F: FnMut(&Self::Captures) -> bool
|
||||||
F: FnMut(&Self::Captures) -> bool,
|
|
||||||
{
|
{
|
||||||
self.try_captures_iter(haystack, caps, |caps| Ok(matched(caps)))
|
self.try_captures_iter(haystack, caps, |caps| Ok(matched(caps)))
|
||||||
.map(|r: Result<(), ()>| r.unwrap())
|
.map(|r: Result<(), ()>| r.unwrap())
|
||||||
@@ -718,8 +709,7 @@ pub trait Matcher {
|
|||||||
caps: &mut Self::Captures,
|
caps: &mut Self::Captures,
|
||||||
mut matched: F,
|
mut matched: F,
|
||||||
) -> Result<Result<(), E>, Self::Error>
|
) -> Result<Result<(), E>, Self::Error>
|
||||||
where
|
where F: FnMut(&Self::Captures) -> Result<bool, E>
|
||||||
F: FnMut(&Self::Captures) -> Result<bool, E>,
|
|
||||||
{
|
{
|
||||||
let mut last_end = 0;
|
let mut last_end = 0;
|
||||||
let mut last_match = None;
|
let mut last_match = None;
|
||||||
@@ -797,8 +787,7 @@ pub trait Matcher {
|
|||||||
dst: &mut Vec<u8>,
|
dst: &mut Vec<u8>,
|
||||||
mut append: F,
|
mut append: F,
|
||||||
) -> Result<(), Self::Error>
|
) -> Result<(), Self::Error>
|
||||||
where
|
where F: FnMut(Match, &mut Vec<u8>) -> bool
|
||||||
F: FnMut(Match, &mut Vec<u8>) -> bool,
|
|
||||||
{
|
{
|
||||||
let mut last_match = 0;
|
let mut last_match = 0;
|
||||||
self.find_iter(haystack, |m| {
|
self.find_iter(haystack, |m| {
|
||||||
@@ -821,8 +810,7 @@ pub trait Matcher {
|
|||||||
dst: &mut Vec<u8>,
|
dst: &mut Vec<u8>,
|
||||||
mut append: F,
|
mut append: F,
|
||||||
) -> Result<(), Self::Error>
|
) -> Result<(), Self::Error>
|
||||||
where
|
where F: FnMut(&Self::Captures, &mut Vec<u8>) -> bool
|
||||||
F: FnMut(&Self::Captures, &mut Vec<u8>) -> bool,
|
|
||||||
{
|
{
|
||||||
let mut last_match = 0;
|
let mut last_match = 0;
|
||||||
self.captures_iter(haystack, caps, |caps| {
|
self.captures_iter(haystack, caps, |caps| {
|
||||||
@@ -1024,7 +1012,10 @@ impl<'a, M: Matcher> Matcher for &'a M {
|
|||||||
(*self).capture_count()
|
(*self).capture_count()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find(&self, haystack: &[u8]) -> Result<Option<Match>, Self::Error> {
|
fn find(
|
||||||
|
&self,
|
||||||
|
haystack: &[u8]
|
||||||
|
) -> Result<Option<Match>, Self::Error> {
|
||||||
(*self).find(haystack)
|
(*self).find(haystack)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1033,8 +1024,7 @@ impl<'a, M: Matcher> Matcher for &'a M {
|
|||||||
haystack: &[u8],
|
haystack: &[u8],
|
||||||
matched: F,
|
matched: F,
|
||||||
) -> Result<(), Self::Error>
|
) -> Result<(), Self::Error>
|
||||||
where
|
where F: FnMut(Match) -> bool
|
||||||
F: FnMut(Match) -> bool,
|
|
||||||
{
|
{
|
||||||
(*self).find_iter(haystack, matched)
|
(*self).find_iter(haystack, matched)
|
||||||
}
|
}
|
||||||
@@ -1044,8 +1034,7 @@ impl<'a, M: Matcher> Matcher for &'a M {
|
|||||||
haystack: &[u8],
|
haystack: &[u8],
|
||||||
matched: F,
|
matched: F,
|
||||||
) -> Result<Result<(), E>, Self::Error>
|
) -> Result<Result<(), E>, Self::Error>
|
||||||
where
|
where F: FnMut(Match) -> Result<bool, E>
|
||||||
F: FnMut(Match) -> Result<bool, E>,
|
|
||||||
{
|
{
|
||||||
(*self).try_find_iter(haystack, matched)
|
(*self).try_find_iter(haystack, matched)
|
||||||
}
|
}
|
||||||
@@ -1064,8 +1053,7 @@ impl<'a, M: Matcher> Matcher for &'a M {
|
|||||||
caps: &mut Self::Captures,
|
caps: &mut Self::Captures,
|
||||||
matched: F,
|
matched: F,
|
||||||
) -> Result<(), Self::Error>
|
) -> Result<(), Self::Error>
|
||||||
where
|
where F: FnMut(&Self::Captures) -> bool
|
||||||
F: FnMut(&Self::Captures) -> bool,
|
|
||||||
{
|
{
|
||||||
(*self).captures_iter(haystack, caps, matched)
|
(*self).captures_iter(haystack, caps, matched)
|
||||||
}
|
}
|
||||||
@@ -1076,8 +1064,7 @@ impl<'a, M: Matcher> Matcher for &'a M {
|
|||||||
caps: &mut Self::Captures,
|
caps: &mut Self::Captures,
|
||||||
matched: F,
|
matched: F,
|
||||||
) -> Result<Result<(), E>, Self::Error>
|
) -> Result<Result<(), E>, Self::Error>
|
||||||
where
|
where F: FnMut(&Self::Captures) -> Result<bool, E>
|
||||||
F: FnMut(&Self::Captures) -> Result<bool, E>,
|
|
||||||
{
|
{
|
||||||
(*self).try_captures_iter(haystack, caps, matched)
|
(*self).try_captures_iter(haystack, caps, matched)
|
||||||
}
|
}
|
||||||
@@ -1088,8 +1075,7 @@ impl<'a, M: Matcher> Matcher for &'a M {
|
|||||||
dst: &mut Vec<u8>,
|
dst: &mut Vec<u8>,
|
||||||
append: F,
|
append: F,
|
||||||
) -> Result<(), Self::Error>
|
) -> Result<(), Self::Error>
|
||||||
where
|
where F: FnMut(Match, &mut Vec<u8>) -> bool
|
||||||
F: FnMut(Match, &mut Vec<u8>) -> bool,
|
|
||||||
{
|
{
|
||||||
(*self).replace(haystack, dst, append)
|
(*self).replace(haystack, dst, append)
|
||||||
}
|
}
|
||||||
@@ -1101,8 +1087,7 @@ impl<'a, M: Matcher> Matcher for &'a M {
|
|||||||
dst: &mut Vec<u8>,
|
dst: &mut Vec<u8>,
|
||||||
append: F,
|
append: F,
|
||||||
) -> Result<(), Self::Error>
|
) -> Result<(), Self::Error>
|
||||||
where
|
where F: FnMut(&Self::Captures, &mut Vec<u8>) -> bool
|
||||||
F: FnMut(&Self::Captures, &mut Vec<u8>) -> bool,
|
|
||||||
{
|
{
|
||||||
(*self).replace_with_captures(haystack, caps, dst, append)
|
(*self).replace_with_captures(haystack, caps, dst, append)
|
||||||
}
|
}
|
||||||
@@ -1114,7 +1099,7 @@ impl<'a, M: Matcher> Matcher for &'a M {
|
|||||||
fn is_match_at(
|
fn is_match_at(
|
||||||
&self,
|
&self,
|
||||||
haystack: &[u8],
|
haystack: &[u8],
|
||||||
at: usize,
|
at: usize
|
||||||
) -> Result<bool, Self::Error> {
|
) -> Result<bool, Self::Error> {
|
||||||
(*self).is_match_at(haystack, at)
|
(*self).is_match_at(haystack, at)
|
||||||
}
|
}
|
@@ -25,22 +25,18 @@ fn find() {
|
|||||||
fn find_iter() {
|
fn find_iter() {
|
||||||
let matcher = matcher(r"(\w+)\s+(\w+)");
|
let matcher = matcher(r"(\w+)\s+(\w+)");
|
||||||
let mut matches = vec![];
|
let mut matches = vec![];
|
||||||
matcher
|
matcher.find_iter(b"aa bb cc dd", |m| {
|
||||||
.find_iter(b"aa bb cc dd", |m| {
|
matches.push(m);
|
||||||
matches.push(m);
|
true
|
||||||
true
|
}).unwrap();
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(matches, vec![m(0, 5), m(6, 11)]);
|
assert_eq!(matches, vec![m(0, 5), m(6, 11)]);
|
||||||
|
|
||||||
// Test that find_iter respects short circuiting.
|
// Test that find_iter respects short circuiting.
|
||||||
matches.clear();
|
matches.clear();
|
||||||
matcher
|
matcher.find_iter(b"aa bb cc dd", |m| {
|
||||||
.find_iter(b"aa bb cc dd", |m| {
|
matches.push(m);
|
||||||
matches.push(m);
|
false
|
||||||
false
|
}).unwrap();
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(matches, vec![m(0, 5)]);
|
assert_eq!(matches, vec![m(0, 5)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,17 +47,14 @@ fn try_find_iter() {
|
|||||||
|
|
||||||
let matcher = matcher(r"(\w+)\s+(\w+)");
|
let matcher = matcher(r"(\w+)\s+(\w+)");
|
||||||
let mut matches = vec![];
|
let mut matches = vec![];
|
||||||
let err = matcher
|
let err = matcher.try_find_iter(b"aa bb cc dd", |m| {
|
||||||
.try_find_iter(b"aa bb cc dd", |m| {
|
if matches.is_empty() {
|
||||||
if matches.is_empty() {
|
matches.push(m);
|
||||||
matches.push(m);
|
Ok(true)
|
||||||
Ok(true)
|
} else {
|
||||||
} else {
|
Err(MyError)
|
||||||
Err(MyError)
|
}
|
||||||
}
|
}).unwrap().unwrap_err();
|
||||||
})
|
|
||||||
.unwrap()
|
|
||||||
.unwrap_err();
|
|
||||||
assert_eq!(matches, vec![m(0, 5)]);
|
assert_eq!(matches, vec![m(0, 5)]);
|
||||||
assert_eq!(err, MyError);
|
assert_eq!(err, MyError);
|
||||||
}
|
}
|
||||||
@@ -96,30 +89,28 @@ fn captures_iter() {
|
|||||||
let matcher = matcher(r"(?P<a>\w+)\s+(?P<b>\w+)");
|
let matcher = matcher(r"(?P<a>\w+)\s+(?P<b>\w+)");
|
||||||
let mut caps = matcher.new_captures().unwrap();
|
let mut caps = matcher.new_captures().unwrap();
|
||||||
let mut matches = vec![];
|
let mut matches = vec![];
|
||||||
matcher
|
matcher.captures_iter(b"aa bb cc dd", &mut caps, |caps| {
|
||||||
.captures_iter(b"aa bb cc dd", &mut caps, |caps| {
|
matches.push(caps.get(0).unwrap());
|
||||||
matches.push(caps.get(0).unwrap());
|
matches.push(caps.get(1).unwrap());
|
||||||
matches.push(caps.get(1).unwrap());
|
matches.push(caps.get(2).unwrap());
|
||||||
matches.push(caps.get(2).unwrap());
|
true
|
||||||
true
|
}).unwrap();
|
||||||
})
|
assert_eq!(matches, vec![
|
||||||
.unwrap();
|
m(0, 5), m(0, 2), m(3, 5),
|
||||||
assert_eq!(
|
m(6, 11), m(6, 8), m(9, 11),
|
||||||
matches,
|
]);
|
||||||
vec![m(0, 5), m(0, 2), m(3, 5), m(6, 11), m(6, 8), m(9, 11),]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Test that captures_iter respects short circuiting.
|
// Test that captures_iter respects short circuiting.
|
||||||
matches.clear();
|
matches.clear();
|
||||||
matcher
|
matcher.captures_iter(b"aa bb cc dd", &mut caps, |caps| {
|
||||||
.captures_iter(b"aa bb cc dd", &mut caps, |caps| {
|
matches.push(caps.get(0).unwrap());
|
||||||
matches.push(caps.get(0).unwrap());
|
matches.push(caps.get(1).unwrap());
|
||||||
matches.push(caps.get(1).unwrap());
|
matches.push(caps.get(2).unwrap());
|
||||||
matches.push(caps.get(2).unwrap());
|
false
|
||||||
false
|
}).unwrap();
|
||||||
})
|
assert_eq!(matches, vec![
|
||||||
.unwrap();
|
m(0, 5), m(0, 2), m(3, 5),
|
||||||
assert_eq!(matches, vec![m(0, 5), m(0, 2), m(3, 5),]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -130,19 +121,16 @@ fn try_captures_iter() {
|
|||||||
let matcher = matcher(r"(?P<a>\w+)\s+(?P<b>\w+)");
|
let matcher = matcher(r"(?P<a>\w+)\s+(?P<b>\w+)");
|
||||||
let mut caps = matcher.new_captures().unwrap();
|
let mut caps = matcher.new_captures().unwrap();
|
||||||
let mut matches = vec![];
|
let mut matches = vec![];
|
||||||
let err = matcher
|
let err = matcher.try_captures_iter(b"aa bb cc dd", &mut caps, |caps| {
|
||||||
.try_captures_iter(b"aa bb cc dd", &mut caps, |caps| {
|
if matches.is_empty() {
|
||||||
if matches.is_empty() {
|
matches.push(caps.get(0).unwrap());
|
||||||
matches.push(caps.get(0).unwrap());
|
matches.push(caps.get(1).unwrap());
|
||||||
matches.push(caps.get(1).unwrap());
|
matches.push(caps.get(2).unwrap());
|
||||||
matches.push(caps.get(2).unwrap());
|
Ok(true)
|
||||||
Ok(true)
|
} else {
|
||||||
} else {
|
Err(MyError)
|
||||||
Err(MyError)
|
}
|
||||||
}
|
}).unwrap().unwrap_err();
|
||||||
})
|
|
||||||
.unwrap()
|
|
||||||
.unwrap_err();
|
|
||||||
assert_eq!(matches, vec![m(0, 5), m(0, 2), m(3, 5)]);
|
assert_eq!(matches, vec![m(0, 5), m(0, 2), m(3, 5)]);
|
||||||
assert_eq!(err, MyError);
|
assert_eq!(err, MyError);
|
||||||
}
|
}
|
||||||
@@ -162,12 +150,10 @@ fn no_captures() {
|
|||||||
assert!(!matcher.captures(b"homer simpson", &mut caps).unwrap());
|
assert!(!matcher.captures(b"homer simpson", &mut caps).unwrap());
|
||||||
|
|
||||||
let mut called = false;
|
let mut called = false;
|
||||||
matcher
|
matcher.captures_iter(b"homer simpson", &mut caps, |_| {
|
||||||
.captures_iter(b"homer simpson", &mut caps, |_| {
|
called = true;
|
||||||
called = true;
|
true
|
||||||
true
|
}).unwrap();
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
assert!(!called);
|
assert!(!called);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,22 +161,18 @@ fn no_captures() {
|
|||||||
fn replace() {
|
fn replace() {
|
||||||
let matcher = matcher(r"(\w+)\s+(\w+)");
|
let matcher = matcher(r"(\w+)\s+(\w+)");
|
||||||
let mut dst = vec![];
|
let mut dst = vec![];
|
||||||
matcher
|
matcher.replace(b"aa bb cc dd", &mut dst, |_, dst| {
|
||||||
.replace(b"aa bb cc dd", &mut dst, |_, dst| {
|
dst.push(b'z');
|
||||||
dst.push(b'z');
|
true
|
||||||
true
|
}).unwrap();
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(dst, b"z z");
|
assert_eq!(dst, b"z z");
|
||||||
|
|
||||||
// Test that replacements respect short circuiting.
|
// Test that replacements respect short circuiting.
|
||||||
dst.clear();
|
dst.clear();
|
||||||
matcher
|
matcher.replace(b"aa bb cc dd", &mut dst, |_, dst| {
|
||||||
.replace(b"aa bb cc dd", &mut dst, |_, dst| {
|
dst.push(b'z');
|
||||||
dst.push(b'z');
|
false
|
||||||
false
|
}).unwrap();
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(dst, b"z cc dd");
|
assert_eq!(dst, b"z cc dd");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,31 +182,27 @@ fn replace_with_captures() {
|
|||||||
let haystack = b"aa bb cc dd";
|
let haystack = b"aa bb cc dd";
|
||||||
let mut caps = matcher.new_captures().unwrap();
|
let mut caps = matcher.new_captures().unwrap();
|
||||||
let mut dst = vec![];
|
let mut dst = vec![];
|
||||||
matcher
|
matcher.replace_with_captures(haystack, &mut caps, &mut dst, |caps, dst| {
|
||||||
.replace_with_captures(haystack, &mut caps, &mut dst, |caps, dst| {
|
caps.interpolate(
|
||||||
caps.interpolate(
|
|name| matcher.capture_index(name),
|
||||||
|name| matcher.capture_index(name),
|
haystack,
|
||||||
haystack,
|
b"$2 $1",
|
||||||
b"$2 $1",
|
dst,
|
||||||
dst,
|
);
|
||||||
);
|
true
|
||||||
true
|
}).unwrap();
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(dst, b"bb aa dd cc");
|
assert_eq!(dst, b"bb aa dd cc");
|
||||||
|
|
||||||
// Test that replacements respect short circuiting.
|
// Test that replacements respect short circuiting.
|
||||||
dst.clear();
|
dst.clear();
|
||||||
matcher
|
matcher.replace_with_captures(haystack, &mut caps, &mut dst, |caps, dst| {
|
||||||
.replace_with_captures(haystack, &mut caps, &mut dst, |caps, dst| {
|
caps.interpolate(
|
||||||
caps.interpolate(
|
|name| matcher.capture_index(name),
|
||||||
|name| matcher.capture_index(name),
|
haystack,
|
||||||
haystack,
|
b"$2 $1",
|
||||||
b"$2 $1",
|
dst,
|
||||||
dst,
|
);
|
||||||
);
|
false
|
||||||
false
|
}).unwrap();
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(dst, b"bb aa cc dd");
|
assert_eq!(dst, b"bb aa cc dd");
|
||||||
}
|
}
|
@@ -18,7 +18,10 @@ impl RegexMatcher {
|
|||||||
names.insert(name.to_string(), i);
|
names.insert(name.to_string(), i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RegexMatcher { re: re, names: names }
|
RegexMatcher {
|
||||||
|
re: re,
|
||||||
|
names: names,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,9 +31,12 @@ impl Matcher for RegexMatcher {
|
|||||||
type Captures = RegexCaptures;
|
type Captures = RegexCaptures;
|
||||||
type Error = NoError;
|
type Error = NoError;
|
||||||
|
|
||||||
fn find_at(&self, haystack: &[u8], at: usize) -> Result<Option<Match>> {
|
fn find_at(
|
||||||
Ok(self
|
&self,
|
||||||
.re
|
haystack: &[u8],
|
||||||
|
at: usize,
|
||||||
|
) -> Result<Option<Match>> {
|
||||||
|
Ok(self.re
|
||||||
.find_at(haystack, at)
|
.find_at(haystack, at)
|
||||||
.map(|m| Match::new(m.start(), m.end())))
|
.map(|m| Match::new(m.start(), m.end())))
|
||||||
}
|
}
|
||||||
@@ -69,9 +75,12 @@ impl Matcher for RegexMatcherNoCaps {
|
|||||||
type Captures = NoCaptures;
|
type Captures = NoCaptures;
|
||||||
type Error = NoError;
|
type Error = NoError;
|
||||||
|
|
||||||
fn find_at(&self, haystack: &[u8], at: usize) -> Result<Option<Match>> {
|
fn find_at(
|
||||||
Ok(self
|
&self,
|
||||||
.0
|
haystack: &[u8],
|
||||||
|
at: usize,
|
||||||
|
) -> Result<Option<Match>> {
|
||||||
|
Ok(self.0
|
||||||
.find_at(haystack, at)
|
.find_at(haystack, at)
|
||||||
.map(|m| Match::new(m.start(), m.end())))
|
.map(|m| Match::new(m.start(), m.end())))
|
||||||
}
|
}
|
@@ -1,17 +1,17 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "grep-pcre2"
|
name = "grep-pcre2"
|
||||||
version = "0.1.4" #:version
|
version = "0.1.3" #:version
|
||||||
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
||||||
description = """
|
description = """
|
||||||
Use PCRE2 with the 'grep' crate.
|
Use PCRE2 with the 'grep' crate.
|
||||||
"""
|
"""
|
||||||
documentation = "https://docs.rs/grep-pcre2"
|
documentation = "https://docs.rs/grep-pcre2"
|
||||||
homepage = "https://github.com/BurntSushi/ripgrep/tree/master/crates/pcre2"
|
homepage = "https://github.com/BurntSushi/ripgrep"
|
||||||
repository = "https://github.com/BurntSushi/ripgrep/tree/master/crates/pcre2"
|
repository = "https://github.com/BurntSushi/ripgrep"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
keywords = ["regex", "grep", "pcre", "backreference", "look"]
|
keywords = ["regex", "grep", "pcre", "backreference", "look"]
|
||||||
license = "Unlicense/MIT"
|
license = "Unlicense/MIT"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
grep-matcher = { version = "0.1.2", path = "../matcher" }
|
grep-matcher = { version = "0.1.2", path = "../grep-matcher" }
|
||||||
pcre2 = "0.2.0"
|
pcre2 = "0.2.0"
|
@@ -33,12 +33,13 @@ impl RegexMatcherBuilder {
|
|||||||
if self.case_smart && !has_uppercase_literal(pattern) {
|
if self.case_smart && !has_uppercase_literal(pattern) {
|
||||||
builder.caseless(true);
|
builder.caseless(true);
|
||||||
}
|
}
|
||||||
let res = if self.word {
|
let res =
|
||||||
let pattern = format!(r"(?<!\w)(?:{})(?!\w)", pattern);
|
if self.word {
|
||||||
builder.build(&pattern)
|
let pattern = format!(r"(?<!\w)(?:{})(?!\w)", pattern);
|
||||||
} else {
|
builder.build(&pattern)
|
||||||
builder.build(pattern)
|
} else {
|
||||||
};
|
builder.build(pattern)
|
||||||
|
};
|
||||||
res.map_err(Error::regex).map(|regex| {
|
res.map_err(Error::regex).map(|regex| {
|
||||||
let mut names = HashMap::new();
|
let mut names = HashMap::new();
|
||||||
for (i, name) in regex.capture_names().iter().enumerate() {
|
for (i, name) in regex.capture_names().iter().enumerate() {
|
||||||
@@ -273,8 +274,7 @@ impl Matcher for RegexMatcher {
|
|||||||
haystack: &[u8],
|
haystack: &[u8],
|
||||||
at: usize,
|
at: usize,
|
||||||
) -> Result<Option<Match>, Error> {
|
) -> Result<Option<Match>, Error> {
|
||||||
Ok(self
|
Ok(self.regex
|
||||||
.regex
|
|
||||||
.find_at(haystack, at)
|
.find_at(haystack, at)
|
||||||
.map_err(Error::regex)?
|
.map_err(Error::regex)?
|
||||||
.map(|m| Match::new(m.start(), m.end())))
|
.map(|m| Match::new(m.start(), m.end())))
|
||||||
@@ -297,8 +297,7 @@ impl Matcher for RegexMatcher {
|
|||||||
haystack: &[u8],
|
haystack: &[u8],
|
||||||
mut matched: F,
|
mut matched: F,
|
||||||
) -> Result<Result<(), E>, Error>
|
) -> Result<Result<(), E>, Error>
|
||||||
where
|
where F: FnMut(Match) -> Result<bool, E>
|
||||||
F: FnMut(Match) -> Result<bool, E>,
|
|
||||||
{
|
{
|
||||||
for result in self.regex.find_iter(haystack) {
|
for result in self.regex.find_iter(haystack) {
|
||||||
let m = result.map_err(Error::regex)?;
|
let m = result.map_err(Error::regex)?;
|
||||||
@@ -317,11 +316,10 @@ impl Matcher for RegexMatcher {
|
|||||||
at: usize,
|
at: usize,
|
||||||
caps: &mut RegexCaptures,
|
caps: &mut RegexCaptures,
|
||||||
) -> Result<bool, Error> {
|
) -> Result<bool, Error> {
|
||||||
Ok(self
|
Ok(self.regex
|
||||||
.regex
|
.captures_read_at(&mut caps.locs, haystack, at)
|
||||||
.captures_read_at(&mut caps.locs, haystack, at)
|
.map_err(Error::regex)?
|
||||||
.map_err(Error::regex)?
|
.is_some())
|
||||||
.is_some())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -385,19 +383,23 @@ fn has_uppercase_literal(pattern: &str) -> bool {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
|
||||||
use grep_matcher::{LineMatchKind, Matcher};
|
use grep_matcher::{LineMatchKind, Matcher};
|
||||||
|
use super::*;
|
||||||
|
|
||||||
// Test that enabling word matches does the right thing and demonstrate
|
// Test that enabling word matches does the right thing and demonstrate
|
||||||
// the difference between it and surrounding the regex in `\b`.
|
// the difference between it and surrounding the regex in `\b`.
|
||||||
#[test]
|
#[test]
|
||||||
fn word() {
|
fn word() {
|
||||||
let matcher =
|
let matcher = RegexMatcherBuilder::new()
|
||||||
RegexMatcherBuilder::new().word(true).build(r"-2").unwrap();
|
.word(true)
|
||||||
|
.build(r"-2")
|
||||||
|
.unwrap();
|
||||||
assert!(matcher.is_match(b"abc -2 foo").unwrap());
|
assert!(matcher.is_match(b"abc -2 foo").unwrap());
|
||||||
|
|
||||||
let matcher =
|
let matcher = RegexMatcherBuilder::new()
|
||||||
RegexMatcherBuilder::new().word(false).build(r"\b-2\b").unwrap();
|
.word(false)
|
||||||
|
.build(r"\b-2\b")
|
||||||
|
.unwrap();
|
||||||
assert!(!matcher.is_match(b"abc -2 foo").unwrap());
|
assert!(!matcher.is_match(b"abc -2 foo").unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -430,12 +432,16 @@ mod tests {
|
|||||||
// Test that smart case works.
|
// Test that smart case works.
|
||||||
#[test]
|
#[test]
|
||||||
fn case_smart() {
|
fn case_smart() {
|
||||||
let matcher =
|
let matcher = RegexMatcherBuilder::new()
|
||||||
RegexMatcherBuilder::new().case_smart(true).build(r"abc").unwrap();
|
.case_smart(true)
|
||||||
|
.build(r"abc")
|
||||||
|
.unwrap();
|
||||||
assert!(matcher.is_match(b"ABC").unwrap());
|
assert!(matcher.is_match(b"ABC").unwrap());
|
||||||
|
|
||||||
let matcher =
|
let matcher = RegexMatcherBuilder::new()
|
||||||
RegexMatcherBuilder::new().case_smart(true).build(r"aBc").unwrap();
|
.case_smart(true)
|
||||||
|
.build(r"aBc")
|
||||||
|
.unwrap();
|
||||||
assert!(!matcher.is_match(b"ABC").unwrap());
|
assert!(!matcher.is_match(b"ABC").unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -449,7 +455,9 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let matcher = RegexMatcherBuilder::new().build(r"\wfoo\s").unwrap();
|
let matcher = RegexMatcherBuilder::new()
|
||||||
|
.build(r"\wfoo\s")
|
||||||
|
.unwrap();
|
||||||
let m = matcher.find_candidate_line(b"afoo ").unwrap().unwrap();
|
let m = matcher.find_candidate_line(b"afoo ").unwrap().unwrap();
|
||||||
assert!(is_confirmed(m));
|
assert!(is_confirmed(m));
|
||||||
}
|
}
|
@@ -1,14 +1,14 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "grep-printer"
|
name = "grep-printer"
|
||||||
version = "0.1.4" #:version
|
version = "0.1.3" #:version
|
||||||
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
||||||
description = """
|
description = """
|
||||||
An implementation of the grep crate's Sink trait that provides standard
|
An implementation of the grep crate's Sink trait that provides standard
|
||||||
printing of search results, similar to grep itself.
|
printing of search results, similar to grep itself.
|
||||||
"""
|
"""
|
||||||
documentation = "https://docs.rs/grep-printer"
|
documentation = "https://docs.rs/grep-printer"
|
||||||
homepage = "https://github.com/BurntSushi/ripgrep/tree/master/crates/printer"
|
homepage = "https://github.com/BurntSushi/ripgrep"
|
||||||
repository = "https://github.com/BurntSushi/ripgrep/tree/master/crates/printer"
|
repository = "https://github.com/BurntSushi/ripgrep"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
keywords = ["grep", "pattern", "print", "printer", "sink"]
|
keywords = ["grep", "pattern", "print", "printer", "sink"]
|
||||||
license = "Unlicense/MIT"
|
license = "Unlicense/MIT"
|
||||||
@@ -18,14 +18,14 @@ default = ["serde1"]
|
|||||||
serde1 = ["base64", "serde", "serde_derive", "serde_json"]
|
serde1 = ["base64", "serde", "serde_derive", "serde_json"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
base64 = { version = "0.11.0", optional = true }
|
base64 = { version = "0.10.0", optional = true }
|
||||||
bstr = "0.2.0"
|
bstr = "0.2.0"
|
||||||
grep-matcher = { version = "0.1.2", path = "../matcher" }
|
grep-matcher = { version = "0.1.2", path = "../grep-matcher" }
|
||||||
grep-searcher = { version = "0.1.4", path = "../searcher" }
|
grep-searcher = { version = "0.1.4", path = "../grep-searcher" }
|
||||||
termcolor = "1.0.4"
|
termcolor = "1.0.4"
|
||||||
serde = { version = "1.0.77", optional = true }
|
serde = { version = "1.0.77", optional = true }
|
||||||
serde_derive = { version = "1.0.77", optional = true }
|
serde_derive = { version = "1.0.77", optional = true }
|
||||||
serde_json = { version = "1.0.27", optional = true }
|
serde_json = { version = "1.0.27", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
grep-regex = { version = "0.1.3", path = "../regex" }
|
grep-regex = { version = "0.1.3", path = "../grep-regex" }
|
@@ -62,32 +62,42 @@ impl ColorError {
|
|||||||
impl fmt::Display for ColorError {
|
impl fmt::Display for ColorError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
ColorError::UnrecognizedOutType(ref name) => write!(
|
ColorError::UnrecognizedOutType(ref name) => {
|
||||||
f,
|
write!(
|
||||||
"unrecognized output type '{}'. Choose from: \
|
f,
|
||||||
|
"unrecognized output type '{}'. Choose from: \
|
||||||
path, line, column, match.",
|
path, line, column, match.",
|
||||||
name,
|
name,
|
||||||
),
|
)
|
||||||
ColorError::UnrecognizedSpecType(ref name) => write!(
|
}
|
||||||
f,
|
ColorError::UnrecognizedSpecType(ref name) => {
|
||||||
"unrecognized spec type '{}'. Choose from: \
|
write!(
|
||||||
|
f,
|
||||||
|
"unrecognized spec type '{}'. Choose from: \
|
||||||
fg, bg, style, none.",
|
fg, bg, style, none.",
|
||||||
name,
|
name,
|
||||||
),
|
)
|
||||||
ColorError::UnrecognizedColor(_, ref msg) => write!(f, "{}", msg),
|
}
|
||||||
ColorError::UnrecognizedStyle(ref name) => write!(
|
ColorError::UnrecognizedColor(_, ref msg) => {
|
||||||
f,
|
write!(f, "{}", msg)
|
||||||
"unrecognized style attribute '{}'. Choose from: \
|
}
|
||||||
|
ColorError::UnrecognizedStyle(ref name) => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"unrecognized style attribute '{}'. Choose from: \
|
||||||
nobold, bold, nointense, intense, nounderline, \
|
nobold, bold, nointense, intense, nounderline, \
|
||||||
underline.",
|
underline.",
|
||||||
name,
|
name,
|
||||||
),
|
)
|
||||||
ColorError::InvalidFormat(ref original) => write!(
|
}
|
||||||
f,
|
ColorError::InvalidFormat(ref original) => {
|
||||||
"invalid color spec format: '{}'. Valid format \
|
write!(
|
||||||
|
f,
|
||||||
|
"invalid color spec format: '{}'. Valid format \
|
||||||
is '(path|line|column|match):(fg|bg|style):(value)'.",
|
is '(path|line|column|match):(fg|bg|style):(value)'.",
|
||||||
original,
|
original,
|
||||||
),
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -217,7 +227,7 @@ enum Style {
|
|||||||
Intense,
|
Intense,
|
||||||
NoIntense,
|
NoIntense,
|
||||||
Underline,
|
Underline,
|
||||||
NoUnderline,
|
NoUnderline
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ColorSpecs {
|
impl ColorSpecs {
|
||||||
@@ -278,32 +288,18 @@ impl SpecValue {
|
|||||||
fn merge_into(&self, cspec: &mut ColorSpec) {
|
fn merge_into(&self, cspec: &mut ColorSpec) {
|
||||||
match *self {
|
match *self {
|
||||||
SpecValue::None => cspec.clear(),
|
SpecValue::None => cspec.clear(),
|
||||||
SpecValue::Fg(ref color) => {
|
SpecValue::Fg(ref color) => { cspec.set_fg(Some(color.clone())); }
|
||||||
cspec.set_fg(Some(color.clone()));
|
SpecValue::Bg(ref color) => { cspec.set_bg(Some(color.clone())); }
|
||||||
|
SpecValue::Style(ref style) => {
|
||||||
|
match *style {
|
||||||
|
Style::Bold => { cspec.set_bold(true); }
|
||||||
|
Style::NoBold => { cspec.set_bold(false); }
|
||||||
|
Style::Intense => { cspec.set_intense(true); }
|
||||||
|
Style::NoIntense => { cspec.set_intense(false); }
|
||||||
|
Style::Underline => { cspec.set_underline(true); }
|
||||||
|
Style::NoUnderline => { cspec.set_underline(false); }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
SpecValue::Bg(ref color) => {
|
|
||||||
cspec.set_bg(Some(color.clone()));
|
|
||||||
}
|
|
||||||
SpecValue::Style(ref style) => match *style {
|
|
||||||
Style::Bold => {
|
|
||||||
cspec.set_bold(true);
|
|
||||||
}
|
|
||||||
Style::NoBold => {
|
|
||||||
cspec.set_bold(false);
|
|
||||||
}
|
|
||||||
Style::Intense => {
|
|
||||||
cspec.set_intense(true);
|
|
||||||
}
|
|
||||||
Style::NoIntense => {
|
|
||||||
cspec.set_intense(false);
|
|
||||||
}
|
|
||||||
Style::Underline => {
|
|
||||||
cspec.set_underline(true);
|
|
||||||
}
|
|
||||||
Style::NoUnderline => {
|
|
||||||
cspec.set_underline(false);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -319,7 +315,10 @@ impl FromStr for UserColorSpec {
|
|||||||
let otype: OutType = pieces[0].parse()?;
|
let otype: OutType = pieces[0].parse()?;
|
||||||
match pieces[1].parse()? {
|
match pieces[1].parse()? {
|
||||||
SpecType::None => {
|
SpecType::None => {
|
||||||
Ok(UserColorSpec { ty: otype, value: SpecValue::None })
|
Ok(UserColorSpec {
|
||||||
|
ty: otype,
|
||||||
|
value: SpecValue::None,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
SpecType::Style => {
|
SpecType::Style => {
|
||||||
if pieces.len() < 3 {
|
if pieces.len() < 3 {
|
||||||
@@ -332,16 +331,18 @@ impl FromStr for UserColorSpec {
|
|||||||
if pieces.len() < 3 {
|
if pieces.len() < 3 {
|
||||||
return Err(ColorError::InvalidFormat(s.to_string()));
|
return Err(ColorError::InvalidFormat(s.to_string()));
|
||||||
}
|
}
|
||||||
let color: Color =
|
let color: Color = pieces[2]
|
||||||
pieces[2].parse().map_err(ColorError::from_parse_error)?;
|
.parse()
|
||||||
|
.map_err(ColorError::from_parse_error)?;
|
||||||
Ok(UserColorSpec { ty: otype, value: SpecValue::Fg(color) })
|
Ok(UserColorSpec { ty: otype, value: SpecValue::Fg(color) })
|
||||||
}
|
}
|
||||||
SpecType::Bg => {
|
SpecType::Bg => {
|
||||||
if pieces.len() < 3 {
|
if pieces.len() < 3 {
|
||||||
return Err(ColorError::InvalidFormat(s.to_string()));
|
return Err(ColorError::InvalidFormat(s.to_string()));
|
||||||
}
|
}
|
||||||
let color: Color =
|
let color: Color = pieces[2]
|
||||||
pieces[2].parse().map_err(ColorError::from_parse_error)?;
|
.parse()
|
||||||
|
.map_err(ColorError::from_parse_error)?;
|
||||||
Ok(UserColorSpec { ty: otype, value: SpecValue::Bg(color) })
|
Ok(UserColorSpec { ty: otype, value: SpecValue::Bg(color) })
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -4,8 +4,8 @@ use std::time::Instant;
|
|||||||
|
|
||||||
use grep_matcher::{Match, Matcher};
|
use grep_matcher::{Match, Matcher};
|
||||||
use grep_searcher::{
|
use grep_searcher::{
|
||||||
Searcher, Sink, SinkContext, SinkContextKind, SinkError, SinkFinish,
|
Searcher,
|
||||||
SinkMatch,
|
Sink, SinkError, SinkContext, SinkContextKind, SinkFinish, SinkMatch,
|
||||||
};
|
};
|
||||||
use serde_json as json;
|
use serde_json as json;
|
||||||
|
|
||||||
@@ -27,7 +27,11 @@ struct Config {
|
|||||||
|
|
||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
fn default() -> Config {
|
fn default() -> Config {
|
||||||
Config { pretty: false, max_matches: None, always_begin_end: false }
|
Config {
|
||||||
|
pretty: false,
|
||||||
|
max_matches: None,
|
||||||
|
always_begin_end: false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -488,9 +492,8 @@ impl<W: io::Write> JSON<W> {
|
|||||||
matcher: M,
|
matcher: M,
|
||||||
path: &'p P,
|
path: &'p P,
|
||||||
) -> JSONSink<'p, 's, M, W>
|
) -> JSONSink<'p, 's, M, W>
|
||||||
where
|
where M: Matcher,
|
||||||
M: Matcher,
|
P: ?Sized + AsRef<Path>,
|
||||||
P: ?Sized + AsRef<Path>,
|
|
||||||
{
|
{
|
||||||
JSONSink {
|
JSONSink {
|
||||||
matcher: matcher,
|
matcher: matcher,
|
||||||
@@ -612,12 +615,10 @@ impl<'p, 's, M: Matcher, W: io::Write> JSONSink<'p, 's, M, W> {
|
|||||||
// the extent that it's easy to ensure that we never do more than
|
// the extent that it's easy to ensure that we never do more than
|
||||||
// one search to find the matches.
|
// one search to find the matches.
|
||||||
let matches = &mut self.json.matches;
|
let matches = &mut self.json.matches;
|
||||||
self.matcher
|
self.matcher.find_iter(bytes, |m| {
|
||||||
.find_iter(bytes, |m| {
|
matches.push(m);
|
||||||
matches.push(m);
|
true
|
||||||
true
|
}).map_err(io::Error::error_message)?;
|
||||||
})
|
|
||||||
.map_err(io::Error::error_message)?;
|
|
||||||
// Don't report empty matches appearing at the end of the bytes.
|
// Don't report empty matches appearing at the end of the bytes.
|
||||||
if !matches.is_empty()
|
if !matches.is_empty()
|
||||||
&& matches.last().unwrap().is_empty()
|
&& matches.last().unwrap().is_empty()
|
||||||
@@ -649,7 +650,9 @@ impl<'p, 's, M: Matcher, W: io::Write> JSONSink<'p, 's, M, W> {
|
|||||||
if self.begin_printed {
|
if self.begin_printed {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let msg = jsont::Message::Begin(jsont::Begin { path: self.path });
|
let msg = jsont::Message::Begin(jsont::Begin {
|
||||||
|
path: self.path,
|
||||||
|
});
|
||||||
self.json.write_message(&msg)?;
|
self.json.write_message(&msg)?;
|
||||||
self.begin_printed = true;
|
self.begin_printed = true;
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -696,12 +699,13 @@ impl<'p, 's, M: Matcher, W: io::Write> Sink for JSONSink<'p, 's, M, W> {
|
|||||||
self.after_context_remaining =
|
self.after_context_remaining =
|
||||||
self.after_context_remaining.saturating_sub(1);
|
self.after_context_remaining.saturating_sub(1);
|
||||||
}
|
}
|
||||||
let submatches = if searcher.invert_match() {
|
let submatches =
|
||||||
self.record_matches(ctx.bytes())?;
|
if searcher.invert_match() {
|
||||||
SubMatches::new(ctx.bytes(), &self.json.matches)
|
self.record_matches(ctx.bytes())?;
|
||||||
} else {
|
SubMatches::new(ctx.bytes(), &self.json.matches)
|
||||||
SubMatches::empty()
|
} else {
|
||||||
};
|
SubMatches::empty()
|
||||||
|
};
|
||||||
let msg = jsont::Message::Context(jsont::Context {
|
let msg = jsont::Message::Context(jsont::Context {
|
||||||
path: self.path,
|
path: self.path,
|
||||||
lines: ctx.bytes(),
|
lines: ctx.bytes(),
|
||||||
@@ -713,7 +717,10 @@ impl<'p, 's, M: Matcher, W: io::Write> Sink for JSONSink<'p, 's, M, W> {
|
|||||||
Ok(!self.should_quit())
|
Ok(!self.should_quit())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn begin(&mut self, _searcher: &Searcher) -> Result<bool, io::Error> {
|
fn begin(
|
||||||
|
&mut self,
|
||||||
|
_searcher: &Searcher,
|
||||||
|
) -> Result<bool, io::Error> {
|
||||||
self.json.wtr.reset_count();
|
self.json.wtr.reset_count();
|
||||||
self.start_time = Instant::now();
|
self.start_time = Instant::now();
|
||||||
self.match_count = 0;
|
self.match_count = 0;
|
||||||
@@ -772,7 +779,7 @@ enum SubMatches<'a> {
|
|||||||
impl<'a> SubMatches<'a> {
|
impl<'a> SubMatches<'a> {
|
||||||
/// Create a new set of match ranges from a set of matches and the
|
/// Create a new set of match ranges from a set of matches and the
|
||||||
/// corresponding bytes that those matches apply to.
|
/// corresponding bytes that those matches apply to.
|
||||||
fn new(bytes: &'a [u8], matches: &[Match]) -> SubMatches<'a> {
|
fn new(bytes: &'a[u8], matches: &[Match]) -> SubMatches<'a> {
|
||||||
if matches.len() == 1 {
|
if matches.len() == 1 {
|
||||||
let mat = matches[0];
|
let mat = matches[0];
|
||||||
SubMatches::Small([jsont::SubMatch {
|
SubMatches::Small([jsont::SubMatch {
|
||||||
@@ -810,11 +817,11 @@ impl<'a> SubMatches<'a> {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use grep_matcher::LineTerminator;
|
|
||||||
use grep_regex::{RegexMatcher, RegexMatcherBuilder};
|
use grep_regex::{RegexMatcher, RegexMatcherBuilder};
|
||||||
|
use grep_matcher::LineTerminator;
|
||||||
use grep_searcher::SearcherBuilder;
|
use grep_searcher::SearcherBuilder;
|
||||||
|
|
||||||
use super::{JSONBuilder, JSON};
|
use super::{JSON, JSONBuilder};
|
||||||
|
|
||||||
const SHERLOCK: &'static [u8] = b"\
|
const SHERLOCK: &'static [u8] = b"\
|
||||||
For the Doctor Watsons of this world, as opposed to the Sherlock
|
For the Doctor Watsons of this world, as opposed to the Sherlock
|
||||||
@@ -825,7 +832,9 @@ but Doctor Watson has to have it taken out for him and dusted,
|
|||||||
and exhibited clearly, with a label attached.
|
and exhibited clearly, with a label attached.
|
||||||
";
|
";
|
||||||
|
|
||||||
fn printer_contents(printer: &mut JSON<Vec<u8>>) -> String {
|
fn printer_contents(
|
||||||
|
printer: &mut JSON<Vec<u8>>,
|
||||||
|
) -> String {
|
||||||
String::from_utf8(printer.get_mut().to_owned()).unwrap()
|
String::from_utf8(printer.get_mut().to_owned()).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -842,8 +851,11 @@ but Doctor Watson has to have it taken out for him and dusted,
|
|||||||
and exhibited clearly, with a label attached.\
|
and exhibited clearly, with a label attached.\
|
||||||
";
|
";
|
||||||
|
|
||||||
let matcher = RegexMatcher::new(r"Watson").unwrap();
|
let matcher = RegexMatcher::new(
|
||||||
let mut printer = JSONBuilder::new().build(vec![]);
|
r"Watson"
|
||||||
|
).unwrap();
|
||||||
|
let mut printer = JSONBuilder::new()
|
||||||
|
.build(vec![]);
|
||||||
SearcherBuilder::new()
|
SearcherBuilder::new()
|
||||||
.binary_detection(BinaryDetection::quit(b'\x00'))
|
.binary_detection(BinaryDetection::quit(b'\x00'))
|
||||||
.heap_limit(Some(80))
|
.heap_limit(Some(80))
|
||||||
@@ -859,9 +871,12 @@ and exhibited clearly, with a label attached.\
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn max_matches() {
|
fn max_matches() {
|
||||||
let matcher = RegexMatcher::new(r"Watson").unwrap();
|
let matcher = RegexMatcher::new(
|
||||||
let mut printer =
|
r"Watson"
|
||||||
JSONBuilder::new().max_matches(Some(1)).build(vec![]);
|
).unwrap();
|
||||||
|
let mut printer = JSONBuilder::new()
|
||||||
|
.max_matches(Some(1))
|
||||||
|
.build(vec![]);
|
||||||
SearcherBuilder::new()
|
SearcherBuilder::new()
|
||||||
.build()
|
.build()
|
||||||
.search_reader(&matcher, SHERLOCK, printer.sink(&matcher))
|
.search_reader(&matcher, SHERLOCK, printer.sink(&matcher))
|
||||||
@@ -873,8 +888,11 @@ and exhibited clearly, with a label attached.\
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn no_match() {
|
fn no_match() {
|
||||||
let matcher = RegexMatcher::new(r"DOES NOT MATCH").unwrap();
|
let matcher = RegexMatcher::new(
|
||||||
let mut printer = JSONBuilder::new().build(vec![]);
|
r"DOES NOT MATCH"
|
||||||
|
).unwrap();
|
||||||
|
let mut printer = JSONBuilder::new()
|
||||||
|
.build(vec![]);
|
||||||
SearcherBuilder::new()
|
SearcherBuilder::new()
|
||||||
.build()
|
.build()
|
||||||
.search_reader(&matcher, SHERLOCK, printer.sink(&matcher))
|
.search_reader(&matcher, SHERLOCK, printer.sink(&matcher))
|
||||||
@@ -886,9 +904,12 @@ and exhibited clearly, with a label attached.\
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn always_begin_end_no_match() {
|
fn always_begin_end_no_match() {
|
||||||
let matcher = RegexMatcher::new(r"DOES NOT MATCH").unwrap();
|
let matcher = RegexMatcher::new(
|
||||||
let mut printer =
|
r"DOES NOT MATCH"
|
||||||
JSONBuilder::new().always_begin_end(true).build(vec![]);
|
).unwrap();
|
||||||
|
let mut printer = JSONBuilder::new()
|
||||||
|
.always_begin_end(true)
|
||||||
|
.build(vec![]);
|
||||||
SearcherBuilder::new()
|
SearcherBuilder::new()
|
||||||
.build()
|
.build()
|
||||||
.search_reader(&matcher, SHERLOCK, printer.sink(&matcher))
|
.search_reader(&matcher, SHERLOCK, printer.sink(&matcher))
|
||||||
@@ -903,8 +924,11 @@ and exhibited clearly, with a label attached.\
|
|||||||
fn missing_crlf() {
|
fn missing_crlf() {
|
||||||
let haystack = "test\r\n".as_bytes();
|
let haystack = "test\r\n".as_bytes();
|
||||||
|
|
||||||
let matcher = RegexMatcherBuilder::new().build("test").unwrap();
|
let matcher = RegexMatcherBuilder::new()
|
||||||
let mut printer = JSONBuilder::new().build(vec![]);
|
.build("test")
|
||||||
|
.unwrap();
|
||||||
|
let mut printer = JSONBuilder::new()
|
||||||
|
.build(vec![]);
|
||||||
SearcherBuilder::new()
|
SearcherBuilder::new()
|
||||||
.build()
|
.build()
|
||||||
.search_reader(&matcher, haystack, printer.sink(&matcher))
|
.search_reader(&matcher, haystack, printer.sink(&matcher))
|
||||||
@@ -917,9 +941,12 @@ and exhibited clearly, with a label attached.\
|
|||||||
got.lines().nth(1).unwrap(),
|
got.lines().nth(1).unwrap(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let matcher =
|
let matcher = RegexMatcherBuilder::new()
|
||||||
RegexMatcherBuilder::new().crlf(true).build("test").unwrap();
|
.crlf(true)
|
||||||
let mut printer = JSONBuilder::new().build(vec![]);
|
.build("test")
|
||||||
|
.unwrap();
|
||||||
|
let mut printer = JSONBuilder::new()
|
||||||
|
.build(vec![]);
|
||||||
SearcherBuilder::new()
|
SearcherBuilder::new()
|
||||||
.line_terminator(LineTerminator::crlf())
|
.line_terminator(LineTerminator::crlf())
|
||||||
.build()
|
.build()
|
@@ -80,9 +80,7 @@ pub struct SubMatch<'a> {
|
|||||||
#[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize)]
|
#[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
enum Data<'a> {
|
enum Data<'a> {
|
||||||
Text {
|
Text { text: Cow<'a, str> },
|
||||||
text: Cow<'a, str>,
|
|
||||||
},
|
|
||||||
Bytes {
|
Bytes {
|
||||||
#[serde(serialize_with = "to_base64")]
|
#[serde(serialize_with = "to_base64")]
|
||||||
bytes: &'a [u8],
|
bytes: &'a [u8],
|
||||||
@@ -118,26 +116,32 @@ impl<'a> Data<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_base64<T, S>(bytes: T, ser: S) -> Result<S::Ok, S::Error>
|
fn to_base64<T, S>(
|
||||||
where
|
bytes: T,
|
||||||
T: AsRef<[u8]>,
|
ser: S,
|
||||||
S: Serializer,
|
) -> Result<S::Ok, S::Error>
|
||||||
|
where T: AsRef<[u8]>,
|
||||||
|
S: Serializer
|
||||||
{
|
{
|
||||||
ser.serialize_str(&base64::encode(&bytes))
|
ser.serialize_str(&base64::encode(&bytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ser_bytes<T, S>(bytes: T, ser: S) -> Result<S::Ok, S::Error>
|
fn ser_bytes<T, S>(
|
||||||
where
|
bytes: T,
|
||||||
T: AsRef<[u8]>,
|
ser: S,
|
||||||
S: Serializer,
|
) -> Result<S::Ok, S::Error>
|
||||||
|
where T: AsRef<[u8]>,
|
||||||
|
S: Serializer
|
||||||
{
|
{
|
||||||
Data::from_bytes(bytes.as_ref()).serialize(ser)
|
Data::from_bytes(bytes.as_ref()).serialize(ser)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ser_path<P, S>(path: &Option<P>, ser: S) -> Result<S::Ok, S::Error>
|
fn ser_path<P, S>(
|
||||||
where
|
path: &Option<P>,
|
||||||
P: AsRef<Path>,
|
ser: S,
|
||||||
S: Serializer,
|
) -> Result<S::Ok, S::Error>
|
||||||
|
where P: AsRef<Path>,
|
||||||
|
S: Serializer
|
||||||
{
|
{
|
||||||
path.as_ref().map(|p| Data::from_path(p.as_ref())).serialize(ser)
|
path.as_ref().map(|p| Data::from_path(p.as_ref())).serialize(ser)
|
||||||
}
|
}
|
@@ -84,9 +84,9 @@ extern crate serde_derive;
|
|||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
extern crate termcolor;
|
extern crate termcolor;
|
||||||
|
|
||||||
pub use color::{default_color_specs, ColorError, ColorSpecs, UserColorSpec};
|
pub use color::{ColorError, ColorSpecs, UserColorSpec, default_color_specs};
|
||||||
#[cfg(feature = "serde1")]
|
#[cfg(feature = "serde1")]
|
||||||
pub use json::{JSONBuilder, JSONSink, JSON};
|
pub use json::{JSON, JSONBuilder, JSONSink};
|
||||||
pub use standard::{Standard, StandardBuilder, StandardSink};
|
pub use standard::{Standard, StandardBuilder, StandardSink};
|
||||||
pub use stats::Stats;
|
pub use stats::Stats;
|
||||||
pub use summary::{Summary, SummaryBuilder, SummaryKind, SummarySink};
|
pub use summary::{Summary, SummaryBuilder, SummaryKind, SummarySink};
|
@@ -8,15 +8,16 @@ use std::time::Instant;
|
|||||||
use bstr::ByteSlice;
|
use bstr::ByteSlice;
|
||||||
use grep_matcher::{Match, Matcher};
|
use grep_matcher::{Match, Matcher};
|
||||||
use grep_searcher::{
|
use grep_searcher::{
|
||||||
LineStep, Searcher, Sink, SinkContext, SinkContextKind, SinkError,
|
LineStep, Searcher,
|
||||||
SinkFinish, SinkMatch,
|
Sink, SinkError,
|
||||||
|
SinkContext, SinkContextKind, SinkFinish, SinkMatch,
|
||||||
};
|
};
|
||||||
use termcolor::{ColorSpec, NoColor, WriteColor};
|
use termcolor::{ColorSpec, NoColor, WriteColor};
|
||||||
|
|
||||||
use color::ColorSpecs;
|
use color::ColorSpecs;
|
||||||
use counter::CounterWriter;
|
use counter::CounterWriter;
|
||||||
use stats::Stats;
|
use stats::Stats;
|
||||||
use util::{trim_ascii_prefix, PrinterPath, Replacer, Sunk};
|
use util::{PrinterPath, Replacer, Sunk, trim_ascii_prefix};
|
||||||
|
|
||||||
/// The configuration for the standard printer.
|
/// The configuration for the standard printer.
|
||||||
///
|
///
|
||||||
@@ -150,7 +151,10 @@ impl StandardBuilder {
|
|||||||
/// This completely overrides any previous color specifications. This does
|
/// This completely overrides any previous color specifications. This does
|
||||||
/// not add to any previously provided color specifications on this
|
/// not add to any previously provided color specifications on this
|
||||||
/// builder.
|
/// builder.
|
||||||
pub fn color_specs(&mut self, specs: ColorSpecs) -> &mut StandardBuilder {
|
pub fn color_specs(
|
||||||
|
&mut self,
|
||||||
|
specs: ColorSpecs,
|
||||||
|
) -> &mut StandardBuilder {
|
||||||
self.config.colors = specs;
|
self.config.colors = specs;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@@ -405,7 +409,10 @@ impl StandardBuilder {
|
|||||||
/// A typical use for this option is to permit cygwin users on Windows to
|
/// A typical use for this option is to permit cygwin users on Windows to
|
||||||
/// set the path separator to `/` instead of using the system default of
|
/// set the path separator to `/` instead of using the system default of
|
||||||
/// `\`.
|
/// `\`.
|
||||||
pub fn separator_path(&mut self, sep: Option<u8>) -> &mut StandardBuilder {
|
pub fn separator_path(
|
||||||
|
&mut self,
|
||||||
|
sep: Option<u8>,
|
||||||
|
) -> &mut StandardBuilder {
|
||||||
self.config.separator_path = sep;
|
self.config.separator_path = sep;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@@ -480,7 +487,12 @@ impl<W: WriteColor> Standard<W> {
|
|||||||
&'s mut self,
|
&'s mut self,
|
||||||
matcher: M,
|
matcher: M,
|
||||||
) -> StandardSink<'static, 's, M, W> {
|
) -> StandardSink<'static, 's, M, W> {
|
||||||
let stats = if self.config.stats { Some(Stats::new()) } else { None };
|
let stats =
|
||||||
|
if self.config.stats {
|
||||||
|
Some(Stats::new())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
let needs_match_granularity = self.needs_match_granularity();
|
let needs_match_granularity = self.needs_match_granularity();
|
||||||
StandardSink {
|
StandardSink {
|
||||||
matcher: matcher,
|
matcher: matcher,
|
||||||
@@ -505,18 +517,20 @@ impl<W: WriteColor> Standard<W> {
|
|||||||
matcher: M,
|
matcher: M,
|
||||||
path: &'p P,
|
path: &'p P,
|
||||||
) -> StandardSink<'p, 's, M, W>
|
) -> StandardSink<'p, 's, M, W>
|
||||||
where
|
where M: Matcher,
|
||||||
M: Matcher,
|
P: ?Sized + AsRef<Path>,
|
||||||
P: ?Sized + AsRef<Path>,
|
|
||||||
{
|
{
|
||||||
if !self.config.path {
|
if !self.config.path {
|
||||||
return self.sink(matcher);
|
return self.sink(matcher);
|
||||||
}
|
}
|
||||||
let stats = if self.config.stats { Some(Stats::new()) } else { None };
|
let stats =
|
||||||
|
if self.config.stats {
|
||||||
|
Some(Stats::new())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
let ppath = PrinterPath::with_separator(
|
let ppath = PrinterPath::with_separator(
|
||||||
path.as_ref(),
|
path.as_ref(), self.config.separator_path);
|
||||||
self.config.separator_path,
|
|
||||||
);
|
|
||||||
let needs_match_granularity = self.needs_match_granularity();
|
let needs_match_granularity = self.needs_match_granularity();
|
||||||
StandardSink {
|
StandardSink {
|
||||||
matcher: matcher,
|
matcher: matcher,
|
||||||
@@ -675,12 +689,10 @@ impl<'p, 's, M: Matcher, W: WriteColor> StandardSink<'p, 's, M, W> {
|
|||||||
// one search to find the matches (well, for replacements, we do one
|
// one search to find the matches (well, for replacements, we do one
|
||||||
// additional search to perform the actual replacement).
|
// additional search to perform the actual replacement).
|
||||||
let matches = &mut self.standard.matches;
|
let matches = &mut self.standard.matches;
|
||||||
self.matcher
|
self.matcher.find_iter(bytes, |m| {
|
||||||
.find_iter(bytes, |m| {
|
matches.push(m);
|
||||||
matches.push(m);
|
true
|
||||||
true
|
}).map_err(io::Error::error_message)?;
|
||||||
})
|
|
||||||
.map_err(io::Error::error_message)?;
|
|
||||||
// Don't report empty matches appearing at the end of the bytes.
|
// Don't report empty matches appearing at the end of the bytes.
|
||||||
if !matches.is_empty()
|
if !matches.is_empty()
|
||||||
&& matches.last().unwrap().is_empty()
|
&& matches.last().unwrap().is_empty()
|
||||||
@@ -702,7 +714,11 @@ impl<'p, 's, M: Matcher, W: WriteColor> StandardSink<'p, 's, M, W> {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|r| &*r)
|
.map(|r| &*r)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
self.replacer.replace_all(&self.matcher, bytes, replacement)?;
|
self.replacer.replace_all(
|
||||||
|
&self.matcher,
|
||||||
|
bytes,
|
||||||
|
replacement,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -795,7 +811,10 @@ impl<'p, 's, M: Matcher, W: WriteColor> Sink for StandardSink<'p, 's, M, W> {
|
|||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn begin(&mut self, _searcher: &Searcher) -> Result<bool, io::Error> {
|
fn begin(
|
||||||
|
&mut self,
|
||||||
|
_searcher: &Searcher,
|
||||||
|
) -> Result<bool, io::Error> {
|
||||||
self.standard.wtr.borrow_mut().reset_count();
|
self.standard.wtr.borrow_mut().reset_count();
|
||||||
self.start_time = Instant::now();
|
self.start_time = Instant::now();
|
||||||
self.match_count = 0;
|
self.match_count = 0;
|
||||||
@@ -868,7 +887,10 @@ impl<'a, M: Matcher, W: WriteColor> StandardImpl<'a, M, W> {
|
|||||||
&sink.standard.matches,
|
&sink.standard.matches,
|
||||||
sink.replacer.replacement(),
|
sink.replacer.replacement(),
|
||||||
);
|
);
|
||||||
StandardImpl { sunk: sunk, ..StandardImpl::new(searcher, sink) }
|
StandardImpl {
|
||||||
|
sunk: sunk,
|
||||||
|
..StandardImpl::new(searcher, sink)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bundle self with a searcher and return the core implementation of Sink
|
/// Bundle self with a searcher and return the core implementation of Sink
|
||||||
@@ -883,7 +905,10 @@ impl<'a, M: Matcher, W: WriteColor> StandardImpl<'a, M, W> {
|
|||||||
&sink.standard.matches,
|
&sink.standard.matches,
|
||||||
sink.replacer.replacement(),
|
sink.replacer.replacement(),
|
||||||
);
|
);
|
||||||
StandardImpl { sunk: sunk, ..StandardImpl::new(searcher, sink) }
|
StandardImpl {
|
||||||
|
sunk: sunk,
|
||||||
|
..StandardImpl::new(searcher, sink)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sink(&self) -> io::Result<()> {
|
fn sink(&self) -> io::Result<()> {
|
||||||
@@ -1059,7 +1084,10 @@ impl<'a, M: Matcher, W: WriteColor> StandardImpl<'a, M, W> {
|
|||||||
line = line.with_start(upto);
|
line = line.with_start(upto);
|
||||||
if self.exceeds_max_columns(&bytes[this_line]) {
|
if self.exceeds_max_columns(&bytes[this_line]) {
|
||||||
self.write_exceeded_line(
|
self.write_exceeded_line(
|
||||||
bytes, this_line, matches, &mut midx,
|
bytes,
|
||||||
|
this_line,
|
||||||
|
matches,
|
||||||
|
&mut midx,
|
||||||
)?;
|
)?;
|
||||||
} else {
|
} else {
|
||||||
self.write_spec(spec, &bytes[this_line])?;
|
self.write_spec(spec, &bytes[this_line])?;
|
||||||
@@ -1150,14 +1178,14 @@ impl<'a, M: Matcher, W: WriteColor> StandardImpl<'a, M, W> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn write_line(&self, line: &[u8]) -> io::Result<()> {
|
fn write_line(
|
||||||
|
&self,
|
||||||
|
line: &[u8],
|
||||||
|
) -> io::Result<()> {
|
||||||
if self.exceeds_max_columns(line) {
|
if self.exceeds_max_columns(line) {
|
||||||
let range = Match::new(0, line.len());
|
let range = Match::new(0, line.len());
|
||||||
self.write_exceeded_line(
|
self.write_exceeded_line(
|
||||||
line,
|
line, range, self.sunk.matches(), &mut 0,
|
||||||
range,
|
|
||||||
self.sunk.matches(),
|
|
||||||
&mut 0,
|
|
||||||
)?;
|
)?;
|
||||||
} else {
|
} else {
|
||||||
self.write_trim(line)?;
|
self.write_trim(line)?;
|
||||||
@@ -1251,8 +1279,7 @@ impl<'a, M: Matcher, W: WriteColor> StandardImpl<'a, M, W> {
|
|||||||
.map(|(_, end, _)| end)
|
.map(|(_, end, _)| end)
|
||||||
.take(self.config().max_columns.unwrap_or(0) as usize)
|
.take(self.config().max_columns.unwrap_or(0) as usize)
|
||||||
.last()
|
.last()
|
||||||
.unwrap_or(0)
|
.unwrap_or(0) + line.start();
|
||||||
+ line.start();
|
|
||||||
line = line.with_end(end);
|
line = line.with_end(end);
|
||||||
self.write_colored_matches(bytes, line, matches, match_index)?;
|
self.write_colored_matches(bytes, line, matches, match_index)?;
|
||||||
|
|
||||||
@@ -1265,12 +1292,16 @@ impl<'a, M: Matcher, W: WriteColor> StandardImpl<'a, M, W> {
|
|||||||
m.start() >= line.end() && m.start() < original.end()
|
m.start() >= line.end() && m.start() < original.end()
|
||||||
})
|
})
|
||||||
.count();
|
.count();
|
||||||
let tense = if remaining == 1 { "match" } else { "matches" };
|
let tense =
|
||||||
|
if remaining == 1 {
|
||||||
|
"match"
|
||||||
|
} else {
|
||||||
|
"matches"
|
||||||
|
};
|
||||||
write!(
|
write!(
|
||||||
self.wtr().borrow_mut(),
|
self.wtr().borrow_mut(),
|
||||||
" [... {} more {}]",
|
" [... {} more {}]",
|
||||||
remaining,
|
remaining, tense,
|
||||||
tense,
|
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
self.write_line_term()?;
|
self.write_line_term()?;
|
||||||
@@ -1365,8 +1396,7 @@ impl<'a, M: Matcher, W: WriteColor> StandardImpl<'a, M, W> {
|
|||||||
}
|
}
|
||||||
let remainder = format!(
|
let remainder = format!(
|
||||||
"after match (found {:?} byte around offset {})\n",
|
"after match (found {:?} byte around offset {})\n",
|
||||||
[byte].as_bstr(),
|
[byte].as_bstr(), offset,
|
||||||
offset,
|
|
||||||
);
|
);
|
||||||
self.write(remainder.as_bytes())?;
|
self.write(remainder.as_bytes())?;
|
||||||
} else if let Some(byte) = bin.convert_byte() {
|
} else if let Some(byte) = bin.convert_byte() {
|
||||||
@@ -1377,8 +1407,7 @@ impl<'a, M: Matcher, W: WriteColor> StandardImpl<'a, M, W> {
|
|||||||
}
|
}
|
||||||
let remainder = format!(
|
let remainder = format!(
|
||||||
"matches (found {:?} byte around offset {})\n",
|
"matches (found {:?} byte around offset {})\n",
|
||||||
[byte].as_bstr(),
|
[byte].as_bstr(), offset,
|
||||||
offset,
|
|
||||||
);
|
);
|
||||||
self.write(remainder.as_bytes())?;
|
self.write(remainder.as_bytes())?;
|
||||||
}
|
}
|
||||||
@@ -1571,14 +1600,17 @@ but Doctor Watson has to have it taken out for him and dusted,\r
|
|||||||
and exhibited clearly, with a label attached.\
|
and exhibited clearly, with a label attached.\
|
||||||
";
|
";
|
||||||
|
|
||||||
fn printer_contents(printer: &mut Standard<NoColor<Vec<u8>>>) -> String {
|
fn printer_contents(
|
||||||
|
printer: &mut Standard<NoColor<Vec<u8>>>,
|
||||||
|
) -> String {
|
||||||
String::from_utf8(printer.get_mut().get_ref().to_owned()).unwrap()
|
String::from_utf8(printer.get_mut().get_ref().to_owned()).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn reports_match() {
|
fn reports_match() {
|
||||||
let matcher = RegexMatcher::new("Sherlock").unwrap();
|
let matcher = RegexMatcher::new("Sherlock").unwrap();
|
||||||
let mut printer = StandardBuilder::new().build(NoColor::new(vec![]));
|
let mut printer = StandardBuilder::new()
|
||||||
|
.build(NoColor::new(vec![]));
|
||||||
let mut sink = printer.sink(&matcher);
|
let mut sink = printer.sink(&matcher);
|
||||||
SearcherBuilder::new()
|
SearcherBuilder::new()
|
||||||
.line_number(false)
|
.line_number(false)
|
||||||
@@ -1588,7 +1620,8 @@ and exhibited clearly, with a label attached.\
|
|||||||
assert!(sink.has_match());
|
assert!(sink.has_match());
|
||||||
|
|
||||||
let matcher = RegexMatcher::new("zzzzz").unwrap();
|
let matcher = RegexMatcher::new("zzzzz").unwrap();
|
||||||
let mut printer = StandardBuilder::new().build(NoColor::new(vec![]));
|
let mut printer = StandardBuilder::new()
|
||||||
|
.build(NoColor::new(vec![]));
|
||||||
let mut sink = printer.sink(&matcher);
|
let mut sink = printer.sink(&matcher);
|
||||||
SearcherBuilder::new()
|
SearcherBuilder::new()
|
||||||
.line_number(false)
|
.line_number(false)
|
||||||
@@ -1603,7 +1636,8 @@ and exhibited clearly, with a label attached.\
|
|||||||
use grep_searcher::BinaryDetection;
|
use grep_searcher::BinaryDetection;
|
||||||
|
|
||||||
let matcher = RegexMatcher::new("Sherlock").unwrap();
|
let matcher = RegexMatcher::new("Sherlock").unwrap();
|
||||||
let mut printer = StandardBuilder::new().build(NoColor::new(vec![]));
|
let mut printer = StandardBuilder::new()
|
||||||
|
.build(NoColor::new(vec![]));
|
||||||
let mut sink = printer.sink(&matcher);
|
let mut sink = printer.sink(&matcher);
|
||||||
SearcherBuilder::new()
|
SearcherBuilder::new()
|
||||||
.line_number(false)
|
.line_number(false)
|
||||||
@@ -1613,7 +1647,8 @@ and exhibited clearly, with a label attached.\
|
|||||||
assert!(sink.binary_byte_offset().is_none());
|
assert!(sink.binary_byte_offset().is_none());
|
||||||
|
|
||||||
let matcher = RegexMatcher::new(".+").unwrap();
|
let matcher = RegexMatcher::new(".+").unwrap();
|
||||||
let mut printer = StandardBuilder::new().build(NoColor::new(vec![]));
|
let mut printer = StandardBuilder::new()
|
||||||
|
.build(NoColor::new(vec![]));
|
||||||
let mut sink = printer.sink(&matcher);
|
let mut sink = printer.sink(&matcher);
|
||||||
SearcherBuilder::new()
|
SearcherBuilder::new()
|
||||||
.line_number(false)
|
.line_number(false)
|
||||||
@@ -1629,8 +1664,9 @@ and exhibited clearly, with a label attached.\
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
let matcher = RegexMatcher::new("Sherlock|opposed").unwrap();
|
let matcher = RegexMatcher::new("Sherlock|opposed").unwrap();
|
||||||
let mut printer =
|
let mut printer = StandardBuilder::new()
|
||||||
StandardBuilder::new().stats(true).build(NoColor::new(vec![]));
|
.stats(true)
|
||||||
|
.build(NoColor::new(vec![]));
|
||||||
let stats = {
|
let stats = {
|
||||||
let mut sink = printer.sink(&matcher);
|
let mut sink = printer.sink(&matcher);
|
||||||
SearcherBuilder::new()
|
SearcherBuilder::new()
|
||||||
@@ -1649,6 +1685,7 @@ and exhibited clearly, with a label attached.\
|
|||||||
assert_eq!(stats.bytes_printed(), buf.len() as u64);
|
assert_eq!(stats.bytes_printed(), buf.len() as u64);
|
||||||
assert_eq!(stats.matched_lines(), 2);
|
assert_eq!(stats.matched_lines(), 2);
|
||||||
assert_eq!(stats.matches(), 3);
|
assert_eq!(stats.matches(), 3);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -1656,8 +1693,9 @@ and exhibited clearly, with a label attached.\
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
let matcher = RegexMatcher::new("Sherlock|opposed").unwrap();
|
let matcher = RegexMatcher::new("Sherlock|opposed").unwrap();
|
||||||
let mut printer =
|
let mut printer = StandardBuilder::new()
|
||||||
StandardBuilder::new().stats(true).build(NoColor::new(vec![]));
|
.stats(true)
|
||||||
|
.build(NoColor::new(vec![]));
|
||||||
let stats = {
|
let stats = {
|
||||||
let mut sink = printer.sink(&matcher);
|
let mut sink = printer.sink(&matcher);
|
||||||
SearcherBuilder::new()
|
SearcherBuilder::new()
|
||||||
@@ -1822,8 +1860,9 @@ and exhibited clearly, with a label attached.
|
|||||||
#[test]
|
#[test]
|
||||||
fn path() {
|
fn path() {
|
||||||
let matcher = RegexMatcher::new("Watson").unwrap();
|
let matcher = RegexMatcher::new("Watson").unwrap();
|
||||||
let mut printer =
|
let mut printer = StandardBuilder::new()
|
||||||
StandardBuilder::new().path(false).build(NoColor::new(vec![]));
|
.path(false)
|
||||||
|
.build(NoColor::new(vec![]));
|
||||||
SearcherBuilder::new()
|
SearcherBuilder::new()
|
||||||
.line_number(true)
|
.line_number(true)
|
||||||
.build()
|
.build()
|
||||||
@@ -1924,8 +1963,9 @@ books/sherlockZbut Doctor Watson has to have it taken out for him and dusted,
|
|||||||
#[test]
|
#[test]
|
||||||
fn heading() {
|
fn heading() {
|
||||||
let matcher = RegexMatcher::new("Watson").unwrap();
|
let matcher = RegexMatcher::new("Watson").unwrap();
|
||||||
let mut printer =
|
let mut printer = StandardBuilder::new()
|
||||||
StandardBuilder::new().heading(true).build(NoColor::new(vec![]));
|
.heading(true)
|
||||||
|
.build(NoColor::new(vec![]));
|
||||||
SearcherBuilder::new()
|
SearcherBuilder::new()
|
||||||
.line_number(false)
|
.line_number(false)
|
||||||
.build()
|
.build()
|
||||||
@@ -1948,8 +1988,9 @@ but Doctor Watson has to have it taken out for him and dusted,
|
|||||||
#[test]
|
#[test]
|
||||||
fn no_heading() {
|
fn no_heading() {
|
||||||
let matcher = RegexMatcher::new("Watson").unwrap();
|
let matcher = RegexMatcher::new("Watson").unwrap();
|
||||||
let mut printer =
|
let mut printer = StandardBuilder::new()
|
||||||
StandardBuilder::new().heading(false).build(NoColor::new(vec![]));
|
.heading(false)
|
||||||
|
.build(NoColor::new(vec![]));
|
||||||
SearcherBuilder::new()
|
SearcherBuilder::new()
|
||||||
.line_number(false)
|
.line_number(false)
|
||||||
.build()
|
.build()
|
||||||
@@ -1971,8 +2012,9 @@ sherlock:but Doctor Watson has to have it taken out for him and dusted,
|
|||||||
#[test]
|
#[test]
|
||||||
fn no_heading_multiple() {
|
fn no_heading_multiple() {
|
||||||
let matcher = RegexMatcher::new("Watson").unwrap();
|
let matcher = RegexMatcher::new("Watson").unwrap();
|
||||||
let mut printer =
|
let mut printer = StandardBuilder::new()
|
||||||
StandardBuilder::new().heading(false).build(NoColor::new(vec![]));
|
.heading(false)
|
||||||
|
.build(NoColor::new(vec![]));
|
||||||
SearcherBuilder::new()
|
SearcherBuilder::new()
|
||||||
.line_number(false)
|
.line_number(false)
|
||||||
.build()
|
.build()
|
||||||
@@ -2007,8 +2049,9 @@ sherlock:be, to a very large extent, the result of luck. Sherlock Holmes
|
|||||||
#[test]
|
#[test]
|
||||||
fn heading_multiple() {
|
fn heading_multiple() {
|
||||||
let matcher = RegexMatcher::new("Watson").unwrap();
|
let matcher = RegexMatcher::new("Watson").unwrap();
|
||||||
let mut printer =
|
let mut printer = StandardBuilder::new()
|
||||||
StandardBuilder::new().heading(true).build(NoColor::new(vec![]));
|
.heading(true)
|
||||||
|
.build(NoColor::new(vec![]));
|
||||||
SearcherBuilder::new()
|
SearcherBuilder::new()
|
||||||
.line_number(false)
|
.line_number(false)
|
||||||
.build()
|
.build()
|
||||||
@@ -2118,7 +2161,8 @@ Watson
|
|||||||
#[test]
|
#[test]
|
||||||
fn line_number() {
|
fn line_number() {
|
||||||
let matcher = RegexMatcher::new("Watson").unwrap();
|
let matcher = RegexMatcher::new("Watson").unwrap();
|
||||||
let mut printer = StandardBuilder::new().build(NoColor::new(vec![]));
|
let mut printer = StandardBuilder::new()
|
||||||
|
.build(NoColor::new(vec![]));
|
||||||
SearcherBuilder::new()
|
SearcherBuilder::new()
|
||||||
.line_number(true)
|
.line_number(true)
|
||||||
.build()
|
.build()
|
||||||
@@ -2140,7 +2184,8 @@ Watson
|
|||||||
#[test]
|
#[test]
|
||||||
fn line_number_multi_line() {
|
fn line_number_multi_line() {
|
||||||
let matcher = RegexMatcher::new("(?s)Watson.+Watson").unwrap();
|
let matcher = RegexMatcher::new("(?s)Watson.+Watson").unwrap();
|
||||||
let mut printer = StandardBuilder::new().build(NoColor::new(vec![]));
|
let mut printer = StandardBuilder::new()
|
||||||
|
.build(NoColor::new(vec![]));
|
||||||
SearcherBuilder::new()
|
SearcherBuilder::new()
|
||||||
.line_number(true)
|
.line_number(true)
|
||||||
.multi_line(true)
|
.multi_line(true)
|
||||||
@@ -2166,8 +2211,9 @@ Watson
|
|||||||
#[test]
|
#[test]
|
||||||
fn column_number() {
|
fn column_number() {
|
||||||
let matcher = RegexMatcher::new("Watson").unwrap();
|
let matcher = RegexMatcher::new("Watson").unwrap();
|
||||||
let mut printer =
|
let mut printer = StandardBuilder::new()
|
||||||
StandardBuilder::new().column(true).build(NoColor::new(vec![]));
|
.column(true)
|
||||||
|
.build(NoColor::new(vec![]));
|
||||||
SearcherBuilder::new()
|
SearcherBuilder::new()
|
||||||
.line_number(false)
|
.line_number(false)
|
||||||
.build()
|
.build()
|
||||||
@@ -2189,8 +2235,9 @@ Watson
|
|||||||
#[test]
|
#[test]
|
||||||
fn column_number_multi_line() {
|
fn column_number_multi_line() {
|
||||||
let matcher = RegexMatcher::new("(?s)Watson.+Watson").unwrap();
|
let matcher = RegexMatcher::new("(?s)Watson.+Watson").unwrap();
|
||||||
let mut printer =
|
let mut printer = StandardBuilder::new()
|
||||||
StandardBuilder::new().column(true).build(NoColor::new(vec![]));
|
.column(true)
|
||||||
|
.build(NoColor::new(vec![]));
|
||||||
SearcherBuilder::new()
|
SearcherBuilder::new()
|
||||||
.line_number(false)
|
.line_number(false)
|
||||||
.multi_line(true)
|
.multi_line(true)
|
||||||
@@ -2393,8 +2440,9 @@ and exhibited clearly, with a label attached.
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn max_columns_with_count_preview_two_matches() {
|
fn max_columns_with_count_preview_two_matches() {
|
||||||
let matcher =
|
let matcher = RegexMatcher::new(
|
||||||
RegexMatcher::new("exhibited|dusted|has to have it").unwrap();
|
"exhibited|dusted|has to have it",
|
||||||
|
).unwrap();
|
||||||
let mut printer = StandardBuilder::new()
|
let mut printer = StandardBuilder::new()
|
||||||
.stats(true)
|
.stats(true)
|
||||||
.max_columns(Some(46))
|
.max_columns(Some(46))
|
||||||
@@ -2445,9 +2493,9 @@ but Doctor Watson has to have it taken out for him and dusted,
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn max_columns_multi_line_preview() {
|
fn max_columns_multi_line_preview() {
|
||||||
let matcher =
|
let matcher = RegexMatcher::new(
|
||||||
RegexMatcher::new("(?s)clew|cigar ash.+have it|exhibited")
|
"(?s)clew|cigar ash.+have it|exhibited",
|
||||||
.unwrap();
|
).unwrap();
|
||||||
let mut printer = StandardBuilder::new()
|
let mut printer = StandardBuilder::new()
|
||||||
.stats(true)
|
.stats(true)
|
||||||
.max_columns(Some(46))
|
.max_columns(Some(46))
|
||||||
@@ -2625,8 +2673,9 @@ For the Doctor Watsons of this world, as opposed to the Sherlock
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn max_matches_multi_line2() {
|
fn max_matches_multi_line2() {
|
||||||
let matcher =
|
let matcher = RegexMatcher::new(
|
||||||
RegexMatcher::new(r"(?s)Watson.+?(Holmeses|clearly)").unwrap();
|
r"(?s)Watson.+?(Holmeses|clearly)"
|
||||||
|
).unwrap();
|
||||||
let mut printer = StandardBuilder::new()
|
let mut printer = StandardBuilder::new()
|
||||||
.max_matches(Some(1))
|
.max_matches(Some(1))
|
||||||
.build(NoColor::new(vec![]));
|
.build(NoColor::new(vec![]));
|
||||||
@@ -2677,8 +2726,9 @@ Holmeses, success in the province of detective work must always
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn only_matching_multi_line1() {
|
fn only_matching_multi_line1() {
|
||||||
let matcher =
|
let matcher = RegexMatcher::new(
|
||||||
RegexMatcher::new(r"(?s:.{0})(Doctor Watsons|Sherlock)").unwrap();
|
r"(?s:.{0})(Doctor Watsons|Sherlock)"
|
||||||
|
).unwrap();
|
||||||
let mut printer = StandardBuilder::new()
|
let mut printer = StandardBuilder::new()
|
||||||
.only_matching(true)
|
.only_matching(true)
|
||||||
.column(true)
|
.column(true)
|
||||||
@@ -2705,8 +2755,9 @@ Holmeses, success in the province of detective work must always
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn only_matching_multi_line2() {
|
fn only_matching_multi_line2() {
|
||||||
let matcher =
|
let matcher = RegexMatcher::new(
|
||||||
RegexMatcher::new(r"(?s)Watson.+?(Holmeses|clearly)").unwrap();
|
r"(?s)Watson.+?(Holmeses|clearly)"
|
||||||
|
).unwrap();
|
||||||
let mut printer = StandardBuilder::new()
|
let mut printer = StandardBuilder::new()
|
||||||
.only_matching(true)
|
.only_matching(true)
|
||||||
.column(true)
|
.column(true)
|
||||||
@@ -2793,8 +2844,9 @@ Holmeses, success in the province of detective work must always
|
|||||||
// can match across multiple lines without actually doing so. This is
|
// can match across multiple lines without actually doing so. This is
|
||||||
// so we can test multi-line handling in the case of a match on only
|
// so we can test multi-line handling in the case of a match on only
|
||||||
// one line.
|
// one line.
|
||||||
let matcher =
|
let matcher = RegexMatcher::new(
|
||||||
RegexMatcher::new(r"(?s:.{0})(Doctor Watsons|Sherlock)").unwrap();
|
r"(?s:.{0})(Doctor Watsons|Sherlock)"
|
||||||
|
).unwrap();
|
||||||
let mut printer = StandardBuilder::new()
|
let mut printer = StandardBuilder::new()
|
||||||
.only_matching(true)
|
.only_matching(true)
|
||||||
.max_columns(Some(10))
|
.max_columns(Some(10))
|
||||||
@@ -2826,8 +2878,9 @@ Holmeses, success in the province of detective work must always
|
|||||||
// can match across multiple lines without actually doing so. This is
|
// can match across multiple lines without actually doing so. This is
|
||||||
// so we can test multi-line handling in the case of a match on only
|
// so we can test multi-line handling in the case of a match on only
|
||||||
// one line.
|
// one line.
|
||||||
let matcher =
|
let matcher = RegexMatcher::new(
|
||||||
RegexMatcher::new(r"(?s:.{0})(Doctor Watsons|Sherlock)").unwrap();
|
r"(?s:.{0})(Doctor Watsons|Sherlock)"
|
||||||
|
).unwrap();
|
||||||
let mut printer = StandardBuilder::new()
|
let mut printer = StandardBuilder::new()
|
||||||
.only_matching(true)
|
.only_matching(true)
|
||||||
.max_columns(Some(10))
|
.max_columns(Some(10))
|
||||||
@@ -2856,8 +2909,9 @@ Holmeses, success in the province of detective work must always
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn only_matching_max_columns_multi_line2() {
|
fn only_matching_max_columns_multi_line2() {
|
||||||
let matcher =
|
let matcher = RegexMatcher::new(
|
||||||
RegexMatcher::new(r"(?s)Watson.+?(Holmeses|clearly)").unwrap();
|
r"(?s)Watson.+?(Holmeses|clearly)"
|
||||||
|
).unwrap();
|
||||||
let mut printer = StandardBuilder::new()
|
let mut printer = StandardBuilder::new()
|
||||||
.only_matching(true)
|
.only_matching(true)
|
||||||
.max_columns(Some(50))
|
.max_columns(Some(50))
|
||||||
@@ -2886,8 +2940,9 @@ Holmeses, success in the province of detective work must always
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn only_matching_max_columns_preview_multi_line2() {
|
fn only_matching_max_columns_preview_multi_line2() {
|
||||||
let matcher =
|
let matcher = RegexMatcher::new(
|
||||||
RegexMatcher::new(r"(?s)Watson.+?(Holmeses|clearly)").unwrap();
|
r"(?s)Watson.+?(Holmeses|clearly)"
|
||||||
|
).unwrap();
|
||||||
let mut printer = StandardBuilder::new()
|
let mut printer = StandardBuilder::new()
|
||||||
.only_matching(true)
|
.only_matching(true)
|
||||||
.max_columns(Some(50))
|
.max_columns(Some(50))
|
||||||
@@ -2943,8 +2998,9 @@ Holmeses, success in the province of detective work must always
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn per_match_multi_line1() {
|
fn per_match_multi_line1() {
|
||||||
let matcher =
|
let matcher = RegexMatcher::new(
|
||||||
RegexMatcher::new(r"(?s:.{0})(Doctor Watsons|Sherlock)").unwrap();
|
r"(?s:.{0})(Doctor Watsons|Sherlock)"
|
||||||
|
).unwrap();
|
||||||
let mut printer = StandardBuilder::new()
|
let mut printer = StandardBuilder::new()
|
||||||
.per_match(true)
|
.per_match(true)
|
||||||
.column(true)
|
.column(true)
|
||||||
@@ -2971,8 +3027,9 @@ Holmeses, success in the province of detective work must always
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn per_match_multi_line2() {
|
fn per_match_multi_line2() {
|
||||||
let matcher =
|
let matcher = RegexMatcher::new(
|
||||||
RegexMatcher::new(r"(?s)Watson.+?(Holmeses|clearly)").unwrap();
|
r"(?s)Watson.+?(Holmeses|clearly)",
|
||||||
|
).unwrap();
|
||||||
let mut printer = StandardBuilder::new()
|
let mut printer = StandardBuilder::new()
|
||||||
.per_match(true)
|
.per_match(true)
|
||||||
.column(true)
|
.column(true)
|
||||||
@@ -3000,8 +3057,9 @@ Holmeses, success in the province of detective work must always
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn per_match_multi_line3() {
|
fn per_match_multi_line3() {
|
||||||
let matcher =
|
let matcher = RegexMatcher::new(
|
||||||
RegexMatcher::new(r"(?s)Watson.+?Holmeses|always.+?be").unwrap();
|
r"(?s)Watson.+?Holmeses|always.+?be",
|
||||||
|
).unwrap();
|
||||||
let mut printer = StandardBuilder::new()
|
let mut printer = StandardBuilder::new()
|
||||||
.per_match(true)
|
.per_match(true)
|
||||||
.column(true)
|
.column(true)
|
||||||
@@ -3136,8 +3194,9 @@ Holmeses, success in the province of detective work must always
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn replacement_max_columns_preview2() {
|
fn replacement_max_columns_preview2() {
|
||||||
let matcher =
|
let matcher = RegexMatcher::new(
|
||||||
RegexMatcher::new("exhibited|dusted|has to have it").unwrap();
|
"exhibited|dusted|has to have it",
|
||||||
|
).unwrap();
|
||||||
let mut printer = StandardBuilder::new()
|
let mut printer = StandardBuilder::new()
|
||||||
.max_columns(Some(43))
|
.max_columns(Some(43))
|
||||||
.max_columns_preview(true)
|
.max_columns_preview(true)
|
||||||
@@ -3218,7 +3277,8 @@ and xxx clearly, with a label attached.
|
|||||||
#[test]
|
#[test]
|
||||||
fn invert() {
|
fn invert() {
|
||||||
let matcher = RegexMatcher::new(r"Sherlock").unwrap();
|
let matcher = RegexMatcher::new(r"Sherlock").unwrap();
|
||||||
let mut printer = StandardBuilder::new().build(NoColor::new(vec![]));
|
let mut printer = StandardBuilder::new()
|
||||||
|
.build(NoColor::new(vec![]));
|
||||||
SearcherBuilder::new()
|
SearcherBuilder::new()
|
||||||
.line_number(true)
|
.line_number(true)
|
||||||
.invert_match(true)
|
.invert_match(true)
|
||||||
@@ -3243,7 +3303,8 @@ and xxx clearly, with a label attached.
|
|||||||
#[test]
|
#[test]
|
||||||
fn invert_multi_line() {
|
fn invert_multi_line() {
|
||||||
let matcher = RegexMatcher::new(r"(?s:.{0})Sherlock").unwrap();
|
let matcher = RegexMatcher::new(r"(?s:.{0})Sherlock").unwrap();
|
||||||
let mut printer = StandardBuilder::new().build(NoColor::new(vec![]));
|
let mut printer = StandardBuilder::new()
|
||||||
|
.build(NoColor::new(vec![]));
|
||||||
SearcherBuilder::new()
|
SearcherBuilder::new()
|
||||||
.multi_line(true)
|
.multi_line(true)
|
||||||
.line_number(true)
|
.line_number(true)
|
||||||
@@ -3269,7 +3330,8 @@ and xxx clearly, with a label attached.
|
|||||||
#[test]
|
#[test]
|
||||||
fn invert_context() {
|
fn invert_context() {
|
||||||
let matcher = RegexMatcher::new(r"Sherlock").unwrap();
|
let matcher = RegexMatcher::new(r"Sherlock").unwrap();
|
||||||
let mut printer = StandardBuilder::new().build(NoColor::new(vec![]));
|
let mut printer = StandardBuilder::new()
|
||||||
|
.build(NoColor::new(vec![]));
|
||||||
SearcherBuilder::new()
|
SearcherBuilder::new()
|
||||||
.line_number(true)
|
.line_number(true)
|
||||||
.invert_match(true)
|
.invert_match(true)
|
||||||
@@ -3298,7 +3360,8 @@ and xxx clearly, with a label attached.
|
|||||||
#[test]
|
#[test]
|
||||||
fn invert_context_multi_line() {
|
fn invert_context_multi_line() {
|
||||||
let matcher = RegexMatcher::new(r"(?s:.{0})Sherlock").unwrap();
|
let matcher = RegexMatcher::new(r"(?s:.{0})Sherlock").unwrap();
|
||||||
let mut printer = StandardBuilder::new().build(NoColor::new(vec![]));
|
let mut printer = StandardBuilder::new()
|
||||||
|
.build(NoColor::new(vec![]));
|
||||||
SearcherBuilder::new()
|
SearcherBuilder::new()
|
||||||
.multi_line(true)
|
.multi_line(true)
|
||||||
.line_number(true)
|
.line_number(true)
|
@@ -34,8 +34,8 @@ impl<'a> Add<&'a Stats> for Stats {
|
|||||||
Stats {
|
Stats {
|
||||||
elapsed: NiceDuration(self.elapsed.0 + rhs.elapsed.0),
|
elapsed: NiceDuration(self.elapsed.0 + rhs.elapsed.0),
|
||||||
searches: self.searches + rhs.searches,
|
searches: self.searches + rhs.searches,
|
||||||
searches_with_match: self.searches_with_match
|
searches_with_match:
|
||||||
+ rhs.searches_with_match,
|
self.searches_with_match + rhs.searches_with_match,
|
||||||
bytes_searched: self.bytes_searched + rhs.bytes_searched,
|
bytes_searched: self.bytes_searched + rhs.bytes_searched,
|
||||||
bytes_printed: self.bytes_printed + rhs.bytes_printed,
|
bytes_printed: self.bytes_printed + rhs.bytes_printed,
|
||||||
matched_lines: self.matched_lines + rhs.matched_lines,
|
matched_lines: self.matched_lines + rhs.matched_lines,
|
@@ -168,7 +168,10 @@ impl SummaryBuilder {
|
|||||||
///
|
///
|
||||||
/// This is a convenience routine for
|
/// This is a convenience routine for
|
||||||
/// `SummaryBuilder::build(termcolor::NoColor::new(wtr))`.
|
/// `SummaryBuilder::build(termcolor::NoColor::new(wtr))`.
|
||||||
pub fn build_no_color<W: io::Write>(&self, wtr: W) -> Summary<NoColor<W>> {
|
pub fn build_no_color<W: io::Write>(
|
||||||
|
&self,
|
||||||
|
wtr: W,
|
||||||
|
) -> Summary<NoColor<W>> {
|
||||||
self.build(NoColor::new(wtr))
|
self.build(NoColor::new(wtr))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,9 +202,10 @@ impl SummaryBuilder {
|
|||||||
/// This completely overrides any previous color specifications. This does
|
/// This completely overrides any previous color specifications. This does
|
||||||
/// not add to any previously provided color specifications on this
|
/// not add to any previously provided color specifications on this
|
||||||
/// builder.
|
/// builder.
|
||||||
///
|
pub fn color_specs(
|
||||||
/// The default color specifications provide no styling.
|
&mut self,
|
||||||
pub fn color_specs(&mut self, specs: ColorSpecs) -> &mut SummaryBuilder {
|
specs: ColorSpecs,
|
||||||
|
) -> &mut SummaryBuilder {
|
||||||
self.config.colors = specs;
|
self.config.colors = specs;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@@ -252,8 +256,6 @@ impl SummaryBuilder {
|
|||||||
/// If multi line search is enabled and a match spans multiple lines, then
|
/// If multi line search is enabled and a match spans multiple lines, then
|
||||||
/// that match is counted exactly once for the purposes of enforcing this
|
/// that match is counted exactly once for the purposes of enforcing this
|
||||||
/// limit, regardless of how many lines it spans.
|
/// limit, regardless of how many lines it spans.
|
||||||
///
|
|
||||||
/// This is disabled by default.
|
|
||||||
pub fn max_matches(&mut self, limit: Option<u64>) -> &mut SummaryBuilder {
|
pub fn max_matches(&mut self, limit: Option<u64>) -> &mut SummaryBuilder {
|
||||||
self.config.max_matches = limit;
|
self.config.max_matches = limit;
|
||||||
self
|
self
|
||||||
@@ -264,8 +266,6 @@ impl SummaryBuilder {
|
|||||||
/// When enabled and the mode is either `Count` or `CountMatches`, then
|
/// When enabled and the mode is either `Count` or `CountMatches`, then
|
||||||
/// results are not printed if no matches were found. Otherwise, every
|
/// results are not printed if no matches were found. Otherwise, every
|
||||||
/// search prints a result with a possibly `0` number of matches.
|
/// search prints a result with a possibly `0` number of matches.
|
||||||
///
|
|
||||||
/// This is enabled by default.
|
|
||||||
pub fn exclude_zero(&mut self, yes: bool) -> &mut SummaryBuilder {
|
pub fn exclude_zero(&mut self, yes: bool) -> &mut SummaryBuilder {
|
||||||
self.config.exclude_zero = yes;
|
self.config.exclude_zero = yes;
|
||||||
self
|
self
|
||||||
@@ -275,7 +275,10 @@ impl SummaryBuilder {
|
|||||||
/// `CountMatches` modes.
|
/// `CountMatches` modes.
|
||||||
///
|
///
|
||||||
/// By default, this is set to `:`.
|
/// By default, this is set to `:`.
|
||||||
pub fn separator_field(&mut self, sep: Vec<u8>) -> &mut SummaryBuilder {
|
pub fn separator_field(
|
||||||
|
&mut self,
|
||||||
|
sep: Vec<u8>,
|
||||||
|
) -> &mut SummaryBuilder {
|
||||||
self.config.separator_field = Arc::new(sep);
|
self.config.separator_field = Arc::new(sep);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@@ -289,9 +292,10 @@ impl SummaryBuilder {
|
|||||||
/// A typical use for this option is to permit cygwin users on Windows to
|
/// A typical use for this option is to permit cygwin users on Windows to
|
||||||
/// set the path separator to `/` instead of using the system default of
|
/// set the path separator to `/` instead of using the system default of
|
||||||
/// `\`.
|
/// `\`.
|
||||||
///
|
pub fn separator_path(
|
||||||
/// This is disabled by default.
|
&mut self,
|
||||||
pub fn separator_path(&mut self, sep: Option<u8>) -> &mut SummaryBuilder {
|
sep: Option<u8>,
|
||||||
|
) -> &mut SummaryBuilder {
|
||||||
self.config.separator_path = sep;
|
self.config.separator_path = sep;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@@ -370,11 +374,12 @@ impl<W: WriteColor> Summary<W> {
|
|||||||
&'s mut self,
|
&'s mut self,
|
||||||
matcher: M,
|
matcher: M,
|
||||||
) -> SummarySink<'static, 's, M, W> {
|
) -> SummarySink<'static, 's, M, W> {
|
||||||
let stats = if self.config.stats || self.config.kind.requires_stats() {
|
let stats =
|
||||||
Some(Stats::new())
|
if self.config.stats || self.config.kind.requires_stats() {
|
||||||
} else {
|
Some(Stats::new())
|
||||||
None
|
} else {
|
||||||
};
|
None
|
||||||
|
};
|
||||||
SummarySink {
|
SummarySink {
|
||||||
matcher: matcher,
|
matcher: matcher,
|
||||||
summary: self,
|
summary: self,
|
||||||
@@ -395,22 +400,20 @@ impl<W: WriteColor> Summary<W> {
|
|||||||
matcher: M,
|
matcher: M,
|
||||||
path: &'p P,
|
path: &'p P,
|
||||||
) -> SummarySink<'p, 's, M, W>
|
) -> SummarySink<'p, 's, M, W>
|
||||||
where
|
where M: Matcher,
|
||||||
M: Matcher,
|
P: ?Sized + AsRef<Path>,
|
||||||
P: ?Sized + AsRef<Path>,
|
|
||||||
{
|
{
|
||||||
if !self.config.path && !self.config.kind.requires_path() {
|
if !self.config.path && !self.config.kind.requires_path() {
|
||||||
return self.sink(matcher);
|
return self.sink(matcher);
|
||||||
}
|
}
|
||||||
let stats = if self.config.stats || self.config.kind.requires_stats() {
|
let stats =
|
||||||
Some(Stats::new())
|
if self.config.stats || self.config.kind.requires_stats() {
|
||||||
} else {
|
Some(Stats::new())
|
||||||
None
|
} else {
|
||||||
};
|
None
|
||||||
|
};
|
||||||
let ppath = PrinterPath::with_separator(
|
let ppath = PrinterPath::with_separator(
|
||||||
path.as_ref(),
|
path.as_ref(), self.config.separator_path);
|
||||||
self.config.separator_path,
|
|
||||||
);
|
|
||||||
SummarySink {
|
SummarySink {
|
||||||
matcher: matcher,
|
matcher: matcher,
|
||||||
summary: self,
|
summary: self,
|
||||||
@@ -585,12 +588,10 @@ impl<'p, 's, M: Matcher, W: WriteColor> Sink for SummarySink<'p, 's, M, W> {
|
|||||||
self.match_count += 1;
|
self.match_count += 1;
|
||||||
if let Some(ref mut stats) = self.stats {
|
if let Some(ref mut stats) = self.stats {
|
||||||
let mut match_count = 0;
|
let mut match_count = 0;
|
||||||
self.matcher
|
self.matcher.find_iter(mat.bytes(), |_| {
|
||||||
.find_iter(mat.bytes(), |_| {
|
match_count += 1;
|
||||||
match_count += 1;
|
true
|
||||||
true
|
}).map_err(io::Error::error_message)?;
|
||||||
})
|
|
||||||
.map_err(io::Error::error_message)?;
|
|
||||||
stats.add_matches(match_count);
|
stats.add_matches(match_count);
|
||||||
stats.add_matched_lines(mat.lines().count() as u64);
|
stats.add_matched_lines(mat.lines().count() as u64);
|
||||||
} else if self.summary.config.kind.quit_early() {
|
} else if self.summary.config.kind.quit_early() {
|
||||||
@@ -599,7 +600,10 @@ impl<'p, 's, M: Matcher, W: WriteColor> Sink for SummarySink<'p, 's, M, W> {
|
|||||||
Ok(!self.should_quit())
|
Ok(!self.should_quit())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn begin(&mut self, _searcher: &Searcher) -> Result<bool, io::Error> {
|
fn begin(
|
||||||
|
&mut self,
|
||||||
|
_searcher: &Searcher,
|
||||||
|
) -> Result<bool, io::Error> {
|
||||||
if self.path.is_none() && self.summary.config.kind.requires_path() {
|
if self.path.is_none() && self.summary.config.kind.requires_path() {
|
||||||
return Err(io::Error::error_message(format!(
|
return Err(io::Error::error_message(format!(
|
||||||
"output kind {:?} requires a file path",
|
"output kind {:?} requires a file path",
|
||||||
@@ -662,7 +666,8 @@ impl<'p, 's, M: Matcher, W: WriteColor> Sink for SummarySink<'p, 's, M, W> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let show_count =
|
let show_count =
|
||||||
!self.summary.config.exclude_zero || self.match_count > 0;
|
!self.summary.config.exclude_zero
|
||||||
|
|| self.match_count > 0;
|
||||||
match self.summary.config.kind {
|
match self.summary.config.kind {
|
||||||
SummaryKind::Count => {
|
SummaryKind::Count => {
|
||||||
if show_count {
|
if show_count {
|
||||||
@@ -673,8 +678,7 @@ impl<'p, 's, M: Matcher, W: WriteColor> Sink for SummarySink<'p, 's, M, W> {
|
|||||||
}
|
}
|
||||||
SummaryKind::CountMatches => {
|
SummaryKind::CountMatches => {
|
||||||
if show_count {
|
if show_count {
|
||||||
let stats = self
|
let stats = self.stats
|
||||||
.stats
|
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.expect("CountMatches should enable stats tracking");
|
.expect("CountMatches should enable stats tracking");
|
||||||
self.write_path_field()?;
|
self.write_path_field()?;
|
||||||
@@ -704,7 +708,7 @@ mod tests {
|
|||||||
use grep_searcher::SearcherBuilder;
|
use grep_searcher::SearcherBuilder;
|
||||||
use termcolor::NoColor;
|
use termcolor::NoColor;
|
||||||
|
|
||||||
use super::{Summary, SummaryBuilder, SummaryKind};
|
use super::{Summary, SummaryKind, SummaryBuilder};
|
||||||
|
|
||||||
const SHERLOCK: &'static [u8] = b"\
|
const SHERLOCK: &'static [u8] = b"\
|
||||||
For the Doctor Watsons of this world, as opposed to the Sherlock
|
For the Doctor Watsons of this world, as opposed to the Sherlock
|
||||||
@@ -715,41 +719,45 @@ but Doctor Watson has to have it taken out for him and dusted,
|
|||||||
and exhibited clearly, with a label attached.
|
and exhibited clearly, with a label attached.
|
||||||
";
|
";
|
||||||
|
|
||||||
fn printer_contents(printer: &mut Summary<NoColor<Vec<u8>>>) -> String {
|
fn printer_contents(
|
||||||
|
printer: &mut Summary<NoColor<Vec<u8>>>,
|
||||||
|
) -> String {
|
||||||
String::from_utf8(printer.get_mut().get_ref().to_owned()).unwrap()
|
String::from_utf8(printer.get_mut().get_ref().to_owned()).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn path_with_match_error() {
|
fn path_with_match_error() {
|
||||||
let matcher = RegexMatcher::new(r"Watson").unwrap();
|
let matcher = RegexMatcher::new(
|
||||||
|
r"Watson"
|
||||||
|
).unwrap();
|
||||||
let mut printer = SummaryBuilder::new()
|
let mut printer = SummaryBuilder::new()
|
||||||
.kind(SummaryKind::PathWithMatch)
|
.kind(SummaryKind::PathWithMatch)
|
||||||
.build_no_color(vec![]);
|
.build_no_color(vec![]);
|
||||||
let res = SearcherBuilder::new().build().search_reader(
|
let res = SearcherBuilder::new()
|
||||||
&matcher,
|
.build()
|
||||||
SHERLOCK,
|
.search_reader(&matcher, SHERLOCK, printer.sink(&matcher));
|
||||||
printer.sink(&matcher),
|
|
||||||
);
|
|
||||||
assert!(res.is_err());
|
assert!(res.is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn path_without_match_error() {
|
fn path_without_match_error() {
|
||||||
let matcher = RegexMatcher::new(r"Watson").unwrap();
|
let matcher = RegexMatcher::new(
|
||||||
|
r"Watson"
|
||||||
|
).unwrap();
|
||||||
let mut printer = SummaryBuilder::new()
|
let mut printer = SummaryBuilder::new()
|
||||||
.kind(SummaryKind::PathWithoutMatch)
|
.kind(SummaryKind::PathWithoutMatch)
|
||||||
.build_no_color(vec![]);
|
.build_no_color(vec![]);
|
||||||
let res = SearcherBuilder::new().build().search_reader(
|
let res = SearcherBuilder::new()
|
||||||
&matcher,
|
.build()
|
||||||
SHERLOCK,
|
.search_reader(&matcher, SHERLOCK, printer.sink(&matcher));
|
||||||
printer.sink(&matcher),
|
|
||||||
);
|
|
||||||
assert!(res.is_err());
|
assert!(res.is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn count_no_path() {
|
fn count_no_path() {
|
||||||
let matcher = RegexMatcher::new(r"Watson").unwrap();
|
let matcher = RegexMatcher::new(
|
||||||
|
r"Watson"
|
||||||
|
).unwrap();
|
||||||
let mut printer = SummaryBuilder::new()
|
let mut printer = SummaryBuilder::new()
|
||||||
.kind(SummaryKind::Count)
|
.kind(SummaryKind::Count)
|
||||||
.build_no_color(vec![]);
|
.build_no_color(vec![]);
|
||||||
@@ -764,7 +772,9 @@ and exhibited clearly, with a label attached.
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn count_no_path_even_with_path() {
|
fn count_no_path_even_with_path() {
|
||||||
let matcher = RegexMatcher::new(r"Watson").unwrap();
|
let matcher = RegexMatcher::new(
|
||||||
|
r"Watson"
|
||||||
|
).unwrap();
|
||||||
let mut printer = SummaryBuilder::new()
|
let mut printer = SummaryBuilder::new()
|
||||||
.kind(SummaryKind::Count)
|
.kind(SummaryKind::Count)
|
||||||
.path(false)
|
.path(false)
|
||||||
@@ -784,7 +794,9 @@ and exhibited clearly, with a label attached.
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn count_path() {
|
fn count_path() {
|
||||||
let matcher = RegexMatcher::new(r"Watson").unwrap();
|
let matcher = RegexMatcher::new(
|
||||||
|
r"Watson"
|
||||||
|
).unwrap();
|
||||||
let mut printer = SummaryBuilder::new()
|
let mut printer = SummaryBuilder::new()
|
||||||
.kind(SummaryKind::Count)
|
.kind(SummaryKind::Count)
|
||||||
.build_no_color(vec![]);
|
.build_no_color(vec![]);
|
||||||
@@ -803,7 +815,9 @@ and exhibited clearly, with a label attached.
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn count_path_with_zero() {
|
fn count_path_with_zero() {
|
||||||
let matcher = RegexMatcher::new(r"NO MATCH").unwrap();
|
let matcher = RegexMatcher::new(
|
||||||
|
r"NO MATCH"
|
||||||
|
).unwrap();
|
||||||
let mut printer = SummaryBuilder::new()
|
let mut printer = SummaryBuilder::new()
|
||||||
.kind(SummaryKind::Count)
|
.kind(SummaryKind::Count)
|
||||||
.exclude_zero(false)
|
.exclude_zero(false)
|
||||||
@@ -823,7 +837,9 @@ and exhibited clearly, with a label attached.
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn count_path_without_zero() {
|
fn count_path_without_zero() {
|
||||||
let matcher = RegexMatcher::new(r"NO MATCH").unwrap();
|
let matcher = RegexMatcher::new(
|
||||||
|
r"NO MATCH"
|
||||||
|
).unwrap();
|
||||||
let mut printer = SummaryBuilder::new()
|
let mut printer = SummaryBuilder::new()
|
||||||
.kind(SummaryKind::Count)
|
.kind(SummaryKind::Count)
|
||||||
.exclude_zero(true)
|
.exclude_zero(true)
|
||||||
@@ -843,7 +859,9 @@ and exhibited clearly, with a label attached.
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn count_path_field_separator() {
|
fn count_path_field_separator() {
|
||||||
let matcher = RegexMatcher::new(r"Watson").unwrap();
|
let matcher = RegexMatcher::new(
|
||||||
|
r"Watson"
|
||||||
|
).unwrap();
|
||||||
let mut printer = SummaryBuilder::new()
|
let mut printer = SummaryBuilder::new()
|
||||||
.kind(SummaryKind::Count)
|
.kind(SummaryKind::Count)
|
||||||
.separator_field(b"ZZ".to_vec())
|
.separator_field(b"ZZ".to_vec())
|
||||||
@@ -863,7 +881,9 @@ and exhibited clearly, with a label attached.
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn count_path_terminator() {
|
fn count_path_terminator() {
|
||||||
let matcher = RegexMatcher::new(r"Watson").unwrap();
|
let matcher = RegexMatcher::new(
|
||||||
|
r"Watson"
|
||||||
|
).unwrap();
|
||||||
let mut printer = SummaryBuilder::new()
|
let mut printer = SummaryBuilder::new()
|
||||||
.kind(SummaryKind::Count)
|
.kind(SummaryKind::Count)
|
||||||
.path_terminator(Some(b'\x00'))
|
.path_terminator(Some(b'\x00'))
|
||||||
@@ -883,7 +903,9 @@ and exhibited clearly, with a label attached.
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn count_path_separator() {
|
fn count_path_separator() {
|
||||||
let matcher = RegexMatcher::new(r"Watson").unwrap();
|
let matcher = RegexMatcher::new(
|
||||||
|
r"Watson"
|
||||||
|
).unwrap();
|
||||||
let mut printer = SummaryBuilder::new()
|
let mut printer = SummaryBuilder::new()
|
||||||
.kind(SummaryKind::Count)
|
.kind(SummaryKind::Count)
|
||||||
.separator_path(Some(b'\\'))
|
.separator_path(Some(b'\\'))
|
||||||
@@ -903,7 +925,9 @@ and exhibited clearly, with a label attached.
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn count_max_matches() {
|
fn count_max_matches() {
|
||||||
let matcher = RegexMatcher::new(r"Watson").unwrap();
|
let matcher = RegexMatcher::new(
|
||||||
|
r"Watson"
|
||||||
|
).unwrap();
|
||||||
let mut printer = SummaryBuilder::new()
|
let mut printer = SummaryBuilder::new()
|
||||||
.kind(SummaryKind::Count)
|
.kind(SummaryKind::Count)
|
||||||
.max_matches(Some(1))
|
.max_matches(Some(1))
|
||||||
@@ -919,7 +943,9 @@ and exhibited clearly, with a label attached.
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn count_matches() {
|
fn count_matches() {
|
||||||
let matcher = RegexMatcher::new(r"Watson|Sherlock").unwrap();
|
let matcher = RegexMatcher::new(
|
||||||
|
r"Watson|Sherlock"
|
||||||
|
).unwrap();
|
||||||
let mut printer = SummaryBuilder::new()
|
let mut printer = SummaryBuilder::new()
|
||||||
.kind(SummaryKind::CountMatches)
|
.kind(SummaryKind::CountMatches)
|
||||||
.build_no_color(vec![]);
|
.build_no_color(vec![]);
|
||||||
@@ -938,7 +964,9 @@ and exhibited clearly, with a label attached.
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn path_with_match_found() {
|
fn path_with_match_found() {
|
||||||
let matcher = RegexMatcher::new(r"Watson").unwrap();
|
let matcher = RegexMatcher::new(
|
||||||
|
r"Watson"
|
||||||
|
).unwrap();
|
||||||
let mut printer = SummaryBuilder::new()
|
let mut printer = SummaryBuilder::new()
|
||||||
.kind(SummaryKind::PathWithMatch)
|
.kind(SummaryKind::PathWithMatch)
|
||||||
.build_no_color(vec![]);
|
.build_no_color(vec![]);
|
||||||
@@ -957,7 +985,9 @@ and exhibited clearly, with a label attached.
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn path_with_match_not_found() {
|
fn path_with_match_not_found() {
|
||||||
let matcher = RegexMatcher::new(r"ZZZZZZZZ").unwrap();
|
let matcher = RegexMatcher::new(
|
||||||
|
r"ZZZZZZZZ"
|
||||||
|
).unwrap();
|
||||||
let mut printer = SummaryBuilder::new()
|
let mut printer = SummaryBuilder::new()
|
||||||
.kind(SummaryKind::PathWithMatch)
|
.kind(SummaryKind::PathWithMatch)
|
||||||
.build_no_color(vec![]);
|
.build_no_color(vec![]);
|
||||||
@@ -974,9 +1004,12 @@ and exhibited clearly, with a label attached.
|
|||||||
assert_eq_printed!("", got);
|
assert_eq_printed!("", got);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn path_without_match_found() {
|
fn path_without_match_found() {
|
||||||
let matcher = RegexMatcher::new(r"ZZZZZZZZZ").unwrap();
|
let matcher = RegexMatcher::new(
|
||||||
|
r"ZZZZZZZZZ"
|
||||||
|
).unwrap();
|
||||||
let mut printer = SummaryBuilder::new()
|
let mut printer = SummaryBuilder::new()
|
||||||
.kind(SummaryKind::PathWithoutMatch)
|
.kind(SummaryKind::PathWithoutMatch)
|
||||||
.build_no_color(vec![]);
|
.build_no_color(vec![]);
|
||||||
@@ -995,7 +1028,9 @@ and exhibited clearly, with a label attached.
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn path_without_match_not_found() {
|
fn path_without_match_not_found() {
|
||||||
let matcher = RegexMatcher::new(r"Watson").unwrap();
|
let matcher = RegexMatcher::new(
|
||||||
|
r"Watson"
|
||||||
|
).unwrap();
|
||||||
let mut printer = SummaryBuilder::new()
|
let mut printer = SummaryBuilder::new()
|
||||||
.kind(SummaryKind::PathWithoutMatch)
|
.kind(SummaryKind::PathWithoutMatch)
|
||||||
.build_no_color(vec![]);
|
.build_no_color(vec![]);
|
||||||
@@ -1014,7 +1049,9 @@ and exhibited clearly, with a label attached.
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn quiet() {
|
fn quiet() {
|
||||||
let matcher = RegexMatcher::new(r"Watson|Sherlock").unwrap();
|
let matcher = RegexMatcher::new(
|
||||||
|
r"Watson|Sherlock"
|
||||||
|
).unwrap();
|
||||||
let mut printer = SummaryBuilder::new()
|
let mut printer = SummaryBuilder::new()
|
||||||
.kind(SummaryKind::Quiet)
|
.kind(SummaryKind::Quiet)
|
||||||
.build_no_color(vec![]);
|
.build_no_color(vec![]);
|
||||||
@@ -1036,7 +1073,9 @@ and exhibited clearly, with a label attached.
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn quiet_with_stats() {
|
fn quiet_with_stats() {
|
||||||
let matcher = RegexMatcher::new(r"Watson|Sherlock").unwrap();
|
let matcher = RegexMatcher::new(
|
||||||
|
r"Watson|Sherlock"
|
||||||
|
).unwrap();
|
||||||
let mut printer = SummaryBuilder::new()
|
let mut printer = SummaryBuilder::new()
|
||||||
.kind(SummaryKind::Quiet)
|
.kind(SummaryKind::Quiet)
|
||||||
.stats(true)
|
.stats(true)
|
@@ -7,7 +7,8 @@ use std::time;
|
|||||||
use bstr::{ByteSlice, ByteVec};
|
use bstr::{ByteSlice, ByteVec};
|
||||||
use grep_matcher::{Captures, LineTerminator, Match, Matcher};
|
use grep_matcher::{Captures, LineTerminator, Match, Matcher};
|
||||||
use grep_searcher::{
|
use grep_searcher::{
|
||||||
LineIter, SinkContext, SinkContextKind, SinkError, SinkMatch,
|
LineIter,
|
||||||
|
SinkError, SinkContext, SinkContextKind, SinkMatch,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "serde1")]
|
#[cfg(feature = "serde1")]
|
||||||
use serde::{Serialize, Serializer};
|
use serde::{Serialize, Serializer};
|
||||||
@@ -57,13 +58,19 @@ impl<M: Matcher> Replacer<M> {
|
|||||||
replacement: &[u8],
|
replacement: &[u8],
|
||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
{
|
{
|
||||||
let &mut Space { ref mut dst, ref mut caps, ref mut matches } =
|
let &mut Space {
|
||||||
self.allocate(matcher)?;
|
ref mut dst,
|
||||||
|
ref mut caps,
|
||||||
|
ref mut matches,
|
||||||
|
} = self.allocate(matcher)?;
|
||||||
dst.clear();
|
dst.clear();
|
||||||
matches.clear();
|
matches.clear();
|
||||||
|
|
||||||
matcher
|
matcher.replace_with_captures(
|
||||||
.replace_with_captures(subject, caps, dst, |caps, dst| {
|
subject,
|
||||||
|
caps,
|
||||||
|
dst,
|
||||||
|
|caps, dst| {
|
||||||
let start = dst.len();
|
let start = dst.len();
|
||||||
caps.interpolate(
|
caps.interpolate(
|
||||||
|name| matcher.capture_index(name),
|
|name| matcher.capture_index(name),
|
||||||
@@ -74,8 +81,8 @@ impl<M: Matcher> Replacer<M> {
|
|||||||
let end = dst.len();
|
let end = dst.len();
|
||||||
matches.push(Match::new(start, end));
|
matches.push(Match::new(start, end));
|
||||||
true
|
true
|
||||||
})
|
},
|
||||||
.map_err(io::Error::error_message)?;
|
).map_err(io::Error::error_message)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -115,10 +122,14 @@ impl<M: Matcher> Replacer<M> {
|
|||||||
/// matcher fails.
|
/// matcher fails.
|
||||||
fn allocate(&mut self, matcher: &M) -> io::Result<&mut Space<M>> {
|
fn allocate(&mut self, matcher: &M) -> io::Result<&mut Space<M>> {
|
||||||
if self.space.is_none() {
|
if self.space.is_none() {
|
||||||
let caps =
|
let caps = matcher
|
||||||
matcher.new_captures().map_err(io::Error::error_message)?;
|
.new_captures()
|
||||||
self.space =
|
.map_err(io::Error::error_message)?;
|
||||||
Some(Space { caps: caps, dst: vec![], matches: vec![] });
|
self.space = Some(Space {
|
||||||
|
caps: caps,
|
||||||
|
dst: vec![],
|
||||||
|
matches: vec![],
|
||||||
|
});
|
||||||
}
|
}
|
||||||
Ok(self.space.as_mut().unwrap())
|
Ok(self.space.as_mut().unwrap())
|
||||||
}
|
}
|
||||||
@@ -165,8 +176,9 @@ impl<'a> Sunk<'a> {
|
|||||||
original_matches: &'a [Match],
|
original_matches: &'a [Match],
|
||||||
replacement: Option<(&'a [u8], &'a [Match])>,
|
replacement: Option<(&'a [u8], &'a [Match])>,
|
||||||
) -> Sunk<'a> {
|
) -> Sunk<'a> {
|
||||||
let (bytes, matches) =
|
let (bytes, matches) = replacement.unwrap_or_else(|| {
|
||||||
replacement.unwrap_or_else(|| (sunk.bytes(), original_matches));
|
(sunk.bytes(), original_matches)
|
||||||
|
});
|
||||||
Sunk {
|
Sunk {
|
||||||
bytes: bytes,
|
bytes: bytes,
|
||||||
absolute_byte_offset: sunk.absolute_byte_offset(),
|
absolute_byte_offset: sunk.absolute_byte_offset(),
|
||||||
@@ -183,8 +195,9 @@ impl<'a> Sunk<'a> {
|
|||||||
original_matches: &'a [Match],
|
original_matches: &'a [Match],
|
||||||
replacement: Option<(&'a [u8], &'a [Match])>,
|
replacement: Option<(&'a [u8], &'a [Match])>,
|
||||||
) -> Sunk<'a> {
|
) -> Sunk<'a> {
|
||||||
let (bytes, matches) =
|
let (bytes, matches) = replacement.unwrap_or_else(|| {
|
||||||
replacement.unwrap_or_else(|| (sunk.bytes(), original_matches));
|
(sunk.bytes(), original_matches)
|
||||||
|
});
|
||||||
Sunk {
|
Sunk {
|
||||||
bytes: bytes,
|
bytes: bytes,
|
||||||
absolute_byte_offset: sunk.absolute_byte_offset(),
|
absolute_byte_offset: sunk.absolute_byte_offset(),
|
||||||
@@ -276,17 +289,13 @@ impl<'a> PrinterPath<'a> {
|
|||||||
/// path separators that are both replaced by `new_sep`. In all other
|
/// path separators that are both replaced by `new_sep`. In all other
|
||||||
/// environments, only `/` is treated as a path separator.
|
/// environments, only `/` is treated as a path separator.
|
||||||
fn replace_separator(&mut self, new_sep: u8) {
|
fn replace_separator(&mut self, new_sep: u8) {
|
||||||
let transformed_path: Vec<u8> = self
|
let transformed_path: Vec<u8> = self.0.bytes().map(|b| {
|
||||||
.0
|
if b == b'/' || (cfg!(windows) && b == b'\\') {
|
||||||
.bytes()
|
new_sep
|
||||||
.map(|b| {
|
} else {
|
||||||
if b == b'/' || (cfg!(windows) && b == b'\\') {
|
b
|
||||||
new_sep
|
}
|
||||||
} else {
|
}).collect();
|
||||||
b
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
self.0 = Cow::Owned(transformed_path);
|
self.0 = Cow::Owned(transformed_path);
|
||||||
}
|
}
|
||||||
|
|
@@ -1,22 +1,21 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "grep-regex"
|
name = "grep-regex"
|
||||||
version = "0.1.7" #:version
|
version = "0.1.5" #:version
|
||||||
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
||||||
description = """
|
description = """
|
||||||
Use Rust's regex library with the 'grep' crate.
|
Use Rust's regex library with the 'grep' crate.
|
||||||
"""
|
"""
|
||||||
documentation = "https://docs.rs/grep-regex"
|
documentation = "https://docs.rs/grep-regex"
|
||||||
homepage = "https://github.com/BurntSushi/ripgrep/tree/master/crates/regex"
|
homepage = "https://github.com/BurntSushi/ripgrep"
|
||||||
repository = "https://github.com/BurntSushi/ripgrep/tree/master/crates/regex"
|
repository = "https://github.com/BurntSushi/ripgrep"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
keywords = ["regex", "grep", "search", "pattern", "line"]
|
keywords = ["regex", "grep", "search", "pattern", "line"]
|
||||||
license = "Unlicense/MIT"
|
license = "Unlicense/MIT"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
aho-corasick = "0.7.3"
|
aho-corasick = "0.7.3"
|
||||||
bstr = "0.2.10"
|
grep-matcher = { version = "0.1.2", path = "../grep-matcher" }
|
||||||
grep-matcher = { version = "0.1.2", path = "../matcher" }
|
|
||||||
log = "0.4.5"
|
log = "0.4.5"
|
||||||
regex = "1.1"
|
regex = "1.1"
|
||||||
regex-syntax = "0.6.5"
|
regex-syntax = "0.6.5"
|
||||||
thread_local = "1"
|
thread_local = "0.3.6"
|
@@ -1,5 +1,5 @@
|
|||||||
use regex_syntax::ast::parse::Parser;
|
|
||||||
use regex_syntax::ast::{self, Ast};
|
use regex_syntax::ast::{self, Ast};
|
||||||
|
use regex_syntax::ast::parse::Parser;
|
||||||
|
|
||||||
/// The results of analyzing AST of a regular expression (e.g., for supporting
|
/// The results of analyzing AST of a regular expression (e.g., for supporting
|
||||||
/// smart case).
|
/// smart case).
|
@@ -51,8 +51,8 @@ impl Default for Config {
|
|||||||
octal: false,
|
octal: false,
|
||||||
// These size limits are much bigger than what's in the regex
|
// These size limits are much bigger than what's in the regex
|
||||||
// crate.
|
// crate.
|
||||||
size_limit: 100 * (1 << 20),
|
size_limit: 100 * (1<<20),
|
||||||
dfa_size_limit: 1000 * (1 << 20),
|
dfa_size_limit: 1000 * (1<<20),
|
||||||
nest_limit: 250,
|
nest_limit: 250,
|
||||||
line_terminator: None,
|
line_terminator: None,
|
||||||
crlf: false,
|
crlf: false,
|
||||||
@@ -87,7 +87,7 @@ impl Config {
|
|||||||
Ok(ConfiguredHIR {
|
Ok(ConfiguredHIR {
|
||||||
original: pattern.to_string(),
|
original: pattern.to_string(),
|
||||||
config: self.clone(),
|
config: self.clone(),
|
||||||
analysis,
|
analysis: analysis,
|
||||||
// If CRLF mode is enabled, replace `$` with `(?:\r?$)`.
|
// If CRLF mode is enabled, replace `$` with `(?:\r?$)`.
|
||||||
expr: if self.crlf { crlfify(expr) } else { expr },
|
expr: if self.crlf { crlfify(expr) } else { expr },
|
||||||
})
|
})
|
||||||
@@ -95,7 +95,10 @@ impl Config {
|
|||||||
|
|
||||||
/// Accounting for the `smart_case` config knob, return true if and only if
|
/// Accounting for the `smart_case` config knob, return true if and only if
|
||||||
/// this pattern should be matched case insensitively.
|
/// this pattern should be matched case insensitively.
|
||||||
fn is_case_insensitive(&self, analysis: &AstAnalysis) -> bool {
|
fn is_case_insensitive(
|
||||||
|
&self,
|
||||||
|
analysis: &AstAnalysis,
|
||||||
|
) -> bool {
|
||||||
if self.case_insensitive {
|
if self.case_insensitive {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -113,7 +116,9 @@ impl Config {
|
|||||||
/// are enabled, since if multi-line can impact the match semantics of a
|
/// are enabled, since if multi-line can impact the match semantics of a
|
||||||
/// regex, then it is by definition not a simple alternation of literals.
|
/// regex, then it is by definition not a simple alternation of literals.
|
||||||
pub fn can_plain_aho_corasick(&self) -> bool {
|
pub fn can_plain_aho_corasick(&self) -> bool {
|
||||||
!self.word && !self.case_insensitive && !self.case_smart
|
!self.word
|
||||||
|
&& !self.case_insensitive
|
||||||
|
&& !self.case_smart
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform analysis on the AST of this pattern.
|
/// Perform analysis on the AST of this pattern.
|
||||||
@@ -198,7 +203,8 @@ impl ConfiguredHIR {
|
|||||||
pub fn with_pattern<F: FnMut(&str) -> String>(
|
pub fn with_pattern<F: FnMut(&str) -> String>(
|
||||||
&self,
|
&self,
|
||||||
mut f: F,
|
mut f: F,
|
||||||
) -> Result<ConfiguredHIR, Error> {
|
) -> Result<ConfiguredHIR, Error>
|
||||||
|
{
|
||||||
self.pattern_to_hir(&f(&self.expr.to_string()))
|
self.pattern_to_hir(&f(&self.expr.to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,7 +288,7 @@ impl ConfiguredHIR {
|
|||||||
original: self.original.clone(),
|
original: self.original.clone(),
|
||||||
config: self.config.clone(),
|
config: self.config.clone(),
|
||||||
analysis: self.analysis.clone(),
|
analysis: self.analysis.clone(),
|
||||||
expr,
|
expr: expr,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -76,8 +76,9 @@ impl Matcher for CRLFMatcher {
|
|||||||
caps: &mut RegexCaptures,
|
caps: &mut RegexCaptures,
|
||||||
) -> Result<bool, NoError> {
|
) -> Result<bool, NoError> {
|
||||||
caps.strip_crlf(false);
|
caps.strip_crlf(false);
|
||||||
let r =
|
let r = self.regex.captures_read_at(
|
||||||
self.regex.captures_read_at(caps.locations_mut(), haystack, at);
|
caps.locations_mut(), haystack, at,
|
||||||
|
);
|
||||||
if !r.is_some() {
|
if !r.is_some() {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
@@ -162,8 +163,8 @@ pub fn crlfify(expr: Hir) -> Hir {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::crlfify;
|
|
||||||
use regex_syntax::Parser;
|
use regex_syntax::Parser;
|
||||||
|
use super::crlfify;
|
||||||
|
|
||||||
fn roundtrip(pattern: &str) -> String {
|
fn roundtrip(pattern: &str) -> String {
|
||||||
let expr1 = Parser::new().parse(pattern).unwrap();
|
let expr1 = Parser::new().parse(pattern).unwrap();
|
@@ -5,7 +5,6 @@ An implementation of `grep-matcher`'s `Matcher` trait for Rust's regex engine.
|
|||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
|
|
||||||
extern crate aho_corasick;
|
extern crate aho_corasick;
|
||||||
extern crate bstr;
|
|
||||||
extern crate grep_matcher;
|
extern crate grep_matcher;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
@@ -5,9 +5,10 @@ the regex engine doesn't look for inner literals. Since we're doing line based
|
|||||||
searching, we can use them, so we need to do it ourselves.
|
searching, we can use them, so we need to do it ourselves.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use bstr::ByteSlice;
|
use std::cmp;
|
||||||
use regex_syntax::hir::literal::{Literal, Literals};
|
|
||||||
use regex_syntax::hir::{self, Hir, HirKind};
|
use regex_syntax::hir::{self, Hir, HirKind};
|
||||||
|
use regex_syntax::hir::literal::{Literal, Literals};
|
||||||
|
|
||||||
use util;
|
use util;
|
||||||
|
|
||||||
@@ -36,7 +37,7 @@ impl LiteralSets {
|
|||||||
LiteralSets {
|
LiteralSets {
|
||||||
prefixes: Literals::prefixes(expr),
|
prefixes: Literals::prefixes(expr),
|
||||||
suffixes: Literals::suffixes(expr),
|
suffixes: Literals::suffixes(expr),
|
||||||
required,
|
required: required,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,12 +101,7 @@ impl LiteralSets {
|
|||||||
// helps with case insensitive matching, which can generate lots of
|
// helps with case insensitive matching, which can generate lots of
|
||||||
// inner required literals.
|
// inner required literals.
|
||||||
let any_empty = req_lits.iter().any(|lit| lit.is_empty());
|
let any_empty = req_lits.iter().any(|lit| lit.is_empty());
|
||||||
let any_white = has_only_whitespace(&req_lits);
|
if req.len() > lit.len() && req_lits.len() > 1 && !any_empty {
|
||||||
if req.len() > lit.len()
|
|
||||||
&& req_lits.len() > 1
|
|
||||||
&& !any_empty
|
|
||||||
&& !any_white
|
|
||||||
{
|
|
||||||
debug!("required literals found: {:?}", req_lits);
|
debug!("required literals found: {:?}", req_lits);
|
||||||
let alts: Vec<String> = req_lits
|
let alts: Vec<String> = req_lits
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@@ -114,74 +110,9 @@ impl LiteralSets {
|
|||||||
// We're matching raw bytes, so disable Unicode mode.
|
// We're matching raw bytes, so disable Unicode mode.
|
||||||
Some(format!("(?-u:{})", alts.join("|")))
|
Some(format!("(?-u:{})", alts.join("|")))
|
||||||
} else if lit.is_empty() {
|
} else if lit.is_empty() {
|
||||||
// If we're here, then we have no LCP. No LCS. And no detected
|
None
|
||||||
// inner required literals. In theory this shouldn't happen, but
|
|
||||||
// the inner literal detector isn't as nice as we hope and doens't
|
|
||||||
// actually support returning a set of alternating required
|
|
||||||
// literals. (Instead, it only returns a set where EVERY literal
|
|
||||||
// in it is required. It cannot currently express "either P or Q
|
|
||||||
// is required.")
|
|
||||||
//
|
|
||||||
// In this case, it is possible that we still have meaningful
|
|
||||||
// prefixes or suffixes to use. So we look for the set of literals
|
|
||||||
// with the highest minimum length and use that to build our "fast"
|
|
||||||
// regex.
|
|
||||||
//
|
|
||||||
// This manifests in fairly common scenarios. e.g.,
|
|
||||||
//
|
|
||||||
// rg -w 'foo|bar|baz|quux'
|
|
||||||
//
|
|
||||||
// Normally, without the `-w`, the regex engine itself would
|
|
||||||
// detect the prefix correctly. Unfortunately, the `-w` option
|
|
||||||
// turns the regex into something like this:
|
|
||||||
//
|
|
||||||
// rg '(^|\W)(foo|bar|baz|quux)($|\W)'
|
|
||||||
//
|
|
||||||
// Which will defeat all prefix and suffix literal optimizations.
|
|
||||||
// (Not in theory---it could be better. But the current
|
|
||||||
// implementation isn't good enough.) ... So we make up for it
|
|
||||||
// here.
|
|
||||||
if !word {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let p_min_len = self.prefixes.min_len();
|
|
||||||
let s_min_len = self.suffixes.min_len();
|
|
||||||
let lits = match (p_min_len, s_min_len) {
|
|
||||||
(None, None) => return None,
|
|
||||||
(Some(_), None) => {
|
|
||||||
debug!("prefix literals found");
|
|
||||||
self.prefixes.literals()
|
|
||||||
}
|
|
||||||
(None, Some(_)) => {
|
|
||||||
debug!("suffix literals found");
|
|
||||||
self.suffixes.literals()
|
|
||||||
}
|
|
||||||
(Some(p), Some(s)) => {
|
|
||||||
if p >= s {
|
|
||||||
debug!("prefix literals found");
|
|
||||||
self.prefixes.literals()
|
|
||||||
} else {
|
|
||||||
debug!("suffix literals found");
|
|
||||||
self.suffixes.literals()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
debug!("prefix/suffix literals found: {:?}", lits);
|
|
||||||
if has_only_whitespace(lits) {
|
|
||||||
debug!("dropping literals because one was whitespace");
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let alts: Vec<String> =
|
|
||||||
lits.into_iter().map(|x| util::bytes_to_regex(x)).collect();
|
|
||||||
// We're matching raw bytes, so disable Unicode mode.
|
|
||||||
Some(format!("(?-u:{})", alts.join("|")))
|
|
||||||
} else {
|
} else {
|
||||||
debug!("required literal found: {:?}", util::show_bytes(lit));
|
debug!("required literal found: {:?}", util::show_bytes(lit));
|
||||||
if lit.chars().all(|c| c.is_whitespace()) {
|
|
||||||
debug!("dropping literal because one was whitespace");
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
Some(format!("(?-u:{})", util::bytes_to_regex(&lit)))
|
Some(format!("(?-u:{})", util::bytes_to_regex(&lit)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -209,28 +140,25 @@ fn union_required(expr: &Hir, lits: &mut Literals) {
|
|||||||
HirKind::Group(hir::Group { ref hir, .. }) => {
|
HirKind::Group(hir::Group { ref hir, .. }) => {
|
||||||
union_required(&**hir, lits);
|
union_required(&**hir, lits);
|
||||||
}
|
}
|
||||||
HirKind::Repetition(ref x) => match x.kind {
|
HirKind::Repetition(ref x) => {
|
||||||
hir::RepetitionKind::ZeroOrOne => lits.cut(),
|
match x.kind {
|
||||||
hir::RepetitionKind::ZeroOrMore => lits.cut(),
|
hir::RepetitionKind::ZeroOrOne => lits.cut(),
|
||||||
hir::RepetitionKind::OneOrMore => {
|
hir::RepetitionKind::ZeroOrMore => lits.cut(),
|
||||||
union_required(&x.hir, lits);
|
hir::RepetitionKind::OneOrMore => {
|
||||||
|
union_required(&x.hir, lits);
|
||||||
|
lits.cut();
|
||||||
|
}
|
||||||
|
hir::RepetitionKind::Range(ref rng) => {
|
||||||
|
let (min, max) = match *rng {
|
||||||
|
hir::RepetitionRange::Exactly(m) => (m, Some(m)),
|
||||||
|
hir::RepetitionRange::AtLeast(m) => (m, None),
|
||||||
|
hir::RepetitionRange::Bounded(m, n) => (m, Some(n)),
|
||||||
|
};
|
||||||
|
repeat_range_literals(
|
||||||
|
&x.hir, min, max, x.greedy, lits, union_required);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
hir::RepetitionKind::Range(ref rng) => {
|
}
|
||||||
let (min, max) = match *rng {
|
|
||||||
hir::RepetitionRange::Exactly(m) => (m, Some(m)),
|
|
||||||
hir::RepetitionRange::AtLeast(m) => (m, None),
|
|
||||||
hir::RepetitionRange::Bounded(m, n) => (m, Some(n)),
|
|
||||||
};
|
|
||||||
repeat_range_literals(
|
|
||||||
&x.hir,
|
|
||||||
min,
|
|
||||||
max,
|
|
||||||
x.greedy,
|
|
||||||
lits,
|
|
||||||
union_required,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
HirKind::Concat(ref es) if es.is_empty() => {}
|
HirKind::Concat(ref es) if es.is_empty() => {}
|
||||||
HirKind::Concat(ref es) if es.len() == 1 => {
|
HirKind::Concat(ref es) if es.len() == 1 => {
|
||||||
union_required(&es[0], lits)
|
union_required(&es[0], lits)
|
||||||
@@ -265,7 +193,7 @@ fn union_required(expr: &Hir, lits: &mut Literals) {
|
|||||||
fn repeat_range_literals<F: FnMut(&Hir, &mut Literals)>(
|
fn repeat_range_literals<F: FnMut(&Hir, &mut Literals)>(
|
||||||
e: &Hir,
|
e: &Hir,
|
||||||
min: u32,
|
min: u32,
|
||||||
_max: Option<u32>,
|
max: Option<u32>,
|
||||||
_greedy: bool,
|
_greedy: bool,
|
||||||
lits: &mut Literals,
|
lits: &mut Literals,
|
||||||
mut f: F,
|
mut f: F,
|
||||||
@@ -276,13 +204,19 @@ fn repeat_range_literals<F: FnMut(&Hir, &mut Literals)>(
|
|||||||
// just treat it as `e*`.
|
// just treat it as `e*`.
|
||||||
lits.cut();
|
lits.cut();
|
||||||
} else {
|
} else {
|
||||||
|
let n = cmp::min(lits.limit_size(), min as usize);
|
||||||
// We only extract literals from a single repetition, even though
|
// We only extract literals from a single repetition, even though
|
||||||
// we could do more. e.g., `a{3}` will have `a` extracted instead of
|
// we could do more. e.g., `a{3}` will have `a` extracted instead of
|
||||||
// `aaa`. The reason is that inner literal extraction can't be unioned
|
// `aaa`. The reason is that inner literal extraction can't be unioned
|
||||||
// across repetitions. e.g., extracting `foofoofoo` from `(\w+foo){3}`
|
// across repetitions. e.g., extracting `foofoofoo` from `(\w+foo){3}`
|
||||||
// is wrong.
|
// is wrong.
|
||||||
f(e, lits);
|
f(e, lits);
|
||||||
lits.cut();
|
if n < min as usize {
|
||||||
|
lits.cut();
|
||||||
|
}
|
||||||
|
if max.map_or(true, |max| min < max) {
|
||||||
|
lits.cut();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -329,9 +263,9 @@ fn is_simple(expr: &Hir) -> bool {
|
|||||||
| HirKind::Repetition(_)
|
| HirKind::Repetition(_)
|
||||||
| HirKind::Concat(_)
|
| HirKind::Concat(_)
|
||||||
| HirKind::Alternation(_) => true,
|
| HirKind::Alternation(_) => true,
|
||||||
HirKind::Anchor(_) | HirKind::WordBoundary(_) | HirKind::Group(_) => {
|
HirKind::Anchor(_)
|
||||||
false
|
| HirKind::WordBoundary(_)
|
||||||
}
|
| HirKind::Group(_) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -345,21 +279,10 @@ fn count_byte_class(cls: &hir::ClassBytes) -> u32 {
|
|||||||
cls.iter().map(|r| 1 + (r.end() as u32 - r.start() as u32)).sum()
|
cls.iter().map(|r| 1 + (r.end() as u32 - r.start() as u32)).sum()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if and only if any of the literals in the given set is
|
|
||||||
/// entirely whitespace.
|
|
||||||
fn has_only_whitespace(lits: &[Literal]) -> bool {
|
|
||||||
for lit in lits {
|
|
||||||
if lit.chars().all(|c| c.is_whitespace()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::LiteralSets;
|
|
||||||
use regex_syntax::Parser;
|
use regex_syntax::Parser;
|
||||||
|
use super::LiteralSets;
|
||||||
|
|
||||||
fn sets(pattern: &str) -> LiteralSets {
|
fn sets(pattern: &str) -> LiteralSets {
|
||||||
let hir = Parser::new().parse(pattern).unwrap();
|
let hir = Parser::new().parse(pattern).unwrap();
|
||||||
@@ -405,15 +328,4 @@ mod tests {
|
|||||||
// assert_eq!(one_regex(r"a.*c"), pat("a"));
|
// assert_eq!(one_regex(r"a.*c"), pat("a"));
|
||||||
assert_eq!(one_regex(r"a(.*c)"), pat("a"));
|
assert_eq!(one_regex(r"a(.*c)"), pat("a"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn regression_1319() {
|
|
||||||
// Regression from:
|
|
||||||
// https://github.com/BurntSushi/ripgrep/issues/1319
|
|
||||||
assert_eq!(
|
|
||||||
one_regex(r"TTGAGTCCAGGAG[ATCG]{2}C"),
|
|
||||||
pat("TTGAGTCCAGGAGA|TTGAGTCCAGGAGC|\
|
|
||||||
TTGAGTCCAGGAGG|TTGAGTCCAGGAGT")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
@@ -1,7 +1,7 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use grep_matcher::{
|
use grep_matcher::{
|
||||||
ByteSet, Captures, LineMatchKind, LineTerminator, Match, Matcher, NoError,
|
Captures, LineMatchKind, LineTerminator, Match, Matcher, NoError, ByteSet,
|
||||||
};
|
};
|
||||||
use regex::bytes::{CaptureLocations, Regex};
|
use regex::bytes::{CaptureLocations, Regex};
|
||||||
|
|
||||||
@@ -34,7 +34,9 @@ impl Default for RegexMatcherBuilder {
|
|||||||
impl RegexMatcherBuilder {
|
impl RegexMatcherBuilder {
|
||||||
/// Create a new builder for configuring a regex matcher.
|
/// Create a new builder for configuring a regex matcher.
|
||||||
pub fn new() -> RegexMatcherBuilder {
|
pub fn new() -> RegexMatcherBuilder {
|
||||||
RegexMatcherBuilder { config: Config::default() }
|
RegexMatcherBuilder {
|
||||||
|
config: Config::default(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build a new matcher using the current configuration for the provided
|
/// Build a new matcher using the current configuration for the provided
|
||||||
@@ -47,16 +49,16 @@ impl RegexMatcherBuilder {
|
|||||||
let fast_line_regex = chir.fast_line_regex()?;
|
let fast_line_regex = chir.fast_line_regex()?;
|
||||||
let non_matching_bytes = chir.non_matching_bytes();
|
let non_matching_bytes = chir.non_matching_bytes();
|
||||||
if let Some(ref re) = fast_line_regex {
|
if let Some(ref re) = fast_line_regex {
|
||||||
debug!("extracted fast line regex: {:?}", re);
|
trace!("extracted fast line regex: {:?}", re);
|
||||||
}
|
}
|
||||||
|
|
||||||
let matcher = RegexMatcherImpl::new(&chir)?;
|
let matcher = RegexMatcherImpl::new(&chir)?;
|
||||||
trace!("final regex: {:?}", matcher.regex());
|
trace!("final regex: {:?}", matcher.regex());
|
||||||
Ok(RegexMatcher {
|
Ok(RegexMatcher {
|
||||||
config: self.config.clone(),
|
config: self.config.clone(),
|
||||||
matcher,
|
matcher: matcher,
|
||||||
fast_line_regex,
|
fast_line_regex: fast_line_regex,
|
||||||
non_matching_bytes,
|
non_matching_bytes: non_matching_bytes,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -380,7 +382,9 @@ impl RegexMatcher {
|
|||||||
/// given pattern contains a literal `\n`. Other uses of `\n` (such as in
|
/// given pattern contains a literal `\n`. Other uses of `\n` (such as in
|
||||||
/// `\s`) are removed transparently.
|
/// `\s`) are removed transparently.
|
||||||
pub fn new_line_matcher(pattern: &str) -> Result<RegexMatcher, Error> {
|
pub fn new_line_matcher(pattern: &str) -> Result<RegexMatcher, Error> {
|
||||||
RegexMatcherBuilder::new().line_terminator(Some(b'\n')).build(pattern)
|
RegexMatcherBuilder::new()
|
||||||
|
.line_terminator(Some(b'\n'))
|
||||||
|
.build(pattern)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -495,9 +499,12 @@ impl Matcher for RegexMatcher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_iter<F>(&self, haystack: &[u8], matched: F) -> Result<(), NoError>
|
fn find_iter<F>(
|
||||||
where
|
&self,
|
||||||
F: FnMut(Match) -> bool,
|
haystack: &[u8],
|
||||||
|
matched: F,
|
||||||
|
) -> Result<(), NoError>
|
||||||
|
where F: FnMut(Match) -> bool
|
||||||
{
|
{
|
||||||
use self::RegexMatcherImpl::*;
|
use self::RegexMatcherImpl::*;
|
||||||
match self.matcher {
|
match self.matcher {
|
||||||
@@ -513,8 +520,7 @@ impl Matcher for RegexMatcher {
|
|||||||
haystack: &[u8],
|
haystack: &[u8],
|
||||||
matched: F,
|
matched: F,
|
||||||
) -> Result<Result<(), E>, NoError>
|
) -> Result<Result<(), E>, NoError>
|
||||||
where
|
where F: FnMut(Match) -> Result<bool, E>
|
||||||
F: FnMut(Match) -> Result<bool, E>,
|
|
||||||
{
|
{
|
||||||
use self::RegexMatcherImpl::*;
|
use self::RegexMatcherImpl::*;
|
||||||
match self.matcher {
|
match self.matcher {
|
||||||
@@ -545,8 +551,7 @@ impl Matcher for RegexMatcher {
|
|||||||
caps: &mut RegexCaptures,
|
caps: &mut RegexCaptures,
|
||||||
matched: F,
|
matched: F,
|
||||||
) -> Result<(), NoError>
|
) -> Result<(), NoError>
|
||||||
where
|
where F: FnMut(&RegexCaptures) -> bool
|
||||||
F: FnMut(&RegexCaptures) -> bool,
|
|
||||||
{
|
{
|
||||||
use self::RegexMatcherImpl::*;
|
use self::RegexMatcherImpl::*;
|
||||||
match self.matcher {
|
match self.matcher {
|
||||||
@@ -563,8 +568,7 @@ impl Matcher for RegexMatcher {
|
|||||||
caps: &mut RegexCaptures,
|
caps: &mut RegexCaptures,
|
||||||
matched: F,
|
matched: F,
|
||||||
) -> Result<Result<(), E>, NoError>
|
) -> Result<Result<(), E>, NoError>
|
||||||
where
|
where F: FnMut(&RegexCaptures) -> Result<bool, E>
|
||||||
F: FnMut(&RegexCaptures) -> Result<bool, E>,
|
|
||||||
{
|
{
|
||||||
use self::RegexMatcherImpl::*;
|
use self::RegexMatcherImpl::*;
|
||||||
match self.matcher {
|
match self.matcher {
|
||||||
@@ -598,8 +602,7 @@ impl Matcher for RegexMatcher {
|
|||||||
dst: &mut Vec<u8>,
|
dst: &mut Vec<u8>,
|
||||||
append: F,
|
append: F,
|
||||||
) -> Result<(), NoError>
|
) -> Result<(), NoError>
|
||||||
where
|
where F: FnMut(Match, &mut Vec<u8>) -> bool
|
||||||
F: FnMut(Match, &mut Vec<u8>) -> bool,
|
|
||||||
{
|
{
|
||||||
use self::RegexMatcherImpl::*;
|
use self::RegexMatcherImpl::*;
|
||||||
match self.matcher {
|
match self.matcher {
|
||||||
@@ -617,8 +620,7 @@ impl Matcher for RegexMatcher {
|
|||||||
dst: &mut Vec<u8>,
|
dst: &mut Vec<u8>,
|
||||||
append: F,
|
append: F,
|
||||||
) -> Result<(), NoError>
|
) -> Result<(), NoError>
|
||||||
where
|
where F: FnMut(&Self::Captures, &mut Vec<u8>) -> bool
|
||||||
F: FnMut(&Self::Captures, &mut Vec<u8>) -> bool,
|
|
||||||
{
|
{
|
||||||
use self::RegexMatcherImpl::*;
|
use self::RegexMatcherImpl::*;
|
||||||
match self.matcher {
|
match self.matcher {
|
||||||
@@ -743,8 +745,7 @@ impl Matcher for StandardMatcher {
|
|||||||
haystack: &[u8],
|
haystack: &[u8],
|
||||||
at: usize,
|
at: usize,
|
||||||
) -> Result<Option<Match>, NoError> {
|
) -> Result<Option<Match>, NoError> {
|
||||||
Ok(self
|
Ok(self.regex
|
||||||
.regex
|
|
||||||
.find_at(haystack, at)
|
.find_at(haystack, at)
|
||||||
.map(|m| Match::new(m.start(), m.end())))
|
.map(|m| Match::new(m.start(), m.end())))
|
||||||
}
|
}
|
||||||
@@ -766,8 +767,7 @@ impl Matcher for StandardMatcher {
|
|||||||
haystack: &[u8],
|
haystack: &[u8],
|
||||||
mut matched: F,
|
mut matched: F,
|
||||||
) -> Result<Result<(), E>, NoError>
|
) -> Result<Result<(), E>, NoError>
|
||||||
where
|
where F: FnMut(Match) -> Result<bool, E>
|
||||||
F: FnMut(Match) -> Result<bool, E>,
|
|
||||||
{
|
{
|
||||||
for m in self.regex.find_iter(haystack) {
|
for m in self.regex.find_iter(haystack) {
|
||||||
match matched(Match::new(m.start(), m.end())) {
|
match matched(Match::new(m.start(), m.end())) {
|
||||||
@@ -785,10 +785,9 @@ impl Matcher for StandardMatcher {
|
|||||||
at: usize,
|
at: usize,
|
||||||
caps: &mut RegexCaptures,
|
caps: &mut RegexCaptures,
|
||||||
) -> Result<bool, NoError> {
|
) -> Result<bool, NoError> {
|
||||||
Ok(self
|
Ok(self.regex.captures_read_at(
|
||||||
.regex
|
&mut caps.locations_mut(), haystack, at,
|
||||||
.captures_read_at(&mut caps.locations_mut(), haystack, at)
|
).is_some())
|
||||||
.is_some())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shortest_match_at(
|
fn shortest_match_at(
|
||||||
@@ -902,9 +901,7 @@ impl RegexCaptures {
|
|||||||
offset: usize,
|
offset: usize,
|
||||||
) -> RegexCaptures {
|
) -> RegexCaptures {
|
||||||
RegexCaptures(RegexCapturesImp::Regex {
|
RegexCaptures(RegexCapturesImp::Regex {
|
||||||
locs,
|
locs, offset, strip_crlf: false,
|
||||||
offset,
|
|
||||||
strip_crlf: false,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -913,7 +910,9 @@ impl RegexCaptures {
|
|||||||
RegexCapturesImp::AhoCorasick { .. } => {
|
RegexCapturesImp::AhoCorasick { .. } => {
|
||||||
panic!("getting locations for simple captures is invalid")
|
panic!("getting locations for simple captures is invalid")
|
||||||
}
|
}
|
||||||
RegexCapturesImp::Regex { ref locs, .. } => locs,
|
RegexCapturesImp::Regex { ref locs, .. } => {
|
||||||
|
locs
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -922,7 +921,9 @@ impl RegexCaptures {
|
|||||||
RegexCapturesImp::AhoCorasick { .. } => {
|
RegexCapturesImp::AhoCorasick { .. } => {
|
||||||
panic!("getting locations for simple captures is invalid")
|
panic!("getting locations for simple captures is invalid")
|
||||||
}
|
}
|
||||||
RegexCapturesImp::Regex { ref mut locs, .. } => locs,
|
RegexCapturesImp::Regex { ref mut locs, .. } => {
|
||||||
|
locs
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -951,19 +952,23 @@ impl RegexCaptures {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
|
||||||
use grep_matcher::{LineMatchKind, Matcher};
|
use grep_matcher::{LineMatchKind, Matcher};
|
||||||
|
use super::*;
|
||||||
|
|
||||||
// Test that enabling word matches does the right thing and demonstrate
|
// Test that enabling word matches does the right thing and demonstrate
|
||||||
// the difference between it and surrounding the regex in `\b`.
|
// the difference between it and surrounding the regex in `\b`.
|
||||||
#[test]
|
#[test]
|
||||||
fn word() {
|
fn word() {
|
||||||
let matcher =
|
let matcher = RegexMatcherBuilder::new()
|
||||||
RegexMatcherBuilder::new().word(true).build(r"-2").unwrap();
|
.word(true)
|
||||||
|
.build(r"-2")
|
||||||
|
.unwrap();
|
||||||
assert!(matcher.is_match(b"abc -2 foo").unwrap());
|
assert!(matcher.is_match(b"abc -2 foo").unwrap());
|
||||||
|
|
||||||
let matcher =
|
let matcher = RegexMatcherBuilder::new()
|
||||||
RegexMatcherBuilder::new().word(false).build(r"\b-2\b").unwrap();
|
.word(false)
|
||||||
|
.build(r"\b-2\b")
|
||||||
|
.unwrap();
|
||||||
assert!(!matcher.is_match(b"abc -2 foo").unwrap());
|
assert!(!matcher.is_match(b"abc -2 foo").unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -972,7 +977,9 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn line_terminator() {
|
fn line_terminator() {
|
||||||
// This works, because there's no line terminator specified.
|
// This works, because there's no line terminator specified.
|
||||||
let matcher = RegexMatcherBuilder::new().build(r"abc\sxyz").unwrap();
|
let matcher = RegexMatcherBuilder::new()
|
||||||
|
.build(r"abc\sxyz")
|
||||||
|
.unwrap();
|
||||||
assert!(matcher.is_match(b"abc\nxyz").unwrap());
|
assert!(matcher.is_match(b"abc\nxyz").unwrap());
|
||||||
|
|
||||||
// This doesn't.
|
// This doesn't.
|
||||||
@@ -1022,12 +1029,16 @@ mod tests {
|
|||||||
// Test that smart case works.
|
// Test that smart case works.
|
||||||
#[test]
|
#[test]
|
||||||
fn case_smart() {
|
fn case_smart() {
|
||||||
let matcher =
|
let matcher = RegexMatcherBuilder::new()
|
||||||
RegexMatcherBuilder::new().case_smart(true).build(r"abc").unwrap();
|
.case_smart(true)
|
||||||
|
.build(r"abc")
|
||||||
|
.unwrap();
|
||||||
assert!(matcher.is_match(b"ABC").unwrap());
|
assert!(matcher.is_match(b"ABC").unwrap());
|
||||||
|
|
||||||
let matcher =
|
let matcher = RegexMatcherBuilder::new()
|
||||||
RegexMatcherBuilder::new().case_smart(true).build(r"aBc").unwrap();
|
.case_smart(true)
|
||||||
|
.build(r"aBc")
|
||||||
|
.unwrap();
|
||||||
assert!(!matcher.is_match(b"ABC").unwrap());
|
assert!(!matcher.is_match(b"ABC").unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1049,7 +1060,9 @@ mod tests {
|
|||||||
|
|
||||||
// With no line terminator set, we can't employ any optimizations,
|
// With no line terminator set, we can't employ any optimizations,
|
||||||
// so we get a confirmed match.
|
// so we get a confirmed match.
|
||||||
let matcher = RegexMatcherBuilder::new().build(r"\wfoo\s").unwrap();
|
let matcher = RegexMatcherBuilder::new()
|
||||||
|
.build(r"\wfoo\s")
|
||||||
|
.unwrap();
|
||||||
let m = matcher.find_candidate_line(b"afoo ").unwrap().unwrap();
|
let m = matcher.find_candidate_line(b"afoo ").unwrap().unwrap();
|
||||||
assert!(is_confirmed(m));
|
assert!(is_confirmed(m));
|
||||||
|
|
@@ -1,5 +1,5 @@
|
|||||||
use aho_corasick::{AhoCorasick, AhoCorasickBuilder, MatchKind};
|
use aho_corasick::{AhoCorasick, AhoCorasickBuilder, MatchKind};
|
||||||
use grep_matcher::{Match, Matcher, NoError};
|
use grep_matcher::{Matcher, Match, NoError};
|
||||||
use regex_syntax::hir::Hir;
|
use regex_syntax::hir::Hir;
|
||||||
|
|
||||||
use error::Error;
|
use error::Error;
|
||||||
@@ -93,13 +93,15 @@ pub fn alternation_literals(expr: &Hir) -> Option<Vec<Vec<u8>>> {
|
|||||||
_ => return None, // one literal isn't worth it
|
_ => return None, // one literal isn't worth it
|
||||||
};
|
};
|
||||||
|
|
||||||
let extendlit = |lit: &Literal, dst: &mut Vec<u8>| match *lit {
|
let extendlit = |lit: &Literal, dst: &mut Vec<u8>| {
|
||||||
Literal::Unicode(c) => {
|
match *lit {
|
||||||
let mut buf = [0; 4];
|
Literal::Unicode(c) => {
|
||||||
dst.extend_from_slice(c.encode_utf8(&mut buf).as_bytes());
|
let mut buf = [0; 4];
|
||||||
}
|
dst.extend_from_slice(c.encode_utf8(&mut buf).as_bytes());
|
||||||
Literal::Byte(b) => {
|
}
|
||||||
dst.push(b);
|
Literal::Byte(b) => {
|
||||||
|
dst.push(b);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@@ -11,9 +11,14 @@ pub fn non_matching_bytes(expr: &Hir) -> ByteSet {
|
|||||||
|
|
||||||
/// Remove any bytes from the given set that can occur in a matched produced by
|
/// Remove any bytes from the given set that can occur in a matched produced by
|
||||||
/// the given expression.
|
/// the given expression.
|
||||||
fn remove_matching_bytes(expr: &Hir, set: &mut ByteSet) {
|
fn remove_matching_bytes(
|
||||||
|
expr: &Hir,
|
||||||
|
set: &mut ByteSet,
|
||||||
|
) {
|
||||||
match *expr.kind() {
|
match *expr.kind() {
|
||||||
HirKind::Empty | HirKind::Anchor(_) | HirKind::WordBoundary(_) => {}
|
HirKind::Empty
|
||||||
|
| HirKind::Anchor(_)
|
||||||
|
| HirKind::WordBoundary(_) => {}
|
||||||
HirKind::Literal(hir::Literal::Unicode(c)) => {
|
HirKind::Literal(hir::Literal::Unicode(c)) => {
|
||||||
for &b in c.encode_utf8(&mut [0; 4]).as_bytes() {
|
for &b in c.encode_utf8(&mut [0; 4]).as_bytes() {
|
||||||
set.remove(b);
|
set.remove(b);
|
||||||
@@ -100,20 +105,15 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn dot() {
|
fn dot() {
|
||||||
assert_eq!(
|
assert_eq!(sparse(&extract(".")), vec![
|
||||||
sparse(&extract(".")),
|
b'\n',
|
||||||
vec![
|
192, 193, 245, 246, 247, 248, 249,
|
||||||
b'\n', 192, 193, 245, 246, 247, 248, 249, 250, 251, 252, 253,
|
250, 251, 252, 253, 254, 255,
|
||||||
254, 255,
|
]);
|
||||||
]
|
assert_eq!(sparse(&extract("(?s).")), vec![
|
||||||
);
|
192, 193, 245, 246, 247, 248, 249,
|
||||||
assert_eq!(
|
250, 251, 252, 253, 254, 255,
|
||||||
sparse(&extract("(?s).")),
|
]);
|
||||||
vec![
|
|
||||||
192, 193, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254,
|
|
||||||
255,
|
|
||||||
]
|
|
||||||
);
|
|
||||||
assert_eq!(sparse(&extract("(?-u).")), vec![b'\n']);
|
assert_eq!(sparse(&extract("(?-u).")), vec![b'\n']);
|
||||||
assert_eq!(sparse(&extract("(?s-u).")), vec![]);
|
assert_eq!(sparse(&extract("(?s-u).")), vec![]);
|
||||||
}
|
}
|
@@ -33,7 +33,10 @@ pub fn strip_from_match(
|
|||||||
|
|
||||||
/// The implementation of strip_from_match. The given byte must be ASCII. This
|
/// The implementation of strip_from_match. The given byte must be ASCII. This
|
||||||
/// function panics otherwise.
|
/// function panics otherwise.
|
||||||
fn strip_from_match_ascii(expr: Hir, byte: u8) -> Result<Hir, Error> {
|
fn strip_from_match_ascii(
|
||||||
|
expr: Hir,
|
||||||
|
byte: u8,
|
||||||
|
) -> Result<Hir, Error> {
|
||||||
assert!(byte <= 0x7F);
|
assert!(byte <= 0x7F);
|
||||||
let chr = byte as char;
|
let chr = byte as char;
|
||||||
assert_eq!(chr.len_utf8(), 1);
|
assert_eq!(chr.len_utf8(), 1);
|
||||||
@@ -85,15 +88,13 @@ fn strip_from_match_ascii(expr: Hir, byte: u8) -> Result<Hir, Error> {
|
|||||||
Hir::group(x)
|
Hir::group(x)
|
||||||
}
|
}
|
||||||
HirKind::Concat(xs) => {
|
HirKind::Concat(xs) => {
|
||||||
let xs = xs
|
let xs = xs.into_iter()
|
||||||
.into_iter()
|
|
||||||
.map(|e| strip_from_match_ascii(e, byte))
|
.map(|e| strip_from_match_ascii(e, byte))
|
||||||
.collect::<Result<Vec<Hir>, Error>>()?;
|
.collect::<Result<Vec<Hir>, Error>>()?;
|
||||||
Hir::concat(xs)
|
Hir::concat(xs)
|
||||||
}
|
}
|
||||||
HirKind::Alternation(xs) => {
|
HirKind::Alternation(xs) => {
|
||||||
let xs = xs
|
let xs = xs.into_iter()
|
||||||
.into_iter()
|
|
||||||
.map(|e| strip_from_match_ascii(e, byte))
|
.map(|e| strip_from_match_ascii(e, byte))
|
||||||
.collect::<Result<Vec<Hir>, Error>>()?;
|
.collect::<Result<Vec<Hir>, Error>>()?;
|
||||||
Hir::alternation(xs)
|
Hir::alternation(xs)
|
||||||
@@ -105,8 +106,8 @@ fn strip_from_match_ascii(expr: Hir, byte: u8) -> Result<Hir, Error> {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use regex_syntax::Parser;
|
use regex_syntax::Parser;
|
||||||
|
|
||||||
use super::{strip_from_match, LineTerminator};
|
|
||||||
use error::Error;
|
use error::Error;
|
||||||
|
use super::{LineTerminator, strip_from_match};
|
||||||
|
|
||||||
fn roundtrip(pattern: &str, byte: u8) -> String {
|
fn roundtrip(pattern: &str, byte: u8) -> String {
|
||||||
roundtrip_line_term(pattern, LineTerminator::byte(byte)).unwrap()
|
roundtrip_line_term(pattern, LineTerminator::byte(byte)).unwrap()
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user