diff --git a/.gitignore b/.gitignore index 02de603..2f2825f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,17 +1,5 @@ .*.swp tags target -/grep/Cargo.lock -/globset/Cargo.lock -/ignore/Cargo.lock -/termcolor/Cargo.lock +/Cargo.lock /wincolor/Cargo.lock -/deployment - -# Snapcraft files -stage -prime -parts -*.snap -*.pyc -ripgrep*_source.tar.bz2 diff --git a/.travis.yml b/.travis.yml index 281bf56..f4d938f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,58 +1,14 @@ language: rust env: global: - - PROJECT_NAME: ripgrep + - PROJECT_NAME: termcolor - 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 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 + env: TARGET=x86_64-apple-darwin - os: linux rust: beta env: TARGET=x86_64-unknown-linux-gnu @@ -61,46 +17,12 @@ matrix: - os: linux rust: 1.20.0 env: TARGET=x86_64-unknown-linux-gnu - - os: linux - rust: 1.20.0 - env: TARGET=x86_64-unknown-linux-musl - - os: linux - rust: 1.20.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 - 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 diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index d872c47..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,879 +0,0 @@ -0.9.0 (TBD) -=========== -This is a new minor version release of ripgrep that mostly contains bug fixes. - -Releases provided on Github for `x86` and `x86_64` will now work on all target -CPUs, and will also automatically take advantage of features found on modern -CPUs (such as AVX2) for additional optimizations. - -**BREAKING CHANGES**: - -* When `--count` and `--only-matching` are provided simultaneously, the - behavior of ripgrep is as if the `--count-matches` flag was given. That is, - the total number of matches is reported, where there may be multiple matches - per line. Previously, the behavior of ripgrep was to report the total number - of matching lines. (Note that this behavior diverges from the behavior of - GNU grep.) -* Octal syntax is no longer supported. ripgrep previously accepted expressions - like `\1` as syntax for matching `U+0001`, but ripgrep will now report an - error instead. -* The `--line-number-width` flag has been removed. Its functionality was not - carefully considered with all ripgrep output formats. - See [#795](https://github.com/BurntSushi/ripgrep/issues/795) for more - details. - -Feature enhancements: - -* [FEATURE #411](https://github.com/BurntSushi/ripgrep/issues/411): - Add a `--stats` flag, which emits aggregate statistics after search results. -* [FEATURE #646](https://github.com/BurntSushi/ripgrep/issues/646): - Add a `--no-ignore-messages` flag, which suppresses parse errors from reading - `.ignore` and `.gitignore` files. -* [FEATURE #702](https://github.com/BurntSushi/ripgrep/issues/702): - Support `\u{..}` Unicode escape sequences. -* [FEATURE #812](https://github.com/BurntSushi/ripgrep/issues/812): - Add `-b/--byte-offset` flag that reports byte offset of each matching line. -* [FEATURE #814](https://github.com/BurntSushi/ripgrep/issues/814): - Add `--count-matches` flag, which is like `--count`, but for each match. -* [FEATURE #880](https://github.com/BurntSushi/ripgrep/issues/880): - Add a `--no-column` flag, which disables column numbers in the output. - -Bug fixes: - -* [BUG #135](https://github.com/BurntSushi/ripgrep/issues/135): - Release portable binaries that conditionally use SSSE3, AVX2, etc., at - runtime. -* [BUG #268](https://github.com/BurntSushi/ripgrep/issues/268): - Print descriptive error message when trying to use look-around or - backreferences. -* [BUG #395](https://github.com/BurntSushi/ripgrep/issues/395): - Show comprehensible error messages for regexes like `\s*{`. -* [BUG #526](https://github.com/BurntSushi/ripgrep/issues/526): - Support backslash escapes in globs. -* [BUG #795](https://github.com/BurntSushi/ripgrep/issues/795): - Fix problems with `--line-number-width` by removing it. -* [BUG #832](https://github.com/BurntSushi/ripgrep/issues/832): - Clarify usage instructions for `-f/--file` flag. -* [BUG #835](https://github.com/BurntSushi/ripgrep/issues/835): - Fix small performance regression while crawling very large directory trees. -* [BUG #851](https://github.com/BurntSushi/ripgrep/issues/851): - Fix `-S/--smart-case` detection once and for all. -* [BUG #852](https://github.com/BurntSushi/ripgrep/issues/852): - Be robust with respect to `ENOMEM` errors returned by `mmap`. -* [BUG #853](https://github.com/BurntSushi/ripgrep/issues/853): - Upgrade `grep` crate to `regex-syntax 0.5.0`. -* [BUG #893](https://github.com/BurntSushi/ripgrep/issues/893): - Improve support for git submodules. - - -0.8.1 (2018-02-20) -================== -This is a patch release of ripgrep that primarily fixes regressions introduced -in 0.8.0 (#820 and #824) in directory traversal on Windows. These regressions -do not impact non-Windows users. - -Feature enhancements: - -* Added or improved file type filtering for csv and VHDL. -* [FEATURE #798](https://github.com/BurntSushi/ripgrep/issues/798): - Add `underline` support to `termcolor` and ripgrep. See documentation on the - `--colors` flag for details. - -Bug fixes: - -* [BUG #684](https://github.com/BurntSushi/ripgrep/issues/684): - Improve documentation for the `--ignore-file` flag. -* [BUG #789](https://github.com/BurntSushi/ripgrep/issues/789): - Don't show `(rev )` if the revision wasn't available during the build. -* [BUG #791](https://github.com/BurntSushi/ripgrep/issues/791): - Add man page to ARM release. -* [BUG #797](https://github.com/BurntSushi/ripgrep/issues/797): - Improve documentation for "intense" setting in `termcolor`. -* [BUG #800](https://github.com/BurntSushi/ripgrep/issues/800): - Fix a bug in the `ignore` crate for custom ignore files. This had no impact - on ripgrep. -* [BUG #807](https://github.com/BurntSushi/ripgrep/issues/807): - Fix a bug where `rg --hidden .` behaved differently from `rg --hidden ./`. -* [BUG #815](https://github.com/BurntSushi/ripgrep/issues/815): - Clarify a common failure mode in user guide. -* [BUG #820](https://github.com/BurntSushi/ripgrep/issues/820): - Fixes a bug on Windows where symlinks were followed even if not requested. -* [BUG #824](https://github.com/BurntSushi/ripgrep/issues/824): - Fix a performance regression in directory traversal on Windows. - - -0.8.0 (2018-02-11) -================== -This is a new minor version releae of ripgrep that satisfies several popular -feature requests (config files, search compressed files, true colors), fixes -many bugs and improves the quality of life for ripgrep maintainers. This -release also includes greatly improved documentation in the form of a -[User Guide](GUIDE.md) and a [FAQ](FAQ.md). - -This release increases the **minimum supported Rust version** from 1.17 to -1.20. - -**BREAKING CHANGES**: - -Note that these are all very minor and unlikely to impact most users. - -* In order to support configuration files, flag overrides needed to be - rethought. In some cases, this changed ripgrep's behavior. For example, - in ripgrep 0.7.1, `rg foo -s -i` will perform a case sensitive search - since the `-s/--case-sensitive` flag was defined to always take precedence - over the `-i/--ignore-case` flag, regardless of position. In ripgrep 0.8.0 - however, the override rule for all flags has changed to "the most recent - flag wins among competing flags." That is, `rg foo -s -i` now performs a - case insensitive search. -* The `-M/--max-columns` flag was tweaked so that specifying a value of `0` - now makes ripgrep behave as if the flag was absent. This makes it possible - to set a default value in a configuration file and then override it. The - previous ripgrep behavior was to suppress all matching non-empty lines. -* In all globs, `[^...]` is now equivalent to `[!...]` (indicating class - negation). Previously, `^` had no special significance in a character class. -* For **downstream packagers**, the directory hierarchy in ripgrep's archive - releases has changed. The root directory now only contains the executable, - README and license. There is now a new directory called `doc` which contains - the man page (previously in the root), a user guide (new), a FAQ (new) and - the CHANGELOG (previously not included in release). The `complete` - directory remains the same. - -Feature enhancements: - -* Added or improved file type filtering for - Apache Avro, C++, GN, Google Closure Templates, Jupyter notebooks, man pages, - Protocol Buffers, Smarty and Web IDL. -* [FEATURE #196](https://github.com/BurntSushi/ripgrep/issues/196): - Support a configuration file. See - [the new user guide](GUIDE.md#configuration-file) - for details. -* [FEATURE #261](https://github.com/BurntSushi/ripgrep/issues/261): - Add extended or "true" color support. Works in Windows 10! - [See the FAQ for details.](FAQ.md#colors) -* [FEATURE #539](https://github.com/BurntSushi/ripgrep/issues/539): - Search gzip, bzip2, lzma or xz files when given `-z/--search-zip` flag. -* [FEATURE #544](https://github.com/BurntSushi/ripgrep/issues/544): - Add support for line number alignment via a new `--line-number-width` flag. -* [FEATURE #654](https://github.com/BurntSushi/ripgrep/pull/654): - Support linuxbrew in ripgrep's Brew tap. -* [FEATURE #673](https://github.com/BurntSushi/ripgrep/issues/673): - Bring back `.rgignore` files. (A higher precedent, application specific - version of `.ignore`.) -* [FEATURE #676](https://github.com/BurntSushi/ripgrep/issues/676): - Provide ARM binaries. **WARNING:** This will be provided on a best effort - basis. -* [FEATURE #709](https://github.com/BurntSushi/ripgrep/issues/709): - Suggest `-F/--fixed-strings` flag on a regex syntax error. -* [FEATURE #740](https://github.com/BurntSushi/ripgrep/issues/740): - Add a `--passthru` flag that causes ripgrep to print every line it reads. -* [FEATURE #785](https://github.com/BurntSushi/ripgrep/pull/785): - Overhaul documentation. Cleaned up README, added user guide and FAQ. -* [FEATURE 7f5c07](https://github.com/BurntSushi/ripgrep/commit/7f5c07434be92103b5bf7e216b9c7494aed2d8cb): - Add hidden flags for convenient overrides (e.g., `--no-text`). - -Bug fixes: - -* [BUG #553](https://github.com/BurntSushi/ripgrep/issues/553): - Permit flags to be repeated. -* [BUG #633](https://github.com/BurntSushi/ripgrep/issues/633): - Fix a bug where ripgrep would panic on Windows while following symlinks. -* [BUG #649](https://github.com/BurntSushi/ripgrep/issues/649): - Fix handling of `!**/` in `.gitignore`. -* [BUG #663](https://github.com/BurntSushi/ripgrep/issues/663): - **BREAKING CHANGE:** Support `[^...]` glob syntax (as identical to `[!...]`). -* [BUG #693](https://github.com/BurntSushi/ripgrep/issues/693): - Don't display context separators when not printing matches. -* [BUG #705](https://github.com/BurntSushi/ripgrep/issues/705): - Fix a bug that prevented ripgrep from searching OneDrive directories. -* [BUG #717](https://github.com/BurntSushi/ripgrep/issues/717): - Improve `--smart-case` uppercase character detection. -* [BUG #725](https://github.com/BurntSushi/ripgrep/issues/725): - Clarify that globs do not override explicitly given paths to search. -* [BUG #742](https://github.com/BurntSushi/ripgrep/pull/742): - Write ANSI reset code as `\x1B[0m` instead of `\x1B[m`. -* [BUG #747](https://github.com/BurntSushi/ripgrep/issues/747): - Remove `yarn.lock` from YAML file type. -* [BUG #760](https://github.com/BurntSushi/ripgrep/issues/760): - ripgrep can now search `/sys/devices/system/cpu/vulnerabilities/*` files. -* [BUG #761](https://github.com/BurntSushi/ripgrep/issues/761): - Fix handling of gitignore patterns that contain a `/`. -* [BUG #776](https://github.com/BurntSushi/ripgrep/pull/776): - **BREAKING CHANGE:** `--max-columns=0` now disables the limit. -* [BUG #779](https://github.com/BurntSushi/ripgrep/issues/779): - Clarify documentation for `--files-without-match`. -* [BUG #780](https://github.com/BurntSushi/ripgrep/issues/780), - [BUG #781](https://github.com/BurntSushi/ripgrep/issues/781): - Fix bug where ripgrep missed some matching lines. - -Maintenance fixes: - -* [MAINT #772](https://github.com/BurntSushi/ripgrep/pull/772): - Drop `env_logger` in favor of simpler logger to avoid many new dependencies. -* [MAINT #772](https://github.com/BurntSushi/ripgrep/pull/772): - Add git revision hash to ripgrep's version string. -* [MAINT #772](https://github.com/BurntSushi/ripgrep/pull/772): - (Seemingly) improve compile times. -* [MAINT #776](https://github.com/BurntSushi/ripgrep/pull/776): - Automatically generate man page during build. -* [MAINT #786](https://github.com/BurntSushi/ripgrep/pull/786): - Remove use of `unsafe` in `globset`. :tada: -* [MAINT e9d448](https://github.com/BurntSushi/ripgrep/commit/e9d448e93bb4e1fb3b0c1afc29adb5af6ed5283d): - Add an issue template (has already drastically improved bug reports). -* [MAINT ae2d03](https://github.com/BurntSushi/ripgrep/commit/ae2d036dd4ba2a46acac9c2d77c32e7c667eb850): - Remove the `compile` script. - -Friends of ripgrep: - -I'd like to extend my gratitude to -[@balajisivaraman](https://github.com/balajisivaraman) -for their recent hard work in a number of areas, and in particular, for -implementing the "search compressed files" feature. Their work in sketching out -a specification for that and other work has been exemplary. - -Thanks -[@balajisivaraman](https://github.com/balajisivaraman)! - - -0.7.1 (2017-10-22) -================== -This is a patch release of ripgrep that includes a fix to very bad regression -introduced in ripgrep 0.7.0. - -Bug fixes: - -* [BUG #648](https://github.com/BurntSushi/ripgrep/issues/648): - Fix a bug where it was very easy to exceed standard file descriptor limits. - - -0.7.0 (2017-10-20) -================== -This is a new minor version release of ripgrep that includes mostly bug fixes. - -ripgrep continues to require Rust 1.17, and there are no known breaking changes -introduced in this release. - -Feature enhancements: - -* Added or improved file type filtering for config & license files, Elm, - Purescript, Standard ML, sh, systemd, Terraform -* [FEATURE #593](https://github.com/BurntSushi/ripgrep/pull/593): - Using both `-o/--only-matching` and `-r/--replace` does the right thing. - -Bug fixes: - -* [BUG #200](https://github.com/BurntSushi/ripgrep/issues/200): - ripgrep will stop when its pipe is closed. -* [BUG #402](https://github.com/BurntSushi/ripgrep/issues/402): - Fix context printing bug when the `-m/--max-count` flag is used. -* [BUG #521](https://github.com/BurntSushi/ripgrep/issues/521): - Fix interaction between `-r/--replace` and terminal colors. -* [BUG #559](https://github.com/BurntSushi/ripgrep/issues/559): - Ignore test that tried reading a non-UTF-8 file path on macOS. -* [BUG #599](https://github.com/BurntSushi/ripgrep/issues/599): - Fix color escapes on empty matches. -* [BUG #600](https://github.com/BurntSushi/ripgrep/issues/600): - Avoid expensive (on Windows) file handle check when using --files. -* [BUG #618](https://github.com/BurntSushi/ripgrep/issues/618): - Clarify installation instructions for Ubuntu users. -* [BUG #633](https://github.com/BurntSushi/ripgrep/issues/633): - Faster symlink loop checking on Windows. - - -0.6.0 (2017-08-23) -================== -This is a new minor version release of ripgrep that includes many bug fixes -and a few new features such as `--iglob` and `-x/--line-regexp`. - -Note that this release increases the minimum supported Rust version from 1.12 -to 1.17. - -Feature enhancements: - -* Added or improved file type filtering for BitBake, C++, Cabal, cshtml, Julia, - Make, msbuild, QMake, Yocto -* [FEATURE #163](https://github.com/BurntSushi/ripgrep/issues/163): - Add an `--iglob` flag that is like `-g/--glob`, but matches globs - case insensitively. -* [FEATURE #520](https://github.com/BurntSushi/ripgrep/pull/518): - Add `-x/--line-regexp` flag, which requires a match to span an entire line. -* [FEATURE #551](https://github.com/BurntSushi/ripgrep/pull/551), - [FEATURE #554](https://github.com/BurntSushi/ripgrep/pull/554): - `ignore`: add new `matched_path_or_any_parents` method. - -Bug fixes: - -* [BUG #342](https://github.com/BurntSushi/ripgrep/issues/342): - Fix invisible text in some PowerShell environments by changing the - default color scheme on Windows. -* [BUG #413](https://github.com/BurntSushi/ripgrep/issues/413): - Release binaries on Unix are now `strip`'d by default. This decreases - binary size by an order of magnitude. -* [BUG #483](https://github.com/BurntSushi/ripgrep/issues/483): - When `--quiet` is passed, `--files` should be quiet. -* [BUG #488](https://github.com/BurntSushi/ripgrep/pull/488): - When `--vimgrep` is passed, `--with-filename` should be enabled - automatically. -* [BUG #493](https://github.com/BurntSushi/ripgrep/issues/493): - Fix another bug in the implementation of the `-o/--only-matching` - flag. -* [BUG #499](https://github.com/BurntSushi/ripgrep/pull/499): - Permit certain flags to override others. -* [BUG #523](https://github.com/BurntSushi/ripgrep/pull/523): - `wincolor`: Re-fetch Windows console on all calls. -* [BUG #523](https://github.com/BurntSushi/ripgrep/issues/524): - `--version` now shows enabled compile-time features. -* [BUG #532](https://github.com/BurntSushi/ripgrep/issues/532), - [BUG #536](https://github.com/BurntSushi/ripgrep/pull/536), - [BUG #538](https://github.com/BurntSushi/ripgrep/pull/538), - [BUG #540](https://github.com/BurntSushi/ripgrep/pull/540), - [BUG #560](https://github.com/BurntSushi/ripgrep/pull/560), - [BUG #565](https://github.com/BurntSushi/ripgrep/pull/565): - Improve zsh completion. -* [BUG #578](https://github.com/BurntSushi/ripgrep/pull/578): - Enable SIMD for `encoding_rs` when appropriate. -* [BUG #580](https://github.com/BurntSushi/ripgrep/issues/580): - Fix `-w/--word-regexp` in the presence of capturing groups. -* [BUG #581](https://github.com/BurntSushi/ripgrep/issues/581): - Document that ripgrep may terminate unexpectedly when searching via - memory maps (which can happen using default settings). - -Friends of ripgrep: - -I'd like to give a big Thank You to @okdana for their recent hard work on -ripgrep. This includes new features like `--line-regexp`, heroic effort on -zsh auto-completion and thinking through some thorny argv issues with me. - -I'd also like to thank @ericbn for their work on improving ripgrep's argv -parsing by allowing some flags to override others. - -Thanks @okdana and @ericbn! - - -0.5.2 (2017-05-11) -================== -Feature enhancements: - -* Added or improved file type filtering for Nix. -* [FEATURE #362](https://github.com/BurntSushi/ripgrep/issues/362): - Add `--regex-size-limit` and `--dfa-size-limit` flags. -* [FEATURE #444](https://github.com/BurntSushi/ripgrep/issues/444): - Improve error messages for invalid globs. - -Bug fixes: - -* [BUG #442](https://github.com/BurntSushi/ripgrep/issues/442): - Fix line wrapping in `--help` output. -* [BUG #451](https://github.com/BurntSushi/ripgrep/issues/451): - Fix bug with duplicate output when using `-o/--only-matching` flag. - - -0.5.1 (2017-04-09) -================== -Feature enhancements: - -* Added or improved file type filtering for vim. -* [FEATURE #34](https://github.com/BurntSushi/ripgrep/issues/34): - Add a `-o/--only-matching` flag. -* [FEATURE #377](https://github.com/BurntSushi/ripgrep/issues/377): - Column numbers can now be customized with a color. (The default is - no color.) -* [FEATURE #419](https://github.com/BurntSushi/ripgrep/issues/419): - Added `-0` short flag option for `--null`. - -Bug fixes: - -* [BUG #381](https://github.com/BurntSushi/ripgrep/issues/381): - Include license text in all subcrates. -* [BUG #418](https://github.com/BurntSushi/ripgrep/issues/418), - [BUG #426](https://github.com/BurntSushi/ripgrep/issues/426), - [BUG #439](https://github.com/BurntSushi/ripgrep/issues/439): - Fix a few bugs with `-h/--help` output. - - -0.5.0 (2017-03-12) -================== -This is a new minor version release of ripgrep that includes one minor breaking -change, bug fixes and several new features including support for text encodings -other than UTF-8. - -A notable accomplishment with respect to Rust is that ripgrep proper now only -contains a single `unsafe` use (for accessing the contents of a memory map). - -The **breaking change** is: - -* [FEATURE #380](https://github.com/BurntSushi/ripgrep/issues/380): - Line numbers are now hidden by default when ripgrep is printing to a tty - **and** the only thing searched is stdin. - -Feature enhancements: - -* Added or improved file type filtering for Ceylon, CSS, Elixir, HTML, log, - SASS, SVG, Twig -* [FEATURE #1](https://github.com/BurntSushi/ripgrep/issues/1): - Add support for additional text encodings, including automatic detection for - UTF-16 via BOM sniffing. Explicit text encoding support with the - `-E/--encoding` flag was also added for latin-1, GBK, EUC-JP - and Shift_JIS, among others. The full list can be found here: - https://encoding.spec.whatwg.org/#concept-encoding-get -* [FEATURE #129](https://github.com/BurntSushi/ripgrep/issues/129): - Add a new `-M/--max-columns` flag that omits lines longer than the given - number of bytes. (Disabled by default!) -* [FEATURE #369](https://github.com/BurntSushi/ripgrep/issues/369): - A new flag, `--max-filesize`, was added for limiting searches to files with - a maximum file size. - -Bug fixes: - -* [BUG #52](https://github.com/BurntSushi/ripgrep/issues/52), - [BUG #311](https://github.com/BurntSushi/ripgrep/issues/311): - Tweak how binary files are detected and handled. (We are slightly less - conservative and will no longer use memory without bound.) -* [BUG #326](https://github.com/BurntSushi/ripgrep/issues/326): - When --files flag is given, we should never attempt to parse positional - arguments as regexes. -* [BUG #327](https://github.com/BurntSushi/ripgrep/issues/327): - Permit the --heading flag to override the --no-heading flag. -* [BUG #340](https://github.com/BurntSushi/ripgrep/pull/340): - Clarify that the `-u/--unrestricted` flags are aliases. -* [BUG #343](https://github.com/BurntSushi/ripgrep/pull/343): - Global git ignore config should use `$HOME/.config/git/ignore` and not - `$HOME/git/ignore`. -* [BUG #345](https://github.com/BurntSushi/ripgrep/pull/345): - Clarify docs for `-g/--glob` flag. -* [BUG #381](https://github.com/BurntSushi/ripgrep/issues/381): - Add license files to each sub-crate. -* [BUG #383](https://github.com/BurntSushi/ripgrep/issues/383): - Use latest version of clap (for argv parsing). -* [BUG #392](https://github.com/BurntSushi/ripgrep/issues/391): - Fix translation of set globs (e.g., `{foo,bar,quux}`) to regexes. -* [BUG #401](https://github.com/BurntSushi/ripgrep/pull/401): - Add PowerShell completion file to Windows release. -* [BUG #405](https://github.com/BurntSushi/ripgrep/issues/405): - Fix bug when excluding absolute paths with the `-g/--glob` flag. - - -0.4.0 -===== -This is a new minor version release of ripgrep that includes a couple very -minor breaking changes, a few new features and lots of bug fixes. - -This version of ripgrep upgrades its `regex` dependency from `0.1` to `0.2`, -which includes a few minor syntax changes: - -* POSIX character classes now require double bracketing. Previously, the regex - `[:upper:]` would parse as the `upper` POSIX character class. Now it parses - as the character class containing the characters `:upper:`. The fix to this - change is to use `[[:upper:]]` instead. Note that variants like - `[[:upper:][:blank:]]` continue to work. -* The character `[` must always be escaped inside a character class. -* The characters `&`, `-` and `~` must be escaped if any one of them are - repeated consecutively. For example, `[&]`, `[\&]`, `[\&\&]`, `[&-&]` are all - equivalent while `[&&]` is illegal. (The motivation for this and the prior - change is to provide a backwards compatible path for adding character class - set notation.) - -Feature enhancements: - -* Added or improved file type filtering for Crystal, Kotlin, Perl, PowerShell, - Ruby, Swig -* [FEATURE #83](https://github.com/BurntSushi/ripgrep/issues/83): - Type definitions can now include other type definitions. -* [FEATURE #243](https://github.com/BurntSushi/ripgrep/issues/243): - **BREAKING CHANGE**: The `--column` flag now implies `--line-number`. -* [FEATURE #263](https://github.com/BurntSushi/ripgrep/issues/263): - Add a new `--sort-files` flag. -* [FEATURE #275](https://github.com/BurntSushi/ripgrep/issues/275): - Add a new `--path-separator` flag. Useful in cygwin. - -Bug fixes: - -* [BUG #182](https://github.com/BurntSushi/ripgrep/issues/182): - Redux: use more portable ANSI color escape sequences when possible. -* [BUG #258](https://github.com/BurntSushi/ripgrep/issues/258): - Fix bug that caused ripgrep's parallel iterator to spin and burn CPU. -* [BUG #262](https://github.com/BurntSushi/ripgrep/issues/262): - Document how to install shell completion files. -* [BUG #266](https://github.com/BurntSushi/ripgrep/issues/266), - [BUG #293](https://github.com/BurntSushi/ripgrep/issues/293): - Fix handling of bold styling and change the default colors. -* [BUG #268](https://github.com/BurntSushi/ripgrep/issues/268): - Make lack of backreference support more explicit. -* [BUG #271](https://github.com/BurntSushi/ripgrep/issues/271): - Remove `~` dependency on clap. -* [BUG #277](https://github.com/BurntSushi/ripgrep/issues/277): - Fix cosmetic issue in `globset` crate docs. -* [BUG #279](https://github.com/BurntSushi/ripgrep/issues/279): - ripgrep did not terminate when `-q/--quiet` was given. -* [BUG #281](https://github.com/BurntSushi/ripgrep/issues/281): - **BREAKING CHANGE**: Completely remove `^C` handling from ripgrep. -* [BUG #284](https://github.com/BurntSushi/ripgrep/issues/284): - Make docs for `-g/--glob` clearer. -* [BUG #286](https://github.com/BurntSushi/ripgrep/pull/286): - When stdout is redirected to a file, don't search that file. -* [BUG #287](https://github.com/BurntSushi/ripgrep/pull/287): - Fix ZSH completions. -* [BUG #295](https://github.com/BurntSushi/ripgrep/pull/295): - Remove superfluous `memmap` dependency in `grep` crate. -* [BUG #308](https://github.com/BurntSushi/ripgrep/pull/308): - Improve docs for `-r/--replace`. -* [BUG #313](https://github.com/BurntSushi/ripgrep/pull/313): - Update bytecount dep to latest version. -* [BUG #318](https://github.com/BurntSushi/ripgrep/pull/318): - Fix invalid UTF-8 output bug in Windows consoles. - - -0.3.2 -===== -Feature enhancements: - -* Added or improved file type filtering for Less, Sass, stylus, Zsh - -Bug fixes: - -* [BUG #229](https://github.com/BurntSushi/ripgrep/issues/229): - Make smart case slightly less conservative. -* [BUG #247](https://github.com/BurntSushi/ripgrep/issues/247): - Clarify use of --heading/--no-heading. -* [BUG #251](https://github.com/BurntSushi/ripgrep/issues/251), - [BUG #264](https://github.com/BurntSushi/ripgrep/issues/264), - [BUG #267](https://github.com/BurntSushi/ripgrep/issues/267): - Fix matching bug caused by literal optimizations. -* [BUG #256](https://github.com/BurntSushi/ripgrep/issues/256): - Fix bug that caused `rg foo` and `rg foo/` to have different behavior - when `foo` was a symlink. -* [BUG #270](https://github.com/BurntSushi/ripgrep/issues/270): - Fix bug where patterns starting with a `-` couldn't be used with the - `-e/--regexp` flag. (This resolves a regression that was introduced in - ripgrep 0.3.0.) - - -0.3.1 -===== -Bug fixes: - -* [BUG #242](https://github.com/BurntSushi/ripgrep/issues/242): - ripgrep didn't respect `--colors foo:none` correctly. Now it does. - - -0.3.0 -===== -This is a new minor version release of ripgrep that includes two breaking -changes with lots of bug fixes and some new features and performance -improvements. Notably, if you had a problem with colors or piping on Windows -before, then that should now be fixed in this release. - -**BREAKING CHANGES**: - -* ripgrep now requires Rust 1.11 to compile. Previously, it could build on - Rust 1.9. The cause of this was the move from - [Docopt to Clap](https://github.com/BurntSushi/ripgrep/pull/233) - for argument parsing. -* The `-e/--regexp` flag can no longer accept a pattern starting with a `-`. - There are two work-arounds: `rg -- -foo` and `rg [-]foo` or `rg -e [-]foo` - will all search for the same `-foo` pattern. The cause of this was the move - from [Docopt to Clap](https://github.com/BurntSushi/ripgrep/pull/233) - for argument parsing. - [This may get fixed in the - future.](https://github.com/kbknapp/clap-rs/issues/742). - -Performance improvements: - -* [PERF #33](https://github.com/BurntSushi/ripgrep/issues/33): - ripgrep now performs similar to GNU grep on small corpora. -* [PERF #136](https://github.com/BurntSushi/ripgrep/issues/136): - ripgrep no longer slows down because of argument parsing when given a large - argument list. - -Feature enhancements: - -* Added or improved file type filtering for Elixir. -* [FEATURE #7](https://github.com/BurntSushi/ripgrep/issues/7): - Add a `-f/--file` flag that causes ripgrep to read patterns from a file. -* [FEATURE #51](https://github.com/BurntSushi/ripgrep/issues/51): - Add a `--colors` flag that enables one to customize the colors used in - ripgrep's output. -* [FEATURE #138](https://github.com/BurntSushi/ripgrep/issues/138): - Add a `--files-without-match` flag that shows only file paths that contain - zero matches. -* [FEATURE #230](https://github.com/BurntSushi/ripgrep/issues/230): - Add completion files to the release (Bash, Fish and PowerShell). - -Bug fixes: - -* [BUG #37](https://github.com/BurntSushi/ripgrep/issues/37): - Use correct ANSI escape sequences when `TERM=screen.linux`. -* [BUG #94](https://github.com/BurntSushi/ripgrep/issues/94): - ripgrep now detects stdin on Windows automatically. -* [BUG #117](https://github.com/BurntSushi/ripgrep/issues/117): - Colors should now work correctly and automatically inside mintty. -* [BUG #182](https://github.com/BurntSushi/ripgrep/issues/182): - Colors should now work within Emacs. In particular, `--color=always` will - emit colors regardless of the current environment. -* [BUG #189](https://github.com/BurntSushi/ripgrep/issues/189): - Show less content when running `rg -h`. The full help content can be - accessed with `rg --help`. -* [BUG #210](https://github.com/BurntSushi/ripgrep/issues/210): - Support non-UTF-8 file names on Unix platforms. -* [BUG #231](https://github.com/BurntSushi/ripgrep/issues/231): - Switch from block buffering to line buffering. -* [BUG #241](https://github.com/BurntSushi/ripgrep/issues/241): - Some error messages weren't suppressed when `--no-messages` was used. - - -0.2.9 -===== -Bug fixes: - -* [BUG #226](https://github.com/BurntSushi/ripgrep/issues/226): - File paths explicitly given on the command line weren't searched in parallel. - (This was a regression in `0.2.7`.) -* [BUG #228](https://github.com/BurntSushi/ripgrep/issues/228): - If a directory was given to `--ignore-file`, ripgrep's memory usage would - grow without bound. - - -0.2.8 -===== -Bug fixes: - -* Fixed a bug with the SIMD/AVX features for using bytecount in commit - `4ca15a`. - - -0.2.7 -===== -Performance improvements: - -* [PERF #223](https://github.com/BurntSushi/ripgrep/pull/223): - Added a parallel recursive directory iterator. This results in major - performance improvements on large repositories. -* [PERF #11](https://github.com/BurntSushi/ripgrep/pull/11): - ripgrep now uses the `bytecount` library for counting new lines. In some - cases, ripgrep runs twice as fast. Use - `RUSTFLAGS="-C target-cpu=native" cargo build --release --features 'simd-accel avx-accel'` - to get the fastest possible binary. - -Feature enhancements: - -* Added or improved file type filtering for Agda, Tex, Taskpaper, Markdown, - asciidoc, textile, rdoc, org, creole, wiki, pod, C#, PDF, C, C++. -* [FEATURE #149](https://github.com/BurntSushi/ripgrep/issues/149): - Add a new `--no-messages` flag that suppresses error messages. - Note that `rg foo 2> /dev/null` also works. -* [FEATURE #159](https://github.com/BurntSushi/ripgrep/issues/159): - Add a new `-m/--max-count` flag that limits the total number of matches - printed for each file searched. - -Bug fixes: - -* [BUG #199](https://github.com/BurntSushi/ripgrep/issues/199): - Fixed a bug where `-S/--smart-case` wasn't being applied correctly to - literal optimizations. -* [BUG #203](https://github.com/BurntSushi/ripgrep/issues/203): - Mention the full name, ripgrep, in more places. It now appears in - the output of `--help` and `--version`. The repository URL is now also - in the output of `--help` and the man page. -* [BUG #215](https://github.com/BurntSushi/ripgrep/issues/215): - Include small note about how to search for a pattern that starts with a `-`. - - -0.2.6 -===== -Feature enhancements: - -* Added or improved file type filtering for Fish. - -Bug fixes: - -* [BUG #206](https://github.com/BurntSushi/ripgrep/issues/206): - Fixed a regression with `-g/--glob` flag in `0.2.5`. - - -0.2.5 -===== -Feature enhancements: - -* Added or improved file type filtering for Groovy, Handlebars, Tcl, zsh and - Python. -* [FEATURE #9](https://github.com/BurntSushi/ripgrep/issues/9): - Support global gitignore config and `.git/info/exclude` files. -* [FEATURE #45](https://github.com/BurntSushi/ripgrep/issues/45): - Add --ignore-file flag for specifying additional ignore files. -* [FEATURE #202](https://github.com/BurntSushi/ripgrep/pull/202): - Introduce a new - [`ignore`](https://github.com/BurntSushi/ripgrep/tree/master/ignore) - crate that encapsulates all of ripgrep's gitignore matching logic. - -Bug fixes: - -* [BUG #44](https://github.com/BurntSushi/ripgrep/issues/44): - ripgrep runs slowly when given lots of positional arguments that are - directories. -* [BUG #119](https://github.com/BurntSushi/ripgrep/issues/119): - ripgrep didn't reset terminal colors if it was interrupted by `^C`. - Fixed in [PR #187](https://github.com/BurntSushi/ripgrep/pull/187). -* [BUG #184](https://github.com/BurntSushi/ripgrep/issues/184): - Fixed a bug related to interpreting gitignore files in parent directories. - - -0.2.4 -===== -SKIPPED. - - -0.2.3 -===== -Bug fixes: - -* [BUG #164](https://github.com/BurntSushi/ripgrep/issues/164): - Fixes a segfault on macos builds. -* [BUG #167](https://github.com/BurntSushi/ripgrep/issues/167): - Clarify documentation for --threads. - - -0.2.2 -===== -Packaging updates: - -* `ripgrep` is now in homebrew-core. `brew install ripgrep` will do the trick - on a Mac. -* `ripgrep` is now in the Archlinux community repository. - `pacman -S ripgrep` will do the trick on Archlinux. -* Support has been discontinued for i686-darwin. -* Glob matching has been moved out into its own crate: - [`globset`](https://crates.io/crates/globset). - -Feature enhancements: - -* Added or improved file type filtering for CMake, config, Jinja, Markdown, - Spark. -* [FEATURE #109](https://github.com/BurntSushi/ripgrep/issues/109): - Add a --max-depth flag for directory traversal. -* [FEATURE #124](https://github.com/BurntSushi/ripgrep/issues/124): - Add -s/--case-sensitive flag. Overrides --smart-case. -* [FEATURE #139](https://github.com/BurntSushi/ripgrep/pull/139): - The `ripgrep` repo is now a Homebrew tap. This is useful for installing - SIMD accelerated binaries, which aren't available in homebrew-core. - -Bug fixes: - -* [BUG #87](https://github.com/BurntSushi/ripgrep/issues/87), - [BUG #127](https://github.com/BurntSushi/ripgrep/issues/127), - [BUG #131](https://github.com/BurntSushi/ripgrep/issues/131): - Various issues related to glob matching. -* [BUG #116](https://github.com/BurntSushi/ripgrep/issues/116): - --quiet should stop search after first match. -* [BUG #121](https://github.com/BurntSushi/ripgrep/pull/121): - --color always should show colors, even when --vimgrep is used. -* [BUG #122](https://github.com/BurntSushi/ripgrep/pull/122): - Colorize file path at beginning of line. -* [BUG #134](https://github.com/BurntSushi/ripgrep/issues/134): - Processing a large ignore file (thousands of globs) was very slow. -* [BUG #137](https://github.com/BurntSushi/ripgrep/issues/137): - Always follow symlinks when given as an explicit argument. -* [BUG #147](https://github.com/BurntSushi/ripgrep/issues/147): - Clarify documentation for --replace. - - -0.2.1 -===== -Feature enhancements: - -* Added or improved file type filtering for Clojure and SystemVerilog. -* [FEATURE #89](https://github.com/BurntSushi/ripgrep/issues/89): - Add a --null flag that outputs a NUL byte after every file path. - -Bug fixes: - -* [BUG #98](https://github.com/BurntSushi/ripgrep/issues/98): - Fix a bug in single threaded mode when if opening a file failed, ripgrep - quit instead of continuing the search. -* [BUG #99](https://github.com/BurntSushi/ripgrep/issues/99): - Fix another bug in single threaded mode where empty lines were being printed - by mistake. -* [BUG #105](https://github.com/BurntSushi/ripgrep/issues/105): - Fix an off-by-one error with --column. -* [BUG #106](https://github.com/BurntSushi/ripgrep/issues/106): - Fix a bug where a whitespace only line in a gitignore file caused ripgrep - to panic (i.e., crash). - - -0.2.0 -===== -Feature enhancements: - -* Added or improved file type filtering for VB, R, F#, Swift, Nim, Javascript, - TypeScript -* [FEATURE #20](https://github.com/BurntSushi/ripgrep/issues/20): - Adds a --no-filename flag. -* [FEATURE #26](https://github.com/BurntSushi/ripgrep/issues/26): - Adds --files-with-matches flag. Like --count, but only prints file paths - and doesn't need to count every match. -* [FEATURE #40](https://github.com/BurntSushi/ripgrep/issues/40): - Switch from using `.rgignore` to `.ignore`. Note that `.rgignore` is - still supported, but deprecated. -* [FEATURE #68](https://github.com/BurntSushi/ripgrep/issues/68): - Add --no-ignore-vcs flag that ignores .gitignore but not .ignore. -* [FEATURE #70](https://github.com/BurntSushi/ripgrep/issues/70): - Add -S/--smart-case flag (but is disabled by default). -* [FEATURE #80](https://github.com/BurntSushi/ripgrep/issues/80): - Add support for `{foo,bar}` globs. - -Many many bug fixes. Thanks every for reporting these and helping make -`ripgrep` better! (Note that I haven't captured every tracking issue here, -some were closed as duplicates.) - -* [BUG #8](https://github.com/BurntSushi/ripgrep/issues/8): - Don't use an intermediate buffer when --threads=1. (Permits constant memory - usage.) -* [BUG #15](https://github.com/BurntSushi/ripgrep/issues/15): - Improves the documentation for --type-add. -* [BUG #16](https://github.com/BurntSushi/ripgrep/issues/16), - [BUG #49](https://github.com/BurntSushi/ripgrep/issues/49), - [BUG #50](https://github.com/BurntSushi/ripgrep/issues/50), - [BUG #65](https://github.com/BurntSushi/ripgrep/issues/65): - Some gitignore globs were being treated as anchored when they weren't. -* [BUG #18](https://github.com/BurntSushi/ripgrep/issues/18): - --vimgrep reported incorrect column number. -* [BUG #19](https://github.com/BurntSushi/ripgrep/issues/19): - ripgrep was hanging waiting on stdin in some Windows terminals. Note that - this introduced a new bug: - [#94](https://github.com/BurntSushi/ripgrep/issues/94). -* [BUG #21](https://github.com/BurntSushi/ripgrep/issues/21): - Removes leading `./` when printing file paths. -* [BUG #22](https://github.com/BurntSushi/ripgrep/issues/22): - Running `rg --help | echo` caused `rg` to panic. -* [BUG #24](https://github.com/BurntSushi/ripgrep/issues/22): - Clarify the central purpose of rg in its usage message. -* [BUG #25](https://github.com/BurntSushi/ripgrep/issues/25): - Anchored gitignore globs weren't applied in subdirectories correctly. -* [BUG #30](https://github.com/BurntSushi/ripgrep/issues/30): - Globs like `foo/**` should match contents of `foo`, but not `foo` itself. -* [BUG #35](https://github.com/BurntSushi/ripgrep/issues/35), - [BUG #81](https://github.com/BurntSushi/ripgrep/issues/81): - When automatically detecting stdin, only read if it's a file or a fifo. - i.e., ignore stdin in `rg foo < /dev/null`. -* [BUG #36](https://github.com/BurntSushi/ripgrep/issues/36): - Don't automatically pick memory maps on MacOS. Ever. -* [BUG #38](https://github.com/BurntSushi/ripgrep/issues/38): - Trailing whitespace in gitignore wasn't being ignored. -* [BUG #43](https://github.com/BurntSushi/ripgrep/issues/43): - --glob didn't work with directories. -* [BUG #46](https://github.com/BurntSushi/ripgrep/issues/46): - Use one fewer worker thread than what is provided on CLI. -* [BUG #47](https://github.com/BurntSushi/ripgrep/issues/47): - --help/--version now work even if other options are set. -* [BUG #55](https://github.com/BurntSushi/ripgrep/issues/55): - ripgrep was refusing to search /proc/cpuinfo. Fixed by disabling memory - maps for files with zero size. -* [BUG #64](https://github.com/BurntSushi/ripgrep/issues/64): - The first path given with --files set was ignored. -* [BUG #67](https://github.com/BurntSushi/ripgrep/issues/67): - Sometimes whitelist globs like `!/dir` weren't interpreted as anchored. -* [BUG #77](https://github.com/BurntSushi/ripgrep/issues/77): - When -q/--quiet flag was passed, ripgrep kept searching even after a match - was found. -* [BUG #90](https://github.com/BurntSushi/ripgrep/issues/90): - Permit whitelisting hidden files. -* [BUG #93](https://github.com/BurntSushi/ripgrep/issues/93): - ripgrep was extracting an erroneous inner literal from a repeated pattern. diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index df657d0..0000000 --- a/Cargo.lock +++ /dev/null @@ -1,417 +0,0 @@ -[[package]] -name = "aho-corasick" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ansi_term" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "atty" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bitflags" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bytecount" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "simd 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cfg-if" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "clap" -version = "2.31.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "encoding_rs" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "simd 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "fnv" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "fuchsia-zircon" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "fuchsia-zircon-sys" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "glob" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "globset" -version = "0.4.0" -dependencies = [ - "aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "grep" -version = "0.1.8" -dependencies = [ - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ignore" -version = "0.4.2" -dependencies = [ - "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "globset 0.4.0", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "lazy_static" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "libc" -version = "0.2.40" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "log" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "memchr" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "memmap" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num_cpus" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "redox_syscall" -version = "0.1.37" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "redox_termios" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "regex" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "regex-syntax" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "remove_dir_all" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ripgrep" -version = "0.8.1" -dependencies = [ - "atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "bytecount 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)", - "encoding_rs 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "globset 0.4.0", - "grep 0.1.8", - "ignore 0.4.2", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 0.3.6", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "same-file" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "simd" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "strsim" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "tempdir" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "termcolor" -version = "0.3.6" -dependencies = [ - "wincolor 0.1.6", -] - -[[package]] -name = "termion" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "textwrap" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "thread_local" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ucd-util" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unicode-width" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unreachable" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "utf8-ranges" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "walkdir" -version = "2.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "wincolor" -version = "0.1.6" -dependencies = [ - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[metadata] -"checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4" -"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" -"checksum atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2fc4a1aa4c24c0718a250f0681885c1af91419d242f29eb8f2ab28502d80dbd1" -"checksum bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c54bb8f454c567f21197eefcdbf5679d0bd99f2ddbe52e84c77061952e6789" -"checksum bytecount 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "882585cd7ec84e902472df34a5e01891202db3bf62614e1f0afe459c1afcf744" -"checksum cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "405216fd8fe65f718daa7102ea808a946b6ce40c742998fbfd3463645552de18" -"checksum clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0f16b89cbb9ee36d87483dc939fe9f1e13c05898d56d7b230a0d4dff033a536" -"checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19" -"checksum encoding_rs 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "98fd0f24d1fb71a4a6b9330c8ca04cbd4e7cc5d846b54ca74ff376bc7c9f798d" -"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" -"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" -"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" -"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" -"checksum libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)" = "6fd41f331ac7c5b8ac259b8bf82c75c0fb2e469bbf37d2becbba9a6a2221965b" -"checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2" -"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d" -"checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff" -"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" -"checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" -"checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd" -"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -"checksum regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "13c93d55961981ba9226a213b385216f83ab43bd6ac53ab16b2eeb47e337cf4e" -"checksum regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1ac0f60d675cc6cf13a20ec076568254472551051ad5dd050364d70671bf6b" -"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" -"checksum same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfb6eded0b06a0b512c8ddbcf04089138c9b4362c2f696f3c3d76039d68f3637" -"checksum simd 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ed3686dd9418ebcc3a26a0c0ae56deab0681e53fe899af91f5bbcee667ebffb1" -"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" -"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" -"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" -"checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693" -"checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963" -"checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d" -"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f" -"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" -"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" -"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "63636bd0eb3d00ccb8b9036381b526efac53caf112b7783b730ab3f8e44da369" -"checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index f0d5439..2350f55 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,81 +1,20 @@ [package] -name = "ripgrep" -version = "0.8.1" #:version +name = "termcolor" +version = "0.3.6" #:version authors = ["Andrew Gallant "] description = """ -ripgrep is a line-oriented search tool that recursively searches your current -directory for a regex pattern while respecting your gitignore rules. ripgrep -has first class support on Windows, macOS and Linux +A simple cross platform library for writing colored text to a terminal. """ -documentation = "https://github.com/BurntSushi/ripgrep" -homepage = "https://github.com/BurntSushi/ripgrep" -repository = "https://github.com/BurntSushi/ripgrep" +documentation = "https://docs.rs/termcolor" +homepage = "https://github.com/BurntSushi/termcolor" +repository = "https://github.com/BurntSushi/termcolor" readme = "README.md" -keywords = ["regex", "grep", "egrep", "search", "pattern"] -categories = ["command-line-utilities", "text-processing"] +keywords = ["windows", "win", "color", "ansi", "console"] license = "Unlicense/MIT" -exclude = ["HomebrewFormula"] -build = "build.rs" -autotests = false -[badges] -travis-ci = { repository = "BurntSushi/ripgrep" } -appveyor = { repository = "BurntSushi/ripgrep" } - -[[bin]] +[lib] +name = "termcolor" bench = false -path = "src/main.rs" -name = "rg" -[[test]] -name = "integration" -path = "tests/tests.rs" - -[workspace] -members = ["grep", "globset", "ignore", "termcolor", "wincolor"] - -[dependencies] -atty = "0.2.9" -bytecount = "0.3.1" -encoding_rs = "0.7" -globset = { version = "0.4.0", path = "globset" } -grep = { version = "0.1.8", path = "grep" } -ignore = { version = "0.4.0", path = "ignore" } -lazy_static = "1" -libc = "0.2" -log = "0.4" -memchr = "2" -memmap = "0.6" -num_cpus = "1" -regex = "1" -same-file = "1" -termcolor = { version = "0.3.4", path = "termcolor" } - -[dependencies.clap] -version = "2.29.4" -default-features = false -features = ["suggestions", "color"] - -[target.'cfg(windows)'.dependencies.winapi] -version = "0.3" -features = ["std", "winnt"] - -[build-dependencies] -lazy_static = "1" - -[build-dependencies.clap] -version = "2.29.4" -default-features = false -features = ["suggestions", "color"] - -[features] -avx-accel = ["bytecount/avx-accel", "regex/unstable"] -simd-accel = [ - "bytecount/simd-accel", - "encoding_rs/simd-accel", - "regex/unstable", -] -unstable = ["regex/unstable"] - -[profile.release] -debug = true +[target.'cfg(windows)'.dependencies] +wincolor = { version = "0.1.6", path = "wincolor" } diff --git a/FAQ.md b/FAQ.md deleted file mode 100644 index c98bafc..0000000 --- a/FAQ.md +++ /dev/null @@ -1,664 +0,0 @@ -## FAQ - -* [Does ripgrep support configuration files?](#config) -* [What's changed in ripgrep recently?](#changelog) -* [When is the next release?](#release) -* [Does ripgrep have a man page?](#manpage) -* [Does ripgrep have support for shell auto-completion?](#complete) -* [How do I use lookaround and/or backreferences?](#fancy) -* [How do I configure ripgrep's colors?](#colors) -* [How do I enable true colors on Windows?](#truecolors-windows) -* [How do I stop ripgrep from messing up colors when I kill it?](#stop-ripgrep) -* [How can I get results in a consistent order?](#order) -* [How do I search files that aren't UTF-8?](#encoding) -* [How do I search compressed files?](#compressed) -* [How do I search over multiple lines?](#multiline) -* [How do I get around the regex size limit?](#size-limit) -* [How do I make the `-f/--file` flag faster?](#dfa-size) -* [How do I make the output look like The Silver Searcher's output?](#silver-searcher-output) -* [When I run `rg`, why does it execute some other command?](#rg-other-cmd) -* [How do I create an alias for ripgrep on Windows?](#rg-alias-windows) -* [How do I create a PowerShell profile?](#powershell-profile) -* [How do I pipe non-ASCII content to ripgrep on Windows?](#pipe-non-ascii-windows) -* [How can I search and replace with ripgrep?](#search-and-replace) -* [How is ripgrep licensed?](#license) -* [Can ripgrep replace grep?](#posix4ever) -* [What does the "rip" in ripgrep mean?](#intentcountsforsomething) - - -

-Does ripgrep support configuration files? -

- -Yes. See the -[guide's section on configuration files](GUIDE.md#configuration-file). - - -

-What's changed in ripgrep recently? -

- -Please consult ripgrep's [CHANGELOG](CHANGELOG.md). - - -

-When is the next release? -

- -ripgrep is a project whose contributors are volunteers. A release schedule -adds undue stress to said volunteers. Therefore, releases are made on a best -effort basis and no dates **will ever be given**. - -One exception to this is high impact bugs. If a ripgrep release contains a -significant regression, then there will generally be a strong push to get a -patch release out with a fix. - - -

-Does ripgrep have a man page? -

- -Yes! Whenever ripgrep is compiled on a system with `asciidoc` present, then a -man page is generated from ripgrep's argv parser. After compiling ripgrep, you -can find the man page like so from the root of the repository: - -``` -$ find ./target -name rg.1 -print0 | xargs -0 ls -t | head -n1 -./target/debug/build/ripgrep-79899d0edd4129ca/out/rg.1 -``` - -Running `man -l ./target/debug/build/ripgrep-79899d0edd4129ca/out/rg.1` will -show the man page in your normal pager. - -Note that the man page's documentation for options is equivalent to the output -shown in `rg --help`. To see more condensed documentation (one line per flag), -run `rg -h`. - -The man page is also included in all -[ripgrep binary releases](https://github.com/BurntSushi/ripgrep/releases). - - -

-Does ripgrep have support for shell auto-completion? -

- -Yes! Shell completions can be found in the -[same directory as the man page](#manpage) -after building ripgrep. Zsh completions are maintained separately and committed -to the repository in `complete/_rg`. - -Shell completions are also included in all -[ripgrep binary releases](https://github.com/BurntSushi/ripgrep/releases). - -For **bash**, move `rg.bash` to -`$XDG_CONFIG_HOME/bash_completion` or `/etc/bash_completion.d/`. - -For **fish**, move `rg.fish` to `$HOME/.config/fish/completions/`. - -For **zsh**, move `_rg` to one of your `$fpath` directories. - -For **PowerShell**, add `. _rg.ps1` to your PowerShell -[profile](https://technet.microsoft.com/en-us/library/bb613488(v=vs.85).aspx) -(note the leading period). If the `_rg.ps1` file is not on your `PATH`, do -`. /path/to/_rg.ps1` instead. - - -

-How can I get results in a consistent order? -

- -By default, ripgrep uses parallelism to execute its search because this makes -the search much faster on most modern systems. This in turn means that ripgrep -has a non-deterministic aspect to it, since the interleaving of threads during -the execution of the program is itself non-deterministic. This has the effect -of printing results in a somewhat arbitrary order, and this order can change -from run to run of ripgrep. - -The only way to make the order of results consistent is to ask ripgrep to -sort the output. Currently, this will disable all parallelism. (On smaller -repositories, you might not notice much of a performance difference!) You -can achieve this with the `--sort-files` flag. - -There is more discussion on this topic here: -https://github.com/BurntSushi/ripgrep/issues/152 - - -

-How do I search files that aren't UTF-8? -

- -See the [guide's section on file encoding](GUIDE.md#file-encoding). - - -

-How do I search compressed files? -

- -ripgrep's `-z/--search-zip` flag will cause it to search compressed files -automatically. Currently, this supports gzip, bzip2, lzma and xz only and -requires the corresponding `gzip`, `bzip2` and `xz` binaries to be installed on -your system. (That is, ripgrep does decompression by shelling out to another -process.) - -ripgrep currently does not search archive formats, so `*.tar.gz` files, for -example, are skipped. - - -

-How do I search over multiple lines? -

- -This isn't currently possible. ripgrep is fundamentally a line-oriented search -tool. With that said, -[multiline search is a planned opt-in feature](https://github.com/BurntSushi/ripgrep/issues/176). - - -

-How do I use lookaround and/or backreferences? -

- -This isn't currently possible. ripgrep uses finite automata to implement -regular expression search, and in turn, guarantees linear time searching on all -inputs. It is difficult to efficiently support lookaround and backreferences in -finite automata engines, so ripgrep does not provide these features. - -If a production quality regular expression engine with these features is ever -written in Rust, then it is possible ripgrep will provide it as an opt-in -feature. - - -

-How do I configure ripgrep's colors? -

- -ripgrep has two flags related to colors: - -* `--color` controls *when* to use colors. -* `--colors` controls *which* colors to use. - -The `--color` flag accepts one of the following possible values: `never`, -`auto`, `always` or `ansi`. The `auto` value is the default and will cause -ripgrep to only enable colors when it is printing to a terminal. But if you -pipe ripgrep to a file or some other process, then it will suppress colors. - -The --colors` flag is a bit more complicated. The general format is: - -``` ---colors '{type}:{attribute}:{value}' -``` - -* `{type}` should be one of `path`, `line`, `column` or `match`. Each of these - correspond to the four different types of things that ripgrep will add color - to in its output. Select the type whose color you want to change. -* `{attribute}` should be one of `fg`, `bg` or `style`, corresponding to - foreground color, background color, or miscellaneous styling (such as whether - to bold the output or not). -* `{value}` is determined by the value of `{attribute}`. If - `{attribute}` is `style`, then `{value}` should be one of `nobold`, - `bold`, `nointense`, `intense`, `nounderline` or `underline`. If - `{attribute}` is `fg` or `bg`, then `{value}` should be a color. - -A color is specified by either one of eight of English names, a single 256-bit -number or an RGB triple (with over 16 million possible values, or "true -color"). - -The color names are `red`, `blue`, `green`, `cyan`, `magenta`, `yellow`, -`white` or `black`. - -A single 256-bit number is a value in the range 0-255 (inclusive). It can -either be in decimal format (e.g., `62`) or hexadecimal format (e.g., `0x3E`). - -An RGB triple corresponds to three numbers (decimal or hexadecimal) separated -by commas. - -As a special case, `--colors '{type}:none'` will clear all colors and styles -associated with `{type}`, which lets you start with a clean slate (instead of -building on top of ripgrep's default color settings). - -Here's an example that makes highlights the matches with a nice blue background -with bolded white text: - -``` -$ rg somepattern \ - --colors 'match:none' \ - --colors 'match:bg:0x33,0x66,0xFF' \ - --colors 'match:fg:white' \ - --colors 'match:style:bold' -``` - -Colors are an ideal candidate to set in your -[configuration file](GUIDE.md#configuration-file). See the -[question on emulating The Silver Searcher's output style](#silver-searcher-output) -for an example specific to colors. - - -

-How do I enable true colors on Windows? -

- -First, see the previous question's -[answer on configuring colors](#colors). - -Secondly, coloring on Windows is a bit complicated. If you're using a terminal -like Cygwin, then it's likely true color support already works out of the box. -However, if you are using a normal Windows console (`cmd` or `PowerShell`) and -a version of Windows prior to 10, then there is no known way to get true -color support. If you are on Windows 10 and using a Windows console, then -true colors should work out of the box with one caveat: you might need to -clear ripgrep's default color settings first. That is, instead of this: - -``` -$ rg somepattern --colors 'match:fg:0x33,0x66,0xFF' -``` - -you should do this - -``` -$ rg somepattern --colors 'match:none' --colors 'match:fg:0x33,0x66,0xFF' -``` - -This is because ripgrep might set the default style for `match` to `bold`, and -it seems like Windows 10's VT100 support doesn't permit bold and true color -ANSI escapes to be used simultaneously. The work-around above will clear -ripgrep's default styling, allowing you to craft it exactly as desired. - - -

-How do I stop ripgrep from messing up colors when I kill it? -

- -Type in `color` in cmd.exe (Command Prompt) and `echo -ne "\033[0m"` on -Unix-like systems to restore your original foreground color. - -In PowerShell, you can add the following code to your profile which will -restore the original foreground color when `Reset-ForegroundColor` is called. -Including the `Set-Alias` line will allow you to call it with simply `color`. - -```powershell -$OrigFgColor = $Host.UI.RawUI.ForegroundColor -function Reset-ForegroundColor { - $Host.UI.RawUI.ForegroundColor = $OrigFgColor -} -Set-Alias -Name color -Value Reset-ForegroundColor -``` - -PR [#187](https://github.com/BurntSushi/ripgrep/pull/187) fixed this, and it -was later deprecated in -[#281](https://github.com/BurntSushi/ripgrep/issues/281). A full explanation is -available -[here](https://github.com/BurntSushi/ripgrep/issues/281#issuecomment-269093893). - - -

-How do I get around the regex size limit? -

- -If you've given ripgrep a particularly large pattern (or a large number of -smaller patterns), then it is possible that it will fail to compile because it -hit a pre-set limit. For example: - -``` -$ rg '\pL{1000}' -Compiled regex exceeds size limit of 10485760 bytes. -``` - -(Note: `\pL{1000}` may look small, but `\pL` is the character class containing -all Unicode letters, which is quite large. *And* it's repeated 1000 times.) - -In this case, you can work around by simply increasing the limit: - -``` -$ rg '\pL{1000}' --regex-size-limit 1G -``` - -Increasing the limit to 1GB does not necessarily mean that ripgrep will use -that much memory. The limit just says that it's allowed to (approximately) use -that much memory for constructing the regular expression. - - -

-How do I make the -f/--file flag faster? -

- -The `-f/--file` permits one to give a file to ripgrep which contains a pattern -on each line. ripgrep will then report any line that matches any of the -patterns. - -If this pattern file gets too big, then it is possible ripgrep will slow down -dramatically. *Typically* this is because an internal cache is too small, and -will cause ripgrep to spill over to a slower but more robust regular expression -engine. If this is indeed the problem, then it is possible to increase this -cache and regain speed. The cache can be controlled via the `--dfa-size-limit` -flag. For example, using `--dfa-size-limit 1G` will set the cache size to 1GB. -(Note that this doesn't mean ripgrep will use 1GB of memory automatically, but -it will allow the regex engine to if it needs to.) - - -

-How do I make the output look like The Silver Searcher's output? -

- -Use the `--colors` flag, like so: - -``` -rg --colors line:fg:yellow \ - --colors line:style:bold \ - --colors path:fg:green \ - --colors path:style:bold \ - --colors match:fg:black \ - --colors match:bg:yellow \ - --colors match:style:nobold \ - foo -``` - -Alternatively, add your color configuration to your ripgrep config file (which -is activated by setting the `RIPGREP_CONFIG_PATH` environment variable to point -to your config file). For example: - -``` -$ cat $HOME/.config/ripgrep/rc ---colors=line:fg:yellow ---colors=line:style:bold ---colors=path:fg:green ---colors=path:style:bold ---colors=match:fg:black ---colors=match:bg:yellow ---colors=match:style:nobold -$ RIPGREP_CONFIG_PATH=$HOME/.config/ripgrep/rc rg foo -``` - - -

-When I run rg, why does it execute some other command? -

- -It's likely that you have a shell alias or even another tool called `rg` which -is interfering with ripgrep. Run `which rg` to see what it is. - -(Notably, the Rails plug-in for -[Oh My Zsh](https://github.com/robbyrussell/oh-my-zsh/wiki/Plugins#rails) sets -up an `rg` alias for `rails generate`.) - -Problems like this can be resolved in one of several ways: - -* If you're using the OMZ Rails plug-in, disable it by editing the `plugins` - array in your zsh configuration. -* Temporarily bypass an existing `rg` alias by calling ripgrep as - `command rg`, `\rg`, or `'rg'`. -* Temporarily bypass an existing alias or another tool named `rg` by calling - ripgrep by its full path (e.g., `/usr/bin/rg` or `/usr/local/bin/rg`). -* Permanently disable an existing `rg` alias by adding `unalias rg` to the - bottom of your shell configuration file (e.g., `.bash_profile` or `.zshrc`). -* Give ripgrep its own alias that doesn't conflict with other tools/aliases by - adding a line like the following to the bottom of your shell configuration - file: `alias ripgrep='command rg'`. - - -

-How do I create an alias for ripgrep on Windows? -

- -Often you can find a need to make alias for commands you use a lot that set -certain flags. But PowerShell function aliases do not behave like your typical -linux shell alias. You always need to propagate arguments and `stdin` input. -But it cannot be done simply as -`function grep() { $input | rg.exe --hidden $args }` - -Use below example as reference to how setup alias in PowerShell. - -```powershell -function grep { - $count = @($input).Count - $input.Reset() - - if ($count) { - $input | rg.exe --hidden $args - } - else { - rg.exe --hidden $args - } -} -``` - -PowerShell special variables: - -* input - is powershell `stdin` object that allows you to access its content. -* args - is array of arguments passed to this function. - -This alias checks whether there is `stdin` input and propagates only if there -is some lines. Otherwise empty `$input` will make powershell to trigger `rg` to -search empty `stdin`. - - -

-How do I create a PowerShell profile? -

- -To customize powershell on start-up, there is a special PowerShell script that -has to be created. In order to find its location, type `$profile`. -See -[Microsoft's documentation](https://technet.microsoft.com/en-us/library/bb613488(v=vs.85).aspx) -for more details. - -Any PowerShell code in this file gets evaluated at the start of console. This -way you can have own aliases to be created at start. - - -

-How do I pipe non-ASCII content to ripgrep on Windows? -

- -When piping input into native executables in PowerShell, the encoding of the -input is controlled by the `$OutputEncoding` variable. By default, this is set -to US-ASCII, and any characters in the pipeline that don't have encodings in -US-ASCII are converted to `?` (question mark) characters. - -To change this setting, set `$OutputEncoding` to a different encoding, as -represented by a .NET encoding object. Some common examples are below. The -value of this variable is reset when PowerShell restarts, so to make this -change take effect every time PowerShell is started add a line setting the -variable into your PowerShell profile. - -Example `$OutputEncoding` settings: - -* UTF-8 without BOM: `$OutputEncoding = [System.Text.UTF8Encoding]::new()` -* The console's output encoding: - `$OutputEncoding = [System.Console]::OutputEncoding` - -If you continue to have encoding problems, you can also force the encoding -that the console will use for printing to UTF-8 with -`[System.Console]::OutputEncoding = [System.Text.Encoding]::UTF8`. This -will also reset when PowerShell is restarted, so you can add that line -to your profile as well if you want to make the setting permanent. - -

-How can I search and replace with ripgrep? -

- -Using ripgrep alone, you can't. ripgrep is a search tool that will never -touch your files. However, the output of ripgrep can be piped to other tools -that do modify files on disk. See -[this issue](https://github.com/BurntSushi/ripgrep/issues/74) for more -information. - -sed is one such tool that can modify files on disk. sed can take a filename -and a substitution command to search and replace in the specified file. -Files containing matching patterns can be provided to sed using - -``` -rg foo --files-with-matches -``` - -The output of this command is a list of filenames that contain a match for -the `foo` pattern. - -This list can be piped into `xargs`, which will split the filenames from -standard input into arguments for the command following xargs. You can use this -combination to pipe a list of filenames into sed for replacement. For example: - -``` -rg foo --files-with-matches | xargs sed -i 's/foo/bar/g' -``` - -will replace all instances of 'foo' with 'bar' in the files in which -ripgrep finds the foo pattern. The `-i` flag to sed indicates that you are -editing files in place, and `s/foo/bar/g` says that you are performing a -**s**ubstitution of the pattren `foo` for `bar`, and that you are doing this -substitution **g**lobally (all occurrences of the pattern in each file). - -Note: the above command assumes that you are using GNU sed. If you are using -BSD sed (the default on macOS and FreeBSD) then you must modify the above -command to be the following: - -``` -rg foo --files-with-matches | xargs sed -i '' 's/foo/bar/g' -``` - -The `-i` flag in BSD sed requires a file extension to be given to make backups -for all modified files. Specifying the empty string prevents file backups from -being made. - -Finally, if any of your file paths contain whitespace in them, then you might -need to delimit your file paths with a NUL terminator. This requires telling -ripgrep to output NUL bytes between each path, and telling xargs to read paths -delimited by NUL bytes: - -``` -rg foo --files-with-matches -0 | xargs -0 sed -i 's/foo/bar/g' -``` - -To learn more about sed, see the sed manual -[here](https://www.gnu.org/software/sed/manual/sed.html). - -Additionally, Facebook has a tool called -[fastmod](https://github.com/facebookincubator/fastmod) -that uses some of the same libraries as ripgrep and might provide a more -ergonomic search-and-replace experience. - - -

-How is ripgrep licensed? -

- -ripgrep is dual licensed under the -[Unlicense](https://unlicense.org/) -and MIT licenses. Specifically, you may use ripgrep under the terms of either -license. - -The reason why ripgrep is dual licensed this way is two-fold: - -1. I, as ripgrep's author, would like to participate in a small bit of - ideological activism by promoting the Unlicense's goal: to disclaim - copyright monopoly interest. -2. I, as ripgrep's author, would like as many people to use rigprep as - possible. Since the Unlicense is not a proven or well known license, ripgrep - is also offered under the MIT license, which is ubiquitous and accepted by - almost everyone. - -More specifically, ripgrep and all its dependencies are compatible with this -licensing choice. In particular, ripgrep's dependencies (direct and transitive) -will always be limited to permissive licenses. That is, ripgrep will never -depend on code that is not permissively licensed. This means rejecting any -dependency that uses a copyleft license such as the GPL, LGPL, MPL or any of -the Creative Commons ShareAlike licenses. Whether the license is "weak" -copyleft or not does not matter; ripgrep will **not** depend on it. - - -

-Can ripgrep replace grep? -

- -Yes and no. - -If, upon hearing that "ripgrep can replace grep," you *actually* hear, "ripgrep -can be used in every instance grep can be used, in exactly the same way, for -the same use cases, with exactly the same bug-for-bug behavior," then no, -ripgrep trivially *cannot* replace grep. Moreover, ripgrep will *never* replace -grep. - -If, upon hearing that "ripgrep can replace grep," you *actually* hear, "ripgrep -can replace grep in some cases and not in other use cases," then yes, that is -indeed true! - -Let's go over some of those use cases in favor of ripgrep. Some of these may -not apply to you. That's OK. There may be other use cases not listed here that -do apply to you. That's OK too. - -(For all claims related to performance in the following words, see my -[blog post](https://blog.burntsushi.net/ripgrep/) -introducing ripgrep.) - -* Are you frequently searching a repository of code? If so, ripgrep might be a - good choice since there's likely a good chunk of your repository that you - don't want to search. grep, can, of course, be made to filter files using - recursive search, and if you don't mind writing out the requisite `--exclude` - rules or writing wrapper scripts, then grep might be sufficient. (I'm not - kidding, I myself did this with grep for almost a decade before writing - ripgrep.) But if you instead enjoy having a search tool respect your - `.gitignore`, then ripgrep might be perfect for you! -* Are you frequently searching non-ASCII text that is UTF-8 encoded? One of - ripgrep's key features is that it can handle Unicode features in your - patterns in a way that tends to be faster than GNU grep. Unicode features - in ripgrep are enabled by default; there is no need to configure your locale - settings to use ripgrep properly because ripgrep doesn't respect your locale - settings. -* Do you need to search UTF-16 files and you don't want to bother explicitly - transcoding them? Great. ripgrep does this for you automatically. No need - to enable it. -* Do you need to search a large directory of large files? ripgrep uses - parallelism by default, which tends to make it faster than a standard - `grep -r` search. However, if you're OK writing the occasional - `find ./ -print0 | xargs -P8 -0 grep` command, then maybe grep is good - enough. - -Here are some cases where you might *not* want to use ripgrep. The same caveats -for the previous section apply. - -* Are you writing portable shell scripts intended to work in a variety of - environments? Great, probably not a good idea to use ripgrep! ripgrep is has - nowhere near the ubquity of grep, so if you do use ripgrep, you might need - 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 - because it never was, isn't and never will be POSIX compatible. -* Do you hate tools that try to do something smart? If so, ripgrep is all about - being smart, so you might prefer to just stick with grep. -* Is there a particular feature of grep you rely on that ripgrep either doesn't - have or never will have? If the former, file a bug report, maybe ripgrep can - do it! If the latter, well, then, just use grep. - - -

-What does the "rip" in ripgrep mean? -

- -When I first started writing ripgrep, I called it `rep`, intending it to be a -shorter variant of `grep`. Soon after, I renamed it to `xrep` since `rep` -wasn't obvious enough of a name for my taste. And also because adding `x` to -anything always makes it better, right? - -Before ripgrep's first public release, I decided that I didn't like `xrep`. I -thought it was slightly awkward to type, and despite my previous praise of the -letter `x`, I kind of thought it was pretty lame. Being someone who really -likes Rust, I wanted to call it "rustgrep" or maybe "rgrep" for short. But I -thought that was just as lame, and maybe a little too in-your-face. But I -wanted to continue using `r` so I could at least pretend Rust had something to -do with it. - -I spent a couple of days trying to think of very short words that began with -the letter `r` that were even somewhat related to the task of searching. I -don't remember how it popped into my head, but "rip" came up as something that -meant "fast," as in, "to rip through your text." The fact that RIP is also -an initialism for "Rest in Peace" (as in, "ripgrep kills grep") never really -dawned on me. Perhaps the coincidence is too striking to believe that, but -I didn't realize it until someone explicitly pointed it out to me after the -initial public release. I admit that I found it mildly amusing, but if I had -realized it myself before the public release, I probably would have pressed on -and chose a different name. Alas, renaming things after a release is hard, so I -decided to mush on. - -Given the fact that -[ripgrep never was, is or will be a 100% drop-in replacement for -grep](#posix4ever), -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 -tools like ack or The Silver Searcher weren't already doing. diff --git a/GUIDE.md b/GUIDE.md deleted file mode 100644 index 313c89a..0000000 --- a/GUIDE.md +++ /dev/null @@ -1,687 +0,0 @@ -## User Guide - -This guide is intended to give an elementary description of ripgrep and an -overview of its capabilities. This guide assumes that ripgrep is -[installed](README.md#installation) -and that readers have passing familiarity with using command line tools. This -also assumes a Unix-like system, although most commands are probably easily -translatable to any command line shell environment. - - -### Table of Contents - -* [Basics](#basics) -* [Recursive search](#recursive-search) -* [Automatic filtering](#automatic-filtering) -* [Manual filtering: globs](#manual-filtering-globs) -* [Manual filtering: file types](#manual-filtering-file-types) -* [Replacements](#replacements) -* [Configuration file](#configuration-file) -* [File encoding](#file-encoding) -* [Common options](#common-options) - - -### Basics - -ripgrep is a command line tool that searches your files for patterns that -you give it. ripgrep behaves as if reading each file line by line. If a line -matches the pattern provided to ripgrep, then that line will be printed. If a -line does not match the pattern, then the line is not printed. - -The best way to see how this works is with an example. To show an example, we -need something to search. Let's try searching ripgrep's source code. First -grab a ripgrep source archive from -https://github.com/BurntSushi/ripgrep/archive/0.7.1.zip -and extract it: - -``` -$ curl -LO https://github.com/BurntSushi/ripgrep/archive/0.7.1.zip -$ unzip 0.7.1.zip -$ cd ripgrep-0.7.1 -$ ls -benchsuite grep tests Cargo.toml LICENSE-MIT -ci ignore wincolor CHANGELOG.md README.md -complete pkg appveyor.yml compile snapcraft.yaml -doc src build.rs COPYING UNLICENSE -globset termcolor Cargo.lock HomebrewFormula -``` - -Let's try our first search by looking for all occurrences of the word `fast` -in `README.md`: - -``` -$ rg fast README.md -75: faster than both. (N.B. It is not, strictly speaking, a "drop-in" replacement -88: color and full Unicode support. Unlike GNU grep, `ripgrep` stays fast while -119:### Is it really faster than everything else? -124:Summarizing, `ripgrep` is fast because: -129: optimizations to make searching very fast. -``` - -(**Note:** If you see an error message from ripgrep saying that it didn't -search any files, then re-run ripgrep with the `--debug` flag. One likely cause -of this is that you have a `*` rule in a `$HOME/.gitignore` file.) - -So what happened here? ripgrep read the contents of `README.md`, and for each -line that contained `fast`, ripgrep printed it to your terminal. ripgrep also -included the line number for each line by default. If your terminal supports -colors, then your output might actually look something like this screenshot: - -[![A screenshot of a sample search ripgrep](https://burntsushi.net/stuff/ripgrep-guide-sample.png)](https://burntsushi.net/stuff/ripgrep-guide-sample.png) - -In this example, we searched for something called a "literal" string. This -means that our pattern was just some normal text that we asked ripgrep to -find. But ripgrep supports the ability to specify patterns via [regular -expressions](https://en.wikipedia.org/wiki/Regular_expression). As an example, -what if we wanted to find all lines have a word that contains `fast` followed -by some number of other letters? - -``` -$ rg 'fast\w+' README.md -75: faster than both. (N.B. It is not, strictly speaking, a "drop-in" replacement -119:### Is it really faster than everything else? -``` - -In this example, we used the pattern `fast\w+`. This pattern tells ripgrep to -look for any lines containing the letters `fast` followed by *one or more* -word-like characters. Namely, `\w` matches characters that compose words (like -`a` and `L` but unlike `.` and ` `). The `+` after the `\w` means, "match the -previous pattern one or more times." This means that the word `fast` won't -match because there are no word characters following the final `t`. But a word -like `faster` will. `faste` would also match! - -Here's a different variation on this same theme: - -``` -$ rg 'fast\w*' README.md -75: faster than both. (N.B. It is not, strictly speaking, a "drop-in" replacement -88: color and full Unicode support. Unlike GNU grep, `ripgrep` stays fast while -119:### Is it really faster than everything else? -124:Summarizing, `ripgrep` is fast because: -129: optimizations to make searching very fast. -``` - -In this case, we used `fast\w*` for our pattern instead of `fast\w+`. The `*` -means that it should match *zero* or more times. In this case, ripgrep will -print the same lines as the pattern `fast`, but if your terminal supports -colors, you'll notice that `faster` will be highlighted instead of just the -`fast` prefix. - -It is beyond the scope of this guide to provide a full tutorial on regular -expressions, but ripgrep's specific syntax is documented here: -https://docs.rs/regex/0.2.5/regex/#syntax - - -### Recursive search - -In the previous section, we showed how to use ripgrep to search a single file. -In this section, we'll show how to use ripgrep to search an entire directory -of files. In fact, *recursively* searching your current working directory is -the default mode of operation for ripgrep, which means doing this is very -simple. - -Using our unzipped archive of ripgrep source code, here's how to find all -function definitions whose name is `write`: - -``` -$ rg 'fn write\(' -src/printer.rs -469: fn write(&mut self, buf: &[u8]) { - -termcolor/src/lib.rs -227: fn write(&mut self, b: &[u8]) -> io::Result { -250: fn write(&mut self, b: &[u8]) -> io::Result { -428: fn write(&mut self, b: &[u8]) -> io::Result { self.wtr.write(b) } -441: fn write(&mut self, b: &[u8]) -> io::Result { self.wtr.write(b) } -454: fn write(&mut self, buf: &[u8]) -> io::Result { -511: fn write(&mut self, buf: &[u8]) -> io::Result { -848: fn write(&mut self, buf: &[u8]) -> io::Result { -915: fn write(&mut self, buf: &[u8]) -> io::Result { -949: fn write(&mut self, buf: &[u8]) -> io::Result { -1114: fn write(&mut self, buf: &[u8]) -> io::Result { -1348: fn write(&mut self, buf: &[u8]) -> io::Result { -1353: fn write(&mut self, buf: &[u8]) -> io::Result { -``` - -(**Note:** We escape the `(` here because `(` has special significance inside -regular expressions. You could also use `rg -F 'fn write('` to achieve the -same thing, where `-F` interprets your pattern as a literal string instead of -a regular expression.) - -In this example, we didn't specify a file at all. Instead, ripgrep defaulted -to searching your current directory in the absence of a path. In general, -`rg foo` is equivalent to `rg foo ./`. - -This particular search showed us results in both the `src` and `termcolor` -directories. The `src` directory is the core ripgrep code where as `termcolor` -is a dependency of ripgrep (and is used by other tools). What if we only wanted -to search core ripgrep code? Well, that's easy, just specify the directory you -want: - -``` -$ rg 'fn write\(' src -src/printer.rs -469: fn write(&mut self, buf: &[u8]) { -``` - -Here, ripgrep limited its search to the `src` directory. Another way of doing -this search would be to `cd` into the `src` directory and simply use `rg 'fn -write\('` again. - - -### Automatic filtering - -After recursive search, ripgrep's most important feature is what it *doesn't* -search. By default, when you search a directory, ripgrep will ignore all of -the following: - -1. Files and directories that match the rules in your `.gitignore` glob - pattern. -2. Hidden files and directories. -3. Binary files. (ripgrep considers any file with a `NUL` byte to be binary.) -4. Symbolic links aren't followed. - -All of these things can be toggled using various flags provided by ripgrep: - -1. You can disable `.gitignore` handling with the `--no-ignore` flag. -2. Hidden files and directories can be searched with the `--hidden` flag. -3. Binary files can be searched via the `--text` (`-a` for short) flag. - Be careful with this flag! Binary files may emit control characters to your - terminal, which might cause strange behavior. -4. ripgrep can follow symlinks with the `--follow` (`-L` for short) flag. - -As a special convenience, ripgrep also provides a flag called `--unrestricted` -(`-u` for short). Repeated uses of this flag will cause ripgrep to disable -more and more of its filtering. That is, `-u` will disable `.gitignore` -handling, `-uu` will search hidden files and directories and `-uuu` will search -binary files. This is useful when you're using ripgrep and you aren't sure -whether its filtering is hiding results from you. Tacking on a couple `-u` -flags is a quick way to find out. (Use the `--debug` flag if you're still -perplexed, and if that doesn't help, -[file an issue](https://github.com/BurntSushi/ripgrep/issues/new).) - -ripgrep's `.gitignore` handling actually goes a bit beyond just `.gitignore` -files. ripgrep will also respect repository specific rules found in -`$GIT_DIR/info/exclude`, as well as any global ignore rules in your -`core.excludesFile` (which is usually `$XDG_CONFIG_HOME/git/ignore` on -Unix-like systems). - -Sometimes you want to search files that are in your `.gitignore`, so it is -possible to specify additional ignore rules or overrides in a `.ignore` -(application agnostic) or `.rgignore` (ripgrep specific) file. - -For example, let's say you have a `.gitignore` file that looks like this: - -``` -log/ -``` - -This generally means that any `log` directory won't be tracked by `git`. -However, perhaps it contains useful output that you'd like to include in your -searches, but you still don't want to track it in `git`. You can achieve this -by creating a `.ignore` file in the same directory as the `.gitignore` file -with the following contents: - -``` -!log/ -``` - -ripgrep treats `.ignore` files with higher precedence than `.gitignore` files -(and treats `.rgignore` files with higher precdence than `.ignore` files). -This means ripgrep will see the `!log/` whitelist rule first and search that -directory. - -Like `.gitignore`, a `.ignore` file can be placed in any directory. Its rules -will be processed with respect to the directory it resides in, just like -`.gitignore`. - -For a more in depth description of how glob patterns in a `.gitignore` file -are interpreted, please see `man gitignore`. - - -### Manual filtering: globs - -In the previous section, we talked about ripgrep's filtering that it does by -default. It is "automatic" because it reacts to your environment. That is, it -uses already existing `.gitignore` files to produce more relevant search -results. - -In addition to automatic filtering, ripgrep also provides more manual or ad hoc -filtering. This comes in two varieties: additional glob patterns specified in -your ripgrep commands and file type filtering. This section covers glob -patterns while the next section covers file type filtering. - -In our ripgrep source code (see [Basics](#basics) for instructions on how to -get a source archive to search), let's say we wanted to see which things depend -on `clap`, our argument parser. - -We could do this: - -``` -$ rg clap -[lots of results] -``` - -But this shows us many things, and we're only interested in where we wrote -`clap` as a dependency. Instead, we could limit ourselves to TOML files, which -is how dependencies are communicated to Rust's build tool, Cargo: - -``` -$ rg clap -g '*.toml' -Cargo.toml -35:clap = "2.26" -51:clap = "2.26" -``` - -The `-g '*.toml'` syntax says, "make sure every file searched matches this -glob pattern." Note that we put `'*.toml'` in single quotes to prevent our -shell from expanding the `*`. - -If we wanted, we could tell ripgrep to search anything *but* `*.toml` files: - -``` -$ rg clap -g '!*.toml' -[lots of results] -``` - -This will give you a lot of results again as above, but they won't include -files ending with `.toml`. Note that the use of a `!` here to mean "negation" -is a bit non-standard, but it was chosen to be consistent with how globs in -`.gitignore` files are written. (Although, the meaning is reversed. In -`.gitignore` files, a `!` prefix means whitelist, and on the command line, a -`!` means blacklist.) - -Globs are interpreted in exactly the same way as `.gitignore` patterns. That -is, later globs will override earlier globs. For example, the following command -will search only `*.toml` files: - -``` -$ rg clap -g '!*.toml' -g '*.toml' -``` - -Interestingly, reversing the order of the globs in this case will match -nothing, since the presence of at least one non-blacklist glob will institute a -requirement that every file searched must match at least one glob. In this -case, the blacklist glob takes precedence over the previous glob and prevents -any file from being searched at all! - - -### Manual filtering: file types - -Over time, you might notice that you use the same glob patterns over and over. -For example, you might find yourself doing a lot of searches where you only -want to see results for Rust files: - -``` -$ rg 'fn run' -g '*.rs' -``` - -Instead of writing out the glob every time, you can use ripgrep's support for -file types: - -``` -$ rg 'fn run' --type rust -``` - -or, more succinctly, - -``` -$ rg 'fn run' -trust -``` - -The way the `--type` flag functions is simple. It acts as a name that is -assigned to one or more globs that match the relevant files. This lets you -write a single type that might encompass a broad range of file extensions. For -example, if you wanted to search C files, you'd have to check both C source -files and C header files: - -``` -$ rg 'int main' -g '*.{c,h}' -``` - -or you could just use the C file type: - -``` -$ rg 'int main' -tc -``` - -Just as you can write blacklist globs, you can blacklist file types too: - -``` -$ rg clap --type-not rust -``` - -or, more succinctly, - -``` -$ rg clap -Trust -``` - -That is, `-t` means "include files of this type" where as `-T` means "exclude -files of this type." - -To see the globs that make up a type, run `rg --type-list`: - -``` -$ rg --type-list | rg '^make:' -make: *.mak, *.mk, GNUmakefile, Gnumakefile, Makefile, gnumakefile, makefile -``` - -By default, ripgrep comes with a bunch of pre-defined types. Generally, these -types correspond to well known public formats. But you can define your own -types as well. For example, perhaps you frequently search "web" files, which -consist of Javascript, HTML and CSS: - -``` -$ rg --type-add 'web:*.html' --type-add 'web:*.css' --type-add 'web:*.js' -tweb title -``` - -or, more succinctly, - -``` -$ rg --type-add 'web:*.{html,css,js}' -tweb title -``` - -The above command defines a new type, `web`, corresponding to the glob -`*.{html,css,js}`. It then applies the new filter with `-tweb` and searches for -the pattern `title`. If you ran - -``` -$ rg --type-add 'web:*.{html,css,js}' --type-list -``` - -Then you would see your `web` type show up in the list, even though it is not -part of ripgrep's built-in types. - -It is important to stress here that the `--type-add` flag only applies to the -current command. It does not add a new file type and save it somewhere in a -persistent form. If you want a type to be available in every ripgrep command, -then you should either create a shell alias: - -``` -alias rg="rg --type-add 'web:*.{html,css,js}'" -``` - -or add `--type-add=web:*.{html,css,js}` to your ripgrep configuration file. -([Configuration files](#configuration-file) are covered in more detail later.) - - -### Replacements - -ripgrep provides a limited ability to modify its output by replacing matched -text with some other text. This is easiest to explain with an example. Remember -when we searched for the word `fast` in ripgrep's README? - -``` -$ rg fast README.md -75: faster than both. (N.B. It is not, strictly speaking, a "drop-in" replacement -88: color and full Unicode support. Unlike GNU grep, `ripgrep` stays fast while -119:### Is it really faster than everything else? -124:Summarizing, `ripgrep` is fast because: -129: optimizations to make searching very fast. -``` - -What if we wanted to *replace* all occurrences of `fast` with `FAST`? That's -easy with ripgrep's `--replace` flag: - -``` -$ rg fast README.md --replace FAST -75: FASTer than both. (N.B. It is not, strictly speaking, a "drop-in" replacement -88: color and full Unicode support. Unlike GNU grep, `ripgrep` stays FAST while -119:### Is it really FASTer than everything else? -124:Summarizing, `ripgrep` is FAST because: -129: optimizations to make searching very FAST. -``` - -or, more succinctly, - -``` -$ rg fast README.md -r FAST -[snip] -``` - -In essence, the `--replace` flag applies *only* to the matching portion of text -in the output. If you instead wanted to replace an entire line of text, then -you need to include the entire line in your match. For example: - -``` -$ rg '^.*fast.*$' README.md -r FAST -75:FAST -88:FAST -119:FAST -124:FAST -129:FAST -``` - -Alternatively, you can combine the `--only-matching` (or `-o` for short) with -the `--replace` flag to achieve the same result: - -``` -$ rg fast README.md --only-matching --replace FAST -75:FAST -88:FAST -119:FAST -124:FAST -129:FAST -``` - -or, more succinctly, - -``` -$ rg fast README.md -or FAST -[snip] -``` - -Finally, replacements can include capturing groups. For example, let's say -we wanted to find all occurrences of `fast` followed by another word and -join them together with a dash. The pattern we might use for that is -`fast\s+(\w+)`, which matches `fast`, followed by any amount of whitespace, -followed by any number of "word" characters. We put the `\w+` in a "capturing -group" (indicated by parentheses) so that we can reference it later in our -replacement string. For example: - -``` -$ rg 'fast\s+(\w+)' README.md -r 'fast-$1' -88: color and full Unicode support. Unlike GNU grep, `ripgrep` stays fast-while -124:Summarizing, `ripgrep` is fast-because: -``` - -Our replacement string here, `fast-$1`, consists of `fast-` followed by the -contents of the capturing group at index `1`. (Capturing groups actually start -at index 0, but the `0`th capturing group always corresponds to the entire -match. The capturing group at index `1` always corresponds to the first -explicit capturing group found in the regex pattern.) - -Capturing groups can also be named, which is sometimes more convenient than -using the indices. For example, the following command is equivalent to the -above command: - -``` -$ rg 'fast\s+(?P\w+)' README.md -r 'fast-$word' -88: color and full Unicode support. Unlike GNU grep, `ripgrep` stays fast-while -124:Summarizing, `ripgrep` is fast-because: -``` - -It is important to note that ripgrep **will never modify your files**. The -`--replace` flag only controls ripgrep's output. (And there is no flag to let -you do a replacement in a file.) - - -### Configuration file - -It is possible that ripgrep's default options aren't suitable in every case. -For that reason, and because shell aliases aren't always convenient, ripgrep -supports configuration files. - -Setting up a configuration file is simple. ripgrep will not look in any -predetermined directory for a config file automatically. Instead, you need to -set the `RIPGREP_CONFIG_PATH` environment variable to the file path of your -config file. Once the environment variable is set, open the file and just type -in the flags you want set automatically. There are only two rules for -describing the format of the config file: - -1. Every line is a shell argument, after trimming ASCII whitespace. -2. Lines starting with `#` (optionally preceded by any amount of - ASCII whitespace) are ignored. - -In particular, there is no escaping. Each line is given to ripgrep as a single -command line argument verbatim. - -Here's an example of a configuration file, which demonstrates some of the -formatting peculiarities: - -``` -$ cat $HOME/.ripgreprc -# Don't let ripgrep vomit really long lines to my terminal. ---max-columns=150 - -# Add my 'web' type. ---type-add -web:*.{html,css,js}* - -# Using glob patterns to include/exclude files or folders ---glob=!git/* - -# or ---glob -!git/* - -# Set the colors. ---colors=line:none ---colors=line:style:bold - -# Because who cares about case!? ---smart-case -``` - -When we use a flag that has a value, we either put the flag and the value on -the same line but delimited by an `=` sign (e.g., `--max-columns=150`), or we -put the flag and the value on two different lines. This is because ripgrep's -argument parser knows to treat the single argument `--max-columns=150` as a -flag with a value, but if we had written `--max-columns 150` in our -configuration file, then ripgrep's argument parser wouldn't know what to do -with it. - -Putting the flag and value on different lines is exactly equivalent and is a -matter of style. - -Comments are encouraged so that you remember what the config is doing. Empty -lines are OK too. - -So let's say you're using the above configuration file, but while you're at a -terminal, you really want to be able to see lines longer than 150 columns. What -do you do? Thankfully, all you need to do is pass `--max-columns 0` (or `-M0` -for short) on the command line, which will override your configuration file's -setting. This works because ripgrep's configuration file is *prepended* to the -explicit arguments you give it on the command line. Since flags given later -override flags given earlier, everything works as expected. This works for most -other flags as well, and each flag's documentation states which other flags -override it. - -If you're confused about what configuration file ripgrep is reading arguments -from, then running ripgrep with the `--debug` flag should help clarify things. -The debug output should note what config file is being loaded and the arugments -that have been read from the configuration. - -Finally, if you want to make absolutely sure that ripgrep *isn't* reading a -configuration file, then you can pass the `--no-config` flag, which will always -prevent ripgrep from reading extraneous configuration from the environment, -regardless of what other methods of configuration are added to ripgrep in the -future. - - -### File encoding - -[Text encoding](https://en.wikipedia.org/wiki/Character_encoding) is a complex -topic, but we can try to summarize its relevancy to ripgrep: - -* Files are generally just a bundle of bytes. There is no reliable way to know - their encoding. -* Either the encoding of the pattern must match the encoding of the files being - searched, or a form of transcoding must be performed converts either the - pattern or the file to the same encoding as the other. -* ripgrep tends to work best on plain text files, and among plain text files, - the most popular encodings likely consist of ASCII, latin1 or UTF-8. As - a special exception, UTF-16 is prevalent in Windows environments - -In light of the above, here is how ripgrep behaves: - -* All input is assumed to be ASCII compatible (which means every byte that - corresponds to an ASCII codepoint actually is an ASCII codepoint). This - includes ASCII itself, latin1 and UTF-8. -* ripgrep works best with UTF-8. For example, ripgrep's regular expression - engine supports Unicode features. Namely, character classes like `\w` will - match all word characters by Unicode's definition and `.` will match any - Unicode codepoint instead of any byte. These constructions assume UTF-8, - so they simply won't match when they come across bytes in a file that aren't - UTF-8. -* To handle the UTF-16 case, ripgrep will do something called "BOM sniffing" - by default. That is, the first three bytes of a file will be read, and if - they correspond to a UTF-16 BOM, then ripgrep will transcode the contents of - the file from UTF-16 to UTF-8, and then execute the search on the transcoded - version of the file. (This incurs a performance penalty since transcoding - is slower than regex searching.) -* To handle other cases, ripgrep provides a `-E/--encoding` flag, which permits - you to specify an encoding from the - [Encoding Standard](https://encoding.spec.whatwg.org/#concept-encoding-get). - ripgrep will assume *all* files searched are the encoding specified and - will perform a transcoding step just like in the UTF-16 case described above. - -By default, ripgrep will not require its input be valid UTF-8. That is, ripgrep -can and will search arbitrary bytes. The key here is that if you're searching -content that isn't UTF-8, then the usefulness of your pattern will degrade. If -you're searching bytes that aren't ASCII compatible, then it's likely the -pattern won't find anything. With all that said, this mode of operation is -important, because it lets you find ASCII or UTF-8 *within* files that are -otherwise arbitrary bytes. - -Finally, it is possible to disable ripgrep's Unicode support from within the -pattern regular expression. For example, let's say you wanted `.` to match any -byte rather than any Unicode codepoint. (You might want this while searching a -binary file, since `.` by default will not match invalid UTF-8.) You could do -this by disabling Unicode via a regular expression flag: - -``` -$ rg '(?-u:.)' -``` - -This works for any part of the pattern. For example, the following will find -any Unicode word character followed by any ASCII word character followed by -another Unicode word character: - -``` -$ rg '\w(?-u:\w)\w' -``` - - -### Common options - -ripgrep has a lot of flags. Too many to keep in your head at once. This section -is intended to give you a sampling of some of the most important and frequently -used options that will likely impact how you use ripgrep on a regular basis. - -* `-h`: Show ripgrep's condensed help output. -* `--help`: Show ripgrep's longer form help output. (Nearly what you'd find in - ripgrep's man page, so pipe it into a pager!) -* `-i/--ignore-case`: When searching for a pattern, ignore case differences. - That is `rg -i fast` matches `fast`, `fASt`, `FAST`, etc. -* `-S/--smart-case`: This is similar to `--ignore-case`, but disables itself - if the pattern contains any uppercase letters. Usually this flag is put into - alias or a config file. -* `-w/--word-regexp`: Require that all matches of the pattern be surrounded - by word boundaries. That is, given `pattern`, the `--word-regexp` flag will - cause ripgrep to behave as if `pattern` were actually `\b(?:pattern)\b`. -* `-c/--count`: Report a count of total matched lines. -* `--files`: Print the files that ripgrep *would* search, but don't actually - search them. -* `-a/--text`: Search binary files as if they were plain text. -* `-z/--search-zip`: Search compressed files (gzip, bzip2, lzma, xz). This is - disabled by default. -* `-C/--context`: Show the lines surrounding a match. -* `--sort-files`: Force ripgrep to sort its output by file name. (This disables - parallelism, so it might be slower.) -* `-L/--follow`: Follow symbolic links while recursively searching. -* `-M/--max-columns`: Limit the length of lines printed by ripgrep. -* `--debug`: Shows ripgrep's debug output. This is useful for understanding - why a particular file might be ignored from search, or what kinds of - configuration ripgrep is loading from the environment. diff --git a/HomebrewFormula b/HomebrewFormula deleted file mode 120000 index 1ffaf04..0000000 --- a/HomebrewFormula +++ /dev/null @@ -1 +0,0 @@ -pkg/brew \ No newline at end of file diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md deleted file mode 100644 index d851750..0000000 --- a/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,53 +0,0 @@ -#### What version of ripgrep are you using? - -Replace this text with the output of `rg --version`. - -#### How did you install ripgrep? - -If you installed ripgrep with snap and are getting strange file permission or -file not found errors, then please do not file a bug. Instead, use one of the -Github binary releases. - -#### What operating system are you using ripgrep on? - -Replace this text with your operating system and version. - -#### Describe your question, feature request, or bug. - -If a question, please describe the problem you're trying to solve and give -as much context as possible. - -If a feature request, please describe the behavior you want and the motivation. -Please also provide an example of how ripgrep would be used if your feature -request were added. - -If a bug, please see below. - -#### If this is a bug, what are the steps to reproduce the behavior? - -If possible, please include both your search patterns and the corpus on which -you are searching. Unless the bug is very obvious, then it is unlikely that it -will be fixed if the ripgrep maintainers cannot reproduce it. - -If the corpus is too big and you cannot decrease its size, file the bug anyway -and the ripgrep maintainers will help figure out next steps. - -#### If this is a bug, what is the actual behavior? - -Show the command you ran and the actual output. Include the `--debug` flag in -your invocation of ripgrep. - -If the output is large, put it in a gist: https://gist.github.com/ - -If the output is small, put it in code fences: - -``` -your -output -goes -here -``` - -#### If this is a bug, what is the expected behavior? - -What do you think ripgrep should have done? diff --git a/README.md b/README.md index eff247a..7317d43 100644 --- a/README.md +++ b/README.md @@ -1,357 +1,86 @@ -ripgrep (rg) ------------- -ripgrep is a line-oriented search tool that recursively searches your current -directory for a regex pattern while respecting your gitignore rules. ripgrep -has first class support on Windows, macOS and Linux, with binary downloads -available for [every release](https://github.com/BurntSushi/ripgrep/releases). -ripgrep is similar to other popular search tools like The Silver Searcher, -ack and grep. +termcolor +========= +A simple cross platform library for writing colored text to a terminal. This +library writes colored text either using standard ANSI escape sequences or +by interacting with the Windows console. Several convenient abstractions +are provided for use in single-threaded or multi-threaded command line +applications. -[![Linux build status](https://travis-ci.org/BurntSushi/ripgrep.svg?branch=master)](https://travis-ci.org/BurntSushi/ripgrep) +[![Linux build status](https://api.travis-ci.org/BurntSushi/ripgrep.png)](https://travis-ci.org/BurntSushi/ripgrep) [![Windows build status](https://ci.appveyor.com/api/projects/status/github/BurntSushi/ripgrep?svg=true)](https://ci.appveyor.com/project/BurntSushi/ripgrep) -[![Crates.io](https://img.shields.io/crates/v/ripgrep.svg)](https://crates.io/crates/ripgrep) +[![](https://img.shields.io/crates/v/termcolor.svg)](https://crates.io/crates/termcolor) Dual-licensed under MIT or the [UNLICENSE](http://unlicense.org). +### Documentation -### CHANGELOG +[https://docs.rs/termcolor](https://docs.rs/termcolor) -Please see the [CHANGELOG](CHANGELOG.md) for a release history. +### Usage -### Documentation quick links +Add this to your `Cargo.toml`: -* [Installation](#installation) -* [User Guide](GUIDE.md) -* [Frequently Asked Questions](FAQ.md) -* [Regex syntax](https://docs.rs/regex/0.2.5/regex/#syntax) -* [Configuration files](GUIDE.md#configuration-file) -* [Shell completions](FAQ.md#complete) -* [Building](#building) - - -### Screenshot of search results - -[![A screenshot of a sample search with ripgrep](http://burntsushi.net/stuff/ripgrep1.png)](http://burntsushi.net/stuff/ripgrep1.png) - - -### Quick examples comparing tools - -This example searches the entire Linux kernel source tree (after running -`make defconfig && make -j8`) for `[A-Z]+_SUSPEND`, where all matches must be -words. Timings were collected on a system with an Intel i7-6900K 3.2 GHz, and -ripgrep was compiled with SIMD enabled. - -Please remember that a single benchmark is never enough! See my -[blog post on ripgrep](http://blog.burntsushi.net/ripgrep/) -for a very detailed comparison with more benchmarks and analysis. - -| Tool | Command | Line count | Time | -| ---- | ------- | ---------- | ---- | -| 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) | `LC_ALL=C git grep -E -n -w '[A-Z]+_SUSPEND'` | 450 | 0.553s | -| [The Silver Searcher](https://github.com/ggreer/the_silver_searcher) | `ag -w '[A-Z]+_SUSPEND'` | 450 | 0.589s | -| [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 | -| [sift](https://github.com/svent/sift) | `sift --git -n -w '[A-Z]+_SUSPEND'` | 450 | 3.505s | -| [ack](https://github.com/petdance/ack2) | `ack -w '[A-Z]+_SUSPEND'` | 1878 | 6.823s | -| [The Platinum Searcher](https://github.com/monochromegane/the_platinum_searcher) | `pt -w -e '[A-Z]+_SUSPEND'` | 450 | 14.208s | - -(Yes, `ack` [has](https://github.com/petdance/ack2/issues/445) a -[bug](https://github.com/petdance/ack2/issues/14).) - -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 | -| ---- | ------- | ---------- | ---- | -| ripgrep | `rg -L -u -tc -n -w '[A-Z]+_SUSPEND'` | 404 | **0.079s** | -| [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'` | 404 | 0.611s | - -(`ucg` [has slightly different behavior in the presence of symbolic links](https://github.com/gvansickle/ucg/issues/106).) - -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 | -| ---- | ------- | ---------- | ---- | -| ripgrep | `rg -w 'Sherlock [A-Z]\w+'` | 5268 | **2.108s** | -| [GNU grep](https://www.gnu.org/software/grep/) | `LC_ALL=C egrep -w 'Sherlock [A-Z]\w+'` | 5268 | 7.014s | - -In the above benchmark, passing the `-n` flag (for showing line numbers) -increases the times to `2.640s` for ripgrep and `10.277s` for GNU grep. - - -### Why should I use ripgrep? - -* It can replace many use cases served by both The Silver Searcher and GNU grep - because it is generally faster than both. (See [the FAQ](FAQ.md#posix4ever) - for more details on whether ripgrep can truly replace grep.) -* Like The Silver Searcher, ripgrep defaults to recursive directory search - and won't search files ignored by your `.gitignore` files. It also ignores - hidden and binary files by default. ripgrep also implements full support - for `.gitignore`, whereas there are many bugs related to that functionality - in The Silver Searcher. -* ripgrep can search specific types of files. For example, `rg -tpy foo` - limits your search to Python files and `rg -Tjs foo` excludes Javascript - files from your search. ripgrep can be taught about new file types with - custom matching rules. -* ripgrep supports many features found in `grep`, such as showing the context - of search results, searching multiple patterns, highlighting matches with - color and full Unicode support. Unlike GNU grep, ripgrep stays fast while - supporting Unicode (which is always on). -* 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 - automatically detecting UTF-16 is provided. Other text encodings must be - specifically specified with the `-E/--encoding` flag.) -* ripgrep supports searching files compressed in a common format (gzip, xz, - lzma or bzip2 current) with the `-z/--search-zip` flag. - -In other words, use ripgrep if you like speed, filtering by default, fewer -bugs, and Unicode support. - - -### Why shouldn't I use ripgrep? - -I'd like to try to convince you why you *shouldn't* use ripgrep. This should -give you a glimpse at some important downsides or missing features of -ripgrep. - -* ripgrep uses a regex engine based on finite automata, so if you want fancy - regex features such as backreferences or lookaround, ripgrep won't provide - them to you. ripgrep does support lots of things though, including, but not - limited to: lazy quantification (e.g., `a+?`), repetitions (e.g., `a{2,5}`), - begin/end assertions (e.g., `^\w+$`), word boundaries (e.g., `\bfoo\b`), and - support for Unicode categories (e.g., `\p{Sc}` to match currency symbols or - `\p{Lu}` to match any uppercase letter). (Fancier regexes will never be - supported.) -* ripgrep doesn't have multiline search. (Will happen as an opt-in feature.) - -In other words, if you like fancy regexes or multiline search, then ripgrep -may not quite meet your needs (yet). - - -### Is it really faster than everything else? - -Generally, yes. A large number of benchmarks with detailed analysis for each is -[available on my blog](http://blog.burntsushi.net/ripgrep/). - -Summarizing, ripgrep is fast because: - -* It is built on top of - [Rust's regex engine](https://github.com/rust-lang-nursery/regex). - Rust's regex engine uses finite automata, SIMD and aggressive literal - optimizations to make searching very fast. -* Rust's regex library maintains performance with full Unicode support by - building UTF-8 decoding directly into its deterministic finite automaton - engine. -* It supports searching with either memory maps or by searching incrementally - with an intermediate buffer. The former is better for single files and the - latter is better for large directories. ripgrep chooses the best searching - strategy for you automatically. -* Applies your ignore patterns in `.gitignore` files using a - [`RegexSet`](https://docs.rs/regex/1.0.0/regex/struct.RegexSet.html). - That means a single file path can be matched against multiple glob patterns - simultaneously. -* It uses a lock-free parallel recursive directory iterator, courtesy of - [`crossbeam`](https://docs.rs/crossbeam) and - [`ignore`](https://docs.rs/ignore). - - -### Feature comparison - -Andy Lester, author of [ack](https://beyondgrep.com/), has published an -excellent table comparing the features of ack, ag, git-grep, GNU grep and -ripgrep: https://beyondgrep.com/feature-comparison/ - - -### Installation - -The binary name for ripgrep is `rg`. - -**[Archives of precompiled binaries for ripgrep are available for Windows, -macOS and Linux.](https://github.com/BurntSushi/ripgrep/releases)** Users of -platforms not explicitly mentioned below are advised to download one of these -archives. - -Linux binaries are static executables. Windows binaries are available either as -built with MinGW (GNU) or with Microsoft Visual C++ (MSVC). When possible, -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) -installed. - -If you're a **macOS Homebrew** or a **Linuxbrew** user, -then you can install ripgrep either -from homebrew-core, (compiled with rust stable, no SIMD): - -``` -$ brew install ripgrep +```toml +[dependencies] +termcolor = "0.3" ``` -or you can install a binary compiled with rust nightly (including SIMD and all -optimizations) by utilizing a custom tap: +and this to your crate root: -``` -$ brew tap burntsushi/ripgrep https://github.com/BurntSushi/ripgrep.git -$ brew install ripgrep-bin +```rust +extern crate termcolor; ``` -If you're a **MacPorts** user, then you can install ripgrep from the -[official ports](https://www.macports.org/ports.php?by=name&substr=ripgrep): +### Organization -``` -$ sudo port install ripgrep +The `WriteColor` trait extends the `io::Write` trait with methods for setting +colors or resetting them. + +`StandardStream` and `StandardStreamLock` both satisfy `WriteColor` and are +analogous to `std::io::Stdout` and `std::io::StdoutLock`, or `std::io::Stderr` +and `std::io::StderrLock`. + +`Buffer` is an in memory buffer that supports colored text. In a parallel +program, each thread might write to its own buffer. A buffer can be printed to +stdout or stderr using a `BufferWriter`. The advantage of this design is that +each thread can work in parallel on a buffer without having to synchronize +access to global resources such as the Windows console. Moreover, this design +also prevents interleaving of buffer output. + +`Ansi` and `NoColor` both satisfy `WriteColor` for arbitrary implementors of +`io::Write`. These types are useful when you know exactly what you need. An +analogous type for the Windows console is not provided since it cannot exist. + +### Example: using `StandardStream` + +The `StandardStream` type in this crate works similarly to `std::io::Stdout`, +except it is augmented with methods for coloring by the `WriteColor` trait. +For example, to write some green text: + +```rust +use std::io::Write; +use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; + +let mut stdout = StandardStream::stdout(ColorChoice::Always); +stdout.set_color(ColorSpec::new().set_fg(Some(Color::Green)))?; +writeln!(&mut stdout, "green text!")?; ``` -If you're a **Windows Chocolatey** user, then you can install ripgrep from the [official repo](https://chocolatey.org/packages/ripgrep): +### Example: using `BufferWriter` +A `BufferWriter` can create buffers and write buffers to stdout or stderr. It +does *not* implement `io::Write` or `WriteColor` itself. Instead, `Buffer` +implements `io::Write` and `termcolor::WriteColor`. + +This example shows how to print some green text to stderr. + +```rust +use std::io::Write; +use termcolor::{BufferWriter, Color, ColorChoice, ColorSpec, WriteColor}; + +let mut bufwtr = BufferWriter::stderr(ColorChoice::Always); +let mut buffer = bufwtr.buffer(); +buffer.set_color(ColorSpec::new().set_fg(Some(Color::Green)))?; +writeln!(&mut buffer, "green text!")?; +bufwtr.print(&buffer)?; ``` -$ choco install ripgrep -``` - -If you're a **Windows Scoop** user, then you can install ripgrep from the [official bucket](https://github.com/lukesampson/scoop/blob/master/bucket/ripgrep.json): - -``` -$ scoop install ripgrep -``` - -If you're an **Arch Linux** user, then you can install ripgrep from the official repos: - -``` -$ pacman -S ripgrep -``` - -If you're a **Gentoo** user, you can install ripgrep from the [official repo](https://packages.gentoo.org/packages/sys-apps/ripgrep): - -``` -$ emerge sys-apps/ripgrep -``` - -If you're a **Fedora 27+** user, you can install ripgrep from official repositories. - -``` -$ sudo dnf install ripgrep -``` - -If you're a **Fedora 24+** user, you can install ripgrep from [copr](https://copr.fedorainfracloud.org/coprs/carlwgeorge/ripgrep/): - -``` -$ sudo dnf copr enable carlwgeorge/ripgrep -$ sudo dnf 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 -``` - -If you're a **RHEL/CentOS 7** user, you can install ripgrep from [copr](https://copr.fedorainfracloud.org/coprs/carlwgeorge/ripgrep/): - -``` -$ sudo yum-config-manager --add-repo=https://copr.fedorainfracloud.org/coprs/carlwgeorge/ripgrep/repo/epel-7/carlwgeorge-ripgrep-epel-7.repo -$ sudo yum install ripgrep -``` - -If you're a **Nix** user, you can install ripgrep from -[nixpkgs](https://github.com/NixOS/nixpkgs/blob/master/pkgs/tools/text/ripgrep/default.nix): - -``` -$ nix-env --install ripgrep -$ # (Or using the attribute name, which is also ripgrep.) -``` - -If you're a **Debian** user (or a user of a Debian derivative like **Ubuntu**), -then ripgrep can be installed using a binary `.deb` file provided in each -[ripgrep release](https://github.com/BurntSushi/ripgrep/releases). Note that -ripgrep is not in the official Debian or Ubuntu repositories. - -``` -$ curl -LO https://github.com/BurntSushi/ripgrep/releases/download/0.8.1/ripgrep_0.8.1_amd64.deb -$ sudo dpkg -i ripgrep_0.8.1_amd64.deb -``` - -(N.B. Various snaps for ripgrep on Ubuntu are also available, but none of them -seem to work right and generate a number of very strange bug reports that I -don't know how to fix and don't have the time to fix. Therefore, it is no -longer a recommended installation option.) - -If you're a **FreeBSD** user, then you can install ripgrep from the [official ports](https://www.freshports.org/textproc/ripgrep/): - -``` -# pkg install ripgrep -``` - -If you're an **OpenBSD** user, then you can install ripgrep from the [official ports](http://openports.se/textproc/ripgrep): - -``` -$ doas pkg_add ripgrep -``` - -If you're a **NetBSD** user, then you can install ripgrep from [pkgsrc](http://pkgsrc.se/textproc/ripgrep): - -``` -# pkgin install ripgrep -``` - -If you're a **Rust programmer**, ripgrep can be installed with `cargo`. -* Note that the minimum supported version of Rust for ripgrep is **1.20**, - although ripgrep may work with older versions. -* Note that the binary may be bigger than expected because it contains debug - symbols. This is intentional. To remove debug symbols and therefore reduce - the file size, run `strip` on the binary. - -``` -$ cargo install ripgrep -``` - -When compiling with Rust 1.27 or newer, this will automatically enable SIMD -optimizations for search. - -ripgrep isn't currently in any other package repositories. -[I'd like to change that](https://github.com/BurntSushi/ripgrep/issues/10). - - -### Building - -ripgrep is written in Rust, so you'll need to grab a -[Rust installation](https://www.rust-lang.org/) in order to compile it. -ripgrep compiles with Rust 1.20 (stable) or newer. Building is easy: - -``` -$ git clone https://github.com/BurntSushi/ripgrep -$ cd ripgrep -$ cargo build --release -$ ./target/release/rg --version -0.1.3 -``` - -If you have a Rust nightly compiler and a recent Intel CPU, then you can enable -additional optional SIMD acceleration like so: - -``` -RUSTFLAGS="-C target-cpu=native" cargo build --release --features 'simd-accel avx-accel' -``` - -If your machine doesn't support AVX instructions, then simply remove -`avx-accel` from the features list. Similarly for SIMD (which corresponds -roughly to SSE instructions). - -The `simd-accel` and `avx-accel` features enable SIMD support in certain -ripgrep dependencies (responsible for counting lines and transcoding). They -are not necessary to get SIMD optimizations for search; those are enabled -automatically. Hopefully, some day, the `simd-accel` and `avx-accel` features -will similarly become unnecessary. - - -### Running tests - -ripgrep is relatively well-tested, including both unit tests and integration -tests. To run the full test suite, use: - -``` -$ cargo test --all -``` - -from the repository root. diff --git a/appveyor.yml b/appveyor.yml index 73626d4..a196efb 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,84 +1,20 @@ -# Inspired from https://github.com/habitat-sh/habitat/blob/master/appveyor.yml -cache: - - c:\cargo\registry - - c:\cargo\git - - c:\projects\ripgrep\target - -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: i686-pc-windows-gnu - CHANNEL: stable - - TARGET: i686-pc-windows-msvc - CHANNEL: stable - - TARGET: x86_64-pc-windows-gnu - CHANNEL: stable - - TARGET: x86_64-pc-windows-msvc - CHANNEL: stable - -matrix: - fast_finish: true - -# Install Rust and Cargo -# (Based on from https://github.com/rust-lang/libc/blob/master/appveyor.yml) + - TARGET: x86_64-pc-windows-msvc + - TARGET: i686-pc-windows-msvc + - TARGET: i686-pc-windows-gnu install: - - curl -sSf -o rustup-init.exe https://win.rustup.rs/ - - rustup-init.exe -y --default-host %TARGET% --no-modify-path - - if defined MSYS2_BITS set PATH=%PATH%;C:\msys64\mingw%MSYS2_BITS%\bin + - ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe" + - rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" + - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin + - SET PATH=%PATH%;C:\MinGW\bin - rustc -V - cargo -V - -# ??? build: false - -# Equivalent to Travis' `script` phase -# TODO modify this phase as you see fit test_script: - - cargo test --verbose --all - -before_deploy: - # Generate artifacts for release - - cargo build --release --features unstable - - 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 'rust-everywhere-v1.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 to use to produce the release artifacts - # NOTE make sure you only release *once* per target - # TODO you may want to pick a different channel - CHANNEL: stable - appveyor_repo_tag: true - + - cargo build --verbose + - cargo test --verbose + - cargo test --verbose --manifest-path wincolor/Cargo.toml branches: only: - - /\d+\.\d+\.\d+/ - master - # - appveyor - # - /\d+\.\d+\.\d+/ - # except: - # - master diff --git a/benchsuite/benchsuite b/benchsuite/benchsuite deleted file mode 100755 index e2587fc..0000000 --- a/benchsuite/benchsuite +++ /dev/null @@ -1,1323 +0,0 @@ -#!/usr/bin/env python3 - -''' -benchsuite is a benchmark runner for comparing command line search tools. -''' - -import argparse -import csv -import os -import os.path as path -from multiprocessing import cpu_count -import re -import shutil -import statistics -import subprocess -import sys -import time - -# Some constants for identifying the corpora we use to run tests. -# We establish two very different kinds of corpora: a small number of large -# files and a large number of small files. These are vastly different use cases -# not only because of their performance characteristics, but also the -# strategies used to increase the relevance of results returned. - -SUBTITLES_DIR = 'subtitles' -SUBTITLES_EN_NAME = 'OpenSubtitles2016.raw.en' -SUBTITLES_EN_NAME_SAMPLE = 'OpenSubtitles2016.raw.sample.en' -SUBTITLES_EN_NAME_GZ = '%s.gz' % SUBTITLES_EN_NAME -SUBTITLES_EN_URL = 'http://opus.lingfil.uu.se/OpenSubtitles2016/mono/OpenSubtitles2016.raw.en.gz' # noqa -SUBTITLES_RU_NAME = 'OpenSubtitles2016.raw.ru' -SUBTITLES_RU_NAME_GZ = '%s.gz' % SUBTITLES_RU_NAME -SUBTITLES_RU_URL = 'http://opus.lingfil.uu.se/OpenSubtitles2016/mono/OpenSubtitles2016.raw.ru.gz' # noqa - -LINUX_DIR = 'linux' -LINUX_CLONE = 'git://github.com/BurntSushi/linux' - -# Grep takes locale settings from the environment. There is a *substantial* -# performance impact for enabling Unicode, so we need to handle this explicitly -# in our benchmarks. -GREP_ASCII = {'LC_ALL': 'C'} -GREP_UNICODE = {'LC_ALL': 'en_US.UTF-8'} - -# Sift tries really hard to search everything by default. In our code search -# benchmarks, we don't want that. -SIFT = [ - 'sift', - '--binary-skip', - '--exclude-files', '.*', - '--exclude-files', '*.pdf', -] - - -def bench_linux_literal_default(suite_dir): - ''' - Benchmark the speed of a literal using *default* settings. - - This is a purposefully unfair benchmark for use in performance - analysis, but it is pedagogically useful to demonstrate how - default behaviors differ. - ''' - require(suite_dir, 'linux') - cwd = path.join(suite_dir, LINUX_DIR) - pat = 'PM_RESUME' - - def mkcmd(*args, **kwargs): - kwargs['cwd'] = cwd - return Command(*args, **kwargs) - - return Benchmark(pattern=pat, commands=[ - mkcmd('rg', ['rg', pat]), - mkcmd('ag', ['ag', pat]), - # ucg reports the exact same matches as ag and rg even though it - # doesn't read gitignore files. Instead, it has a file whitelist - # that happens to match up exactly with the gitignores for this search. - mkcmd('ucg', ['ucg', pat]), - # I guess setting LC_ALL=en_US.UTF-8 probably isn't necessarily the - # default, but I'd guess it to be on most desktop systems. - mkcmd('pt', ['pt', pat]), - # sift reports an extra line here for a binary file matched. - mkcmd('sift', ['sift', pat]), - mkcmd('git grep', ['git', 'grep', pat], env={'LC_ALL': 'en_US.UTF-8'}), - ]) - - -def bench_linux_literal(suite_dir): - ''' - Benchmark the speed of a literal, attempting to be fair. - - This tries to use the minimum set of options available in all tools - to test how fast they are. For example, it makes sure there is - no case insensitive matching and that line numbers are computed - (because some tools don't permit disabling line numbers). - ''' - require(suite_dir, 'linux') - cwd = path.join(suite_dir, LINUX_DIR) - pat = 'PM_RESUME' - - def mkcmd(*args, **kwargs): - kwargs['cwd'] = cwd - return Command(*args, **kwargs) - - return Benchmark(pattern=pat, commands=[ - mkcmd('rg (ignore)', ['rg', '-n', pat]), - mkcmd('rg (ignore) (mmap)', ['rg', '-n', '--mmap', pat]), - mkcmd('ag (ignore) (mmap)', ['ag', '-s', pat]), - mkcmd('pt (ignore)', ['pt', pat]), - mkcmd('sift (ignore)', SIFT + ['-n', '--git', pat]), - mkcmd('git grep (ignore)', [ - 'git', 'grep', '-I', '-n', pat, - ], env={'LC_ALL': 'C'}), - mkcmd('rg (whitelist)', ['rg', '-n', '--no-ignore', '-tall', pat]), - mkcmd('ucg (whitelist)', ['ucg', '--nosmart-case', pat]), - ]) - - -def bench_linux_literal_casei(suite_dir): - ''' - Benchmark the speed of a case insensitive literal search. - - This is like the linux_literal benchmark, except we ask the - search tools to do case insensitive search. - ''' - require(suite_dir, 'linux') - cwd = path.join(suite_dir, LINUX_DIR) - pat = 'PM_RESUME' - - def mkcmd(*args, **kwargs): - kwargs['cwd'] = cwd - return Command(*args, **kwargs) - - return Benchmark(pattern=pat, commands=[ - mkcmd('rg (ignore)', ['rg', '-n', '-i', pat]), - mkcmd('rg (ignore) (mmap)', ['rg', '-n', '-i', '--mmap', pat]), - mkcmd('ag (ignore) (mmap)', ['ag', '-i', pat]), - mkcmd('pt (ignore)', ['pt', '-i', pat]), - mkcmd('sift (ignore)', SIFT + ['-n', '-i', '--git', pat]), - # It'd technically be more appropriate to set LC_ALL=en_US.UTF-8 here, - # since that is certainly what ripgrep is doing, but this is for an - # ASCII literal, so we should give `git grep` all the opportunity to - # do its best. - mkcmd('git grep (ignore)', [ - 'git', 'grep', '-I', '-n', '-i', pat, - ], env={'LC_ALL': 'C'}), - mkcmd('rg (whitelist)', [ - 'rg', '-n', '-i', '--no-ignore', '-tall', pat, - ]), - mkcmd('ucg (whitelist)', ['ucg', '-i', pat]), - ]) - - -def bench_linux_re_literal_suffix(suite_dir): - ''' - Benchmark the speed of a literal inside a regex. - - This, for example, inhibits a prefix byte optimization used - inside of Go's regex engine (relevant for sift and pt). - ''' - require(suite_dir, 'linux') - cwd = path.join(suite_dir, LINUX_DIR) - pat = '[A-Z]+_RESUME' - - def mkcmd(*args, **kwargs): - kwargs['cwd'] = cwd - return Command(*args, **kwargs) - - return Benchmark(pattern=pat, commands=[ - mkcmd('rg (ignore)', ['rg', '-n', pat]), - mkcmd('ag (ignore)', ['ag', '-s', pat]), - mkcmd('pt (ignore)', ['pt', '-e', pat]), - mkcmd('sift (ignore)', SIFT + ['-n', '--git', pat]), - mkcmd( - 'git grep (ignore)', - ['git', 'grep', '-E', '-I', '-n', pat], - env={'LC_ALL': 'C'}, - ), - mkcmd('rg (whitelist)', ['rg', '-n', '--no-ignore', '-tall', pat]), - mkcmd('ucg (whitelist)', ['ucg', '--nosmart-case', pat]), - ]) - - -def bench_linux_word(suite_dir): - ''' - Benchmark use of the -w ("match word") flag in each tool. - - sift has a lot of trouble with this because it forces it into Go's - regex engine by surrounding the pattern with \b assertions. - ''' - require(suite_dir, 'linux') - cwd = path.join(suite_dir, LINUX_DIR) - pat = 'PM_RESUME' - - def mkcmd(*args, **kwargs): - kwargs['cwd'] = cwd - return Command(*args, **kwargs) - - return Benchmark(pattern=pat, commands=[ - mkcmd('rg (ignore)', ['rg', '-n', '-w', pat]), - mkcmd('ag (ignore)', ['ag', '-s', '-w', pat]), - mkcmd('pt (ignore)', ['pt', '-w', pat]), - mkcmd('sift (ignore)', SIFT + ['-n', '-w', '--git', pat]), - mkcmd( - 'git grep (ignore)', - ['git', 'grep', '-E', '-I', '-n', '-w', pat], - env={'LC_ALL': 'C'}, - ), - mkcmd('rg (whitelist)', [ - 'rg', '-n', '-w', '--no-ignore', '-tall', pat, - ]), - mkcmd('ucg (whitelist)', ['ucg', '--nosmart-case', '-w', pat]), - ]) - - -def bench_linux_unicode_greek(suite_dir): - ''' - Benchmark matching of a Unicode category. - - Only three tools (ripgrep, sift and pt) support this. We omit - pt because it is too slow. - ''' - require(suite_dir, 'linux') - cwd = path.join(suite_dir, LINUX_DIR) - pat = r'\p{Greek}' - - def mkcmd(*args, **kwargs): - kwargs['cwd'] = cwd - return Command(*args, **kwargs) - - return Benchmark(pattern=pat, commands=[ - mkcmd('rg', ['rg', '-n', pat]), - mkcmd('pt', ['pt', '-e', pat]), - mkcmd('sift', SIFT + ['-n', '--git', pat]), - ]) - - -def bench_linux_unicode_greek_casei(suite_dir): - ''' - Benchmark matching of a Unicode category, case insensitively. - - Only ripgrep gets this right (and it's still fast). - ''' - require(suite_dir, 'linux') - cwd = path.join(suite_dir, LINUX_DIR) - pat = r'\p{Greek}' - - def mkcmd(*args, **kwargs): - kwargs['cwd'] = cwd - return Command(*args, **kwargs) - - return Benchmark(pattern=pat, commands=[ - mkcmd('rg', ['rg', '-n', '-i', pat]), - mkcmd('pt', ['pt', '-i', '-e', pat]), - mkcmd('sift', SIFT + ['-n', '-i', '--git', pat]), - ]) - - -def bench_linux_unicode_word(suite_dir): - ''' - Benchmark Unicode aware \w character class. - - Only ripgrep and git-grep (with LC_ALL=en_US.UTF-8) actually get - this right. Everything else uses the standard ASCII interpretation - of \w. - ''' - require(suite_dir, 'linux') - cwd = path.join(suite_dir, LINUX_DIR) - pat = r'\wAh' - - def mkcmd(*args, **kwargs): - kwargs['cwd'] = cwd - return Command(*args, **kwargs) - - return Benchmark(pattern=pat, commands=[ - mkcmd('rg (ignore)', ['rg', '-n', pat]), - mkcmd('rg (ignore) (ASCII)', ['rg', '-n', '(?-u)' + pat]), - mkcmd('ag (ignore) (ASCII)', ['ag', '-s', pat]), - mkcmd('pt (ignore) (ASCII)', ['pt', '-e', pat]), - mkcmd('sift (ignore) (ASCII)', SIFT + ['-n', '--git', pat]), - mkcmd( - 'git grep (ignore)', - ['git', 'grep', '-E', '-I', '-n', pat], - env={'LC_ALL': 'en_US.UTF-8'}, - ), - mkcmd( - 'git grep (ignore) (ASCII)', - ['git', 'grep', '-E', '-I', '-n', pat], - env={'LC_ALL': 'C'}, - ), - mkcmd('rg (whitelist)', ['rg', '-n', '--no-ignore', '-tall', pat]), - mkcmd('rg (whitelist) (ASCII)', [ - 'rg', '-n', '--no-ignore', '-tall', '(?-u)' + pat, - ]), - mkcmd('ucg (ASCII)', ['ucg', '--nosmart-case', pat]), - ]) - - -def bench_linux_no_literal(suite_dir): - ''' - Benchmark a regex that defeats all literal optimizations. - - Most search patterns have some kind of literal in them, which - typically permits searches to take some shortcuts. Therefore, the - applicability of this benchmark is somewhat suspicious, but the - suite wouldn't feel complete without it. - ''' - require(suite_dir, 'linux') - cwd = path.join(suite_dir, LINUX_DIR) - pat = r'\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}' - - def mkcmd(*args, **kwargs): - kwargs['cwd'] = cwd - return Command(*args, **kwargs) - - return Benchmark(pattern=pat, commands=[ - mkcmd('rg (ignore)', ['rg', '-n', pat]), - mkcmd('rg (ignore) (ASCII)', ['rg', '-n', '(?-u)' + pat]), - mkcmd('ag (ignore) (ASCII)', ['ag', '-s', pat]), - mkcmd('pt (ignore) (ASCII)', ['pt', '-e', pat]), - mkcmd('sift (ignore) (ASCII)', SIFT + ['-n', '--git', pat]), - mkcmd( - 'git grep (ignore)', - ['git', 'grep', '-E', '-I', '-n', pat], - env={'LC_ALL': 'en_US.UTF-8'}, - ), - mkcmd( - 'git grep (ignore) (ASCII)', - ['git', 'grep', '-E', '-I', '-n', pat], - env={'LC_ALL': 'C'}, - ), - mkcmd('rg (whitelist)', ['rg', '-n', '--no-ignore', '-tall', pat]), - mkcmd('rg (whitelist) (ASCII)', [ - 'rg', '-n', '--no-ignore', '-tall', '(?-u)' + pat, - ]), - mkcmd('ucg (whitelist) (ASCII)', ['ucg', '--nosmart-case', pat]), - ]) - - -def bench_linux_alternates(suite_dir): - ''' - Benchmark a small alternation of literals. - - sift doesn't make the cut. It's more than 10x slower than the next - fastest result. The slowdown is likely because the Go regexp engine - doesn't do any literal optimizations for this case (there is no - common leading byte). - ''' - require(suite_dir, 'linux') - cwd = path.join(suite_dir, LINUX_DIR) - pat = 'ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT' - - def mkcmd(*args, **kwargs): - kwargs['cwd'] = cwd - return Command(*args, **kwargs) - - return Benchmark(pattern=pat, commands=[ - mkcmd('rg (ignore)', ['rg', '-n', pat]), - mkcmd('ag (ignore)', ['ag', '-s', pat]), - mkcmd( - 'git grep (ignore)', - ['git', 'grep', '-E', '-I', '-n', pat], - env={'LC_ALL': 'C'}, - ), - mkcmd('rg (whitelist)', ['rg', '--no-ignore', '-n', pat]), - mkcmd('ucg (whitelist)', ['ucg', '--nosmart-case', pat]), - ]) - - -def bench_linux_alternates_casei(suite_dir): - 'Benchmark a small alternation of literals case insensitively.' - require(suite_dir, 'linux') - cwd = path.join(suite_dir, LINUX_DIR) - pat = 'ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT' - - def mkcmd(*args, **kwargs): - kwargs['cwd'] = cwd - return Command(*args, **kwargs) - - return Benchmark(pattern=pat, commands=[ - mkcmd('rg (ignore)', ['rg', '-n', '-i', pat]), - mkcmd('ag (ignore)', ['ag', '-i', pat]), - mkcmd( - 'git grep (ignore)', - ['git', 'grep', '-E', '-I', '-n', '-i', pat], - env={'LC_ALL': 'C'}, - ), - mkcmd('rg (whitelist)', ['rg', '--no-ignore', '-n', '-i', pat]), - mkcmd('ucg (whitelist)', ['ucg', '-i', pat]), - ]) - - -def bench_subtitles_en_literal(suite_dir): - ''' - Benchmark the speed of an ASCII string literal. - ''' - require(suite_dir, 'subtitles-en') - en = path.join(suite_dir, SUBTITLES_DIR, SUBTITLES_EN_NAME_SAMPLE) - pat = 'Sherlock Holmes' - - return Benchmark(pattern=pat, commands=[ - Command('rg', ['rg', pat, en]), - Command('rg (no mmap)', ['rg', '--no-mmap', pat, en]), - Command('pt', ['pt', '-N', pat, en]), - Command('sift', ['sift', pat, en]), - Command('grep', ['grep', '-a', pat, en], env=GREP_ASCII), - Command('rg (lines)', ['rg', '-n', pat, en]), - Command('ag (lines)', ['ag', '-s', pat, en]), - Command('ucg (lines)', ['ucg', '--nosmart-case', pat, en]), - Command('pt (lines)', ['pt', pat, en]), - Command('sift (lines)', ['sift', '-n', pat, en]), - Command('grep (lines)', ['grep', '-an', pat, en], env=GREP_ASCII), - ]) - - -def bench_subtitles_en_literal_casei(suite_dir): - ''' - Benchmark the speed of a Unicode-y string case insensitively. - ''' - require(suite_dir, 'subtitles-en') - en = path.join(suite_dir, SUBTITLES_DIR, SUBTITLES_EN_NAME_SAMPLE) - pat = 'Sherlock Holmes' - - return Benchmark(pattern=pat, commands=[ - Command('rg', ['rg', '-i', pat, en]), - Command('grep', ['grep', '-ai', pat, en], env=GREP_UNICODE), - Command('grep (ASCII)', [ - 'grep', '-E', '-ai', pat, en, - ], env=GREP_ASCII), - Command('rg (lines)', ['rg', '-n', '-i', pat, en]), - Command('ag (lines) (ASCII)', ['ag', '-i', pat, en]), - Command('ucg (lines) (ASCII)', ['ucg', '-i', pat, en]), - ]) - - -def bench_subtitles_en_literal_word(suite_dir): - ''' - Benchmark the speed of finding a literal inside word boundaries. - ''' - require(suite_dir, 'subtitles-en') - en = path.join(suite_dir, SUBTITLES_DIR, SUBTITLES_EN_NAME_SAMPLE) - pat = 'Sherlock Holmes' - - return Benchmark(pattern=pat, commands=[ - Command('rg (ASCII)', [ - 'rg', '-n', r'(?-u:\b)' + pat + r'(?-u:\b)', en, - ]), - Command('ag (ASCII)', ['ag', '-sw', pat, en]), - Command('ucg (ASCII)', ['ucg', '--nosmart-case', pat, en]), - Command('grep (ASCII)', [ - 'grep', '-anw', pat, en, - ], env=GREP_ASCII), - Command('rg', ['rg', '-nw', pat, en]), - Command('grep', ['grep', '-anw', pat, en], env=GREP_UNICODE), - ]) - - -def bench_subtitles_en_alternate(suite_dir): - ''' - Benchmark the speed of a set of alternate literals. - ''' - require(suite_dir, 'subtitles-en') - en = path.join(suite_dir, SUBTITLES_DIR, SUBTITLES_EN_NAME_SAMPLE) - pat = '|'.join([ - 'Sherlock Holmes', - 'John Watson', - 'Irene Adler', - 'Inspector Lestrade', - 'Professor Moriarty', - ]) - - return Benchmark(pattern=pat, commands=[ - Command('rg (lines)', ['rg', '-n', pat, en]), - Command('ag (lines)', ['ag', '-s', pat, en]), - Command('ucg (lines)', ['ucg', '--nosmart-case', pat, en]), - Command('grep (lines)', [ - 'grep', '-E', '-an', pat, en, - ], env=GREP_ASCII), - Command('rg', ['rg', pat, en]), - Command('grep', [ - 'grep', '-E', '-a', pat, en, - ], env=GREP_ASCII), - ]) - - -def bench_subtitles_en_alternate_casei(suite_dir): - ''' - Benchmark the speed of a set of alternate literals. - ''' - require(suite_dir, 'subtitles-en') - en = path.join(suite_dir, SUBTITLES_DIR, SUBTITLES_EN_NAME_SAMPLE) - pat = '|'.join([ - 'Sherlock Holmes', - 'John Watson', - 'Irene Adler', - 'Inspector Lestrade', - 'Professor Moriarty', - ]) - - return Benchmark(pattern=pat, commands=[ - Command('ag (ASCII)', ['ag', '-s', '-i', pat, en]), - Command('ucg (ASCII)', ['ucg', '-i', pat, en]), - Command('grep (ASCII)', [ - 'grep', '-E', '-ani', pat, en, - ], env=GREP_ASCII), - Command('rg', ['rg', '-n', '-i', pat, en]), - Command('grep', ['grep', '-E', '-ani', pat, en], env=GREP_UNICODE), - ]) - - -def bench_subtitles_en_surrounding_words(suite_dir): - ''' - Benchmark a more complex regex with an inner literal. - ''' - require(suite_dir, 'subtitles-en') - en = path.join(suite_dir, SUBTITLES_DIR, SUBTITLES_EN_NAME_SAMPLE) - pat = r'\w+\s+Holmes\s+\w+' - - return Benchmark(pattern=pat, commands=[ - Command('rg', ['rg', '-n', pat, en]), - Command('grep', ['grep', '-E', '-an', pat, en], env=GREP_UNICODE), - Command('rg (ASCII)', ['rg', '-n', '(?-u)' + pat, en]), - Command('ag (ASCII)', ['ag', '-s', pat, en]), - Command('ucg (ASCII)', ['ucg', '--nosmart-case', pat, en]), - Command('grep (ASCII)', [ - 'grep', '-E', '-an', pat, en, - ], env=GREP_ASCII), - ]) - - -def bench_subtitles_en_no_literal(suite_dir): - ''' - Benchmark the speed of a regex with no literals. - - Note that we don't even try to run grep with Unicode support - on this one. While it should eventually get the right answer, - I killed it after it had already been running for two minutes - and showed no signs of finishing soon. - ''' - require(suite_dir, 'subtitles-en') - en = path.join(suite_dir, SUBTITLES_DIR, SUBTITLES_EN_NAME_SAMPLE) - pat = r'\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}' - - return Benchmark(pattern=pat, commands=[ - Command('rg', ['rg', '-n', pat, en]), - Command('rg (ASCII)', ['rg', '-n', '(?-u)' + pat, en]), - Command('ag (ASCII)', ['ag', '-s', pat, en]), - Command('ucg (ASCII)', ['ucg', '--nosmart-case', pat, en]), - Command('grep (ASCII)', [ - 'grep', '-E', '-an', pat, en, - ], env=GREP_ASCII), - ]) - - -def bench_subtitles_ru_literal(suite_dir): - ''' - Benchmark the speed of a Unicode-y string literal. - ''' - require(suite_dir, 'subtitles-ru') - ru = path.join(suite_dir, SUBTITLES_DIR, SUBTITLES_RU_NAME) - pat = 'Шерлок Холмс' # Sherlock Holmes - - return Benchmark(pattern=pat, commands=[ - Command('rg', ['rg', pat, ru]), - Command('rg (no mmap)', ['rg', '--no-mmap', pat, ru]), - Command('pt', ['pt', '-N', pat, ru]), - Command('sift', ['sift', pat, ru]), - Command('grep', ['grep', '-a', pat, ru], env=GREP_ASCII), - Command('rg (lines)', ['rg', '-n', pat, ru]), - Command('ag (lines)', ['ag', '-s', pat, ru]), - Command('ucg (lines)', ['ucg', '--nosmart-case', pat, ru]), - Command('pt (lines)', ['pt', pat, ru]), - Command('sift (lines)', ['sift', '-n', pat, ru]), - Command('grep (lines)', ['grep', '-an', pat, ru], env=GREP_ASCII), - ]) - - -def bench_subtitles_ru_literal_casei(suite_dir): - ''' - Benchmark the speed of a Unicode-y string case insensitively. - ''' - require(suite_dir, 'subtitles-ru') - ru = path.join(suite_dir, SUBTITLES_DIR, SUBTITLES_RU_NAME) - pat = 'Шерлок Холмс' # Sherlock Holmes - - return Benchmark(pattern=pat, commands=[ - Command('rg', ['rg', '-i', pat, ru]), - Command('grep', ['grep', '-ai', pat, ru], env=GREP_UNICODE), - Command('grep (ASCII)', [ - 'grep', '-E', '-ai', pat, ru, - ], env=GREP_ASCII), - Command('rg (lines)', ['rg', '-n', '-i', pat, ru]), - Command('ag (lines) (ASCII)', ['ag', '-i', pat, ru]), - Command('ucg (lines) (ASCII)', ['ucg', '-i', pat, ru]), - ]) - - -def bench_subtitles_ru_literal_word(suite_dir): - ''' - Benchmark the speed of finding a literal inside word boundaries. - ''' - require(suite_dir, 'subtitles-ru') - ru = path.join(suite_dir, SUBTITLES_DIR, SUBTITLES_RU_NAME) - pat = 'Шерлок Холмс' # Sherlock Holmes - - return Benchmark(pattern=pat, commands=[ - Command('rg (ASCII)', [ - 'rg', '-n', r'(?-u:\b)' + pat + r'(?-u:\b)', ru, - ]), - Command('ag (ASCII)', ['ag', '-sw', pat, ru]), - Command('ucg (ASCII)', ['ucg', '--nosmart-case', pat, ru]), - Command('grep (ASCII)', [ - 'grep', '-anw', pat, ru, - ], env=GREP_ASCII), - Command('rg', ['rg', '-nw', pat, ru]), - Command('grep', ['grep', '-anw', pat, ru], env=GREP_UNICODE), - ]) - - -def bench_subtitles_ru_alternate(suite_dir): - ''' - Benchmark the speed of a set of alternate literals. - ''' - require(suite_dir, 'subtitles-ru') - ru = path.join(suite_dir, SUBTITLES_DIR, SUBTITLES_RU_NAME) - pat = '|'.join([ - 'Шерлок Холмс', # Sherlock Holmes - 'Джон Уотсон', # John Watson - 'Ирен Адлер', # Irene Adler - 'инспектор Лестрейд', # Inspector Lestrade - 'профессор Мориарти', # Professor Moriarty - ]) - - return Benchmark(pattern=pat, commands=[ - Command('rg (lines)', ['rg', '-n', pat, ru]), - Command('ag (lines)', ['ag', '-s', pat, ru]), - Command('ucg (lines)', ['ucg', '--nosmart-case', pat, ru]), - Command('grep (lines)', [ - 'grep', '-E', '-an', pat, ru, - ], env=GREP_ASCII), - Command('rg', ['rg', pat, ru]), - Command('grep', [ - 'grep', '-E', '-a', pat, ru, - ], env=GREP_ASCII), - ]) - - -def bench_subtitles_ru_alternate_casei(suite_dir): - ''' - Benchmark the speed of a set of alternate literals. - ''' - require(suite_dir, 'subtitles-ru') - ru = path.join(suite_dir, SUBTITLES_DIR, SUBTITLES_RU_NAME) - pat = '|'.join([ - 'Шерлок Холмс', # Sherlock Holmes - 'Джон Уотсон', # John Watson - 'Ирен Адлер', # Irene Adler - 'инспектор Лестрейд', # Inspector Lestrade - 'профессор Мориарти', # Professor Moriarty - ]) - - return Benchmark(pattern=pat, commands=[ - Command('ag (ASCII)', ['ag', '-s', '-i', pat, ru]), - Command('ucg (ASCII)', ['ucg', '-i', pat, ru]), - Command('grep (ASCII)', [ - 'grep', '-E', '-ani', pat, ru, - ], env=GREP_ASCII), - Command('rg', ['rg', '-n', '-i', pat, ru]), - Command('grep', ['grep', '-E', '-ani', pat, ru], env=GREP_UNICODE), - ]) - - -def bench_subtitles_ru_surrounding_words(suite_dir): - ''' - Benchmark a more complex regex with an inner literal. - ''' - require(suite_dir, 'subtitles-en') - ru = path.join(suite_dir, SUBTITLES_DIR, SUBTITLES_RU_NAME) - pat = r'\w+\s+Холмс\s+\w+' - - return Benchmark(pattern=pat, commands=[ - Command('rg', ['rg', '-n', pat, ru]), - Command('grep', ['grep', '-E', '-an', pat, ru], env=GREP_UNICODE), - Command('ag (ASCII)', ['ag', '-s', pat, ru]), - Command('ucg (ASCII)', ['ucg', '--nosmart-case', pat, ru]), - Command('grep (ASCII)', [ - 'grep', '-E', '-an', pat, ru, - ], env=GREP_ASCII), - ]) - - -def bench_subtitles_ru_no_literal(suite_dir): - ''' - Benchmark the speed of a regex with no literals. - - Note that we don't even try to run grep with Unicode support - on this one. While it should eventually get the right answer, - I killed it after it had already been running for two minutes - and showed no signs of finishing soon. - ''' - require(suite_dir, 'subtitles-ru') - ru = path.join(suite_dir, SUBTITLES_DIR, SUBTITLES_RU_NAME) - pat = r'\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}' - - return Benchmark(pattern=pat, commands=[ - Command('rg', ['rg', '-n', pat, ru]), - Command('rg (ASCII)', ['rg', '-n', '(?-u)' + pat, ru]), - Command('ag (ASCII)', ['ag', '-s', pat, ru]), - Command('ucg (ASCII)', ['ucg', '--nosmart-case', pat, ru]), - Command('grep (ASCII)', [ - 'grep', '-E', '-an', pat, ru, - ], env=GREP_ASCII), - ]) - - -class MissingDependencies(Exception): - ''' - A missing dependency exception. - - This exception occurs when running a benchmark that requires a - particular corpus that isn't available. - - :ivar list(str) missing_names: - A list of missing dependency names. These names correspond to - names that can be used with the --download flag. - ''' - def __init__(self, missing_names): - self.missing_names = missing_names - - def __str__(self): - return 'MissingDependency(%s)' % repr(self.missing_names) - - -class MissingCommands(Exception): - ''' - A missing command exception. - - This exception occurs when running a command in a benchmark - where the command could not be found on the current system. - - :ivar list(str) missing_names: - The names of the command binaries that could not be found. - ''' - def __init__(self, missing_names): - self.missing_names = sorted(set(missing_names)) - - def __str__(self): - return 'MissingCommands(%s)' % repr(self.missing_names) - - -class Benchmark(object): - ''' - A single benchmark corresponding to a grouping of commands. - - The main purpose of a benchmark is to compare the performance - characteristics of a group of commands. - ''' - - def __init__(self, name=None, pattern=None, commands=None, - warmup_count=1, count=3, line_count=True, - allow_missing_commands=False, - disabled_cmds=None): - ''' - Create a single benchmark. - - A single benchmark is composed of a set of commands that are - benchmarked and compared against one another. A benchmark may - have multiple commands that use the same search tool (but - probably should have something differentiating them). - - The grouping of commands is a purely human driven process. - - By default, the output of every command is sent to /dev/null. - Other types of behavior are available via the methods defined - on this benchmark. - - :param str name: - A human readable string denoting the name of this - benchmark. - :param str pattern: - The pattern that is used in search. - :param list(Command) commands: - A list of commands to initialize this benchmark with. More - commands may be added before running the benchmark. - :param int warmup_count: - The number of times to run each command before recording - samples. - :param int count: - The number of samples to collect from each command. - :param bool line_count: - When set, the lines of each search are counted and included - in the samples produced. - :param bool allow_missing_commands: - When set, if a command is missing, then the benchmark - will simply skip it. - :param list(str) disabled_cmds: - A list of commands to skip. - ''' - self.name = name - self.pattern = pattern - self.commands = commands or [] - self.warmup_count = warmup_count - self.count = count - self.line_count = line_count - self.allow_missing_commands = allow_missing_commands - self.disabled_cmds = set(disabled_cmds or []) - - def raise_if_missing(self): - ''' - Raises a MissingCommands exception if applicable. - - A MissingCommands exception is raised when the following - criteria are met: 1) allow_missing_commands is False, and 2) at - least one command in this benchmark could not be found on this - system. - ''' - missing_commands = [] - for c in self.commands: - if c.binary_name in self.disabled_cmds or c.exists(): - continue - missing_commands.append(c.binary_name) - if not self.allow_missing_commands and len(missing_commands) > 0: - raise MissingCommands(missing_commands) - - def run(self): - ''' - Runs this benchmark and returns the results. - - :rtype: Result - :raises: - MissingCommands if any command doesn't exist. - (Unless allow_missing_commands is enabled.) - ''' - self.raise_if_missing() - result = Result(self) - for cmd in self.commands: - if cmd.binary_name in self.disabled_cmds: - continue - if self.allow_missing_commands and not cmd.exists(): - # Skip this command if we're OK with it. - continue - # Do a warmup first. - for _ in range(self.warmup_count): - self.run_one(cmd) - for _ in range(self.count): - result.add(cmd, **self.run_one(cmd)) - return result - - def run_one(self, cmd): - ''' - Runs the given command exactly once. - - Returns an object that includes the time taken by the command. - If this benchmark was configured to count the number of lines - returned, then the line count is also returned. - - :param Command cmd: The command to run. - :returns: - A dict with two fields, duration and line_count. - The duration is in seconds, with fractional milliseconds, - and is guaranteed to be available. The line_count is set - to None unless line counting is enabled, in which case, - it is the number of lines in the search output. - :rtype: int - ''' - if not cmd.exists(): - raise MissingCommands([cmd.cmd[0]]) - cmd.kwargs['stderr'] = subprocess.DEVNULL - if self.line_count: - cmd.kwargs['stdout'] = subprocess.PIPE - else: - cmd.kwargs['stdout'] = subprocess.DEVNULL - - start = time.time() - completed = cmd.run() - end = time.time() - - line_count = None - if self.line_count: - line_count = completed.stdout.count(b'\n') - return { - 'duration': end - start, - 'line_count': line_count, - } - - -class Result(object): - ''' - The result of running a benchmark. - - Benchmark results consist of a set of samples, where each sample - corresponds to a single run of a single command in the benchmark. - Various statistics can be computed from these samples such as mean - and standard deviation. - ''' - def __init__(self, benchmark): - ''' - Create a new set of results, initially empty. - - :param Benchmarl benchmark: - The benchmark that produced these results. - ''' - self.benchmark = benchmark - self.samples = [] - - def add(self, cmd, duration, line_count=None): - ''' - Add a new sample to this result set. - - :param Command cmd: - The command that produced this sample. - :param int duration: - The duration, in milliseconds, that the command took to - run. - :param int line_count: - The number of lines in the search output. This is optional. - ''' - self.samples.append({ - 'cmd': cmd, - 'duration': duration, - 'line_count': line_count, - }) - - def fastest_sample(self): - ''' - Returns the fastest recorded sample. - ''' - return min(self.samples, key=lambda s: s['duration']) - - def fastest_cmd(self): - ''' - Returns the fastest command according to distribution. - ''' - means = [] - for cmd in self.benchmark.commands: - mean, _ = self.distribution_for(cmd) - if mean is None: - continue - means.append((cmd, mean)) - return min(means, key=lambda tup: tup[1])[0] - - def samples_for(self, cmd): - 'Returns an iterable of samples for cmd' - yield from (s for s in self.samples if s['cmd'].name == cmd.name) - - def line_counts_for(self, cmd): - ''' - Returns the line counts recorded for each command. - - :returns: - A dictionary from command name to a set of line - counts recorded. - ''' - return {s['line_count'] - for s in self.samples_for(cmd) - if s['line_count'] is not None} - - def distribution_for(self, cmd): - ''' - Returns the distribution (mean +/- std) of the given command. - - If there are no samples for this command (i.e., it was skipped), - then return ``(None, None)``. - - :rtype: (float, float) - :returns: - A tuple containing the mean and standard deviation, in that - order. - ''' - samples = list(s['duration'] for s in self.samples_for(cmd)) - if len(samples) == 0: - return None, None - return statistics.mean(samples), statistics.stdev(samples) - - -class Command(object): - def __init__(self, name, cmd, *args, **kwargs): - ''' - Create a new command that is run as part of a benchmark. - - *args and **kwargs are passed directly to ``subprocess.run``. - An exception to this is stdin/stdout/stderr. Output - redirection is completely controlled by the benchmark harness. - Trying to set them here will trigger an assert. - - :param str name: - The human readable name of this command. This is - particularly useful if the same search tool is used - multiple times in the same benchmark with different - arguments. - :param list(str) cmd: - The command to run as a list of arguments (including the - command name itself). - ''' - assert 'stdin' not in kwargs - assert 'stdout' not in kwargs - assert 'stderr' not in kwargs - self.name = name - self.cmd = cmd - self.args = args - self.kwargs = kwargs - - def exists(self): - 'Returns true if and only if this command exists.' - return shutil.which(self.binary_name) is not None - - @property - def binary_name(self): - 'Return the binary name of this command.' - return self.cmd[0] - - def run(self): - ''' - Runs this command and returns its status. - - :rtype: subprocess.CompletedProcess - ''' - return subprocess.run(self.cmd, *self.args, **self.kwargs) - - -def eprint(*args, **kwargs): - 'Like print, but to stderr.' - kwargs['file'] = sys.stderr - print(*args, **kwargs) - - -def run_cmd(cmd, *args, **kwargs): - ''' - Print the command to stderr and run it. - - If the command fails, throw a traceback. - ''' - eprint('# %s' % ' '.join(cmd)) - kwargs['check'] = True - return subprocess.run(cmd, *args, **kwargs) - - -def require(suite_dir, *names): - ''' - Declare a dependency on the given names for a benchmark. - - If any dependency doesn't exist, then fail with an error message. - ''' - errs = [] - for name in names: - fun_name = name.replace('-', '_') - if not globals()['has_%s' % fun_name](suite_dir): - errs.append(name) - if len(errs) > 0: - raise MissingDependencies(errs) - - -def download_linux(suite_dir): - 'Download and build the Linux kernel.' - checkout_dir = path.join(suite_dir, LINUX_DIR) - if not os.path.isdir(checkout_dir): - # Clone from my fork so that we always get the same corpus *and* still - # do a shallow clone. Shallow clones are much much cheaper than full - # clones. - run_cmd(['git', 'clone', '--depth', '1', LINUX_CLONE, checkout_dir]) - # We want to build the kernel because the process of building it produces - # a lot of junk in the repository that a search tool probably shouldn't - # touch. - if not os.path.exists(path.join(checkout_dir, 'vmlinux')): - eprint('# Building Linux kernel...') - run_cmd(['make', 'defconfig'], cwd=checkout_dir) - run_cmd(['make', '-j', str(cpu_count())], cwd=checkout_dir) - - -def has_linux(suite_dir): - 'Returns true if we believe the Linux kernel is built.' - checkout_dir = path.join(suite_dir, LINUX_DIR) - return path.exists(path.join(checkout_dir, 'vmlinux')) - - -def download_subtitles_en(suite_dir): - 'Download and decompress English subtitles.' - subtitle_dir = path.join(suite_dir, SUBTITLES_DIR) - en_path_gz = path.join(subtitle_dir, SUBTITLES_EN_NAME_GZ) - en_path = path.join(subtitle_dir, SUBTITLES_EN_NAME) - en_path_sample = path.join(subtitle_dir, SUBTITLES_EN_NAME_SAMPLE) - - if not os.path.isdir(subtitle_dir): - os.makedirs(subtitle_dir) - if not os.path.exists(en_path): - if not os.path.exists(en_path_gz): - run_cmd(['curl', '-LO', SUBTITLES_EN_URL], cwd=subtitle_dir) - run_cmd(['gunzip', en_path_gz]) - if not os.path.exists(en_path_sample): - # Get a sample roughly the same size as the Russian corpus so that - # benchmarks finish in a reasonable time. - with open(path.join(subtitle_dir, en_path_sample), 'wb+') as f: - run_cmd( - ['head', '-n', '32722372', en_path], - cwd=subtitle_dir, stdout=f) - - -def has_subtitles_en(suite_dir): - 'Returns true if English subtitles have been downloaded.' - subtitle_dir = path.join(suite_dir, SUBTITLES_DIR) - return path.exists(path.join(subtitle_dir, SUBTITLES_EN_NAME_SAMPLE)) - - -def download_subtitles_ru(suite_dir): - 'Download and decompress Russian subtitles.' - subtitle_dir = path.join(suite_dir, SUBTITLES_DIR) - ru_path_gz = path.join(subtitle_dir, SUBTITLES_RU_NAME_GZ) - ru_path = path.join(subtitle_dir, SUBTITLES_RU_NAME) - - if not os.path.isdir(subtitle_dir): - os.makedirs(subtitle_dir) - if not os.path.exists(ru_path): - if not os.path.exists(ru_path_gz): - run_cmd(['curl', '-LO', SUBTITLES_RU_URL], cwd=subtitle_dir) - run_cmd(['gunzip', ru_path_gz]) - - -def has_subtitles_ru(suite_dir): - 'Returns true if Russian subtitles have been downloaded.' - subtitle_dir = path.join(suite_dir, SUBTITLES_DIR) - return path.exists(path.join(subtitle_dir, SUBTITLES_RU_NAME)) - - -def download(suite_dir, choices): - ''' - Download choices into suite_dir. - - Specifically, choices specifies a list of corpora to fetch. - - :param str suite_dir: - The directory in which to download corpora. - :param list(str) choices: - A list of corpora to download. Available choices are: - all, linux, subtitles-en, subtitles-ru. - ''' - for choice in choices: - if choice == 'linux': - download_linux(suite_dir) - elif choice == 'subtitles-en': - download_subtitles_en(suite_dir) - elif choice == 'subtitles-ru': - download_subtitles_ru(suite_dir) - elif choice == 'all': - download_linux(suite_dir) - download_subtitles_en(suite_dir) - download_subtitles_ru(suite_dir) - else: - eprint('Unrecognized download choice: %s' % choice) - sys.exit(1) - - -def collect_benchmarks(suite_dir, filter_pat=None, - allow_missing_commands=False, - disabled_cmds=None, - warmup_iter=1, bench_iter=3): - ''' - Return an iterable of all runnable benchmarks. - - :param str suite_dir: - The directory containing corpora. - :param str filter_pat: - A single regular expression that is used to filter benchmarks - by their name. When not specified, all benchmarks are run. - :returns: - An iterable over all runnable benchmarks. If a benchmark - requires corpora that are missing, then a log message is - emitted to stderr and it is not yielded. - ''' - for fun in sorted(globals()): - if not fun.startswith('bench_'): - continue - name = re.sub('^bench_', '', fun) - if filter_pat is not None and not re.search(filter_pat, name): - continue - try: - benchmark = globals()[fun](suite_dir) - benchmark.name = name - benchmark.warmup_count = warmup_iter - benchmark.count = bench_iter - benchmark.allow_missing_commands = allow_missing_commands - benchmark.disabled_cmds = disabled_cmds - benchmark.raise_if_missing() - except MissingDependencies as e: - eprint( - 'missing: %s, skipping benchmark %s (try running with: %s)' % ( - ', '.join(e.missing_names), - name, - ' '.join(['--download %s' % n for n in e.missing_names]), - )) - continue - except MissingCommands as e: - fmt = 'missing commands: %s, skipping benchmark %s ' \ - '(run with --allow-missing to run incomplete benchmarks)' - eprint(fmt % (', '.join(e.missing_names), name)) - continue - yield benchmark - - -def main(): - download_choices = ['all', 'linux', 'subtitles-en', 'subtitles-ru'] - p = argparse.ArgumentParser('Command line search tool benchmark suite.') - p.add_argument( - '--dir', metavar='PATH', default=os.getcwd(), - help='The directory in which to download data and perform searches.') - p.add_argument( - '--download', metavar='CORPUS', action='append', - choices=download_choices, - help='Download and prepare corpus data, then exit without running ' - 'any benchmarks. Note that this command is intended to be ' - 'idempotent. WARNING: This downloads over a gigabyte of data, ' - 'and also includes building the Linux kernel. If "all" is used ' - 'then the total uncompressed size is around 13 GB. ' - 'Choices: %s' % ', '.join(download_choices)) - p.add_argument( - '--allow-missing', action='store_true', - help='Permit benchmarks to run even if some commands are missing.') - p.add_argument( - '--disabled', help='A list of comma separated commands to skip.') - p.add_argument( - '-f', '--force', action='store_true', - help='Overwrite existing files if there is a conflict.') - p.add_argument( - '--list', action='store_true', - help='List available benchmarks by name.') - p.add_argument( - '--raw', metavar='PATH', - help='Dump raw data (all samples collected) in CSV format to the ' - 'file path provided.') - p.add_argument( - '--warmup-iter', metavar='INTEGER', type=int, default=1, - help='The number of iterations to run each command before ' - 'recording measurements.') - p.add_argument( - '--bench-iter', metavar='INTEGER', type=int, default=3, - help='The number of iterations to run each command while ' - 'recording measurements.') - p.add_argument( - 'bench', metavar='PAT', nargs='?', - help='A regex pattern that will only run benchmarks that match.') - args = p.parse_args() - - if args.list: - benchmarks = collect_benchmarks( - args.dir, filter_pat=args.bench, - allow_missing_commands=args.allow_missing, - disabled_cmds=(args.disabled or '').split(','), - warmup_iter=args.warmup_iter, bench_iter=args.bench_iter) - for b in benchmarks: - print(b.name) - sys.exit(0) - if args.download is not None and len(args.download) > 0: - download(args.dir, args.download) - sys.exit(0) - - if not path.isdir(args.dir): - os.makedirs(args.dir) - if args.raw is not None and path.exists(args.raw) and not args.force: - eprint('File %s already exists (delete it or use --force)' % args.raw) - sys.exit(1) - raw_handle, raw_csv_wtr = None, None - if args.raw is not None: - fields = [ - 'benchmark', 'warmup_iter', 'iter', - 'name', 'command', 'duration', 'lines', 'env', - ] - raw_handle = open(args.raw, 'w+') - raw_csv_wtr = csv.DictWriter(raw_handle, fields) - raw_csv_wtr.writerow({x: x for x in fields}) - - benchmarks = collect_benchmarks( - args.dir, filter_pat=args.bench, - allow_missing_commands=args.allow_missing, - disabled_cmds=(args.disabled or '').split(','), - warmup_iter=args.warmup_iter, bench_iter=args.bench_iter) - for i, b in enumerate(benchmarks): - result = b.run() - fastest_cmd = result.fastest_cmd() - fastest_sample = result.fastest_sample() - max_name_len = max(len(cmd.name) for cmd in b.commands) - - if i > 0: - print() - header = '%s (pattern: %s)' % (b.name, b.pattern) - print('%s\n%s' % (header, '-' * len(header))) - for cmd in b.commands: - name = cmd.name - mean, stdev = result.distribution_for(cmd) - if mean is None: - # If we couldn't get a distribution for this command then - # it was skipped. - continue - line_counts = result.line_counts_for(cmd) - show_fast_cmd, show_line_counts = '', '' - if fastest_cmd.name == cmd.name: - show_fast_cmd = '*' - if fastest_sample['cmd'].name == cmd.name: - name += '*' - if len(line_counts) > 0: - counts = map(str, line_counts) - show_line_counts = ' (lines: %s)' % ', '.join(counts) - fmt = '{name:{pad}} {mean:0.3f} +/- {stdev:0.3f}{lines}{fast_cmd}' - print(fmt.format( - name=name, pad=max_name_len + 2, fast_cmd=show_fast_cmd, - mean=mean, stdev=stdev, lines=show_line_counts)) - sys.stdout.flush() - - if raw_csv_wtr is not None: - for sample in result.samples: - cmd, duration = sample['cmd'], sample['duration'] - env = ' '.join(['%s=%s' % (k, v) - for k, v in cmd.kwargs.get('env', {}).items()]) - raw_csv_wtr.writerow({ - 'benchmark': b.name, - 'warmup_iter': b.warmup_count, - 'iter': b.count, - 'name': sample['cmd'].name, - 'command': ' '.join(cmd.cmd), - 'duration': duration, - 'lines': sample['line_count'] or '', - 'env': env, - }) - raw_handle.flush() - - -if __name__ == '__main__': - main() diff --git a/benchsuite/runs/2016-09-17-ubuntu1604-ec2/README.SETUP b/benchsuite/runs/2016-09-17-ubuntu1604-ec2/README.SETUP deleted file mode 100644 index f4098b7..0000000 --- a/benchsuite/runs/2016-09-17-ubuntu1604-ec2/README.SETUP +++ /dev/null @@ -1,93 +0,0 @@ -Ubuntu 16.04 HVM AMI -c3.2xlarge, Xeon E5-2680, 2.8 GHz, 8 CPUs, 16 GB memory, 80 GB SSD - -# Generic system setup - -mkfs.ext4 /dev/xvdb -sudo mount /dev/xvdb /mnt -sudo chown ubuntu /mnt -sudo apt-get update -sudo apt-get install \ # for building Linux kernel - make gcc bc -sudo apt-get install \ # for the silver searcher - automake pkg-config zlib1g-dev liblzma-dev libpcre3 libpcre3-dev -sudo apt-get install \ # for Universal Code Grep - libtool libpcre2-8-0 libpcre2-dev -sudo apt-get install \ # for sift and the platinum searcher - go - -# Get benchmark corpora - -cd /mnt -mkdir /mnt/bench -git clone git://github.com/BurntSushi/ripgrep -cd ripgrep/benchsuite -./benchsuite --dir /mnt/bench/ --download all # takes around 15 minutes - -# Install search tools -mkdir /mnt/bin/ - -## ripgrep - -cd /mnt -mkdir ripgrep-bin -cd ripgrep-bin -curl -LO 'https://github.com/BurntSushi/ripgrep/releases/download/0.1.2/ripgrep-0.1.2-x86_64-unknown-linux-musl.tar.gz' -cp ripgrep-0.1.2-x86_64-unknown-linux-musl/rg /mnt/bin/ - -## The Silver Searcher - -cd /mnt -git clone git://github.com/ggreer/the_silver_searcher -cd the_silver_searcher -git checkout cda635 -./build.sh -cp ag /mnt/bin/ - -## Universal Code Grep - -cd /mnt -git clone git://github.com/gvansickle/ucg -cd ucg -git checkout 487bfb -autoreconf -i -./configure -make -cp ucg /mnt/bin/ - -## The Platinum Searcher - -export GOPATH=/mnt/go -go get github.com/monochromegane/the_platinum_searcher -cd /mnt/go/src/github.com/monochromegane/the_platinum_searcher -git checkout 509368 -go install github.com/monochromegane/the_platinum_searcher/cmd/... -cp /mnt/go/bin/pt /mnt/bin/ - -## Sift - -export GOPATH=/mnt/go -go get github.com/svent/sift -cd /mnt/go/src/github.com/svent/sift -git checkout 2d175c -go install -cp /mnt/go/bin/sift /mnt/bin/ - -## 'git grep' and GNU grep - -They are part of the standard Ubuntu install, and are pretty recent (as of -September 2016). - -$ git --version -git version 2.7.4 -$ grep --version -grep (GNU grep) 2.25 - - -# Running benchmarks - -export PATH="/mnt/bin:$PATH" -cd /mnt/ripgrep/benchsuite -./benchsuite --dir /mnt/bench/ --raw /mnt/bench/raw.csv \ - | tee /mnt/bench/summary -# The above took around 30 minutes to run to completion. diff --git a/benchsuite/runs/2016-09-17-ubuntu1604-ec2/raw.csv b/benchsuite/runs/2016-09-17-ubuntu1604-ec2/raw.csv deleted file mode 100644 index 155da9a..0000000 --- a/benchsuite/runs/2016-09-17-ubuntu1604-ec2/raw.csv +++ /dev/null @@ -1,457 +0,0 @@ -benchmark,warmup_iter,iter,name,command,duration,lines,env -linux_alternates,1,3,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.30042552947998047,68, -linux_alternates,1,3,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.3699159622192383,68, -linux_alternates,1,3,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.2950403690338135,68, -linux_alternates,1,3,ag (ignore),ag -s ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,1.7572166919708252,68, -linux_alternates,1,3,ag (ignore),ag -s ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,1.7568728923797607,68, -linux_alternates,1,3,ag (ignore),ag -s ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,1.7468714714050293,68, -linux_alternates,1,3,git grep (ignore),git grep -E -I -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.5062770843505859,68,LC_ALL=C -linux_alternates,1,3,git grep (ignore),git grep -E -I -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.49932026863098145,68,LC_ALL=C -linux_alternates,1,3,git grep (ignore),git grep -E -I -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.5008277893066406,68,LC_ALL=C -linux_alternates,1,3,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.19775605201721191,68, -linux_alternates,1,3,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.19699668884277344,68, -linux_alternates,1,3,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.19636178016662598,68, -linux_alternates,1,3,ucg (whitelist),ucg --nosmart-case ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.21344256401062012,68, -linux_alternates,1,3,ucg (whitelist),ucg --nosmart-case ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.21743154525756836,68, -linux_alternates,1,3,ucg (whitelist),ucg --nosmart-case ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.22065043449401855,68, -linux_alternates_casei,1,3,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.31632304191589355,160, -linux_alternates_casei,1,3,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.3168807029724121,160, -linux_alternates_casei,1,3,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.4834277629852295,160, -linux_alternates_casei,1,3,ag (ignore),ag -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,1.9558978080749512,160, -linux_alternates_casei,1,3,ag (ignore),ag -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,1.9736671447753906,160, -linux_alternates_casei,1,3,ag (ignore),ag -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,1.9648356437683105,160, -linux_alternates_casei,1,3,git grep (ignore),git grep -E -I -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,2.0229439735412598,160,LC_ALL=C -linux_alternates_casei,1,3,git grep (ignore),git grep -E -I -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,2.0214922428131104,160,LC_ALL=C -linux_alternates_casei,1,3,git grep (ignore),git grep -E -I -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,2.022616147994995,160,LC_ALL=C -linux_alternates_casei,1,3,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.22146987915039062,160, -linux_alternates_casei,1,3,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.22275280952453613,160, -linux_alternates_casei,1,3,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.22226715087890625,160, -linux_alternates_casei,1,3,ucg (whitelist),ucg -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.5290391445159912,160, -linux_alternates_casei,1,3,ucg (whitelist),ucg -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.5196049213409424,160, -linux_alternates_casei,1,3,ucg (whitelist),ucg -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.5219125747680664,160, -linux_literal,1,3,rg (ignore),rg -n PM_RESUME,0.2871882915496826,16, -linux_literal,1,3,rg (ignore),rg -n PM_RESUME,0.38920140266418457,16, -linux_literal,1,3,rg (ignore),rg -n PM_RESUME,0.3668382167816162,16, -linux_literal,1,3,rg (ignore) (mmap),rg -n --mmap PM_RESUME,1.6073203086853027,16, -linux_literal,1,3,rg (ignore) (mmap),rg -n --mmap PM_RESUME,1.6012177467346191,16, -linux_literal,1,3,rg (ignore) (mmap),rg -n --mmap PM_RESUME,1.5818352699279785,16, -linux_literal,1,3,ag (ignore) (mmap),ag -s PM_RESUME,1.592775583267212,16, -linux_literal,1,3,ag (ignore) (mmap),ag -s PM_RESUME,1.5901448726654053,16, -linux_literal,1,3,ag (ignore) (mmap),ag -s PM_RESUME,1.586061716079712,16, -linux_literal,1,3,pt (ignore),pt PM_RESUME,0.45094990730285645,16, -linux_literal,1,3,pt (ignore),pt PM_RESUME,0.47065186500549316,16, -linux_literal,1,3,pt (ignore),pt PM_RESUME,0.4422800540924072,16, -linux_literal,1,3,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git PM_RESUME,0.6293809413909912,16, -linux_literal,1,3,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git PM_RESUME,0.6314799785614014,16, -linux_literal,1,3,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git PM_RESUME,0.6289358139038086,16, -linux_literal,1,3,git grep (ignore),git grep -I -n PM_RESUME,0.347550630569458,16,LC_ALL=C -linux_literal,1,3,git grep (ignore),git grep -I -n PM_RESUME,0.345928430557251,16,LC_ALL=C -linux_literal,1,3,git grep (ignore),git grep -I -n PM_RESUME,0.33939385414123535,16,LC_ALL=C -linux_literal,1,3,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.20830345153808594,16, -linux_literal,1,3,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.34220385551452637,16, -linux_literal,1,3,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.2077772617340088,16, -linux_literal,1,3,ucg (whitelist),ucg --nosmart-case PM_RESUME,0.21996808052062988,16, -linux_literal,1,3,ucg (whitelist),ucg --nosmart-case PM_RESUME,0.22822093963623047,16, -linux_literal,1,3,ucg (whitelist),ucg --nosmart-case PM_RESUME,0.21923017501831055,16, -linux_literal_casei,1,3,rg (ignore),rg -n -i PM_RESUME,0.2988588809967041,370, -linux_literal_casei,1,3,rg (ignore),rg -n -i PM_RESUME,0.5339267253875732,370, -linux_literal_casei,1,3,rg (ignore),rg -n -i PM_RESUME,0.43750762939453125,370, -linux_literal_casei,1,3,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,1.603757381439209,370, -linux_literal_casei,1,3,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,1.618077278137207,370, -linux_literal_casei,1,3,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,1.6234121322631836,370, -linux_literal_casei,1,3,ag (ignore) (mmap),ag -i PM_RESUME,1.621368646621704,370, -linux_literal_casei,1,3,ag (ignore) (mmap),ag -i PM_RESUME,1.5698626041412354,370, -linux_literal_casei,1,3,ag (ignore) (mmap),ag -i PM_RESUME,1.6105949878692627,370, -linux_literal_casei,1,3,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git PM_RESUME,0.8005843162536621,370, -linux_literal_casei,1,3,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git PM_RESUME,0.8044955730438232,370, -linux_literal_casei,1,3,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git PM_RESUME,0.806922197341919,370, -linux_literal_casei,1,3,git grep (ignore),git grep -I -n -i PM_RESUME,0.34161829948425293,370,LC_ALL=C -linux_literal_casei,1,3,git grep (ignore),git grep -I -n -i PM_RESUME,0.3455958366394043,370,LC_ALL=C -linux_literal_casei,1,3,git grep (ignore),git grep -I -n -i PM_RESUME,0.3493361473083496,370,LC_ALL=C -linux_literal_casei,1,3,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.2149522304534912,370, -linux_literal_casei,1,3,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.21602368354797363,370, -linux_literal_casei,1,3,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.27021098136901855,370, -linux_literal_casei,1,3,ucg (whitelist),ucg -i PM_RESUME,0.22747421264648438,370, -linux_literal_casei,1,3,ucg (whitelist),ucg -i PM_RESUME,0.22050881385803223,370, -linux_literal_casei,1,3,ucg (whitelist),ucg -i PM_RESUME,0.21217584609985352,370, -linux_literal_default,1,3,rg,rg PM_RESUME,0.27482175827026367,16, -linux_literal_default,1,3,rg,rg PM_RESUME,0.2796294689178467,16, -linux_literal_default,1,3,rg,rg PM_RESUME,0.27638936042785645,16, -linux_literal_default,1,3,ag,ag PM_RESUME,1.598384141921997,16, -linux_literal_default,1,3,ag,ag PM_RESUME,1.5849597454071045,16, -linux_literal_default,1,3,ag,ag PM_RESUME,1.6000149250030518,16, -linux_literal_default,1,3,ucg,ucg PM_RESUME,0.2263963222503662,16, -linux_literal_default,1,3,ucg,ucg PM_RESUME,0.21367835998535156,16, -linux_literal_default,1,3,ucg,ucg PM_RESUME,0.21764111518859863,16, -linux_literal_default,1,3,pt,pt PM_RESUME,0.42263340950012207,16, -linux_literal_default,1,3,pt,pt PM_RESUME,0.467041015625,16, -linux_literal_default,1,3,pt,pt PM_RESUME,0.42820048332214355,16, -linux_literal_default,1,3,sift,sift PM_RESUME,0.33421826362609863,16, -linux_literal_default,1,3,sift,sift PM_RESUME,0.35932135581970215,16, -linux_literal_default,1,3,sift,sift PM_RESUME,0.3372631072998047,16, -linux_literal_default,1,3,git grep,git grep PM_RESUME,0.348984956741333,16,LC_ALL=en_US.UTF-8 -linux_literal_default,1,3,git grep,git grep PM_RESUME,0.34420299530029297,16,LC_ALL=en_US.UTF-8 -linux_literal_default,1,3,git grep,git grep PM_RESUME,0.33880615234375,16,LC_ALL=en_US.UTF-8 -linux_no_literal,1,3,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.5833027362823486,490, -linux_no_literal,1,3,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.5783836841583252,490, -linux_no_literal,1,3,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.5806806087493896,490, -linux_no_literal,1,3,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.4163496494293213,490, -linux_no_literal,1,3,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.4040029048919678,490, -linux_no_literal,1,3,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.40265560150146484,490, -linux_no_literal,1,3,ag (ignore) (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},2.3176910877227783,766, -linux_no_literal,1,3,ag (ignore) (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},2.3504347801208496,766, -linux_no_literal,1,3,ag (ignore) (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},2.317542552947998,766, -linux_no_literal,1,3,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},25.821982383728027,491, -linux_no_literal,1,3,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},25.82067561149597,491, -linux_no_literal,1,3,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},25.626302242279053,491, -linux_no_literal,1,3,git grep (ignore),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},26.349210023880005,490,LC_ALL=en_US.UTF-8 -linux_no_literal,1,3,git grep (ignore),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},26.34226369857788,490,LC_ALL=en_US.UTF-8 -linux_no_literal,1,3,git grep (ignore),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},26.340656995773315,490,LC_ALL=en_US.UTF-8 -linux_no_literal,1,3,git grep (ignore) (ASCII),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},4.14680290222168,490,LC_ALL=C -linux_no_literal,1,3,git grep (ignore) (ASCII),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},4.153340578079224,490,LC_ALL=C -linux_no_literal,1,3,git grep (ignore) (ASCII),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},4.154819011688232,490,LC_ALL=C -linux_no_literal,1,3,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.49768829345703125,419, -linux_no_literal,1,3,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.5121400356292725,419, -linux_no_literal,1,3,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.49718427658081055,419, -linux_no_literal,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.38550543785095215,419, -linux_no_literal,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.32651591300964355,419, -linux_no_literal,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.3246915340423584,419, -linux_no_literal,1,3,ucg (whitelist) (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},1.128183126449585,416, -linux_no_literal,1,3,ucg (whitelist) (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},1.1255216598510742,416, -linux_no_literal,1,3,ucg (whitelist) (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},1.1268525123596191,416, -linux_re_literal_suffix,1,3,rg (ignore),rg -n [A-Z]+_RESUME,0.36306214332580566,1652, -linux_re_literal_suffix,1,3,rg (ignore),rg -n [A-Z]+_RESUME,0.45077037811279297,1652, -linux_re_literal_suffix,1,3,rg (ignore),rg -n [A-Z]+_RESUME,0.3804624080657959,1652, -linux_re_literal_suffix,1,3,ag (ignore),ag -s [A-Z]+_RESUME,1.8995850086212158,1652, -linux_re_literal_suffix,1,3,ag (ignore),ag -s [A-Z]+_RESUME,1.8897662162780762,1652, -linux_re_literal_suffix,1,3,ag (ignore),ag -s [A-Z]+_RESUME,1.878380537033081,1652, -linux_re_literal_suffix,1,3,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git [A-Z]+_RESUME,10.48949646949768,1652, -linux_re_literal_suffix,1,3,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git [A-Z]+_RESUME,10.289165735244751,1652, -linux_re_literal_suffix,1,3,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git [A-Z]+_RESUME,10.000468254089355,1652, -linux_re_literal_suffix,1,3,git grep (ignore),git grep -E -I -n [A-Z]+_RESUME,1.1080453395843506,1652,LC_ALL=C -linux_re_literal_suffix,1,3,git grep (ignore),git grep -E -I -n [A-Z]+_RESUME,1.10821533203125,1652,LC_ALL=C -linux_re_literal_suffix,1,3,git grep (ignore),git grep -E -I -n [A-Z]+_RESUME,1.105595588684082,1652,LC_ALL=C -linux_re_literal_suffix,1,3,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.2073357105255127,1630, -linux_re_literal_suffix,1,3,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.20552492141723633,1630, -linux_re_literal_suffix,1,3,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.2061319351196289,1630, -linux_re_literal_suffix,1,3,ucg (whitelist),ucg --nosmart-case [A-Z]+_RESUME,0.3013310432434082,1630, -linux_re_literal_suffix,1,3,ucg (whitelist),ucg --nosmart-case [A-Z]+_RESUME,0.3005218505859375,1630, -linux_re_literal_suffix,1,3,ucg (whitelist),ucg --nosmart-case [A-Z]+_RESUME,0.29984378814697266,1630, -linux_unicode_greek,1,3,rg,rg -n \p{Greek},0.4162716865539551,23, -linux_unicode_greek,1,3,rg,rg -n \p{Greek},0.47885966300964355,23, -linux_unicode_greek,1,3,rg,rg -n \p{Greek},0.5135962963104248,23, -linux_unicode_greek,1,3,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \p{Greek},7.570494651794434,23, -linux_unicode_greek,1,3,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \p{Greek},7.790151596069336,23, -linux_unicode_greek,1,3,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \p{Greek},7.783358812332153,23, -linux_unicode_greek_casei,1,3,rg,rg -n -i \p{Greek},0.4370443820953369,103, -linux_unicode_greek_casei,1,3,rg,rg -n -i \p{Greek},0.40680766105651855,103, -linux_unicode_greek_casei,1,3,rg,rg -n -i \p{Greek},0.4011569023132324,103, -linux_unicode_greek_casei,1,3,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git \p{Greek},0.002422809600830078,, -linux_unicode_greek_casei,1,3,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git \p{Greek},0.002414226531982422,, -linux_unicode_greek_casei,1,3,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git \p{Greek},0.002293109893798828,, -linux_unicode_word,1,3,rg (ignore),rg -n \wAh,0.44771265983581543,186, -linux_unicode_word,1,3,rg (ignore),rg -n \wAh,0.3006107807159424,186, -linux_unicode_word,1,3,rg (ignore),rg -n \wAh,0.3026111125946045,186, -linux_unicode_word,1,3,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.43827080726623535,174, -linux_unicode_word,1,3,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.2931697368621826,174, -linux_unicode_word,1,3,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.33072638511657715,174, -linux_unicode_word,1,3,ag (ignore) (ASCII),ag -s \wAh,1.7645132541656494,174, -linux_unicode_word,1,3,ag (ignore) (ASCII),ag -s \wAh,1.7730333805084229,174, -linux_unicode_word,1,3,ag (ignore) (ASCII),ag -s \wAh,1.773383378982544,174, -linux_unicode_word,1,3,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n \wAh,10.872124671936035,174, -linux_unicode_word,1,3,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n \wAh,11.147738456726074,174, -linux_unicode_word,1,3,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n \wAh,11.029243469238281,174, -linux_unicode_word,1,3,git grep (ignore),git grep -E -I -n \wAh,13.047154664993286,186,LC_ALL=en_US.UTF-8 -linux_unicode_word,1,3,git grep (ignore),git grep -E -I -n \wAh,13.025037288665771,186,LC_ALL=en_US.UTF-8 -linux_unicode_word,1,3,git grep (ignore),git grep -E -I -n \wAh,13.081012487411499,186,LC_ALL=en_US.UTF-8 -linux_unicode_word,1,3,git grep (ignore) (ASCII),git grep -E -I -n \wAh,2.98722767829895,174,LC_ALL=C -linux_unicode_word,1,3,git grep (ignore) (ASCII),git grep -E -I -n \wAh,2.987990379333496,174,LC_ALL=C -linux_unicode_word,1,3,git grep (ignore) (ASCII),git grep -E -I -n \wAh,2.988698959350586,174,LC_ALL=C -linux_unicode_word,1,3,rg (whitelist),rg -n --no-ignore -tall \wAh,0.21961355209350586,180, -linux_unicode_word,1,3,rg (whitelist),rg -n --no-ignore -tall \wAh,0.2884254455566406,180, -linux_unicode_word,1,3,rg (whitelist),rg -n --no-ignore -tall \wAh,0.21905040740966797,180, -linux_unicode_word,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.23966765403747559,168, -linux_unicode_word,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.21801042556762695,168, -linux_unicode_word,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.21909880638122559,168, -linux_unicode_word,1,3,ucg (ASCII),ucg --nosmart-case \wAh,0.2259504795074463,168, -linux_unicode_word,1,3,ucg (ASCII),ucg --nosmart-case \wAh,0.22269177436828613,168, -linux_unicode_word,1,3,ucg (ASCII),ucg --nosmart-case \wAh,0.2259974479675293,168, -linux_word,1,3,rg (ignore),rg -n -w PM_RESUME,0.34968090057373047,6, -linux_word,1,3,rg (ignore),rg -n -w PM_RESUME,0.28850769996643066,6, -linux_word,1,3,rg (ignore),rg -n -w PM_RESUME,0.34809160232543945,6, -linux_word,1,3,ag (ignore),ag -s -w PM_RESUME,1.6134660243988037,6, -linux_word,1,3,ag (ignore),ag -s -w PM_RESUME,1.59847092628479,6, -linux_word,1,3,ag (ignore),ag -s -w PM_RESUME,1.581369161605835,6, -linux_word,1,3,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -w --git PM_RESUME,7.644887208938599,6, -linux_word,1,3,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -w --git PM_RESUME,7.8782219886779785,6, -linux_word,1,3,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -w --git PM_RESUME,7.754150152206421,6, -linux_word,1,3,git grep (ignore),git grep -E -I -n -w PM_RESUME,0.34302353858947754,6,LC_ALL=C -linux_word,1,3,git grep (ignore),git grep -E -I -n -w PM_RESUME,0.33672142028808594,6,LC_ALL=C -linux_word,1,3,git grep (ignore),git grep -E -I -n -w PM_RESUME,0.35193610191345215,6,LC_ALL=C -linux_word,1,3,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.33329272270202637,6, -linux_word,1,3,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.25751829147338867,6, -linux_word,1,3,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.21761608123779297,6, -linux_word,1,3,ucg (whitelist),ucg --nosmart-case -w PM_RESUME,0.22014284133911133,6, -linux_word,1,3,ucg (whitelist),ucg --nosmart-case -w PM_RESUME,0.22314929962158203,6, -linux_word,1,3,ucg (whitelist),ucg --nosmart-case -w PM_RESUME,0.2202434539794922,6, -subtitles_en_alternate,1,3,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.622809886932373,848, -subtitles_en_alternate,1,3,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6181182861328125,848, -subtitles_en_alternate,1,3,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6205663681030273,848, -subtitles_en_alternate,1,3,ag (lines),ag -s Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.7565691471099854,848, -subtitles_en_alternate,1,3,ag (lines),ag -s Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.7561769485473633,848, -subtitles_en_alternate,1,3,ag (lines),ag -s Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.7559969425201416,848, -subtitles_en_alternate,1,3,ucg (lines),ucg --nosmart-case Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.4493463039398193,848, -subtitles_en_alternate,1,3,ucg (lines),ucg --nosmart-case Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.44877028465271,848, -subtitles_en_alternate,1,3,ucg (lines),ucg --nosmart-case Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.4433801174163818,848, -subtitles_en_alternate,1,3,grep (lines),grep -E -an Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.4114174842834473,848,LC_ALL=C -subtitles_en_alternate,1,3,grep (lines),grep -E -an Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.411625862121582,848,LC_ALL=C -subtitles_en_alternate,1,3,grep (lines),grep -E -an Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.408623456954956,848,LC_ALL=C -subtitles_en_alternate,1,3,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.2900726795196533,848, -subtitles_en_alternate,1,3,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.2905848026275635,848, -subtitles_en_alternate,1,3,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.2903940677642822,848, -subtitles_en_alternate,1,3,grep,grep -E -a Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.9546515941619873,848,LC_ALL=C -subtitles_en_alternate,1,3,grep,grep -E -a Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.955279588699341,848,LC_ALL=C -subtitles_en_alternate,1,3,grep,grep -E -a Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.954089403152466,848,LC_ALL=C -subtitles_en_alternate_casei,1,3,ag (ASCII),ag -s -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,5.169135332107544,862, -subtitles_en_alternate_casei,1,3,ag (ASCII),ag -s -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,5.174601078033447,862, -subtitles_en_alternate_casei,1,3,ag (ASCII),ag -s -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,5.1684675216674805,862, -subtitles_en_alternate_casei,1,3,ucg (ASCII),ucg -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.4171736240386963,862, -subtitles_en_alternate_casei,1,3,ucg (ASCII),ucg -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.4158167839050293,862, -subtitles_en_alternate_casei,1,3,ucg (ASCII),ucg -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.4186513423919678,862, -subtitles_en_alternate_casei,1,3,grep (ASCII),grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.531639575958252,862,LC_ALL=C -subtitles_en_alternate_casei,1,3,grep (ASCII),grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.526550054550171,862,LC_ALL=C -subtitles_en_alternate_casei,1,3,grep (ASCII),grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.528509140014648,862,LC_ALL=C -subtitles_en_alternate_casei,1,3,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.722398281097412,862, -subtitles_en_alternate_casei,1,3,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.7225935459136963,862, -subtitles_en_alternate_casei,1,3,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.7222185134887695,862, -subtitles_en_alternate_casei,1,3,grep,grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,5.12151837348938,862,LC_ALL=en_US.UTF-8 -subtitles_en_alternate_casei,1,3,grep,grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,5.119963884353638,862,LC_ALL=en_US.UTF-8 -subtitles_en_alternate_casei,1,3,grep,grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,5.121079683303833,862,LC_ALL=en_US.UTF-8 -subtitles_en_literal,1,3,rg,rg Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.2684764862060547,629, -subtitles_en_literal,1,3,rg,rg Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.26811957359313965,629, -subtitles_en_literal,1,3,rg,rg Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.2684173583984375,629, -subtitles_en_literal,1,3,pt,pt -N Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.435128688812256,629, -subtitles_en_literal,1,3,pt,pt -N Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.4362881183624268,629, -subtitles_en_literal,1,3,pt,pt -N Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.4399220943450928,629, -subtitles_en_literal,1,3,sift,sift Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.32662391662597656,629, -subtitles_en_literal,1,3,sift,sift Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.3277275562286377,629, -subtitles_en_literal,1,3,sift,sift Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.32798290252685547,629, -subtitles_en_literal,1,3,grep,grep -a Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.520500659942627,629,LC_ALL=C -subtitles_en_literal,1,3,grep,grep -a Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5191032886505127,629,LC_ALL=C -subtitles_en_literal,1,3,grep,grep -a Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5171597003936768,629,LC_ALL=C -subtitles_en_literal,1,3,rg (lines),rg -n Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.595801830291748,629, -subtitles_en_literal,1,3,rg (lines),rg -n Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5954360961914062,629, -subtitles_en_literal,1,3,rg (lines),rg -n Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5945618152618408,629, -subtitles_en_literal,1,3,ag (lines),ag -s Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.7291676998138428,629, -subtitles_en_literal,1,3,ag (lines),ag -s Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.730966329574585,629, -subtitles_en_literal,1,3,ag (lines),ag -s Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.728854179382324,629, -subtitles_en_literal,1,3,ucg (lines),ucg --nosmart-case Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.775996208190918,629, -subtitles_en_literal,1,3,ucg (lines),ucg --nosmart-case Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.7760195732116699,629, -subtitles_en_literal,1,3,ucg (lines),ucg --nosmart-case Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.7763564586639404,629, -subtitles_en_literal,1,3,pt (lines),pt Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.433366060256958,629, -subtitles_en_literal,1,3,pt (lines),pt Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.4338581562042236,629, -subtitles_en_literal,1,3,pt (lines),pt Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.435924768447876,629, -subtitles_en_literal,1,3,sift (lines),sift -n Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.7586827278137207,629, -subtitles_en_literal,1,3,sift (lines),sift -n Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.7590317726135254,629, -subtitles_en_literal,1,3,sift (lines),sift -n Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.754432201385498,629, -subtitles_en_literal,1,3,grep (lines),grep -an Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.9726488590240479,629,LC_ALL=C -subtitles_en_literal,1,3,grep (lines),grep -an Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.9699857234954834,629,LC_ALL=C -subtitles_en_literal,1,3,grep (lines),grep -an Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.9714112281799316,629,LC_ALL=C -subtitles_en_literal_casei,1,3,rg,rg -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.36658453941345215,642, -subtitles_en_literal_casei,1,3,rg,rg -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.3654778003692627,642, -subtitles_en_literal_casei,1,3,rg,rg -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.36565113067626953,642, -subtitles_en_literal_casei,1,3,grep,grep -ai Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.0890116691589355,642,LC_ALL=en_US.UTF-8 -subtitles_en_literal_casei,1,3,grep,grep -ai Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.08124852180481,642,LC_ALL=en_US.UTF-8 -subtitles_en_literal_casei,1,3,grep,grep -ai Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.0796849727630615,642,LC_ALL=en_US.UTF-8 -subtitles_en_literal_casei,1,3,grep (ASCII),grep -E -ai Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6151647567749023,642,LC_ALL=C -subtitles_en_literal_casei,1,3,grep (ASCII),grep -E -ai Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6141552925109863,642,LC_ALL=C -subtitles_en_literal_casei,1,3,grep (ASCII),grep -E -ai Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6132988929748535,642,LC_ALL=C -subtitles_en_literal_casei,1,3,rg (lines),rg -n -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6962459087371826,642, -subtitles_en_literal_casei,1,3,rg (lines),rg -n -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6945579051971436,642, -subtitles_en_literal_casei,1,3,rg (lines),rg -n -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.693866491317749,642, -subtitles_en_literal_casei,1,3,ag (lines) (ASCII),ag -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.771639823913574,642, -subtitles_en_literal_casei,1,3,ag (lines) (ASCII),ag -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.772296190261841,642, -subtitles_en_literal_casei,1,3,ag (lines) (ASCII),ag -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.7712018489837646,642, -subtitles_en_literal_casei,1,3,ucg (lines) (ASCII),ucg -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.8068230152130127,642, -subtitles_en_literal_casei,1,3,ucg (lines) (ASCII),ucg -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.80411696434021,642, -subtitles_en_literal_casei,1,3,ucg (lines) (ASCII),ucg -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.8038516044616699,642, -subtitles_en_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5951778888702393,629, -subtitles_en_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5971941947937012,629, -subtitles_en_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5952184200286865,629, -subtitles_en_literal_word,1,3,ag (ASCII),ag -sw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.7292284965515137,629, -subtitles_en_literal_word,1,3,ag (ASCII),ag -sw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.728681802749634,629, -subtitles_en_literal_word,1,3,ag (ASCII),ag -sw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.7315311431884766,629, -subtitles_en_literal_word,1,3,ucg (ASCII),ucg --nosmart-case Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.784024715423584,629, -subtitles_en_literal_word,1,3,ucg (ASCII),ucg --nosmart-case Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.780540943145752,629, -subtitles_en_literal_word,1,3,ucg (ASCII),ucg --nosmart-case Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.7772648334503174,629, -subtitles_en_literal_word,1,3,grep (ASCII),grep -anw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.9744353294372559,629,LC_ALL=C -subtitles_en_literal_word,1,3,grep (ASCII),grep -anw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.9781327247619629,629,LC_ALL=C -subtitles_en_literal_word,1,3,grep (ASCII),grep -anw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.9798097610473633,629,LC_ALL=C -subtitles_en_literal_word,1,3,rg,rg -nw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5965189933776855,629, -subtitles_en_literal_word,1,3,rg,rg -nw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5960156917572021,629, -subtitles_en_literal_word,1,3,rg,rg -nw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5975723266601562,629, -subtitles_en_literal_word,1,3,grep,grep -anw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.9818971157073975,629,LC_ALL=en_US.UTF-8 -subtitles_en_literal_word,1,3,grep,grep -anw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.9785251617431641,629,LC_ALL=en_US.UTF-8 -subtitles_en_literal_word,1,3,grep,grep -anw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.977081298828125,629,LC_ALL=en_US.UTF-8 -subtitles_en_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.7750890254974365,13, -subtitles_en_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.774017333984375,13, -subtitles_en_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.783200740814209,13, -subtitles_en_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.5396409034729004,13, -subtitles_en_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.5404820442199707,13, -subtitles_en_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.5400590896606445,13, -subtitles_en_no_literal,1,3,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,10.072888612747192,48, -subtitles_en_no_literal,1,3,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,10.075153350830078,48, -subtitles_en_no_literal,1,3,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,10.0713791847229,48, -subtitles_en_no_literal,1,3,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,7.734791278839111,13, -subtitles_en_no_literal,1,3,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,7.7345263957977295,13, -subtitles_en_no_literal,1,3,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,7.73199462890625,13, -subtitles_en_no_literal,1,3,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.411367416381836,13,LC_ALL=C -subtitles_en_no_literal,1,3,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.41072940826416,13,LC_ALL=C -subtitles_en_no_literal,1,3,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.414730072021484,13,LC_ALL=C -subtitles_en_surrounding_words,1,3,rg,rg -n \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6052529811859131,317, -subtitles_en_surrounding_words,1,3,rg,rg -n \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6049232482910156,317, -subtitles_en_surrounding_words,1,3,rg,rg -n \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6045565605163574,317, -subtitles_en_surrounding_words,1,3,grep,grep -E -an \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.2849924564361572,317,LC_ALL=en_US.UTF-8 -subtitles_en_surrounding_words,1,3,grep,grep -E -an \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.2837722301483154,317,LC_ALL=en_US.UTF-8 -subtitles_en_surrounding_words,1,3,grep,grep -E -an \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.2847650051116943,317,LC_ALL=en_US.UTF-8 -subtitles_en_surrounding_words,1,3,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6005992889404297,317, -subtitles_en_surrounding_words,1,3,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.600543737411499,317, -subtitles_en_surrounding_words,1,3,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6009273529052734,317, -subtitles_en_surrounding_words,1,3,ag (ASCII),ag -s \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,11.664374113082886,323, -subtitles_en_surrounding_words,1,3,ag (ASCII),ag -s \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,11.674306869506836,323, -subtitles_en_surrounding_words,1,3,ag (ASCII),ag -s \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,11.657484769821167,323, -subtitles_en_surrounding_words,1,3,ucg (ASCII),ucg --nosmart-case \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.650290012359619,317, -subtitles_en_surrounding_words,1,3,ucg (ASCII),ucg --nosmart-case \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.651855707168579,317, -subtitles_en_surrounding_words,1,3,ucg (ASCII),ucg --nosmart-case \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.649921417236328,317, -subtitles_en_surrounding_words,1,3,grep (ASCII),grep -E -an \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.2745037078857422,317,LC_ALL=C -subtitles_en_surrounding_words,1,3,grep (ASCII),grep -E -an \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.275665521621704,317,LC_ALL=C -subtitles_en_surrounding_words,1,3,grep (ASCII),grep -E -an \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.273988962173462,317,LC_ALL=C -subtitles_ru_alternate,1,3,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.9031155109405518,691, -subtitles_ru_alternate,1,3,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.9021081924438477,691, -subtitles_ru_alternate,1,3,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.9028818607330322,691, -subtitles_ru_alternate,1,3,ag (lines),ag -s Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,5.8895978927612305,691, -subtitles_ru_alternate,1,3,ag (lines),ag -s Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,5.891357660293579,691, -subtitles_ru_alternate,1,3,ag (lines),ag -s Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,5.892467975616455,691, -subtitles_ru_alternate,1,3,ucg (lines),ucg --nosmart-case Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.7517757415771484,691, -subtitles_ru_alternate,1,3,ucg (lines),ucg --nosmart-case Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.7550888061523438,691, -subtitles_ru_alternate,1,3,ucg (lines),ucg --nosmart-case Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.7555651664733887,691, -subtitles_ru_alternate,1,3,grep (lines),grep -E -an Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.51417875289917,691,LC_ALL=C -subtitles_ru_alternate,1,3,grep (lines),grep -E -an Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.512972116470337,691,LC_ALL=C -subtitles_ru_alternate,1,3,grep (lines),grep -E -an Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.507266521453857,691,LC_ALL=C -subtitles_ru_alternate,1,3,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.300950288772583,691, -subtitles_ru_alternate,1,3,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.2987852096557617,691, -subtitles_ru_alternate,1,3,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.3024635314941406,691, -subtitles_ru_alternate,1,3,grep,grep -E -a Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,7.983739137649536,691,LC_ALL=C -subtitles_ru_alternate,1,3,grep,grep -E -a Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,7.988446950912476,691,LC_ALL=C -subtitles_ru_alternate,1,3,grep,grep -E -a Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,7.979671478271484,691,LC_ALL=C -subtitles_ru_alternate_casei,1,3,ag (ASCII),ag -s -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,5.889382362365723,691, -subtitles_ru_alternate_casei,1,3,ag (ASCII),ag -s -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,5.902577877044678,691, -subtitles_ru_alternate_casei,1,3,ag (ASCII),ag -s -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,5.890571355819702,691, -subtitles_ru_alternate_casei,1,3,ucg (ASCII),ucg -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.7548162937164307,691, -subtitles_ru_alternate_casei,1,3,ucg (ASCII),ucg -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.747791051864624,691, -subtitles_ru_alternate_casei,1,3,ucg (ASCII),ucg -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.7396674156188965,691, -subtitles_ru_alternate_casei,1,3,grep (ASCII),grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.58053183555603,691,LC_ALL=C -subtitles_ru_alternate_casei,1,3,grep (ASCII),grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.594751596450806,691,LC_ALL=C -subtitles_ru_alternate_casei,1,3,grep (ASCII),grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.561670541763306,691,LC_ALL=C -subtitles_ru_alternate_casei,1,3,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.833597183227539,735, -subtitles_ru_alternate_casei,1,3,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.831137180328369,735, -subtitles_ru_alternate_casei,1,3,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.830361843109131,735, -subtitles_ru_alternate_casei,1,3,grep,grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.723876953125,735,LC_ALL=en_US.UTF-8 -subtitles_ru_alternate_casei,1,3,grep,grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.723239183425903,735,LC_ALL=en_US.UTF-8 -subtitles_ru_alternate_casei,1,3,grep,grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.722000360488892,735,LC_ALL=en_US.UTF-8 -subtitles_ru_literal,1,3,rg,rg Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.3252851963043213,583, -subtitles_ru_literal,1,3,rg,rg Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.3270294666290283,583, -subtitles_ru_literal,1,3,rg,rg Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.32680773735046387,583, -subtitles_ru_literal,1,3,pt,pt -N Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,12.932488679885864,583, -subtitles_ru_literal,1,3,pt,pt -N Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,12.91330337524414,583, -subtitles_ru_literal,1,3,pt,pt -N Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,12.911381006240845,583, -subtitles_ru_literal,1,3,sift,sift Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,16.438587427139282,583, -subtitles_ru_literal,1,3,sift,sift Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,16.412389755249023,583, -subtitles_ru_literal,1,3,sift,sift Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,16.412444353103638,583, -subtitles_ru_literal,1,3,grep,grep -a Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7865939140319824,583,LC_ALL=C -subtitles_ru_literal,1,3,grep,grep -a Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7889957427978516,583,LC_ALL=C -subtitles_ru_literal,1,3,grep,grep -a Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7923679351806641,583,LC_ALL=C -subtitles_ru_literal,1,3,rg (lines),rg -n Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.9255633354187012,583, -subtitles_ru_literal,1,3,rg (lines),rg -n Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.9285938739776611,583, -subtitles_ru_literal,1,3,rg (lines),rg -n Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.9274048805236816,583, -subtitles_ru_literal,1,3,ag (lines),ag -s Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.4811036586761475,583, -subtitles_ru_literal,1,3,ag (lines),ag -s Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.4785168170928955,583, -subtitles_ru_literal,1,3,ag (lines),ag -s Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.484618186950684,583, -subtitles_ru_literal,1,3,ucg (lines),ucg --nosmart-case Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.7743628025054932,583, -subtitles_ru_literal,1,3,ucg (lines),ucg --nosmart-case Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.7731456756591797,583, -subtitles_ru_literal,1,3,ucg (lines),ucg --nosmart-case Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.7749128341674805,583, -subtitles_ru_literal,1,3,pt (lines),pt Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,12.931540250778198,583, -subtitles_ru_literal,1,3,pt (lines),pt Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,12.935162782669067,583, -subtitles_ru_literal,1,3,pt (lines),pt Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,12.949711561203003,583, -subtitles_ru_literal,1,3,sift (lines),sift -n Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,17.183809995651245,583, -subtitles_ru_literal,1,3,sift (lines),sift -n Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,17.19060492515564,583, -subtitles_ru_literal,1,3,sift (lines),sift -n Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,17.17626404762268,583, -subtitles_ru_literal,1,3,grep (lines),grep -an Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.3023960590362549,583,LC_ALL=C -subtitles_ru_literal,1,3,grep (lines),grep -an Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.2992589473724365,583,LC_ALL=C -subtitles_ru_literal,1,3,grep (lines),grep -an Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.299330711364746,583,LC_ALL=C -subtitles_ru_literal_casei,1,3,rg,rg -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.1320264339447021,604, -subtitles_ru_literal_casei,1,3,rg,rg -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.1323668956756592,604, -subtitles_ru_literal_casei,1,3,rg,rg -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.1354515552520752,604, -subtitles_ru_literal_casei,1,3,grep,grep -ai Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.194744348526001,604,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_casei,1,3,grep,grep -ai Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.190656423568726,604,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_casei,1,3,grep,grep -ai Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.18506383895874,604,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_casei,1,3,grep (ASCII),grep -E -ai Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7826528549194336,583,LC_ALL=C -subtitles_ru_literal_casei,1,3,grep (ASCII),grep -E -ai Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7846219539642334,583,LC_ALL=C -subtitles_ru_literal_casei,1,3,grep (ASCII),grep -E -ai Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7846999168395996,583,LC_ALL=C -subtitles_ru_literal_casei,1,3,rg (lines),rg -n -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.734788179397583,604, -subtitles_ru_literal_casei,1,3,rg (lines),rg -n -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.7333040237426758,604, -subtitles_ru_literal_casei,1,3,rg (lines),rg -n -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.731860637664795,604, -subtitles_ru_literal_casei,1,3,ag (lines) (ASCII),ag -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7297205924987793,, -subtitles_ru_literal_casei,1,3,ag (lines) (ASCII),ag -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7314808368682861,, -subtitles_ru_literal_casei,1,3,ag (lines) (ASCII),ag -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7289514541625977,, -subtitles_ru_literal_casei,1,3,ucg (lines) (ASCII),ucg -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.7773914337158203,583, -subtitles_ru_literal_casei,1,3,ucg (lines) (ASCII),ucg -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.774536371231079,583, -subtitles_ru_literal_casei,1,3,ucg (lines) (ASCII),ucg -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.7740859985351562,583, -subtitles_ru_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.3252553939819336,, -subtitles_ru_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.32543301582336426,, -subtitles_ru_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.32512736320495605,, -subtitles_ru_literal_word,1,3,ag (ASCII),ag -sw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7519562244415283,, -subtitles_ru_literal_word,1,3,ag (ASCII),ag -sw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.752692699432373,, -subtitles_ru_literal_word,1,3,ag (ASCII),ag -sw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7524521350860596,, -subtitles_ru_literal_word,1,3,ucg (ASCII),ucg --nosmart-case Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.7868170738220215,583, -subtitles_ru_literal_word,1,3,ucg (ASCII),ucg --nosmart-case Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.7786612510681152,583, -subtitles_ru_literal_word,1,3,ucg (ASCII),ucg --nosmart-case Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.776214838027954,583, -subtitles_ru_literal_word,1,3,grep (ASCII),grep -anw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.303652286529541,583,LC_ALL=C -subtitles_ru_literal_word,1,3,grep (ASCII),grep -anw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.3012151718139648,583,LC_ALL=C -subtitles_ru_literal_word,1,3,grep (ASCII),grep -anw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.307457685470581,583,LC_ALL=C -subtitles_ru_literal_word,1,3,rg,rg -nw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.9280951023101807,579, -subtitles_ru_literal_word,1,3,rg,rg -nw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.9285900592803955,579, -subtitles_ru_literal_word,1,3,rg,rg -nw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.9288535118103027,579, -subtitles_ru_literal_word,1,3,grep,grep -anw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.3026466369628906,579,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_word,1,3,grep,grep -anw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.3016819953918457,579,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_word,1,3,grep,grep -anw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.3006587028503418,579,LC_ALL=en_US.UTF-8 -subtitles_ru_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.895586729049683,41, -subtitles_ru_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.914353132247925,41, -subtitles_ru_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.902980327606201,41, -subtitles_ru_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,3.972637891769409,, -subtitles_ru_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,3.9723849296569824,, -subtitles_ru_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,3.9723057746887207,, -subtitles_ru_no_literal,1,3,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.3936586380004883,, -subtitles_ru_no_literal,1,3,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.3987748622894287,, -subtitles_ru_no_literal,1,3,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.393911361694336,, -subtitles_ru_no_literal,1,3,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.8932065963745117,, -subtitles_ru_no_literal,1,3,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.8977222442626953,, -subtitles_ru_no_literal,1,3,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.893040895462036,, -subtitles_ru_no_literal,1,3,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.4844722747802734,,LC_ALL=C -subtitles_ru_no_literal,1,3,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.485093116760254,,LC_ALL=C -subtitles_ru_no_literal,1,3,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.482459306716919,,LC_ALL=C -subtitles_ru_surrounding_words,1,3,rg,rg -n \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.9564735889434814,278, -subtitles_ru_surrounding_words,1,3,rg,rg -n \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.9561436176300049,278, -subtitles_ru_surrounding_words,1,3,rg,rg -n \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.9558789730072021,278, -subtitles_ru_surrounding_words,1,3,grep,grep -E -an \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.6620113849639893,278,LC_ALL=en_US.UTF-8 -subtitles_ru_surrounding_words,1,3,grep,grep -E -an \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.6624438762664795,278,LC_ALL=en_US.UTF-8 -subtitles_ru_surrounding_words,1,3,grep,grep -E -an \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.6610260009765625,278,LC_ALL=en_US.UTF-8 -subtitles_ru_surrounding_words,1,3,ag (ASCII),ag -s \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.4094629287719727,, -subtitles_ru_surrounding_words,1,3,ag (ASCII),ag -s \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.409822702407837,, -subtitles_ru_surrounding_words,1,3,ag (ASCII),ag -s \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.4094691276550293,, -subtitles_ru_surrounding_words,1,3,ucg (ASCII),ucg --nosmart-case \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.866976261138916,, -subtitles_ru_surrounding_words,1,3,ucg (ASCII),ucg --nosmart-case \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.8666067123413086,, -subtitles_ru_surrounding_words,1,3,ucg (ASCII),ucg --nosmart-case \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.865297317504883,, -subtitles_ru_surrounding_words,1,3,grep (ASCII),grep -E -an \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.602109670639038,,LC_ALL=C -subtitles_ru_surrounding_words,1,3,grep (ASCII),grep -E -an \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.598329782485962,,LC_ALL=C -subtitles_ru_surrounding_words,1,3,grep (ASCII),grep -E -an \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.5975282192230225,,LC_ALL=C diff --git a/benchsuite/runs/2016-09-17-ubuntu1604-ec2/summary b/benchsuite/runs/2016-09-17-ubuntu1604-ec2/summary deleted file mode 100644 index 4877cd3..0000000 --- a/benchsuite/runs/2016-09-17-ubuntu1604-ec2/summary +++ /dev/null @@ -1,226 +0,0 @@ -linux_alternates (pattern: ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT) -------------------------------------------------------------------------- -rg (ignore) 0.322 +/- 0.042 (lines: 68) -ag (ignore) 1.754 +/- 0.006 (lines: 68) -git grep (ignore) 0.502 +/- 0.004 (lines: 68) -rg (whitelist)* 0.197 +/- 0.001 (lines: 68)* -ucg (whitelist) 0.217 +/- 0.004 (lines: 68) - -linux_alternates_casei (pattern: ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT) -------------------------------------------------------------------------------- -rg (ignore) 0.372 +/- 0.096 (lines: 160) -ag (ignore) 1.965 +/- 0.009 (lines: 160) -git grep (ignore) 2.022 +/- 0.001 (lines: 160) -rg (whitelist)* 0.222 +/- 0.001 (lines: 160)* -ucg (whitelist) 0.524 +/- 0.005 (lines: 160) - -linux_literal (pattern: PM_RESUME) ----------------------------------- -rg (ignore) 0.348 +/- 0.054 (lines: 16) -rg (ignore) (mmap) 1.597 +/- 0.013 (lines: 16) -ag (ignore) (mmap) 1.590 +/- 0.003 (lines: 16) -pt (ignore) 0.455 +/- 0.015 (lines: 16) -sift (ignore) 0.630 +/- 0.001 (lines: 16) -git grep (ignore) 0.344 +/- 0.004 (lines: 16) -rg (whitelist)* 0.253 +/- 0.077 (lines: 16) -ucg (whitelist) 0.222 +/- 0.005 (lines: 16)* - -linux_literal_casei (pattern: PM_RESUME) ----------------------------------------- -rg (ignore) 0.423 +/- 0.118 (lines: 370) -rg (ignore) (mmap) 1.615 +/- 0.010 (lines: 370) -ag (ignore) (mmap) 1.601 +/- 0.027 (lines: 370) -sift (ignore) 0.804 +/- 0.003 (lines: 370) -git grep (ignore) 0.346 +/- 0.004 (lines: 370) -rg (whitelist) 0.234 +/- 0.032 (lines: 370) -ucg (whitelist)* 0.220 +/- 0.008 (lines: 370)* - -linux_literal_default (pattern: PM_RESUME) ------------------------------------------- -rg 0.277 +/- 0.002 (lines: 16) -ag 1.594 +/- 0.008 (lines: 16) -ucg* 0.219 +/- 0.007 (lines: 16)* -pt 0.439 +/- 0.024 (lines: 16) -sift 0.344 +/- 0.014 (lines: 16) -git grep 0.344 +/- 0.005 (lines: 16) - -linux_no_literal (pattern: \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}) ------------------------------------------------------------------ -rg (ignore) 0.581 +/- 0.002 (lines: 490) -rg (ignore) (ASCII) 0.408 +/- 0.008 (lines: 490) -ag (ignore) (ASCII) 2.329 +/- 0.019 (lines: 766) -sift (ignore) (ASCII) 25.756 +/- 0.113 (lines: 491) -git grep (ignore) 26.344 +/- 0.005 (lines: 490) -git grep (ignore) (ASCII) 4.152 +/- 0.004 (lines: 490) -rg (whitelist) 0.502 +/- 0.008 (lines: 419) -rg (whitelist) (ASCII)* 0.346 +/- 0.035 (lines: 419)* -ucg (whitelist) (ASCII) 1.127 +/- 0.001 (lines: 416) - -linux_re_literal_suffix (pattern: [A-Z]+_RESUME) ------------------------------------------------- -rg (ignore) 0.398 +/- 0.046 (lines: 1652) -ag (ignore) 1.889 +/- 0.011 (lines: 1652) -sift (ignore) 10.260 +/- 0.246 (lines: 1652) -git grep (ignore) 1.107 +/- 0.001 (lines: 1652) -rg (whitelist)* 0.206 +/- 0.001 (lines: 1630)* -ucg (whitelist) 0.301 +/- 0.001 (lines: 1630) - -linux_unicode_greek (pattern: \p{Greek}) ----------------------------------------- -rg* 0.470 +/- 0.049 (lines: 23)* -sift 7.715 +/- 0.125 (lines: 23) - -linux_unicode_greek_casei (pattern: \p{Greek}) ----------------------------------------------- -rg 0.415 +/- 0.019 (lines: 103) -sift* 0.002 +/- 0.000 (lines: 0)* - -linux_unicode_word (pattern: \wAh) ----------------------------------- -rg (ignore) 0.350 +/- 0.084 (lines: 186) -rg (ignore) (ASCII) 0.354 +/- 0.075 (lines: 174) -ag (ignore) (ASCII) 1.770 +/- 0.005 (lines: 174) -sift (ignore) (ASCII) 11.016 +/- 0.138 (lines: 174) -git grep (ignore) 13.051 +/- 0.028 (lines: 186) -git grep (ignore) (ASCII) 2.988 +/- 0.001 (lines: 174) -rg (whitelist) 0.242 +/- 0.040 (lines: 180) -rg (whitelist) (ASCII)* 0.226 +/- 0.012 (lines: 168) -ucg (ASCII) 0.225 +/- 0.002 (lines: 168)* - -linux_word (pattern: PM_RESUME) -------------------------------- -rg (ignore) 0.329 +/- 0.035 (lines: 6) -ag (ignore) 1.598 +/- 0.016 (lines: 6) -sift (ignore) 7.759 +/- 0.117 (lines: 6) -git grep (ignore) 0.344 +/- 0.008 (lines: 6) -rg (whitelist)* 0.269 +/- 0.059 (lines: 6) -ucg (whitelist) 0.221 +/- 0.002 (lines: 6)* - -subtitles_en_alternate (pattern: Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty) ---------------------------------------------------------------------------------------------------------------- -rg (lines) 0.620 +/- 0.002 (lines: 848) -ag (lines) 3.756 +/- 0.000 (lines: 848) -ucg (lines) 1.447 +/- 0.003 (lines: 848) -grep (lines) 3.411 +/- 0.002 (lines: 848) -rg* 0.290 +/- 0.000 (lines: 848)* -grep 2.955 +/- 0.001 (lines: 848) - -subtitles_en_alternate_casei (pattern: Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty) ---------------------------------------------------------------------------------------------------------------------- -ag (ASCII) 5.171 +/- 0.003 (lines: 862) -ucg (ASCII) 3.417 +/- 0.001 (lines: 862) -grep (ASCII) 4.529 +/- 0.003 (lines: 862) -rg* 2.722 +/- 0.000 (lines: 862)* -grep 5.121 +/- 0.001 (lines: 862) - -subtitles_en_literal (pattern: Sherlock Holmes) ------------------------------------------------ -rg* 0.268 +/- 0.000 (lines: 629)* -pt 3.437 +/- 0.003 (lines: 629) -sift 0.327 +/- 0.001 (lines: 629) -grep 0.519 +/- 0.002 (lines: 629) -rg (lines) 0.595 +/- 0.001 (lines: 629) -ag (lines) 2.730 +/- 0.001 (lines: 629) -ucg (lines) 0.776 +/- 0.000 (lines: 629) -pt (lines) 3.434 +/- 0.001 (lines: 629) -sift (lines) 0.757 +/- 0.003 (lines: 629) -grep (lines) 0.971 +/- 0.001 (lines: 629) - -subtitles_en_literal_casei (pattern: Sherlock Holmes) ------------------------------------------------------ -rg* 0.366 +/- 0.001 (lines: 642)* -grep 4.083 +/- 0.005 (lines: 642) -grep (ASCII) 0.614 +/- 0.001 (lines: 642) -rg (lines) 0.695 +/- 0.001 (lines: 642) -ag (lines) (ASCII) 2.772 +/- 0.001 (lines: 642) -ucg (lines) (ASCII) 0.805 +/- 0.002 (lines: 642) - -subtitles_en_literal_word (pattern: Sherlock Holmes) ----------------------------------------------------- -rg (ASCII)* 0.596 +/- 0.001 (lines: 629)* -ag (ASCII) 2.730 +/- 0.002 (lines: 629) -ucg (ASCII) 0.781 +/- 0.003 (lines: 629) -grep (ASCII) 0.977 +/- 0.003 (lines: 629) -rg 0.597 +/- 0.001 (lines: 629) -grep 0.979 +/- 0.002 (lines: 629) - -subtitles_en_no_literal (pattern: \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}) ----------------------------------------------------------------------------------------- -rg 2.777 +/- 0.005 (lines: 13) -rg (ASCII)* 2.540 +/- 0.000 (lines: 13)* -ag (ASCII) 10.073 +/- 0.002 (lines: 48) -ucg (ASCII) 7.734 +/- 0.002 (lines: 13) -grep (ASCII) 4.412 +/- 0.002 (lines: 13) - -subtitles_en_surrounding_words (pattern: \w+\s+Holmes\s+\w+) ------------------------------------------------------------- -rg 0.605 +/- 0.000 (lines: 317) -grep 1.285 +/- 0.001 (lines: 317) -rg (ASCII)* 0.601 +/- 0.000 (lines: 317)* -ag (ASCII) 11.665 +/- 0.008 (lines: 323) -ucg (ASCII) 4.651 +/- 0.001 (lines: 317) -grep (ASCII) 1.275 +/- 0.001 (lines: 317) - -subtitles_ru_alternate (pattern: Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти) ------------------------------------------------------------------------------------------------------------ -rg (lines) 1.903 +/- 0.001 (lines: 691) -ag (lines) 5.891 +/- 0.001 (lines: 691) -ucg (lines) 2.754 +/- 0.002 (lines: 691) -grep (lines) 8.511 +/- 0.004 (lines: 691) -rg* 1.301 +/- 0.002 (lines: 691)* -grep 7.984 +/- 0.004 (lines: 691) - -subtitles_ru_alternate_casei (pattern: Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти) ------------------------------------------------------------------------------------------------------------------ -ag (ASCII) 5.894 +/- 0.007 (lines: 691) -ucg (ASCII)* 2.747 +/- 0.008 (lines: 691)* -grep (ASCII) 8.579 +/- 0.017 (lines: 691) -rg 4.832 +/- 0.002 (lines: 735) -grep 8.723 +/- 0.001 (lines: 735) - -subtitles_ru_literal (pattern: Шерлок Холмс) --------------------------------------------- -rg* 0.326 +/- 0.001 (lines: 583)* -pt 12.919 +/- 0.012 (lines: 583) -sift 16.421 +/- 0.015 (lines: 583) -grep 0.789 +/- 0.003 (lines: 583) -rg (lines) 0.927 +/- 0.002 (lines: 583) -ag (lines) 4.481 +/- 0.003 (lines: 583) -ucg (lines) 1.774 +/- 0.001 (lines: 583) -pt (lines) 12.939 +/- 0.010 (lines: 583) -sift (lines) 17.184 +/- 0.007 (lines: 583) -grep (lines) 1.300 +/- 0.002 (lines: 583) - -subtitles_ru_literal_casei (pattern: Шерлок Холмс) --------------------------------------------------- -rg 1.133 +/- 0.002 (lines: 604) -grep 8.190 +/- 0.005 (lines: 604) -grep (ASCII) 0.784 +/- 0.001 (lines: 583) -rg (lines) 1.733 +/- 0.001 (lines: 604) -ag (lines) (ASCII)* 0.730 +/- 0.001 (lines: 0)* -ucg (lines) (ASCII) 1.775 +/- 0.002 (lines: 583) - -subtitles_ru_literal_word (pattern: Шерлок Холмс) -------------------------------------------------- -rg (ASCII)* 0.325 +/- 0.000 (lines: 0)* -ag (ASCII) 0.752 +/- 0.000 (lines: 0) -ucg (ASCII) 1.781 +/- 0.006 (lines: 583) -grep (ASCII) 1.304 +/- 0.003 (lines: 583) -rg 0.929 +/- 0.000 (lines: 579) -grep 1.302 +/- 0.001 (lines: 579) - -subtitles_ru_no_literal (pattern: \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}) ----------------------------------------------------------------------------------------- -rg 4.904 +/- 0.009 (lines: 41) -rg (ASCII) 3.972 +/- 0.000 (lines: 0) -ag (ASCII)* 2.395 +/- 0.003 (lines: 0)* -ucg (ASCII) 2.895 +/- 0.003 (lines: 0) -grep (ASCII) 2.484 +/- 0.001 (lines: 0) - -subtitles_ru_surrounding_words (pattern: \w+\s+Холмс\s+\w+) ------------------------------------------------------------ -rg* 0.956 +/- 0.000 (lines: 278)* -grep 1.662 +/- 0.001 (lines: 278) -ag (ASCII) 2.410 +/- 0.000 (lines: 0) -ucg (ASCII) 2.866 +/- 0.001 (lines: 0) -grep (ASCII) 1.599 +/- 0.002 (lines: 0) diff --git a/benchsuite/runs/2016-09-20-ubuntu1604-ec2/README.SETUP b/benchsuite/runs/2016-09-20-ubuntu1604-ec2/README.SETUP deleted file mode 100644 index 7bc3938..0000000 --- a/benchsuite/runs/2016-09-20-ubuntu1604-ec2/README.SETUP +++ /dev/null @@ -1,93 +0,0 @@ -Ubuntu 16.04 HVM AMI -c3.2xlarge, Xeon E5-2680, 2.8 GHz, 8 CPUs, 16 GB memory, 80 GB SSD - -# Generic system setup - -mkfs.ext4 /dev/xvdb -sudo mount /dev/xvdb /mnt -sudo chown ubuntu /mnt -sudo apt-get update -sudo apt-get install \ # for building Linux kernel - make gcc bc -sudo apt-get install \ # for the silver searcher - automake pkg-config zlib1g-dev liblzma-dev libpcre3 libpcre3-dev -sudo apt-get install \ # for Universal Code Grep - libtool libpcre2-8-0 libpcre2-dev -sudo apt-get install \ # for sift and the platinum searcher - go - -# Get benchmark corpora - -cd /mnt -mkdir /mnt/bench -git clone git://github.com/BurntSushi/ripgrep -cd ripgrep/benchsuite -./benchsuite --dir /mnt/bench/ --download all # takes around 15 minutes - -# Install search tools -mkdir /mnt/bin/ - -## ripgrep - -cd /mnt -mkdir ripgrep-bin -cd ripgrep-bin -curl -LO 'https://github.com/BurntSushi/ripgrep/releases/download/0.1.2/ripgrep-0.1.2-x86_64-unknown-linux-musl.tar.gz' -cp ripgrep-0.1.2-x86_64-unknown-linux-musl/rg /mnt/bin/ - -## The Silver Searcher - -cd /mnt -git clone git://github.com/ggreer/the_silver_searcher -cd the_silver_searcher -git checkout cda635 -./build.sh -cp ag /mnt/bin/ - -## Universal Code Grep - -cd /mnt -git clone git://github.com/gvansickle/ucg -cd ucg -git checkout 487bfb -autoreconf -i -./configure -make -cp ucg /mnt/bin/ - -## The Platinum Searcher - -export GOPATH=/mnt/go -go get github.com/monochromegane/the_platinum_searcher -cd /mnt/go/src/github.com/monochromegane/the_platinum_searcher -git checkout 509368 -go install github.com/monochromegane/the_platinum_searcher/cmd/... -cp /mnt/go/bin/pt /mnt/bin/ - -## Sift - -export GOPATH=/mnt/go -go get github.com/svent/sift -cd /mnt/go/src/github.com/svent/sift -git checkout 2d175c -go install -cp /mnt/go/bin/sift /mnt/bin/ - -## 'git grep' and GNU grep - -They are part of the standard Ubuntu install, and are pretty recent (as of -September 2016). - -$ git --version -git version 2.7.4 -$ grep --version -grep (GNU grep) 2.25 - - -# Running benchmarks - -export PATH="/mnt/bin:$PATH" -cd /mnt/ripgrep/benchsuite -./benchsuite \ - --dir /mnt/bench/ --raw /mnt/bench/raw.csv --warmup-iter 3 --bench-iter 10 -# The above took around 120 minutes to run to completion. diff --git a/benchsuite/runs/2016-09-20-ubuntu1604-ec2/raw.csv b/benchsuite/runs/2016-09-20-ubuntu1604-ec2/raw.csv deleted file mode 100644 index 2f1cb00..0000000 --- a/benchsuite/runs/2016-09-20-ubuntu1604-ec2/raw.csv +++ /dev/null @@ -1,1611 +0,0 @@ -benchmark,warmup_iter,iter,name,command,duration,lines,env -linux_alternates,3,10,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.47386884689331055,68, -linux_alternates,3,10,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.4676964282989502,68, -linux_alternates,3,10,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.2977464199066162,68, -linux_alternates,3,10,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.404477596282959,68, -linux_alternates,3,10,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.29970765113830566,68, -linux_alternates,3,10,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.2981560230255127,68, -linux_alternates,3,10,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.29827141761779785,68, -linux_alternates,3,10,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.2970547676086426,68, -linux_alternates,3,10,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.37766170501708984,68, -linux_alternates,3,10,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.2981750965118408,68, -linux_alternates,3,10,ag (ignore),ag -s ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,1.745070219039917,68, -linux_alternates,3,10,ag (ignore),ag -s ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,1.743051290512085,68, -linux_alternates,3,10,ag (ignore),ag -s ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,1.7471156120300293,68, -linux_alternates,3,10,ag (ignore),ag -s ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,1.7482519149780273,68, -linux_alternates,3,10,ag (ignore),ag -s ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,1.7504711151123047,68, -linux_alternates,3,10,ag (ignore),ag -s ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,1.7388739585876465,68, -linux_alternates,3,10,ag (ignore),ag -s ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,1.751807451248169,68, -linux_alternates,3,10,ag (ignore),ag -s ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,1.7407019138336182,68, -linux_alternates,3,10,ag (ignore),ag -s ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,1.7513477802276611,68, -linux_alternates,3,10,ag (ignore),ag -s ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,1.7503643035888672,68, -linux_alternates,3,10,git grep (ignore),git grep -E -I -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.4976229667663574,68,LC_ALL=C -linux_alternates,3,10,git grep (ignore),git grep -E -I -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.5058624744415283,68,LC_ALL=C -linux_alternates,3,10,git grep (ignore),git grep -E -I -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.5003554821014404,68,LC_ALL=C -linux_alternates,3,10,git grep (ignore),git grep -E -I -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.5036265850067139,68,LC_ALL=C -linux_alternates,3,10,git grep (ignore),git grep -E -I -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.502265453338623,68,LC_ALL=C -linux_alternates,3,10,git grep (ignore),git grep -E -I -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.5051944255828857,68,LC_ALL=C -linux_alternates,3,10,git grep (ignore),git grep -E -I -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.49764204025268555,68,LC_ALL=C -linux_alternates,3,10,git grep (ignore),git grep -E -I -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.5026199817657471,68,LC_ALL=C -linux_alternates,3,10,git grep (ignore),git grep -E -I -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.500784158706665,68,LC_ALL=C -linux_alternates,3,10,git grep (ignore),git grep -E -I -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.4986872673034668,68,LC_ALL=C -linux_alternates,3,10,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.19666719436645508,68, -linux_alternates,3,10,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.20122385025024414,68, -linux_alternates,3,10,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.2921123504638672,68, -linux_alternates,3,10,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.19991230964660645,68, -linux_alternates,3,10,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.20190691947937012,68, -linux_alternates,3,10,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.23188090324401855,68, -linux_alternates,3,10,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.2041609287261963,68, -linux_alternates,3,10,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.19266295433044434,68, -linux_alternates,3,10,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.24373841285705566,68, -linux_alternates,3,10,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.19818353652954102,68, -linux_alternates,3,10,ucg (whitelist),ucg --nosmart-case ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.21015572547912598,68, -linux_alternates,3,10,ucg (whitelist),ucg --nosmart-case ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.22674226760864258,68, -linux_alternates,3,10,ucg (whitelist),ucg --nosmart-case ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.21504473686218262,68, -linux_alternates,3,10,ucg (whitelist),ucg --nosmart-case ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.22454237937927246,68, -linux_alternates,3,10,ucg (whitelist),ucg --nosmart-case ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.2039196491241455,68, -linux_alternates,3,10,ucg (whitelist),ucg --nosmart-case ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.2037363052368164,68, -linux_alternates,3,10,ucg (whitelist),ucg --nosmart-case ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.20755791664123535,68, -linux_alternates,3,10,ucg (whitelist),ucg --nosmart-case ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.21857881546020508,68, -linux_alternates,3,10,ucg (whitelist),ucg --nosmart-case ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.2158210277557373,68, -linux_alternates,3,10,ucg (whitelist),ucg --nosmart-case ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.213883638381958,68, -linux_alternates_casei,3,10,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.5118546485900879,160, -linux_alternates_casei,3,10,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.4563937187194824,160, -linux_alternates_casei,3,10,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.3091299533843994,160, -linux_alternates_casei,3,10,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.3657255172729492,160, -linux_alternates_casei,3,10,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.31900572776794434,160, -linux_alternates_casei,3,10,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.31780076026916504,160, -linux_alternates_casei,3,10,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.4655437469482422,160, -linux_alternates_casei,3,10,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.4731638431549072,160, -linux_alternates_casei,3,10,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.31702089309692383,160, -linux_alternates_casei,3,10,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.37751269340515137,160, -linux_alternates_casei,3,10,ag (ignore),ag -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,1.9786202907562256,160, -linux_alternates_casei,3,10,ag (ignore),ag -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,1.9616754055023193,160, -linux_alternates_casei,3,10,ag (ignore),ag -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,1.982335090637207,160, -linux_alternates_casei,3,10,ag (ignore),ag -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,1.9551584720611572,160, -linux_alternates_casei,3,10,ag (ignore),ag -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,1.9577994346618652,160, -linux_alternates_casei,3,10,ag (ignore),ag -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,1.971240758895874,160, -linux_alternates_casei,3,10,ag (ignore),ag -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,1.9659252166748047,160, -linux_alternates_casei,3,10,ag (ignore),ag -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,1.968651294708252,160, -linux_alternates_casei,3,10,ag (ignore),ag -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,1.974630355834961,160, -linux_alternates_casei,3,10,ag (ignore),ag -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,1.9673101902008057,160, -linux_alternates_casei,3,10,git grep (ignore),git grep -E -I -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,2.0195815563201904,160,LC_ALL=C -linux_alternates_casei,3,10,git grep (ignore),git grep -E -I -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,2.014780044555664,160,LC_ALL=C -linux_alternates_casei,3,10,git grep (ignore),git grep -E -I -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,2.0152857303619385,160,LC_ALL=C -linux_alternates_casei,3,10,git grep (ignore),git grep -E -I -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,2.021533727645874,160,LC_ALL=C -linux_alternates_casei,3,10,git grep (ignore),git grep -E -I -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,2.008901596069336,160,LC_ALL=C -linux_alternates_casei,3,10,git grep (ignore),git grep -E -I -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,2.017594575881958,160,LC_ALL=C -linux_alternates_casei,3,10,git grep (ignore),git grep -E -I -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,2.030247449874878,160,LC_ALL=C -linux_alternates_casei,3,10,git grep (ignore),git grep -E -I -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,2.0156710147857666,160,LC_ALL=C -linux_alternates_casei,3,10,git grep (ignore),git grep -E -I -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,2.0224251747131348,160,LC_ALL=C -linux_alternates_casei,3,10,git grep (ignore),git grep -E -I -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,2.01462459564209,160,LC_ALL=C -linux_alternates_casei,3,10,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.22264957427978516,160, -linux_alternates_casei,3,10,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.22289133071899414,160, -linux_alternates_casei,3,10,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.22011518478393555,160, -linux_alternates_casei,3,10,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.22271180152893066,160, -linux_alternates_casei,3,10,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.22096776962280273,160, -linux_alternates_casei,3,10,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.22350811958312988,160, -linux_alternates_casei,3,10,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.22304296493530273,160, -linux_alternates_casei,3,10,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.22333812713623047,160, -linux_alternates_casei,3,10,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.2226696014404297,160, -linux_alternates_casei,3,10,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.2225027084350586,160, -linux_alternates_casei,3,10,ucg (whitelist),ucg -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.5201499462127686,160, -linux_alternates_casei,3,10,ucg (whitelist),ucg -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.5199308395385742,160, -linux_alternates_casei,3,10,ucg (whitelist),ucg -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.5204341411590576,160, -linux_alternates_casei,3,10,ucg (whitelist),ucg -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.5242149829864502,160, -linux_alternates_casei,3,10,ucg (whitelist),ucg -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.5222067832946777,160, -linux_alternates_casei,3,10,ucg (whitelist),ucg -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.5239078998565674,160, -linux_alternates_casei,3,10,ucg (whitelist),ucg -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.5225164890289307,160, -linux_alternates_casei,3,10,ucg (whitelist),ucg -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.5211355686187744,160, -linux_alternates_casei,3,10,ucg (whitelist),ucg -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.521998405456543,160, -linux_alternates_casei,3,10,ucg (whitelist),ucg -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.5194001197814941,160, -linux_literal,3,10,rg (ignore),rg -n PM_RESUME,0.2887847423553467,16, -linux_literal,3,10,rg (ignore),rg -n PM_RESUME,0.33100366592407227,16, -linux_literal,3,10,rg (ignore),rg -n PM_RESUME,0.29135560989379883,16, -linux_literal,3,10,rg (ignore),rg -n PM_RESUME,0.35103440284729004,16, -linux_literal,3,10,rg (ignore),rg -n PM_RESUME,0.28871941566467285,16, -linux_literal,3,10,rg (ignore),rg -n PM_RESUME,0.41626620292663574,16, -linux_literal,3,10,rg (ignore),rg -n PM_RESUME,0.4109630584716797,16, -linux_literal,3,10,rg (ignore),rg -n PM_RESUME,0.28783345222473145,16, -linux_literal,3,10,rg (ignore),rg -n PM_RESUME,0.2896847724914551,16, -linux_literal,3,10,rg (ignore),rg -n PM_RESUME,0.3816063404083252,16, -linux_literal,3,10,rg (ignore) (mmap),rg -n --mmap PM_RESUME,1.6185925006866455,16, -linux_literal,3,10,rg (ignore) (mmap),rg -n --mmap PM_RESUME,1.6278767585754395,16, -linux_literal,3,10,rg (ignore) (mmap),rg -n --mmap PM_RESUME,1.6153473854064941,16, -linux_literal,3,10,rg (ignore) (mmap),rg -n --mmap PM_RESUME,1.6009879112243652,16, -linux_literal,3,10,rg (ignore) (mmap),rg -n --mmap PM_RESUME,1.6033079624176025,16, -linux_literal,3,10,rg (ignore) (mmap),rg -n --mmap PM_RESUME,1.597747564315796,16, -linux_literal,3,10,rg (ignore) (mmap),rg -n --mmap PM_RESUME,1.6077642440795898,16, -linux_literal,3,10,rg (ignore) (mmap),rg -n --mmap PM_RESUME,1.6068522930145264,16, -linux_literal,3,10,rg (ignore) (mmap),rg -n --mmap PM_RESUME,1.6185357570648193,16, -linux_literal,3,10,rg (ignore) (mmap),rg -n --mmap PM_RESUME,1.6097495555877686,16, -linux_literal,3,10,ag (ignore) (mmap),ag -s PM_RESUME,1.5874614715576172,16, -linux_literal,3,10,ag (ignore) (mmap),ag -s PM_RESUME,1.6032404899597168,16, -linux_literal,3,10,ag (ignore) (mmap),ag -s PM_RESUME,1.5708537101745605,16, -linux_literal,3,10,ag (ignore) (mmap),ag -s PM_RESUME,1.5849754810333252,16, -linux_literal,3,10,ag (ignore) (mmap),ag -s PM_RESUME,1.5937259197235107,16, -linux_literal,3,10,ag (ignore) (mmap),ag -s PM_RESUME,1.5755681991577148,16, -linux_literal,3,10,ag (ignore) (mmap),ag -s PM_RESUME,1.606102705001831,16, -linux_literal,3,10,ag (ignore) (mmap),ag -s PM_RESUME,1.5942778587341309,16, -linux_literal,3,10,ag (ignore) (mmap),ag -s PM_RESUME,1.5798444747924805,16, -linux_literal,3,10,ag (ignore) (mmap),ag -s PM_RESUME,1.587292194366455,16, -linux_literal,3,10,pt (ignore),pt PM_RESUME,0.48366618156433105,16, -linux_literal,3,10,pt (ignore),pt PM_RESUME,0.43807315826416016,16, -linux_literal,3,10,pt (ignore),pt PM_RESUME,0.4620192050933838,16, -linux_literal,3,10,pt (ignore),pt PM_RESUME,0.4109156131744385,16, -linux_literal,3,10,pt (ignore),pt PM_RESUME,0.4734470844268799,16, -linux_literal,3,10,pt (ignore),pt PM_RESUME,0.4730203151702881,16, -linux_literal,3,10,pt (ignore),pt PM_RESUME,0.46596622467041016,16, -linux_literal,3,10,pt (ignore),pt PM_RESUME,0.43018555641174316,16, -linux_literal,3,10,pt (ignore),pt PM_RESUME,0.48219823837280273,16, -linux_literal,3,10,pt (ignore),pt PM_RESUME,0.43694376945495605,16, -linux_literal,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git PM_RESUME,0.6309304237365723,16, -linux_literal,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git PM_RESUME,0.6273376941680908,16, -linux_literal,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git PM_RESUME,0.6281638145446777,16, -linux_literal,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git PM_RESUME,0.6282968521118164,16, -linux_literal,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git PM_RESUME,0.6298778057098389,16, -linux_literal,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git PM_RESUME,0.6303853988647461,16, -linux_literal,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git PM_RESUME,0.6214172840118408,16, -linux_literal,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git PM_RESUME,0.6326169967651367,16, -linux_literal,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git PM_RESUME,0.6357946395874023,16, -linux_literal,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git PM_RESUME,0.6349425315856934,16, -linux_literal,3,10,git grep (ignore),git grep -I -n PM_RESUME,0.3352987766265869,16,LC_ALL=C -linux_literal,3,10,git grep (ignore),git grep -I -n PM_RESUME,0.34267115592956543,16,LC_ALL=C -linux_literal,3,10,git grep (ignore),git grep -I -n PM_RESUME,0.33582019805908203,16,LC_ALL=C -linux_literal,3,10,git grep (ignore),git grep -I -n PM_RESUME,0.3533494472503662,16,LC_ALL=C -linux_literal,3,10,git grep (ignore),git grep -I -n PM_RESUME,0.35305285453796387,16,LC_ALL=C -linux_literal,3,10,git grep (ignore),git grep -I -n PM_RESUME,0.35210490226745605,16,LC_ALL=C -linux_literal,3,10,git grep (ignore),git grep -I -n PM_RESUME,0.3439147472381592,16,LC_ALL=C -linux_literal,3,10,git grep (ignore),git grep -I -n PM_RESUME,0.3385200500488281,16,LC_ALL=C -linux_literal,3,10,git grep (ignore),git grep -I -n PM_RESUME,0.34418511390686035,16,LC_ALL=C -linux_literal,3,10,git grep (ignore),git grep -I -n PM_RESUME,0.351276159286499,16,LC_ALL=C -linux_literal,3,10,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.21218633651733398,16, -linux_literal,3,10,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.2074875831604004,16, -linux_literal,3,10,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.2121737003326416,16, -linux_literal,3,10,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.29766225814819336,16, -linux_literal,3,10,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.20844221115112305,16, -linux_literal,3,10,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.21107196807861328,16, -linux_literal,3,10,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.3164327144622803,16, -linux_literal,3,10,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.2020113468170166,16, -linux_literal,3,10,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.21297645568847656,16, -linux_literal,3,10,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.20153403282165527,16, -linux_literal,3,10,ucg (whitelist),ucg --nosmart-case PM_RESUME,0.21353983879089355,16, -linux_literal,3,10,ucg (whitelist),ucg --nosmart-case PM_RESUME,0.20673179626464844,16, -linux_literal,3,10,ucg (whitelist),ucg --nosmart-case PM_RESUME,0.21759939193725586,16, -linux_literal,3,10,ucg (whitelist),ucg --nosmart-case PM_RESUME,0.2182610034942627,16, -linux_literal,3,10,ucg (whitelist),ucg --nosmart-case PM_RESUME,0.21338224411010742,16, -linux_literal,3,10,ucg (whitelist),ucg --nosmart-case PM_RESUME,0.2172555923461914,16, -linux_literal,3,10,ucg (whitelist),ucg --nosmart-case PM_RESUME,0.2167196273803711,16, -linux_literal,3,10,ucg (whitelist),ucg --nosmart-case PM_RESUME,0.22050833702087402,16, -linux_literal,3,10,ucg (whitelist),ucg --nosmart-case PM_RESUME,0.22791433334350586,16, -linux_literal,3,10,ucg (whitelist),ucg --nosmart-case PM_RESUME,0.22888803482055664,16, -linux_literal_casei,3,10,rg (ignore),rg -n -i PM_RESUME,0.3006107807159424,370, -linux_literal_casei,3,10,rg (ignore),rg -n -i PM_RESUME,0.300311803817749,370, -linux_literal_casei,3,10,rg (ignore),rg -n -i PM_RESUME,0.29694652557373047,370, -linux_literal_casei,3,10,rg (ignore),rg -n -i PM_RESUME,0.41213250160217285,370, -linux_literal_casei,3,10,rg (ignore),rg -n -i PM_RESUME,0.2940239906311035,370, -linux_literal_casei,3,10,rg (ignore),rg -n -i PM_RESUME,0.5161991119384766,370, -linux_literal_casei,3,10,rg (ignore),rg -n -i PM_RESUME,0.38535594940185547,370, -linux_literal_casei,3,10,rg (ignore),rg -n -i PM_RESUME,0.3468937873840332,370, -linux_literal_casei,3,10,rg (ignore),rg -n -i PM_RESUME,0.3020455837249756,370, -linux_literal_casei,3,10,rg (ignore),rg -n -i PM_RESUME,0.2997910976409912,370, -linux_literal_casei,3,10,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,1.6084694862365723,370, -linux_literal_casei,3,10,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,1.606147289276123,370, -linux_literal_casei,3,10,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,1.62626051902771,370, -linux_literal_casei,3,10,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,1.6127331256866455,370, -linux_literal_casei,3,10,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,1.6354174613952637,370, -linux_literal_casei,3,10,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,1.6024584770202637,370, -linux_literal_casei,3,10,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,1.611799716949463,370, -linux_literal_casei,3,10,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,1.5951638221740723,370, -linux_literal_casei,3,10,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,1.6110625267028809,370, -linux_literal_casei,3,10,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,1.61025071144104,370, -linux_literal_casei,3,10,ag (ignore) (mmap),ag -i PM_RESUME,1.61818528175354,370, -linux_literal_casei,3,10,ag (ignore) (mmap),ag -i PM_RESUME,1.6345157623291016,370, -linux_literal_casei,3,10,ag (ignore) (mmap),ag -i PM_RESUME,1.5905261039733887,370, -linux_literal_casei,3,10,ag (ignore) (mmap),ag -i PM_RESUME,1.6204230785369873,370, -linux_literal_casei,3,10,ag (ignore) (mmap),ag -i PM_RESUME,1.5921993255615234,370, -linux_literal_casei,3,10,ag (ignore) (mmap),ag -i PM_RESUME,1.5896248817443848,370, -linux_literal_casei,3,10,ag (ignore) (mmap),ag -i PM_RESUME,1.6044423580169678,370, -linux_literal_casei,3,10,ag (ignore) (mmap),ag -i PM_RESUME,1.611330509185791,370, -linux_literal_casei,3,10,ag (ignore) (mmap),ag -i PM_RESUME,1.6240627765655518,370, -linux_literal_casei,3,10,ag (ignore) (mmap),ag -i PM_RESUME,1.6050136089324951,370, -linux_literal_casei,3,10,pt (ignore),pt -i PM_RESUME,17.215137004852295,370, -linux_literal_casei,3,10,pt (ignore),pt -i PM_RESUME,17.027225255966187,370, -linux_literal_casei,3,10,pt (ignore),pt -i PM_RESUME,17.218045234680176,370, -linux_literal_casei,3,10,pt (ignore),pt -i PM_RESUME,17.382962942123413,370, -linux_literal_casei,3,10,pt (ignore),pt -i PM_RESUME,17.16927456855774,370, -linux_literal_casei,3,10,pt (ignore),pt -i PM_RESUME,17.348739862442017,370, -linux_literal_casei,3,10,pt (ignore),pt -i PM_RESUME,17.116779565811157,370, -linux_literal_casei,3,10,pt (ignore),pt -i PM_RESUME,17.035597562789917,370, -linux_literal_casei,3,10,pt (ignore),pt -i PM_RESUME,17.179709911346436,370, -linux_literal_casei,3,10,pt (ignore),pt -i PM_RESUME,17.351134777069092,370, -linux_literal_casei,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git PM_RESUME,0.7961351871490479,370, -linux_literal_casei,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git PM_RESUME,0.8030610084533691,370, -linux_literal_casei,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git PM_RESUME,0.803156852722168,370, -linux_literal_casei,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git PM_RESUME,0.8085391521453857,370, -linux_literal_casei,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git PM_RESUME,0.8109989166259766,370, -linux_literal_casei,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git PM_RESUME,0.8001055717468262,370, -linux_literal_casei,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git PM_RESUME,0.8120794296264648,370, -linux_literal_casei,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git PM_RESUME,0.8061761856079102,370, -linux_literal_casei,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git PM_RESUME,0.8085212707519531,370, -linux_literal_casei,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git PM_RESUME,0.7987847328186035,370, -linux_literal_casei,3,10,git grep (ignore),git grep -I -n -i PM_RESUME,0.34406495094299316,370,LC_ALL=C -linux_literal_casei,3,10,git grep (ignore),git grep -I -n -i PM_RESUME,0.3358898162841797,370,LC_ALL=C -linux_literal_casei,3,10,git grep (ignore),git grep -I -n -i PM_RESUME,0.3549189567565918,370,LC_ALL=C -linux_literal_casei,3,10,git grep (ignore),git grep -I -n -i PM_RESUME,0.3384251594543457,370,LC_ALL=C -linux_literal_casei,3,10,git grep (ignore),git grep -I -n -i PM_RESUME,0.34453749656677246,370,LC_ALL=C -linux_literal_casei,3,10,git grep (ignore),git grep -I -n -i PM_RESUME,0.34092092514038086,370,LC_ALL=C -linux_literal_casei,3,10,git grep (ignore),git grep -I -n -i PM_RESUME,0.3376765251159668,370,LC_ALL=C -linux_literal_casei,3,10,git grep (ignore),git grep -I -n -i PM_RESUME,0.34916138648986816,370,LC_ALL=C -linux_literal_casei,3,10,git grep (ignore),git grep -I -n -i PM_RESUME,0.33722376823425293,370,LC_ALL=C -linux_literal_casei,3,10,git grep (ignore),git grep -I -n -i PM_RESUME,0.3521549701690674,370,LC_ALL=C -linux_literal_casei,3,10,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.22751879692077637,370, -linux_literal_casei,3,10,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.2776045799255371,370, -linux_literal_casei,3,10,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.21505451202392578,370, -linux_literal_casei,3,10,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.21794772148132324,370, -linux_literal_casei,3,10,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.21863842010498047,370, -linux_literal_casei,3,10,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.20025348663330078,370, -linux_literal_casei,3,10,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.21541285514831543,370, -linux_literal_casei,3,10,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.21509718894958496,370, -linux_literal_casei,3,10,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.21069550514221191,370, -linux_literal_casei,3,10,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.21798276901245117,370, -linux_literal_casei,3,10,ucg (whitelist),ucg -i PM_RESUME,0.21774601936340332,370, -linux_literal_casei,3,10,ucg (whitelist),ucg -i PM_RESUME,0.20911478996276855,370, -linux_literal_casei,3,10,ucg (whitelist),ucg -i PM_RESUME,0.22953128814697266,370, -linux_literal_casei,3,10,ucg (whitelist),ucg -i PM_RESUME,0.20992112159729004,370, -linux_literal_casei,3,10,ucg (whitelist),ucg -i PM_RESUME,0.2173295021057129,370, -linux_literal_casei,3,10,ucg (whitelist),ucg -i PM_RESUME,0.22140860557556152,370, -linux_literal_casei,3,10,ucg (whitelist),ucg -i PM_RESUME,0.2150726318359375,370, -linux_literal_casei,3,10,ucg (whitelist),ucg -i PM_RESUME,0.22086834907531738,370, -linux_literal_casei,3,10,ucg (whitelist),ucg -i PM_RESUME,0.21045351028442383,370, -linux_literal_casei,3,10,ucg (whitelist),ucg -i PM_RESUME,0.22116923332214355,370, -linux_literal_default,3,10,rg,rg PM_RESUME,0.547431468963623,16, -linux_literal_default,3,10,rg,rg PM_RESUME,0.2980644702911377,16, -linux_literal_default,3,10,rg,rg PM_RESUME,0.2759268283843994,16, -linux_literal_default,3,10,rg,rg PM_RESUME,0.47458386421203613,16, -linux_literal_default,3,10,rg,rg PM_RESUME,0.31407952308654785,16, -linux_literal_default,3,10,rg,rg PM_RESUME,0.27758288383483887,16, -linux_literal_default,3,10,rg,rg PM_RESUME,0.4621877670288086,16, -linux_literal_default,3,10,rg,rg PM_RESUME,0.2774538993835449,16, -linux_literal_default,3,10,rg,rg PM_RESUME,0.2882564067840576,16, -linux_literal_default,3,10,rg,rg PM_RESUME,0.27521324157714844,16, -linux_literal_default,3,10,ag,ag PM_RESUME,1.5812609195709229,16, -linux_literal_default,3,10,ag,ag PM_RESUME,1.6005668640136719,16, -linux_literal_default,3,10,ag,ag PM_RESUME,1.5730962753295898,16, -linux_literal_default,3,10,ag,ag PM_RESUME,1.592977523803711,16, -linux_literal_default,3,10,ag,ag PM_RESUME,1.5821592807769775,16, -linux_literal_default,3,10,ag,ag PM_RESUME,1.5887324810028076,16, -linux_literal_default,3,10,ag,ag PM_RESUME,1.5817389488220215,16, -linux_literal_default,3,10,ag,ag PM_RESUME,1.594618558883667,16, -linux_literal_default,3,10,ag,ag PM_RESUME,1.5992517471313477,16, -linux_literal_default,3,10,ag,ag PM_RESUME,1.596695899963379,16, -linux_literal_default,3,10,ucg,ucg PM_RESUME,0.21654176712036133,16, -linux_literal_default,3,10,ucg,ucg PM_RESUME,0.21590709686279297,16, -linux_literal_default,3,10,ucg,ucg PM_RESUME,0.2110304832458496,16, -linux_literal_default,3,10,ucg,ucg PM_RESUME,0.21798467636108398,16, -linux_literal_default,3,10,ucg,ucg PM_RESUME,0.23079442977905273,16, -linux_literal_default,3,10,ucg,ucg PM_RESUME,0.2108612060546875,16, -linux_literal_default,3,10,ucg,ucg PM_RESUME,0.22725200653076172,16, -linux_literal_default,3,10,ucg,ucg PM_RESUME,0.21680736541748047,16, -linux_literal_default,3,10,ucg,ucg PM_RESUME,0.21963763236999512,16, -linux_literal_default,3,10,ucg,ucg PM_RESUME,0.20926284790039062,16, -linux_literal_default,3,10,pt,pt PM_RESUME,0.46857309341430664,16, -linux_literal_default,3,10,pt,pt PM_RESUME,0.47760438919067383,16, -linux_literal_default,3,10,pt,pt PM_RESUME,0.46701765060424805,16, -linux_literal_default,3,10,pt,pt PM_RESUME,0.4331653118133545,16, -linux_literal_default,3,10,pt,pt PM_RESUME,0.45867037773132324,16, -linux_literal_default,3,10,pt,pt PM_RESUME,0.4557461738586426,16, -linux_literal_default,3,10,pt,pt PM_RESUME,0.46278929710388184,16, -linux_literal_default,3,10,pt,pt PM_RESUME,0.4585258960723877,16, -linux_literal_default,3,10,pt,pt PM_RESUME,0.47124767303466797,16, -linux_literal_default,3,10,pt,pt PM_RESUME,0.4672355651855469,16, -linux_literal_default,3,10,sift,sift PM_RESUME,0.38060545921325684,16, -linux_literal_default,3,10,sift,sift PM_RESUME,0.3329169750213623,16, -linux_literal_default,3,10,sift,sift PM_RESUME,0.33484435081481934,16, -linux_literal_default,3,10,sift,sift PM_RESUME,0.35355401039123535,16, -linux_literal_default,3,10,sift,sift PM_RESUME,0.35204195976257324,16, -linux_literal_default,3,10,sift,sift PM_RESUME,0.338015079498291,16, -linux_literal_default,3,10,sift,sift PM_RESUME,0.33859682083129883,16, -linux_literal_default,3,10,sift,sift PM_RESUME,0.37181973457336426,16, -linux_literal_default,3,10,sift,sift PM_RESUME,0.34308838844299316,16, -linux_literal_default,3,10,sift,sift PM_RESUME,0.37679576873779297,16, -linux_literal_default,3,10,git grep,git grep PM_RESUME,0.34804248809814453,16,LC_ALL=en_US.UTF-8 -linux_literal_default,3,10,git grep,git grep PM_RESUME,0.3415200710296631,16,LC_ALL=en_US.UTF-8 -linux_literal_default,3,10,git grep,git grep PM_RESUME,0.33733463287353516,16,LC_ALL=en_US.UTF-8 -linux_literal_default,3,10,git grep,git grep PM_RESUME,0.3332488536834717,16,LC_ALL=en_US.UTF-8 -linux_literal_default,3,10,git grep,git grep PM_RESUME,0.34481191635131836,16,LC_ALL=en_US.UTF-8 -linux_literal_default,3,10,git grep,git grep PM_RESUME,0.34947681427001953,16,LC_ALL=en_US.UTF-8 -linux_literal_default,3,10,git grep,git grep PM_RESUME,0.34740161895751953,16,LC_ALL=en_US.UTF-8 -linux_literal_default,3,10,git grep,git grep PM_RESUME,0.33948254585266113,16,LC_ALL=en_US.UTF-8 -linux_literal_default,3,10,git grep,git grep PM_RESUME,0.3381669521331787,16,LC_ALL=en_US.UTF-8 -linux_literal_default,3,10,git grep,git grep PM_RESUME,0.34292149543762207,16,LC_ALL=en_US.UTF-8 -linux_no_literal,3,10,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.5793054103851318,490, -linux_no_literal,3,10,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.5733230113983154,490, -linux_no_literal,3,10,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.5830531120300293,490, -linux_no_literal,3,10,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.5784716606140137,490, -linux_no_literal,3,10,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.5747678279876709,490, -linux_no_literal,3,10,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.5774915218353271,490, -linux_no_literal,3,10,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.5772106647491455,490, -linux_no_literal,3,10,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.576981782913208,490, -linux_no_literal,3,10,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.5727875232696533,490, -linux_no_literal,3,10,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.5777604579925537,490, -linux_no_literal,3,10,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.47701001167297363,490, -linux_no_literal,3,10,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.4056098461151123,490, -linux_no_literal,3,10,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.40029191970825195,490, -linux_no_literal,3,10,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.4043698310852051,490, -linux_no_literal,3,10,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.39755749702453613,490, -linux_no_literal,3,10,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.40610837936401367,490, -linux_no_literal,3,10,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.40239667892456055,490, -linux_no_literal,3,10,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.44395995140075684,490, -linux_no_literal,3,10,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.41157984733581543,490, -linux_no_literal,3,10,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.40621185302734375,490, -linux_no_literal,3,10,ag (ignore) (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},2.346493721008301,766, -linux_no_literal,3,10,ag (ignore) (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},2.3504796028137207,766, -linux_no_literal,3,10,ag (ignore) (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},2.337827682495117,766, -linux_no_literal,3,10,ag (ignore) (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},2.3482706546783447,766, -linux_no_literal,3,10,ag (ignore) (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},2.321526288986206,766, -linux_no_literal,3,10,ag (ignore) (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},2.3464548587799072,766, -linux_no_literal,3,10,ag (ignore) (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},2.3376870155334473,766, -linux_no_literal,3,10,ag (ignore) (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},2.337705612182617,766, -linux_no_literal,3,10,ag (ignore) (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},2.328770637512207,766, -linux_no_literal,3,10,ag (ignore) (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},2.3303186893463135,766, -linux_no_literal,3,10,pt (ignore) (ASCII),pt -e \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},22.04857587814331,490, -linux_no_literal,3,10,pt (ignore) (ASCII),pt -e \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},22.10808300971985,490, -linux_no_literal,3,10,pt (ignore) (ASCII),pt -e \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},22.033851861953735,490, -linux_no_literal,3,10,pt (ignore) (ASCII),pt -e \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},22.140597581863403,490, -linux_no_literal,3,10,pt (ignore) (ASCII),pt -e \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},22.119322299957275,490, -linux_no_literal,3,10,pt (ignore) (ASCII),pt -e \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},21.98818349838257,490, -linux_no_literal,3,10,pt (ignore) (ASCII),pt -e \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},21.977314949035645,490, -linux_no_literal,3,10,pt (ignore) (ASCII),pt -e \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},22.06201982498169,490, -linux_no_literal,3,10,pt (ignore) (ASCII),pt -e \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},22.061450242996216,490, -linux_no_literal,3,10,pt (ignore) (ASCII),pt -e \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},22.124264001846313,490, -linux_no_literal,3,10,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},25.59274411201477,490, -linux_no_literal,3,10,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},25.573359489440918,490, -linux_no_literal,3,10,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},25.742077112197876,490, -linux_no_literal,3,10,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},25.54994797706604,490, -linux_no_literal,3,10,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},25.706160306930542,490, -linux_no_literal,3,10,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},25.445934057235718,490, -linux_no_literal,3,10,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},25.45766806602478,490, -linux_no_literal,3,10,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},25.43312954902649,490, -linux_no_literal,3,10,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},25.491786241531372,490, -linux_no_literal,3,10,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},25.634543895721436,490, -linux_no_literal,3,10,git grep (ignore),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},26.399667501449585,490,LC_ALL=en_US.UTF-8 -linux_no_literal,3,10,git grep (ignore),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},26.38280701637268,490,LC_ALL=en_US.UTF-8 -linux_no_literal,3,10,git grep (ignore),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},26.41436266899109,490,LC_ALL=en_US.UTF-8 -linux_no_literal,3,10,git grep (ignore),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},26.356714010238647,490,LC_ALL=en_US.UTF-8 -linux_no_literal,3,10,git grep (ignore),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},26.372775316238403,490,LC_ALL=en_US.UTF-8 -linux_no_literal,3,10,git grep (ignore),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},26.366456031799316,490,LC_ALL=en_US.UTF-8 -linux_no_literal,3,10,git grep (ignore),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},26.345572233200073,490,LC_ALL=en_US.UTF-8 -linux_no_literal,3,10,git grep (ignore),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},26.359038591384888,490,LC_ALL=en_US.UTF-8 -linux_no_literal,3,10,git grep (ignore),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},26.339266777038574,490,LC_ALL=en_US.UTF-8 -linux_no_literal,3,10,git grep (ignore),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},26.48772692680359,490,LC_ALL=en_US.UTF-8 -linux_no_literal,3,10,git grep (ignore) (ASCII),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},4.16526985168457,490,LC_ALL=C -linux_no_literal,3,10,git grep (ignore) (ASCII),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},4.1695733070373535,490,LC_ALL=C -linux_no_literal,3,10,git grep (ignore) (ASCII),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},4.155884027481079,490,LC_ALL=C -linux_no_literal,3,10,git grep (ignore) (ASCII),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},4.143868684768677,490,LC_ALL=C -linux_no_literal,3,10,git grep (ignore) (ASCII),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},4.147655248641968,490,LC_ALL=C -linux_no_literal,3,10,git grep (ignore) (ASCII),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},4.151846885681152,490,LC_ALL=C -linux_no_literal,3,10,git grep (ignore) (ASCII),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},4.140476703643799,490,LC_ALL=C -linux_no_literal,3,10,git grep (ignore) (ASCII),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},4.142986059188843,490,LC_ALL=C -linux_no_literal,3,10,git grep (ignore) (ASCII),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},4.156916379928589,490,LC_ALL=C -linux_no_literal,3,10,git grep (ignore) (ASCII),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},4.157176971435547,490,LC_ALL=C -linux_no_literal,3,10,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.5112531185150146,419, -linux_no_literal,3,10,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.5284323692321777,419, -linux_no_literal,3,10,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.49768805503845215,419, -linux_no_literal,3,10,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.4940907955169678,419, -linux_no_literal,3,10,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.5072541236877441,419, -linux_no_literal,3,10,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.50177001953125,419, -linux_no_literal,3,10,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.494765043258667,419, -linux_no_literal,3,10,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.49721837043762207,419, -linux_no_literal,3,10,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.49683475494384766,419, -linux_no_literal,3,10,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.4985806941986084,419, -linux_no_literal,3,10,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.3259718418121338,419, -linux_no_literal,3,10,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.32500338554382324,419, -linux_no_literal,3,10,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.32590746879577637,419, -linux_no_literal,3,10,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.3270235061645508,419, -linux_no_literal,3,10,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.40813469886779785,419, -linux_no_literal,3,10,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.3254811763763428,419, -linux_no_literal,3,10,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.32666945457458496,419, -linux_no_literal,3,10,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.42030978202819824,419, -linux_no_literal,3,10,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.3227384090423584,419, -linux_no_literal,3,10,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.3258059024810791,419, -linux_no_literal,3,10,ucg (whitelist) (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},1.132291555404663,416, -linux_no_literal,3,10,ucg (whitelist) (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},1.1314997673034668,416, -linux_no_literal,3,10,ucg (whitelist) (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},1.129917860031128,416, -linux_no_literal,3,10,ucg (whitelist) (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},1.1349639892578125,416, -linux_no_literal,3,10,ucg (whitelist) (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},1.1323256492614746,416, -linux_no_literal,3,10,ucg (whitelist) (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},1.1280417442321777,416, -linux_no_literal,3,10,ucg (whitelist) (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},1.128892183303833,416, -linux_no_literal,3,10,ucg (whitelist) (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},1.12849760055542,416, -linux_no_literal,3,10,ucg (whitelist) (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},1.128230094909668,416, -linux_no_literal,3,10,ucg (whitelist) (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},1.126936435699463,416, -linux_re_literal_suffix,3,10,rg (ignore),rg -n [A-Z]+_RESUME,0.2936074733734131,1652, -linux_re_literal_suffix,3,10,rg (ignore),rg -n [A-Z]+_RESUME,0.28904199600219727,1652, -linux_re_literal_suffix,3,10,rg (ignore),rg -n [A-Z]+_RESUME,0.35044193267822266,1652, -linux_re_literal_suffix,3,10,rg (ignore),rg -n [A-Z]+_RESUME,0.33156752586364746,1652, -linux_re_literal_suffix,3,10,rg (ignore),rg -n [A-Z]+_RESUME,0.2898244857788086,1652, -linux_re_literal_suffix,3,10,rg (ignore),rg -n [A-Z]+_RESUME,0.28866147994995117,1652, -linux_re_literal_suffix,3,10,rg (ignore),rg -n [A-Z]+_RESUME,0.39086151123046875,1652, -linux_re_literal_suffix,3,10,rg (ignore),rg -n [A-Z]+_RESUME,0.2908496856689453,1652, -linux_re_literal_suffix,3,10,rg (ignore),rg -n [A-Z]+_RESUME,0.3271830081939697,1652, -linux_re_literal_suffix,3,10,rg (ignore),rg -n [A-Z]+_RESUME,0.3252100944519043,1652, -linux_re_literal_suffix,3,10,ag (ignore),ag -s [A-Z]+_RESUME,1.8963699340820312,1652, -linux_re_literal_suffix,3,10,ag (ignore),ag -s [A-Z]+_RESUME,1.8861753940582275,1652, -linux_re_literal_suffix,3,10,ag (ignore),ag -s [A-Z]+_RESUME,1.8948850631713867,1652, -linux_re_literal_suffix,3,10,ag (ignore),ag -s [A-Z]+_RESUME,1.9025893211364746,1652, -linux_re_literal_suffix,3,10,ag (ignore),ag -s [A-Z]+_RESUME,1.9024877548217773,1652, -linux_re_literal_suffix,3,10,ag (ignore),ag -s [A-Z]+_RESUME,1.916628122329712,1652, -linux_re_literal_suffix,3,10,ag (ignore),ag -s [A-Z]+_RESUME,1.895963430404663,1652, -linux_re_literal_suffix,3,10,ag (ignore),ag -s [A-Z]+_RESUME,1.8982641696929932,1652, -linux_re_literal_suffix,3,10,ag (ignore),ag -s [A-Z]+_RESUME,1.906947135925293,1652, -linux_re_literal_suffix,3,10,ag (ignore),ag -s [A-Z]+_RESUME,1.8928930759429932,1652, -linux_re_literal_suffix,3,10,pt (ignore),pt -e [A-Z]+_RESUME,13.542996168136597,1652, -linux_re_literal_suffix,3,10,pt (ignore),pt -e [A-Z]+_RESUME,13.356479167938232,1652, -linux_re_literal_suffix,3,10,pt (ignore),pt -e [A-Z]+_RESUME,14.192973136901855,1652, -linux_re_literal_suffix,3,10,pt (ignore),pt -e [A-Z]+_RESUME,13.541444063186646,1652, -linux_re_literal_suffix,3,10,pt (ignore),pt -e [A-Z]+_RESUME,13.854554653167725,1652, -linux_re_literal_suffix,3,10,pt (ignore),pt -e [A-Z]+_RESUME,13.603343725204468,1652, -linux_re_literal_suffix,3,10,pt (ignore),pt -e [A-Z]+_RESUME,13.799452781677246,1652, -linux_re_literal_suffix,3,10,pt (ignore),pt -e [A-Z]+_RESUME,13.863913774490356,1652, -linux_re_literal_suffix,3,10,pt (ignore),pt -e [A-Z]+_RESUME,13.838748455047607,1652, -linux_re_literal_suffix,3,10,pt (ignore),pt -e [A-Z]+_RESUME,13.538004636764526,1652, -linux_re_literal_suffix,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git [A-Z]+_RESUME,10.060765504837036,1652, -linux_re_literal_suffix,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git [A-Z]+_RESUME,10.49359679222107,1652, -linux_re_literal_suffix,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git [A-Z]+_RESUME,10.081884145736694,1652, -linux_re_literal_suffix,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git [A-Z]+_RESUME,10.493861675262451,1652, -linux_re_literal_suffix,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git [A-Z]+_RESUME,10.067906379699707,1652, -linux_re_literal_suffix,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git [A-Z]+_RESUME,9.981789588928223,1652, -linux_re_literal_suffix,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git [A-Z]+_RESUME,10.265925168991089,1652, -linux_re_literal_suffix,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git [A-Z]+_RESUME,10.045130014419556,1652, -linux_re_literal_suffix,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git [A-Z]+_RESUME,10.06310224533081,1652, -linux_re_literal_suffix,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git [A-Z]+_RESUME,10.161619186401367,1652, -linux_re_literal_suffix,3,10,git grep (ignore),git grep -E -I -n [A-Z]+_RESUME,1.1039769649505615,1652,LC_ALL=C -linux_re_literal_suffix,3,10,git grep (ignore),git grep -E -I -n [A-Z]+_RESUME,1.114553689956665,1652,LC_ALL=C -linux_re_literal_suffix,3,10,git grep (ignore),git grep -E -I -n [A-Z]+_RESUME,1.1093242168426514,1652,LC_ALL=C -linux_re_literal_suffix,3,10,git grep (ignore),git grep -E -I -n [A-Z]+_RESUME,1.1064682006835938,1652,LC_ALL=C -linux_re_literal_suffix,3,10,git grep (ignore),git grep -E -I -n [A-Z]+_RESUME,1.1018595695495605,1652,LC_ALL=C -linux_re_literal_suffix,3,10,git grep (ignore),git grep -E -I -n [A-Z]+_RESUME,1.109755516052246,1652,LC_ALL=C -linux_re_literal_suffix,3,10,git grep (ignore),git grep -E -I -n [A-Z]+_RESUME,1.1123108863830566,1652,LC_ALL=C -linux_re_literal_suffix,3,10,git grep (ignore),git grep -E -I -n [A-Z]+_RESUME,1.1048264503479004,1652,LC_ALL=C -linux_re_literal_suffix,3,10,git grep (ignore),git grep -E -I -n [A-Z]+_RESUME,1.109236478805542,1652,LC_ALL=C -linux_re_literal_suffix,3,10,git grep (ignore),git grep -E -I -n [A-Z]+_RESUME,1.10935640335083,1652,LC_ALL=C -linux_re_literal_suffix,3,10,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.20705485343933105,1630, -linux_re_literal_suffix,3,10,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.2106492519378662,1630, -linux_re_literal_suffix,3,10,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.2084188461303711,1630, -linux_re_literal_suffix,3,10,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.2640719413757324,1630, -linux_re_literal_suffix,3,10,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.2081773281097412,1630, -linux_re_literal_suffix,3,10,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.2118208408355713,1630, -linux_re_literal_suffix,3,10,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.2089850902557373,1630, -linux_re_literal_suffix,3,10,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.23274970054626465,1630, -linux_re_literal_suffix,3,10,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.25668978691101074,1630, -linux_re_literal_suffix,3,10,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.20613741874694824,1630, -linux_re_literal_suffix,3,10,ucg (whitelist),ucg --nosmart-case [A-Z]+_RESUME,0.30318307876586914,1630, -linux_re_literal_suffix,3,10,ucg (whitelist),ucg --nosmart-case [A-Z]+_RESUME,0.2986927032470703,1630, -linux_re_literal_suffix,3,10,ucg (whitelist),ucg --nosmart-case [A-Z]+_RESUME,0.2998936176300049,1630, -linux_re_literal_suffix,3,10,ucg (whitelist),ucg --nosmart-case [A-Z]+_RESUME,0.3013923168182373,1630, -linux_re_literal_suffix,3,10,ucg (whitelist),ucg --nosmart-case [A-Z]+_RESUME,0.3002176284790039,1630, -linux_re_literal_suffix,3,10,ucg (whitelist),ucg --nosmart-case [A-Z]+_RESUME,0.29929661750793457,1630, -linux_re_literal_suffix,3,10,ucg (whitelist),ucg --nosmart-case [A-Z]+_RESUME,0.3002638816833496,1630, -linux_re_literal_suffix,3,10,ucg (whitelist),ucg --nosmart-case [A-Z]+_RESUME,0.3022594451904297,1630, -linux_re_literal_suffix,3,10,ucg (whitelist),ucg --nosmart-case [A-Z]+_RESUME,0.3005950450897217,1630, -linux_re_literal_suffix,3,10,ucg (whitelist),ucg --nosmart-case [A-Z]+_RESUME,0.3003072738647461,1630, -linux_unicode_greek,3,10,rg,rg -n \p{Greek},0.4220447540283203,23, -linux_unicode_greek,3,10,rg,rg -n \p{Greek},0.4022982120513916,23, -linux_unicode_greek,3,10,rg,rg -n \p{Greek},0.40406036376953125,23, -linux_unicode_greek,3,10,rg,rg -n \p{Greek},0.414935827255249,23, -linux_unicode_greek,3,10,rg,rg -n \p{Greek},0.39977121353149414,23, -linux_unicode_greek,3,10,rg,rg -n \p{Greek},0.4032399654388428,23, -linux_unicode_greek,3,10,rg,rg -n \p{Greek},0.4270012378692627,23, -linux_unicode_greek,3,10,rg,rg -n \p{Greek},0.4013488292694092,23, -linux_unicode_greek,3,10,rg,rg -n \p{Greek},0.46738338470458984,23, -linux_unicode_greek,3,10,rg,rg -n \p{Greek},0.4026005268096924,23, -linux_unicode_greek,3,10,pt,pt -e \p{Greek},12.682367086410522,23, -linux_unicode_greek,3,10,pt,pt -e \p{Greek},12.691372394561768,23, -linux_unicode_greek,3,10,pt,pt -e \p{Greek},12.737368822097778,23, -linux_unicode_greek,3,10,pt,pt -e \p{Greek},12.813798666000366,23, -linux_unicode_greek,3,10,pt,pt -e \p{Greek},12.881911754608154,23, -linux_unicode_greek,3,10,pt,pt -e \p{Greek},12.321162462234497,23, -linux_unicode_greek,3,10,pt,pt -e \p{Greek},12.792261838912964,23, -linux_unicode_greek,3,10,pt,pt -e \p{Greek},12.894794464111328,23, -linux_unicode_greek,3,10,pt,pt -e \p{Greek},12.860591650009155,23, -linux_unicode_greek,3,10,pt,pt -e \p{Greek},12.774003744125366,23, -linux_unicode_greek,3,10,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \p{Greek},7.338077068328857,23, -linux_unicode_greek,3,10,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \p{Greek},7.741130113601685,23, -linux_unicode_greek,3,10,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \p{Greek},7.807847023010254,23, -linux_unicode_greek,3,10,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \p{Greek},7.8104469776153564,23, -linux_unicode_greek,3,10,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \p{Greek},7.743628978729248,23, -linux_unicode_greek,3,10,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \p{Greek},7.728483438491821,23, -linux_unicode_greek,3,10,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \p{Greek},8.222429275512695,23, -linux_unicode_greek,3,10,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \p{Greek},8.043334722518921,23, -linux_unicode_greek,3,10,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \p{Greek},7.848775863647461,23, -linux_unicode_greek,3,10,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \p{Greek},7.382145643234253,23, -linux_unicode_greek_casei,3,10,rg,rg -n -i \p{Greek},0.4646949768066406,103, -linux_unicode_greek_casei,3,10,rg,rg -n -i \p{Greek},0.40577101707458496,103, -linux_unicode_greek_casei,3,10,rg,rg -n -i \p{Greek},0.39434385299682617,103, -linux_unicode_greek_casei,3,10,rg,rg -n -i \p{Greek},0.42445874214172363,103, -linux_unicode_greek_casei,3,10,rg,rg -n -i \p{Greek},0.4024500846862793,103, -linux_unicode_greek_casei,3,10,rg,rg -n -i \p{Greek},0.41817784309387207,103, -linux_unicode_greek_casei,3,10,rg,rg -n -i \p{Greek},0.41820359230041504,103, -linux_unicode_greek_casei,3,10,rg,rg -n -i \p{Greek},0.4578087329864502,103, -linux_unicode_greek_casei,3,10,rg,rg -n -i \p{Greek},0.4002723693847656,103, -linux_unicode_greek_casei,3,10,rg,rg -n -i \p{Greek},0.460965633392334,103, -linux_unicode_greek_casei,3,10,pt,pt -i -e \p{Greek},12.604194641113281,23, -linux_unicode_greek_casei,3,10,pt,pt -i -e \p{Greek},12.585155010223389,23, -linux_unicode_greek_casei,3,10,pt,pt -i -e \p{Greek},12.904623985290527,23, -linux_unicode_greek_casei,3,10,pt,pt -i -e \p{Greek},12.603661298751831,23, -linux_unicode_greek_casei,3,10,pt,pt -i -e \p{Greek},12.89511752128601,23, -linux_unicode_greek_casei,3,10,pt,pt -i -e \p{Greek},12.375482320785522,23, -linux_unicode_greek_casei,3,10,pt,pt -i -e \p{Greek},12.77438759803772,23, -linux_unicode_greek_casei,3,10,pt,pt -i -e \p{Greek},12.416762113571167,23, -linux_unicode_greek_casei,3,10,pt,pt -i -e \p{Greek},12.711334705352783,23, -linux_unicode_greek_casei,3,10,pt,pt -i -e \p{Greek},12.253499746322632,23, -linux_unicode_greek_casei,3,10,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git \p{Greek},0.0025110244750976562,, -linux_unicode_greek_casei,3,10,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git \p{Greek},0.002439260482788086,, -linux_unicode_greek_casei,3,10,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git \p{Greek},0.0024383068084716797,, -linux_unicode_greek_casei,3,10,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git \p{Greek},0.0023565292358398438,, -linux_unicode_greek_casei,3,10,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git \p{Greek},0.0022935867309570312,, -linux_unicode_greek_casei,3,10,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git \p{Greek},0.0023267269134521484,, -linux_unicode_greek_casei,3,10,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git \p{Greek},0.002335071563720703,, -linux_unicode_greek_casei,3,10,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git \p{Greek},0.0022766590118408203,, -linux_unicode_greek_casei,3,10,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git \p{Greek},0.002285003662109375,, -linux_unicode_greek_casei,3,10,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git \p{Greek},0.002235889434814453,, -linux_unicode_word,3,10,rg (ignore),rg -n \wAh,0.5075342655181885,186, -linux_unicode_word,3,10,rg (ignore),rg -n \wAh,0.3014566898345947,186, -linux_unicode_word,3,10,rg (ignore),rg -n \wAh,0.30255842208862305,186, -linux_unicode_word,3,10,rg (ignore),rg -n \wAh,0.419527530670166,186, -linux_unicode_word,3,10,rg (ignore),rg -n \wAh,0.30051612854003906,186, -linux_unicode_word,3,10,rg (ignore),rg -n \wAh,0.41606736183166504,186, -linux_unicode_word,3,10,rg (ignore),rg -n \wAh,0.3061816692352295,186, -linux_unicode_word,3,10,rg (ignore),rg -n \wAh,0.316450834274292,186, -linux_unicode_word,3,10,rg (ignore),rg -n \wAh,0.29686737060546875,186, -linux_unicode_word,3,10,rg (ignore),rg -n \wAh,0.3846714496612549,186, -linux_unicode_word,3,10,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.30101466178894043,174, -linux_unicode_word,3,10,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.29622554779052734,174, -linux_unicode_word,3,10,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.3100159168243408,174, -linux_unicode_word,3,10,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.30087780952453613,174, -linux_unicode_word,3,10,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.29802870750427246,174, -linux_unicode_word,3,10,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.4232194423675537,174, -linux_unicode_word,3,10,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.45890188217163086,174, -linux_unicode_word,3,10,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.2998533248901367,174, -linux_unicode_word,3,10,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.29979395866394043,174, -linux_unicode_word,3,10,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.2986025810241699,174, -linux_unicode_word,3,10,ag (ignore) (ASCII),ag -s \wAh,1.7579238414764404,174, -linux_unicode_word,3,10,ag (ignore) (ASCII),ag -s \wAh,1.7875633239746094,174, -linux_unicode_word,3,10,ag (ignore) (ASCII),ag -s \wAh,1.7632112503051758,174, -linux_unicode_word,3,10,ag (ignore) (ASCII),ag -s \wAh,1.7843427658081055,174, -linux_unicode_word,3,10,ag (ignore) (ASCII),ag -s \wAh,1.7860534191131592,174, -linux_unicode_word,3,10,ag (ignore) (ASCII),ag -s \wAh,1.7815673351287842,174, -linux_unicode_word,3,10,ag (ignore) (ASCII),ag -s \wAh,1.7678496837615967,174, -linux_unicode_word,3,10,ag (ignore) (ASCII),ag -s \wAh,1.7820045948028564,174, -linux_unicode_word,3,10,ag (ignore) (ASCII),ag -s \wAh,1.7667298316955566,174, -linux_unicode_word,3,10,ag (ignore) (ASCII),ag -s \wAh,1.765808343887329,174, -linux_unicode_word,3,10,pt (ignore) (ASCII),pt -e \wAh,14.26370882987976,174, -linux_unicode_word,3,10,pt (ignore) (ASCII),pt -e \wAh,13.948208808898926,174, -linux_unicode_word,3,10,pt (ignore) (ASCII),pt -e \wAh,14.321836948394775,174, -linux_unicode_word,3,10,pt (ignore) (ASCII),pt -e \wAh,14.353292226791382,174, -linux_unicode_word,3,10,pt (ignore) (ASCII),pt -e \wAh,13.980775117874146,174, -linux_unicode_word,3,10,pt (ignore) (ASCII),pt -e \wAh,14.000723600387573,174, -linux_unicode_word,3,10,pt (ignore) (ASCII),pt -e \wAh,14.369597673416138,174, -linux_unicode_word,3,10,pt (ignore) (ASCII),pt -e \wAh,13.967730045318604,174, -linux_unicode_word,3,10,pt (ignore) (ASCII),pt -e \wAh,14.324349164962769,174, -linux_unicode_word,3,10,pt (ignore) (ASCII),pt -e \wAh,14.270223140716553,174, -linux_unicode_word,3,10,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \wAh,11.162141561508179,174, -linux_unicode_word,3,10,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \wAh,10.980525970458984,174, -linux_unicode_word,3,10,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \wAh,11.026103496551514,174, -linux_unicode_word,3,10,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \wAh,11.277002811431885,174, -linux_unicode_word,3,10,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \wAh,11.148287057876587,174, -linux_unicode_word,3,10,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \wAh,11.005484819412231,174, -linux_unicode_word,3,10,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \wAh,10.91290545463562,174, -linux_unicode_word,3,10,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \wAh,11.106207847595215,174, -linux_unicode_word,3,10,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \wAh,11.16712760925293,174, -linux_unicode_word,3,10,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \wAh,11.083898544311523,174, -linux_unicode_word,3,10,git grep (ignore),git grep -E -I -n \wAh,13.044305801391602,186,LC_ALL=en_US.UTF-8 -linux_unicode_word,3,10,git grep (ignore),git grep -E -I -n \wAh,13.056626081466675,186,LC_ALL=en_US.UTF-8 -linux_unicode_word,3,10,git grep (ignore),git grep -E -I -n \wAh,13.048550844192505,186,LC_ALL=en_US.UTF-8 -linux_unicode_word,3,10,git grep (ignore),git grep -E -I -n \wAh,13.029039859771729,186,LC_ALL=en_US.UTF-8 -linux_unicode_word,3,10,git grep (ignore),git grep -E -I -n \wAh,13.047250509262085,186,LC_ALL=en_US.UTF-8 -linux_unicode_word,3,10,git grep (ignore),git grep -E -I -n \wAh,13.04845643043518,186,LC_ALL=en_US.UTF-8 -linux_unicode_word,3,10,git grep (ignore),git grep -E -I -n \wAh,13.051046133041382,186,LC_ALL=en_US.UTF-8 -linux_unicode_word,3,10,git grep (ignore),git grep -E -I -n \wAh,13.03917121887207,186,LC_ALL=en_US.UTF-8 -linux_unicode_word,3,10,git grep (ignore),git grep -E -I -n \wAh,13.039993047714233,186,LC_ALL=en_US.UTF-8 -linux_unicode_word,3,10,git grep (ignore),git grep -E -I -n \wAh,13.041208982467651,186,LC_ALL=en_US.UTF-8 -linux_unicode_word,3,10,git grep (ignore) (ASCII),git grep -E -I -n \wAh,2.9960885047912598,174,LC_ALL=C -linux_unicode_word,3,10,git grep (ignore) (ASCII),git grep -E -I -n \wAh,2.985478401184082,174,LC_ALL=C -linux_unicode_word,3,10,git grep (ignore) (ASCII),git grep -E -I -n \wAh,2.9874212741851807,174,LC_ALL=C -linux_unicode_word,3,10,git grep (ignore) (ASCII),git grep -E -I -n \wAh,2.987626314163208,174,LC_ALL=C -linux_unicode_word,3,10,git grep (ignore) (ASCII),git grep -E -I -n \wAh,2.994694471359253,174,LC_ALL=C -linux_unicode_word,3,10,git grep (ignore) (ASCII),git grep -E -I -n \wAh,2.992467164993286,174,LC_ALL=C -linux_unicode_word,3,10,git grep (ignore) (ASCII),git grep -E -I -n \wAh,2.9871950149536133,174,LC_ALL=C -linux_unicode_word,3,10,git grep (ignore) (ASCII),git grep -E -I -n \wAh,2.995185613632202,174,LC_ALL=C -linux_unicode_word,3,10,git grep (ignore) (ASCII),git grep -E -I -n \wAh,2.9936091899871826,174,LC_ALL=C -linux_unicode_word,3,10,git grep (ignore) (ASCII),git grep -E -I -n \wAh,2.9940080642700195,174,LC_ALL=C -linux_unicode_word,3,10,rg (whitelist),rg -n --no-ignore -tall \wAh,0.21994638442993164,180, -linux_unicode_word,3,10,rg (whitelist),rg -n --no-ignore -tall \wAh,0.22097373008728027,180, -linux_unicode_word,3,10,rg (whitelist),rg -n --no-ignore -tall \wAh,0.23552775382995605,180, -linux_unicode_word,3,10,rg (whitelist),rg -n --no-ignore -tall \wAh,0.21982312202453613,180, -linux_unicode_word,3,10,rg (whitelist),rg -n --no-ignore -tall \wAh,0.3113522529602051,180, -linux_unicode_word,3,10,rg (whitelist),rg -n --no-ignore -tall \wAh,0.26632070541381836,180, -linux_unicode_word,3,10,rg (whitelist),rg -n --no-ignore -tall \wAh,0.21911191940307617,180, -linux_unicode_word,3,10,rg (whitelist),rg -n --no-ignore -tall \wAh,0.22008752822875977,180, -linux_unicode_word,3,10,rg (whitelist),rg -n --no-ignore -tall \wAh,0.21874570846557617,180, -linux_unicode_word,3,10,rg (whitelist),rg -n --no-ignore -tall \wAh,0.21397948265075684,180, -linux_unicode_word,3,10,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.21848511695861816,168, -linux_unicode_word,3,10,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.2182908058166504,168, -linux_unicode_word,3,10,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.2177116870880127,168, -linux_unicode_word,3,10,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.21211910247802734,168, -linux_unicode_word,3,10,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.2223820686340332,168, -linux_unicode_word,3,10,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.22381138801574707,168, -linux_unicode_word,3,10,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.2192692756652832,168, -linux_unicode_word,3,10,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.28908252716064453,168, -linux_unicode_word,3,10,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.21803808212280273,168, -linux_unicode_word,3,10,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.21266746520996094,168, -linux_unicode_word,3,10,ucg (ASCII),ucg --nosmart-case \wAh,0.22500395774841309,168, -linux_unicode_word,3,10,ucg (ASCII),ucg --nosmart-case \wAh,0.2196519374847412,168, -linux_unicode_word,3,10,ucg (ASCII),ucg --nosmart-case \wAh,0.23636341094970703,168, -linux_unicode_word,3,10,ucg (ASCII),ucg --nosmart-case \wAh,0.22854065895080566,168, -linux_unicode_word,3,10,ucg (ASCII),ucg --nosmart-case \wAh,0.24159979820251465,168, -linux_unicode_word,3,10,ucg (ASCII),ucg --nosmart-case \wAh,0.2279496192932129,168, -linux_unicode_word,3,10,ucg (ASCII),ucg --nosmart-case \wAh,0.2282264232635498,168, -linux_unicode_word,3,10,ucg (ASCII),ucg --nosmart-case \wAh,0.22038722038269043,168, -linux_unicode_word,3,10,ucg (ASCII),ucg --nosmart-case \wAh,0.2304396629333496,168, -linux_unicode_word,3,10,ucg (ASCII),ucg --nosmart-case \wAh,0.22999143600463867,168, -linux_word,3,10,rg (ignore),rg -n -w PM_RESUME,0.4643971920013428,6, -linux_word,3,10,rg (ignore),rg -n -w PM_RESUME,0.31100964546203613,6, -linux_word,3,10,rg (ignore),rg -n -w PM_RESUME,0.2884225845336914,6, -linux_word,3,10,rg (ignore),rg -n -w PM_RESUME,0.3069937229156494,6, -linux_word,3,10,rg (ignore),rg -n -w PM_RESUME,0.29024529457092285,6, -linux_word,3,10,rg (ignore),rg -n -w PM_RESUME,0.4824669361114502,6, -linux_word,3,10,rg (ignore),rg -n -w PM_RESUME,0.46274733543395996,6, -linux_word,3,10,rg (ignore),rg -n -w PM_RESUME,0.28812289237976074,6, -linux_word,3,10,rg (ignore),rg -n -w PM_RESUME,0.350308895111084,6, -linux_word,3,10,rg (ignore),rg -n -w PM_RESUME,0.374927282333374,6, -linux_word,3,10,ag (ignore),ag -s -w PM_RESUME,1.6171681880950928,6, -linux_word,3,10,ag (ignore),ag -s -w PM_RESUME,1.6098666191101074,6, -linux_word,3,10,ag (ignore),ag -s -w PM_RESUME,1.5964553356170654,6, -linux_word,3,10,ag (ignore),ag -s -w PM_RESUME,1.6071968078613281,6, -linux_word,3,10,ag (ignore),ag -s -w PM_RESUME,1.5954012870788574,6, -linux_word,3,10,ag (ignore),ag -s -w PM_RESUME,1.6015000343322754,6, -linux_word,3,10,ag (ignore),ag -s -w PM_RESUME,1.601473331451416,6, -linux_word,3,10,ag (ignore),ag -s -w PM_RESUME,1.5954999923706055,6, -linux_word,3,10,ag (ignore),ag -s -w PM_RESUME,1.6129882335662842,6, -linux_word,3,10,ag (ignore),ag -s -w PM_RESUME,1.588838815689087,6, -linux_word,3,10,pt (ignore),pt -w PM_RESUME,14.572103500366211,6, -linux_word,3,10,pt (ignore),pt -w PM_RESUME,14.43345308303833,6, -linux_word,3,10,pt (ignore),pt -w PM_RESUME,14.209619045257568,6, -linux_word,3,10,pt (ignore),pt -w PM_RESUME,14.430129051208496,6, -linux_word,3,10,pt (ignore),pt -w PM_RESUME,14.560482263565063,6, -linux_word,3,10,pt (ignore),pt -w PM_RESUME,14.483187913894653,6, -linux_word,3,10,pt (ignore),pt -w PM_RESUME,14.457705020904541,6, -linux_word,3,10,pt (ignore),pt -w PM_RESUME,14.179070472717285,6, -linux_word,3,10,pt (ignore),pt -w PM_RESUME,14.290963411331177,6, -linux_word,3,10,pt (ignore),pt -w PM_RESUME,14.554560422897339,6, -linux_word,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -w --git PM_RESUME,7.818600416183472,6, -linux_word,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -w --git PM_RESUME,7.8375983238220215,6, -linux_word,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -w --git PM_RESUME,8.135910034179688,6, -linux_word,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -w --git PM_RESUME,7.684378623962402,6, -linux_word,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -w --git PM_RESUME,7.841930389404297,6, -linux_word,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -w --git PM_RESUME,7.910590171813965,6, -linux_word,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -w --git PM_RESUME,7.786734104156494,6, -linux_word,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -w --git PM_RESUME,7.763006687164307,6, -linux_word,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -w --git PM_RESUME,7.749568223953247,6, -linux_word,3,10,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -w --git PM_RESUME,7.872854232788086,6, -linux_word,3,10,git grep (ignore),git grep -E -I -n -w PM_RESUME,0.34014463424682617,6,LC_ALL=C -linux_word,3,10,git grep (ignore),git grep -E -I -n -w PM_RESUME,0.3321688175201416,6,LC_ALL=C -linux_word,3,10,git grep (ignore),git grep -E -I -n -w PM_RESUME,0.34490489959716797,6,LC_ALL=C -linux_word,3,10,git grep (ignore),git grep -E -I -n -w PM_RESUME,0.34313368797302246,6,LC_ALL=C -linux_word,3,10,git grep (ignore),git grep -E -I -n -w PM_RESUME,0.3335700035095215,6,LC_ALL=C -linux_word,3,10,git grep (ignore),git grep -E -I -n -w PM_RESUME,0.33677148818969727,6,LC_ALL=C -linux_word,3,10,git grep (ignore),git grep -E -I -n -w PM_RESUME,0.3442800045013428,6,LC_ALL=C -linux_word,3,10,git grep (ignore),git grep -E -I -n -w PM_RESUME,0.3435385227203369,6,LC_ALL=C -linux_word,3,10,git grep (ignore),git grep -E -I -n -w PM_RESUME,0.3433525562286377,6,LC_ALL=C -linux_word,3,10,git grep (ignore),git grep -E -I -n -w PM_RESUME,0.3496122360229492,6,LC_ALL=C -linux_word,3,10,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.20868396759033203,6, -linux_word,3,10,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.20928955078125,6, -linux_word,3,10,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.21094799041748047,6, -linux_word,3,10,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.21063971519470215,6, -linux_word,3,10,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.20990324020385742,6, -linux_word,3,10,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.28969311714172363,6, -linux_word,3,10,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.20476388931274414,6, -linux_word,3,10,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.23818445205688477,6, -linux_word,3,10,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.2111814022064209,6, -linux_word,3,10,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.20949006080627441,6, -linux_word,3,10,ucg (whitelist),ucg --nosmart-case -w PM_RESUME,0.22462105751037598,6, -linux_word,3,10,ucg (whitelist),ucg --nosmart-case -w PM_RESUME,0.22188782691955566,6, -linux_word,3,10,ucg (whitelist),ucg --nosmart-case -w PM_RESUME,0.22634053230285645,6, -linux_word,3,10,ucg (whitelist),ucg --nosmart-case -w PM_RESUME,0.21634244918823242,6, -linux_word,3,10,ucg (whitelist),ucg --nosmart-case -w PM_RESUME,0.2205817699432373,6, -linux_word,3,10,ucg (whitelist),ucg --nosmart-case -w PM_RESUME,0.22465920448303223,6, -linux_word,3,10,ucg (whitelist),ucg --nosmart-case -w PM_RESUME,0.2336571216583252,6, -linux_word,3,10,ucg (whitelist),ucg --nosmart-case -w PM_RESUME,0.20835447311401367,6, -linux_word,3,10,ucg (whitelist),ucg --nosmart-case -w PM_RESUME,0.21285319328308105,6, -linux_word,3,10,ucg (whitelist),ucg --nosmart-case -w PM_RESUME,0.2190699577331543,6, -subtitles_en_alternate,3,10,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6189219951629639,848, -subtitles_en_alternate,3,10,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6190304756164551,848, -subtitles_en_alternate,3,10,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6199381351470947,848, -subtitles_en_alternate,3,10,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.618828296661377,848, -subtitles_en_alternate,3,10,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6196391582489014,848, -subtitles_en_alternate,3,10,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6181838512420654,848, -subtitles_en_alternate,3,10,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6187732219696045,848, -subtitles_en_alternate,3,10,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6184597015380859,848, -subtitles_en_alternate,3,10,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6172432899475098,848, -subtitles_en_alternate,3,10,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6174371242523193,848, -subtitles_en_alternate,3,10,ag (lines),ag -s Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.755958080291748,848, -subtitles_en_alternate,3,10,ag (lines),ag -s Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.757115602493286,848, -subtitles_en_alternate,3,10,ag (lines),ag -s Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.756659746170044,848, -subtitles_en_alternate,3,10,ag (lines),ag -s Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.755875825881958,848, -subtitles_en_alternate,3,10,ag (lines),ag -s Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.7559609413146973,848, -subtitles_en_alternate,3,10,ag (lines),ag -s Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.7556204795837402,848, -subtitles_en_alternate,3,10,ag (lines),ag -s Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.757873773574829,848, -subtitles_en_alternate,3,10,ag (lines),ag -s Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.7584357261657715,848, -subtitles_en_alternate,3,10,ag (lines),ag -s Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.7554702758789062,848, -subtitles_en_alternate,3,10,ag (lines),ag -s Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.756683111190796,848, -subtitles_en_alternate,3,10,ucg (lines),ucg --nosmart-case Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.4781913757324219,848, -subtitles_en_alternate,3,10,ucg (lines),ucg --nosmart-case Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.480832576751709,848, -subtitles_en_alternate,3,10,ucg (lines),ucg --nosmart-case Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.481184959411621,848, -subtitles_en_alternate,3,10,ucg (lines),ucg --nosmart-case Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.479053258895874,848, -subtitles_en_alternate,3,10,ucg (lines),ucg --nosmart-case Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.4790685176849365,848, -subtitles_en_alternate,3,10,ucg (lines),ucg --nosmart-case Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.4752089977264404,848, -subtitles_en_alternate,3,10,ucg (lines),ucg --nosmart-case Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.479438304901123,848, -subtitles_en_alternate,3,10,ucg (lines),ucg --nosmart-case Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.4795243740081787,848, -subtitles_en_alternate,3,10,ucg (lines),ucg --nosmart-case Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.4814894199371338,848, -subtitles_en_alternate,3,10,ucg (lines),ucg --nosmart-case Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.4802560806274414,848, -subtitles_en_alternate,3,10,grep (lines),grep -E -an Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.4137959480285645,848,LC_ALL=C -subtitles_en_alternate,3,10,grep (lines),grep -E -an Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.4180681705474854,848,LC_ALL=C -subtitles_en_alternate,3,10,grep (lines),grep -E -an Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.4078221321105957,848,LC_ALL=C -subtitles_en_alternate,3,10,grep (lines),grep -E -an Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.4076828956604004,848,LC_ALL=C -subtitles_en_alternate,3,10,grep (lines),grep -E -an Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.41274094581604,848,LC_ALL=C -subtitles_en_alternate,3,10,grep (lines),grep -E -an Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.4122402667999268,848,LC_ALL=C -subtitles_en_alternate,3,10,grep (lines),grep -E -an Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.409217357635498,848,LC_ALL=C -subtitles_en_alternate,3,10,grep (lines),grep -E -an Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.407381057739258,848,LC_ALL=C -subtitles_en_alternate,3,10,grep (lines),grep -E -an Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.413433790206909,848,LC_ALL=C -subtitles_en_alternate,3,10,grep (lines),grep -E -an Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.417088270187378,848,LC_ALL=C -subtitles_en_alternate,3,10,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.2927560806274414,848, -subtitles_en_alternate,3,10,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.29286980628967285,848, -subtitles_en_alternate,3,10,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.29212307929992676,848, -subtitles_en_alternate,3,10,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.2928035259246826,848, -subtitles_en_alternate,3,10,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.29462766647338867,848, -subtitles_en_alternate,3,10,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.29508256912231445,848, -subtitles_en_alternate,3,10,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.2949047088623047,848, -subtitles_en_alternate,3,10,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.29440784454345703,848, -subtitles_en_alternate,3,10,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.29571032524108887,848, -subtitles_en_alternate,3,10,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.2957477569580078,848, -subtitles_en_alternate,3,10,grep,grep -E -a Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.9552104473114014,848,LC_ALL=C -subtitles_en_alternate,3,10,grep,grep -E -a Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.9549355506896973,848,LC_ALL=C -subtitles_en_alternate,3,10,grep,grep -E -a Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.9537510871887207,848,LC_ALL=C -subtitles_en_alternate,3,10,grep,grep -E -a Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.9541327953338623,848,LC_ALL=C -subtitles_en_alternate,3,10,grep,grep -E -a Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.956911087036133,848,LC_ALL=C -subtitles_en_alternate,3,10,grep,grep -E -a Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.9570367336273193,848,LC_ALL=C -subtitles_en_alternate,3,10,grep,grep -E -a Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.9511656761169434,848,LC_ALL=C -subtitles_en_alternate,3,10,grep,grep -E -a Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.9506640434265137,848,LC_ALL=C -subtitles_en_alternate,3,10,grep,grep -E -a Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.9526963233947754,848,LC_ALL=C -subtitles_en_alternate,3,10,grep,grep -E -a Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.9588701725006104,848,LC_ALL=C -subtitles_en_alternate_casei,3,10,ag (ASCII),ag -s -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,5.168982028961182,862, -subtitles_en_alternate_casei,3,10,ag (ASCII),ag -s -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,5.168334722518921,862, -subtitles_en_alternate_casei,3,10,ag (ASCII),ag -s -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,5.168300628662109,862, -subtitles_en_alternate_casei,3,10,ag (ASCII),ag -s -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,5.167222499847412,862, -subtitles_en_alternate_casei,3,10,ag (ASCII),ag -s -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,5.166507244110107,862, -subtitles_en_alternate_casei,3,10,ag (ASCII),ag -s -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,5.170989274978638,862, -subtitles_en_alternate_casei,3,10,ag (ASCII),ag -s -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,5.1682024002075195,862, -subtitles_en_alternate_casei,3,10,ag (ASCII),ag -s -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,5.167780637741089,862, -subtitles_en_alternate_casei,3,10,ag (ASCII),ag -s -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,5.168872356414795,862, -subtitles_en_alternate_casei,3,10,ag (ASCII),ag -s -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,5.180398464202881,862, -subtitles_en_alternate_casei,3,10,ucg (ASCII),ucg -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.4541521072387695,862, -subtitles_en_alternate_casei,3,10,ucg (ASCII),ucg -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.4504010677337646,862, -subtitles_en_alternate_casei,3,10,ucg (ASCII),ucg -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.447232961654663,862, -subtitles_en_alternate_casei,3,10,ucg (ASCII),ucg -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.4495904445648193,862, -subtitles_en_alternate_casei,3,10,ucg (ASCII),ucg -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.4561190605163574,862, -subtitles_en_alternate_casei,3,10,ucg (ASCII),ucg -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.4501171112060547,862, -subtitles_en_alternate_casei,3,10,ucg (ASCII),ucg -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.446692705154419,862, -subtitles_en_alternate_casei,3,10,ucg (ASCII),ucg -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.4604244232177734,862, -subtitles_en_alternate_casei,3,10,ucg (ASCII),ucg -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.4578661918640137,862, -subtitles_en_alternate_casei,3,10,ucg (ASCII),ucg -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.4538376331329346,862, -subtitles_en_alternate_casei,3,10,grep (ASCII),grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.52874755859375,862,LC_ALL=C -subtitles_en_alternate_casei,3,10,grep (ASCII),grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.528880596160889,862,LC_ALL=C -subtitles_en_alternate_casei,3,10,grep (ASCII),grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.531128168106079,862,LC_ALL=C -subtitles_en_alternate_casei,3,10,grep (ASCII),grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.530141353607178,862,LC_ALL=C -subtitles_en_alternate_casei,3,10,grep (ASCII),grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.60682225227356,862,LC_ALL=C -subtitles_en_alternate_casei,3,10,grep (ASCII),grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.5284905433654785,862,LC_ALL=C -subtitles_en_alternate_casei,3,10,grep (ASCII),grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.528053283691406,862,LC_ALL=C -subtitles_en_alternate_casei,3,10,grep (ASCII),grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.52666974067688,862,LC_ALL=C -subtitles_en_alternate_casei,3,10,grep (ASCII),grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.530948877334595,862,LC_ALL=C -subtitles_en_alternate_casei,3,10,grep (ASCII),grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.527572393417358,862,LC_ALL=C -subtitles_en_alternate_casei,3,10,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.7230067253112793,862, -subtitles_en_alternate_casei,3,10,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.72373366355896,862, -subtitles_en_alternate_casei,3,10,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.7248330116271973,862, -subtitles_en_alternate_casei,3,10,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.723958730697632,862, -subtitles_en_alternate_casei,3,10,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.7269558906555176,862, -subtitles_en_alternate_casei,3,10,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.7254459857940674,862, -subtitles_en_alternate_casei,3,10,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.722374439239502,862, -subtitles_en_alternate_casei,3,10,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.7215871810913086,862, -subtitles_en_alternate_casei,3,10,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.722040891647339,862, -subtitles_en_alternate_casei,3,10,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.7217414379119873,862, -subtitles_en_alternate_casei,3,10,grep,grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,5.120846271514893,862,LC_ALL=en_US.UTF-8 -subtitles_en_alternate_casei,3,10,grep,grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,5.124289512634277,862,LC_ALL=en_US.UTF-8 -subtitles_en_alternate_casei,3,10,grep,grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,5.121231555938721,862,LC_ALL=en_US.UTF-8 -subtitles_en_alternate_casei,3,10,grep,grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,5.133900880813599,862,LC_ALL=en_US.UTF-8 -subtitles_en_alternate_casei,3,10,grep,grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,5.13477349281311,862,LC_ALL=en_US.UTF-8 -subtitles_en_alternate_casei,3,10,grep,grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,5.124036550521851,862,LC_ALL=en_US.UTF-8 -subtitles_en_alternate_casei,3,10,grep,grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,5.12525200843811,862,LC_ALL=en_US.UTF-8 -subtitles_en_alternate_casei,3,10,grep,grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,5.119184970855713,862,LC_ALL=en_US.UTF-8 -subtitles_en_alternate_casei,3,10,grep,grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,5.11840033531189,862,LC_ALL=en_US.UTF-8 -subtitles_en_alternate_casei,3,10,grep,grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,5.127475023269653,862,LC_ALL=en_US.UTF-8 -subtitles_en_literal,3,10,rg,rg Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.26776623725891113,629, -subtitles_en_literal,3,10,rg,rg Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.2677316665649414,629, -subtitles_en_literal,3,10,rg,rg Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.26764774322509766,629, -subtitles_en_literal,3,10,rg,rg Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.26764392852783203,629, -subtitles_en_literal,3,10,rg,rg Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.2678048610687256,629, -subtitles_en_literal,3,10,rg,rg Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.26839542388916016,629, -subtitles_en_literal,3,10,rg,rg Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.2679786682128906,629, -subtitles_en_literal,3,10,rg,rg Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.26825690269470215,629, -subtitles_en_literal,3,10,rg,rg Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.2678089141845703,629, -subtitles_en_literal,3,10,rg,rg Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.2678341865539551,629, -subtitles_en_literal,3,10,rg (no mmap),rg --no-mmap Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.3364849090576172,629, -subtitles_en_literal,3,10,rg (no mmap),rg --no-mmap Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.33446741104125977,629, -subtitles_en_literal,3,10,rg (no mmap),rg --no-mmap Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.3352184295654297,629, -subtitles_en_literal,3,10,rg (no mmap),rg --no-mmap Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.33528780937194824,629, -subtitles_en_literal,3,10,rg (no mmap),rg --no-mmap Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.33663368225097656,629, -subtitles_en_literal,3,10,rg (no mmap),rg --no-mmap Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.33841681480407715,629, -subtitles_en_literal,3,10,rg (no mmap),rg --no-mmap Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.3371107578277588,629, -subtitles_en_literal,3,10,rg (no mmap),rg --no-mmap Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.3376932144165039,629, -subtitles_en_literal,3,10,rg (no mmap),rg --no-mmap Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.33527708053588867,629, -subtitles_en_literal,3,10,rg (no mmap),rg --no-mmap Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.33412981033325195,629, -subtitles_en_literal,3,10,pt,pt -N Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.4306020736694336,629, -subtitles_en_literal,3,10,pt,pt -N Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.4329919815063477,629, -subtitles_en_literal,3,10,pt,pt -N Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.4332242012023926,629, -subtitles_en_literal,3,10,pt,pt -N Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.432997941970825,629, -subtitles_en_literal,3,10,pt,pt -N Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.4360785484313965,629, -subtitles_en_literal,3,10,pt,pt -N Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.435281276702881,629, -subtitles_en_literal,3,10,pt,pt -N Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.431150436401367,629, -subtitles_en_literal,3,10,pt,pt -N Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.4315969944000244,629, -subtitles_en_literal,3,10,pt,pt -N Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.4306139945983887,629, -subtitles_en_literal,3,10,pt,pt -N Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.4309916496276855,629, -subtitles_en_literal,3,10,sift,sift Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.32330894470214844,629, -subtitles_en_literal,3,10,sift,sift Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.3243591785430908,629, -subtitles_en_literal,3,10,sift,sift Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.3266782760620117,629, -subtitles_en_literal,3,10,sift,sift Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.32552504539489746,629, -subtitles_en_literal,3,10,sift,sift Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.32386016845703125,629, -subtitles_en_literal,3,10,sift,sift Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.3260154724121094,629, -subtitles_en_literal,3,10,sift,sift Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.32358860969543457,629, -subtitles_en_literal,3,10,sift,sift Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.3273475170135498,629, -subtitles_en_literal,3,10,sift,sift Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.3286449909210205,629, -subtitles_en_literal,3,10,sift,sift Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.3271455764770508,629, -subtitles_en_literal,3,10,grep,grep -a Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5178654193878174,629,LC_ALL=C -subtitles_en_literal,3,10,grep,grep -a Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5178477764129639,629,LC_ALL=C -subtitles_en_literal,3,10,grep,grep -a Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5173301696777344,629,LC_ALL=C -subtitles_en_literal,3,10,grep,grep -a Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5160887241363525,629,LC_ALL=C -subtitles_en_literal,3,10,grep,grep -a Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5176410675048828,629,LC_ALL=C -subtitles_en_literal,3,10,grep,grep -a Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5159375667572021,629,LC_ALL=C -subtitles_en_literal,3,10,grep,grep -a Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5159437656402588,629,LC_ALL=C -subtitles_en_literal,3,10,grep,grep -a Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5144126415252686,629,LC_ALL=C -subtitles_en_literal,3,10,grep,grep -a Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5155332088470459,629,LC_ALL=C -subtitles_en_literal,3,10,grep,grep -a Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.514521598815918,629,LC_ALL=C -subtitles_en_literal,3,10,rg (lines),rg -n Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5953242778778076,629, -subtitles_en_literal,3,10,rg (lines),rg -n Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5949890613555908,629, -subtitles_en_literal,3,10,rg (lines),rg -n Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5955290794372559,629, -subtitles_en_literal,3,10,rg (lines),rg -n Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5951504707336426,629, -subtitles_en_literal,3,10,rg (lines),rg -n Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5948066711425781,629, -subtitles_en_literal,3,10,rg (lines),rg -n Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5955345630645752,629, -subtitles_en_literal,3,10,rg (lines),rg -n Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5947279930114746,629, -subtitles_en_literal,3,10,rg (lines),rg -n Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5945889949798584,629, -subtitles_en_literal,3,10,rg (lines),rg -n Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5973446369171143,629, -subtitles_en_literal,3,10,rg (lines),rg -n Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.594796895980835,629, -subtitles_en_literal,3,10,ag (lines),ag -s Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.734492301940918,629, -subtitles_en_literal,3,10,ag (lines),ag -s Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.7287397384643555,629, -subtitles_en_literal,3,10,ag (lines),ag -s Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.7362167835235596,629, -subtitles_en_literal,3,10,ag (lines),ag -s Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.7313451766967773,629, -subtitles_en_literal,3,10,ag (lines),ag -s Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.7278831005096436,629, -subtitles_en_literal,3,10,ag (lines),ag -s Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.728785276412964,629, -subtitles_en_literal,3,10,ag (lines),ag -s Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.7299938201904297,629, -subtitles_en_literal,3,10,ag (lines),ag -s Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.727299213409424,629, -subtitles_en_literal,3,10,ag (lines),ag -s Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.7277636528015137,629, -subtitles_en_literal,3,10,ag (lines),ag -s Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.7295165061950684,629, -subtitles_en_literal,3,10,ucg (lines),ucg --nosmart-case Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.7461349964141846,629, -subtitles_en_literal,3,10,ucg (lines),ucg --nosmart-case Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.7452898025512695,629, -subtitles_en_literal,3,10,ucg (lines),ucg --nosmart-case Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.7452714443206787,629, -subtitles_en_literal,3,10,ucg (lines),ucg --nosmart-case Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.744922399520874,629, -subtitles_en_literal,3,10,ucg (lines),ucg --nosmart-case Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.7460696697235107,629, -subtitles_en_literal,3,10,ucg (lines),ucg --nosmart-case Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.7454876899719238,629, -subtitles_en_literal,3,10,ucg (lines),ucg --nosmart-case Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.7456295490264893,629, -subtitles_en_literal,3,10,ucg (lines),ucg --nosmart-case Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.7443864345550537,629, -subtitles_en_literal,3,10,ucg (lines),ucg --nosmart-case Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.7447819709777832,629, -subtitles_en_literal,3,10,ucg (lines),ucg --nosmart-case Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.7446470260620117,629, -subtitles_en_literal,3,10,pt (lines),pt Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.4404242038726807,629, -subtitles_en_literal,3,10,pt (lines),pt Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.4294676780700684,629, -subtitles_en_literal,3,10,pt (lines),pt Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.429917097091675,629, -subtitles_en_literal,3,10,pt (lines),pt Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.431140422821045,629, -subtitles_en_literal,3,10,pt (lines),pt Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.4285945892333984,629, -subtitles_en_literal,3,10,pt (lines),pt Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.4293277263641357,629, -subtitles_en_literal,3,10,pt (lines),pt Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.4368669986724854,629, -subtitles_en_literal,3,10,pt (lines),pt Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.4359662532806396,629, -subtitles_en_literal,3,10,pt (lines),pt Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.4405126571655273,629, -subtitles_en_literal,3,10,pt (lines),pt Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,3.433344841003418,629, -subtitles_en_literal,3,10,sift (lines),sift -n Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.7574958801269531,629, -subtitles_en_literal,3,10,sift (lines),sift -n Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.7570157051086426,629, -subtitles_en_literal,3,10,sift (lines),sift -n Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.7525804042816162,629, -subtitles_en_literal,3,10,sift (lines),sift -n Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.7591047286987305,629, -subtitles_en_literal,3,10,sift (lines),sift -n Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.755040168762207,629, -subtitles_en_literal,3,10,sift (lines),sift -n Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.7555766105651855,629, -subtitles_en_literal,3,10,sift (lines),sift -n Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.7529222965240479,629, -subtitles_en_literal,3,10,sift (lines),sift -n Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.758681058883667,629, -subtitles_en_literal,3,10,sift (lines),sift -n Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.7559700012207031,629, -subtitles_en_literal,3,10,sift (lines),sift -n Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.7559340000152588,629, -subtitles_en_literal,3,10,grep (lines),grep -an Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.9682326316833496,629,LC_ALL=C -subtitles_en_literal,3,10,grep (lines),grep -an Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.9697835445404053,629,LC_ALL=C -subtitles_en_literal,3,10,grep (lines),grep -an Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.9684174060821533,629,LC_ALL=C -subtitles_en_literal,3,10,grep (lines),grep -an Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.9705235958099365,629,LC_ALL=C -subtitles_en_literal,3,10,grep (lines),grep -an Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.9682950973510742,629,LC_ALL=C -subtitles_en_literal,3,10,grep (lines),grep -an Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.9695034027099609,629,LC_ALL=C -subtitles_en_literal,3,10,grep (lines),grep -an Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.9688384532928467,629,LC_ALL=C -subtitles_en_literal,3,10,grep (lines),grep -an Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.9686503410339355,629,LC_ALL=C -subtitles_en_literal,3,10,grep (lines),grep -an Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.9681143760681152,629,LC_ALL=C -subtitles_en_literal,3,10,grep (lines),grep -an Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.9680168628692627,629,LC_ALL=C -subtitles_en_literal_casei,3,10,rg,rg -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.3666412830352783,642, -subtitles_en_literal_casei,3,10,rg,rg -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.3665914535522461,642, -subtitles_en_literal_casei,3,10,rg,rg -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.36571455001831055,642, -subtitles_en_literal_casei,3,10,rg,rg -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.3664999008178711,642, -subtitles_en_literal_casei,3,10,rg,rg -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.36658453941345215,642, -subtitles_en_literal_casei,3,10,rg,rg -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.3661923408508301,642, -subtitles_en_literal_casei,3,10,rg,rg -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.36447882652282715,642, -subtitles_en_literal_casei,3,10,rg,rg -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.3663473129272461,642, -subtitles_en_literal_casei,3,10,rg,rg -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.36589932441711426,642, -subtitles_en_literal_casei,3,10,rg,rg -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.3653714656829834,642, -subtitles_en_literal_casei,3,10,grep,grep -ai Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.081154823303223,642,LC_ALL=en_US.UTF-8 -subtitles_en_literal_casei,3,10,grep,grep -ai Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.084660291671753,642,LC_ALL=en_US.UTF-8 -subtitles_en_literal_casei,3,10,grep,grep -ai Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.08470344543457,642,LC_ALL=en_US.UTF-8 -subtitles_en_literal_casei,3,10,grep,grep -ai Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.082594156265259,642,LC_ALL=en_US.UTF-8 -subtitles_en_literal_casei,3,10,grep,grep -ai Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.080471515655518,642,LC_ALL=en_US.UTF-8 -subtitles_en_literal_casei,3,10,grep,grep -ai Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.086612701416016,642,LC_ALL=en_US.UTF-8 -subtitles_en_literal_casei,3,10,grep,grep -ai Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.081760406494141,642,LC_ALL=en_US.UTF-8 -subtitles_en_literal_casei,3,10,grep,grep -ai Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.097002983093262,642,LC_ALL=en_US.UTF-8 -subtitles_en_literal_casei,3,10,grep,grep -ai Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.08205771446228,642,LC_ALL=en_US.UTF-8 -subtitles_en_literal_casei,3,10,grep,grep -ai Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.081174373626709,642,LC_ALL=en_US.UTF-8 -subtitles_en_literal_casei,3,10,grep (ASCII),grep -E -ai Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6137702465057373,642,LC_ALL=C -subtitles_en_literal_casei,3,10,grep (ASCII),grep -E -ai Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.613584041595459,642,LC_ALL=C -subtitles_en_literal_casei,3,10,grep (ASCII),grep -E -ai Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6138026714324951,642,LC_ALL=C -subtitles_en_literal_casei,3,10,grep (ASCII),grep -E -ai Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6139190196990967,642,LC_ALL=C -subtitles_en_literal_casei,3,10,grep (ASCII),grep -E -ai Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.613776445388794,642,LC_ALL=C -subtitles_en_literal_casei,3,10,grep (ASCII),grep -E -ai Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6142146587371826,642,LC_ALL=C -subtitles_en_literal_casei,3,10,grep (ASCII),grep -E -ai Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6156847476959229,642,LC_ALL=C -subtitles_en_literal_casei,3,10,grep (ASCII),grep -E -ai Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6130235195159912,642,LC_ALL=C -subtitles_en_literal_casei,3,10,grep (ASCII),grep -E -ai Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6155576705932617,642,LC_ALL=C -subtitles_en_literal_casei,3,10,grep (ASCII),grep -E -ai Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6164846420288086,642,LC_ALL=C -subtitles_en_literal_casei,3,10,rg (lines),rg -n -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6970095634460449,642, -subtitles_en_literal_casei,3,10,rg (lines),rg -n -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6997818946838379,642, -subtitles_en_literal_casei,3,10,rg (lines),rg -n -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6979782581329346,642, -subtitles_en_literal_casei,3,10,rg (lines),rg -n -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6970696449279785,642, -subtitles_en_literal_casei,3,10,rg (lines),rg -n -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6959774494171143,642, -subtitles_en_literal_casei,3,10,rg (lines),rg -n -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6961612701416016,642, -subtitles_en_literal_casei,3,10,rg (lines),rg -n -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6932253837585449,642, -subtitles_en_literal_casei,3,10,rg (lines),rg -n -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6929948329925537,642, -subtitles_en_literal_casei,3,10,rg (lines),rg -n -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6953890323638916,642, -subtitles_en_literal_casei,3,10,rg (lines),rg -n -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6952941417694092,642, -subtitles_en_literal_casei,3,10,ag (lines) (ASCII),ag -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.7740752696990967,642, -subtitles_en_literal_casei,3,10,ag (lines) (ASCII),ag -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.774446964263916,642, -subtitles_en_literal_casei,3,10,ag (lines) (ASCII),ag -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.7716448307037354,642, -subtitles_en_literal_casei,3,10,ag (lines) (ASCII),ag -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.773153781890869,642, -subtitles_en_literal_casei,3,10,ag (lines) (ASCII),ag -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.779618740081787,642, -subtitles_en_literal_casei,3,10,ag (lines) (ASCII),ag -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.7801287174224854,642, -subtitles_en_literal_casei,3,10,ag (lines) (ASCII),ag -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.781130075454712,642, -subtitles_en_literal_casei,3,10,ag (lines) (ASCII),ag -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.772829055786133,642, -subtitles_en_literal_casei,3,10,ag (lines) (ASCII),ag -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.77199649810791,642, -subtitles_en_literal_casei,3,10,ag (lines) (ASCII),ag -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.7716152667999268,642, -subtitles_en_literal_casei,3,10,ucg (lines) (ASCII),ucg -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.839766263961792,642, -subtitles_en_literal_casei,3,10,ucg (lines) (ASCII),ucg -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.8391139507293701,642, -subtitles_en_literal_casei,3,10,ucg (lines) (ASCII),ucg -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.8380751609802246,642, -subtitles_en_literal_casei,3,10,ucg (lines) (ASCII),ucg -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.840296745300293,642, -subtitles_en_literal_casei,3,10,ucg (lines) (ASCII),ucg -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.8403871059417725,642, -subtitles_en_literal_casei,3,10,ucg (lines) (ASCII),ucg -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.8408434391021729,642, -subtitles_en_literal_casei,3,10,ucg (lines) (ASCII),ucg -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.8414220809936523,642, -subtitles_en_literal_casei,3,10,ucg (lines) (ASCII),ucg -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.8398075103759766,642, -subtitles_en_literal_casei,3,10,ucg (lines) (ASCII),ucg -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.8436241149902344,642, -subtitles_en_literal_casei,3,10,ucg (lines) (ASCII),ucg -i Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.8423728942871094,642, -subtitles_en_literal_word,3,10,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5950007438659668,629, -subtitles_en_literal_word,3,10,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5956854820251465,629, -subtitles_en_literal_word,3,10,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5952165126800537,629, -subtitles_en_literal_word,3,10,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5980286598205566,629, -subtitles_en_literal_word,3,10,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5956542491912842,629, -subtitles_en_literal_word,3,10,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5966405868530273,629, -subtitles_en_literal_word,3,10,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5958805084228516,629, -subtitles_en_literal_word,3,10,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5963141918182373,629, -subtitles_en_literal_word,3,10,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5990002155303955,629, -subtitles_en_literal_word,3,10,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5966975688934326,629, -subtitles_en_literal_word,3,10,ag (ASCII),ag -sw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.7282555103302,629, -subtitles_en_literal_word,3,10,ag (ASCII),ag -sw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.729177474975586,629, -subtitles_en_literal_word,3,10,ag (ASCII),ag -sw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.7297959327697754,629, -subtitles_en_literal_word,3,10,ag (ASCII),ag -sw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.7296860218048096,629, -subtitles_en_literal_word,3,10,ag (ASCII),ag -sw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.729125499725342,629, -subtitles_en_literal_word,3,10,ag (ASCII),ag -sw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.729316234588623,629, -subtitles_en_literal_word,3,10,ag (ASCII),ag -sw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.7287533283233643,629, -subtitles_en_literal_word,3,10,ag (ASCII),ag -sw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.7305104732513428,629, -subtitles_en_literal_word,3,10,ag (ASCII),ag -sw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.7299206256866455,629, -subtitles_en_literal_word,3,10,ag (ASCII),ag -sw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.729327440261841,629, -subtitles_en_literal_word,3,10,ucg (ASCII),ucg --nosmart-case Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.8094220161437988,629, -subtitles_en_literal_word,3,10,ucg (ASCII),ucg --nosmart-case Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.8118293285369873,629, -subtitles_en_literal_word,3,10,ucg (ASCII),ucg --nosmart-case Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.8110437393188477,629, -subtitles_en_literal_word,3,10,ucg (ASCII),ucg --nosmart-case Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.811244010925293,629, -subtitles_en_literal_word,3,10,ucg (ASCII),ucg --nosmart-case Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.8089673519134521,629, -subtitles_en_literal_word,3,10,ucg (ASCII),ucg --nosmart-case Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.8087558746337891,629, -subtitles_en_literal_word,3,10,ucg (ASCII),ucg --nosmart-case Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.8099534511566162,629, -subtitles_en_literal_word,3,10,ucg (ASCII),ucg --nosmart-case Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.805889368057251,629, -subtitles_en_literal_word,3,10,ucg (ASCII),ucg --nosmart-case Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.8085830211639404,629, -subtitles_en_literal_word,3,10,ucg (ASCII),ucg --nosmart-case Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.810387134552002,629, -subtitles_en_literal_word,3,10,grep (ASCII),grep -anw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.969839334487915,629,LC_ALL=C -subtitles_en_literal_word,3,10,grep (ASCII),grep -anw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.9697055816650391,629,LC_ALL=C -subtitles_en_literal_word,3,10,grep (ASCII),grep -anw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.969874382019043,629,LC_ALL=C -subtitles_en_literal_word,3,10,grep (ASCII),grep -anw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.9701571464538574,629,LC_ALL=C -subtitles_en_literal_word,3,10,grep (ASCII),grep -anw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.9694199562072754,629,LC_ALL=C -subtitles_en_literal_word,3,10,grep (ASCII),grep -anw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.9696424007415771,629,LC_ALL=C -subtitles_en_literal_word,3,10,grep (ASCII),grep -anw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.9697527885437012,629,LC_ALL=C -subtitles_en_literal_word,3,10,grep (ASCII),grep -anw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.968994140625,629,LC_ALL=C -subtitles_en_literal_word,3,10,grep (ASCII),grep -anw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.9701812267303467,629,LC_ALL=C -subtitles_en_literal_word,3,10,grep (ASCII),grep -anw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.9686706066131592,629,LC_ALL=C -subtitles_en_literal_word,3,10,rg,rg -nw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.595914363861084,629, -subtitles_en_literal_word,3,10,rg,rg -nw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5983798503875732,629, -subtitles_en_literal_word,3,10,rg,rg -nw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5960469245910645,629, -subtitles_en_literal_word,3,10,rg,rg -nw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5948517322540283,629, -subtitles_en_literal_word,3,10,rg,rg -nw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5958602428436279,629, -subtitles_en_literal_word,3,10,rg,rg -nw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5954585075378418,629, -subtitles_en_literal_word,3,10,rg,rg -nw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5953717231750488,629, -subtitles_en_literal_word,3,10,rg,rg -nw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5959024429321289,629, -subtitles_en_literal_word,3,10,rg,rg -nw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5959782600402832,629, -subtitles_en_literal_word,3,10,rg,rg -nw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.5955371856689453,629, -subtitles_en_literal_word,3,10,grep,grep -anw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.9723165035247803,629,LC_ALL=en_US.UTF-8 -subtitles_en_literal_word,3,10,grep,grep -anw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.9710309505462646,629,LC_ALL=en_US.UTF-8 -subtitles_en_literal_word,3,10,grep,grep -anw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.9703977108001709,629,LC_ALL=en_US.UTF-8 -subtitles_en_literal_word,3,10,grep,grep -anw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.9703128337860107,629,LC_ALL=en_US.UTF-8 -subtitles_en_literal_word,3,10,grep,grep -anw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.9703538417816162,629,LC_ALL=en_US.UTF-8 -subtitles_en_literal_word,3,10,grep,grep -anw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.9708397388458252,629,LC_ALL=en_US.UTF-8 -subtitles_en_literal_word,3,10,grep,grep -anw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.9728231430053711,629,LC_ALL=en_US.UTF-8 -subtitles_en_literal_word,3,10,grep,grep -anw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.9786312580108643,629,LC_ALL=en_US.UTF-8 -subtitles_en_literal_word,3,10,grep,grep -anw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.9749376773834229,629,LC_ALL=en_US.UTF-8 -subtitles_en_literal_word,3,10,grep,grep -anw Sherlock Holmes /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.9707028865814209,629,LC_ALL=en_US.UTF-8 -subtitles_en_no_literal,3,10,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.7828025817871094,13, -subtitles_en_no_literal,3,10,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.7794389724731445,13, -subtitles_en_no_literal,3,10,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.778043270111084,13, -subtitles_en_no_literal,3,10,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.774141788482666,13, -subtitles_en_no_literal,3,10,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.778355121612549,13, -subtitles_en_no_literal,3,10,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.7741646766662598,13, -subtitles_en_no_literal,3,10,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.772979259490967,13, -subtitles_en_no_literal,3,10,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.7767364978790283,13, -subtitles_en_no_literal,3,10,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.7799744606018066,13, -subtitles_en_no_literal,3,10,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.7726826667785645,13, -subtitles_en_no_literal,3,10,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.551705837249756,13, -subtitles_en_no_literal,3,10,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.5482068061828613,13, -subtitles_en_no_literal,3,10,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.538416624069214,13, -subtitles_en_no_literal,3,10,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.5385212898254395,13, -subtitles_en_no_literal,3,10,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.5387394428253174,13, -subtitles_en_no_literal,3,10,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.5385680198669434,13, -subtitles_en_no_literal,3,10,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.5381128787994385,13, -subtitles_en_no_literal,3,10,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.538067579269409,13, -subtitles_en_no_literal,3,10,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.5391359329223633,13, -subtitles_en_no_literal,3,10,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,2.5382723808288574,13, -subtitles_en_no_literal,3,10,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,10.07424545288086,48, -subtitles_en_no_literal,3,10,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,10.07216191291809,48, -subtitles_en_no_literal,3,10,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,10.090161323547363,48, -subtitles_en_no_literal,3,10,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,10.073503732681274,48, -subtitles_en_no_literal,3,10,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,10.074660062789917,48, -subtitles_en_no_literal,3,10,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,10.071975708007812,48, -subtitles_en_no_literal,3,10,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,10.076007604598999,48, -subtitles_en_no_literal,3,10,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,10.074021816253662,48, -subtitles_en_no_literal,3,10,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,10.075836896896362,48, -subtitles_en_no_literal,3,10,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,10.07709789276123,48, -subtitles_en_no_literal,3,10,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,7.783349275588989,13, -subtitles_en_no_literal,3,10,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,7.7711498737335205,13, -subtitles_en_no_literal,3,10,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,7.7679526805877686,13, -subtitles_en_no_literal,3,10,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,7.769197463989258,13, -subtitles_en_no_literal,3,10,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,7.770420789718628,13, -subtitles_en_no_literal,3,10,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,7.770123720169067,13, -subtitles_en_no_literal,3,10,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,7.769317150115967,13, -subtitles_en_no_literal,3,10,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,7.772680997848511,13, -subtitles_en_no_literal,3,10,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,7.769444227218628,13, -subtitles_en_no_literal,3,10,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,7.768393516540527,13, -subtitles_en_no_literal,3,10,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.407429218292236,13,LC_ALL=C -subtitles_en_no_literal,3,10,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.40935754776001,13,LC_ALL=C -subtitles_en_no_literal,3,10,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.409480810165405,13,LC_ALL=C -subtitles_en_no_literal,3,10,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.409695625305176,13,LC_ALL=C -subtitles_en_no_literal,3,10,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.4078004360198975,13,LC_ALL=C -subtitles_en_no_literal,3,10,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.413295745849609,13,LC_ALL=C -subtitles_en_no_literal,3,10,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.420169353485107,13,LC_ALL=C -subtitles_en_no_literal,3,10,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.414563179016113,13,LC_ALL=C -subtitles_en_no_literal,3,10,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.40968656539917,13,LC_ALL=C -subtitles_en_no_literal,3,10,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.410497188568115,13,LC_ALL=C -subtitles_en_surrounding_words,3,10,rg,rg -n \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.605414628982544,317, -subtitles_en_surrounding_words,3,10,rg,rg -n \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6049544811248779,317, -subtitles_en_surrounding_words,3,10,rg,rg -n \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6051681041717529,317, -subtitles_en_surrounding_words,3,10,rg,rg -n \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6063950061798096,317, -subtitles_en_surrounding_words,3,10,rg,rg -n \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6052758693695068,317, -subtitles_en_surrounding_words,3,10,rg,rg -n \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6048481464385986,317, -subtitles_en_surrounding_words,3,10,rg,rg -n \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.60489821434021,317, -subtitles_en_surrounding_words,3,10,rg,rg -n \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6051614284515381,317, -subtitles_en_surrounding_words,3,10,rg,rg -n \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6050229072570801,317, -subtitles_en_surrounding_words,3,10,rg,rg -n \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6052291393280029,317, -subtitles_en_surrounding_words,3,10,grep,grep -E -an \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.2898845672607422,317,LC_ALL=en_US.UTF-8 -subtitles_en_surrounding_words,3,10,grep,grep -E -an \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.2869348526000977,317,LC_ALL=en_US.UTF-8 -subtitles_en_surrounding_words,3,10,grep,grep -E -an \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.2862842082977295,317,LC_ALL=en_US.UTF-8 -subtitles_en_surrounding_words,3,10,grep,grep -E -an \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.2864055633544922,317,LC_ALL=en_US.UTF-8 -subtitles_en_surrounding_words,3,10,grep,grep -E -an \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.2851040363311768,317,LC_ALL=en_US.UTF-8 -subtitles_en_surrounding_words,3,10,grep,grep -E -an \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.285186529159546,317,LC_ALL=en_US.UTF-8 -subtitles_en_surrounding_words,3,10,grep,grep -E -an \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.2865922451019287,317,LC_ALL=en_US.UTF-8 -subtitles_en_surrounding_words,3,10,grep,grep -E -an \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.2853999137878418,317,LC_ALL=en_US.UTF-8 -subtitles_en_surrounding_words,3,10,grep,grep -E -an \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.2826249599456787,317,LC_ALL=en_US.UTF-8 -subtitles_en_surrounding_words,3,10,grep,grep -E -an \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.2860167026519775,317,LC_ALL=en_US.UTF-8 -subtitles_en_surrounding_words,3,10,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6012325286865234,317, -subtitles_en_surrounding_words,3,10,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.601163387298584,317, -subtitles_en_surrounding_words,3,10,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6019690036773682,317, -subtitles_en_surrounding_words,3,10,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6013593673706055,317, -subtitles_en_surrounding_words,3,10,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6016466617584229,317, -subtitles_en_surrounding_words,3,10,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6019842624664307,317, -subtitles_en_surrounding_words,3,10,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6014797687530518,317, -subtitles_en_surrounding_words,3,10,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6019721031188965,317, -subtitles_en_surrounding_words,3,10,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.601752758026123,317, -subtitles_en_surrounding_words,3,10,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,0.6017599105834961,317, -subtitles_en_surrounding_words,3,10,ag (ASCII),ag -s \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,11.68667197227478,323, -subtitles_en_surrounding_words,3,10,ag (ASCII),ag -s \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,11.660332679748535,323, -subtitles_en_surrounding_words,3,10,ag (ASCII),ag -s \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,11.660835266113281,323, -subtitles_en_surrounding_words,3,10,ag (ASCII),ag -s \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,11.660434007644653,323, -subtitles_en_surrounding_words,3,10,ag (ASCII),ag -s \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,11.664055347442627,323, -subtitles_en_surrounding_words,3,10,ag (ASCII),ag -s \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,11.662182569503784,323, -subtitles_en_surrounding_words,3,10,ag (ASCII),ag -s \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,11.660929679870605,323, -subtitles_en_surrounding_words,3,10,ag (ASCII),ag -s \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,11.657424688339233,323, -subtitles_en_surrounding_words,3,10,ag (ASCII),ag -s \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,11.659005165100098,323, -subtitles_en_surrounding_words,3,10,ag (ASCII),ag -s \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,11.660208225250244,323, -subtitles_en_surrounding_words,3,10,ucg (ASCII),ucg --nosmart-case \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.690763711929321,317, -subtitles_en_surrounding_words,3,10,ucg (ASCII),ucg --nosmart-case \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.688983201980591,317, -subtitles_en_surrounding_words,3,10,ucg (ASCII),ucg --nosmart-case \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.69182276725769,317, -subtitles_en_surrounding_words,3,10,ucg (ASCII),ucg --nosmart-case \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.690439462661743,317, -subtitles_en_surrounding_words,3,10,ucg (ASCII),ucg --nosmart-case \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.689068794250488,317, -subtitles_en_surrounding_words,3,10,ucg (ASCII),ucg --nosmart-case \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.6937761306762695,317, -subtitles_en_surrounding_words,3,10,ucg (ASCII),ucg --nosmart-case \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.6903581619262695,317, -subtitles_en_surrounding_words,3,10,ucg (ASCII),ucg --nosmart-case \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.687433242797852,317, -subtitles_en_surrounding_words,3,10,ucg (ASCII),ucg --nosmart-case \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.68887186050415,317, -subtitles_en_surrounding_words,3,10,ucg (ASCII),ucg --nosmart-case \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,4.686846017837524,317, -subtitles_en_surrounding_words,3,10,grep (ASCII),grep -E -an \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.2726647853851318,317,LC_ALL=C -subtitles_en_surrounding_words,3,10,grep (ASCII),grep -E -an \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.2737226486206055,317,LC_ALL=C -subtitles_en_surrounding_words,3,10,grep (ASCII),grep -E -an \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.2792630195617676,317,LC_ALL=C -subtitles_en_surrounding_words,3,10,grep (ASCII),grep -E -an \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.2764034271240234,317,LC_ALL=C -subtitles_en_surrounding_words,3,10,grep (ASCII),grep -E -an \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.2774908542633057,317,LC_ALL=C -subtitles_en_surrounding_words,3,10,grep (ASCII),grep -E -an \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.2776587009429932,317,LC_ALL=C -subtitles_en_surrounding_words,3,10,grep (ASCII),grep -E -an \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.2776594161987305,317,LC_ALL=C -subtitles_en_surrounding_words,3,10,grep (ASCII),grep -E -an \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.2777113914489746,317,LC_ALL=C -subtitles_en_surrounding_words,3,10,grep (ASCII),grep -E -an \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.2754859924316406,317,LC_ALL=C -subtitles_en_surrounding_words,3,10,grep (ASCII),grep -E -an \w+\s+Holmes\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.sample.en,1.2763752937316895,317,LC_ALL=C -subtitles_ru_alternate,3,10,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.9028000831604004,691, -subtitles_ru_alternate,3,10,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.901930332183838,691, -subtitles_ru_alternate,3,10,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.9000146389007568,691, -subtitles_ru_alternate,3,10,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.9049570560455322,691, -subtitles_ru_alternate,3,10,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.9017412662506104,691, -subtitles_ru_alternate,3,10,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.9024994373321533,691, -subtitles_ru_alternate,3,10,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.9020378589630127,691, -subtitles_ru_alternate,3,10,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.901792049407959,691, -subtitles_ru_alternate,3,10,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.9039933681488037,691, -subtitles_ru_alternate,3,10,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.8997247219085693,691, -subtitles_ru_alternate,3,10,ag (lines),ag -s Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,5.9008402824401855,691, -subtitles_ru_alternate,3,10,ag (lines),ag -s Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,5.893612861633301,691, -subtitles_ru_alternate,3,10,ag (lines),ag -s Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,5.8897013664245605,691, -subtitles_ru_alternate,3,10,ag (lines),ag -s Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,5.890028238296509,691, -subtitles_ru_alternate,3,10,ag (lines),ag -s Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,5.889577865600586,691, -subtitles_ru_alternate,3,10,ag (lines),ag -s Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,5.890358209609985,691, -subtitles_ru_alternate,3,10,ag (lines),ag -s Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,5.890805244445801,691, -subtitles_ru_alternate,3,10,ag (lines),ag -s Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,5.891323804855347,691, -subtitles_ru_alternate,3,10,ag (lines),ag -s Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,5.890573501586914,691, -subtitles_ru_alternate,3,10,ag (lines),ag -s Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,5.892488718032837,691, -subtitles_ru_alternate,3,10,ucg (lines),ucg --nosmart-case Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.8788585662841797,691, -subtitles_ru_alternate,3,10,ucg (lines),ucg --nosmart-case Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.863766670227051,691, -subtitles_ru_alternate,3,10,ucg (lines),ucg --nosmart-case Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.8625569343566895,691, -subtitles_ru_alternate,3,10,ucg (lines),ucg --nosmart-case Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.857377529144287,691, -subtitles_ru_alternate,3,10,ucg (lines),ucg --nosmart-case Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.8643264770507812,691, -subtitles_ru_alternate,3,10,ucg (lines),ucg --nosmart-case Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.863802909851074,691, -subtitles_ru_alternate,3,10,ucg (lines),ucg --nosmart-case Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.859354019165039,691, -subtitles_ru_alternate,3,10,ucg (lines),ucg --nosmart-case Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.8629326820373535,691, -subtitles_ru_alternate,3,10,ucg (lines),ucg --nosmart-case Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.862051486968994,691, -subtitles_ru_alternate,3,10,ucg (lines),ucg --nosmart-case Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.8658623695373535,691, -subtitles_ru_alternate,3,10,grep (lines),grep -E -an Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.515479803085327,691,LC_ALL=C -subtitles_ru_alternate,3,10,grep (lines),grep -E -an Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.503782033920288,691,LC_ALL=C -subtitles_ru_alternate,3,10,grep (lines),grep -E -an Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.510310888290405,691,LC_ALL=C -subtitles_ru_alternate,3,10,grep (lines),grep -E -an Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.509161472320557,691,LC_ALL=C -subtitles_ru_alternate,3,10,grep (lines),grep -E -an Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.52185344696045,691,LC_ALL=C -subtitles_ru_alternate,3,10,grep (lines),grep -E -an Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.509994506835938,691,LC_ALL=C -subtitles_ru_alternate,3,10,grep (lines),grep -E -an Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.509246349334717,691,LC_ALL=C -subtitles_ru_alternate,3,10,grep (lines),grep -E -an Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.511957168579102,691,LC_ALL=C -subtitles_ru_alternate,3,10,grep (lines),grep -E -an Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.508247375488281,691,LC_ALL=C -subtitles_ru_alternate,3,10,grep (lines),grep -E -an Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.51308274269104,691,LC_ALL=C -subtitles_ru_alternate,3,10,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.3016955852508545,691, -subtitles_ru_alternate,3,10,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.299199104309082,691, -subtitles_ru_alternate,3,10,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.3037669658660889,691, -subtitles_ru_alternate,3,10,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.303251028060913,691, -subtitles_ru_alternate,3,10,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.2978003025054932,691, -subtitles_ru_alternate,3,10,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.3006718158721924,691, -subtitles_ru_alternate,3,10,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.3024837970733643,691, -subtitles_ru_alternate,3,10,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.297926425933838,691, -subtitles_ru_alternate,3,10,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.297990083694458,691, -subtitles_ru_alternate,3,10,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.298790693283081,691, -subtitles_ru_alternate,3,10,grep,grep -E -a Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,7.991622447967529,691,LC_ALL=C -subtitles_ru_alternate,3,10,grep,grep -E -a Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,7.981353759765625,691,LC_ALL=C -subtitles_ru_alternate,3,10,grep,grep -E -a Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,7.982196092605591,691,LC_ALL=C -subtitles_ru_alternate,3,10,grep,grep -E -a Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,7.99190878868103,691,LC_ALL=C -subtitles_ru_alternate,3,10,grep,grep -E -a Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.016578912734985,691,LC_ALL=C -subtitles_ru_alternate,3,10,grep,grep -E -a Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,7.9818947315216064,691,LC_ALL=C -subtitles_ru_alternate,3,10,grep,grep -E -a Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,7.982048988342285,691,LC_ALL=C -subtitles_ru_alternate,3,10,grep,grep -E -a Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,7.986757755279541,691,LC_ALL=C -subtitles_ru_alternate,3,10,grep,grep -E -a Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,7.99491548538208,691,LC_ALL=C -subtitles_ru_alternate,3,10,grep,grep -E -a Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.03109359741211,691,LC_ALL=C -subtitles_ru_alternate_casei,3,10,ag (ASCII),ag -s -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,5.890226364135742,691, -subtitles_ru_alternate_casei,3,10,ag (ASCII),ag -s -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,5.891613721847534,691, -subtitles_ru_alternate_casei,3,10,ag (ASCII),ag -s -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,5.890208959579468,691, -subtitles_ru_alternate_casei,3,10,ag (ASCII),ag -s -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,5.892171859741211,691, -subtitles_ru_alternate_casei,3,10,ag (ASCII),ag -s -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,5.891136407852173,691, -subtitles_ru_alternate_casei,3,10,ag (ASCII),ag -s -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,5.8886566162109375,691, -subtitles_ru_alternate_casei,3,10,ag (ASCII),ag -s -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,5.889105319976807,691, -subtitles_ru_alternate_casei,3,10,ag (ASCII),ag -s -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,5.890317916870117,691, -subtitles_ru_alternate_casei,3,10,ag (ASCII),ag -s -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,5.890429496765137,691, -subtitles_ru_alternate_casei,3,10,ag (ASCII),ag -s -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,5.891230344772339,691, -subtitles_ru_alternate_casei,3,10,ucg (ASCII),ucg -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.868140935897827,691, -subtitles_ru_alternate_casei,3,10,ucg (ASCII),ucg -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.863978624343872,691, -subtitles_ru_alternate_casei,3,10,ucg (ASCII),ucg -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.862642526626587,691, -subtitles_ru_alternate_casei,3,10,ucg (ASCII),ucg -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.8691396713256836,691, -subtitles_ru_alternate_casei,3,10,ucg (ASCII),ucg -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.871619939804077,691, -subtitles_ru_alternate_casei,3,10,ucg (ASCII),ucg -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.877925395965576,691, -subtitles_ru_alternate_casei,3,10,ucg (ASCII),ucg -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.8617172241210938,691, -subtitles_ru_alternate_casei,3,10,ucg (ASCII),ucg -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.8666179180145264,691, -subtitles_ru_alternate_casei,3,10,ucg (ASCII),ucg -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.866544246673584,691, -subtitles_ru_alternate_casei,3,10,ucg (ASCII),ucg -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.868028163909912,691, -subtitles_ru_alternate_casei,3,10,grep (ASCII),grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.564217805862427,691,LC_ALL=C -subtitles_ru_alternate_casei,3,10,grep (ASCII),grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.56824803352356,691,LC_ALL=C -subtitles_ru_alternate_casei,3,10,grep (ASCII),grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.567821741104126,691,LC_ALL=C -subtitles_ru_alternate_casei,3,10,grep (ASCII),grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.568634986877441,691,LC_ALL=C -subtitles_ru_alternate_casei,3,10,grep (ASCII),grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.564311742782593,691,LC_ALL=C -subtitles_ru_alternate_casei,3,10,grep (ASCII),grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.573625564575195,691,LC_ALL=C -subtitles_ru_alternate_casei,3,10,grep (ASCII),grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.590597152709961,691,LC_ALL=C -subtitles_ru_alternate_casei,3,10,grep (ASCII),grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.56586766242981,691,LC_ALL=C -subtitles_ru_alternate_casei,3,10,grep (ASCII),grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.572263956069946,691,LC_ALL=C -subtitles_ru_alternate_casei,3,10,grep (ASCII),grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.582438707351685,691,LC_ALL=C -subtitles_ru_alternate_casei,3,10,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.836108446121216,735, -subtitles_ru_alternate_casei,3,10,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.830481290817261,735, -subtitles_ru_alternate_casei,3,10,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.837197780609131,735, -subtitles_ru_alternate_casei,3,10,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.831356048583984,735, -subtitles_ru_alternate_casei,3,10,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.829216480255127,735, -subtitles_ru_alternate_casei,3,10,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.835860013961792,735, -subtitles_ru_alternate_casei,3,10,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.8315253257751465,735, -subtitles_ru_alternate_casei,3,10,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.832231044769287,735, -subtitles_ru_alternate_casei,3,10,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.843297004699707,735, -subtitles_ru_alternate_casei,3,10,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.830520153045654,735, -subtitles_ru_alternate_casei,3,10,grep,grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.727419137954712,735,LC_ALL=en_US.UTF-8 -subtitles_ru_alternate_casei,3,10,grep,grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.736006021499634,735,LC_ALL=en_US.UTF-8 -subtitles_ru_alternate_casei,3,10,grep,grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.733150720596313,735,LC_ALL=en_US.UTF-8 -subtitles_ru_alternate_casei,3,10,grep,grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.727008819580078,735,LC_ALL=en_US.UTF-8 -subtitles_ru_alternate_casei,3,10,grep,grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.726323366165161,735,LC_ALL=en_US.UTF-8 -subtitles_ru_alternate_casei,3,10,grep,grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.724290132522583,735,LC_ALL=en_US.UTF-8 -subtitles_ru_alternate_casei,3,10,grep,grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.725264549255371,735,LC_ALL=en_US.UTF-8 -subtitles_ru_alternate_casei,3,10,grep,grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.726403951644897,735,LC_ALL=en_US.UTF-8 -subtitles_ru_alternate_casei,3,10,grep,grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.729755640029907,735,LC_ALL=en_US.UTF-8 -subtitles_ru_alternate_casei,3,10,grep,grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.736154317855835,735,LC_ALL=en_US.UTF-8 -subtitles_ru_literal,3,10,rg,rg Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.3251616954803467,583, -subtitles_ru_literal,3,10,rg,rg Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.3260176181793213,583, -subtitles_ru_literal,3,10,rg,rg Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.325009822845459,583, -subtitles_ru_literal,3,10,rg,rg Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.3253958225250244,583, -subtitles_ru_literal,3,10,rg,rg Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.3255586624145508,583, -subtitles_ru_literal,3,10,rg,rg Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.32509374618530273,583, -subtitles_ru_literal,3,10,rg,rg Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.32692670822143555,583, -subtitles_ru_literal,3,10,rg,rg Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.32549190521240234,583, -subtitles_ru_literal,3,10,rg,rg Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.32480716705322266,583, -subtitles_ru_literal,3,10,rg,rg Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.3243875503540039,583, -subtitles_ru_literal,3,10,rg (no mmap),rg --no-mmap Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.4499814510345459,583, -subtitles_ru_literal,3,10,rg (no mmap),rg --no-mmap Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.45062875747680664,583, -subtitles_ru_literal,3,10,rg (no mmap),rg --no-mmap Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.4532792568206787,583, -subtitles_ru_literal,3,10,rg (no mmap),rg --no-mmap Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.4568295478820801,583, -subtitles_ru_literal,3,10,rg (no mmap),rg --no-mmap Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.45064687728881836,583, -subtitles_ru_literal,3,10,rg (no mmap),rg --no-mmap Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.4510054588317871,583, -subtitles_ru_literal,3,10,rg (no mmap),rg --no-mmap Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.45026254653930664,583, -subtitles_ru_literal,3,10,rg (no mmap),rg --no-mmap Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.4513223171234131,583, -subtitles_ru_literal,3,10,rg (no mmap),rg --no-mmap Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.4508659839630127,583, -subtitles_ru_literal,3,10,rg (no mmap),rg --no-mmap Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.45338964462280273,583, -subtitles_ru_literal,3,10,pt,pt -N Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,12.911964416503906,583, -subtitles_ru_literal,3,10,pt,pt -N Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,12.907763004302979,583, -subtitles_ru_literal,3,10,pt,pt -N Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,12.93012261390686,583, -subtitles_ru_literal,3,10,pt,pt -N Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,12.91182827949524,583, -subtitles_ru_literal,3,10,pt,pt -N Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,12.911576986312866,583, -subtitles_ru_literal,3,10,pt,pt -N Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,12.928250551223755,583, -subtitles_ru_literal,3,10,pt,pt -N Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,12.926709175109863,583, -subtitles_ru_literal,3,10,pt,pt -N Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,12.9106764793396,583, -subtitles_ru_literal,3,10,pt,pt -N Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,12.90697717666626,583, -subtitles_ru_literal,3,10,pt,pt -N Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,12.926398754119873,583, -subtitles_ru_literal,3,10,sift,sift Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,16.41078209877014,583, -subtitles_ru_literal,3,10,sift,sift Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,16.421114921569824,583, -subtitles_ru_literal,3,10,sift,sift Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,16.42653226852417,583, -subtitles_ru_literal,3,10,sift,sift Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,16.411635160446167,583, -subtitles_ru_literal,3,10,sift,sift Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,16.41897940635681,583, -subtitles_ru_literal,3,10,sift,sift Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,16.415560722351074,583, -subtitles_ru_literal,3,10,sift,sift Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,16.41150665283203,583, -subtitles_ru_literal,3,10,sift,sift Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,16.434045553207397,583, -subtitles_ru_literal,3,10,sift,sift Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,16.408607959747314,583, -subtitles_ru_literal,3,10,sift,sift Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,16.418298482894897,583, -subtitles_ru_literal,3,10,grep,grep -a Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7815132141113281,583,LC_ALL=C -subtitles_ru_literal,3,10,grep,grep -a Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7787928581237793,583,LC_ALL=C -subtitles_ru_literal,3,10,grep,grep -a Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7789037227630615,583,LC_ALL=C -subtitles_ru_literal,3,10,grep,grep -a Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7791144847869873,583,LC_ALL=C -subtitles_ru_literal,3,10,grep,grep -a Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7804174423217773,583,LC_ALL=C -subtitles_ru_literal,3,10,grep,grep -a Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7803263664245605,583,LC_ALL=C -subtitles_ru_literal,3,10,grep,grep -a Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.779409646987915,583,LC_ALL=C -subtitles_ru_literal,3,10,grep,grep -a Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7803800106048584,583,LC_ALL=C -subtitles_ru_literal,3,10,grep,grep -a Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7826926708221436,583,LC_ALL=C -subtitles_ru_literal,3,10,grep,grep -a Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7790436744689941,583,LC_ALL=C -subtitles_ru_literal,3,10,rg (lines),rg -n Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.9256212711334229,583, -subtitles_ru_literal,3,10,rg (lines),rg -n Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.9252862930297852,583, -subtitles_ru_literal,3,10,rg (lines),rg -n Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.9253382682800293,583, -subtitles_ru_literal,3,10,rg (lines),rg -n Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.9255073070526123,583, -subtitles_ru_literal,3,10,rg (lines),rg -n Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.925473690032959,583, -subtitles_ru_literal,3,10,rg (lines),rg -n Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.9254281520843506,583, -subtitles_ru_literal,3,10,rg (lines),rg -n Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.9273276329040527,583, -subtitles_ru_literal,3,10,rg (lines),rg -n Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.9264523983001709,583, -subtitles_ru_literal,3,10,rg (lines),rg -n Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.9256389141082764,583, -subtitles_ru_literal,3,10,rg (lines),rg -n Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.9267659187316895,583, -subtitles_ru_literal,3,10,ag (lines),ag -s Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.481263160705566,583, -subtitles_ru_literal,3,10,ag (lines),ag -s Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.478214979171753,583, -subtitles_ru_literal,3,10,ag (lines),ag -s Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.479391813278198,583, -subtitles_ru_literal,3,10,ag (lines),ag -s Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.480245590209961,583, -subtitles_ru_literal,3,10,ag (lines),ag -s Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.479216575622559,583, -subtitles_ru_literal,3,10,ag (lines),ag -s Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.480084419250488,583, -subtitles_ru_literal,3,10,ag (lines),ag -s Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.4808125495910645,583, -subtitles_ru_literal,3,10,ag (lines),ag -s Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.479414224624634,583, -subtitles_ru_literal,3,10,ag (lines),ag -s Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.477892637252808,583, -subtitles_ru_literal,3,10,ag (lines),ag -s Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.488618850708008,583, -subtitles_ru_literal,3,10,ucg (lines),ucg --nosmart-case Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.8875257968902588,583, -subtitles_ru_literal,3,10,ucg (lines),ucg --nosmart-case Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.8994288444519043,583, -subtitles_ru_literal,3,10,ucg (lines),ucg --nosmart-case Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.8891081809997559,583, -subtitles_ru_literal,3,10,ucg (lines),ucg --nosmart-case Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.8927254676818848,583, -subtitles_ru_literal,3,10,ucg (lines),ucg --nosmart-case Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.8885462284088135,583, -subtitles_ru_literal,3,10,ucg (lines),ucg --nosmart-case Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.8860197067260742,583, -subtitles_ru_literal,3,10,ucg (lines),ucg --nosmart-case Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.8897171020507812,583, -subtitles_ru_literal,3,10,ucg (lines),ucg --nosmart-case Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.8881864547729492,583, -subtitles_ru_literal,3,10,ucg (lines),ucg --nosmart-case Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.8842110633850098,583, -subtitles_ru_literal,3,10,ucg (lines),ucg --nosmart-case Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.8878448009490967,583, -subtitles_ru_literal,3,10,pt (lines),pt Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,12.960192918777466,583, -subtitles_ru_literal,3,10,pt (lines),pt Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,12.926759719848633,583, -subtitles_ru_literal,3,10,pt (lines),pt Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,12.929388761520386,583, -subtitles_ru_literal,3,10,pt (lines),pt Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,12.947829723358154,583, -subtitles_ru_literal,3,10,pt (lines),pt Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,12.930480718612671,583, -subtitles_ru_literal,3,10,pt (lines),pt Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,12.931763648986816,583, -subtitles_ru_literal,3,10,pt (lines),pt Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,12.929036140441895,583, -subtitles_ru_literal,3,10,pt (lines),pt Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,12.93698763847351,583, -subtitles_ru_literal,3,10,pt (lines),pt Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,12.929525375366211,583, -subtitles_ru_literal,3,10,pt (lines),pt Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,12.932105541229248,583, -subtitles_ru_literal,3,10,sift (lines),sift -n Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,17.172893047332764,583, -subtitles_ru_literal,3,10,sift (lines),sift -n Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,17.174585819244385,583, -subtitles_ru_literal,3,10,sift (lines),sift -n Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,17.17912483215332,583, -subtitles_ru_literal,3,10,sift (lines),sift -n Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,17.173067092895508,583, -subtitles_ru_literal,3,10,sift (lines),sift -n Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,17.189521074295044,583, -subtitles_ru_literal,3,10,sift (lines),sift -n Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,17.172780513763428,583, -subtitles_ru_literal,3,10,sift (lines),sift -n Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,17.16919755935669,583, -subtitles_ru_literal,3,10,sift (lines),sift -n Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,17.16868829727173,583, -subtitles_ru_literal,3,10,sift (lines),sift -n Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,17.19803738594055,583, -subtitles_ru_literal,3,10,sift (lines),sift -n Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,17.171013832092285,583, -subtitles_ru_literal,3,10,grep (lines),grep -an Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.2980215549468994,583,LC_ALL=C -subtitles_ru_literal,3,10,grep (lines),grep -an Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.2992823123931885,583,LC_ALL=C -subtitles_ru_literal,3,10,grep (lines),grep -an Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.2971000671386719,583,LC_ALL=C -subtitles_ru_literal,3,10,grep (lines),grep -an Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.2973082065582275,583,LC_ALL=C -subtitles_ru_literal,3,10,grep (lines),grep -an Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.2979285717010498,583,LC_ALL=C -subtitles_ru_literal,3,10,grep (lines),grep -an Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.299248218536377,583,LC_ALL=C -subtitles_ru_literal,3,10,grep (lines),grep -an Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.307051658630371,583,LC_ALL=C -subtitles_ru_literal,3,10,grep (lines),grep -an Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.3012950420379639,583,LC_ALL=C -subtitles_ru_literal,3,10,grep (lines),grep -an Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.300577163696289,583,LC_ALL=C -subtitles_ru_literal,3,10,grep (lines),grep -an Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.2991137504577637,583,LC_ALL=C -subtitles_ru_literal_casei,3,10,rg,rg -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.1314334869384766,604, -subtitles_ru_literal_casei,3,10,rg,rg -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.1306557655334473,604, -subtitles_ru_literal_casei,3,10,rg,rg -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.1315603256225586,604, -subtitles_ru_literal_casei,3,10,rg,rg -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.1313893795013428,604, -subtitles_ru_literal_casei,3,10,rg,rg -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.132558822631836,604, -subtitles_ru_literal_casei,3,10,rg,rg -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.1295897960662842,604, -subtitles_ru_literal_casei,3,10,rg,rg -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.131528615951538,604, -subtitles_ru_literal_casei,3,10,rg,rg -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.130932092666626,604, -subtitles_ru_literal_casei,3,10,rg,rg -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.1316814422607422,604, -subtitles_ru_literal_casei,3,10,rg,rg -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.1331970691680908,604, -subtitles_ru_literal_casei,3,10,grep,grep -ai Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.192144632339478,604,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_casei,3,10,grep,grep -ai Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.181128025054932,604,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_casei,3,10,grep,grep -ai Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.183438777923584,604,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_casei,3,10,grep,grep -ai Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.195424556732178,604,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_casei,3,10,grep,grep -ai Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.191128015518188,604,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_casei,3,10,grep,grep -ai Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.181877851486206,604,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_casei,3,10,grep,grep -ai Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.183242797851562,604,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_casei,3,10,grep,grep -ai Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.18350863456726,604,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_casei,3,10,grep,grep -ai Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.18522834777832,604,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_casei,3,10,grep,grep -ai Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,8.195779085159302,604,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_casei,3,10,grep (ASCII),grep -E -ai Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7842297554016113,583,LC_ALL=C -subtitles_ru_literal_casei,3,10,grep (ASCII),grep -E -ai Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7869102954864502,583,LC_ALL=C -subtitles_ru_literal_casei,3,10,grep (ASCII),grep -E -ai Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7825243473052979,583,LC_ALL=C -subtitles_ru_literal_casei,3,10,grep (ASCII),grep -E -ai Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7850461006164551,583,LC_ALL=C -subtitles_ru_literal_casei,3,10,grep (ASCII),grep -E -ai Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7839555740356445,583,LC_ALL=C -subtitles_ru_literal_casei,3,10,grep (ASCII),grep -E -ai Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7831940650939941,583,LC_ALL=C -subtitles_ru_literal_casei,3,10,grep (ASCII),grep -E -ai Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7849681377410889,583,LC_ALL=C -subtitles_ru_literal_casei,3,10,grep (ASCII),grep -E -ai Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7857487201690674,583,LC_ALL=C -subtitles_ru_literal_casei,3,10,grep (ASCII),grep -E -ai Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7865192890167236,583,LC_ALL=C -subtitles_ru_literal_casei,3,10,grep (ASCII),grep -E -ai Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.784534215927124,583,LC_ALL=C -subtitles_ru_literal_casei,3,10,rg (lines),rg -n -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.731257438659668,604, -subtitles_ru_literal_casei,3,10,rg (lines),rg -n -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.730975866317749,604, -subtitles_ru_literal_casei,3,10,rg (lines),rg -n -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.731431007385254,604, -subtitles_ru_literal_casei,3,10,rg (lines),rg -n -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.733675479888916,604, -subtitles_ru_literal_casei,3,10,rg (lines),rg -n -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.7313485145568848,604, -subtitles_ru_literal_casei,3,10,rg (lines),rg -n -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.7320530414581299,604, -subtitles_ru_literal_casei,3,10,rg (lines),rg -n -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.7312524318695068,604, -subtitles_ru_literal_casei,3,10,rg (lines),rg -n -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.7336010932922363,604, -subtitles_ru_literal_casei,3,10,rg (lines),rg -n -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.7369468212127686,604, -subtitles_ru_literal_casei,3,10,rg (lines),rg -n -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.7337863445281982,604, -subtitles_ru_literal_casei,3,10,ag (lines) (ASCII),ag -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7288784980773926,, -subtitles_ru_literal_casei,3,10,ag (lines) (ASCII),ag -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7287564277648926,, -subtitles_ru_literal_casei,3,10,ag (lines) (ASCII),ag -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7289779186248779,, -subtitles_ru_literal_casei,3,10,ag (lines) (ASCII),ag -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7297887802124023,, -subtitles_ru_literal_casei,3,10,ag (lines) (ASCII),ag -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7297365665435791,, -subtitles_ru_literal_casei,3,10,ag (lines) (ASCII),ag -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7302100658416748,, -subtitles_ru_literal_casei,3,10,ag (lines) (ASCII),ag -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7292482852935791,, -subtitles_ru_literal_casei,3,10,ag (lines) (ASCII),ag -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7287256717681885,, -subtitles_ru_literal_casei,3,10,ag (lines) (ASCII),ag -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7282981872558594,, -subtitles_ru_literal_casei,3,10,ag (lines) (ASCII),ag -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7294399738311768,, -subtitles_ru_literal_casei,3,10,ucg (lines) (ASCII),ucg -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.902496337890625,583, -subtitles_ru_literal_casei,3,10,ucg (lines) (ASCII),ucg -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.9001023769378662,583, -subtitles_ru_literal_casei,3,10,ucg (lines) (ASCII),ucg -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.895233392715454,583, -subtitles_ru_literal_casei,3,10,ucg (lines) (ASCII),ucg -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.8891777992248535,583, -subtitles_ru_literal_casei,3,10,ucg (lines) (ASCII),ucg -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.8906826972961426,583, -subtitles_ru_literal_casei,3,10,ucg (lines) (ASCII),ucg -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.9022135734558105,583, -subtitles_ru_literal_casei,3,10,ucg (lines) (ASCII),ucg -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.8985214233398438,583, -subtitles_ru_literal_casei,3,10,ucg (lines) (ASCII),ucg -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.8962385654449463,583, -subtitles_ru_literal_casei,3,10,ucg (lines) (ASCII),ucg -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.8911592960357666,583, -subtitles_ru_literal_casei,3,10,ucg (lines) (ASCII),ucg -i Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.894214153289795,583, -subtitles_ru_literal_word,3,10,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.3251180648803711,, -subtitles_ru_literal_word,3,10,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.3250443935394287,, -subtitles_ru_literal_word,3,10,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.3250398635864258,, -subtitles_ru_literal_word,3,10,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.3258678913116455,, -subtitles_ru_literal_word,3,10,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.3260321617126465,, -subtitles_ru_literal_word,3,10,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.32577013969421387,, -subtitles_ru_literal_word,3,10,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.32557225227355957,, -subtitles_ru_literal_word,3,10,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.32527589797973633,, -subtitles_ru_literal_word,3,10,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.3257458209991455,, -subtitles_ru_literal_word,3,10,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.3253803253173828,, -subtitles_ru_literal_word,3,10,ag (ASCII),ag -sw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7521560192108154,, -subtitles_ru_literal_word,3,10,ag (ASCII),ag -sw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7522988319396973,, -subtitles_ru_literal_word,3,10,ag (ASCII),ag -sw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7518208026885986,, -subtitles_ru_literal_word,3,10,ag (ASCII),ag -sw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7535896301269531,, -subtitles_ru_literal_word,3,10,ag (ASCII),ag -sw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7515583038330078,, -subtitles_ru_literal_word,3,10,ag (ASCII),ag -sw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.75272536277771,, -subtitles_ru_literal_word,3,10,ag (ASCII),ag -sw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7540724277496338,, -subtitles_ru_literal_word,3,10,ag (ASCII),ag -sw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7537317276000977,, -subtitles_ru_literal_word,3,10,ag (ASCII),ag -sw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7529683113098145,, -subtitles_ru_literal_word,3,10,ag (ASCII),ag -sw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.7519652843475342,, -subtitles_ru_literal_word,3,10,ucg (ASCII),ucg --nosmart-case Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.895404577255249,583, -subtitles_ru_literal_word,3,10,ucg (ASCII),ucg --nosmart-case Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.8901162147521973,583, -subtitles_ru_literal_word,3,10,ucg (ASCII),ucg --nosmart-case Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.8873977661132812,583, -subtitles_ru_literal_word,3,10,ucg (ASCII),ucg --nosmart-case Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.885707139968872,583, -subtitles_ru_literal_word,3,10,ucg (ASCII),ucg --nosmart-case Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.8928821086883545,583, -subtitles_ru_literal_word,3,10,ucg (ASCII),ucg --nosmart-case Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.8904106616973877,583, -subtitles_ru_literal_word,3,10,ucg (ASCII),ucg --nosmart-case Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.8904242515563965,583, -subtitles_ru_literal_word,3,10,ucg (ASCII),ucg --nosmart-case Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.890967845916748,583, -subtitles_ru_literal_word,3,10,ucg (ASCII),ucg --nosmart-case Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.8881947994232178,583, -subtitles_ru_literal_word,3,10,ucg (ASCII),ucg --nosmart-case Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.900097131729126,583, -subtitles_ru_literal_word,3,10,grep (ASCII),grep -anw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.301781415939331,583,LC_ALL=C -subtitles_ru_literal_word,3,10,grep (ASCII),grep -anw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.3029043674468994,583,LC_ALL=C -subtitles_ru_literal_word,3,10,grep (ASCII),grep -anw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.302168369293213,583,LC_ALL=C -subtitles_ru_literal_word,3,10,grep (ASCII),grep -anw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.3010151386260986,583,LC_ALL=C -subtitles_ru_literal_word,3,10,grep (ASCII),grep -anw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.3041775226593018,583,LC_ALL=C -subtitles_ru_literal_word,3,10,grep (ASCII),grep -anw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.3008759021759033,583,LC_ALL=C -subtitles_ru_literal_word,3,10,grep (ASCII),grep -anw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.3115224838256836,583,LC_ALL=C -subtitles_ru_literal_word,3,10,grep (ASCII),grep -anw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.3092575073242188,583,LC_ALL=C -subtitles_ru_literal_word,3,10,grep (ASCII),grep -anw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.3020920753479004,583,LC_ALL=C -subtitles_ru_literal_word,3,10,grep (ASCII),grep -anw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.299107313156128,583,LC_ALL=C -subtitles_ru_literal_word,3,10,rg,rg -nw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.9281308650970459,579, -subtitles_ru_literal_word,3,10,rg,rg -nw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.9305391311645508,579, -subtitles_ru_literal_word,3,10,rg,rg -nw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.928086519241333,579, -subtitles_ru_literal_word,3,10,rg,rg -nw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.9288325309753418,579, -subtitles_ru_literal_word,3,10,rg,rg -nw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.9280257225036621,579, -subtitles_ru_literal_word,3,10,rg,rg -nw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.9294643402099609,579, -subtitles_ru_literal_word,3,10,rg,rg -nw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.9276673793792725,579, -subtitles_ru_literal_word,3,10,rg,rg -nw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.9298434257507324,579, -subtitles_ru_literal_word,3,10,rg,rg -nw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.9300410747528076,579, -subtitles_ru_literal_word,3,10,rg,rg -nw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.928978443145752,579, -subtitles_ru_literal_word,3,10,grep,grep -anw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.3036572933197021,579,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_word,3,10,grep,grep -anw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.301509141921997,579,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_word,3,10,grep,grep -anw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.301844596862793,579,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_word,3,10,grep,grep -anw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.300811767578125,579,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_word,3,10,grep,grep -anw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.3004207611083984,579,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_word,3,10,grep,grep -anw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.3020946979522705,579,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_word,3,10,grep,grep -anw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.3045520782470703,579,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_word,3,10,grep,grep -anw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.3078258037567139,579,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_word,3,10,grep,grep -anw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.3057043552398682,579,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_word,3,10,grep,grep -anw Шерлок Холмс /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.3066091537475586,579,LC_ALL=en_US.UTF-8 -subtitles_ru_no_literal,3,10,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.906493186950684,41, -subtitles_ru_no_literal,3,10,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.905959129333496,41, -subtitles_ru_no_literal,3,10,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.9105610847473145,41, -subtitles_ru_no_literal,3,10,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.905940532684326,41, -subtitles_ru_no_literal,3,10,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.903593063354492,41, -subtitles_ru_no_literal,3,10,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.902836561203003,41, -subtitles_ru_no_literal,3,10,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.903217792510986,41, -subtitles_ru_no_literal,3,10,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.903507709503174,41, -subtitles_ru_no_literal,3,10,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.905400037765503,41, -subtitles_ru_no_literal,3,10,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,4.898482322692871,41, -subtitles_ru_no_literal,3,10,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,3.972111940383911,, -subtitles_ru_no_literal,3,10,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,3.970813512802124,, -subtitles_ru_no_literal,3,10,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,3.976404905319214,, -subtitles_ru_no_literal,3,10,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,3.9732987880706787,, -subtitles_ru_no_literal,3,10,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,3.972306966781616,, -subtitles_ru_no_literal,3,10,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,3.97151255607605,, -subtitles_ru_no_literal,3,10,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,3.9718263149261475,, -subtitles_ru_no_literal,3,10,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,3.973245859146118,, -subtitles_ru_no_literal,3,10,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,3.9723284244537354,, -subtitles_ru_no_literal,3,10,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,3.9733688831329346,, -subtitles_ru_no_literal,3,10,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.3929569721221924,, -subtitles_ru_no_literal,3,10,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.392943859100342,, -subtitles_ru_no_literal,3,10,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.392956256866455,, -subtitles_ru_no_literal,3,10,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.4027605056762695,, -subtitles_ru_no_literal,3,10,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.3976504802703857,, -subtitles_ru_no_literal,3,10,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.399548053741455,, -subtitles_ru_no_literal,3,10,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.39271879196167,, -subtitles_ru_no_literal,3,10,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.3926007747650146,, -subtitles_ru_no_literal,3,10,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.3937296867370605,, -subtitles_ru_no_literal,3,10,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.3968875408172607,, -subtitles_ru_no_literal,3,10,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,3.012164831161499,, -subtitles_ru_no_literal,3,10,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,3.016608953475952,, -subtitles_ru_no_literal,3,10,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,3.0102171897888184,, -subtitles_ru_no_literal,3,10,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,3.000244379043579,, -subtitles_ru_no_literal,3,10,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,3.0036542415618896,, -subtitles_ru_no_literal,3,10,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,3.002727508544922,, -subtitles_ru_no_literal,3,10,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,3.000943660736084,, -subtitles_ru_no_literal,3,10,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,3.0042483806610107,, -subtitles_ru_no_literal,3,10,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,3.0024917125701904,, -subtitles_ru_no_literal,3,10,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,3.007298707962036,, -subtitles_ru_no_literal,3,10,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.488464593887329,,LC_ALL=C -subtitles_ru_no_literal,3,10,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.4832253456115723,,LC_ALL=C -subtitles_ru_no_literal,3,10,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.4868624210357666,,LC_ALL=C -subtitles_ru_no_literal,3,10,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.482663631439209,,LC_ALL=C -subtitles_ru_no_literal,3,10,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.4814178943634033,,LC_ALL=C -subtitles_ru_no_literal,3,10,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.4921915531158447,,LC_ALL=C -subtitles_ru_no_literal,3,10,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.477674722671509,,LC_ALL=C -subtitles_ru_no_literal,3,10,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.4839584827423096,,LC_ALL=C -subtitles_ru_no_literal,3,10,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.4775733947753906,,LC_ALL=C -subtitles_ru_no_literal,3,10,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.4787662029266357,,LC_ALL=C -subtitles_ru_surrounding_words,3,10,rg,rg -n \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.9554853439331055,278, -subtitles_ru_surrounding_words,3,10,rg,rg -n \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.9573261737823486,278, -subtitles_ru_surrounding_words,3,10,rg,rg -n \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.9586184024810791,278, -subtitles_ru_surrounding_words,3,10,rg,rg -n \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.9581241607666016,278, -subtitles_ru_surrounding_words,3,10,rg,rg -n \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.9575743675231934,278, -subtitles_ru_surrounding_words,3,10,rg,rg -n \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.9565131664276123,278, -subtitles_ru_surrounding_words,3,10,rg,rg -n \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.957273006439209,278, -subtitles_ru_surrounding_words,3,10,rg,rg -n \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.9568536281585693,278, -subtitles_ru_surrounding_words,3,10,rg,rg -n \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.9590330123901367,278, -subtitles_ru_surrounding_words,3,10,rg,rg -n \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,0.956944465637207,278, -subtitles_ru_surrounding_words,3,10,grep,grep -E -an \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.6629645824432373,278,LC_ALL=en_US.UTF-8 -subtitles_ru_surrounding_words,3,10,grep,grep -E -an \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.6628422737121582,278,LC_ALL=en_US.UTF-8 -subtitles_ru_surrounding_words,3,10,grep,grep -E -an \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.6596570014953613,278,LC_ALL=en_US.UTF-8 -subtitles_ru_surrounding_words,3,10,grep,grep -E -an \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.6606900691986084,278,LC_ALL=en_US.UTF-8 -subtitles_ru_surrounding_words,3,10,grep,grep -E -an \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.6575767993927002,278,LC_ALL=en_US.UTF-8 -subtitles_ru_surrounding_words,3,10,grep,grep -E -an \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.6601543426513672,278,LC_ALL=en_US.UTF-8 -subtitles_ru_surrounding_words,3,10,grep,grep -E -an \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.6579883098602295,278,LC_ALL=en_US.UTF-8 -subtitles_ru_surrounding_words,3,10,grep,grep -E -an \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.6584765911102295,278,LC_ALL=en_US.UTF-8 -subtitles_ru_surrounding_words,3,10,grep,grep -E -an \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.6587963104248047,278,LC_ALL=en_US.UTF-8 -subtitles_ru_surrounding_words,3,10,grep,grep -E -an \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.6574666500091553,278,LC_ALL=en_US.UTF-8 -subtitles_ru_surrounding_words,3,10,ag (ASCII),ag -s \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.410092353820801,, -subtitles_ru_surrounding_words,3,10,ag (ASCII),ag -s \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.4107093811035156,, -subtitles_ru_surrounding_words,3,10,ag (ASCII),ag -s \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.4124505519866943,, -subtitles_ru_surrounding_words,3,10,ag (ASCII),ag -s \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.41247820854187,, -subtitles_ru_surrounding_words,3,10,ag (ASCII),ag -s \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.4112393856048584,, -subtitles_ru_surrounding_words,3,10,ag (ASCII),ag -s \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.4098284244537354,, -subtitles_ru_surrounding_words,3,10,ag (ASCII),ag -s \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.4091367721557617,, -subtitles_ru_surrounding_words,3,10,ag (ASCII),ag -s \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.4103705883026123,, -subtitles_ru_surrounding_words,3,10,ag (ASCII),ag -s \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.409790515899658,, -subtitles_ru_surrounding_words,3,10,ag (ASCII),ag -s \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.4096734523773193,, -subtitles_ru_surrounding_words,3,10,ucg (ASCII),ucg --nosmart-case \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.9796345233917236,, -subtitles_ru_surrounding_words,3,10,ucg (ASCII),ucg --nosmart-case \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.9837162494659424,, -subtitles_ru_surrounding_words,3,10,ucg (ASCII),ucg --nosmart-case \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.9813201427459717,, -subtitles_ru_surrounding_words,3,10,ucg (ASCII),ucg --nosmart-case \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.979423999786377,, -subtitles_ru_surrounding_words,3,10,ucg (ASCII),ucg --nosmart-case \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.976318120956421,, -subtitles_ru_surrounding_words,3,10,ucg (ASCII),ucg --nosmart-case \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.9775450229644775,, -subtitles_ru_surrounding_words,3,10,ucg (ASCII),ucg --nosmart-case \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.976980447769165,, -subtitles_ru_surrounding_words,3,10,ucg (ASCII),ucg --nosmart-case \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.979104518890381,, -subtitles_ru_surrounding_words,3,10,ucg (ASCII),ucg --nosmart-case \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.980332612991333,, -subtitles_ru_surrounding_words,3,10,ucg (ASCII),ucg --nosmart-case \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,2.9827349185943604,, -subtitles_ru_surrounding_words,3,10,grep (ASCII),grep -E -an \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.60090970993042,,LC_ALL=C -subtitles_ru_surrounding_words,3,10,grep (ASCII),grep -E -an \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.5965259075164795,,LC_ALL=C -subtitles_ru_surrounding_words,3,10,grep (ASCII),grep -E -an \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.5928871631622314,,LC_ALL=C -subtitles_ru_surrounding_words,3,10,grep (ASCII),grep -E -an \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.5957767963409424,,LC_ALL=C -subtitles_ru_surrounding_words,3,10,grep (ASCII),grep -E -an \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.5944275856018066,,LC_ALL=C -subtitles_ru_surrounding_words,3,10,grep (ASCII),grep -E -an \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.6034324169158936,,LC_ALL=C -subtitles_ru_surrounding_words,3,10,grep (ASCII),grep -E -an \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.5949978828430176,,LC_ALL=C -subtitles_ru_surrounding_words,3,10,grep (ASCII),grep -E -an \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.5950729846954346,,LC_ALL=C -subtitles_ru_surrounding_words,3,10,grep (ASCII),grep -E -an \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.593465805053711,,LC_ALL=C -subtitles_ru_surrounding_words,3,10,grep (ASCII),grep -E -an \w+\s+Холмс\s+\w+ /mnt/bench/subtitles/OpenSubtitles2016.raw.ru,1.5951871871948242,,LC_ALL=C diff --git a/benchsuite/runs/2016-09-20-ubuntu1604-ec2/summary b/benchsuite/runs/2016-09-20-ubuntu1604-ec2/summary deleted file mode 100644 index 867974e..0000000 --- a/benchsuite/runs/2016-09-20-ubuntu1604-ec2/summary +++ /dev/null @@ -1,235 +0,0 @@ -linux_alternates (pattern: ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT) -------------------------------------------------------------------------- -rg (ignore) 0.351 +/- 0.074 (lines: 68) -ag (ignore) 1.747 +/- 0.005 (lines: 68) -git grep (ignore) 0.501 +/- 0.003 (lines: 68) -rg (whitelist)* 0.216 +/- 0.031 (lines: 68) -ucg (whitelist) 0.214 +/- 0.008 (lines: 68)* - -linux_alternates_casei (pattern: ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT) -------------------------------------------------------------------------------- -rg (ignore) 0.391 +/- 0.078 (lines: 160) -ag (ignore) 1.968 +/- 0.009 (lines: 160) -git grep (ignore) 2.018 +/- 0.006 (lines: 160) -rg (whitelist)* 0.222 +/- 0.001 (lines: 160)* -ucg (whitelist) 0.522 +/- 0.002 (lines: 160) - -linux_literal (pattern: PM_RESUME) ----------------------------------- -rg (ignore) 0.334 +/- 0.053 (lines: 16) -rg (ignore) (mmap) 1.611 +/- 0.009 (lines: 16) -ag (ignore) (mmap) 1.588 +/- 0.011 (lines: 16) -pt (ignore) 0.456 +/- 0.025 (lines: 16) -sift (ignore) 0.630 +/- 0.004 (lines: 16) -git grep (ignore) 0.345 +/- 0.007 (lines: 16) -rg (whitelist)* 0.228 +/- 0.042 (lines: 16) -ucg (whitelist) 0.218 +/- 0.007 (lines: 16)* - -linux_literal_casei (pattern: PM_RESUME) ----------------------------------------- -rg (ignore) 0.345 +/- 0.073 (lines: 370) -rg (ignore) (mmap) 1.612 +/- 0.011 (lines: 370) -ag (ignore) (mmap) 1.609 +/- 0.015 (lines: 370) -pt (ignore) 17.204 +/- 0.126 (lines: 370) -sift (ignore) 0.805 +/- 0.005 (lines: 370) -git grep (ignore) 0.343 +/- 0.007 (lines: 370) -rg (whitelist)* 0.222 +/- 0.021 (lines: 370) -ucg (whitelist) 0.217 +/- 0.006 (lines: 370)* - -linux_literal_default (pattern: PM_RESUME) ------------------------------------------- -rg 0.349 +/- 0.104 (lines: 16) -ag 1.589 +/- 0.009 (lines: 16) -ucg* 0.218 +/- 0.007 (lines: 16)* -pt 0.462 +/- 0.012 (lines: 16) -sift 0.352 +/- 0.018 (lines: 16) -git grep 0.342 +/- 0.005 (lines: 16) - -linux_no_literal (pattern: \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}) ------------------------------------------------------------------ -rg (ignore) 0.577 +/- 0.003 (lines: 490) -rg (ignore) (ASCII) 0.416 +/- 0.025 (lines: 490) -ag (ignore) (ASCII) 2.339 +/- 0.010 (lines: 766) -pt (ignore) (ASCII) 22.066 +/- 0.057 (lines: 490) -sift (ignore) (ASCII) 25.563 +/- 0.108 (lines: 490) -git grep (ignore) 26.382 +/- 0.044 (lines: 490) -git grep (ignore) (ASCII) 4.153 +/- 0.010 (lines: 490) -rg (whitelist) 0.503 +/- 0.011 (lines: 419) -rg (whitelist) (ASCII)* 0.343 +/- 0.038 (lines: 419)* -ucg (whitelist) (ASCII) 1.130 +/- 0.003 (lines: 416) - -linux_re_literal_suffix (pattern: [A-Z]+_RESUME) ------------------------------------------------- -rg (ignore) 0.318 +/- 0.034 (lines: 1652) -ag (ignore) 1.899 +/- 0.008 (lines: 1652) -pt (ignore) 13.713 +/- 0.241 (lines: 1652) -sift (ignore) 10.172 +/- 0.186 (lines: 1652) -git grep (ignore) 1.108 +/- 0.004 (lines: 1652) -rg (whitelist)* 0.221 +/- 0.022 (lines: 1630)* -ucg (whitelist) 0.301 +/- 0.001 (lines: 1630) - -linux_unicode_greek (pattern: \p{Greek}) ----------------------------------------- -rg* 0.414 +/- 0.021 (lines: 23)* -pt 12.745 +/- 0.166 (lines: 23) -sift 7.767 +/- 0.264 (lines: 23) - -linux_unicode_greek_casei (pattern: \p{Greek}) ----------------------------------------------- -rg 0.425 +/- 0.027 (lines: 103) -pt 12.612 +/- 0.217 (lines: 23) -sift* 0.002 +/- 0.000 (lines: 0)* - -linux_unicode_word (pattern: \wAh) ----------------------------------- -rg (ignore) 0.355 +/- 0.073 (lines: 186) -rg (ignore) (ASCII) 0.329 +/- 0.060 (lines: 174) -ag (ignore) (ASCII) 1.774 +/- 0.011 (lines: 174) -pt (ignore) (ASCII) 14.180 +/- 0.180 (lines: 174) -sift (ignore) (ASCII) 11.087 +/- 0.108 (lines: 174) -git grep (ignore) 13.045 +/- 0.008 (lines: 186) -git grep (ignore) (ASCII) 2.991 +/- 0.004 (lines: 174) -rg (whitelist) 0.235 +/- 0.031 (lines: 180) -rg (whitelist) (ASCII)* 0.225 +/- 0.023 (lines: 168)* -ucg (ASCII) 0.229 +/- 0.007 (lines: 168) - -linux_word (pattern: PM_RESUME) -------------------------------- -rg (ignore) 0.362 +/- 0.080 (lines: 6) -ag (ignore) 1.603 +/- 0.009 (lines: 6) -pt (ignore) 14.417 +/- 0.144 (lines: 6) -sift (ignore) 7.840 +/- 0.123 (lines: 6) -git grep (ignore) 0.341 +/- 0.005 (lines: 6) -rg (whitelist)* 0.220 +/- 0.026 (lines: 6)* -ucg (whitelist) 0.221 +/- 0.007 (lines: 6) - -subtitles_en_alternate (pattern: Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty) ---------------------------------------------------------------------------------------------------------------- -rg (lines) 0.619 +/- 0.001 (lines: 848) -ag (lines) 3.757 +/- 0.001 (lines: 848) -ucg (lines) 1.479 +/- 0.002 (lines: 848) -grep (lines) 3.412 +/- 0.004 (lines: 848) -rg* 0.294 +/- 0.001 (lines: 848)* -grep 2.955 +/- 0.003 (lines: 848) - -subtitles_en_alternate_casei (pattern: Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty) ---------------------------------------------------------------------------------------------------------------------- -ag (ASCII) 5.170 +/- 0.004 (lines: 862) -ucg (ASCII) 3.453 +/- 0.005 (lines: 862) -grep (ASCII) 4.537 +/- 0.025 (lines: 862) -rg* 2.724 +/- 0.002 (lines: 862)* -grep 5.125 +/- 0.006 (lines: 862) - -subtitles_en_literal (pattern: Sherlock Holmes) ------------------------------------------------ -rg* 0.268 +/- 0.000 (lines: 629)* -rg (no mmap) 0.336 +/- 0.001 (lines: 629) -pt 3.433 +/- 0.002 (lines: 629) -sift 0.326 +/- 0.002 (lines: 629) -grep 0.516 +/- 0.001 (lines: 629) -rg (lines) 0.595 +/- 0.001 (lines: 629) -ag (lines) 2.730 +/- 0.003 (lines: 629) -ucg (lines) 0.745 +/- 0.001 (lines: 629) -pt (lines) 3.434 +/- 0.005 (lines: 629) -sift (lines) 0.756 +/- 0.002 (lines: 629) -grep (lines) 0.969 +/- 0.001 (lines: 629) - -subtitles_en_literal_casei (pattern: Sherlock Holmes) ------------------------------------------------------ -rg* 0.366 +/- 0.001 (lines: 642)* -grep 4.084 +/- 0.005 (lines: 642) -grep (ASCII) 0.614 +/- 0.001 (lines: 642) -rg (lines) 0.696 +/- 0.002 (lines: 642) -ag (lines) (ASCII) 2.775 +/- 0.004 (lines: 642) -ucg (lines) (ASCII) 0.841 +/- 0.002 (lines: 642) - -subtitles_en_literal_word (pattern: Sherlock Holmes) ----------------------------------------------------- -rg (ASCII) 0.596 +/- 0.001 (lines: 629) -ag (ASCII) 2.729 +/- 0.001 (lines: 629) -ucg (ASCII) 0.810 +/- 0.002 (lines: 629) -grep (ASCII) 0.970 +/- 0.000 (lines: 629) -rg* 0.596 +/- 0.001 (lines: 629)* -grep 0.972 +/- 0.003 (lines: 629) - -subtitles_en_no_literal (pattern: \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}) ----------------------------------------------------------------------------------------- -rg 2.777 +/- 0.003 (lines: 13) -rg (ASCII)* 2.541 +/- 0.005 (lines: 13)* -ag (ASCII) 10.076 +/- 0.005 (lines: 48) -ucg (ASCII) 7.771 +/- 0.004 (lines: 13) -grep (ASCII) 4.411 +/- 0.004 (lines: 13) - -subtitles_en_surrounding_words (pattern: \w+\s+Holmes\s+\w+) ------------------------------------------------------------- -rg 0.605 +/- 0.000 (lines: 317) -grep 1.286 +/- 0.002 (lines: 317) -rg (ASCII)* 0.602 +/- 0.000 (lines: 317)* -ag (ASCII) 11.663 +/- 0.008 (lines: 323) -ucg (ASCII) 4.690 +/- 0.002 (lines: 317) -grep (ASCII) 1.276 +/- 0.002 (lines: 317) - -subtitles_ru_alternate (pattern: Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти) ------------------------------------------------------------------------------------------------------------ -rg (lines) 1.902 +/- 0.002 (lines: 691) -ag (lines) 5.892 +/- 0.003 (lines: 691) -ucg (lines) 2.864 +/- 0.006 (lines: 691) -grep (lines) 8.511 +/- 0.005 (lines: 691) -rg* 1.300 +/- 0.002 (lines: 691)* -grep 7.994 +/- 0.017 (lines: 691) - -subtitles_ru_alternate_casei (pattern: Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти) ------------------------------------------------------------------------------------------------------------------ -ag (ASCII) 5.891 +/- 0.001 (lines: 691) -ucg (ASCII)* 2.868 +/- 0.005 (lines: 691)* -grep (ASCII) 8.572 +/- 0.009 (lines: 691) -rg 4.834 +/- 0.004 (lines: 735) -grep 8.729 +/- 0.004 (lines: 735) - -subtitles_ru_literal (pattern: Шерлок Холмс) --------------------------------------------- -rg* 0.325 +/- 0.001 (lines: 583)* -rg (no mmap) 0.452 +/- 0.002 (lines: 583) -pt 12.917 +/- 0.009 (lines: 583) -sift 16.418 +/- 0.008 (lines: 583) -grep 0.780 +/- 0.001 (lines: 583) -rg (lines) 0.926 +/- 0.001 (lines: 583) -ag (lines) 4.481 +/- 0.003 (lines: 583) -ucg (lines) 1.889 +/- 0.004 (lines: 583) -pt (lines) 12.935 +/- 0.011 (lines: 583) -sift (lines) 17.177 +/- 0.010 (lines: 583) -grep (lines) 1.300 +/- 0.003 (lines: 583) - -subtitles_ru_literal_casei (pattern: Шерлок Холмс) --------------------------------------------------- -rg 1.131 +/- 0.001 (lines: 604) -grep 8.187 +/- 0.006 (lines: 604) -grep (ASCII) 0.785 +/- 0.001 (lines: 583) -rg (lines) 1.733 +/- 0.002 (lines: 604) -ag (lines) (ASCII)* 0.729 +/- 0.001 (lines: 0)* -ucg (lines) (ASCII) 1.896 +/- 0.005 (lines: 583) - -subtitles_ru_literal_word (pattern: Шерлок Холмс) -------------------------------------------------- -rg (ASCII)* 0.325 +/- 0.000 (lines: 0)* -ag (ASCII) 0.753 +/- 0.001 (lines: 0) -ucg (ASCII) 1.891 +/- 0.004 (lines: 583) -grep (ASCII) 1.303 +/- 0.004 (lines: 583) -rg 0.929 +/- 0.001 (lines: 579) -grep 1.304 +/- 0.003 (lines: 579) - -subtitles_ru_no_literal (pattern: \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}) ----------------------------------------------------------------------------------------- -rg 4.905 +/- 0.003 (lines: 41) -rg (ASCII) 3.973 +/- 0.002 (lines: 0) -ag (ASCII)* 2.395 +/- 0.004 (lines: 0)* -ucg (ASCII) 3.006 +/- 0.005 (lines: 0) -grep (ASCII) 2.483 +/- 0.005 (lines: 0) - -subtitles_ru_surrounding_words (pattern: \w+\s+Холмс\s+\w+) ------------------------------------------------------------ -rg* 0.957 +/- 0.001 (lines: 278)* -grep 1.660 +/- 0.002 (lines: 278) -ag (ASCII) 2.411 +/- 0.001 (lines: 0) -ucg (ASCII) 2.980 +/- 0.002 (lines: 0) -grep (ASCII) 1.596 +/- 0.003 (lines: 0) diff --git a/benchsuite/runs/2016-09-22-archlinux-cheetah/raw.csv b/benchsuite/runs/2016-09-22-archlinux-cheetah/raw.csv deleted file mode 100644 index 10d826b..0000000 --- a/benchsuite/runs/2016-09-22-archlinux-cheetah/raw.csv +++ /dev/null @@ -1,484 +0,0 @@ -benchmark,warmup_iter,iter,name,command,duration,lines,env -linux_alternates,1,3,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.16187143325805664,68, -linux_alternates,1,3,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.15862464904785156,68, -linux_alternates,1,3,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.15711188316345215,68, -linux_alternates,1,3,ag (ignore),ag -s ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.5682125091552734,68, -linux_alternates,1,3,ag (ignore),ag -s ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.551994800567627,68, -linux_alternates,1,3,ag (ignore),ag -s ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.5516140460968018,68, -linux_alternates,1,3,git grep (ignore),git grep -E -I -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.24930572509765625,68,LC_ALL=C -linux_alternates,1,3,git grep (ignore),git grep -E -I -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.25743985176086426,68,LC_ALL=C -linux_alternates,1,3,git grep (ignore),git grep -E -I -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.24960589408874512,68,LC_ALL=C -linux_alternates,1,3,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.1039431095123291,68, -linux_alternates,1,3,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.10251975059509277,68, -linux_alternates,1,3,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.10156440734863281,68, -linux_alternates,1,3,ucg (whitelist),ucg --nosmart-case ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.15678954124450684,68, -linux_alternates,1,3,ucg (whitelist),ucg --nosmart-case ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.15236687660217285,68, -linux_alternates,1,3,ucg (whitelist),ucg --nosmart-case ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.1554563045501709,68, -linux_alternates_casei,1,3,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.16192197799682617,160, -linux_alternates_casei,1,3,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.15988397598266602,160, -linux_alternates_casei,1,3,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.1610555648803711,160, -linux_alternates_casei,1,3,ag (ignore),ag -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.6026794910430908,160, -linux_alternates_casei,1,3,ag (ignore),ag -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.6083211898803711,160, -linux_alternates_casei,1,3,ag (ignore),ag -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.674222469329834,160, -linux_alternates_casei,1,3,git grep (ignore),git grep -E -I -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,1.0635485649108887,160,LC_ALL=C -linux_alternates_casei,1,3,git grep (ignore),git grep -E -I -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.8944556713104248,160,LC_ALL=C -linux_alternates_casei,1,3,git grep (ignore),git grep -E -I -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.860692024230957,160,LC_ALL=C -linux_alternates_casei,1,3,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.11778616905212402,160, -linux_alternates_casei,1,3,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.11570453643798828,160, -linux_alternates_casei,1,3,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.13424015045166016,160, -linux_alternates_casei,1,3,ucg (whitelist),ucg -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.2392585277557373,160, -linux_alternates_casei,1,3,ucg (whitelist),ucg -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.2421557903289795,160, -linux_alternates_casei,1,3,ucg (whitelist),ucg -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.2390902042388916,160, -linux_literal,1,3,rg (ignore),rg -n PM_RESUME,0.14362168312072754,16, -linux_literal,1,3,rg (ignore),rg -n PM_RESUME,0.16165685653686523,16, -linux_literal,1,3,rg (ignore),rg -n PM_RESUME,0.1725757122039795,16, -linux_literal,1,3,rg (ignore) (mmap),rg -n --mmap PM_RESUME,0.3785591125488281,16, -linux_literal,1,3,rg (ignore) (mmap),rg -n --mmap PM_RESUME,0.3961794376373291,16, -linux_literal,1,3,rg (ignore) (mmap),rg -n --mmap PM_RESUME,0.3924229145050049,16, -linux_literal,1,3,ag (ignore) (mmap),ag -s PM_RESUME,0.5462315082550049,16, -linux_literal,1,3,ag (ignore) (mmap),ag -s PM_RESUME,0.7240490913391113,16, -linux_literal,1,3,ag (ignore) (mmap),ag -s PM_RESUME,0.4528837203979492,16, -linux_literal,1,3,pt (ignore),pt PM_RESUME,0.16354584693908691,16, -linux_literal,1,3,pt (ignore),pt PM_RESUME,0.15301966667175293,16, -linux_literal,1,3,pt (ignore),pt PM_RESUME,0.15467524528503418,16, -linux_literal,1,3,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git PM_RESUME,0.33901119232177734,16, -linux_literal,1,3,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git PM_RESUME,0.34641242027282715,16, -linux_literal,1,3,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git PM_RESUME,0.3532230854034424,16, -linux_literal,1,3,git grep (ignore),git grep -I -n PM_RESUME,0.1970062255859375,16,LC_ALL=C -linux_literal,1,3,git grep (ignore),git grep -I -n PM_RESUME,0.21334624290466309,16,LC_ALL=C -linux_literal,1,3,git grep (ignore),git grep -I -n PM_RESUME,0.19323515892028809,16,LC_ALL=C -linux_literal,1,3,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.10708379745483398,16, -linux_literal,1,3,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.10089921951293945,16, -linux_literal,1,3,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.10404157638549805,16, -linux_literal,1,3,ucg (whitelist),ucg --nosmart-case PM_RESUME,0.17191362380981445,16, -linux_literal,1,3,ucg (whitelist),ucg --nosmart-case PM_RESUME,0.1670548915863037,16, -linux_literal,1,3,ucg (whitelist),ucg --nosmart-case PM_RESUME,0.16875147819519043,16, -linux_literal_casei,1,3,rg (ignore),rg -n -i PM_RESUME,0.16549420356750488,370, -linux_literal_casei,1,3,rg (ignore),rg -n -i PM_RESUME,0.14867877960205078,370, -linux_literal_casei,1,3,rg (ignore),rg -n -i PM_RESUME,0.1509239673614502,370, -linux_literal_casei,1,3,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,0.38896727561950684,370, -linux_literal_casei,1,3,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,0.39926719665527344,370, -linux_literal_casei,1,3,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,0.3912012577056885,370, -linux_literal_casei,1,3,ag (ignore) (mmap),ag -i PM_RESUME,0.48294734954833984,370, -linux_literal_casei,1,3,ag (ignore) (mmap),ag -i PM_RESUME,0.4827127456665039,370, -linux_literal_casei,1,3,ag (ignore) (mmap),ag -i PM_RESUME,0.4216601848602295,370, -linux_literal_casei,1,3,pt (ignore),pt -i PM_RESUME,11.884198665618896,370, -linux_literal_casei,1,3,pt (ignore),pt -i PM_RESUME,12.05774974822998,370, -linux_literal_casei,1,3,pt (ignore),pt -i PM_RESUME,11.864668130874634,370, -linux_literal_casei,1,3,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git PM_RESUME,0.3698842525482178,370, -linux_literal_casei,1,3,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git PM_RESUME,0.3745250701904297,370, -linux_literal_casei,1,3,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git PM_RESUME,0.3670051097869873,370, -linux_literal_casei,1,3,git grep (ignore),git grep -I -n -i PM_RESUME,0.18896126747131348,370,LC_ALL=C -linux_literal_casei,1,3,git grep (ignore),git grep -I -n -i PM_RESUME,0.19655537605285645,370,LC_ALL=C -linux_literal_casei,1,3,git grep (ignore),git grep -I -n -i PM_RESUME,0.183945894241333,370,LC_ALL=C -linux_literal_casei,1,3,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.11336517333984375,370, -linux_literal_casei,1,3,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.10497522354125977,370, -linux_literal_casei,1,3,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.10771870613098145,370, -linux_literal_casei,1,3,ucg (whitelist),ucg -i PM_RESUME,0.1626441478729248,370, -linux_literal_casei,1,3,ucg (whitelist),ucg -i PM_RESUME,0.16270971298217773,370, -linux_literal_casei,1,3,ucg (whitelist),ucg -i PM_RESUME,0.1596980094909668,370, -linux_literal_default,1,3,rg,rg PM_RESUME,0.14002084732055664,16, -linux_literal_default,1,3,rg,rg PM_RESUME,0.13782882690429688,16, -linux_literal_default,1,3,rg,rg PM_RESUME,0.13794231414794922,16, -linux_literal_default,1,3,ag,ag PM_RESUME,0.4623262882232666,16, -linux_literal_default,1,3,ag,ag PM_RESUME,0.419907808303833,16, -linux_literal_default,1,3,ag,ag PM_RESUME,0.44193005561828613,16, -linux_literal_default,1,3,ucg,ucg PM_RESUME,0.1634502410888672,16, -linux_literal_default,1,3,ucg,ucg PM_RESUME,0.17029428482055664,16, -linux_literal_default,1,3,ucg,ucg PM_RESUME,0.16076922416687012,16, -linux_literal_default,1,3,pt,pt PM_RESUME,0.15809178352355957,16, -linux_literal_default,1,3,pt,pt PM_RESUME,0.1554114818572998,16, -linux_literal_default,1,3,pt,pt PM_RESUME,0.15415430068969727,16, -linux_literal_default,1,3,sift,sift PM_RESUME,0.1160738468170166,16, -linux_literal_default,1,3,sift,sift PM_RESUME,0.11754369735717773,16, -linux_literal_default,1,3,sift,sift PM_RESUME,0.11825299263000488,16, -linux_literal_default,1,3,git grep,git grep PM_RESUME,0.18619132041931152,16,LC_ALL=en_US.UTF-8 -linux_literal_default,1,3,git grep,git grep PM_RESUME,0.16708111763000488,16,LC_ALL=en_US.UTF-8 -linux_literal_default,1,3,git grep,git grep PM_RESUME,0.20236515998840332,16,LC_ALL=en_US.UTF-8 -linux_no_literal,1,3,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.34000611305236816,490, -linux_no_literal,1,3,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.36969494819641113,490, -linux_no_literal,1,3,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.3622872829437256,490, -linux_no_literal,1,3,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.2572669982910156,490, -linux_no_literal,1,3,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.3148176670074463,490, -linux_no_literal,1,3,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.3092081546783447,490, -linux_no_literal,1,3,ag (ignore) (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.7651598453521729,766, -linux_no_literal,1,3,ag (ignore) (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.7487096786499023,766, -linux_no_literal,1,3,ag (ignore) (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.7506840229034424,766, -linux_no_literal,1,3,pt (ignore) (ASCII),pt -e \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},12.426137685775757,490, -linux_no_literal,1,3,pt (ignore) (ASCII),pt -e \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},12.454124450683594,490, -linux_no_literal,1,3,pt (ignore) (ASCII),pt -e \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},12.573740243911743,490, -linux_no_literal,1,3,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},8.734328746795654,490, -linux_no_literal,1,3,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},8.95349931716919,490, -linux_no_literal,1,3,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},8.97816801071167,490, -linux_no_literal,1,3,git grep (ignore),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},8.792009830474854,490,LC_ALL=en_US.UTF-8 -linux_no_literal,1,3,git grep (ignore),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},8.744960308074951,490,LC_ALL=en_US.UTF-8 -linux_no_literal,1,3,git grep (ignore),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},9.04098892211914,490,LC_ALL=en_US.UTF-8 -linux_no_literal,1,3,git grep (ignore) (ASCII),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},1.8596012592315674,490,LC_ALL=C -linux_no_literal,1,3,git grep (ignore) (ASCII),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},1.824751853942871,490,LC_ALL=C -linux_no_literal,1,3,git grep (ignore) (ASCII),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},1.9543235301971436,490,LC_ALL=C -linux_no_literal,1,3,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.31849026679992676,419, -linux_no_literal,1,3,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.3028290271759033,419, -linux_no_literal,1,3,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.31795716285705566,419, -linux_no_literal,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.22214102745056152,419, -linux_no_literal,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.2748534679412842,419, -linux_no_literal,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.2098088264465332,419, -linux_no_literal,1,3,ucg (whitelist) (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.4494349956512451,416, -linux_no_literal,1,3,ucg (whitelist) (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.44551706314086914,416, -linux_no_literal,1,3,ucg (whitelist) (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.4425935745239258,416, -linux_re_literal_suffix,1,3,rg (ignore),rg -n [A-Z]+_RESUME,0.19018173217773438,1652, -linux_re_literal_suffix,1,3,rg (ignore),rg -n [A-Z]+_RESUME,0.1422746181488037,1652, -linux_re_literal_suffix,1,3,rg (ignore),rg -n [A-Z]+_RESUME,0.14041566848754883,1652, -linux_re_literal_suffix,1,3,ag (ignore),ag -s [A-Z]+_RESUME,0.5190994739532471,1652, -linux_re_literal_suffix,1,3,ag (ignore),ag -s [A-Z]+_RESUME,0.5290501117706299,1652, -linux_re_literal_suffix,1,3,ag (ignore),ag -s [A-Z]+_RESUME,0.5360753536224365,1652, -linux_re_literal_suffix,1,3,pt (ignore),pt -e [A-Z]+_RESUME,11.900719404220581,1652, -linux_re_literal_suffix,1,3,pt (ignore),pt -e [A-Z]+_RESUME,11.905181646347046,1652, -linux_re_literal_suffix,1,3,pt (ignore),pt -e [A-Z]+_RESUME,11.878832817077637,1652, -linux_re_literal_suffix,1,3,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git [A-Z]+_RESUME,3.9338936805725098,1652, -linux_re_literal_suffix,1,3,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git [A-Z]+_RESUME,3.971776247024536,1652, -linux_re_literal_suffix,1,3,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git [A-Z]+_RESUME,4.010965585708618,1652, -linux_re_literal_suffix,1,3,git grep (ignore),git grep -E -I -n [A-Z]+_RESUME,0.553400993347168,1652,LC_ALL=C -linux_re_literal_suffix,1,3,git grep (ignore),git grep -E -I -n [A-Z]+_RESUME,0.5757920742034912,1652,LC_ALL=C -linux_re_literal_suffix,1,3,git grep (ignore),git grep -E -I -n [A-Z]+_RESUME,0.6472165584564209,1652,LC_ALL=C -linux_re_literal_suffix,1,3,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.10109567642211914,1630, -linux_re_literal_suffix,1,3,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.1010751724243164,1630, -linux_re_literal_suffix,1,3,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.10259413719177246,1630, -linux_re_literal_suffix,1,3,ucg (whitelist),ucg --nosmart-case [A-Z]+_RESUME,0.13558602333068848,1630, -linux_re_literal_suffix,1,3,ucg (whitelist),ucg --nosmart-case [A-Z]+_RESUME,0.13765740394592285,1630, -linux_re_literal_suffix,1,3,ucg (whitelist),ucg --nosmart-case [A-Z]+_RESUME,0.14018011093139648,1630, -linux_unicode_greek,1,3,rg,rg -n \p{Greek},0.2655603885650635,23, -linux_unicode_greek,1,3,rg,rg -n \p{Greek},0.2579922676086426,23, -linux_unicode_greek,1,3,rg,rg -n \p{Greek},0.2389824390411377,23, -linux_unicode_greek,1,3,pt,pt -e \p{Greek},11.789764881134033,23, -linux_unicode_greek,1,3,pt,pt -e \p{Greek},11.717109680175781,23, -linux_unicode_greek,1,3,pt,pt -e \p{Greek},11.714937448501587,23, -linux_unicode_greek,1,3,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \p{Greek},2.732529401779175,23, -linux_unicode_greek,1,3,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \p{Greek},2.782707452774048,23, -linux_unicode_greek,1,3,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \p{Greek},2.8073642253875732,23, -linux_unicode_greek_casei,1,3,rg,rg -n -i \p{Greek},0.29653406143188477,103, -linux_unicode_greek_casei,1,3,rg,rg -n -i \p{Greek},0.24062681198120117,103, -linux_unicode_greek_casei,1,3,rg,rg -n -i \p{Greek},0.24714946746826172,103, -linux_unicode_greek_casei,1,3,pt,pt -i -e \p{Greek},11.754312515258789,23, -linux_unicode_greek_casei,1,3,pt,pt -i -e \p{Greek},11.742995500564575,23, -linux_unicode_greek_casei,1,3,pt,pt -i -e \p{Greek},11.763852596282959,23, -linux_unicode_greek_casei,1,3,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git \p{Greek},0.0018308162689208984,, -linux_unicode_greek_casei,1,3,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git \p{Greek},0.0017769336700439453,, -linux_unicode_greek_casei,1,3,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git \p{Greek},0.0018434524536132812,, -linux_unicode_word,1,3,rg (ignore),rg -n \wAh,0.19392776489257812,186, -linux_unicode_word,1,3,rg (ignore),rg -n \wAh,0.14665579795837402,186, -linux_unicode_word,1,3,rg (ignore),rg -n \wAh,0.15625548362731934,186, -linux_unicode_word,1,3,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.14500045776367188,174, -linux_unicode_word,1,3,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.15199685096740723,174, -linux_unicode_word,1,3,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.14606475830078125,174, -linux_unicode_word,1,3,ag (ignore) (ASCII),ag -s \wAh,0.47933006286621094,174, -linux_unicode_word,1,3,ag (ignore) (ASCII),ag -s \wAh,0.4965095520019531,174, -linux_unicode_word,1,3,ag (ignore) (ASCII),ag -s \wAh,0.4971892833709717,174, -linux_unicode_word,1,3,pt (ignore) (ASCII),pt -e \wAh,12.043948650360107,174, -linux_unicode_word,1,3,pt (ignore) (ASCII),pt -e \wAh,12.024799823760986,174, -linux_unicode_word,1,3,pt (ignore) (ASCII),pt -e \wAh,12.032919883728027,174, -linux_unicode_word,1,3,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \wAh,4.146677255630493,174, -linux_unicode_word,1,3,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \wAh,4.05977988243103,174, -linux_unicode_word,1,3,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \wAh,4.246629238128662,174, -linux_unicode_word,1,3,git grep (ignore),git grep -E -I -n \wAh,4.401025772094727,186,LC_ALL=en_US.UTF-8 -linux_unicode_word,1,3,git grep (ignore),git grep -E -I -n \wAh,4.499484062194824,186,LC_ALL=en_US.UTF-8 -linux_unicode_word,1,3,git grep (ignore),git grep -E -I -n \wAh,4.530885934829712,186,LC_ALL=en_US.UTF-8 -linux_unicode_word,1,3,git grep (ignore) (ASCII),git grep -E -I -n \wAh,1.552142858505249,174,LC_ALL=C -linux_unicode_word,1,3,git grep (ignore) (ASCII),git grep -E -I -n \wAh,1.4553732872009277,174,LC_ALL=C -linux_unicode_word,1,3,git grep (ignore) (ASCII),git grep -E -I -n \wAh,1.3407535552978516,174,LC_ALL=C -linux_unicode_word,1,3,rg (whitelist),rg -n --no-ignore -tall \wAh,0.10183477401733398,180, -linux_unicode_word,1,3,rg (whitelist),rg -n --no-ignore -tall \wAh,0.10535907745361328,180, -linux_unicode_word,1,3,rg (whitelist),rg -n --no-ignore -tall \wAh,0.10527634620666504,180, -linux_unicode_word,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.10268187522888184,168, -linux_unicode_word,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.10159945487976074,168, -linux_unicode_word,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.09854245185852051,168, -linux_unicode_word,1,3,ucg (ASCII),ucg --nosmart-case \wAh,0.17232871055603027,168, -linux_unicode_word,1,3,ucg (ASCII),ucg --nosmart-case \wAh,0.17245817184448242,168, -linux_unicode_word,1,3,ucg (ASCII),ucg --nosmart-case \wAh,0.1736738681793213,168, -linux_word,1,3,rg (ignore),rg -n -w PM_RESUME,0.18302679061889648,6, -linux_word,1,3,rg (ignore),rg -n -w PM_RESUME,0.14654874801635742,6, -linux_word,1,3,rg (ignore),rg -n -w PM_RESUME,0.14666008949279785,6, -linux_word,1,3,ag (ignore),ag -s -w PM_RESUME,0.43340468406677246,6, -linux_word,1,3,ag (ignore),ag -s -w PM_RESUME,0.4431777000427246,6, -linux_word,1,3,ag (ignore),ag -s -w PM_RESUME,0.4939415454864502,6, -linux_word,1,3,pt (ignore),pt -w PM_RESUME,12.12212347984314,6, -linux_word,1,3,pt (ignore),pt -w PM_RESUME,12.106850862503052,6, -linux_word,1,3,pt (ignore),pt -w PM_RESUME,12.119231224060059,6, -linux_word,1,3,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -w --git PM_RESUME,3.3320345878601074,6, -linux_word,1,3,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -w --git PM_RESUME,3.2089524269104004,6, -linux_word,1,3,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -w --git PM_RESUME,3.34165096282959,6, -linux_word,1,3,git grep (ignore),git grep -E -I -n -w PM_RESUME,0.20112895965576172,6,LC_ALL=C -linux_word,1,3,git grep (ignore),git grep -E -I -n -w PM_RESUME,0.16607999801635742,6,LC_ALL=C -linux_word,1,3,git grep (ignore),git grep -E -I -n -w PM_RESUME,0.2049086093902588,6,LC_ALL=C -linux_word,1,3,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.10440325736999512,6, -linux_word,1,3,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.09853243827819824,6, -linux_word,1,3,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.09580087661743164,6, -linux_word,1,3,ucg (whitelist),ucg --nosmart-case -w PM_RESUME,0.16874432563781738,6, -linux_word,1,3,ucg (whitelist),ucg --nosmart-case -w PM_RESUME,0.16241073608398438,6, -linux_word,1,3,ucg (whitelist),ucg --nosmart-case -w PM_RESUME,0.1621534824371338,6, -subtitles_en_alternate,1,3,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.5109667778015137,848, -subtitles_en_alternate,1,3,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.662921667098999,848, -subtitles_en_alternate,1,3,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.627272367477417,848, -subtitles_en_alternate,1,3,ag (lines),ag -s Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.4915170669555664,848, -subtitles_en_alternate,1,3,ag (lines),ag -s Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.294611930847168,848, -subtitles_en_alternate,1,3,ag (lines),ag -s Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.475243330001831,848, -subtitles_en_alternate,1,3,ucg (lines),ucg --nosmart-case Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.450028419494629,848, -subtitles_en_alternate,1,3,ucg (lines),ucg --nosmart-case Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.266982078552246,848, -subtitles_en_alternate,1,3,ucg (lines),ucg --nosmart-case Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.429199457168579,848, -subtitles_en_alternate,1,3,grep (lines),grep -E -an Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.81933856010437,848,LC_ALL=C -subtitles_en_alternate,1,3,grep (lines),grep -E -an Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.829207420349121,848,LC_ALL=C -subtitles_en_alternate,1,3,grep (lines),grep -E -an Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.795469284057617,848,LC_ALL=C -subtitles_en_alternate,1,3,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.3135373592376709,848, -subtitles_en_alternate,1,3,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.47072267532348633,848, -subtitles_en_alternate,1,3,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.3777759075164795,848, -subtitles_en_alternate,1,3,grep,grep -E -a Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.2277214527130127,848,LC_ALL=C -subtitles_en_alternate,1,3,grep,grep -E -a Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.4641876220703125,848,LC_ALL=C -subtitles_en_alternate,1,3,grep,grep -E -a Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.4201643466949463,848,LC_ALL=C -subtitles_en_alternate_casei,1,3,ag (ASCII),ag -s -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,3.925377368927002,862, -subtitles_en_alternate_casei,1,3,ag (ASCII),ag -s -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,3.7743782997131348,862, -subtitles_en_alternate_casei,1,3,ag (ASCII),ag -s -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,3.9031031131744385,862, -subtitles_en_alternate_casei,1,3,ucg (ASCII),ucg -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.902085542678833,862, -subtitles_en_alternate_casei,1,3,ucg (ASCII),ucg -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.9104111194610596,862, -subtitles_en_alternate_casei,1,3,ucg (ASCII),ucg -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.9407846927642822,862, -subtitles_en_alternate_casei,1,3,grep (ASCII),grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,3.6935694217681885,862,LC_ALL=C -subtitles_en_alternate_casei,1,3,grep (ASCII),grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,3.7745134830474854,862,LC_ALL=C -subtitles_en_alternate_casei,1,3,grep (ASCII),grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,3.5532472133636475,862,LC_ALL=C -subtitles_en_alternate_casei,1,3,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.3000056743621826,862, -subtitles_en_alternate_casei,1,3,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.46085786819458,862, -subtitles_en_alternate_casei,1,3,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.2774720191955566,862, -subtitles_en_alternate_casei,1,3,grep,grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,4.183770418167114,862,LC_ALL=en_US.UTF-8 -subtitles_en_alternate_casei,1,3,grep,grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,4.210017442703247,862,LC_ALL=en_US.UTF-8 -subtitles_en_alternate_casei,1,3,grep,grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,4.052750587463379,862,LC_ALL=en_US.UTF-8 -subtitles_en_literal,1,3,rg,rg Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2422008514404297,629, -subtitles_en_literal,1,3,rg,rg Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.18678736686706543,629, -subtitles_en_literal,1,3,rg,rg Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.20187044143676758,629, -subtitles_en_literal,1,3,rg (no mmap),rg --no-mmap Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.21189618110656738,629, -subtitles_en_literal,1,3,rg (no mmap),rg --no-mmap Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.21378588676452637,629, -subtitles_en_literal,1,3,rg (no mmap),rg --no-mmap Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2638204097747803,629, -subtitles_en_literal,1,3,pt,pt -N Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.6680185794830322,629, -subtitles_en_literal,1,3,pt,pt -N Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.7018795013427734,629, -subtitles_en_literal,1,3,pt,pt -N Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.7135086059570312,629, -subtitles_en_literal,1,3,sift,sift Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.33170270919799805,629, -subtitles_en_literal,1,3,sift,sift Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.3204488754272461,629, -subtitles_en_literal,1,3,sift,sift Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.3302597999572754,629, -subtitles_en_literal,1,3,grep,grep -a Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.5119576454162598,629,LC_ALL=C -subtitles_en_literal,1,3,grep,grep -a Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.48076844215393066,629,LC_ALL=C -subtitles_en_literal,1,3,grep,grep -a Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.6118988990783691,629,LC_ALL=C -subtitles_en_literal,1,3,rg (lines),rg -n Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.6149063110351562,629, -subtitles_en_literal,1,3,rg (lines),rg -n Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.547245979309082,629, -subtitles_en_literal,1,3,rg (lines),rg -n Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.5441193580627441,629, -subtitles_en_literal,1,3,ag (lines),ag -s Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.990401268005371,629, -subtitles_en_literal,1,3,ag (lines),ag -s Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.9924650192260742,629, -subtitles_en_literal,1,3,ag (lines),ag -s Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.807952642440796,629, -subtitles_en_literal,1,3,ucg (lines),ucg --nosmart-case Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.772294282913208,629, -subtitles_en_literal,1,3,ucg (lines),ucg --nosmart-case Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.8758792877197266,629, -subtitles_en_literal,1,3,ucg (lines),ucg --nosmart-case Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.8043625354766846,629, -subtitles_en_literal,1,3,pt (lines),pt Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.5409111976623535,629, -subtitles_en_literal,1,3,pt (lines),pt Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.535851001739502,629, -subtitles_en_literal,1,3,pt (lines),pt Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.6951041221618652,629, -subtitles_en_literal,1,3,sift (lines),sift -n Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.7138817310333252,629, -subtitles_en_literal,1,3,sift (lines),sift -n Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.727524995803833,629, -subtitles_en_literal,1,3,sift (lines),sift -n Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.7202486991882324,629, -subtitles_en_literal,1,3,grep (lines),grep -an Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.0228428840637207,629,LC_ALL=C -subtitles_en_literal,1,3,grep (lines),grep -an Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.9452800750732422,629,LC_ALL=C -subtitles_en_literal,1,3,grep (lines),grep -an Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.0286569595336914,629,LC_ALL=C -subtitles_en_literal_casei,1,3,rg,rg -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.36867737770080566,642, -subtitles_en_literal_casei,1,3,rg,rg -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.391110897064209,642, -subtitles_en_literal_casei,1,3,rg,rg -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.42432594299316406,642, -subtitles_en_literal_casei,1,3,grep,grep -ai Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,3.2124955654144287,642,LC_ALL=en_US.UTF-8 -subtitles_en_literal_casei,1,3,grep,grep -ai Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,3.288994789123535,642,LC_ALL=en_US.UTF-8 -subtitles_en_literal_casei,1,3,grep,grep -ai Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,3.2279436588287354,642,LC_ALL=en_US.UTF-8 -subtitles_en_literal_casei,1,3,grep (ASCII),grep -E -ai Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.5713660717010498,642,LC_ALL=C -subtitles_en_literal_casei,1,3,grep (ASCII),grep -E -ai Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.5478014945983887,642,LC_ALL=C -subtitles_en_literal_casei,1,3,grep (ASCII),grep -E -ai Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.5502541065216064,642,LC_ALL=C -subtitles_en_literal_casei,1,3,rg (lines),rg -n -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.5866222381591797,642, -subtitles_en_literal_casei,1,3,rg (lines),rg -n -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.5829083919525146,642, -subtitles_en_literal_casei,1,3,rg (lines),rg -n -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.7458250522613525,642, -subtitles_en_literal_casei,1,3,ag (lines) (ASCII),ag -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.8324756622314453,642, -subtitles_en_literal_casei,1,3,ag (lines) (ASCII),ag -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.8361680507659912,642, -subtitles_en_literal_casei,1,3,ag (lines) (ASCII),ag -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.017822265625,642, -subtitles_en_literal_casei,1,3,ucg (lines) (ASCII),ucg -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.9228289127349854,642, -subtitles_en_literal_casei,1,3,ucg (lines) (ASCII),ucg -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.9356215000152588,642, -subtitles_en_literal_casei,1,3,ucg (lines) (ASCII),ucg -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.9355306625366211,642, -subtitles_en_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.46090102195739746,629, -subtitles_en_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.41375064849853516,629, -subtitles_en_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.4181649684906006,629, -subtitles_en_literal_word,1,3,ag (ASCII),ag -sw Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.8445067405700684,629, -subtitles_en_literal_word,1,3,ag (ASCII),ag -sw Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.805356740951538,629, -subtitles_en_literal_word,1,3,ag (ASCII),ag -sw Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.8274097442626953,629, -subtitles_en_literal_word,1,3,ucg (ASCII),ucg --nosmart-case Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.9036450386047363,629, -subtitles_en_literal_word,1,3,ucg (ASCII),ucg --nosmart-case Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.7601873874664307,629, -subtitles_en_literal_word,1,3,ucg (ASCII),ucg --nosmart-case Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.7341368198394775,629, -subtitles_en_literal_word,1,3,grep (ASCII),grep -anw Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.867140531539917,629,LC_ALL=C -subtitles_en_literal_word,1,3,grep (ASCII),grep -anw Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.8452246189117432,629,LC_ALL=C -subtitles_en_literal_word,1,3,grep (ASCII),grep -anw Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.8254234790802002,629,LC_ALL=C -subtitles_en_literal_word,1,3,rg,rg -nw Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.39222264289855957,629, -subtitles_en_literal_word,1,3,rg,rg -nw Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.5510556697845459,629, -subtitles_en_literal_word,1,3,rg,rg -nw Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.439284086227417,629, -subtitles_en_literal_word,1,3,grep,grep -anw Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.8688523769378662,629,LC_ALL=en_US.UTF-8 -subtitles_en_literal_word,1,3,grep,grep -anw Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.0727341175079346,629,LC_ALL=en_US.UTF-8 -subtitles_en_literal_word,1,3,grep,grep -anw Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.8665497303009033,629,LC_ALL=en_US.UTF-8 -subtitles_en_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.2950611114501953,13, -subtitles_en_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.226304769515991,13, -subtitles_en_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.3140387535095215,13, -subtitles_en_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.055910587310791,13, -subtitles_en_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.032794952392578,13, -subtitles_en_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.0602478981018066,13, -subtitles_en_no_literal,1,3,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,7.566168308258057,48, -subtitles_en_no_literal,1,3,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,7.360717535018921,48, -subtitles_en_no_literal,1,3,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,7.30781364440918,48, -subtitles_en_no_literal,1,3,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,6.13957142829895,13, -subtitles_en_no_literal,1,3,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,6.132368564605713,13, -subtitles_en_no_literal,1,3,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,5.929611921310425,13, -subtitles_en_no_literal,1,3,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,3.432003974914551,13,LC_ALL=C -subtitles_en_no_literal,1,3,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,3.714038610458374,13,LC_ALL=C -subtitles_en_no_literal,1,3,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,3.6915385723114014,13,LC_ALL=C -subtitles_en_surrounding_words,1,3,rg,rg -n \w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.42601513862609863,317, -subtitles_en_surrounding_words,1,3,rg,rg -n \w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.561565637588501,317, -subtitles_en_surrounding_words,1,3,rg,rg -n \w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.5141217708587646,317, -subtitles_en_surrounding_words,1,3,grep,grep -E -an \w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.3077969551086426,317,LC_ALL=en_US.UTF-8 -subtitles_en_surrounding_words,1,3,grep,grep -E -an \w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.1768431663513184,317,LC_ALL=en_US.UTF-8 -subtitles_en_surrounding_words,1,3,grep,grep -E -an \w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.0883615016937256,317,LC_ALL=en_US.UTF-8 -subtitles_en_surrounding_words,1,3,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.5061089992523193,317, -subtitles_en_surrounding_words,1,3,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.4004178047180176,317, -subtitles_en_surrounding_words,1,3,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.5536422729492188,317, -subtitles_en_surrounding_words,1,3,ag (ASCII),ag -s \w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,4.981522798538208,323, -subtitles_en_surrounding_words,1,3,ag (ASCII),ag -s \w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,4.83101487159729,323, -subtitles_en_surrounding_words,1,3,ag (ASCII),ag -s \w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,5.025806427001953,323, -subtitles_en_surrounding_words,1,3,ucg (ASCII),ucg --nosmart-case \w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,3.906707286834717,317, -subtitles_en_surrounding_words,1,3,ucg (ASCII),ucg --nosmart-case \w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,3.8826284408569336,317, -subtitles_en_surrounding_words,1,3,ucg (ASCII),ucg --nosmart-case \w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,3.852736711502075,317, -subtitles_en_surrounding_words,1,3,grep (ASCII),grep -E -an \w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.262470006942749,317,LC_ALL=C -subtitles_en_surrounding_words,1,3,grep (ASCII),grep -E -an \w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.1661438941955566,317,LC_ALL=C -subtitles_en_surrounding_words,1,3,grep (ASCII),grep -E -an \w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.1648437976837158,317,LC_ALL=C -subtitles_ru_alternate,1,3,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.79972243309021,691, -subtitles_ru_alternate,1,3,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.629694938659668,691, -subtitles_ru_alternate,1,3,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.8325402736663818,691, -subtitles_ru_alternate,1,3,ag (lines),ag -s Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,4.124853849411011,691, -subtitles_ru_alternate,1,3,ag (lines),ag -s Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,4.0995543003082275,691, -subtitles_ru_alternate,1,3,ag (lines),ag -s Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,4.105457544326782,691, -subtitles_ru_alternate,1,3,ucg (lines),ucg --nosmart-case Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.491947650909424,691, -subtitles_ru_alternate,1,3,ucg (lines),ucg --nosmart-case Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.544341802597046,691, -subtitles_ru_alternate,1,3,ucg (lines),ucg --nosmart-case Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.6295418739318848,691, -subtitles_ru_alternate,1,3,grep (lines),grep -E -an Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,6.948693513870239,691,LC_ALL=C -subtitles_ru_alternate,1,3,grep (lines),grep -E -an Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,6.991183280944824,691,LC_ALL=C -subtitles_ru_alternate,1,3,grep (lines),grep -E -an Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,7.004202842712402,691,LC_ALL=C -subtitles_ru_alternate,1,3,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.1708271503448486,691, -subtitles_ru_alternate,1,3,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.3341143131256104,691, -subtitles_ru_alternate,1,3,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.3589985370635986,691, -subtitles_ru_alternate,1,3,grep,grep -E -a Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,6.3860955238342285,691,LC_ALL=C -subtitles_ru_alternate,1,3,grep,grep -E -a Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,6.437295436859131,691,LC_ALL=C -subtitles_ru_alternate,1,3,grep,grep -E -a Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,6.34372615814209,691,LC_ALL=C -subtitles_ru_alternate_casei,1,3,ag (ASCII),ag -s -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,4.100299119949341,691, -subtitles_ru_alternate_casei,1,3,ag (ASCII),ag -s -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,4.343926668167114,691, -subtitles_ru_alternate_casei,1,3,ag (ASCII),ag -s -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,4.247299432754517,691, -subtitles_ru_alternate_casei,1,3,ucg (ASCII),ucg -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.6179757118225098,691, -subtitles_ru_alternate_casei,1,3,ucg (ASCII),ucg -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.438668727874756,691, -subtitles_ru_alternate_casei,1,3,ucg (ASCII),ucg -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.6296229362487793,691, -subtitles_ru_alternate_casei,1,3,grep (ASCII),grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,6.816138744354248,691,LC_ALL=C -subtitles_ru_alternate_casei,1,3,grep (ASCII),grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,7.005900859832764,691,LC_ALL=C -subtitles_ru_alternate_casei,1,3,grep (ASCII),grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,6.96263861656189,691,LC_ALL=C -subtitles_ru_alternate_casei,1,3,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,4.222437858581543,735, -subtitles_ru_alternate_casei,1,3,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,4.260664463043213,735, -subtitles_ru_alternate_casei,1,3,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,4.040424823760986,735, -subtitles_ru_alternate_casei,1,3,grep,grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,7.112156391143799,735,LC_ALL=en_US.UTF-8 -subtitles_ru_alternate_casei,1,3,grep,grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,7.066831350326538,735,LC_ALL=en_US.UTF-8 -subtitles_ru_alternate_casei,1,3,grep,grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,6.983258962631226,735,LC_ALL=en_US.UTF-8 -subtitles_ru_literal,1,3,rg,rg Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3009657859802246,583, -subtitles_ru_literal,1,3,rg,rg Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.31114768981933594,583, -subtitles_ru_literal,1,3,rg,rg Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3145453929901123,583, -subtitles_ru_literal,1,3,rg (no mmap),rg --no-mmap Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3670217990875244,583, -subtitles_ru_literal,1,3,rg (no mmap),rg --no-mmap Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.39557576179504395,583, -subtitles_ru_literal,1,3,rg (no mmap),rg --no-mmap Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.38857460021972656,583, -subtitles_ru_literal,1,3,pt,pt -N Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,5.653504133224487,583, -subtitles_ru_literal,1,3,pt,pt -N Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,5.440903663635254,583, -subtitles_ru_literal,1,3,pt,pt -N Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,5.604345321655273,583, -subtitles_ru_literal,1,3,sift,sift Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,6.333267450332642,583, -subtitles_ru_literal,1,3,sift,sift Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,6.3738181591033936,583, -subtitles_ru_literal,1,3,sift,sift Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,6.604928970336914,583, -subtitles_ru_literal,1,3,grep,grep -a Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.7382421493530273,583,LC_ALL=C -subtitles_ru_literal,1,3,grep,grep -a Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.7205381393432617,583,LC_ALL=C -subtitles_ru_literal,1,3,grep,grep -a Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.8509528636932373,583,LC_ALL=C -subtitles_ru_literal,1,3,rg (lines),rg -n Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.6589868068695068,583, -subtitles_ru_literal,1,3,rg (lines),rg -n Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.857933759689331,583, -subtitles_ru_literal,1,3,rg (lines),rg -n Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.7283596992492676,583, -subtitles_ru_literal,1,3,ag (lines),ag -s Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.111611843109131,583, -subtitles_ru_literal,1,3,ag (lines),ag -s Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.1084604263305664,583, -subtitles_ru_literal,1,3,ag (lines),ag -s Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.993370771408081,583, -subtitles_ru_literal,1,3,ucg (lines),ucg --nosmart-case Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.8463020324707031,583, -subtitles_ru_literal,1,3,ucg (lines),ucg --nosmart-case Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.8160367012023926,583, -subtitles_ru_literal,1,3,ucg (lines),ucg --nosmart-case Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.9012954235076904,583, -subtitles_ru_literal,1,3,pt (lines),pt Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,5.590208530426025,583, -subtitles_ru_literal,1,3,pt (lines),pt Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,5.712487697601318,583, -subtitles_ru_literal,1,3,pt (lines),pt Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,5.628024339675903,583, -subtitles_ru_literal,1,3,sift (lines),sift -n Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,6.999194145202637,583, -subtitles_ru_literal,1,3,sift (lines),sift -n Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,6.639494895935059,583, -subtitles_ru_literal,1,3,sift (lines),sift -n Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,6.6554951667785645,583, -subtitles_ru_literal,1,3,grep (lines),grep -an Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.3319404125213623,583,LC_ALL=C -subtitles_ru_literal,1,3,grep (lines),grep -an Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.3712143898010254,583,LC_ALL=C -subtitles_ru_literal,1,3,grep (lines),grep -an Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.2382845878601074,583,LC_ALL=C -subtitles_ru_literal_casei,1,3,rg,rg -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.2365717887878418,604, -subtitles_ru_literal_casei,1,3,rg,rg -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.2306108474731445,604, -subtitles_ru_literal_casei,1,3,rg,rg -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.22041654586792,604, -subtitles_ru_literal_casei,1,3,grep,grep -ai Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,6.636392116546631,604,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_casei,1,3,grep,grep -ai Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,6.447664976119995,604,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_casei,1,3,grep,grep -ai Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,6.47466516494751,604,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_casei,1,3,grep (ASCII),grep -E -ai Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.8679373264312744,583,LC_ALL=C -subtitles_ru_literal_casei,1,3,grep (ASCII),grep -E -ai Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.8400778770446777,583,LC_ALL=C -subtitles_ru_literal_casei,1,3,grep (ASCII),grep -E -ai Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.8912734985351562,583,LC_ALL=C -subtitles_ru_literal_casei,1,3,rg (lines),rg -n -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.6649067401885986,604, -subtitles_ru_literal_casei,1,3,rg (lines),rg -n -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.472435712814331,604, -subtitles_ru_literal_casei,1,3,rg (lines),rg -n -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.5518934726715088,604, -subtitles_ru_literal_casei,1,3,ag (lines) (ASCII),ag -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.6329071521759033,, -subtitles_ru_literal_casei,1,3,ag (lines) (ASCII),ag -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.6236186027526855,, -subtitles_ru_literal_casei,1,3,ag (lines) (ASCII),ag -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.744124174118042,, -subtitles_ru_literal_casei,1,3,ucg (lines) (ASCII),ucg -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.842088222503662,583, -subtitles_ru_literal_casei,1,3,ucg (lines) (ASCII),ucg -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.6797516345977783,583, -subtitles_ru_literal_casei,1,3,ucg (lines) (ASCII),ucg -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.86281418800354,583, -subtitles_ru_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3059053421020508,, -subtitles_ru_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3220036029815674,, -subtitles_ru_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3317573070526123,, -subtitles_ru_literal_word,1,3,ag (ASCII),ag -sw Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.790125846862793,, -subtitles_ru_literal_word,1,3,ag (ASCII),ag -sw Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.8004007339477539,, -subtitles_ru_literal_word,1,3,ag (ASCII),ag -sw Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.7884745597839355,, -subtitles_ru_literal_word,1,3,ucg (ASCII),ucg --nosmart-case Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.8595643043518066,583, -subtitles_ru_literal_word,1,3,ucg (ASCII),ucg --nosmart-case Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.8338594436645508,583, -subtitles_ru_literal_word,1,3,ucg (ASCII),ucg --nosmart-case Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.6697683334350586,583, -subtitles_ru_literal_word,1,3,grep (ASCII),grep -anw Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.1608448028564453,583,LC_ALL=C -subtitles_ru_literal_word,1,3,grep (ASCII),grep -anw Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.3229436874389648,583,LC_ALL=C -subtitles_ru_literal_word,1,3,grep (ASCII),grep -anw Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.3650012016296387,583,LC_ALL=C -subtitles_ru_literal_word,1,3,rg,rg -nw Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.840968132019043,579, -subtitles_ru_literal_word,1,3,rg,rg -nw Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.7012484073638916,579, -subtitles_ru_literal_word,1,3,rg,rg -nw Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.6782803535461426,579, -subtitles_ru_literal_word,1,3,grep,grep -anw Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.3308250904083252,579,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_word,1,3,grep,grep -anw Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.2687301635742188,579,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_word,1,3,grep,grep -anw Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.317870855331421,579,LC_ALL=en_US.UTF-8 -subtitles_ru_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.8553390502929688,41, -subtitles_ru_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.6567201614379883,41, -subtitles_ru_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.6484830379486084,41, -subtitles_ru_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.968876838684082,, -subtitles_ru_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.0976366996765137,, -subtitles_ru_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.9159646034240723,, -subtitles_ru_no_literal,1,3,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.8425374031066895,, -subtitles_ru_no_literal,1,3,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.0483176708221436,, -subtitles_ru_no_literal,1,3,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.0838112831115723,, -subtitles_ru_no_literal,1,3,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.510307550430298,, -subtitles_ru_no_literal,1,3,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.542471408843994,, -subtitles_ru_no_literal,1,3,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.5069386959075928,, -subtitles_ru_no_literal,1,3,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.0888967514038086,,LC_ALL=C -subtitles_ru_no_literal,1,3,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.119218349456787,,LC_ALL=C -subtitles_ru_no_literal,1,3,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.0531933307647705,,LC_ALL=C -subtitles_ru_surrounding_words,1,3,rg,rg -n \w+\s+Холмс\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.792813777923584,278, -subtitles_ru_surrounding_words,1,3,rg,rg -n \w+\s+Холмс\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.8660504817962646,278, -subtitles_ru_surrounding_words,1,3,rg,rg -n \w+\s+Холмс\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.8515620231628418,278, -subtitles_ru_surrounding_words,1,3,grep,grep -E -an \w+\s+Холмс\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.4405500888824463,278,LC_ALL=en_US.UTF-8 -subtitles_ru_surrounding_words,1,3,grep,grep -E -an \w+\s+Холмс\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.6386635303497314,278,LC_ALL=en_US.UTF-8 -subtitles_ru_surrounding_words,1,3,grep,grep -E -an \w+\s+Холмс\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.5895426273345947,278,LC_ALL=en_US.UTF-8 -subtitles_ru_surrounding_words,1,3,ag (ASCII),ag -s \w+\s+Холмс\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.032708168029785,, -subtitles_ru_surrounding_words,1,3,ag (ASCII),ag -s \w+\s+Холмс\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.927478551864624,, -subtitles_ru_surrounding_words,1,3,ag (ASCII),ag -s \w+\s+Холмс\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.019101619720459,, -subtitles_ru_surrounding_words,1,3,ucg (ASCII),ucg --nosmart-case \w+\s+Холмс\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.6226632595062256,, -subtitles_ru_surrounding_words,1,3,ucg (ASCII),ucg --nosmart-case \w+\s+Холмс\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.5062124729156494,, -subtitles_ru_surrounding_words,1,3,ucg (ASCII),ucg --nosmart-case \w+\s+Холмс\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.5160763263702393,, -subtitles_ru_surrounding_words,1,3,grep (ASCII),grep -E -an \w+\s+Холмс\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.613976240158081,,LC_ALL=C -subtitles_ru_surrounding_words,1,3,grep (ASCII),grep -E -an \w+\s+Холмс\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.5636706352233887,,LC_ALL=C -subtitles_ru_surrounding_words,1,3,grep (ASCII),grep -E -an \w+\s+Холмс\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.4378304481506348,,LC_ALL=C diff --git a/benchsuite/runs/2016-09-22-archlinux-cheetah/summary b/benchsuite/runs/2016-09-22-archlinux-cheetah/summary deleted file mode 100644 index 3f84c28..0000000 --- a/benchsuite/runs/2016-09-22-archlinux-cheetah/summary +++ /dev/null @@ -1,235 +0,0 @@ -linux_alternates (pattern: ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT) -------------------------------------------------------------------------- -rg (ignore) 0.159 +/- 0.002 (lines: 68) -ag (ignore) 0.557 +/- 0.009 (lines: 68) -git grep (ignore) 0.252 +/- 0.005 (lines: 68) -rg (whitelist)* 0.103 +/- 0.001 (lines: 68)* -ucg (whitelist) 0.155 +/- 0.002 (lines: 68) - -linux_alternates_casei (pattern: ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT) -------------------------------------------------------------------------------- -rg (ignore) 0.161 +/- 0.001 (lines: 160) -ag (ignore) 0.628 +/- 0.040 (lines: 160) -git grep (ignore) 0.940 +/- 0.109 (lines: 160) -rg (whitelist)* 0.123 +/- 0.010 (lines: 160)* -ucg (whitelist) 0.240 +/- 0.002 (lines: 160) - -linux_literal (pattern: PM_RESUME) ----------------------------------- -rg (ignore) 0.159 +/- 0.015 (lines: 16) -rg (ignore) (mmap) 0.389 +/- 0.009 (lines: 16) -ag (ignore) (mmap) 0.574 +/- 0.138 (lines: 16) -pt (ignore) 0.157 +/- 0.006 (lines: 16) -sift (ignore) 0.346 +/- 0.007 (lines: 16) -git grep (ignore) 0.201 +/- 0.011 (lines: 16) -rg (whitelist)* 0.104 +/- 0.003 (lines: 16)* -ucg (whitelist) 0.169 +/- 0.002 (lines: 16) - -linux_literal_casei (pattern: PM_RESUME) ----------------------------------------- -rg (ignore) 0.155 +/- 0.009 (lines: 370) -rg (ignore) (mmap) 0.393 +/- 0.005 (lines: 370) -ag (ignore) (mmap) 0.462 +/- 0.035 (lines: 370) -pt (ignore) 11.936 +/- 0.106 (lines: 370) -sift (ignore) 0.370 +/- 0.004 (lines: 370) -git grep (ignore) 0.190 +/- 0.006 (lines: 370) -rg (whitelist)* 0.109 +/- 0.004 (lines: 370)* -ucg (whitelist) 0.162 +/- 0.002 (lines: 370) - -linux_literal_default (pattern: PM_RESUME) ------------------------------------------- -rg 0.139 +/- 0.001 (lines: 16) -ag 0.441 +/- 0.021 (lines: 16) -ucg 0.165 +/- 0.005 (lines: 16) -pt 0.156 +/- 0.002 (lines: 16) -sift* 0.117 +/- 0.001 (lines: 16)* -git grep 0.185 +/- 0.018 (lines: 16) - -linux_no_literal (pattern: \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}) ------------------------------------------------------------------ -rg (ignore) 0.357 +/- 0.015 (lines: 490) -rg (ignore) (ASCII) 0.294 +/- 0.032 (lines: 490) -ag (ignore) (ASCII) 0.755 +/- 0.009 (lines: 766) -pt (ignore) (ASCII) 12.485 +/- 0.078 (lines: 490) -sift (ignore) (ASCII) 8.889 +/- 0.134 (lines: 490) -git grep (ignore) 8.859 +/- 0.159 (lines: 490) -git grep (ignore) (ASCII) 1.880 +/- 0.067 (lines: 490) -rg (whitelist) 0.313 +/- 0.009 (lines: 419) -rg (whitelist) (ASCII)* 0.236 +/- 0.035 (lines: 419)* -ucg (whitelist) (ASCII) 0.446 +/- 0.003 (lines: 416) - -linux_re_literal_suffix (pattern: [A-Z]+_RESUME) ------------------------------------------------- -rg (ignore) 0.158 +/- 0.028 (lines: 1652) -ag (ignore) 0.528 +/- 0.009 (lines: 1652) -pt (ignore) 11.895 +/- 0.014 (lines: 1652) -sift (ignore) 3.972 +/- 0.039 (lines: 1652) -git grep (ignore) 0.592 +/- 0.049 (lines: 1652) -rg (whitelist)* 0.102 +/- 0.001 (lines: 1630)* -ucg (whitelist) 0.138 +/- 0.002 (lines: 1630) - -linux_unicode_greek (pattern: \p{Greek}) ----------------------------------------- -rg* 0.254 +/- 0.014 (lines: 23)* -pt 11.741 +/- 0.043 (lines: 23) -sift 2.774 +/- 0.038 (lines: 23) - -linux_unicode_greek_casei (pattern: \p{Greek}) ----------------------------------------------- -rg 0.261 +/- 0.031 (lines: 103) -pt 11.754 +/- 0.010 (lines: 23) -sift* 0.002 +/- 0.000 (lines: 0)* - -linux_unicode_word (pattern: \wAh) ----------------------------------- -rg (ignore) 0.166 +/- 0.025 (lines: 186) -rg (ignore) (ASCII) 0.148 +/- 0.004 (lines: 174) -ag (ignore) (ASCII) 0.491 +/- 0.010 (lines: 174) -pt (ignore) (ASCII) 12.034 +/- 0.010 (lines: 174) -sift (ignore) (ASCII) 4.151 +/- 0.094 (lines: 174) -git grep (ignore) 4.477 +/- 0.068 (lines: 186) -git grep (ignore) (ASCII) 1.449 +/- 0.106 (lines: 174) -rg (whitelist) 0.104 +/- 0.002 (lines: 180) -rg (whitelist) (ASCII)* 0.101 +/- 0.002 (lines: 168)* -ucg (ASCII) 0.173 +/- 0.001 (lines: 168) - -linux_word (pattern: PM_RESUME) -------------------------------- -rg (ignore) 0.159 +/- 0.021 (lines: 6) -ag (ignore) 0.457 +/- 0.032 (lines: 6) -pt (ignore) 12.116 +/- 0.008 (lines: 6) -sift (ignore) 3.294 +/- 0.074 (lines: 6) -git grep (ignore) 0.191 +/- 0.021 (lines: 6) -rg (whitelist)* 0.100 +/- 0.004 (lines: 6)* -ucg (whitelist) 0.164 +/- 0.004 (lines: 6) - -subtitles_en_alternate (pattern: Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty) ---------------------------------------------------------------------------------------------------------------- -rg (lines) 0.600 +/- 0.079 (lines: 848) -ag (lines) 2.420 +/- 0.109 (lines: 848) -ucg (lines) 1.382 +/- 0.100 (lines: 848) -grep (lines) 2.815 +/- 0.017 (lines: 848) -rg* 0.387 +/- 0.079 (lines: 848)* -grep 2.371 +/- 0.126 (lines: 848) - -subtitles_en_alternate_casei (pattern: Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty) ---------------------------------------------------------------------------------------------------------------------- -ag (ASCII) 3.868 +/- 0.082 (lines: 862) -ucg (ASCII) 2.918 +/- 0.020 (lines: 862) -grep (ASCII) 3.674 +/- 0.112 (lines: 862) -rg* 2.346 +/- 0.100 (lines: 862)* -grep 4.149 +/- 0.084 (lines: 862) - -subtitles_en_literal (pattern: Sherlock Holmes) ------------------------------------------------ -rg* 0.210 +/- 0.029 (lines: 629)* -rg (no mmap) 0.230 +/- 0.029 (lines: 629) -pt 1.694 +/- 0.024 (lines: 629) -sift 0.327 +/- 0.006 (lines: 629) -grep 0.535 +/- 0.069 (lines: 629) -rg (lines) 0.569 +/- 0.040 (lines: 629) -ag (lines) 1.930 +/- 0.106 (lines: 629) -ucg (lines) 0.818 +/- 0.053 (lines: 629) -pt (lines) 1.591 +/- 0.091 (lines: 629) -sift (lines) 0.721 +/- 0.007 (lines: 629) -grep (lines) 0.999 +/- 0.047 (lines: 629) - -subtitles_en_literal_casei (pattern: Sherlock Holmes) ------------------------------------------------------ -rg* 0.395 +/- 0.028 (lines: 642)* -grep 3.243 +/- 0.040 (lines: 642) -grep (ASCII) 0.556 +/- 0.013 (lines: 642) -rg (lines) 0.638 +/- 0.093 (lines: 642) -ag (lines) (ASCII) 1.895 +/- 0.106 (lines: 642) -ucg (lines) (ASCII) 0.931 +/- 0.007 (lines: 642) - -subtitles_en_literal_word (pattern: Sherlock Holmes) ----------------------------------------------------- -rg (ASCII) 0.431 +/- 0.026 (lines: 629)* -ag (ASCII) 1.826 +/- 0.020 (lines: 629) -ucg (ASCII) 0.799 +/- 0.091 (lines: 629) -grep (ASCII) 0.846 +/- 0.021 (lines: 629) -rg* 0.461 +/- 0.082 (lines: 629) -grep 0.936 +/- 0.118 (lines: 629) - -subtitles_en_no_literal (pattern: \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}) ----------------------------------------------------------------------------------------- -rg 2.278 +/- 0.046 (lines: 13) -rg (ASCII)* 2.050 +/- 0.015 (lines: 13)* -ag (ASCII) 7.412 +/- 0.136 (lines: 48) -ucg (ASCII) 6.067 +/- 0.119 (lines: 13) -grep (ASCII) 3.613 +/- 0.157 (lines: 13) - -subtitles_en_surrounding_words (pattern: \w+\s+Holmes\s+\w+) ------------------------------------------------------------- -rg 0.501 +/- 0.069 (lines: 317) -grep 1.191 +/- 0.110 (lines: 317) -rg (ASCII)* 0.487 +/- 0.078 (lines: 317)* -ag (ASCII) 4.946 +/- 0.102 (lines: 323) -ucg (ASCII) 3.881 +/- 0.027 (lines: 317) -grep (ASCII) 1.198 +/- 0.056 (lines: 317) - -subtitles_ru_alternate (pattern: Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти) ------------------------------------------------------------------------------------------------------------ -rg (lines) 1.754 +/- 0.109 (lines: 691) -ag (lines) 4.110 +/- 0.013 (lines: 691) -ucg (lines) 2.555 +/- 0.069 (lines: 691) -grep (lines) 6.981 +/- 0.029 (lines: 691) -rg* 1.288 +/- 0.102 (lines: 691)* -grep 6.389 +/- 0.047 (lines: 691) - -subtitles_ru_alternate_casei (pattern: Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти) ------------------------------------------------------------------------------------------------------------------ -ag (ASCII) 4.231 +/- 0.123 (lines: 691) -ucg (ASCII)* 2.562 +/- 0.107 (lines: 691)* -grep (ASCII) 6.928 +/- 0.099 (lines: 691) -rg 4.175 +/- 0.118 (lines: 735) -grep 7.054 +/- 0.065 (lines: 735) - -subtitles_ru_literal (pattern: Шерлок Холмс) --------------------------------------------- -rg* 0.309 +/- 0.007 (lines: 583)* -rg (no mmap) 0.384 +/- 0.015 (lines: 583) -pt 5.566 +/- 0.111 (lines: 583) -sift 6.437 +/- 0.147 (lines: 583) -grep 0.770 +/- 0.071 (lines: 583) -rg (lines) 0.748 +/- 0.101 (lines: 583) -ag (lines) 3.071 +/- 0.067 (lines: 583) -ucg (lines) 1.855 +/- 0.043 (lines: 583) -pt (lines) 5.644 +/- 0.063 (lines: 583) -sift (lines) 6.765 +/- 0.203 (lines: 583) -grep (lines) 1.314 +/- 0.068 (lines: 583) - -subtitles_ru_literal_casei (pattern: Шерлок Холмс) --------------------------------------------------- -rg 1.229 +/- 0.008 (lines: 604) -grep 6.520 +/- 0.102 (lines: 604) -grep (ASCII) 0.866 +/- 0.026 (lines: 583) -rg (lines) 1.563 +/- 0.097 (lines: 604) -ag (lines) (ASCII)* 0.667 +/- 0.067 (lines: 0)* -ucg (lines) (ASCII) 1.795 +/- 0.100 (lines: 583) - -subtitles_ru_literal_word (pattern: Шерлок Холмс) -------------------------------------------------- -rg (ASCII)* 0.320 +/- 0.013 (lines: 0)* -ag (ASCII) 0.793 +/- 0.006 (lines: 0) -ucg (ASCII) 1.788 +/- 0.103 (lines: 583) -grep (ASCII) 1.283 +/- 0.108 (lines: 583) -rg 0.740 +/- 0.088 (lines: 579) -grep 1.306 +/- 0.033 (lines: 579) - -subtitles_ru_no_literal (pattern: \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}) ----------------------------------------------------------------------------------------- -rg 3.720 +/- 0.117 (lines: 41) -rg (ASCII) 2.994 +/- 0.093 (lines: 0) -ag (ASCII)* 1.992 +/- 0.130 (lines: 0)* -ucg (ASCII) 2.520 +/- 0.020 (lines: 0) -grep (ASCII) 2.087 +/- 0.033 (lines: 0) - -subtitles_ru_surrounding_words (pattern: \w+\s+Холмс\s+\w+) ------------------------------------------------------------ -rg* 0.837 +/- 0.039 (lines: 278)* -grep 1.556 +/- 0.103 (lines: 278) -ag (ASCII) 1.993 +/- 0.057 (lines: 0) -ucg (ASCII) 2.548 +/- 0.065 (lines: 0) -grep (ASCII) 1.538 +/- 0.091 (lines: 0) diff --git a/benchsuite/runs/2016-12-24-archlinux-cheetah-glibc-jemalloc/raw.csv b/benchsuite/runs/2016-12-24-archlinux-cheetah-glibc-jemalloc/raw.csv deleted file mode 100644 index 36d8e44..0000000 --- a/benchsuite/runs/2016-12-24-archlinux-cheetah-glibc-jemalloc/raw.csv +++ /dev/null @@ -1,157 +0,0 @@ -benchmark,warmup_iter,iter,name,command,duration,lines,env -linux_alternates,1,3,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.09452986717224121,68, -linux_alternates,1,3,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.08666801452636719,68, -linux_alternates,1,3,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.08859610557556152,68, -linux_alternates,1,3,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.07011771202087402,68, -linux_alternates,1,3,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.06441712379455566,68, -linux_alternates,1,3,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.06532430648803711,68, -linux_alternates_casei,1,3,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.10056233406066895,160, -linux_alternates_casei,1,3,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.09930968284606934,160, -linux_alternates_casei,1,3,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.09773039817810059,160, -linux_alternates_casei,1,3,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.07829093933105469,160, -linux_alternates_casei,1,3,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.0827643871307373,160, -linux_alternates_casei,1,3,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.08210110664367676,160, -linux_literal,1,3,rg (ignore),rg -n PM_RESUME,0.06728911399841309,16, -linux_literal,1,3,rg (ignore),rg -n PM_RESUME,0.06839728355407715,16, -linux_literal,1,3,rg (ignore),rg -n PM_RESUME,0.0736091136932373,16, -linux_literal,1,3,rg (ignore) (mmap),rg -n --mmap PM_RESUME,0.3859975337982178,16, -linux_literal,1,3,rg (ignore) (mmap),rg -n --mmap PM_RESUME,0.38575077056884766,16, -linux_literal,1,3,rg (ignore) (mmap),rg -n --mmap PM_RESUME,0.4032607078552246,16, -linux_literal,1,3,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.0657193660736084,16, -linux_literal,1,3,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.058367013931274414,16, -linux_literal,1,3,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.05761837959289551,16, -linux_literal_casei,1,3,rg (ignore),rg -n -i PM_RESUME,0.07888174057006836,370, -linux_literal_casei,1,3,rg (ignore),rg -n -i PM_RESUME,0.08236145973205566,370, -linux_literal_casei,1,3,rg (ignore),rg -n -i PM_RESUME,0.07680559158325195,370, -linux_literal_casei,1,3,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,0.3796377182006836,370, -linux_literal_casei,1,3,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,0.3852665424346924,370, -linux_literal_casei,1,3,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,0.387775182723999,370, -linux_literal_casei,1,3,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.06758904457092285,370, -linux_literal_casei,1,3,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.06706357002258301,370, -linux_literal_casei,1,3,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.07329010963439941,370, -linux_literal_default,1,3,rg,rg PM_RESUME,0.06952190399169922,16, -linux_literal_default,1,3,rg,rg PM_RESUME,0.06766009330749512,16, -linux_literal_default,1,3,rg,rg PM_RESUME,0.06621623039245605,16, -linux_no_literal,1,3,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.29076576232910156,490, -linux_no_literal,1,3,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.3039717674255371,490, -linux_no_literal,1,3,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.3147861957550049,490, -linux_no_literal,1,3,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.16966867446899414,490, -linux_no_literal,1,3,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.16578006744384766,490, -linux_no_literal,1,3,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.16440153121948242,490, -linux_no_literal,1,3,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.2742593288421631,419, -linux_no_literal,1,3,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.27411365509033203,419, -linux_no_literal,1,3,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.2799038887023926,419, -linux_no_literal,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.15713810920715332,419, -linux_no_literal,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.15285205841064453,419, -linux_no_literal,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.14862322807312012,419, -linux_re_literal_suffix,1,3,rg (ignore),rg -n [A-Z]+_RESUME,0.06728196144104004,1652, -linux_re_literal_suffix,1,3,rg (ignore),rg -n [A-Z]+_RESUME,0.06869316101074219,1652, -linux_re_literal_suffix,1,3,rg (ignore),rg -n [A-Z]+_RESUME,0.07347917556762695,1652, -linux_re_literal_suffix,1,3,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.05894923210144043,1630, -linux_re_literal_suffix,1,3,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.0584101676940918,1630, -linux_re_literal_suffix,1,3,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.05851030349731445,1630, -linux_unicode_greek,1,3,rg,rg -n \p{Greek},0.16553878784179688,23, -linux_unicode_greek,1,3,rg,rg -n \p{Greek},0.16529393196105957,23, -linux_unicode_greek,1,3,rg,rg -n \p{Greek},0.16843223571777344,23, -linux_unicode_greek_casei,1,3,rg,rg -n -i \p{Greek},0.16363120079040527,103, -linux_unicode_greek_casei,1,3,rg,rg -n -i \p{Greek},0.16463160514831543,103, -linux_unicode_greek_casei,1,3,rg,rg -n -i \p{Greek},0.16590571403503418,103, -linux_unicode_word,1,3,rg (ignore),rg -n \wAh,0.07585549354553223,186, -linux_unicode_word,1,3,rg (ignore),rg -n \wAh,0.07546257972717285,186, -linux_unicode_word,1,3,rg (ignore),rg -n \wAh,0.07645726203918457,186, -linux_unicode_word,1,3,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.0733344554901123,174, -linux_unicode_word,1,3,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.07160758972167969,174, -linux_unicode_word,1,3,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.07302546501159668,174, -linux_unicode_word,1,3,rg (whitelist),rg -n --no-ignore -tall \wAh,0.06922054290771484,180, -linux_unicode_word,1,3,rg (whitelist),rg -n --no-ignore -tall \wAh,0.06507658958435059,180, -linux_unicode_word,1,3,rg (whitelist),rg -n --no-ignore -tall \wAh,0.06478118896484375,180, -linux_unicode_word,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.06373715400695801,168, -linux_unicode_word,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.06354117393493652,168, -linux_unicode_word,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.06615662574768066,168, -linux_word,1,3,rg (ignore),rg -n -w PM_RESUME,0.07121825218200684,6, -linux_word,1,3,rg (ignore),rg -n -w PM_RESUME,0.07050347328186035,6, -linux_word,1,3,rg (ignore),rg -n -w PM_RESUME,0.07254600524902344,6, -linux_word,1,3,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.06099557876586914,6, -linux_word,1,3,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.061118364334106445,6, -linux_word,1,3,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.062296390533447266,6, -subtitles_en_alternate,1,3,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2724471092224121,848, -subtitles_en_alternate,1,3,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.26970720291137695,848, -subtitles_en_alternate,1,3,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2697625160217285,848, -subtitles_en_alternate,1,3,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.21796512603759766,848, -subtitles_en_alternate,1,3,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.32093358039855957,848, -subtitles_en_alternate,1,3,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.35228729248046875,848, -subtitles_en_alternate_casei,1,3,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.2418622970581055,862, -subtitles_en_alternate_casei,1,3,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.2306008338928223,862, -subtitles_en_alternate_casei,1,3,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.1873059272766113,862, -subtitles_en_literal,1,3,rg,rg Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.22467422485351562,629, -subtitles_en_literal,1,3,rg,rg Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.23565077781677246,629, -subtitles_en_literal,1,3,rg,rg Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.21903586387634277,629, -subtitles_en_literal,1,3,rg (no mmap),rg --no-mmap Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.19292092323303223,629, -subtitles_en_literal,1,3,rg (no mmap),rg --no-mmap Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.19452929496765137,629, -subtitles_en_literal,1,3,rg (no mmap),rg --no-mmap Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.1927196979522705,629, -subtitles_en_literal,1,3,rg (lines),rg -n Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.28882503509521484,629, -subtitles_en_literal,1,3,rg (lines),rg -n Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.29108643531799316,629, -subtitles_en_literal,1,3,rg (lines),rg -n Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.29820847511291504,629, -subtitles_en_literal_casei,1,3,rg,rg -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.32578349113464355,642, -subtitles_en_literal_casei,1,3,rg,rg -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2801830768585205,642, -subtitles_en_literal_casei,1,3,rg,rg -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.41840386390686035,642, -subtitles_en_literal_casei,1,3,rg (lines),rg -n -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.42424988746643066,642, -subtitles_en_literal_casei,1,3,rg (lines),rg -n -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.3513953685760498,642, -subtitles_en_literal_casei,1,3,rg (lines),rg -n -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.35476160049438477,642, -subtitles_en_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2841978073120117,629, -subtitles_en_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.18991756439208984,629, -subtitles_en_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.296999454498291,629, -subtitles_en_literal_word,1,3,rg,rg -nw Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2810351848602295,629, -subtitles_en_literal_word,1,3,rg,rg -nw Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.27904558181762695,629, -subtitles_en_literal_word,1,3,rg,rg -nw Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.28331899642944336,629, -subtitles_en_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.065884590148926,13, -subtitles_en_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.9066839218139648,13, -subtitles_en_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.8898587226867676,13, -subtitles_en_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.8937196731567383,13, -subtitles_en_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.8904955387115479,13, -subtitles_en_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.8846819400787354,13, -subtitles_en_surrounding_words,1,3,rg,rg -n \w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2928280830383301,317, -subtitles_en_surrounding_words,1,3,rg,rg -n \w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2243812084197998,317, -subtitles_en_surrounding_words,1,3,rg,rg -n \w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2868325710296631,317, -subtitles_en_surrounding_words,1,3,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2832787036895752,317, -subtitles_en_surrounding_words,1,3,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2892146110534668,317, -subtitles_en_surrounding_words,1,3,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.22050261497497559,317, -subtitles_ru_alternate,1,3,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.1501314640045166,691, -subtitles_ru_alternate,1,3,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.3660097122192383,691, -subtitles_ru_alternate,1,3,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.3461437225341797,691, -subtitles_ru_alternate,1,3,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.281209945678711,691, -subtitles_ru_alternate,1,3,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.287156343460083,691, -subtitles_ru_alternate,1,3,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.2730507850646973,691, -subtitles_ru_alternate_casei,1,3,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.712820529937744,735, -subtitles_ru_alternate_casei,1,3,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.7904467582702637,735, -subtitles_ru_alternate_casei,1,3,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.657541036605835,735, -subtitles_ru_literal,1,3,rg,rg Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.28091931343078613,583, -subtitles_ru_literal,1,3,rg,rg Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.2749307155609131,583, -subtitles_ru_literal,1,3,rg,rg Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.27948546409606934,583, -subtitles_ru_literal,1,3,rg (no mmap),rg --no-mmap Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3499312400817871,583, -subtitles_ru_literal,1,3,rg (no mmap),rg --no-mmap Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3630790710449219,583, -subtitles_ru_literal,1,3,rg (no mmap),rg --no-mmap Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.35364317893981934,583, -subtitles_ru_literal,1,3,rg (lines),rg -n Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.36719226837158203,583, -subtitles_ru_literal,1,3,rg (lines),rg -n Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3705906867980957,583, -subtitles_ru_literal,1,3,rg (lines),rg -n Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3758120536804199,583, -subtitles_ru_literal_casei,1,3,rg,rg -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.1964221000671387,604, -subtitles_ru_literal_casei,1,3,rg,rg -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.1625583171844482,604, -subtitles_ru_literal_casei,1,3,rg,rg -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.1898295879364014,604, -subtitles_ru_literal_casei,1,3,rg (lines),rg -n -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.168842077255249,604, -subtitles_ru_literal_casei,1,3,rg (lines),rg -n -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.2533905506134033,604, -subtitles_ru_literal_casei,1,3,rg (lines),rg -n -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.2375917434692383,604, -subtitles_ru_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.27202439308166504,, -subtitles_ru_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.26978445053100586,, -subtitles_ru_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.21065115928649902,, -subtitles_ru_literal_word,1,3,rg,rg -nw Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.36217236518859863,579, -subtitles_ru_literal_word,1,3,rg,rg -nw Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.36077117919921875,579, -subtitles_ru_literal_word,1,3,rg,rg -nw Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.2883784770965576,579, -subtitles_ru_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.496169090270996,41, -subtitles_ru_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.315001964569092,41, -subtitles_ru_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.3024141788482666,41, -subtitles_ru_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.0939135551452637,, -subtitles_ru_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.8922672271728516,, -subtitles_ru_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.1002702713012695,, -subtitles_ru_surrounding_words,1,3,rg,rg -n \w+\s+Холмс\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3976116180419922,278, -subtitles_ru_surrounding_words,1,3,rg,rg -n \w+\s+Холмс\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.4013686180114746,278, -subtitles_ru_surrounding_words,1,3,rg,rg -n \w+\s+Холмс\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3070716857910156,278, diff --git a/benchsuite/runs/2016-12-24-archlinux-cheetah-glibc-jemalloc/summary b/benchsuite/runs/2016-12-24-archlinux-cheetah-glibc-jemalloc/summary deleted file mode 100644 index d7fa50e..0000000 --- a/benchsuite/runs/2016-12-24-archlinux-cheetah-glibc-jemalloc/summary +++ /dev/null @@ -1,126 +0,0 @@ -linux_alternates (pattern: ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT) -------------------------------------------------------------------------- -rg (ignore) 0.090 +/- 0.004 (lines: 68) -rg (whitelist)* 0.067 +/- 0.003 (lines: 68)* - -linux_alternates_casei (pattern: ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT) -------------------------------------------------------------------------------- -rg (ignore) 0.099 +/- 0.001 (lines: 160) -rg (whitelist)* 0.081 +/- 0.002 (lines: 160)* - -linux_literal (pattern: PM_RESUME) ----------------------------------- -rg (ignore) 0.070 +/- 0.003 (lines: 16) -rg (ignore) (mmap) 0.392 +/- 0.010 (lines: 16) -rg (whitelist)* 0.061 +/- 0.004 (lines: 16)* - -linux_literal_casei (pattern: PM_RESUME) ----------------------------------------- -rg (ignore) 0.079 +/- 0.003 (lines: 370) -rg (ignore) (mmap) 0.384 +/- 0.004 (lines: 370) -rg (whitelist)* 0.069 +/- 0.003 (lines: 370)* - -linux_literal_default (pattern: PM_RESUME) ------------------------------------------- -rg* 0.068 +/- 0.002 (lines: 16)* - -linux_no_literal (pattern: \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}) ------------------------------------------------------------------ -rg (ignore) 0.303 +/- 0.012 (lines: 490) -rg (ignore) (ASCII) 0.167 +/- 0.003 (lines: 490) -rg (whitelist) 0.276 +/- 0.003 (lines: 419) -rg (whitelist) (ASCII)* 0.153 +/- 0.004 (lines: 419)* - -linux_re_literal_suffix (pattern: [A-Z]+_RESUME) ------------------------------------------------- -rg (ignore) 0.070 +/- 0.003 (lines: 1652) -rg (whitelist)* 0.059 +/- 0.000 (lines: 1630)* - -linux_unicode_greek (pattern: \p{Greek}) ----------------------------------------- -rg* 0.166 +/- 0.002 (lines: 23)* - -linux_unicode_greek_casei (pattern: \p{Greek}) ----------------------------------------------- -rg* 0.165 +/- 0.001 (lines: 103)* - -linux_unicode_word (pattern: \wAh) ----------------------------------- -rg (ignore) 0.076 +/- 0.001 (lines: 186) -rg (ignore) (ASCII) 0.073 +/- 0.001 (lines: 174) -rg (whitelist) 0.066 +/- 0.002 (lines: 180) -rg (whitelist) (ASCII)* 0.064 +/- 0.001 (lines: 168)* - -linux_word (pattern: PM_RESUME) -------------------------------- -rg (ignore) 0.071 +/- 0.001 (lines: 6) -rg (whitelist)* 0.061 +/- 0.001 (lines: 6)* - -subtitles_en_alternate (pattern: Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty) ---------------------------------------------------------------------------------------------------------------- -rg (lines) 0.271 +/- 0.002 (lines: 848)* -rg* 0.297 +/- 0.070 (lines: 848) - -subtitles_en_alternate_casei (pattern: Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty) ---------------------------------------------------------------------------------------------------------------------- -rg* 2.220 +/- 0.029 (lines: 862)* - -subtitles_en_literal (pattern: Sherlock Holmes) ------------------------------------------------ -rg 0.226 +/- 0.008 (lines: 629) -rg (no mmap)* 0.193 +/- 0.001 (lines: 629)* -rg (lines) 0.293 +/- 0.005 (lines: 629) - -subtitles_en_literal_casei (pattern: Sherlock Holmes) ------------------------------------------------------ -rg* 0.341 +/- 0.070 (lines: 642)* -rg (lines) 0.377 +/- 0.041 (lines: 642) - -subtitles_en_literal_word (pattern: Sherlock Holmes) ----------------------------------------------------- -rg (ASCII)* 0.257 +/- 0.058 (lines: 629)* -rg 0.281 +/- 0.002 (lines: 629) - -subtitles_en_no_literal (pattern: \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}) ----------------------------------------------------------------------------------------- -rg 1.954 +/- 0.097 (lines: 13) -rg (ASCII)* 1.890 +/- 0.005 (lines: 13)* - -subtitles_en_surrounding_words (pattern: \w+\s+Holmes\s+\w+) ------------------------------------------------------------- -rg 0.268 +/- 0.038 (lines: 317) -rg (ASCII)* 0.264 +/- 0.038 (lines: 317)* - -subtitles_ru_alternate (pattern: Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти) ------------------------------------------------------------------------------------------------------------ -rg (lines)* 1.287 +/- 0.119 (lines: 691) -rg 1.280 +/- 0.007 (lines: 691)* - -subtitles_ru_alternate_casei (pattern: Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти) ------------------------------------------------------------------------------------------------------------------ -rg* 3.720 +/- 0.067 (lines: 735)* - -subtitles_ru_literal (pattern: Шерлок Холмс) --------------------------------------------- -rg* 0.278 +/- 0.003 (lines: 583)* -rg (no mmap) 0.356 +/- 0.007 (lines: 583) -rg (lines) 0.371 +/- 0.004 (lines: 583) - -subtitles_ru_literal_casei (pattern: Шерлок Холмс) --------------------------------------------------- -rg* 1.183 +/- 0.018 (lines: 604)* -rg (lines) 1.220 +/- 0.045 (lines: 604) - -subtitles_ru_literal_word (pattern: Шерлок Холмс) -------------------------------------------------- -rg (ASCII)* 0.251 +/- 0.035 (lines: 0)* -rg 0.337 +/- 0.042 (lines: 579) - -subtitles_ru_no_literal (pattern: \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}) ----------------------------------------------------------------------------------------- -rg 3.371 +/- 0.108 (lines: 41) -rg (ASCII)* 3.029 +/- 0.118 (lines: 0)* - -subtitles_ru_surrounding_words (pattern: \w+\s+Холмс\s+\w+) ------------------------------------------------------------ -rg* 0.369 +/- 0.053 (lines: 278)* diff --git a/benchsuite/runs/2016-12-24-archlinux-cheetah-glibc-system/raw.csv b/benchsuite/runs/2016-12-24-archlinux-cheetah-glibc-system/raw.csv deleted file mode 100644 index 9835e14..0000000 --- a/benchsuite/runs/2016-12-24-archlinux-cheetah-glibc-system/raw.csv +++ /dev/null @@ -1,157 +0,0 @@ -benchmark,warmup_iter,iter,name,command,duration,lines,env -linux_alternates,1,3,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.09608030319213867,68, -linux_alternates,1,3,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.08815908432006836,68, -linux_alternates,1,3,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.08974266052246094,68, -linux_alternates,1,3,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.06675052642822266,68, -linux_alternates,1,3,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.06632375717163086,68, -linux_alternates,1,3,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.06531620025634766,68, -linux_alternates_casei,1,3,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.09764790534973145,160, -linux_alternates_casei,1,3,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.10003781318664551,160, -linux_alternates_casei,1,3,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.10493707656860352,160, -linux_alternates_casei,1,3,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.07940077781677246,160, -linux_alternates_casei,1,3,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.07863998413085938,160, -linux_alternates_casei,1,3,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.07791614532470703,160, -linux_literal,1,3,rg (ignore),rg -n PM_RESUME,0.06878829002380371,16, -linux_literal,1,3,rg (ignore),rg -n PM_RESUME,0.06836318969726562,16, -linux_literal,1,3,rg (ignore),rg -n PM_RESUME,0.07277226448059082,16, -linux_literal,1,3,rg (ignore) (mmap),rg -n --mmap PM_RESUME,0.379986047744751,16, -linux_literal,1,3,rg (ignore) (mmap),rg -n --mmap PM_RESUME,0.40039825439453125,16, -linux_literal,1,3,rg (ignore) (mmap),rg -n --mmap PM_RESUME,0.39777183532714844,16, -linux_literal,1,3,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.059081315994262695,16, -linux_literal,1,3,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.05873990058898926,16, -linux_literal,1,3,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.0586698055267334,16, -linux_literal_casei,1,3,rg (ignore),rg -n -i PM_RESUME,0.07791399955749512,370, -linux_literal_casei,1,3,rg (ignore),rg -n -i PM_RESUME,0.0774388313293457,370, -linux_literal_casei,1,3,rg (ignore),rg -n -i PM_RESUME,0.07851481437683105,370, -linux_literal_casei,1,3,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,0.3788566589355469,370, -linux_literal_casei,1,3,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,0.385251522064209,370, -linux_literal_casei,1,3,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,0.38781046867370605,370, -linux_literal_casei,1,3,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.06934094429016113,370, -linux_literal_casei,1,3,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.07142090797424316,370, -linux_literal_casei,1,3,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.07115054130554199,370, -linux_literal_default,1,3,rg,rg PM_RESUME,0.06683826446533203,16, -linux_literal_default,1,3,rg,rg PM_RESUME,0.0690450668334961,16, -linux_literal_default,1,3,rg,rg PM_RESUME,0.06625819206237793,16, -linux_no_literal,1,3,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.2812047004699707,490, -linux_no_literal,1,3,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.2557988166809082,490, -linux_no_literal,1,3,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.2892444133758545,490, -linux_no_literal,1,3,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.16913127899169922,490, -linux_no_literal,1,3,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.16315627098083496,490, -linux_no_literal,1,3,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.16622567176818848,490, -linux_no_literal,1,3,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.2771792411804199,419, -linux_no_literal,1,3,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.2861213684082031,419, -linux_no_literal,1,3,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.2742443084716797,419, -linux_no_literal,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.15151619911193848,419, -linux_no_literal,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.15233445167541504,419, -linux_no_literal,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.1620476245880127,419, -linux_re_literal_suffix,1,3,rg (ignore),rg -n [A-Z]+_RESUME,0.07045555114746094,1652, -linux_re_literal_suffix,1,3,rg (ignore),rg -n [A-Z]+_RESUME,0.07046008110046387,1652, -linux_re_literal_suffix,1,3,rg (ignore),rg -n [A-Z]+_RESUME,0.07087540626525879,1652, -linux_re_literal_suffix,1,3,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.06178712844848633,1630, -linux_re_literal_suffix,1,3,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.0631401538848877,1630, -linux_re_literal_suffix,1,3,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.0627889633178711,1630, -linux_unicode_greek,1,3,rg,rg -n \p{Greek},0.16510963439941406,23, -linux_unicode_greek,1,3,rg,rg -n \p{Greek},0.16919803619384766,23, -linux_unicode_greek,1,3,rg,rg -n \p{Greek},0.16366028785705566,23, -linux_unicode_greek_casei,1,3,rg,rg -n -i \p{Greek},0.17235875129699707,103, -linux_unicode_greek_casei,1,3,rg,rg -n -i \p{Greek},0.16506695747375488,103, -linux_unicode_greek_casei,1,3,rg,rg -n -i \p{Greek},0.16702055931091309,103, -linux_unicode_word,1,3,rg (ignore),rg -n \wAh,0.07636308670043945,186, -linux_unicode_word,1,3,rg (ignore),rg -n \wAh,0.0767667293548584,186, -linux_unicode_word,1,3,rg (ignore),rg -n \wAh,0.07441020011901855,186, -linux_unicode_word,1,3,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.07776570320129395,174, -linux_unicode_word,1,3,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.07788562774658203,174, -linux_unicode_word,1,3,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.07390785217285156,174, -linux_unicode_word,1,3,rg (whitelist),rg -n --no-ignore -tall \wAh,0.06318306922912598,180, -linux_unicode_word,1,3,rg (whitelist),rg -n --no-ignore -tall \wAh,0.06787896156311035,180, -linux_unicode_word,1,3,rg (whitelist),rg -n --no-ignore -tall \wAh,0.06569766998291016,180, -linux_unicode_word,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.06557774543762207,168, -linux_unicode_word,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.06389331817626953,168, -linux_unicode_word,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.06407284736633301,168, -linux_word,1,3,rg (ignore),rg -n -w PM_RESUME,0.06868839263916016,6, -linux_word,1,3,rg (ignore),rg -n -w PM_RESUME,0.07014894485473633,6, -linux_word,1,3,rg (ignore),rg -n -w PM_RESUME,0.06822323799133301,6, -linux_word,1,3,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.05816149711608887,6, -linux_word,1,3,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.0577540397644043,6, -linux_word,1,3,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.06107187271118164,6, -subtitles_en_alternate,1,3,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.38473939895629883,848, -subtitles_en_alternate,1,3,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2760040760040283,848, -subtitles_en_alternate,1,3,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.366499662399292,848, -subtitles_en_alternate,1,3,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.32836484909057617,848, -subtitles_en_alternate,1,3,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.3063969612121582,848, -subtitles_en_alternate,1,3,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.3368823528289795,848, -subtitles_en_alternate_casei,1,3,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.2332417964935303,862, -subtitles_en_alternate_casei,1,3,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.0444729328155518,862, -subtitles_en_alternate_casei,1,3,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.0396711826324463,862, -subtitles_en_literal,1,3,rg,rg Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.13685226440429688,629, -subtitles_en_literal,1,3,rg,rg Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.1380929946899414,629, -subtitles_en_literal,1,3,rg,rg Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.13843274116516113,629, -subtitles_en_literal,1,3,rg (no mmap),rg --no-mmap Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.192030668258667,629, -subtitles_en_literal,1,3,rg (no mmap),rg --no-mmap Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.1971268653869629,629, -subtitles_en_literal,1,3,rg (no mmap),rg --no-mmap Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2931783199310303,629, -subtitles_en_literal,1,3,rg (lines),rg -n Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2777669429779053,629, -subtitles_en_literal,1,3,rg (lines),rg -n Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.28525233268737793,629, -subtitles_en_literal,1,3,rg (lines),rg -n Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.22691082954406738,629, -subtitles_en_literal_casei,1,3,rg,rg -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.31324243545532227,642, -subtitles_en_literal_casei,1,3,rg,rg -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.4144246578216553,642, -subtitles_en_literal_casei,1,3,rg,rg -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.41251444816589355,642, -subtitles_en_literal_casei,1,3,rg (lines),rg -n -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.492443323135376,642, -subtitles_en_literal_casei,1,3,rg (lines),rg -n -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.4691810607910156,642, -subtitles_en_literal_casei,1,3,rg (lines),rg -n -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.4890565872192383,642, -subtitles_en_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2987544536590576,629, -subtitles_en_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.28134918212890625,629, -subtitles_en_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.29971933364868164,629, -subtitles_en_literal_word,1,3,rg,rg -nw Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.22062921524047852,629, -subtitles_en_literal_word,1,3,rg,rg -nw Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2716941833496094,629, -subtitles_en_literal_word,1,3,rg,rg -nw Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2172706127166748,629, -subtitles_en_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.0828537940979004,13, -subtitles_en_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.8791723251342773,13, -subtitles_en_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.079643964767456,13, -subtitles_en_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.8388440608978271,13, -subtitles_en_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.8970744609832764,13, -subtitles_en_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.6844482421875,13, -subtitles_en_surrounding_words,1,3,rg,rg -n \w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.28177690505981445,317, -subtitles_en_surrounding_words,1,3,rg,rg -n \w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.29820775985717773,317, -subtitles_en_surrounding_words,1,3,rg,rg -n \w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2861142158508301,317, -subtitles_en_surrounding_words,1,3,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.22010159492492676,317, -subtitles_en_surrounding_words,1,3,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.22217011451721191,317, -subtitles_en_surrounding_words,1,3,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2219986915588379,317, -subtitles_ru_alternate,1,3,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.146566390991211,691, -subtitles_ru_alternate,1,3,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.3609087467193604,691, -subtitles_ru_alternate,1,3,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.1496453285217285,691, -subtitles_ru_alternate,1,3,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.281858205795288,691, -subtitles_ru_alternate,1,3,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.365553855895996,691, -subtitles_ru_alternate,1,3,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.2781758308410645,691, -subtitles_ru_alternate_casei,1,3,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.622640609741211,735, -subtitles_ru_alternate_casei,1,3,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.7452948093414307,735, -subtitles_ru_alternate_casei,1,3,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.762295961380005,735, -subtitles_ru_literal,1,3,rg,rg Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.27922916412353516,583, -subtitles_ru_literal,1,3,rg,rg Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.2578129768371582,583, -subtitles_ru_literal,1,3,rg,rg Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.21048188209533691,583, -subtitles_ru_literal,1,3,rg (no mmap),rg --no-mmap Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.34738945960998535,583, -subtitles_ru_literal,1,3,rg (no mmap),rg --no-mmap Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.368546724319458,583, -subtitles_ru_literal,1,3,rg (no mmap),rg --no-mmap Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.35752224922180176,583, -subtitles_ru_literal,1,3,rg (lines),rg -n Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.2654876708984375,583, -subtitles_ru_literal,1,3,rg (lines),rg -n Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.2697427272796631,583, -subtitles_ru_literal,1,3,rg (lines),rg -n Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3652024269104004,583, -subtitles_ru_literal_casei,1,3,rg,rg -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.178579330444336,604, -subtitles_ru_literal_casei,1,3,rg,rg -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.1693329811096191,604, -subtitles_ru_literal_casei,1,3,rg,rg -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.144824504852295,604, -subtitles_ru_literal_casei,1,3,rg (lines),rg -n -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.0454356670379639,604, -subtitles_ru_literal_casei,1,3,rg (lines),rg -n -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.0725409984588623,604, -subtitles_ru_literal_casei,1,3,rg (lines),rg -n -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.2725732326507568,604, -subtitles_ru_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.20514369010925293,, -subtitles_ru_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.18602967262268066,, -subtitles_ru_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.2725963592529297,, -subtitles_ru_literal_word,1,3,rg,rg -nw Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.35959553718566895,579, -subtitles_ru_literal_word,1,3,rg,rg -nw Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.36090755462646484,579, -subtitles_ru_literal_word,1,3,rg,rg -nw Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.35926032066345215,579, -subtitles_ru_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.509491205215454,41, -subtitles_ru_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.292212963104248,41, -subtitles_ru_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.4941117763519287,41, -subtitles_ru_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.0987064838409424,, -subtitles_ru_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.1049976348876953,, -subtitles_ru_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.098233222961426,, -subtitles_ru_surrounding_words,1,3,rg,rg -n \w+\s+Холмс\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3214902877807617,278, -subtitles_ru_surrounding_words,1,3,rg,rg -n \w+\s+Холмс\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.38519954681396484,278, -subtitles_ru_surrounding_words,1,3,rg,rg -n \w+\s+Холмс\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3827836513519287,278, diff --git a/benchsuite/runs/2016-12-24-archlinux-cheetah-glibc-system/summary b/benchsuite/runs/2016-12-24-archlinux-cheetah-glibc-system/summary deleted file mode 100644 index 788c367..0000000 --- a/benchsuite/runs/2016-12-24-archlinux-cheetah-glibc-system/summary +++ /dev/null @@ -1,126 +0,0 @@ -linux_alternates (pattern: ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT) -------------------------------------------------------------------------- -rg (ignore) 0.091 +/- 0.004 (lines: 68) -rg (whitelist)* 0.066 +/- 0.001 (lines: 68)* - -linux_alternates_casei (pattern: ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT) -------------------------------------------------------------------------------- -rg (ignore) 0.101 +/- 0.004 (lines: 160) -rg (whitelist)* 0.079 +/- 0.001 (lines: 160)* - -linux_literal (pattern: PM_RESUME) ----------------------------------- -rg (ignore) 0.070 +/- 0.002 (lines: 16) -rg (ignore) (mmap) 0.393 +/- 0.011 (lines: 16) -rg (whitelist)* 0.059 +/- 0.000 (lines: 16)* - -linux_literal_casei (pattern: PM_RESUME) ----------------------------------------- -rg (ignore) 0.078 +/- 0.001 (lines: 370) -rg (ignore) (mmap) 0.384 +/- 0.005 (lines: 370) -rg (whitelist)* 0.071 +/- 0.001 (lines: 370)* - -linux_literal_default (pattern: PM_RESUME) ------------------------------------------- -rg* 0.067 +/- 0.001 (lines: 16)* - -linux_no_literal (pattern: \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}) ------------------------------------------------------------------ -rg (ignore) 0.275 +/- 0.017 (lines: 490) -rg (ignore) (ASCII) 0.166 +/- 0.003 (lines: 490) -rg (whitelist) 0.279 +/- 0.006 (lines: 419) -rg (whitelist) (ASCII)* 0.155 +/- 0.006 (lines: 419)* - -linux_re_literal_suffix (pattern: [A-Z]+_RESUME) ------------------------------------------------- -rg (ignore) 0.071 +/- 0.000 (lines: 1652) -rg (whitelist)* 0.063 +/- 0.001 (lines: 1630)* - -linux_unicode_greek (pattern: \p{Greek}) ----------------------------------------- -rg* 0.166 +/- 0.003 (lines: 23)* - -linux_unicode_greek_casei (pattern: \p{Greek}) ----------------------------------------------- -rg* 0.168 +/- 0.004 (lines: 103)* - -linux_unicode_word (pattern: \wAh) ----------------------------------- -rg (ignore) 0.076 +/- 0.001 (lines: 186) -rg (ignore) (ASCII) 0.077 +/- 0.002 (lines: 174) -rg (whitelist)* 0.066 +/- 0.002 (lines: 180) -rg (whitelist) (ASCII) 0.065 +/- 0.001 (lines: 168)* - -linux_word (pattern: PM_RESUME) -------------------------------- -rg (ignore) 0.069 +/- 0.001 (lines: 6) -rg (whitelist)* 0.059 +/- 0.002 (lines: 6)* - -subtitles_en_alternate (pattern: Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty) ---------------------------------------------------------------------------------------------------------------- -rg (lines)* 0.342 +/- 0.058 (lines: 848) -rg 0.324 +/- 0.016 (lines: 848)* - -subtitles_en_alternate_casei (pattern: Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty) ---------------------------------------------------------------------------------------------------------------------- -rg* 2.106 +/- 0.110 (lines: 862)* - -subtitles_en_literal (pattern: Sherlock Holmes) ------------------------------------------------ -rg* 0.138 +/- 0.001 (lines: 629)* -rg (no mmap) 0.227 +/- 0.057 (lines: 629) -rg (lines) 0.263 +/- 0.032 (lines: 629) - -subtitles_en_literal_casei (pattern: Sherlock Holmes) ------------------------------------------------------ -rg* 0.380 +/- 0.058 (lines: 642)* -rg (lines) 0.484 +/- 0.013 (lines: 642) - -subtitles_en_literal_word (pattern: Sherlock Holmes) ----------------------------------------------------- -rg (ASCII) 0.293 +/- 0.010 (lines: 629) -rg* 0.237 +/- 0.030 (lines: 629)* - -subtitles_en_no_literal (pattern: \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}) ----------------------------------------------------------------------------------------- -rg 2.014 +/- 0.117 (lines: 13) -rg (ASCII)* 1.807 +/- 0.110 (lines: 13)* - -subtitles_en_surrounding_words (pattern: \w+\s+Holmes\s+\w+) ------------------------------------------------------------- -rg 0.289 +/- 0.009 (lines: 317) -rg (ASCII)* 0.221 +/- 0.001 (lines: 317)* - -subtitles_ru_alternate (pattern: Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти) ------------------------------------------------------------------------------------------------------------ -rg (lines)* 1.219 +/- 0.123 (lines: 691)* -rg 1.309 +/- 0.049 (lines: 691) - -subtitles_ru_alternate_casei (pattern: Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти) ------------------------------------------------------------------------------------------------------------------ -rg* 3.710 +/- 0.076 (lines: 735)* - -subtitles_ru_literal (pattern: Шерлок Холмс) --------------------------------------------- -rg* 0.249 +/- 0.035 (lines: 583)* -rg (no mmap) 0.358 +/- 0.011 (lines: 583) -rg (lines) 0.300 +/- 0.056 (lines: 583) - -subtitles_ru_literal_casei (pattern: Шерлок Холмс) --------------------------------------------------- -rg 1.164 +/- 0.017 (lines: 604) -rg (lines)* 1.130 +/- 0.124 (lines: 604)* - -subtitles_ru_literal_word (pattern: Шерлок Холмс) -------------------------------------------------- -rg (ASCII)* 0.221 +/- 0.045 (lines: 0)* -rg 0.360 +/- 0.001 (lines: 579) - -subtitles_ru_no_literal (pattern: \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}) ----------------------------------------------------------------------------------------- -rg 3.432 +/- 0.121 (lines: 41) -rg (ASCII)* 3.101 +/- 0.004 (lines: 0)* - -subtitles_ru_surrounding_words (pattern: \w+\s+Холмс\s+\w+) ------------------------------------------------------------ -rg* 0.363 +/- 0.036 (lines: 278)* diff --git a/benchsuite/runs/2016-12-24-archlinux-cheetah-musl-jemalloc/raw.csv b/benchsuite/runs/2016-12-24-archlinux-cheetah-musl-jemalloc/raw.csv deleted file mode 100644 index 67a1e14..0000000 --- a/benchsuite/runs/2016-12-24-archlinux-cheetah-musl-jemalloc/raw.csv +++ /dev/null @@ -1,157 +0,0 @@ -benchmark,warmup_iter,iter,name,command,duration,lines,env -linux_alternates,1,3,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.10048675537109375,68, -linux_alternates,1,3,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.09462523460388184,68, -linux_alternates,1,3,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.0931856632232666,68, -linux_alternates,1,3,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.06952047348022461,68, -linux_alternates,1,3,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.07045698165893555,68, -linux_alternates,1,3,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.06589603424072266,68, -linux_alternates_casei,1,3,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.09840559959411621,160, -linux_alternates_casei,1,3,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.0973203182220459,160, -linux_alternates_casei,1,3,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.09747123718261719,160, -linux_alternates_casei,1,3,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.07976746559143066,160, -linux_alternates_casei,1,3,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.07973408699035645,160, -linux_alternates_casei,1,3,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.0842599868774414,160, -linux_literal,1,3,rg (ignore),rg -n PM_RESUME,0.06900453567504883,16, -linux_literal,1,3,rg (ignore),rg -n PM_RESUME,0.06771540641784668,16, -linux_literal,1,3,rg (ignore),rg -n PM_RESUME,0.07333683967590332,16, -linux_literal,1,3,rg (ignore) (mmap),rg -n --mmap PM_RESUME,0.38510584831237793,16, -linux_literal,1,3,rg (ignore) (mmap),rg -n --mmap PM_RESUME,0.38396191596984863,16, -linux_literal,1,3,rg (ignore) (mmap),rg -n --mmap PM_RESUME,0.37463903427124023,16, -linux_literal,1,3,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.05757570266723633,16, -linux_literal,1,3,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.058022260665893555,16, -linux_literal,1,3,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.06006050109863281,16, -linux_literal_casei,1,3,rg (ignore),rg -n -i PM_RESUME,0.07654142379760742,370, -linux_literal_casei,1,3,rg (ignore),rg -n -i PM_RESUME,0.07764244079589844,370, -linux_literal_casei,1,3,rg (ignore),rg -n -i PM_RESUME,0.07787275314331055,370, -linux_literal_casei,1,3,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,0.38339757919311523,370, -linux_literal_casei,1,3,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,0.38019704818725586,370, -linux_literal_casei,1,3,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,0.3887295722961426,370, -linux_literal_casei,1,3,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.06747794151306152,370, -linux_literal_casei,1,3,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.06868124008178711,370, -linux_literal_casei,1,3,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.06679105758666992,370, -linux_literal_default,1,3,rg,rg PM_RESUME,0.07849764823913574,16, -linux_literal_default,1,3,rg,rg PM_RESUME,0.08336472511291504,16, -linux_literal_default,1,3,rg,rg PM_RESUME,0.06723690032958984,16, -linux_no_literal,1,3,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.25814294815063477,490, -linux_no_literal,1,3,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.29274845123291016,490, -linux_no_literal,1,3,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.2985391616821289,490, -linux_no_literal,1,3,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.16458344459533691,490, -linux_no_literal,1,3,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.16898059844970703,490, -linux_no_literal,1,3,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.1756742000579834,490, -linux_no_literal,1,3,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.3002643585205078,419, -linux_no_literal,1,3,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.2709066867828369,419, -linux_no_literal,1,3,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.2683436870574951,419, -linux_no_literal,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.1489565372467041,419, -linux_no_literal,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.14751625061035156,419, -linux_no_literal,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.1487743854522705,419, -linux_re_literal_suffix,1,3,rg (ignore),rg -n [A-Z]+_RESUME,0.06930160522460938,1652, -linux_re_literal_suffix,1,3,rg (ignore),rg -n [A-Z]+_RESUME,0.07447147369384766,1652, -linux_re_literal_suffix,1,3,rg (ignore),rg -n [A-Z]+_RESUME,0.07432723045349121,1652, -linux_re_literal_suffix,1,3,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.06141376495361328,1630, -linux_re_literal_suffix,1,3,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.06345224380493164,1630, -linux_re_literal_suffix,1,3,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.05813455581665039,1630, -linux_unicode_greek,1,3,rg,rg -n \p{Greek},0.16566061973571777,23, -linux_unicode_greek,1,3,rg,rg -n \p{Greek},0.17109084129333496,23, -linux_unicode_greek,1,3,rg,rg -n \p{Greek},0.16268444061279297,23, -linux_unicode_greek_casei,1,3,rg,rg -n -i \p{Greek},0.16269755363464355,103, -linux_unicode_greek_casei,1,3,rg,rg -n -i \p{Greek},0.16636371612548828,103, -linux_unicode_greek_casei,1,3,rg,rg -n -i \p{Greek},0.16133809089660645,103, -linux_unicode_word,1,3,rg (ignore),rg -n \wAh,0.07663178443908691,186, -linux_unicode_word,1,3,rg (ignore),rg -n \wAh,0.07986211776733398,186, -linux_unicode_word,1,3,rg (ignore),rg -n \wAh,0.07756590843200684,186, -linux_unicode_word,1,3,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.07402157783508301,174, -linux_unicode_word,1,3,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.07861495018005371,174, -linux_unicode_word,1,3,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.07465910911560059,174, -linux_unicode_word,1,3,rg (whitelist),rg -n --no-ignore -tall \wAh,0.06782341003417969,180, -linux_unicode_word,1,3,rg (whitelist),rg -n --no-ignore -tall \wAh,0.06639862060546875,180, -linux_unicode_word,1,3,rg (whitelist),rg -n --no-ignore -tall \wAh,0.06768679618835449,180, -linux_unicode_word,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.06638240814208984,168, -linux_unicode_word,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.06481051445007324,168, -linux_unicode_word,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.06659054756164551,168, -linux_word,1,3,rg (ignore),rg -n -w PM_RESUME,0.06744074821472168,6, -linux_word,1,3,rg (ignore),rg -n -w PM_RESUME,0.06904149055480957,6, -linux_word,1,3,rg (ignore),rg -n -w PM_RESUME,0.07302141189575195,6, -linux_word,1,3,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.05972766876220703,6, -linux_word,1,3,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.0587460994720459,6, -linux_word,1,3,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.05879020690917969,6, -subtitles_en_alternate,1,3,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.3649451732635498,848, -subtitles_en_alternate,1,3,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.37390756607055664,848, -subtitles_en_alternate,1,3,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.3691575527191162,848, -subtitles_en_alternate,1,3,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.3192598819732666,848, -subtitles_en_alternate,1,3,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.3968648910522461,848, -subtitles_en_alternate,1,3,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.347275972366333,848, -subtitles_en_alternate_casei,1,3,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.11361026763916,862, -subtitles_en_alternate_casei,1,3,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.9423036575317383,862, -subtitles_en_alternate_casei,1,3,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.9265573024749756,862, -subtitles_en_literal,1,3,rg,rg Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.21686100959777832,629, -subtitles_en_literal,1,3,rg,rg Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.23349666595458984,629, -subtitles_en_literal,1,3,rg,rg Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2394559383392334,629, -subtitles_en_literal,1,3,rg (no mmap),rg --no-mmap Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2971608638763428,629, -subtitles_en_literal,1,3,rg (no mmap),rg --no-mmap Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2950170040130615,629, -subtitles_en_literal,1,3,rg (no mmap),rg --no-mmap Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2873063087463379,629, -subtitles_en_literal,1,3,rg (lines),rg -n Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2898998260498047,629, -subtitles_en_literal,1,3,rg (lines),rg -n Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.21834325790405273,629, -subtitles_en_literal,1,3,rg (lines),rg -n Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2833542823791504,629, -subtitles_en_literal_casei,1,3,rg,rg -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.3961493968963623,642, -subtitles_en_literal_casei,1,3,rg,rg -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.30686163902282715,642, -subtitles_en_literal_casei,1,3,rg,rg -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.44585490226745605,642, -subtitles_en_literal_casei,1,3,rg (lines),rg -n -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.46064209938049316,642, -subtitles_en_literal_casei,1,3,rg (lines),rg -n -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.4497091770172119,642, -subtitles_en_literal_casei,1,3,rg (lines),rg -n -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.34823131561279297,642, -subtitles_en_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2819490432739258,629, -subtitles_en_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.18886327743530273,629, -subtitles_en_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.28542351722717285,629, -subtitles_en_literal_word,1,3,rg,rg -nw Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.18991541862487793,629, -subtitles_en_literal_word,1,3,rg,rg -nw Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.27848052978515625,629, -subtitles_en_literal_word,1,3,rg,rg -nw Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.21271944046020508,629, -subtitles_en_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.0810630321502686,13, -subtitles_en_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.0093939304351807,13, -subtitles_en_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.8533532619476318,13, -subtitles_en_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.8952853679656982,13, -subtitles_en_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.7897896766662598,13, -subtitles_en_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.893296480178833,13, -subtitles_en_surrounding_words,1,3,rg,rg -n \w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.19786620140075684,317, -subtitles_en_surrounding_words,1,3,rg,rg -n \w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.1896834373474121,317, -subtitles_en_surrounding_words,1,3,rg,rg -n \w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.29248762130737305,317, -subtitles_en_surrounding_words,1,3,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2933495044708252,317, -subtitles_en_surrounding_words,1,3,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.29410600662231445,317, -subtitles_en_surrounding_words,1,3,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.23128199577331543,317, -subtitles_ru_alternate,1,3,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.343696117401123,691, -subtitles_ru_alternate,1,3,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.3544535636901855,691, -subtitles_ru_alternate,1,3,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.3534214496612549,691, -subtitles_ru_alternate,1,3,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.2638463973999023,691, -subtitles_ru_alternate,1,3,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.2450191974639893,691, -subtitles_ru_alternate,1,3,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.2779006958007812,691, -subtitles_ru_alternate_casei,1,3,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.7900640964508057,735, -subtitles_ru_alternate_casei,1,3,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.812807321548462,735, -subtitles_ru_alternate_casei,1,3,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.7412266731262207,735, -subtitles_ru_literal,1,3,rg,rg Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.2562215328216553,583, -subtitles_ru_literal,1,3,rg,rg Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.2781085968017578,583, -subtitles_ru_literal,1,3,rg,rg Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.21145415306091309,583, -subtitles_ru_literal,1,3,rg (no mmap),rg --no-mmap Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.36469101905822754,583, -subtitles_ru_literal,1,3,rg (no mmap),rg --no-mmap Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.37107086181640625,583, -subtitles_ru_literal,1,3,rg (no mmap),rg --no-mmap Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.29900336265563965,583, -subtitles_ru_literal,1,3,rg (lines),rg -n Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3739583492279053,583, -subtitles_ru_literal,1,3,rg (lines),rg -n Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3521237373352051,583, -subtitles_ru_literal,1,3,rg (lines),rg -n Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3766622543334961,583, -subtitles_ru_literal_casei,1,3,rg,rg -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.1903154850006104,604, -subtitles_ru_literal_casei,1,3,rg,rg -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.196908950805664,604, -subtitles_ru_literal_casei,1,3,rg,rg -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.1714701652526855,604, -subtitles_ru_literal_casei,1,3,rg (lines),rg -n -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.0471339225769043,604, -subtitles_ru_literal_casei,1,3,rg (lines),rg -n -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.2229478359222412,604, -subtitles_ru_literal_casei,1,3,rg (lines),rg -n -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.1774308681488037,604, -subtitles_ru_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.20592975616455078,, -subtitles_ru_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.2680799961090088,, -subtitles_ru_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.29538846015930176,, -subtitles_ru_literal_word,1,3,rg,rg -nw Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.36015796661376953,579, -subtitles_ru_literal_word,1,3,rg,rg -nw Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3006131649017334,579, -subtitles_ru_literal_word,1,3,rg,rg -nw Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.36701369285583496,579, -subtitles_ru_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.4495208263397217,41, -subtitles_ru_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.4749486446380615,41, -subtitles_ru_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.29917049407959,41, -subtitles_ru_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.0949668884277344,, -subtitles_ru_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.1213910579681396,, -subtitles_ru_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.905003070831299,, -subtitles_ru_surrounding_words,1,3,rg,rg -n \w+\s+Холмс\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.39461803436279297,278, -subtitles_ru_surrounding_words,1,3,rg,rg -n \w+\s+Холмс\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3211812973022461,278, -subtitles_ru_surrounding_words,1,3,rg,rg -n \w+\s+Холмс\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3848116397857666,278, diff --git a/benchsuite/runs/2016-12-24-archlinux-cheetah-musl-jemalloc/summary b/benchsuite/runs/2016-12-24-archlinux-cheetah-musl-jemalloc/summary deleted file mode 100644 index dda1521..0000000 --- a/benchsuite/runs/2016-12-24-archlinux-cheetah-musl-jemalloc/summary +++ /dev/null @@ -1,126 +0,0 @@ -linux_alternates (pattern: ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT) -------------------------------------------------------------------------- -rg (ignore) 0.096 +/- 0.004 (lines: 68) -rg (whitelist)* 0.069 +/- 0.002 (lines: 68)* - -linux_alternates_casei (pattern: ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT) -------------------------------------------------------------------------------- -rg (ignore) 0.098 +/- 0.001 (lines: 160) -rg (whitelist)* 0.081 +/- 0.003 (lines: 160)* - -linux_literal (pattern: PM_RESUME) ----------------------------------- -rg (ignore) 0.070 +/- 0.003 (lines: 16) -rg (ignore) (mmap) 0.381 +/- 0.006 (lines: 16) -rg (whitelist)* 0.059 +/- 0.001 (lines: 16)* - -linux_literal_casei (pattern: PM_RESUME) ----------------------------------------- -rg (ignore) 0.077 +/- 0.001 (lines: 370) -rg (ignore) (mmap) 0.384 +/- 0.004 (lines: 370) -rg (whitelist)* 0.068 +/- 0.001 (lines: 370)* - -linux_literal_default (pattern: PM_RESUME) ------------------------------------------- -rg* 0.076 +/- 0.008 (lines: 16)* - -linux_no_literal (pattern: \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}) ------------------------------------------------------------------ -rg (ignore) 0.283 +/- 0.022 (lines: 490) -rg (ignore) (ASCII) 0.170 +/- 0.006 (lines: 490) -rg (whitelist) 0.280 +/- 0.018 (lines: 419) -rg (whitelist) (ASCII)* 0.148 +/- 0.001 (lines: 419)* - -linux_re_literal_suffix (pattern: [A-Z]+_RESUME) ------------------------------------------------- -rg (ignore) 0.073 +/- 0.003 (lines: 1652) -rg (whitelist)* 0.061 +/- 0.003 (lines: 1630)* - -linux_unicode_greek (pattern: \p{Greek}) ----------------------------------------- -rg* 0.166 +/- 0.004 (lines: 23)* - -linux_unicode_greek_casei (pattern: \p{Greek}) ----------------------------------------------- -rg* 0.163 +/- 0.003 (lines: 103)* - -linux_unicode_word (pattern: \wAh) ----------------------------------- -rg (ignore) 0.078 +/- 0.002 (lines: 186) -rg (ignore) (ASCII) 0.076 +/- 0.002 (lines: 174) -rg (whitelist) 0.067 +/- 0.001 (lines: 180) -rg (whitelist) (ASCII)* 0.066 +/- 0.001 (lines: 168)* - -linux_word (pattern: PM_RESUME) -------------------------------- -rg (ignore) 0.070 +/- 0.003 (lines: 6) -rg (whitelist)* 0.059 +/- 0.001 (lines: 6)* - -subtitles_en_alternate (pattern: Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty) ---------------------------------------------------------------------------------------------------------------- -rg (lines) 0.369 +/- 0.004 (lines: 848) -rg* 0.354 +/- 0.039 (lines: 848)* - -subtitles_en_alternate_casei (pattern: Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty) ---------------------------------------------------------------------------------------------------------------------- -rg* 1.994 +/- 0.104 (lines: 862)* - -subtitles_en_literal (pattern: Sherlock Holmes) ------------------------------------------------ -rg* 0.230 +/- 0.012 (lines: 629)* -rg (no mmap) 0.293 +/- 0.005 (lines: 629) -rg (lines) 0.264 +/- 0.040 (lines: 629) - -subtitles_en_literal_casei (pattern: Sherlock Holmes) ------------------------------------------------------ -rg* 0.383 +/- 0.070 (lines: 642)* -rg (lines) 0.420 +/- 0.062 (lines: 642) - -subtitles_en_literal_word (pattern: Sherlock Holmes) ----------------------------------------------------- -rg (ASCII)* 0.252 +/- 0.055 (lines: 629) -rg 0.227 +/- 0.046 (lines: 629)* - -subtitles_en_no_literal (pattern: \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}) ----------------------------------------------------------------------------------------- -rg 1.981 +/- 0.116 (lines: 13) -rg (ASCII)* 1.859 +/- 0.060 (lines: 13)* - -subtitles_en_surrounding_words (pattern: \w+\s+Holmes\s+\w+) ------------------------------------------------------------- -rg* 0.227 +/- 0.057 (lines: 317)* -rg (ASCII) 0.273 +/- 0.036 (lines: 317) - -subtitles_ru_alternate (pattern: Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти) ------------------------------------------------------------------------------------------------------------ -rg (lines) 1.351 +/- 0.006 (lines: 691) -rg* 1.262 +/- 0.016 (lines: 691)* - -subtitles_ru_alternate_casei (pattern: Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти) ------------------------------------------------------------------------------------------------------------------ -rg* 3.781 +/- 0.037 (lines: 735)* - -subtitles_ru_literal (pattern: Шерлок Холмс) --------------------------------------------- -rg* 0.249 +/- 0.034 (lines: 583)* -rg (no mmap) 0.345 +/- 0.040 (lines: 583) -rg (lines) 0.368 +/- 0.013 (lines: 583) - -subtitles_ru_literal_casei (pattern: Шерлок Холмс) --------------------------------------------------- -rg 1.186 +/- 0.013 (lines: 604) -rg (lines)* 1.149 +/- 0.091 (lines: 604)* - -subtitles_ru_literal_word (pattern: Шерлок Холмс) -------------------------------------------------- -rg (ASCII)* 0.256 +/- 0.046 (lines: 0)* -rg 0.343 +/- 0.037 (lines: 579) - -subtitles_ru_no_literal (pattern: \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}) ----------------------------------------------------------------------------------------- -rg 3.408 +/- 0.095 (lines: 41) -rg (ASCII)* 3.040 +/- 0.118 (lines: 0)* - -subtitles_ru_surrounding_words (pattern: \w+\s+Холмс\s+\w+) ------------------------------------------------------------ -rg* 0.367 +/- 0.040 (lines: 278)* diff --git a/benchsuite/runs/2016-12-24-archlinux-cheetah-musl-system/raw.csv b/benchsuite/runs/2016-12-24-archlinux-cheetah-musl-system/raw.csv deleted file mode 100644 index 42be529..0000000 --- a/benchsuite/runs/2016-12-24-archlinux-cheetah-musl-system/raw.csv +++ /dev/null @@ -1,157 +0,0 @@ -benchmark,warmup_iter,iter,name,command,duration,lines,env -linux_alternates,1,3,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.09466052055358887,68, -linux_alternates,1,3,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.09342074394226074,68, -linux_alternates,1,3,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.0869603157043457,68, -linux_alternates,1,3,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.06717634201049805,68, -linux_alternates,1,3,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.06487321853637695,68, -linux_alternates,1,3,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.06573486328125,68, -linux_alternates_casei,1,3,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.10077238082885742,160, -linux_alternates_casei,1,3,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.10428118705749512,160, -linux_alternates_casei,1,3,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.09920215606689453,160, -linux_alternates_casei,1,3,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.07973098754882812,160, -linux_alternates_casei,1,3,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.07897496223449707,160, -linux_alternates_casei,1,3,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.07888197898864746,160, -linux_literal,1,3,rg (ignore),rg -n PM_RESUME,0.06830811500549316,16, -linux_literal,1,3,rg (ignore),rg -n PM_RESUME,0.0715939998626709,16, -linux_literal,1,3,rg (ignore),rg -n PM_RESUME,0.06830549240112305,16, -linux_literal,1,3,rg (ignore) (mmap),rg -n --mmap PM_RESUME,0.3897213935852051,16, -linux_literal,1,3,rg (ignore) (mmap),rg -n --mmap PM_RESUME,0.39376020431518555,16, -linux_literal,1,3,rg (ignore) (mmap),rg -n --mmap PM_RESUME,0.3769495487213135,16, -linux_literal,1,3,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.060272932052612305,16, -linux_literal,1,3,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.058103322982788086,16, -linux_literal,1,3,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.06174445152282715,16, -linux_literal_casei,1,3,rg (ignore),rg -n -i PM_RESUME,0.07664990425109863,370, -linux_literal_casei,1,3,rg (ignore),rg -n -i PM_RESUME,0.07809257507324219,370, -linux_literal_casei,1,3,rg (ignore),rg -n -i PM_RESUME,0.08361077308654785,370, -linux_literal_casei,1,3,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,0.38071417808532715,370, -linux_literal_casei,1,3,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,0.37515711784362793,370, -linux_literal_casei,1,3,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,0.38091325759887695,370, -linux_literal_casei,1,3,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.06704211235046387,370, -linux_literal_casei,1,3,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.06667947769165039,370, -linux_literal_casei,1,3,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.06667375564575195,370, -linux_literal_default,1,3,rg,rg PM_RESUME,0.06779932975769043,16, -linux_literal_default,1,3,rg,rg PM_RESUME,0.06725239753723145,16, -linux_literal_default,1,3,rg,rg PM_RESUME,0.06754946708679199,16, -linux_no_literal,1,3,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.2662222385406494,490, -linux_no_literal,1,3,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.30044007301330566,490, -linux_no_literal,1,3,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.30494165420532227,490, -linux_no_literal,1,3,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.17267060279846191,490, -linux_no_literal,1,3,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.16266226768493652,490, -linux_no_literal,1,3,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.16399097442626953,490, -linux_no_literal,1,3,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.25603818893432617,419, -linux_no_literal,1,3,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.26952672004699707,419, -linux_no_literal,1,3,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.2737579345703125,419, -linux_no_literal,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.14797663688659668,419, -linux_no_literal,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.15069222450256348,419, -linux_no_literal,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.15210580825805664,419, -linux_re_literal_suffix,1,3,rg (ignore),rg -n [A-Z]+_RESUME,0.06923699378967285,1652, -linux_re_literal_suffix,1,3,rg (ignore),rg -n [A-Z]+_RESUME,0.07373404502868652,1652, -linux_re_literal_suffix,1,3,rg (ignore),rg -n [A-Z]+_RESUME,0.07130026817321777,1652, -linux_re_literal_suffix,1,3,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.05809664726257324,1630, -linux_re_literal_suffix,1,3,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.06291556358337402,1630, -linux_re_literal_suffix,1,3,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.062150001525878906,1630, -linux_unicode_greek,1,3,rg,rg -n \p{Greek},0.16234064102172852,23, -linux_unicode_greek,1,3,rg,rg -n \p{Greek},0.16682648658752441,23, -linux_unicode_greek,1,3,rg,rg -n \p{Greek},0.1634657382965088,23, -linux_unicode_greek_casei,1,3,rg,rg -n -i \p{Greek},0.16612553596496582,103, -linux_unicode_greek_casei,1,3,rg,rg -n -i \p{Greek},0.1632983684539795,103, -linux_unicode_greek_casei,1,3,rg,rg -n -i \p{Greek},0.16044902801513672,103, -linux_unicode_word,1,3,rg (ignore),rg -n \wAh,0.07571697235107422,186, -linux_unicode_word,1,3,rg (ignore),rg -n \wAh,0.07967901229858398,186, -linux_unicode_word,1,3,rg (ignore),rg -n \wAh,0.07469820976257324,186, -linux_unicode_word,1,3,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.07374238967895508,174, -linux_unicode_word,1,3,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.07341313362121582,174, -linux_unicode_word,1,3,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.07449674606323242,174, -linux_unicode_word,1,3,rg (whitelist),rg -n --no-ignore -tall \wAh,0.06552338600158691,180, -linux_unicode_word,1,3,rg (whitelist),rg -n --no-ignore -tall \wAh,0.06324410438537598,180, -linux_unicode_word,1,3,rg (whitelist),rg -n --no-ignore -tall \wAh,0.0665595531463623,180, -linux_unicode_word,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.06373834609985352,168, -linux_unicode_word,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.06749844551086426,168, -linux_unicode_word,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.06431031227111816,168, -linux_word,1,3,rg (ignore),rg -n -w PM_RESUME,0.0686798095703125,6, -linux_word,1,3,rg (ignore),rg -n -w PM_RESUME,0.06870913505554199,6, -linux_word,1,3,rg (ignore),rg -n -w PM_RESUME,0.06892633438110352,6, -linux_word,1,3,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.05895066261291504,6, -linux_word,1,3,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.06163740158081055,6, -linux_word,1,3,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.058525800704956055,6, -subtitles_en_alternate,1,3,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.34538722038269043,848, -subtitles_en_alternate,1,3,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.265763521194458,848, -subtitles_en_alternate,1,3,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.26305389404296875,848, -subtitles_en_alternate,1,3,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.20859956741333008,848, -subtitles_en_alternate,1,3,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.20516705513000488,848, -subtitles_en_alternate,1,3,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.20496821403503418,848, -subtitles_en_alternate_casei,1,3,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.2090365886688232,862, -subtitles_en_alternate_casei,1,3,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.226768732070923,862, -subtitles_en_alternate_casei,1,3,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.226130962371826,862, -subtitles_en_literal,1,3,rg,rg Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.24144577980041504,629, -subtitles_en_literal,1,3,rg,rg Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.21985626220703125,629, -subtitles_en_literal,1,3,rg,rg Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.21775150299072266,629, -subtitles_en_literal,1,3,rg (no mmap),rg --no-mmap Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2918863296508789,629, -subtitles_en_literal,1,3,rg (no mmap),rg --no-mmap Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.1962728500366211,629, -subtitles_en_literal,1,3,rg (no mmap),rg --no-mmap Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.19310998916625977,629, -subtitles_en_literal,1,3,rg (lines),rg -n Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.26285672187805176,629, -subtitles_en_literal,1,3,rg (lines),rg -n Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.18955564498901367,629, -subtitles_en_literal,1,3,rg (lines),rg -n Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.1910560131072998,629, -subtitles_en_literal_casei,1,3,rg,rg -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.40812134742736816,642, -subtitles_en_literal_casei,1,3,rg,rg -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.31265878677368164,642, -subtitles_en_literal_casei,1,3,rg,rg -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.31433773040771484,642, -subtitles_en_literal_casei,1,3,rg (lines),rg -n -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.3256862163543701,642, -subtitles_en_literal_casei,1,3,rg (lines),rg -n -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.32616353034973145,642, -subtitles_en_literal_casei,1,3,rg (lines),rg -n -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.32959580421447754,642, -subtitles_en_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.27936625480651855,629, -subtitles_en_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.28154826164245605,629, -subtitles_en_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.20779705047607422,629, -subtitles_en_literal_word,1,3,rg,rg -nw Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.26377248764038086,629, -subtitles_en_literal_word,1,3,rg,rg -nw Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2896091938018799,629, -subtitles_en_literal_word,1,3,rg,rg -nw Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.21306395530700684,629, -subtitles_en_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.0740439891815186,13, -subtitles_en_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.875295639038086,13, -subtitles_en_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.0514187812805176,13, -subtitles_en_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.6831274032592773,13, -subtitles_en_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.6856412887573242,13, -subtitles_en_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.6853716373443604,13, -subtitles_en_surrounding_words,1,3,rg,rg -n \w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2878584861755371,317, -subtitles_en_surrounding_words,1,3,rg,rg -n \w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.22226691246032715,317, -subtitles_en_surrounding_words,1,3,rg,rg -n \w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.294330358505249,317, -subtitles_en_surrounding_words,1,3,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.3013031482696533,317, -subtitles_en_surrounding_words,1,3,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2214052677154541,317, -subtitles_en_surrounding_words,1,3,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.19563746452331543,317, -subtitles_ru_alternate,1,3,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.1506719589233398,691, -subtitles_ru_alternate,1,3,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.345916509628296,691, -subtitles_ru_alternate,1,3,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.3316686153411865,691, -subtitles_ru_alternate,1,3,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.2255687713623047,691, -subtitles_ru_alternate,1,3,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.0810630321502686,691, -subtitles_ru_alternate,1,3,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.2861762046813965,691, -subtitles_ru_alternate_casei,1,3,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.666182279586792,735, -subtitles_ru_alternate_casei,1,3,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.730118751525879,735, -subtitles_ru_alternate_casei,1,3,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.7910759449005127,735, -subtitles_ru_literal,1,3,rg,rg Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.265308141708374,583, -subtitles_ru_literal,1,3,rg,rg Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.2775256633758545,583, -subtitles_ru_literal,1,3,rg,rg Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.29873085021972656,583, -subtitles_ru_literal,1,3,rg (no mmap),rg --no-mmap Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3600039482116699,583, -subtitles_ru_literal,1,3,rg (no mmap),rg --no-mmap Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3705918788909912,583, -subtitles_ru_literal,1,3,rg (no mmap),rg --no-mmap Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.37277793884277344,583, -subtitles_ru_literal,1,3,rg (lines),rg -n Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3728773593902588,583, -subtitles_ru_literal,1,3,rg (lines),rg -n Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.2903330326080322,583, -subtitles_ru_literal,1,3,rg (lines),rg -n Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3601820468902588,583, -subtitles_ru_literal_casei,1,3,rg,rg -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.1635336875915527,604, -subtitles_ru_literal_casei,1,3,rg,rg -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.9739360809326172,604, -subtitles_ru_literal_casei,1,3,rg,rg -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.155383825302124,604, -subtitles_ru_literal_casei,1,3,rg (lines),rg -n -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.2030081748962402,604, -subtitles_ru_literal_casei,1,3,rg (lines),rg -n -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.0454139709472656,604, -subtitles_ru_literal_casei,1,3,rg (lines),rg -n -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.2500181198120117,604, -subtitles_ru_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.2797272205352783,, -subtitles_ru_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.2795555591583252,, -subtitles_ru_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.2683413028717041,, -subtitles_ru_literal_word,1,3,rg,rg -nw Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.2863891124725342,579, -subtitles_ru_literal_word,1,3,rg,rg -nw Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.35770344734191895,579, -subtitles_ru_literal_word,1,3,rg,rg -nw Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3524661064147949,579, -subtitles_ru_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.514166831970215,41, -subtitles_ru_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.4967641830444336,41, -subtitles_ru_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.2882306575775146,41, -subtitles_ru_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.8897318840026855,, -subtitles_ru_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.1153793334960938,, -subtitles_ru_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.100428581237793,, -subtitles_ru_surrounding_words,1,3,rg,rg -n \w+\s+Холмс\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.4093492031097412,278, -subtitles_ru_surrounding_words,1,3,rg,rg -n \w+\s+Холмс\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.4054989814758301,278, -subtitles_ru_surrounding_words,1,3,rg,rg -n \w+\s+Холмс\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3883328437805176,278, diff --git a/benchsuite/runs/2016-12-24-archlinux-cheetah-musl-system/summary b/benchsuite/runs/2016-12-24-archlinux-cheetah-musl-system/summary deleted file mode 100644 index 6f89062..0000000 --- a/benchsuite/runs/2016-12-24-archlinux-cheetah-musl-system/summary +++ /dev/null @@ -1,126 +0,0 @@ -linux_alternates (pattern: ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT) -------------------------------------------------------------------------- -rg (ignore) 0.092 +/- 0.004 (lines: 68) -rg (whitelist)* 0.066 +/- 0.001 (lines: 68)* - -linux_alternates_casei (pattern: ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT) -------------------------------------------------------------------------------- -rg (ignore) 0.101 +/- 0.003 (lines: 160) -rg (whitelist)* 0.079 +/- 0.000 (lines: 160)* - -linux_literal (pattern: PM_RESUME) ----------------------------------- -rg (ignore) 0.069 +/- 0.002 (lines: 16) -rg (ignore) (mmap) 0.387 +/- 0.009 (lines: 16) -rg (whitelist)* 0.060 +/- 0.002 (lines: 16)* - -linux_literal_casei (pattern: PM_RESUME) ----------------------------------------- -rg (ignore) 0.079 +/- 0.004 (lines: 370) -rg (ignore) (mmap) 0.379 +/- 0.003 (lines: 370) -rg (whitelist)* 0.067 +/- 0.000 (lines: 370)* - -linux_literal_default (pattern: PM_RESUME) ------------------------------------------- -rg* 0.068 +/- 0.000 (lines: 16)* - -linux_no_literal (pattern: \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}) ------------------------------------------------------------------ -rg (ignore) 0.291 +/- 0.021 (lines: 490) -rg (ignore) (ASCII) 0.166 +/- 0.005 (lines: 490) -rg (whitelist) 0.266 +/- 0.009 (lines: 419) -rg (whitelist) (ASCII)* 0.150 +/- 0.002 (lines: 419)* - -linux_re_literal_suffix (pattern: [A-Z]+_RESUME) ------------------------------------------------- -rg (ignore) 0.071 +/- 0.002 (lines: 1652) -rg (whitelist)* 0.061 +/- 0.003 (lines: 1630)* - -linux_unicode_greek (pattern: \p{Greek}) ----------------------------------------- -rg* 0.164 +/- 0.002 (lines: 23)* - -linux_unicode_greek_casei (pattern: \p{Greek}) ----------------------------------------------- -rg* 0.163 +/- 0.003 (lines: 103)* - -linux_unicode_word (pattern: \wAh) ----------------------------------- -rg (ignore) 0.077 +/- 0.003 (lines: 186) -rg (ignore) (ASCII) 0.074 +/- 0.001 (lines: 174) -rg (whitelist)* 0.065 +/- 0.002 (lines: 180)* -rg (whitelist) (ASCII) 0.065 +/- 0.002 (lines: 168) - -linux_word (pattern: PM_RESUME) -------------------------------- -rg (ignore) 0.069 +/- 0.000 (lines: 6) -rg (whitelist)* 0.060 +/- 0.002 (lines: 6)* - -subtitles_en_alternate (pattern: Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty) ---------------------------------------------------------------------------------------------------------------- -rg (lines) 0.291 +/- 0.047 (lines: 848) -rg* 0.206 +/- 0.002 (lines: 848)* - -subtitles_en_alternate_casei (pattern: Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty) ---------------------------------------------------------------------------------------------------------------------- -rg* 2.221 +/- 0.010 (lines: 862)* - -subtitles_en_literal (pattern: Sherlock Holmes) ------------------------------------------------ -rg 0.226 +/- 0.013 (lines: 629) -rg (no mmap) 0.227 +/- 0.056 (lines: 629) -rg (lines)* 0.214 +/- 0.042 (lines: 629)* - -subtitles_en_literal_casei (pattern: Sherlock Holmes) ------------------------------------------------------ -rg* 0.345 +/- 0.055 (lines: 642) -rg (lines) 0.327 +/- 0.002 (lines: 642)* - -subtitles_en_literal_word (pattern: Sherlock Holmes) ----------------------------------------------------- -rg (ASCII)* 0.256 +/- 0.042 (lines: 629) -rg 0.255 +/- 0.039 (lines: 629)* - -subtitles_en_no_literal (pattern: \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}) ----------------------------------------------------------------------------------------- -rg 2.000 +/- 0.109 (lines: 13) -rg (ASCII)* 1.685 +/- 0.001 (lines: 13)* - -subtitles_en_surrounding_words (pattern: \w+\s+Holmes\s+\w+) ------------------------------------------------------------- -rg 0.268 +/- 0.040 (lines: 317) -rg (ASCII)* 0.239 +/- 0.055 (lines: 317)* - -subtitles_ru_alternate (pattern: Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти) ------------------------------------------------------------------------------------------------------------ -rg (lines) 1.276 +/- 0.109 (lines: 691) -rg* 1.198 +/- 0.105 (lines: 691)* - -subtitles_ru_alternate_casei (pattern: Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти) ------------------------------------------------------------------------------------------------------------------ -rg* 3.729 +/- 0.062 (lines: 735)* - -subtitles_ru_literal (pattern: Шерлок Холмс) --------------------------------------------- -rg* 0.281 +/- 0.017 (lines: 583)* -rg (no mmap) 0.368 +/- 0.007 (lines: 583) -rg (lines) 0.341 +/- 0.044 (lines: 583) - -subtitles_ru_literal_casei (pattern: Шерлок Холмс) --------------------------------------------------- -rg* 1.098 +/- 0.107 (lines: 604)* -rg (lines) 1.166 +/- 0.107 (lines: 604) - -subtitles_ru_literal_word (pattern: Шерлок Холмс) -------------------------------------------------- -rg (ASCII)* 0.276 +/- 0.007 (lines: 0)* -rg 0.332 +/- 0.040 (lines: 579) - -subtitles_ru_no_literal (pattern: \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}) ----------------------------------------------------------------------------------------- -rg 3.433 +/- 0.126 (lines: 41) -rg (ASCII)* 3.035 +/- 0.126 (lines: 0)* - -subtitles_ru_surrounding_words (pattern: \w+\s+Холмс\s+\w+) ------------------------------------------------------------ -rg* 0.401 +/- 0.011 (lines: 278)* diff --git a/benchsuite/runs/2016-12-24-archlinux-cheetah/raw.csv b/benchsuite/runs/2016-12-24-archlinux-cheetah/raw.csv deleted file mode 100644 index 03f09e1..0000000 --- a/benchsuite/runs/2016-12-24-archlinux-cheetah/raw.csv +++ /dev/null @@ -1,157 +0,0 @@ -benchmark,warmup_iter,iter,name,command,duration,lines,env -linux_alternates,1,3,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.09865546226501465,68, -linux_alternates,1,3,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.08865809440612793,68, -linux_alternates,1,3,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.0934293270111084,68, -linux_alternates,1,3,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.07241153717041016,68, -linux_alternates,1,3,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.06905841827392578,68, -linux_alternates,1,3,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.06687068939208984,68, -linux_alternates_casei,1,3,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.1011350154876709,160, -linux_alternates_casei,1,3,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.1053009033203125,160, -linux_alternates_casei,1,3,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.10577726364135742,160, -linux_alternates_casei,1,3,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.0832066535949707,160, -linux_alternates_casei,1,3,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.0812225341796875,160, -linux_alternates_casei,1,3,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.08363056182861328,160, -linux_literal,1,3,rg (ignore),rg -n PM_RESUME,0.07260608673095703,16, -linux_literal,1,3,rg (ignore),rg -n PM_RESUME,0.06956887245178223,16, -linux_literal,1,3,rg (ignore),rg -n PM_RESUME,0.07262110710144043,16, -linux_literal,1,3,rg (ignore) (mmap),rg -n --mmap PM_RESUME,0.3854484558105469,16, -linux_literal,1,3,rg (ignore) (mmap),rg -n --mmap PM_RESUME,0.3801109790802002,16, -linux_literal,1,3,rg (ignore) (mmap),rg -n --mmap PM_RESUME,0.38498902320861816,16, -linux_literal,1,3,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.06220889091491699,16, -linux_literal,1,3,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.059615373611450195,16, -linux_literal,1,3,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.06207394599914551,16, -linux_literal_casei,1,3,rg (ignore),rg -n -i PM_RESUME,0.08192729949951172,370, -linux_literal_casei,1,3,rg (ignore),rg -n -i PM_RESUME,0.08037471771240234,370, -linux_literal_casei,1,3,rg (ignore),rg -n -i PM_RESUME,0.08067464828491211,370, -linux_literal_casei,1,3,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,0.3890647888183594,370, -linux_literal_casei,1,3,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,0.3882875442504883,370, -linux_literal_casei,1,3,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,0.3826119899749756,370, -linux_literal_casei,1,3,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.07255673408508301,370, -linux_literal_casei,1,3,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.07240700721740723,370, -linux_literal_casei,1,3,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.06744766235351562,370, -linux_literal_default,1,3,rg,rg PM_RESUME,0.06866455078125,16, -linux_literal_default,1,3,rg,rg PM_RESUME,0.06612515449523926,16, -linux_literal_default,1,3,rg,rg PM_RESUME,0.06630897521972656,16, -linux_no_literal,1,3,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.30286335945129395,490, -linux_no_literal,1,3,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.2710304260253906,490, -linux_no_literal,1,3,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.30267834663391113,490, -linux_no_literal,1,3,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.16382431983947754,490, -linux_no_literal,1,3,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.1649789810180664,490, -linux_no_literal,1,3,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.16989731788635254,490, -linux_no_literal,1,3,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.3308746814727783,419, -linux_no_literal,1,3,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.27356576919555664,419, -linux_no_literal,1,3,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.2729830741882324,419, -linux_no_literal,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.16254186630249023,419, -linux_no_literal,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.15763211250305176,419, -linux_no_literal,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.15112638473510742,419, -linux_re_literal_suffix,1,3,rg (ignore),rg -n [A-Z]+_RESUME,0.07556724548339844,1652, -linux_re_literal_suffix,1,3,rg (ignore),rg -n [A-Z]+_RESUME,0.07514452934265137,1652, -linux_re_literal_suffix,1,3,rg (ignore),rg -n [A-Z]+_RESUME,0.06890320777893066,1652, -linux_re_literal_suffix,1,3,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.061008453369140625,1630, -linux_re_literal_suffix,1,3,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.06007099151611328,1630, -linux_re_literal_suffix,1,3,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.058913469314575195,1630, -linux_unicode_greek,1,3,rg,rg -n \p{Greek},0.1675281524658203,23, -linux_unicode_greek,1,3,rg,rg -n \p{Greek},0.1719217300415039,23, -linux_unicode_greek,1,3,rg,rg -n \p{Greek},0.1675257682800293,23, -linux_unicode_greek_casei,1,3,rg,rg -n -i \p{Greek},0.16816997528076172,103, -linux_unicode_greek_casei,1,3,rg,rg -n -i \p{Greek},0.16349577903747559,103, -linux_unicode_greek_casei,1,3,rg,rg -n -i \p{Greek},0.1649951934814453,103, -linux_unicode_word,1,3,rg (ignore),rg -n \wAh,0.07944488525390625,186, -linux_unicode_word,1,3,rg (ignore),rg -n \wAh,0.08015990257263184,186, -linux_unicode_word,1,3,rg (ignore),rg -n \wAh,0.07640767097473145,186, -linux_unicode_word,1,3,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.0741121768951416,174, -linux_unicode_word,1,3,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.07456159591674805,174, -linux_unicode_word,1,3,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.07508492469787598,174, -linux_unicode_word,1,3,rg (whitelist),rg -n --no-ignore -tall \wAh,0.06891131401062012,180, -linux_unicode_word,1,3,rg (whitelist),rg -n --no-ignore -tall \wAh,0.0655059814453125,180, -linux_unicode_word,1,3,rg (whitelist),rg -n --no-ignore -tall \wAh,0.06730937957763672,180, -linux_unicode_word,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.0630197525024414,168, -linux_unicode_word,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.06429147720336914,168, -linux_unicode_word,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.06670451164245605,168, -linux_word,1,3,rg (ignore),rg -n -w PM_RESUME,0.07088422775268555,6, -linux_word,1,3,rg (ignore),rg -n -w PM_RESUME,0.06971001625061035,6, -linux_word,1,3,rg (ignore),rg -n -w PM_RESUME,0.06918931007385254,6, -linux_word,1,3,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.05994749069213867,6, -linux_word,1,3,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.06264781951904297,6, -linux_word,1,3,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.061440467834472656,6, -subtitles_en_alternate,1,3,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.4529764652252197,848, -subtitles_en_alternate,1,3,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.28824853897094727,848, -subtitles_en_alternate,1,3,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.287844181060791,848, -subtitles_en_alternate,1,3,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.34439826011657715,848, -subtitles_en_alternate,1,3,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.34816765785217285,848, -subtitles_en_alternate,1,3,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.23656105995178223,848, -subtitles_en_alternate_casei,1,3,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.026144027709961,862, -subtitles_en_alternate_casei,1,3,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.2452991008758545,862, -subtitles_en_alternate_casei,1,3,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.2087535858154297,862, -subtitles_en_literal,1,3,rg,rg Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2194046974182129,629, -subtitles_en_literal,1,3,rg,rg Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.22587895393371582,629, -subtitles_en_literal,1,3,rg,rg Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.22500324249267578,629, -subtitles_en_literal,1,3,rg (no mmap),rg --no-mmap Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.3005552291870117,629, -subtitles_en_literal,1,3,rg (no mmap),rg --no-mmap Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2805304527282715,629, -subtitles_en_literal,1,3,rg (no mmap),rg --no-mmap Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.30254316329956055,629, -subtitles_en_literal,1,3,rg (lines),rg -n Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2822296619415283,629, -subtitles_en_literal,1,3,rg (lines),rg -n Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2205369472503662,629, -subtitles_en_literal,1,3,rg (lines),rg -n Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.23558998107910156,629, -subtitles_en_literal_casei,1,3,rg,rg -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.4217369556427002,642, -subtitles_en_literal_casei,1,3,rg,rg -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.4352266788482666,642, -subtitles_en_literal_casei,1,3,rg,rg -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.3286154270172119,642, -subtitles_en_literal_casei,1,3,rg (lines),rg -n -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.4068911075592041,642, -subtitles_en_literal_casei,1,3,rg (lines),rg -n -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.4721720218658447,642, -subtitles_en_literal_casei,1,3,rg (lines),rg -n -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.49277544021606445,642, -subtitles_en_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2922394275665283,629, -subtitles_en_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2809920310974121,629, -subtitles_en_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2835381031036377,629, -subtitles_en_literal_word,1,3,rg,rg -nw Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.28315305709838867,629, -subtitles_en_literal_word,1,3,rg,rg -nw Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.29279136657714844,629, -subtitles_en_literal_word,1,3,rg,rg -nw Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.29344797134399414,629, -subtitles_en_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.0767383575439453,13, -subtitles_en_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.0589702129364014,13, -subtitles_en_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.8731834888458252,13, -subtitles_en_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.6820619106292725,13, -subtitles_en_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.8845677375793457,13, -subtitles_en_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.6996817588806152,13, -subtitles_en_surrounding_words,1,3,rg,rg -n \w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2987375259399414,317, -subtitles_en_surrounding_words,1,3,rg,rg -n \w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2955625057220459,317, -subtitles_en_surrounding_words,1,3,rg,rg -n \w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2865116596221924,317, -subtitles_en_surrounding_words,1,3,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.27387547492980957,317, -subtitles_en_surrounding_words,1,3,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2899343967437744,317, -subtitles_en_surrounding_words,1,3,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.19668984413146973,317, -subtitles_ru_alternate,1,3,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.4088802337646484,691, -subtitles_ru_alternate,1,3,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.3826014995574951,691, -subtitles_ru_alternate,1,3,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.4164769649505615,691, -subtitles_ru_alternate,1,3,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.2548110485076904,691, -subtitles_ru_alternate,1,3,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.080472707748413,691, -subtitles_ru_alternate,1,3,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.3337528705596924,691, -subtitles_ru_alternate_casei,1,3,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.449100971221924,735, -subtitles_ru_alternate_casei,1,3,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.747535467147827,735, -subtitles_ru_alternate_casei,1,3,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.7990715503692627,735, -subtitles_ru_literal,1,3,rg,rg Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.21280717849731445,583, -subtitles_ru_literal,1,3,rg,rg Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.18636178970336914,583, -subtitles_ru_literal,1,3,rg,rg Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.2740190029144287,583, -subtitles_ru_literal,1,3,rg (no mmap),rg --no-mmap Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.36304640769958496,583, -subtitles_ru_literal,1,3,rg (no mmap),rg --no-mmap Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3737907409667969,583, -subtitles_ru_literal,1,3,rg (no mmap),rg --no-mmap Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.37337779998779297,583, -subtitles_ru_literal,1,3,rg (lines),rg -n Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.2974729537963867,583, -subtitles_ru_literal,1,3,rg (lines),rg -n Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.2715010643005371,583, -subtitles_ru_literal,1,3,rg (lines),rg -n Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.36052799224853516,583, -subtitles_ru_literal_casei,1,3,rg,rg -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.206491231918335,604, -subtitles_ru_literal_casei,1,3,rg,rg -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.202974557876587,604, -subtitles_ru_literal_casei,1,3,rg,rg -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.195291519165039,604, -subtitles_ru_literal_casei,1,3,rg (lines),rg -n -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.2875757217407227,604, -subtitles_ru_literal_casei,1,3,rg (lines),rg -n -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.2895469665527344,604, -subtitles_ru_literal_casei,1,3,rg (lines),rg -n -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.277585506439209,604, -subtitles_ru_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.2928614616394043,, -subtitles_ru_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.2610359191894531,, -subtitles_ru_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.2692301273345947,, -subtitles_ru_literal_word,1,3,rg,rg -nw Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.36007237434387207,579, -subtitles_ru_literal_word,1,3,rg,rg -nw Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.37184953689575195,579, -subtitles_ru_literal_word,1,3,rg,rg -nw Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3902134895324707,579, -subtitles_ru_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.2949090003967285,41, -subtitles_ru_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.48958683013916,41, -subtitles_ru_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.389604091644287,41, -subtitles_ru_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.894768714904785,, -subtitles_ru_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.873474359512329,, -subtitles_ru_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.088130474090576,, -subtitles_ru_surrounding_words,1,3,rg,rg -n \w+\s+Холмс\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3918273448944092,278, -subtitles_ru_surrounding_words,1,3,rg,rg -n \w+\s+Холмс\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.38251543045043945,278, -subtitles_ru_surrounding_words,1,3,rg,rg -n \w+\s+Холмс\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.2919657230377197,278, diff --git a/benchsuite/runs/2016-12-24-archlinux-cheetah/summary b/benchsuite/runs/2016-12-24-archlinux-cheetah/summary deleted file mode 100644 index 818514c..0000000 --- a/benchsuite/runs/2016-12-24-archlinux-cheetah/summary +++ /dev/null @@ -1,126 +0,0 @@ -linux_alternates (pattern: ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT) -------------------------------------------------------------------------- -rg (ignore) 0.094 +/- 0.005 (lines: 68) -rg (whitelist)* 0.069 +/- 0.003 (lines: 68)* - -linux_alternates_casei (pattern: ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT) -------------------------------------------------------------------------------- -rg (ignore) 0.104 +/- 0.003 (lines: 160) -rg (whitelist)* 0.083 +/- 0.001 (lines: 160)* - -linux_literal (pattern: PM_RESUME) ----------------------------------- -rg (ignore) 0.072 +/- 0.002 (lines: 16) -rg (ignore) (mmap) 0.384 +/- 0.003 (lines: 16) -rg (whitelist)* 0.061 +/- 0.001 (lines: 16)* - -linux_literal_casei (pattern: PM_RESUME) ----------------------------------------- -rg (ignore) 0.081 +/- 0.001 (lines: 370) -rg (ignore) (mmap) 0.387 +/- 0.004 (lines: 370) -rg (whitelist)* 0.071 +/- 0.003 (lines: 370)* - -linux_literal_default (pattern: PM_RESUME) ------------------------------------------- -rg* 0.067 +/- 0.001 (lines: 16)* - -linux_no_literal (pattern: \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}) ------------------------------------------------------------------ -rg (ignore) 0.292 +/- 0.018 (lines: 490) -rg (ignore) (ASCII) 0.166 +/- 0.003 (lines: 490) -rg (whitelist) 0.292 +/- 0.033 (lines: 419) -rg (whitelist) (ASCII)* 0.157 +/- 0.006 (lines: 419)* - -linux_re_literal_suffix (pattern: [A-Z]+_RESUME) ------------------------------------------------- -rg (ignore) 0.073 +/- 0.004 (lines: 1652) -rg (whitelist)* 0.060 +/- 0.001 (lines: 1630)* - -linux_unicode_greek (pattern: \p{Greek}) ----------------------------------------- -rg* 0.169 +/- 0.003 (lines: 23)* - -linux_unicode_greek_casei (pattern: \p{Greek}) ----------------------------------------------- -rg* 0.166 +/- 0.002 (lines: 103)* - -linux_unicode_word (pattern: \wAh) ----------------------------------- -rg (ignore) 0.079 +/- 0.002 (lines: 186) -rg (ignore) (ASCII) 0.075 +/- 0.000 (lines: 174) -rg (whitelist) 0.067 +/- 0.002 (lines: 180) -rg (whitelist) (ASCII)* 0.065 +/- 0.002 (lines: 168)* - -linux_word (pattern: PM_RESUME) -------------------------------- -rg (ignore) 0.070 +/- 0.001 (lines: 6) -rg (whitelist)* 0.061 +/- 0.001 (lines: 6)* - -subtitles_en_alternate (pattern: Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty) ---------------------------------------------------------------------------------------------------------------- -rg (lines) 0.343 +/- 0.095 (lines: 848) -rg* 0.310 +/- 0.063 (lines: 848)* - -subtitles_en_alternate_casei (pattern: Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty) ---------------------------------------------------------------------------------------------------------------------- -rg* 2.160 +/- 0.117 (lines: 862)* - -subtitles_en_literal (pattern: Sherlock Holmes) ------------------------------------------------ -rg* 0.223 +/- 0.004 (lines: 629)* -rg (no mmap) 0.295 +/- 0.012 (lines: 629) -rg (lines) 0.246 +/- 0.032 (lines: 629) - -subtitles_en_literal_casei (pattern: Sherlock Holmes) ------------------------------------------------------ -rg* 0.395 +/- 0.058 (lines: 642)* -rg (lines) 0.457 +/- 0.045 (lines: 642) - -subtitles_en_literal_word (pattern: Sherlock Holmes) ----------------------------------------------------- -rg (ASCII)* 0.286 +/- 0.006 (lines: 629)* -rg 0.290 +/- 0.006 (lines: 629) - -subtitles_en_no_literal (pattern: \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}) ----------------------------------------------------------------------------------------- -rg 2.003 +/- 0.113 (lines: 13) -rg (ASCII)* 1.755 +/- 0.112 (lines: 13)* - -subtitles_en_surrounding_words (pattern: \w+\s+Holmes\s+\w+) ------------------------------------------------------------- -rg 0.294 +/- 0.006 (lines: 317) -rg (ASCII)* 0.253 +/- 0.050 (lines: 317)* - -subtitles_ru_alternate (pattern: Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти) ------------------------------------------------------------------------------------------------------------ -rg (lines) 1.403 +/- 0.018 (lines: 691) -rg* 1.223 +/- 0.130 (lines: 691)* - -subtitles_ru_alternate_casei (pattern: Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти) ------------------------------------------------------------------------------------------------------------------ -rg* 3.665 +/- 0.189 (lines: 735)* - -subtitles_ru_literal (pattern: Шерлок Холмс) --------------------------------------------- -rg* 0.224 +/- 0.045 (lines: 583)* -rg (no mmap) 0.370 +/- 0.006 (lines: 583) -rg (lines) 0.310 +/- 0.046 (lines: 583) - -subtitles_ru_literal_casei (pattern: Шерлок Холмс) --------------------------------------------------- -rg* 1.202 +/- 0.006 (lines: 604)* -rg (lines) 1.285 +/- 0.006 (lines: 604) - -subtitles_ru_literal_word (pattern: Шерлок Холмс) -------------------------------------------------- -rg (ASCII)* 0.274 +/- 0.017 (lines: 0)* -rg 0.374 +/- 0.015 (lines: 579) - -subtitles_ru_no_literal (pattern: \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}) ----------------------------------------------------------------------------------------- -rg 3.391 +/- 0.097 (lines: 41) -rg (ASCII)* 2.952 +/- 0.118 (lines: 0)* - -subtitles_ru_surrounding_words (pattern: \w+\s+Холмс\s+\w+) ------------------------------------------------------------ -rg* 0.355 +/- 0.055 (lines: 278)* diff --git a/benchsuite/runs/2016-12-30-archlinux-cheetah/raw.csv b/benchsuite/runs/2016-12-30-archlinux-cheetah/raw.csv deleted file mode 100644 index e780d27..0000000 --- a/benchsuite/runs/2016-12-30-archlinux-cheetah/raw.csv +++ /dev/null @@ -1,157 +0,0 @@ -benchmark,warmup_iter,iter,name,command,duration,lines,env -linux_alternates,1,3,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.09816598892211914,68, -linux_alternates,1,3,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.08965039253234863,68, -linux_alternates,1,3,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.09101128578186035,68, -linux_alternates,1,3,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.07472872734069824,68, -linux_alternates,1,3,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.07628297805786133,68, -linux_alternates,1,3,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.07189559936523438,68, -linux_alternates_casei,1,3,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.10288548469543457,160, -linux_alternates_casei,1,3,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.10204243659973145,160, -linux_alternates_casei,1,3,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.1031193733215332,160, -linux_alternates_casei,1,3,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.08190178871154785,160, -linux_alternates_casei,1,3,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.08523178100585938,160, -linux_alternates_casei,1,3,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.07952761650085449,160, -linux_literal,1,3,rg (ignore),rg -n PM_RESUME,0.06972551345825195,16, -linux_literal,1,3,rg (ignore),rg -n PM_RESUME,0.0691523551940918,16, -linux_literal,1,3,rg (ignore),rg -n PM_RESUME,0.06865429878234863,16, -linux_literal,1,3,rg (ignore) (mmap),rg -n --mmap PM_RESUME,0.39247632026672363,16, -linux_literal,1,3,rg (ignore) (mmap),rg -n --mmap PM_RESUME,0.4009978771209717,16, -linux_literal,1,3,rg (ignore) (mmap),rg -n --mmap PM_RESUME,0.40122294425964355,16, -linux_literal,1,3,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.062048912048339844,16, -linux_literal,1,3,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.05932760238647461,16, -linux_literal,1,3,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.058171749114990234,16, -linux_literal_casei,1,3,rg (ignore),rg -n -i PM_RESUME,0.08261799812316895,370, -linux_literal_casei,1,3,rg (ignore),rg -n -i PM_RESUME,0.0780181884765625,370, -linux_literal_casei,1,3,rg (ignore),rg -n -i PM_RESUME,0.07934045791625977,370, -linux_literal_casei,1,3,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,0.4008915424346924,370, -linux_literal_casei,1,3,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,0.3899986743927002,370, -linux_literal_casei,1,3,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,0.39725732803344727,370, -linux_literal_casei,1,3,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.07104611396789551,370, -linux_literal_casei,1,3,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.0707247257232666,370, -linux_literal_casei,1,3,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.06864142417907715,370, -linux_literal_default,1,3,rg,rg PM_RESUME,0.06764745712280273,16, -linux_literal_default,1,3,rg,rg PM_RESUME,0.06994485855102539,16, -linux_literal_default,1,3,rg,rg PM_RESUME,0.0682222843170166,16, -linux_no_literal,1,3,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.27941250801086426,490, -linux_no_literal,1,3,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.31389880180358887,490, -linux_no_literal,1,3,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.30502963066101074,490, -linux_no_literal,1,3,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.16565680503845215,490, -linux_no_literal,1,3,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.16579079627990723,490, -linux_no_literal,1,3,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.169691801071167,490, -linux_no_literal,1,3,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.2969038486480713,419, -linux_no_literal,1,3,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.2995884418487549,419, -linux_no_literal,1,3,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.27426910400390625,419, -linux_no_literal,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.15207958221435547,419, -linux_no_literal,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.15367984771728516,419, -linux_no_literal,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.15249848365783691,419, -linux_re_literal_suffix,1,3,rg (ignore),rg -n [A-Z]+_RESUME,0.07145977020263672,1652, -linux_re_literal_suffix,1,3,rg (ignore),rg -n [A-Z]+_RESUME,0.07139325141906738,1652, -linux_re_literal_suffix,1,3,rg (ignore),rg -n [A-Z]+_RESUME,0.0708932876586914,1652, -linux_re_literal_suffix,1,3,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.05987191200256348,1630, -linux_re_literal_suffix,1,3,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.06223797798156738,1630, -linux_re_literal_suffix,1,3,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.06115579605102539,1630, -linux_unicode_greek,1,3,rg,rg -n \p{Greek},0.16427040100097656,23, -linux_unicode_greek,1,3,rg,rg -n \p{Greek},0.16524410247802734,23, -linux_unicode_greek,1,3,rg,rg -n \p{Greek},0.1664714813232422,23, -linux_unicode_greek_casei,1,3,rg,rg -n -i \p{Greek},0.16639113426208496,103, -linux_unicode_greek_casei,1,3,rg,rg -n -i \p{Greek},0.16803503036499023,103, -linux_unicode_greek_casei,1,3,rg,rg -n -i \p{Greek},0.16656923294067383,103, -linux_unicode_word,1,3,rg (ignore),rg -n \wAh,0.07580804824829102,186, -linux_unicode_word,1,3,rg (ignore),rg -n \wAh,0.07589507102966309,186, -linux_unicode_word,1,3,rg (ignore),rg -n \wAh,0.07574295997619629,186, -linux_unicode_word,1,3,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.07641291618347168,174, -linux_unicode_word,1,3,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.07523059844970703,174, -linux_unicode_word,1,3,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.07748007774353027,174, -linux_unicode_word,1,3,rg (whitelist),rg -n --no-ignore -tall \wAh,0.06804847717285156,180, -linux_unicode_word,1,3,rg (whitelist),rg -n --no-ignore -tall \wAh,0.06720519065856934,180, -linux_unicode_word,1,3,rg (whitelist),rg -n --no-ignore -tall \wAh,0.06687021255493164,180, -linux_unicode_word,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.06528687477111816,168, -linux_unicode_word,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.07101035118103027,168, -linux_unicode_word,1,3,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.06446981430053711,168, -linux_word,1,3,rg (ignore),rg -n -w PM_RESUME,0.07159972190856934,6, -linux_word,1,3,rg (ignore),rg -n -w PM_RESUME,0.0695488452911377,6, -linux_word,1,3,rg (ignore),rg -n -w PM_RESUME,0.07082796096801758,6, -linux_word,1,3,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.06297016143798828,6, -linux_word,1,3,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.06128263473510742,6, -linux_word,1,3,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.06177973747253418,6, -subtitles_en_alternate,1,3,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.36841607093811035,848, -subtitles_en_alternate,1,3,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.30306172370910645,848, -subtitles_en_alternate,1,3,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.3288271427154541,848, -subtitles_en_alternate,1,3,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.3186373710632324,848, -subtitles_en_alternate,1,3,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.23814082145690918,848, -subtitles_en_alternate,1,3,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.23152780532836914,848, -subtitles_en_alternate_casei,1,3,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.2480580806732178,862, -subtitles_en_alternate_casei,1,3,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.2288904190063477,862, -subtitles_en_alternate_casei,1,3,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.287020206451416,862, -subtitles_en_literal,1,3,rg,rg Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.21738362312316895,629, -subtitles_en_literal,1,3,rg,rg Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.16032648086547852,629, -subtitles_en_literal,1,3,rg,rg Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.15392351150512695,629, -subtitles_en_literal,1,3,rg (no mmap),rg --no-mmap Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.21230578422546387,629, -subtitles_en_literal,1,3,rg (no mmap),rg --no-mmap Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.27013158798217773,629, -subtitles_en_literal,1,3,rg (no mmap),rg --no-mmap Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.19994258880615234,629, -subtitles_en_literal,1,3,rg (lines),rg -n Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2728753089904785,629, -subtitles_en_literal,1,3,rg (lines),rg -n Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.23652935028076172,629, -subtitles_en_literal,1,3,rg (lines),rg -n Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2579770088195801,629, -subtitles_en_literal_casei,1,3,rg,rg -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.3031468391418457,642, -subtitles_en_literal_casei,1,3,rg,rg -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.40822505950927734,642, -subtitles_en_literal_casei,1,3,rg,rg -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.38727545738220215,642, -subtitles_en_literal_casei,1,3,rg (lines),rg -n -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.4260599613189697,642, -subtitles_en_literal_casei,1,3,rg (lines),rg -n -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.4490511417388916,642, -subtitles_en_literal_casei,1,3,rg (lines),rg -n -i Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.49449872970581055,642, -subtitles_en_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2707977294921875,629, -subtitles_en_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2691836357116699,629, -subtitles_en_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.24464011192321777,629, -subtitles_en_literal_word,1,3,rg,rg -nw Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.22373199462890625,629, -subtitles_en_literal_word,1,3,rg,rg -nw Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.25702810287475586,629, -subtitles_en_literal_word,1,3,rg,rg -nw Sherlock Holmes /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.23047828674316406,629, -subtitles_en_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.139404773712158,13, -subtitles_en_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.0484464168548584,13, -subtitles_en_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.0293972492218018,13, -subtitles_en_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.840238094329834,13, -subtitles_en_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.7812306880950928,13, -subtitles_en_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.7657690048217773,13, -subtitles_en_surrounding_words,1,3,rg,rg -n \w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.26054978370666504,317, -subtitles_en_surrounding_words,1,3,rg,rg -n \w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2869753837585449,317, -subtitles_en_surrounding_words,1,3,rg,rg -n \w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.22949600219726562,317, -subtitles_en_surrounding_words,1,3,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.21858429908752441,317, -subtitles_en_surrounding_words,1,3,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2064223289489746,317, -subtitles_en_surrounding_words,1,3,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.20789289474487305,317, -subtitles_ru_alternate,1,3,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.313758373260498,691, -subtitles_ru_alternate,1,3,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.2925219535827637,691, -subtitles_ru_alternate,1,3,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.3444299697875977,691, -subtitles_ru_alternate,1,3,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.264918565750122,691, -subtitles_ru_alternate,1,3,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.30733060836792,691, -subtitles_ru_alternate,1,3,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.1466560363769531,691, -subtitles_ru_alternate_casei,1,3,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.783818244934082,735, -subtitles_ru_alternate_casei,1,3,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.76894474029541,735, -subtitles_ru_alternate_casei,1,3,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.788987398147583,735, -subtitles_ru_literal,1,3,rg,rg Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.2822730541229248,583, -subtitles_ru_literal,1,3,rg,rg Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.25232434272766113,583, -subtitles_ru_literal,1,3,rg,rg Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.2563645839691162,583, -subtitles_ru_literal,1,3,rg (no mmap),rg --no-mmap Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.34694504737854004,583, -subtitles_ru_literal,1,3,rg (no mmap),rg --no-mmap Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3202054500579834,583, -subtitles_ru_literal,1,3,rg (no mmap),rg --no-mmap Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3236703872680664,583, -subtitles_ru_literal,1,3,rg (lines),rg -n Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.36035776138305664,583, -subtitles_ru_literal,1,3,rg (lines),rg -n Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3270585536956787,583, -subtitles_ru_literal,1,3,rg (lines),rg -n Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3121967315673828,583, -subtitles_ru_literal_casei,1,3,rg,rg -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.0397696495056152,604, -subtitles_ru_literal_casei,1,3,rg,rg -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.158402442932129,604, -subtitles_ru_literal_casei,1,3,rg,rg -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.1158676147460938,604, -subtitles_ru_literal_casei,1,3,rg (lines),rg -n -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.2041549682617188,604, -subtitles_ru_literal_casei,1,3,rg (lines),rg -n -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.1511006355285645,604, -subtitles_ru_literal_casei,1,3,rg (lines),rg -n -i Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.1794021129608154,604, -subtitles_ru_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.19694828987121582,, -subtitles_ru_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.1980271339416504,, -subtitles_ru_literal_word,1,3,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.2128591537475586,, -subtitles_ru_literal_word,1,3,rg,rg -nw Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3568108081817627,579, -subtitles_ru_literal_word,1,3,rg,rg -nw Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3353869915008545,579, -subtitles_ru_literal_word,1,3,rg,rg -nw Шерлок Холмс /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3075387477874756,579, -subtitles_ru_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.5629587173461914,41, -subtitles_ru_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.5984435081481934,41, -subtitles_ru_no_literal,1,3,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.4725229740142822,41, -subtitles_ru_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.170077323913574,, -subtitles_ru_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.064476490020752,, -subtitles_ru_no_literal,1,3,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.159156084060669,, -subtitles_ru_surrounding_words,1,3,rg,rg -n \w+\s+Холмс\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3924906253814697,278, -subtitles_ru_surrounding_words,1,3,rg,rg -n \w+\s+Холмс\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3874075412750244,278, -subtitles_ru_surrounding_words,1,3,rg,rg -n \w+\s+Холмс\s+\w+ /data/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.39940643310546875,278, diff --git a/benchsuite/runs/2016-12-30-archlinux-cheetah/summary b/benchsuite/runs/2016-12-30-archlinux-cheetah/summary deleted file mode 100644 index f4a7451..0000000 --- a/benchsuite/runs/2016-12-30-archlinux-cheetah/summary +++ /dev/null @@ -1,126 +0,0 @@ -linux_alternates (pattern: ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT) -------------------------------------------------------------------------- -rg (ignore) 0.093 +/- 0.005 (lines: 68) -rg (whitelist)* 0.074 +/- 0.002 (lines: 68)* - -linux_alternates_casei (pattern: ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT) -------------------------------------------------------------------------------- -rg (ignore) 0.103 +/- 0.001 (lines: 160) -rg (whitelist)* 0.082 +/- 0.003 (lines: 160)* - -linux_literal (pattern: PM_RESUME) ----------------------------------- -rg (ignore) 0.069 +/- 0.001 (lines: 16) -rg (ignore) (mmap) 0.398 +/- 0.005 (lines: 16) -rg (whitelist)* 0.060 +/- 0.002 (lines: 16)* - -linux_literal_casei (pattern: PM_RESUME) ----------------------------------------- -rg (ignore) 0.080 +/- 0.002 (lines: 370) -rg (ignore) (mmap) 0.396 +/- 0.006 (lines: 370) -rg (whitelist)* 0.070 +/- 0.001 (lines: 370)* - -linux_literal_default (pattern: PM_RESUME) ------------------------------------------- -rg* 0.069 +/- 0.001 (lines: 16)* - -linux_no_literal (pattern: \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}) ------------------------------------------------------------------ -rg (ignore) 0.299 +/- 0.018 (lines: 490) -rg (ignore) (ASCII) 0.167 +/- 0.002 (lines: 490) -rg (whitelist) 0.290 +/- 0.014 (lines: 419) -rg (whitelist) (ASCII)* 0.153 +/- 0.001 (lines: 419)* - -linux_re_literal_suffix (pattern: [A-Z]+_RESUME) ------------------------------------------------- -rg (ignore) 0.071 +/- 0.000 (lines: 1652) -rg (whitelist)* 0.061 +/- 0.001 (lines: 1630)* - -linux_unicode_greek (pattern: \p{Greek}) ----------------------------------------- -rg* 0.165 +/- 0.001 (lines: 23)* - -linux_unicode_greek_casei (pattern: \p{Greek}) ----------------------------------------------- -rg* 0.167 +/- 0.001 (lines: 103)* - -linux_unicode_word (pattern: \wAh) ----------------------------------- -rg (ignore) 0.076 +/- 0.000 (lines: 186) -rg (ignore) (ASCII) 0.076 +/- 0.001 (lines: 174) -rg (whitelist) 0.067 +/- 0.001 (lines: 180) -rg (whitelist) (ASCII)* 0.067 +/- 0.004 (lines: 168)* - -linux_word (pattern: PM_RESUME) -------------------------------- -rg (ignore) 0.071 +/- 0.001 (lines: 6) -rg (whitelist)* 0.062 +/- 0.001 (lines: 6)* - -subtitles_en_alternate (pattern: Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty) ---------------------------------------------------------------------------------------------------------------- -rg (lines) 0.333 +/- 0.033 (lines: 848) -rg* 0.263 +/- 0.048 (lines: 848)* - -subtitles_en_alternate_casei (pattern: Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty) ---------------------------------------------------------------------------------------------------------------------- -rg* 2.255 +/- 0.030 (lines: 862)* - -subtitles_en_literal (pattern: Sherlock Holmes) ------------------------------------------------ -rg* 0.177 +/- 0.035 (lines: 629)* -rg (no mmap) 0.227 +/- 0.037 (lines: 629) -rg (lines) 0.256 +/- 0.018 (lines: 629) - -subtitles_en_literal_casei (pattern: Sherlock Holmes) ------------------------------------------------------ -rg* 0.366 +/- 0.056 (lines: 642)* -rg (lines) 0.457 +/- 0.035 (lines: 642) - -subtitles_en_literal_word (pattern: Sherlock Holmes) ----------------------------------------------------- -rg (ASCII) 0.262 +/- 0.015 (lines: 629) -rg* 0.237 +/- 0.018 (lines: 629)* - -subtitles_en_no_literal (pattern: \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}) ----------------------------------------------------------------------------------------- -rg 2.072 +/- 0.059 (lines: 13) -rg (ASCII)* 1.796 +/- 0.039 (lines: 13)* - -subtitles_en_surrounding_words (pattern: \w+\s+Holmes\s+\w+) ------------------------------------------------------------- -rg 0.259 +/- 0.029 (lines: 317) -rg (ASCII)* 0.211 +/- 0.007 (lines: 317)* - -subtitles_ru_alternate (pattern: Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти) ------------------------------------------------------------------------------------------------------------ -rg (lines) 1.317 +/- 0.026 (lines: 691) -rg* 1.240 +/- 0.083 (lines: 691)* - -subtitles_ru_alternate_casei (pattern: Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти) ------------------------------------------------------------------------------------------------------------------ -rg* 3.781 +/- 0.010 (lines: 735)* - -subtitles_ru_literal (pattern: Шерлок Холмс) --------------------------------------------- -rg* 0.264 +/- 0.016 (lines: 583)* -rg (no mmap) 0.330 +/- 0.015 (lines: 583) -rg (lines) 0.333 +/- 0.025 (lines: 583) - -subtitles_ru_literal_casei (pattern: Шерлок Холмс) --------------------------------------------------- -rg* 1.105 +/- 0.060 (lines: 604)* -rg (lines) 1.178 +/- 0.027 (lines: 604) - -subtitles_ru_literal_word (pattern: Шерлок Холмс) -------------------------------------------------- -rg (ASCII)* 0.203 +/- 0.009 (lines: 0)* -rg 0.333 +/- 0.025 (lines: 579) - -subtitles_ru_no_literal (pattern: \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}) ----------------------------------------------------------------------------------------- -rg 3.545 +/- 0.065 (lines: 41) -rg (ASCII)* 3.131 +/- 0.058 (lines: 0)* - -subtitles_ru_surrounding_words (pattern: \w+\s+Холмс\s+\w+) ------------------------------------------------------------ -rg* 0.393 +/- 0.006 (lines: 278)* diff --git a/benchsuite/runs/2018-01-08-archlinux-cheetah/README b/benchsuite/runs/2018-01-08-archlinux-cheetah/README deleted file mode 100644 index 4dcc4b5..0000000 --- a/benchsuite/runs/2018-01-08-archlinux-cheetah/README +++ /dev/null @@ -1,59 +0,0 @@ -This directory contains updated benchmarks as of 2018-01-08. They were captured -via the benchsuite script at `benchsuite/benchsuite` from the root of this -repository. The command that was run: - - $ ./benchsuite \ - --dir /tmp/benchsuite \ - --raw runs/2018-01-08-archlinux-cheetah/raw.csv \ - --warmup-iter 1 \ - --bench-iter 5 - -These results are most directly comparable to the -`2016-09-22-archlinux-cheetah` run in the parent directory. - -The versions of each tool are as follows: - - $ grep -V - grep (GNU grep) 3.1 - - $ ag -V - ag version 2.1.0 - Features: - +jit +lzma +zlib - - $ sift -V - sift 0.8.0 (linux/amd64) - built from commit 2ca94717 (which seems to be 0.9.0) - - $ pt --version - pt version 2.1.4 - - $ ucg -V - UniversalCodeGrep 0.3.3 - [...] - Build info - - Repo version: 0.3.3-251-g9b5a3e3 - - Compiler info: - Name ($(CXX)): "g++ -std=gnu++1z" - Version string: "g++ (GCC) 7.2.1 20171224" - - ISA extensions in use: - sse4.2: yes - popcnt: yes - - libpcre info: - Not linked against libpcre. - - libpcre2-8 info: - Version: 10.30 2017-08-14 - JIT support built in?: yes - JIT target architecture: x86 64bit (little endian + unaligned) - Newline style: LF - -The version of ripgrep was compiled from source on commit 85d463c0, with the -simd-accel and avx-accel features enabled: - - $ export RUSTFLAGS="-C target-cpu=native" - $ cargo build --release --features 'simd-accel avx-accel' diff --git a/benchsuite/runs/2018-01-08-archlinux-cheetah/raw.csv b/benchsuite/runs/2018-01-08-archlinux-cheetah/raw.csv deleted file mode 100644 index 778e923..0000000 --- a/benchsuite/runs/2018-01-08-archlinux-cheetah/raw.csv +++ /dev/null @@ -1,806 +0,0 @@ -benchmark,warmup_iter,iter,name,command,duration,lines,env -linux_alternates,1,5,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.10186767578125,68, -linux_alternates,1,5,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.10199356079101562,68, -linux_alternates,1,5,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.09750819206237793,68, -linux_alternates,1,5,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.09634733200073242,68, -linux_alternates,1,5,rg (ignore),rg -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.10117292404174805,68, -linux_alternates,1,5,ag (ignore),ag -s ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.49642109870910645,68, -linux_alternates,1,5,ag (ignore),ag -s ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.48993706703186035,68, -linux_alternates,1,5,ag (ignore),ag -s ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.4837028980255127,68, -linux_alternates,1,5,ag (ignore),ag -s ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.4773833751678467,68, -linux_alternates,1,5,ag (ignore),ag -s ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.558436393737793,68, -linux_alternates,1,5,git grep (ignore),git grep -E -I -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.2605454921722412,68,LC_ALL=C -linux_alternates,1,5,git grep (ignore),git grep -E -I -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.26748204231262207,68,LC_ALL=C -linux_alternates,1,5,git grep (ignore),git grep -E -I -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.26719212532043457,68,LC_ALL=C -linux_alternates,1,5,git grep (ignore),git grep -E -I -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.2719383239746094,68,LC_ALL=C -linux_alternates,1,5,git grep (ignore),git grep -E -I -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.26963257789611816,68,LC_ALL=C -linux_alternates,1,5,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.08797001838684082,68, -linux_alternates,1,5,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.09073781967163086,68, -linux_alternates,1,5,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.0914468765258789,68, -linux_alternates,1,5,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.09071612358093262,68, -linux_alternates,1,5,rg (whitelist),rg --no-ignore -n ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.0914316177368164,68, -linux_alternates,1,5,ucg (whitelist),ucg --nosmart-case ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.1372535228729248,68, -linux_alternates,1,5,ucg (whitelist),ucg --nosmart-case ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.13880419731140137,68, -linux_alternates,1,5,ucg (whitelist),ucg --nosmart-case ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.13315439224243164,68, -linux_alternates,1,5,ucg (whitelist),ucg --nosmart-case ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.1367807388305664,68, -linux_alternates,1,5,ucg (whitelist),ucg --nosmart-case ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.13135552406311035,68, -linux_alternates_casei,1,5,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.12781810760498047,160, -linux_alternates_casei,1,5,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.11988544464111328,160, -linux_alternates_casei,1,5,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.1205439567565918,160, -linux_alternates_casei,1,5,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.12867259979248047,160, -linux_alternates_casei,1,5,rg (ignore),rg -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.1215970516204834,160, -linux_alternates_casei,1,5,ag (ignore),ag -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.5444357395172119,160, -linux_alternates_casei,1,5,ag (ignore),ag -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.5511739253997803,160, -linux_alternates_casei,1,5,ag (ignore),ag -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.5382294654846191,160, -linux_alternates_casei,1,5,ag (ignore),ag -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.5499558448791504,160, -linux_alternates_casei,1,5,ag (ignore),ag -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.6376545429229736,160, -linux_alternates_casei,1,5,git grep (ignore),git grep -E -I -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.9767155647277832,160,LC_ALL=C -linux_alternates_casei,1,5,git grep (ignore),git grep -E -I -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.920574426651001,160,LC_ALL=C -linux_alternates_casei,1,5,git grep (ignore),git grep -E -I -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.9352290630340576,160,LC_ALL=C -linux_alternates_casei,1,5,git grep (ignore),git grep -E -I -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.8866012096405029,160,LC_ALL=C -linux_alternates_casei,1,5,git grep (ignore),git grep -E -I -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.9189445972442627,160,LC_ALL=C -linux_alternates_casei,1,5,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.09351730346679688,160, -linux_alternates_casei,1,5,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.09393739700317383,160, -linux_alternates_casei,1,5,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.09986448287963867,160, -linux_alternates_casei,1,5,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.09596824645996094,160, -linux_alternates_casei,1,5,rg (whitelist),rg --no-ignore -n -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.09604883193969727,160, -linux_alternates_casei,1,5,ucg (whitelist),ucg -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.23943114280700684,160, -linux_alternates_casei,1,5,ucg (whitelist),ucg -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.2587015628814697,160, -linux_alternates_casei,1,5,ucg (whitelist),ucg -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.2543606758117676,160, -linux_alternates_casei,1,5,ucg (whitelist),ucg -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.2490406036376953,160, -linux_alternates_casei,1,5,ucg (whitelist),ucg -i ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT,0.24046540260314941,160, -linux_literal,1,5,rg (ignore),rg -n PM_RESUME,0.08253765106201172,16, -linux_literal,1,5,rg (ignore),rg -n PM_RESUME,0.08176755905151367,16, -linux_literal,1,5,rg (ignore),rg -n PM_RESUME,0.08141684532165527,16, -linux_literal,1,5,rg (ignore),rg -n PM_RESUME,0.08108830451965332,16, -linux_literal,1,5,rg (ignore),rg -n PM_RESUME,0.08082938194274902,16, -linux_literal,1,5,rg (ignore) (mmap),rg -n --mmap PM_RESUME,0.6870582103729248,16, -linux_literal,1,5,rg (ignore) (mmap),rg -n --mmap PM_RESUME,0.807842493057251,16, -linux_literal,1,5,rg (ignore) (mmap),rg -n --mmap PM_RESUME,0.8129942417144775,16, -linux_literal,1,5,rg (ignore) (mmap),rg -n --mmap PM_RESUME,0.7582321166992188,16, -linux_literal,1,5,rg (ignore) (mmap),rg -n --mmap PM_RESUME,0.6869800090789795,16, -linux_literal,1,5,ag (ignore) (mmap),ag -s PM_RESUME,0.6534101963043213,16, -linux_literal,1,5,ag (ignore) (mmap),ag -s PM_RESUME,0.6020612716674805,16, -linux_literal,1,5,ag (ignore) (mmap),ag -s PM_RESUME,0.6712157726287842,16, -linux_literal,1,5,ag (ignore) (mmap),ag -s PM_RESUME,0.6267571449279785,16, -linux_literal,1,5,ag (ignore) (mmap),ag -s PM_RESUME,0.505136251449585,16, -linux_literal,1,5,pt (ignore),pt PM_RESUME,0.21415948867797852,16, -linux_literal,1,5,pt (ignore),pt PM_RESUME,0.19318318367004395,16, -linux_literal,1,5,pt (ignore),pt PM_RESUME,0.21352124214172363,16, -linux_literal,1,5,pt (ignore),pt PM_RESUME,0.18979454040527344,16, -linux_literal,1,5,pt (ignore),pt PM_RESUME,0.16629600524902344,16, -linux_literal,1,5,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git PM_RESUME,0.46967077255249023,16, -linux_literal,1,5,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git PM_RESUME,0.46343088150024414,16, -linux_literal,1,5,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git PM_RESUME,0.4723978042602539,16, -linux_literal,1,5,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git PM_RESUME,0.4741063117980957,16, -linux_literal,1,5,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git PM_RESUME,0.4613051414489746,16, -linux_literal,1,5,git grep (ignore),git grep -I -n PM_RESUME,0.20196986198425293,16,LC_ALL=C -linux_literal,1,5,git grep (ignore),git grep -I -n PM_RESUME,0.18932533264160156,16,LC_ALL=C -linux_literal,1,5,git grep (ignore),git grep -I -n PM_RESUME,0.19396305084228516,16,LC_ALL=C -linux_literal,1,5,git grep (ignore),git grep -I -n PM_RESUME,0.1952073574066162,16,LC_ALL=C -linux_literal,1,5,git grep (ignore),git grep -I -n PM_RESUME,0.20149731636047363,16,LC_ALL=C -linux_literal,1,5,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.08270478248596191,16, -linux_literal,1,5,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.08414745330810547,16, -linux_literal,1,5,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.08627724647521973,16, -linux_literal,1,5,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.08978700637817383,16, -linux_literal,1,5,rg (whitelist),rg -n --no-ignore -tall PM_RESUME,0.0836489200592041,16, -linux_literal,1,5,ucg (whitelist),ucg --nosmart-case PM_RESUME,0.15774202346801758,16, -linux_literal,1,5,ucg (whitelist),ucg --nosmart-case PM_RESUME,0.16005396842956543,16, -linux_literal,1,5,ucg (whitelist),ucg --nosmart-case PM_RESUME,0.15743708610534668,16, -linux_literal,1,5,ucg (whitelist),ucg --nosmart-case PM_RESUME,0.16156601905822754,16, -linux_literal,1,5,ucg (whitelist),ucg --nosmart-case PM_RESUME,0.1557624340057373,16, -linux_literal_casei,1,5,rg (ignore),rg -n -i PM_RESUME,0.1028127670288086,374, -linux_literal_casei,1,5,rg (ignore),rg -n -i PM_RESUME,0.10258054733276367,374, -linux_literal_casei,1,5,rg (ignore),rg -n -i PM_RESUME,0.10902261734008789,374, -linux_literal_casei,1,5,rg (ignore),rg -n -i PM_RESUME,0.10802555084228516,374, -linux_literal_casei,1,5,rg (ignore),rg -n -i PM_RESUME,0.10153412818908691,374, -linux_literal_casei,1,5,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,0.7902817726135254,374, -linux_literal_casei,1,5,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,0.7985179424285889,374, -linux_literal_casei,1,5,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,0.8208649158477783,374, -linux_literal_casei,1,5,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,0.7937076091766357,374, -linux_literal_casei,1,5,rg (ignore) (mmap),rg -n -i --mmap PM_RESUME,0.7936429977416992,374, -linux_literal_casei,1,5,ag (ignore) (mmap),ag -i PM_RESUME,0.5215470790863037,374, -linux_literal_casei,1,5,ag (ignore) (mmap),ag -i PM_RESUME,0.46518707275390625,374, -linux_literal_casei,1,5,ag (ignore) (mmap),ag -i PM_RESUME,0.4467353820800781,374, -linux_literal_casei,1,5,ag (ignore) (mmap),ag -i PM_RESUME,0.4595184326171875,374, -linux_literal_casei,1,5,ag (ignore) (mmap),ag -i PM_RESUME,0.4531285762786865,374, -linux_literal_casei,1,5,pt (ignore),pt -i PM_RESUME,14.187762022018433,374, -linux_literal_casei,1,5,pt (ignore),pt -i PM_RESUME,14.178058385848999,374, -linux_literal_casei,1,5,pt (ignore),pt -i PM_RESUME,14.096448421478271,374, -linux_literal_casei,1,5,pt (ignore),pt -i PM_RESUME,14.190524339675903,374, -linux_literal_casei,1,5,pt (ignore),pt -i PM_RESUME,14.231573343276978,374, -linux_literal_casei,1,5,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git PM_RESUME,0.4668574333190918,374, -linux_literal_casei,1,5,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git PM_RESUME,0.46050214767456055,374, -linux_literal_casei,1,5,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git PM_RESUME,0.46228861808776855,374, -linux_literal_casei,1,5,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git PM_RESUME,0.44957947731018066,374, -linux_literal_casei,1,5,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git PM_RESUME,0.4612581729888916,374, -linux_literal_casei,1,5,git grep (ignore),git grep -I -n -i PM_RESUME,0.1932981014251709,370,LC_ALL=C -linux_literal_casei,1,5,git grep (ignore),git grep -I -n -i PM_RESUME,0.20561552047729492,370,LC_ALL=C -linux_literal_casei,1,5,git grep (ignore),git grep -I -n -i PM_RESUME,0.19516706466674805,370,LC_ALL=C -linux_literal_casei,1,5,git grep (ignore),git grep -I -n -i PM_RESUME,0.20196247100830078,370,LC_ALL=C -linux_literal_casei,1,5,git grep (ignore),git grep -I -n -i PM_RESUME,0.19236421585083008,370,LC_ALL=C -linux_literal_casei,1,5,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.09555959701538086,370, -linux_literal_casei,1,5,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.09589338302612305,370, -linux_literal_casei,1,5,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.09479856491088867,370, -linux_literal_casei,1,5,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.09741568565368652,370, -linux_literal_casei,1,5,rg (whitelist),rg -n -i --no-ignore -tall PM_RESUME,0.10127615928649902,370, -linux_literal_casei,1,5,ucg (whitelist),ucg -i PM_RESUME,0.15514039993286133,370, -linux_literal_casei,1,5,ucg (whitelist),ucg -i PM_RESUME,0.15668940544128418,370, -linux_literal_casei,1,5,ucg (whitelist),ucg -i PM_RESUME,0.15429425239562988,370, -linux_literal_casei,1,5,ucg (whitelist),ucg -i PM_RESUME,0.15332818031311035,370, -linux_literal_casei,1,5,ucg (whitelist),ucg -i PM_RESUME,0.14861536026000977,370, -linux_literal_default,1,5,rg,rg PM_RESUME,0.08931398391723633,16, -linux_literal_default,1,5,rg,rg PM_RESUME,0.08717465400695801,16, -linux_literal_default,1,5,rg,rg PM_RESUME,0.0879361629486084,16, -linux_literal_default,1,5,rg,rg PM_RESUME,0.08688950538635254,16, -linux_literal_default,1,5,rg,rg PM_RESUME,0.09138607978820801,16, -linux_literal_default,1,5,ag,ag PM_RESUME,0.5342838764190674,16, -linux_literal_default,1,5,ag,ag PM_RESUME,0.47187042236328125,16, -linux_literal_default,1,5,ag,ag PM_RESUME,0.4456596374511719,16, -linux_literal_default,1,5,ag,ag PM_RESUME,0.4507424831390381,16, -linux_literal_default,1,5,ag,ag PM_RESUME,0.44472575187683105,16, -linux_literal_default,1,5,ucg,ucg PM_RESUME,0.15556907653808594,16, -linux_literal_default,1,5,ucg,ucg PM_RESUME,0.1533644199371338,16, -linux_literal_default,1,5,ucg,ucg PM_RESUME,0.15392351150512695,16, -linux_literal_default,1,5,ucg,ucg PM_RESUME,0.1535196304321289,16, -linux_literal_default,1,5,ucg,ucg PM_RESUME,0.15589547157287598,16, -linux_literal_default,1,5,pt,pt PM_RESUME,0.2261514663696289,16, -linux_literal_default,1,5,pt,pt PM_RESUME,0.2731902599334717,16, -linux_literal_default,1,5,pt,pt PM_RESUME,0.2563004493713379,16, -linux_literal_default,1,5,pt,pt PM_RESUME,0.2575085163116455,16, -linux_literal_default,1,5,pt,pt PM_RESUME,0.1724245548248291,16, -linux_literal_default,1,5,sift,sift PM_RESUME,0.13233542442321777,16, -linux_literal_default,1,5,sift,sift PM_RESUME,0.1256580352783203,16, -linux_literal_default,1,5,sift,sift PM_RESUME,0.12435102462768555,16, -linux_literal_default,1,5,sift,sift PM_RESUME,0.1259307861328125,16, -linux_literal_default,1,5,sift,sift PM_RESUME,0.12412142753601074,16, -linux_literal_default,1,5,git grep,git grep PM_RESUME,0.1742086410522461,16,LC_ALL=en_US.UTF-8 -linux_literal_default,1,5,git grep,git grep PM_RESUME,0.16890597343444824,16,LC_ALL=en_US.UTF-8 -linux_literal_default,1,5,git grep,git grep PM_RESUME,0.16680669784545898,16,LC_ALL=en_US.UTF-8 -linux_literal_default,1,5,git grep,git grep PM_RESUME,0.16899871826171875,16,LC_ALL=en_US.UTF-8 -linux_literal_default,1,5,git grep,git grep PM_RESUME,0.19794917106628418,16,LC_ALL=en_US.UTF-8 -linux_no_literal,1,5,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.33940672874450684,490, -linux_no_literal,1,5,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.3274960517883301,490, -linux_no_literal,1,5,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.32681775093078613,490, -linux_no_literal,1,5,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.32865071296691895,490, -linux_no_literal,1,5,rg (ignore),rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.3240926265716553,490, -linux_no_literal,1,5,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.17426586151123047,490, -linux_no_literal,1,5,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.17265701293945312,490, -linux_no_literal,1,5,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.1703634262084961,490, -linux_no_literal,1,5,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.17192435264587402,490, -linux_no_literal,1,5,rg (ignore) (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.1704559326171875,490, -linux_no_literal,1,5,ag (ignore) (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.8443403244018555,766, -linux_no_literal,1,5,ag (ignore) (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.6956703662872314,766, -linux_no_literal,1,5,ag (ignore) (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.6938261985778809,766, -linux_no_literal,1,5,ag (ignore) (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.695967435836792,766, -linux_no_literal,1,5,ag (ignore) (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.6945271492004395,766, -linux_no_literal,1,5,pt (ignore) (ASCII),pt -e \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},12.645716428756714,490, -linux_no_literal,1,5,pt (ignore) (ASCII),pt -e \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},12.441533088684082,490, -linux_no_literal,1,5,pt (ignore) (ASCII),pt -e \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},12.472522735595703,490, -linux_no_literal,1,5,pt (ignore) (ASCII),pt -e \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},12.42497444152832,490, -linux_no_literal,1,5,pt (ignore) (ASCII),pt -e \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},12.407486200332642,490, -linux_no_literal,1,5,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},9.091489553451538,490, -linux_no_literal,1,5,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},9.049214124679565,490, -linux_no_literal,1,5,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},8.879419803619385,490, -linux_no_literal,1,5,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},9.07261848449707,490, -linux_no_literal,1,5,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},8.918747901916504,490, -linux_no_literal,1,5,git grep (ignore),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},8.334321975708008,490,LC_ALL=en_US.UTF-8 -linux_no_literal,1,5,git grep (ignore),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},8.993232727050781,490,LC_ALL=en_US.UTF-8 -linux_no_literal,1,5,git grep (ignore),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},8.622304916381836,490,LC_ALL=en_US.UTF-8 -linux_no_literal,1,5,git grep (ignore),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},8.35973048210144,490,LC_ALL=en_US.UTF-8 -linux_no_literal,1,5,git grep (ignore),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},8.39980435371399,490,LC_ALL=en_US.UTF-8 -linux_no_literal,1,5,git grep (ignore) (ASCII),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},2.0318400859832764,490,LC_ALL=C -linux_no_literal,1,5,git grep (ignore) (ASCII),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},1.8587837219238281,490,LC_ALL=C -linux_no_literal,1,5,git grep (ignore) (ASCII),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},1.873384714126587,490,LC_ALL=C -linux_no_literal,1,5,git grep (ignore) (ASCII),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},1.8111364841461182,490,LC_ALL=C -linux_no_literal,1,5,git grep (ignore) (ASCII),git grep -E -I -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},1.8385357856750488,490,LC_ALL=C -linux_no_literal,1,5,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.28792643547058105,458, -linux_no_literal,1,5,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.28545212745666504,458, -linux_no_literal,1,5,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.28576135635375977,458, -linux_no_literal,1,5,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.29883813858032227,458, -linux_no_literal,1,5,rg (whitelist),rg -n --no-ignore -tall \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.28493285179138184,458, -linux_no_literal,1,5,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.15974783897399902,458, -linux_no_literal,1,5,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.15943312644958496,458, -linux_no_literal,1,5,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.160233736038208,458, -linux_no_literal,1,5,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.16201996803283691,458, -linux_no_literal,1,5,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.16033530235290527,458, -linux_no_literal,1,5,ucg (whitelist) (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.4639148712158203,416, -linux_no_literal,1,5,ucg (whitelist) (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.46042823791503906,416, -linux_no_literal,1,5,ucg (whitelist) (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.45925426483154297,416, -linux_no_literal,1,5,ucg (whitelist) (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.477064847946167,416, -linux_no_literal,1,5,ucg (whitelist) (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5},0.507554292678833,416, -linux_re_literal_suffix,1,5,rg (ignore),rg -n [A-Z]+_RESUME,0.08520364761352539,1652, -linux_re_literal_suffix,1,5,rg (ignore),rg -n [A-Z]+_RESUME,0.08203816413879395,1652, -linux_re_literal_suffix,1,5,rg (ignore),rg -n [A-Z]+_RESUME,0.08355021476745605,1652, -linux_re_literal_suffix,1,5,rg (ignore),rg -n [A-Z]+_RESUME,0.0865166187286377,1652, -linux_re_literal_suffix,1,5,rg (ignore),rg -n [A-Z]+_RESUME,0.08125448226928711,1652, -linux_re_literal_suffix,1,5,ag (ignore),ag -s [A-Z]+_RESUME,0.4846627712249756,1652, -linux_re_literal_suffix,1,5,ag (ignore),ag -s [A-Z]+_RESUME,0.48070311546325684,1652, -linux_re_literal_suffix,1,5,ag (ignore),ag -s [A-Z]+_RESUME,0.4813041687011719,1652, -linux_re_literal_suffix,1,5,ag (ignore),ag -s [A-Z]+_RESUME,0.4755582809448242,1652, -linux_re_literal_suffix,1,5,ag (ignore),ag -s [A-Z]+_RESUME,0.4926290512084961,1652, -linux_re_literal_suffix,1,5,pt (ignore),pt -e [A-Z]+_RESUME,14.124520540237427,1652, -linux_re_literal_suffix,1,5,pt (ignore),pt -e [A-Z]+_RESUME,14.151537656784058,1652, -linux_re_literal_suffix,1,5,pt (ignore),pt -e [A-Z]+_RESUME,14.157994270324707,1652, -linux_re_literal_suffix,1,5,pt (ignore),pt -e [A-Z]+_RESUME,14.102291822433472,1652, -linux_re_literal_suffix,1,5,pt (ignore),pt -e [A-Z]+_RESUME,14.103861093521118,1652, -linux_re_literal_suffix,1,5,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git [A-Z]+_RESUME,4.182392835617065,1652, -linux_re_literal_suffix,1,5,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git [A-Z]+_RESUME,4.190829277038574,1652, -linux_re_literal_suffix,1,5,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git [A-Z]+_RESUME,3.9770240783691406,1652, -linux_re_literal_suffix,1,5,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git [A-Z]+_RESUME,3.9978606700897217,1652, -linux_re_literal_suffix,1,5,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git [A-Z]+_RESUME,4.146454572677612,1652, -linux_re_literal_suffix,1,5,git grep (ignore),git grep -E -I -n [A-Z]+_RESUME,0.5080702304840088,1652,LC_ALL=C -linux_re_literal_suffix,1,5,git grep (ignore),git grep -E -I -n [A-Z]+_RESUME,0.5281260013580322,1652,LC_ALL=C -linux_re_literal_suffix,1,5,git grep (ignore),git grep -E -I -n [A-Z]+_RESUME,0.5350546836853027,1652,LC_ALL=C -linux_re_literal_suffix,1,5,git grep (ignore),git grep -E -I -n [A-Z]+_RESUME,0.5474245548248291,1652,LC_ALL=C -linux_re_literal_suffix,1,5,git grep (ignore),git grep -E -I -n [A-Z]+_RESUME,0.5256762504577637,1652,LC_ALL=C -linux_re_literal_suffix,1,5,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.07924222946166992,1630, -linux_re_literal_suffix,1,5,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.0767812728881836,1630, -linux_re_literal_suffix,1,5,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.07874488830566406,1630, -linux_re_literal_suffix,1,5,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.0804905891418457,1630, -linux_re_literal_suffix,1,5,rg (whitelist),rg -n --no-ignore -tall [A-Z]+_RESUME,0.07479119300842285,1630, -linux_re_literal_suffix,1,5,ucg (whitelist),ucg --nosmart-case [A-Z]+_RESUME,0.13643193244934082,1630, -linux_re_literal_suffix,1,5,ucg (whitelist),ucg --nosmart-case [A-Z]+_RESUME,0.13543128967285156,1630, -linux_re_literal_suffix,1,5,ucg (whitelist),ucg --nosmart-case [A-Z]+_RESUME,0.13312768936157227,1630, -linux_re_literal_suffix,1,5,ucg (whitelist),ucg --nosmart-case [A-Z]+_RESUME,0.13562273979187012,1630, -linux_re_literal_suffix,1,5,ucg (whitelist),ucg --nosmart-case [A-Z]+_RESUME,0.13236212730407715,1630, -linux_unicode_greek,1,5,rg,rg -n \p{Greek},0.17355775833129883,23, -linux_unicode_greek,1,5,rg,rg -n \p{Greek},0.1676032543182373,23, -linux_unicode_greek,1,5,rg,rg -n \p{Greek},0.1727275848388672,23, -linux_unicode_greek,1,5,rg,rg -n \p{Greek},0.17095375061035156,23, -linux_unicode_greek,1,5,rg,rg -n \p{Greek},0.17271947860717773,23, -linux_unicode_greek,1,5,pt,pt -e \p{Greek},14.14364218711853,23, -linux_unicode_greek,1,5,pt,pt -e \p{Greek},14.137334108352661,23, -linux_unicode_greek,1,5,pt,pt -e \p{Greek},14.083475351333618,23, -linux_unicode_greek,1,5,pt,pt -e \p{Greek},14.095231056213379,23, -linux_unicode_greek,1,5,pt,pt -e \p{Greek},14.151906490325928,23, -linux_unicode_greek,1,5,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \p{Greek},2.8376963138580322,23, -linux_unicode_greek,1,5,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \p{Greek},2.8271427154541016,23, -linux_unicode_greek,1,5,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \p{Greek},2.8310961723327637,23, -linux_unicode_greek,1,5,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \p{Greek},2.826141595840454,23, -linux_unicode_greek,1,5,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \p{Greek},2.805818796157837,23, -linux_unicode_greek_casei,1,5,rg,rg -n -i \p{Greek},0.16843819618225098,103, -linux_unicode_greek_casei,1,5,rg,rg -n -i \p{Greek},0.1704998016357422,103, -linux_unicode_greek_casei,1,5,rg,rg -n -i \p{Greek},0.17055058479309082,103, -linux_unicode_greek_casei,1,5,rg,rg -n -i \p{Greek},0.17064881324768066,103, -linux_unicode_greek_casei,1,5,rg,rg -n -i \p{Greek},0.1699228286743164,103, -linux_unicode_greek_casei,1,5,pt,pt -i -e \p{Greek},14.164355993270874,23, -linux_unicode_greek_casei,1,5,pt,pt -i -e \p{Greek},14.099931478500366,23, -linux_unicode_greek_casei,1,5,pt,pt -i -e \p{Greek},14.155095338821411,23, -linux_unicode_greek_casei,1,5,pt,pt -i -e \p{Greek},14.109308004379272,23, -linux_unicode_greek_casei,1,5,pt,pt -i -e \p{Greek},14.072362422943115,23, -linux_unicode_greek_casei,1,5,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git \p{Greek},0.003945589065551758,, -linux_unicode_greek_casei,1,5,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git \p{Greek},0.004189729690551758,, -linux_unicode_greek_casei,1,5,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git \p{Greek},0.0034589767456054688,, -linux_unicode_greek_casei,1,5,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git \p{Greek},0.003614187240600586,, -linux_unicode_greek_casei,1,5,sift,sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -i --git \p{Greek},0.003975629806518555,, -linux_unicode_word,1,5,rg (ignore),rg -n \wAh,0.09798526763916016,186, -linux_unicode_word,1,5,rg (ignore),rg -n \wAh,0.09575009346008301,186, -linux_unicode_word,1,5,rg (ignore),rg -n \wAh,0.10181760787963867,186, -linux_unicode_word,1,5,rg (ignore),rg -n \wAh,0.09650158882141113,186, -linux_unicode_word,1,5,rg (ignore),rg -n \wAh,0.09717488288879395,186, -linux_unicode_word,1,5,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.09417867660522461,174, -linux_unicode_word,1,5,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.09903812408447266,174, -linux_unicode_word,1,5,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.09407877922058105,174, -linux_unicode_word,1,5,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.09681963920593262,174, -linux_unicode_word,1,5,rg (ignore) (ASCII),rg -n (?-u)\wAh,0.09762454032897949,174, -linux_unicode_word,1,5,ag (ignore) (ASCII),ag -s \wAh,0.5779609680175781,174, -linux_unicode_word,1,5,ag (ignore) (ASCII),ag -s \wAh,0.635645866394043,174, -linux_unicode_word,1,5,ag (ignore) (ASCII),ag -s \wAh,0.6109263896942139,174, -linux_unicode_word,1,5,ag (ignore) (ASCII),ag -s \wAh,0.6260912418365479,174, -linux_unicode_word,1,5,ag (ignore) (ASCII),ag -s \wAh,0.6823546886444092,174, -linux_unicode_word,1,5,pt (ignore) (ASCII),pt -e \wAh,14.178487062454224,174, -linux_unicode_word,1,5,pt (ignore) (ASCII),pt -e \wAh,14.190000057220459,174, -linux_unicode_word,1,5,pt (ignore) (ASCII),pt -e \wAh,14.16363000869751,174, -linux_unicode_word,1,5,pt (ignore) (ASCII),pt -e \wAh,14.160430431365967,174, -linux_unicode_word,1,5,pt (ignore) (ASCII),pt -e \wAh,14.2189621925354,174, -linux_unicode_word,1,5,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \wAh,4.17629337310791,174, -linux_unicode_word,1,5,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \wAh,4.051238059997559,174, -linux_unicode_word,1,5,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \wAh,4.323853015899658,174, -linux_unicode_word,1,5,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \wAh,4.085661172866821,174, -linux_unicode_word,1,5,sift (ignore) (ASCII),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n --git \wAh,4.036486625671387,174, -linux_unicode_word,1,5,git grep (ignore),git grep -E -I -n \wAh,4.620476961135864,186,LC_ALL=en_US.UTF-8 -linux_unicode_word,1,5,git grep (ignore),git grep -E -I -n \wAh,4.536192417144775,186,LC_ALL=en_US.UTF-8 -linux_unicode_word,1,5,git grep (ignore),git grep -E -I -n \wAh,4.510494232177734,186,LC_ALL=en_US.UTF-8 -linux_unicode_word,1,5,git grep (ignore),git grep -E -I -n \wAh,6.001620769500732,186,LC_ALL=en_US.UTF-8 -linux_unicode_word,1,5,git grep (ignore),git grep -E -I -n \wAh,4.602652311325073,186,LC_ALL=en_US.UTF-8 -linux_unicode_word,1,5,git grep (ignore) (ASCII),git grep -E -I -n \wAh,1.3785994052886963,174,LC_ALL=C -linux_unicode_word,1,5,git grep (ignore) (ASCII),git grep -E -I -n \wAh,1.4163663387298584,174,LC_ALL=C -linux_unicode_word,1,5,git grep (ignore) (ASCII),git grep -E -I -n \wAh,1.402677297592163,174,LC_ALL=C -linux_unicode_word,1,5,git grep (ignore) (ASCII),git grep -E -I -n \wAh,1.3327512741088867,174,LC_ALL=C -linux_unicode_word,1,5,git grep (ignore) (ASCII),git grep -E -I -n \wAh,1.3501760959625244,174,LC_ALL=C -linux_unicode_word,1,5,rg (whitelist),rg -n --no-ignore -tall \wAh,0.07958698272705078,180, -linux_unicode_word,1,5,rg (whitelist),rg -n --no-ignore -tall \wAh,0.0798649787902832,180, -linux_unicode_word,1,5,rg (whitelist),rg -n --no-ignore -tall \wAh,0.08086204528808594,180, -linux_unicode_word,1,5,rg (whitelist),rg -n --no-ignore -tall \wAh,0.0814356803894043,180, -linux_unicode_word,1,5,rg (whitelist),rg -n --no-ignore -tall \wAh,0.08273720741271973,180, -linux_unicode_word,1,5,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.08280825614929199,168, -linux_unicode_word,1,5,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.08074021339416504,168, -linux_unicode_word,1,5,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.0821676254272461,168, -linux_unicode_word,1,5,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.07926368713378906,168, -linux_unicode_word,1,5,rg (whitelist) (ASCII),rg -n --no-ignore -tall (?-u)\wAh,0.08405280113220215,168, -linux_unicode_word,1,5,ucg (ASCII),ucg --nosmart-case \wAh,0.1545090675354004,168, -linux_unicode_word,1,5,ucg (ASCII),ucg --nosmart-case \wAh,0.1517190933227539,168, -linux_unicode_word,1,5,ucg (ASCII),ucg --nosmart-case \wAh,0.15704965591430664,168, -linux_unicode_word,1,5,ucg (ASCII),ucg --nosmart-case \wAh,0.15523767471313477,168, -linux_unicode_word,1,5,ucg (ASCII),ucg --nosmart-case \wAh,0.1582942008972168,168, -linux_word,1,5,rg (ignore),rg -n -w PM_RESUME,0.09102368354797363,6, -linux_word,1,5,rg (ignore),rg -n -w PM_RESUME,0.08986210823059082,6, -linux_word,1,5,rg (ignore),rg -n -w PM_RESUME,0.08989477157592773,6, -linux_word,1,5,rg (ignore),rg -n -w PM_RESUME,0.0895695686340332,6, -linux_word,1,5,rg (ignore),rg -n -w PM_RESUME,0.09547114372253418,6, -linux_word,1,5,ag (ignore),ag -s -w PM_RESUME,0.4948008060455322,6, -linux_word,1,5,ag (ignore),ag -s -w PM_RESUME,0.45710110664367676,6, -linux_word,1,5,ag (ignore),ag -s -w PM_RESUME,0.44803452491760254,6, -linux_word,1,5,ag (ignore),ag -s -w PM_RESUME,0.44779396057128906,6, -linux_word,1,5,ag (ignore),ag -s -w PM_RESUME,0.4563112258911133,6, -linux_word,1,5,pt (ignore),pt -w PM_RESUME,14.233235597610474,6, -linux_word,1,5,pt (ignore),pt -w PM_RESUME,14.277648687362671,6, -linux_word,1,5,pt (ignore),pt -w PM_RESUME,14.218127727508545,6, -linux_word,1,5,pt (ignore),pt -w PM_RESUME,14.171622037887573,6, -linux_word,1,5,pt (ignore),pt -w PM_RESUME,14.214240312576294,6, -linux_word,1,5,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -w --git PM_RESUME,3.1536731719970703,6, -linux_word,1,5,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -w --git PM_RESUME,3.2415099143981934,6, -linux_word,1,5,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -w --git PM_RESUME,3.2526626586914062,6, -linux_word,1,5,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -w --git PM_RESUME,3.2590816020965576,6, -linux_word,1,5,sift (ignore),sift --binary-skip --exclude-files .* --exclude-files *.pdf -n -w --git PM_RESUME,3.222473621368408,6, -linux_word,1,5,git grep (ignore),git grep -E -I -n -w PM_RESUME,0.16982412338256836,6,LC_ALL=C -linux_word,1,5,git grep (ignore),git grep -E -I -n -w PM_RESUME,0.16739583015441895,6,LC_ALL=C -linux_word,1,5,git grep (ignore),git grep -E -I -n -w PM_RESUME,0.16866540908813477,6,LC_ALL=C -linux_word,1,5,git grep (ignore),git grep -E -I -n -w PM_RESUME,0.18207120895385742,6,LC_ALL=C -linux_word,1,5,git grep (ignore),git grep -E -I -n -w PM_RESUME,0.17716264724731445,6,LC_ALL=C -linux_word,1,5,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.07490420341491699,6, -linux_word,1,5,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.07714152336120605,6, -linux_word,1,5,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.07552146911621094,6, -linux_word,1,5,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.07651710510253906,6, -linux_word,1,5,rg (whitelist),rg -n -w --no-ignore -tall PM_RESUME,0.0757131576538086,6, -linux_word,1,5,ucg (whitelist),ucg --nosmart-case -w PM_RESUME,0.1530015468597412,6, -linux_word,1,5,ucg (whitelist),ucg --nosmart-case -w PM_RESUME,0.15152239799499512,6, -linux_word,1,5,ucg (whitelist),ucg --nosmart-case -w PM_RESUME,0.1571195125579834,6, -linux_word,1,5,ucg (whitelist),ucg --nosmart-case -w PM_RESUME,0.15993595123291016,6, -linux_word,1,5,ucg (whitelist),ucg --nosmart-case -w PM_RESUME,0.15633797645568848,6, -subtitles_en_alternate,1,5,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.33371877670288086,848, -subtitles_en_alternate,1,5,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.3207988739013672,848, -subtitles_en_alternate,1,5,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.3301675319671631,848, -subtitles_en_alternate,1,5,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.29731154441833496,848, -subtitles_en_alternate,1,5,rg (lines),rg -n Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2711911201477051,848, -subtitles_en_alternate,1,5,ag (lines),ag -s Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.186570405960083,848, -subtitles_en_alternate,1,5,ag (lines),ag -s Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.1659939289093018,848, -subtitles_en_alternate,1,5,ag (lines),ag -s Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.187847137451172,848, -subtitles_en_alternate,1,5,ag (lines),ag -s Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.3522064685821533,848, -subtitles_en_alternate,1,5,ag (lines),ag -s Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.316105842590332,848, -subtitles_en_alternate,1,5,ucg (lines),ucg --nosmart-case Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.1400718688964844,848, -subtitles_en_alternate,1,5,ucg (lines),ucg --nosmart-case Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.1492774486541748,848, -subtitles_en_alternate,1,5,ucg (lines),ucg --nosmart-case Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.1337254047393799,848, -subtitles_en_alternate,1,5,ucg (lines),ucg --nosmart-case Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.1037378311157227,848, -subtitles_en_alternate,1,5,ucg (lines),ucg --nosmart-case Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.1312851905822754,848, -subtitles_en_alternate,1,5,grep (lines),grep -E -an Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.8294000625610352,848,LC_ALL=C -subtitles_en_alternate,1,5,grep (lines),grep -E -an Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.808884620666504,848,LC_ALL=C -subtitles_en_alternate,1,5,grep (lines),grep -E -an Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.8134734630584717,848,LC_ALL=C -subtitles_en_alternate,1,5,grep (lines),grep -E -an Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.8405649662017822,848,LC_ALL=C -subtitles_en_alternate,1,5,grep (lines),grep -E -an Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.8500289916992188,848,LC_ALL=C -subtitles_en_alternate,1,5,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.21175312995910645,848, -subtitles_en_alternate,1,5,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2118232250213623,848, -subtitles_en_alternate,1,5,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.21287035942077637,848, -subtitles_en_alternate,1,5,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.21167230606079102,848, -subtitles_en_alternate,1,5,rg,rg Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.28102636337280273,848, -subtitles_en_alternate,1,5,grep,grep -E -a Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.5029187202453613,848,LC_ALL=C -subtitles_en_alternate,1,5,grep,grep -E -a Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.49977445602417,848,LC_ALL=C -subtitles_en_alternate,1,5,grep,grep -E -a Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.508340835571289,848,LC_ALL=C -subtitles_en_alternate,1,5,grep,grep -E -a Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.5002548694610596,848,LC_ALL=C -subtitles_en_alternate,1,5,grep,grep -E -a Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.629526138305664,848,LC_ALL=C -subtitles_en_alternate_casei,1,5,ag (ASCII),ag -s -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,3.730497360229492,862, -subtitles_en_alternate_casei,1,5,ag (ASCII),ag -s -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,3.781018018722534,862, -subtitles_en_alternate_casei,1,5,ag (ASCII),ag -s -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,3.7858059406280518,862, -subtitles_en_alternate_casei,1,5,ag (ASCII),ag -s -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,3.7127914428710938,862, -subtitles_en_alternate_casei,1,5,ag (ASCII),ag -s -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,3.717308759689331,862, -subtitles_en_alternate_casei,1,5,ucg (ASCII),ucg -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.428208351135254,862, -subtitles_en_alternate_casei,1,5,ucg (ASCII),ucg -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.389420509338379,862, -subtitles_en_alternate_casei,1,5,ucg (ASCII),ucg -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.403301954269409,862, -subtitles_en_alternate_casei,1,5,ucg (ASCII),ucg -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.4691550731658936,862, -subtitles_en_alternate_casei,1,5,ucg (ASCII),ucg -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.4245004653930664,862, -subtitles_en_alternate_casei,1,5,grep (ASCII),grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.978189706802368,862,LC_ALL=C -subtitles_en_alternate_casei,1,5,grep (ASCII),grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.974303722381592,862,LC_ALL=C -subtitles_en_alternate_casei,1,5,grep (ASCII),grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.982886552810669,862,LC_ALL=C -subtitles_en_alternate_casei,1,5,grep (ASCII),grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.90018630027771,862,LC_ALL=C -subtitles_en_alternate_casei,1,5,grep (ASCII),grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,3.0078439712524414,862,LC_ALL=C -subtitles_en_alternate_casei,1,5,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.9129142761230469,862, -subtitles_en_alternate_casei,1,5,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.9066660404205322,862, -subtitles_en_alternate_casei,1,5,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.946380615234375,862, -subtitles_en_alternate_casei,1,5,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.9672930240631104,862, -subtitles_en_alternate_casei,1,5,rg,rg -n -i Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.028451919555664,862, -subtitles_en_alternate_casei,1,5,grep,grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.9427030086517334,862,LC_ALL=en_US.UTF-8 -subtitles_en_alternate_casei,1,5,grep,grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.938739061355591,862,LC_ALL=en_US.UTF-8 -subtitles_en_alternate_casei,1,5,grep,grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.921248435974121,862,LC_ALL=en_US.UTF-8 -subtitles_en_alternate_casei,1,5,grep,grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.9194068908691406,862,LC_ALL=en_US.UTF-8 -subtitles_en_alternate_casei,1,5,grep,grep -E -ani Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,2.917184829711914,862,LC_ALL=en_US.UTF-8 -subtitles_en_literal,1,5,rg,rg Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.12293672561645508,629, -subtitles_en_literal,1,5,rg,rg Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.1259000301361084,629, -subtitles_en_literal,1,5,rg,rg Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.12285709381103516,629, -subtitles_en_literal,1,5,rg,rg Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.12280964851379395,629, -subtitles_en_literal,1,5,rg,rg Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.1547396183013916,629, -subtitles_en_literal,1,5,rg (no mmap),rg --no-mmap Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.22011375427246094,629, -subtitles_en_literal,1,5,rg (no mmap),rg --no-mmap Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.23095202445983887,629, -subtitles_en_literal,1,5,rg (no mmap),rg --no-mmap Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2577846050262451,629, -subtitles_en_literal,1,5,rg (no mmap),rg --no-mmap Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2563819885253906,629, -subtitles_en_literal,1,5,rg (no mmap),rg --no-mmap Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.24869346618652344,629, -subtitles_en_literal,1,5,pt,pt -N Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.415337324142456,629, -subtitles_en_literal,1,5,pt,pt -N Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.4208543300628662,629, -subtitles_en_literal,1,5,pt,pt -N Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.416351079940796,629, -subtitles_en_literal,1,5,pt,pt -N Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.4270708560943604,629, -subtitles_en_literal,1,5,pt,pt -N Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.4243996143341064,629, -subtitles_en_literal,1,5,sift,sift Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2245020866394043,629, -subtitles_en_literal,1,5,sift,sift Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2382345199584961,629, -subtitles_en_literal,1,5,sift,sift Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.23533034324645996,629, -subtitles_en_literal,1,5,sift,sift Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2577829360961914,629, -subtitles_en_literal,1,5,sift,sift Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2599349021911621,629, -subtitles_en_literal,1,5,grep,grep -a Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.4733700752258301,629,LC_ALL=C -subtitles_en_literal,1,5,grep,grep -a Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.4598572254180908,629,LC_ALL=C -subtitles_en_literal,1,5,grep,grep -a Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.5303301811218262,629,LC_ALL=C -subtitles_en_literal,1,5,grep,grep -a Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.4775106906890869,629,LC_ALL=C -subtitles_en_literal,1,5,grep,grep -a Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.4881136417388916,629,LC_ALL=C -subtitles_en_literal,1,5,rg (lines),rg -n Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.20051789283752441,629, -subtitles_en_literal,1,5,rg (lines),rg -n Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.17326998710632324,629, -subtitles_en_literal,1,5,rg (lines),rg -n Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.20733428001403809,629, -subtitles_en_literal,1,5,rg (lines),rg -n Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.189713716506958,629, -subtitles_en_literal,1,5,rg (lines),rg -n Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.17817258834838867,629, -subtitles_en_literal,1,5,ag (lines),ag -s Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.5327835083007812,629, -subtitles_en_literal,1,5,ag (lines),ag -s Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.5411181449890137,629, -subtitles_en_literal,1,5,ag (lines),ag -s Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.600783109664917,629, -subtitles_en_literal,1,5,ag (lines),ag -s Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.5838911533355713,629, -subtitles_en_literal,1,5,ag (lines),ag -s Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.6051928997039795,629, -subtitles_en_literal,1,5,ucg (lines),ucg --nosmart-case Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.4090385437011719,629, -subtitles_en_literal,1,5,ucg (lines),ucg --nosmart-case Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.3816399574279785,629, -subtitles_en_literal,1,5,ucg (lines),ucg --nosmart-case Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.38033008575439453,629, -subtitles_en_literal,1,5,ucg (lines),ucg --nosmart-case Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.3731727600097656,629, -subtitles_en_literal,1,5,ucg (lines),ucg --nosmart-case Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.38796329498291016,629, -subtitles_en_literal,1,5,pt (lines),pt Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.4102630615234375,629, -subtitles_en_literal,1,5,pt (lines),pt Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.4137451648712158,629, -subtitles_en_literal,1,5,pt (lines),pt Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.4649333953857422,629, -subtitles_en_literal,1,5,pt (lines),pt Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.430387258529663,629, -subtitles_en_literal,1,5,pt (lines),pt Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.541991949081421,629, -subtitles_en_literal,1,5,sift (lines),sift -n Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.6231405735015869,629, -subtitles_en_literal,1,5,sift (lines),sift -n Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.5986526012420654,629, -subtitles_en_literal,1,5,sift (lines),sift -n Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.5821917057037354,629, -subtitles_en_literal,1,5,sift (lines),sift -n Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.6045489311218262,629, -subtitles_en_literal,1,5,sift (lines),sift -n Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.5986905097961426,629, -subtitles_en_literal,1,5,grep (lines),grep -an Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.8278565406799316,629,LC_ALL=C -subtitles_en_literal,1,5,grep (lines),grep -an Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.777052640914917,629,LC_ALL=C -subtitles_en_literal,1,5,grep (lines),grep -an Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.7619414329528809,629,LC_ALL=C -subtitles_en_literal,1,5,grep (lines),grep -an Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.8248744010925293,629,LC_ALL=C -subtitles_en_literal,1,5,grep (lines),grep -an Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.824932336807251,629,LC_ALL=C -subtitles_en_literal_casei,1,5,rg,rg -i Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.2718961238861084,642, -subtitles_en_literal_casei,1,5,rg,rg -i Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.27082157135009766,642, -subtitles_en_literal_casei,1,5,rg,rg -i Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.27086758613586426,642, -subtitles_en_literal_casei,1,5,rg,rg -i Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.274705171585083,642, -subtitles_en_literal_casei,1,5,rg,rg -i Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.3337059020996094,642, -subtitles_en_literal_casei,1,5,grep,grep -ai Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.9112112522125244,642,LC_ALL=en_US.UTF-8 -subtitles_en_literal_casei,1,5,grep,grep -ai Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.907888650894165,642,LC_ALL=en_US.UTF-8 -subtitles_en_literal_casei,1,5,grep,grep -ai Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.912668228149414,642,LC_ALL=en_US.UTF-8 -subtitles_en_literal_casei,1,5,grep,grep -ai Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.9082865715026855,642,LC_ALL=en_US.UTF-8 -subtitles_en_literal_casei,1,5,grep,grep -ai Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.9177796840667725,642,LC_ALL=en_US.UTF-8 -subtitles_en_literal_casei,1,5,grep (ASCII),grep -E -ai Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.6020669937133789,642,LC_ALL=C -subtitles_en_literal_casei,1,5,grep (ASCII),grep -E -ai Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.568228006362915,642,LC_ALL=C -subtitles_en_literal_casei,1,5,grep (ASCII),grep -E -ai Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.5648214817047119,642,LC_ALL=C -subtitles_en_literal_casei,1,5,grep (ASCII),grep -E -ai Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.5568234920501709,642,LC_ALL=C -subtitles_en_literal_casei,1,5,grep (ASCII),grep -E -ai Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.5588953495025635,642,LC_ALL=C -subtitles_en_literal_casei,1,5,rg (lines),rg -n -i Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.3486766815185547,642, -subtitles_en_literal_casei,1,5,rg (lines),rg -n -i Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.34010815620422363,642, -subtitles_en_literal_casei,1,5,rg (lines),rg -n -i Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.33849263191223145,642, -subtitles_en_literal_casei,1,5,rg (lines),rg -n -i Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.3917088508605957,642, -subtitles_en_literal_casei,1,5,rg (lines),rg -n -i Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.39266490936279297,642, -subtitles_en_literal_casei,1,5,ag (lines) (ASCII),ag -i Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.5564041137695312,642, -subtitles_en_literal_casei,1,5,ag (lines) (ASCII),ag -i Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.5533506870269775,642, -subtitles_en_literal_casei,1,5,ag (lines) (ASCII),ag -i Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.6205368041992188,642, -subtitles_en_literal_casei,1,5,ag (lines) (ASCII),ag -i Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.5530028343200684,642, -subtitles_en_literal_casei,1,5,ag (lines) (ASCII),ag -i Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.6189889907836914,642, -subtitles_en_literal_casei,1,5,ucg (lines) (ASCII),ucg -i Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.3834850788116455,642, -subtitles_en_literal_casei,1,5,ucg (lines) (ASCII),ucg -i Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.41916346549987793,642, -subtitles_en_literal_casei,1,5,ucg (lines) (ASCII),ucg -i Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.3895289897918701,642, -subtitles_en_literal_casei,1,5,ucg (lines) (ASCII),ucg -i Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.4278140068054199,642, -subtitles_en_literal_casei,1,5,ucg (lines) (ASCII),ucg -i Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.4013493061065674,642, -subtitles_en_literal_word,1,5,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.17953085899353027,629, -subtitles_en_literal_word,1,5,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.17679834365844727,629, -subtitles_en_literal_word,1,5,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.17448186874389648,629, -subtitles_en_literal_word,1,5,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.21117281913757324,629, -subtitles_en_literal_word,1,5,rg (ASCII),rg -n (?-u:\b)Sherlock Holmes(?-u:\b) /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.1848156452178955,629, -subtitles_en_literal_word,1,5,ag (ASCII),ag -sw Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.5236153602600098,629, -subtitles_en_literal_word,1,5,ag (ASCII),ag -sw Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.52512526512146,629, -subtitles_en_literal_word,1,5,ag (ASCII),ag -sw Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.5218794345855713,629, -subtitles_en_literal_word,1,5,ag (ASCII),ag -sw Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.5384306907653809,629, -subtitles_en_literal_word,1,5,ag (ASCII),ag -sw Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.5150353908538818,629, -subtitles_en_literal_word,1,5,ucg (ASCII),ucg --nosmart-case Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.3757903575897217,629, -subtitles_en_literal_word,1,5,ucg (ASCII),ucg --nosmart-case Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.3744041919708252,629, -subtitles_en_literal_word,1,5,ucg (ASCII),ucg --nosmart-case Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.37261366844177246,629, -subtitles_en_literal_word,1,5,ucg (ASCII),ucg --nosmart-case Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.40795230865478516,629, -subtitles_en_literal_word,1,5,ucg (ASCII),ucg --nosmart-case Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.3868849277496338,629, -subtitles_en_literal_word,1,5,grep (ASCII),grep -anw Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.8265349864959717,629,LC_ALL=C -subtitles_en_literal_word,1,5,grep (ASCII),grep -anw Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.8123743534088135,629,LC_ALL=C -subtitles_en_literal_word,1,5,grep (ASCII),grep -anw Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.7669925689697266,629,LC_ALL=C -subtitles_en_literal_word,1,5,grep (ASCII),grep -anw Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.766636848449707,629,LC_ALL=C -subtitles_en_literal_word,1,5,grep (ASCII),grep -anw Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.7665839195251465,629,LC_ALL=C -subtitles_en_literal_word,1,5,rg,rg -nw Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.1879115104675293,629, -subtitles_en_literal_word,1,5,rg,rg -nw Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.18082356452941895,629, -subtitles_en_literal_word,1,5,rg,rg -nw Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.18497347831726074,629, -subtitles_en_literal_word,1,5,rg,rg -nw Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.1769394874572754,629, -subtitles_en_literal_word,1,5,rg,rg -nw Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.1917715072631836,629, -subtitles_en_literal_word,1,5,grep,grep -anw Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.8192996978759766,629,LC_ALL=en_US.UTF-8 -subtitles_en_literal_word,1,5,grep,grep -anw Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.8193323612213135,629,LC_ALL=en_US.UTF-8 -subtitles_en_literal_word,1,5,grep,grep -anw Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.7837738990783691,629,LC_ALL=en_US.UTF-8 -subtitles_en_literal_word,1,5,grep,grep -anw Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.7639024257659912,629,LC_ALL=en_US.UTF-8 -subtitles_en_literal_word,1,5,grep,grep -anw Sherlock Holmes /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.7634689807891846,629,LC_ALL=en_US.UTF-8 -subtitles_en_no_literal,1,5,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.7922985553741455,13, -subtitles_en_no_literal,1,5,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.7885758876800537,13, -subtitles_en_no_literal,1,5,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.802325963973999,13, -subtitles_en_no_literal,1,5,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.792595386505127,13, -subtitles_en_no_literal,1,5,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.7909605503082275,13, -subtitles_en_no_literal,1,5,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.5903098583221436,13, -subtitles_en_no_literal,1,5,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.5982813835144043,13, -subtitles_en_no_literal,1,5,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.5926671028137207,13, -subtitles_en_no_literal,1,5,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.5976767539978027,13, -subtitles_en_no_literal,1,5,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.593153953552246,13, -subtitles_en_no_literal,1,5,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,6.614634275436401,48, -subtitles_en_no_literal,1,5,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,6.574857473373413,48, -subtitles_en_no_literal,1,5,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,6.54079270362854,48, -subtitles_en_no_literal,1,5,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,6.600660800933838,48, -subtitles_en_no_literal,1,5,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,6.531627178192139,48, -subtitles_en_no_literal,1,5,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,5.361133337020874,13, -subtitles_en_no_literal,1,5,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,5.456786870956421,13, -subtitles_en_no_literal,1,5,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,5.403071403503418,13, -subtitles_en_no_literal,1,5,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,5.398236274719238,13, -subtitles_en_no_literal,1,5,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,5.348573923110962,13, -subtitles_en_no_literal,1,5,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,3.5057969093322754,13,LC_ALL=C -subtitles_en_no_literal,1,5,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,3.4157862663269043,13,LC_ALL=C -subtitles_en_no_literal,1,5,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,3.471182346343994,13,LC_ALL=C -subtitles_en_no_literal,1,5,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,3.4590909481048584,13,LC_ALL=C -subtitles_en_no_literal,1,5,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,3.3759689331054688,13,LC_ALL=C -subtitles_en_surrounding_words,1,5,rg,rg -n \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.18518710136413574,317, -subtitles_en_surrounding_words,1,5,rg,rg -n \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.18791556358337402,317, -subtitles_en_surrounding_words,1,5,rg,rg -n \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.18598675727844238,317, -subtitles_en_surrounding_words,1,5,rg,rg -n \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.18552684783935547,317, -subtitles_en_surrounding_words,1,5,rg,rg -n \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.19262075424194336,317, -subtitles_en_surrounding_words,1,5,grep,grep -E -an \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.1321008205413818,317,LC_ALL=en_US.UTF-8 -subtitles_en_surrounding_words,1,5,grep,grep -E -an \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.0709969997406006,317,LC_ALL=en_US.UTF-8 -subtitles_en_surrounding_words,1,5,grep,grep -E -an \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.1117346286773682,317,LC_ALL=en_US.UTF-8 -subtitles_en_surrounding_words,1,5,grep,grep -E -an \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.0880234241485596,317,LC_ALL=en_US.UTF-8 -subtitles_en_surrounding_words,1,5,grep,grep -E -an \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.0745558738708496,317,LC_ALL=en_US.UTF-8 -subtitles_en_surrounding_words,1,5,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.1827528476715088,317, -subtitles_en_surrounding_words,1,5,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.18874144554138184,317, -subtitles_en_surrounding_words,1,5,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.17983436584472656,317, -subtitles_en_surrounding_words,1,5,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.18831133842468262,317, -subtitles_en_surrounding_words,1,5,rg (ASCII),rg -n (?-u)\w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,0.17810606956481934,317, -subtitles_en_surrounding_words,1,5,ag (ASCII),ag -s \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,4.5957207679748535,323, -subtitles_en_surrounding_words,1,5,ag (ASCII),ag -s \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,4.627211570739746,323, -subtitles_en_surrounding_words,1,5,ag (ASCII),ag -s \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,4.554431200027466,323, -subtitles_en_surrounding_words,1,5,ag (ASCII),ag -s \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,4.492656469345093,323, -subtitles_en_surrounding_words,1,5,ag (ASCII),ag -s \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,4.443558216094971,323, -subtitles_en_surrounding_words,1,5,ucg (ASCII),ucg --nosmart-case \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,3.522758722305298,317, -subtitles_en_surrounding_words,1,5,ucg (ASCII),ucg --nosmart-case \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,3.502918004989624,317, -subtitles_en_surrounding_words,1,5,ucg (ASCII),ucg --nosmart-case \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,3.6503307819366455,317, -subtitles_en_surrounding_words,1,5,ucg (ASCII),ucg --nosmart-case \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,3.58940052986145,317, -subtitles_en_surrounding_words,1,5,ucg (ASCII),ucg --nosmart-case \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,3.569624423980713,317, -subtitles_en_surrounding_words,1,5,grep (ASCII),grep -E -an \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.0672054290771484,317,LC_ALL=C -subtitles_en_surrounding_words,1,5,grep (ASCII),grep -E -an \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.0729331970214844,317,LC_ALL=C -subtitles_en_surrounding_words,1,5,grep (ASCII),grep -E -an \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.052501916885376,317,LC_ALL=C -subtitles_en_surrounding_words,1,5,grep (ASCII),grep -E -an \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.0711696147918701,317,LC_ALL=C -subtitles_en_surrounding_words,1,5,grep (ASCII),grep -E -an \w+\s+Holmes\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.sample.en,1.0863316059112549,317,LC_ALL=C -subtitles_ru_alternate,1,5,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.0312588214874268,691, -subtitles_ru_alternate,1,5,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.063939094543457,691, -subtitles_ru_alternate,1,5,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.0000121593475342,691, -subtitles_ru_alternate,1,5,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.9842438697814941,691, -subtitles_ru_alternate,1,5,rg (lines),rg -n Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.95733642578125,691, -subtitles_ru_alternate,1,5,ag (lines),ag -s Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.7781903743743896,691, -subtitles_ru_alternate,1,5,ag (lines),ag -s Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.861164093017578,691, -subtitles_ru_alternate,1,5,ag (lines),ag -s Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.8268885612487793,691, -subtitles_ru_alternate,1,5,ag (lines),ag -s Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.8621268272399902,691, -subtitles_ru_alternate,1,5,ag (lines),ag -s Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.8216166496276855,691, -subtitles_ru_alternate,1,5,ucg (lines),ucg --nosmart-case Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.0069098472595215,691, -subtitles_ru_alternate,1,5,ucg (lines),ucg --nosmart-case Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.025178909301758,691, -subtitles_ru_alternate,1,5,ucg (lines),ucg --nosmart-case Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.0631070137023926,691, -subtitles_ru_alternate,1,5,ucg (lines),ucg --nosmart-case Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.0902633666992188,691, -subtitles_ru_alternate,1,5,ucg (lines),ucg --nosmart-case Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.0272655487060547,691, -subtitles_ru_alternate,1,5,grep (lines),grep -E -an Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,7.510146617889404,691,LC_ALL=C -subtitles_ru_alternate,1,5,grep (lines),grep -E -an Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,7.541701793670654,691,LC_ALL=C -subtitles_ru_alternate,1,5,grep (lines),grep -E -an Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,7.506088733673096,691,LC_ALL=C -subtitles_ru_alternate,1,5,grep (lines),grep -E -an Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,7.51838755607605,691,LC_ALL=C -subtitles_ru_alternate,1,5,grep (lines),grep -E -an Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,7.486810684204102,691,LC_ALL=C -subtitles_ru_alternate,1,5,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.9679937362670898,691, -subtitles_ru_alternate,1,5,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.9942011833190918,691, -subtitles_ru_alternate,1,5,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.9233448505401611,691, -subtitles_ru_alternate,1,5,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.9294781684875488,691, -subtitles_ru_alternate,1,5,rg,rg Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.8729774951934814,691, -subtitles_ru_alternate,1,5,grep,grep -E -a Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,7.100147485733032,691,LC_ALL=C -subtitles_ru_alternate,1,5,grep,grep -E -a Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,7.075790166854858,691,LC_ALL=C -subtitles_ru_alternate,1,5,grep,grep -E -a Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,7.069685220718384,691,LC_ALL=C -subtitles_ru_alternate,1,5,grep,grep -E -a Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,7.0526063442230225,691,LC_ALL=C -subtitles_ru_alternate,1,5,grep,grep -E -a Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,7.129194498062134,691,LC_ALL=C -subtitles_ru_alternate_casei,1,5,ag (ASCII),ag -s -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.7894201278686523,691, -subtitles_ru_alternate_casei,1,5,ag (ASCII),ag -s -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.7878782749176025,691, -subtitles_ru_alternate_casei,1,5,ag (ASCII),ag -s -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.796328544616699,691, -subtitles_ru_alternate_casei,1,5,ag (ASCII),ag -s -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.8249149322509766,691, -subtitles_ru_alternate_casei,1,5,ag (ASCII),ag -s -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.7949724197387695,691, -subtitles_ru_alternate_casei,1,5,ucg (ASCII),ucg -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.075739622116089,691, -subtitles_ru_alternate_casei,1,5,ucg (ASCII),ucg -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.013590097427368,691, -subtitles_ru_alternate_casei,1,5,ucg (ASCII),ucg -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.012375593185425,691, -subtitles_ru_alternate_casei,1,5,ucg (ASCII),ucg -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.023118495941162,691, -subtitles_ru_alternate_casei,1,5,ucg (ASCII),ucg -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.0641982555389404,691, -subtitles_ru_alternate_casei,1,5,grep (ASCII),grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,7.467320442199707,691,LC_ALL=C -subtitles_ru_alternate_casei,1,5,grep (ASCII),grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,7.486851692199707,691,LC_ALL=C -subtitles_ru_alternate_casei,1,5,grep (ASCII),grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,7.479818344116211,691,LC_ALL=C -subtitles_ru_alternate_casei,1,5,grep (ASCII),grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,7.516186475753784,691,LC_ALL=C -subtitles_ru_alternate_casei,1,5,grep (ASCII),grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,7.471773862838745,691,LC_ALL=C -subtitles_ru_alternate_casei,1,5,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,11.026185274124146,735, -subtitles_ru_alternate_casei,1,5,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,11.168465614318848,735, -subtitles_ru_alternate_casei,1,5,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,11.039950370788574,735, -subtitles_ru_alternate_casei,1,5,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,11.089850425720215,735, -subtitles_ru_alternate_casei,1,5,rg,rg -n -i Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,11.112446546554565,735, -subtitles_ru_alternate_casei,1,5,grep,grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,6.822641849517822,735,LC_ALL=en_US.UTF-8 -subtitles_ru_alternate_casei,1,5,grep,grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,6.808355331420898,735,LC_ALL=en_US.UTF-8 -subtitles_ru_alternate_casei,1,5,grep,grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,6.80171275138855,735,LC_ALL=en_US.UTF-8 -subtitles_ru_alternate_casei,1,5,grep,grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,6.794351577758789,735,LC_ALL=en_US.UTF-8 -subtitles_ru_alternate_casei,1,5,grep,grep -E -ani Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,6.844403266906738,735,LC_ALL=en_US.UTF-8 -subtitles_ru_literal,1,5,rg,rg Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.20681476593017578,583, -subtitles_ru_literal,1,5,rg,rg Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.190568208694458,583, -subtitles_ru_literal,1,5,rg,rg Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.18462657928466797,583, -subtitles_ru_literal,1,5,rg,rg Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.1873643398284912,583, -subtitles_ru_literal,1,5,rg,rg Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.20382428169250488,583, -subtitles_ru_literal,1,5,rg (no mmap),rg --no-mmap Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3085510730743408,583, -subtitles_ru_literal,1,5,rg (no mmap),rg --no-mmap Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.318758487701416,583, -subtitles_ru_literal,1,5,rg (no mmap),rg --no-mmap Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3177149295806885,583, -subtitles_ru_literal,1,5,rg (no mmap),rg --no-mmap Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.31236958503723145,583, -subtitles_ru_literal,1,5,rg (no mmap),rg --no-mmap Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.31880998611450195,583, -subtitles_ru_literal,1,5,pt,pt -N Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,5.152938365936279,583, -subtitles_ru_literal,1,5,pt,pt -N Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,5.124867677688599,583, -subtitles_ru_literal,1,5,pt,pt -N Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,5.132290363311768,583, -subtitles_ru_literal,1,5,pt,pt -N Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,5.158328056335449,583, -subtitles_ru_literal,1,5,pt,pt -N Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,5.1022467613220215,583, -subtitles_ru_literal,1,5,sift,sift Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,5.807113409042358,583, -subtitles_ru_literal,1,5,sift,sift Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,5.8178558349609375,583, -subtitles_ru_literal,1,5,sift,sift Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,5.925220012664795,583, -subtitles_ru_literal,1,5,sift,sift Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,5.861236333847046,583, -subtitles_ru_literal,1,5,sift,sift Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,5.763278484344482,583, -subtitles_ru_literal,1,5,grep,grep -a Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.704503059387207,583,LC_ALL=C -subtitles_ru_literal,1,5,grep,grep -a Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.6887199878692627,583,LC_ALL=C -subtitles_ru_literal,1,5,grep,grep -a Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.7092702388763428,583,LC_ALL=C -subtitles_ru_literal,1,5,grep,grep -a Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.6964359283447266,583,LC_ALL=C -subtitles_ru_literal,1,5,grep,grep -a Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.6928379535675049,583,LC_ALL=C -subtitles_ru_literal,1,5,rg (lines),rg -n Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.2646975517272949,583, -subtitles_ru_literal,1,5,rg (lines),rg -n Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.26806163787841797,583, -subtitles_ru_literal,1,5,rg (lines),rg -n Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.2700214385986328,583, -subtitles_ru_literal,1,5,rg (lines),rg -n Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.2669072151184082,583, -subtitles_ru_literal,1,5,rg (lines),rg -n Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.2656106948852539,583, -subtitles_ru_literal,1,5,ag (lines),ag -s Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.9972407817840576,583, -subtitles_ru_literal,1,5,ag (lines),ag -s Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.906053066253662,583, -subtitles_ru_literal,1,5,ag (lines),ag -s Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.864766836166382,583, -subtitles_ru_literal,1,5,ag (lines),ag -s Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.7820546627044678,583, -subtitles_ru_literal,1,5,ag (lines),ag -s Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.7599871158599854,583, -subtitles_ru_literal,1,5,ucg (lines),ucg --nosmart-case Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.411653995513916,583, -subtitles_ru_literal,1,5,ucg (lines),ucg --nosmart-case Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.394604206085205,583, -subtitles_ru_literal,1,5,ucg (lines),ucg --nosmart-case Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.362853765487671,583, -subtitles_ru_literal,1,5,ucg (lines),ucg --nosmart-case Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.4795477390289307,583, -subtitles_ru_literal,1,5,ucg (lines),ucg --nosmart-case Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.4428844451904297,583, -subtitles_ru_literal,1,5,pt (lines),pt Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,5.122563123703003,583, -subtitles_ru_literal,1,5,pt (lines),pt Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,5.17008900642395,583, -subtitles_ru_literal,1,5,pt (lines),pt Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,5.1965367794036865,583, -subtitles_ru_literal,1,5,pt (lines),pt Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,5.152370929718018,583, -subtitles_ru_literal,1,5,pt (lines),pt Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,5.106513738632202,583, -subtitles_ru_literal,1,5,sift (lines),sift -n Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,6.408761978149414,583, -subtitles_ru_literal,1,5,sift (lines),sift -n Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,6.423579454421997,583, -subtitles_ru_literal,1,5,sift (lines),sift -n Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,6.2807464599609375,583, -subtitles_ru_literal,1,5,sift (lines),sift -n Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,6.3771467208862305,583, -subtitles_ru_literal,1,5,sift (lines),sift -n Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,6.378506422042847,583, -subtitles_ru_literal,1,5,grep (lines),grep -an Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.121800422668457,583,LC_ALL=C -subtitles_ru_literal,1,5,grep (lines),grep -an Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.1189923286437988,583,LC_ALL=C -subtitles_ru_literal,1,5,grep (lines),grep -an Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.0678138732910156,583,LC_ALL=C -subtitles_ru_literal,1,5,grep (lines),grep -an Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.0668041706085205,583,LC_ALL=C -subtitles_ru_literal,1,5,grep (lines),grep -an Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.0713574886322021,583,LC_ALL=C -subtitles_ru_literal_casei,1,5,rg,rg -i Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.9427816867828369,604, -subtitles_ru_literal_casei,1,5,rg,rg -i Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.0397350788116455,604, -subtitles_ru_literal_casei,1,5,rg,rg -i Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.9732518196105957,604, -subtitles_ru_literal_casei,1,5,rg,rg -i Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.9387776851654053,604, -subtitles_ru_literal_casei,1,5,rg,rg -i Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.9536802768707275,604, -subtitles_ru_literal_casei,1,5,grep,grep -ai Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,6.338641405105591,604,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_casei,1,5,grep,grep -ai Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,6.280565023422241,604,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_casei,1,5,grep,grep -ai Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,6.241750240325928,604,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_casei,1,5,grep,grep -ai Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,6.316105604171753,604,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_casei,1,5,grep,grep -ai Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,6.307560205459595,604,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_casei,1,5,grep (ASCII),grep -E -ai Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.7379302978515625,583,LC_ALL=C -subtitles_ru_literal_casei,1,5,grep (ASCII),grep -E -ai Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.7226619720458984,583,LC_ALL=C -subtitles_ru_literal_casei,1,5,grep (ASCII),grep -E -ai Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.683293342590332,583,LC_ALL=C -subtitles_ru_literal_casei,1,5,grep (ASCII),grep -E -ai Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.714146614074707,583,LC_ALL=C -subtitles_ru_literal_casei,1,5,grep (ASCII),grep -E -ai Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.7654330730438232,583,LC_ALL=C -subtitles_ru_literal_casei,1,5,rg (lines),rg -n -i Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.0237820148468018,604, -subtitles_ru_literal_casei,1,5,rg (lines),rg -n -i Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.0194151401519775,604, -subtitles_ru_literal_casei,1,5,rg (lines),rg -n -i Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.0364336967468262,604, -subtitles_ru_literal_casei,1,5,rg (lines),rg -n -i Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.035005807876587,604, -subtitles_ru_literal_casei,1,5,rg (lines),rg -n -i Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.0438766479492188,604, -subtitles_ru_literal_casei,1,5,ag (lines) (ASCII),ag -i Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.619025468826294,, -subtitles_ru_literal_casei,1,5,ag (lines) (ASCII),ag -i Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.647244930267334,, -subtitles_ru_literal_casei,1,5,ag (lines) (ASCII),ag -i Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.6785612106323242,, -subtitles_ru_literal_casei,1,5,ag (lines) (ASCII),ag -i Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.6503715515136719,, -subtitles_ru_literal_casei,1,5,ag (lines) (ASCII),ag -i Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.6314499378204346,, -subtitles_ru_literal_casei,1,5,ucg (lines) (ASCII),ucg -i Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.8302316665649414,583, -subtitles_ru_literal_casei,1,5,ucg (lines) (ASCII),ucg -i Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.7719593048095703,583, -subtitles_ru_literal_casei,1,5,ucg (lines) (ASCII),ucg -i Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.7697594165802002,583, -subtitles_ru_literal_casei,1,5,ucg (lines) (ASCII),ucg -i Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.7312629222869873,583, -subtitles_ru_literal_casei,1,5,ucg (lines) (ASCII),ucg -i Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.767866849899292,583, -subtitles_ru_literal_word,1,5,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.19411826133728027,, -subtitles_ru_literal_word,1,5,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.18651676177978516,, -subtitles_ru_literal_word,1,5,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.19614577293395996,, -subtitles_ru_literal_word,1,5,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.18459081649780273,, -subtitles_ru_literal_word,1,5,rg (ASCII),rg -n (?-u:\b)Шерлок Холмс(?-u:\b) /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.1797487735748291,, -subtitles_ru_literal_word,1,5,ag (ASCII),ag -sw Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.6507105827331543,, -subtitles_ru_literal_word,1,5,ag (ASCII),ag -sw Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.6480035781860352,, -subtitles_ru_literal_word,1,5,ag (ASCII),ag -sw Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.7138750553131104,, -subtitles_ru_literal_word,1,5,ag (ASCII),ag -sw Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.6521759033203125,, -subtitles_ru_literal_word,1,5,ag (ASCII),ag -sw Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.6728894710540771,, -subtitles_ru_literal_word,1,5,ucg (ASCII),ucg --nosmart-case Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.3646819591522217,583, -subtitles_ru_literal_word,1,5,ucg (ASCII),ucg --nosmart-case Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.3836848735809326,583, -subtitles_ru_literal_word,1,5,ucg (ASCII),ucg --nosmart-case Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.419490337371826,583, -subtitles_ru_literal_word,1,5,ucg (ASCII),ucg --nosmart-case Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.363335609436035,583, -subtitles_ru_literal_word,1,5,ucg (ASCII),ucg --nosmart-case Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.488351345062256,583, -subtitles_ru_literal_word,1,5,grep (ASCII),grep -anw Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.171506643295288,583,LC_ALL=C -subtitles_ru_literal_word,1,5,grep (ASCII),grep -anw Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.1602776050567627,583,LC_ALL=C -subtitles_ru_literal_word,1,5,grep (ASCII),grep -anw Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.084787368774414,583,LC_ALL=C -subtitles_ru_literal_word,1,5,grep (ASCII),grep -anw Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.0714166164398193,583,LC_ALL=C -subtitles_ru_literal_word,1,5,grep (ASCII),grep -anw Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.083632469177246,583,LC_ALL=C -subtitles_ru_literal_word,1,5,rg,rg -nw Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.2769143581390381,579, -subtitles_ru_literal_word,1,5,rg,rg -nw Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.2694058418273926,579, -subtitles_ru_literal_word,1,5,rg,rg -nw Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.26763367652893066,579, -subtitles_ru_literal_word,1,5,rg,rg -nw Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.2671318054199219,579, -subtitles_ru_literal_word,1,5,rg,rg -nw Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.2922348976135254,579, -subtitles_ru_literal_word,1,5,grep,grep -anw Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.083528757095337,579,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_word,1,5,grep,grep -anw Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.0857081413269043,579,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_word,1,5,grep,grep -anw Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.07025146484375,579,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_word,1,5,grep,grep -anw Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.071930170059204,579,LC_ALL=en_US.UTF-8 -subtitles_ru_literal_word,1,5,grep,grep -anw Шерлок Холмс /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.0709245204925537,579,LC_ALL=en_US.UTF-8 -subtitles_ru_no_literal,1,5,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.1552906036376953,41, -subtitles_ru_no_literal,1,5,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.164951801300049,41, -subtitles_ru_no_literal,1,5,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.175389289855957,41, -subtitles_ru_no_literal,1,5,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.1861774921417236,41, -subtitles_ru_no_literal,1,5,rg,rg -n \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,3.153625011444092,41, -subtitles_ru_no_literal,1,5,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.7353317737579346,, -subtitles_ru_no_literal,1,5,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.7592883110046387,, -subtitles_ru_no_literal,1,5,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.7242491245269775,, -subtitles_ru_no_literal,1,5,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.747089385986328,, -subtitles_ru_no_literal,1,5,rg (ASCII),rg -n (?-u)\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.732586145401001,, -subtitles_ru_no_literal,1,5,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.0796375274658203,, -subtitles_ru_no_literal,1,5,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.9670393466949463,, -subtitles_ru_no_literal,1,5,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.9413447380065918,, -subtitles_ru_no_literal,1,5,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.916764497756958,, -subtitles_ru_no_literal,1,5,ag (ASCII),ag -s \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.9110031127929688,, -subtitles_ru_no_literal,1,5,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.0622072219848633,, -subtitles_ru_no_literal,1,5,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.0975682735443115,, -subtitles_ru_no_literal,1,5,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.0741493701934814,, -subtitles_ru_no_literal,1,5,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.0423810482025146,, -subtitles_ru_no_literal,1,5,ucg (ASCII),ucg --nosmart-case \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.000764846801758,, -subtitles_ru_no_literal,1,5,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.6251120567321777,,LC_ALL=C -subtitles_ru_no_literal,1,5,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.644089698791504,,LC_ALL=C -subtitles_ru_no_literal,1,5,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.6416165828704834,,LC_ALL=C -subtitles_ru_no_literal,1,5,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.6321892738342285,,LC_ALL=C -subtitles_ru_no_literal,1,5,grep (ASCII),grep -E -an \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5} /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.6264762878417969,,LC_ALL=C -subtitles_ru_surrounding_words,1,5,rg,rg -n \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.29879307746887207,278, -subtitles_ru_surrounding_words,1,5,rg,rg -n \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.3226010799407959,278, -subtitles_ru_surrounding_words,1,5,rg,rg -n \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.32187771797180176,278, -subtitles_ru_surrounding_words,1,5,rg,rg -n \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.2825047969818115,278, -subtitles_ru_surrounding_words,1,5,rg,rg -n \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,0.283217191696167,278, -subtitles_ru_surrounding_words,1,5,grep,grep -E -an \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.3977878093719482,278,LC_ALL=en_US.UTF-8 -subtitles_ru_surrounding_words,1,5,grep,grep -E -an \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.4288139343261719,278,LC_ALL=en_US.UTF-8 -subtitles_ru_surrounding_words,1,5,grep,grep -E -an \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.4054889678955078,278,LC_ALL=en_US.UTF-8 -subtitles_ru_surrounding_words,1,5,grep,grep -E -an \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.4003441333770752,278,LC_ALL=en_US.UTF-8 -subtitles_ru_surrounding_words,1,5,grep,grep -E -an \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.5269148349761963,278,LC_ALL=en_US.UTF-8 -subtitles_ru_surrounding_words,1,5,ag (ASCII),ag -s \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.8912529945373535,, -subtitles_ru_surrounding_words,1,5,ag (ASCII),ag -s \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.9221522808074951,, -subtitles_ru_surrounding_words,1,5,ag (ASCII),ag -s \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.9416618347167969,, -subtitles_ru_surrounding_words,1,5,ag (ASCII),ag -s \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.893650770187378,, -subtitles_ru_surrounding_words,1,5,ag (ASCII),ag -s \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.8895554542541504,, -subtitles_ru_surrounding_words,1,5,ucg (ASCII),ucg --nosmart-case \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.0110745429992676,, -subtitles_ru_surrounding_words,1,5,ucg (ASCII),ucg --nosmart-case \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.9790067672729492,, -subtitles_ru_surrounding_words,1,5,ucg (ASCII),ucg --nosmart-case \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.0426392555236816,, -subtitles_ru_surrounding_words,1,5,ucg (ASCII),ucg --nosmart-case \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.121723175048828,, -subtitles_ru_surrounding_words,1,5,ucg (ASCII),ucg --nosmart-case \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,2.1247596740722656,, -subtitles_ru_surrounding_words,1,5,grep (ASCII),grep -E -an \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.3579976558685303,,LC_ALL=C -subtitles_ru_surrounding_words,1,5,grep (ASCII),grep -E -an \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.382859468460083,,LC_ALL=C -subtitles_ru_surrounding_words,1,5,grep (ASCII),grep -E -an \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.393401861190796,,LC_ALL=C -subtitles_ru_surrounding_words,1,5,grep (ASCII),grep -E -an \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.474374532699585,,LC_ALL=C -subtitles_ru_surrounding_words,1,5,grep (ASCII),grep -E -an \w+\s+Холмс\s+\w+ /tmp/benchsuite/subtitles/OpenSubtitles2016.raw.ru,1.3835601806640625,,LC_ALL=C diff --git a/benchsuite/runs/2018-01-08-archlinux-cheetah/summary b/benchsuite/runs/2018-01-08-archlinux-cheetah/summary deleted file mode 100644 index 348c0d6..0000000 --- a/benchsuite/runs/2018-01-08-archlinux-cheetah/summary +++ /dev/null @@ -1,235 +0,0 @@ -linux_alternates (pattern: ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT) -------------------------------------------------------------------------- -rg (ignore) 0.100 +/- 0.003 (lines: 68) -ag (ignore) 0.501 +/- 0.033 (lines: 68) -git grep (ignore) 0.267 +/- 0.004 (lines: 68) -rg (whitelist)* 0.090 +/- 0.001 (lines: 68)* -ucg (whitelist) 0.135 +/- 0.003 (lines: 68) - -linux_alternates_casei (pattern: ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT) -------------------------------------------------------------------------------- -rg (ignore) 0.124 +/- 0.004 (lines: 160) -ag (ignore) 0.564 +/- 0.041 (lines: 160) -git grep (ignore) 0.928 +/- 0.033 (lines: 160) -rg (whitelist)* 0.096 +/- 0.003 (lines: 160)* -ucg (whitelist) 0.248 +/- 0.008 (lines: 160) - -linux_literal (pattern: PM_RESUME) ----------------------------------- -rg (ignore)* 0.082 +/- 0.001 (lines: 16)* -rg (ignore) (mmap) 0.751 +/- 0.062 (lines: 16) -ag (ignore) (mmap) 0.612 +/- 0.065 (lines: 16) -pt (ignore) 0.195 +/- 0.020 (lines: 16) -sift (ignore) 0.468 +/- 0.006 (lines: 16) -git grep (ignore) 0.196 +/- 0.005 (lines: 16) -rg (whitelist) 0.085 +/- 0.003 (lines: 16) -ucg (whitelist) 0.159 +/- 0.002 (lines: 16) - -linux_literal_casei (pattern: PM_RESUME) ----------------------------------------- -rg (ignore) 0.105 +/- 0.003 (lines: 374) -rg (ignore) (mmap) 0.799 +/- 0.012 (lines: 374) -ag (ignore) (mmap) 0.469 +/- 0.030 (lines: 374) -pt (ignore) 14.177 +/- 0.049 (lines: 374) -sift (ignore) 0.460 +/- 0.006 (lines: 374) -git grep (ignore) 0.198 +/- 0.006 (lines: 370) -rg (whitelist)* 0.097 +/- 0.003 (lines: 370)* -ucg (whitelist) 0.154 +/- 0.003 (lines: 370) - -linux_literal_default (pattern: PM_RESUME) ------------------------------------------- -rg* 0.089 +/- 0.002 (lines: 16)* -ag 0.469 +/- 0.038 (lines: 16) -ucg 0.154 +/- 0.001 (lines: 16) -pt 0.237 +/- 0.040 (lines: 16) -sift 0.126 +/- 0.003 (lines: 16) -git grep 0.175 +/- 0.013 (lines: 16) - -linux_no_literal (pattern: \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}) ------------------------------------------------------------------ -rg (ignore) 0.329 +/- 0.006 (lines: 490) -rg (ignore) (ASCII) 0.172 +/- 0.002 (lines: 490) -ag (ignore) (ASCII) 0.725 +/- 0.067 (lines: 766) -pt (ignore) (ASCII) 12.478 +/- 0.097 (lines: 490) -sift (ignore) (ASCII) 9.002 +/- 0.096 (lines: 490) -git grep (ignore) 8.542 +/- 0.277 (lines: 490) -git grep (ignore) (ASCII) 1.883 +/- 0.087 (lines: 490) -rg (whitelist) 0.289 +/- 0.006 (lines: 458) -rg (whitelist) (ASCII)* 0.160 +/- 0.001 (lines: 458)* -ucg (whitelist) (ASCII) 0.474 +/- 0.020 (lines: 416) - -linux_re_literal_suffix (pattern: [A-Z]+_RESUME) ------------------------------------------------- -rg (ignore) 0.084 +/- 0.002 (lines: 1652) -ag (ignore) 0.483 +/- 0.006 (lines: 1652) -pt (ignore) 14.128 +/- 0.026 (lines: 1652) -sift (ignore) 4.099 +/- 0.103 (lines: 1652) -git grep (ignore) 0.529 +/- 0.014 (lines: 1652) -rg (whitelist)* 0.078 +/- 0.002 (lines: 1630)* -ucg (whitelist) 0.135 +/- 0.002 (lines: 1630) - -linux_unicode_greek (pattern: \p{Greek}) ----------------------------------------- -rg* 0.172 +/- 0.002 (lines: 23)* -pt 14.122 +/- 0.031 (lines: 23) -sift 2.826 +/- 0.012 (lines: 23) - -linux_unicode_greek_casei (pattern: \p{Greek}) ----------------------------------------------- -rg 0.170 +/- 0.001 (lines: 103) -pt 14.120 +/- 0.039 (lines: 23) -sift* 0.004 +/- 0.000 (lines: 0)* - -linux_unicode_word (pattern: \wAh) ----------------------------------- -rg (ignore) 0.098 +/- 0.002 (lines: 186) -rg (ignore) (ASCII) 0.096 +/- 0.002 (lines: 174) -ag (ignore) (ASCII) 0.627 +/- 0.038 (lines: 174) -pt (ignore) (ASCII) 14.182 +/- 0.024 (lines: 174) -sift (ignore) (ASCII) 4.135 +/- 0.119 (lines: 174) -git grep (ignore) 4.854 +/- 0.643 (lines: 186) -git grep (ignore) (ASCII) 1.376 +/- 0.035 (lines: 174) -rg (whitelist) 0.081 +/- 0.001 (lines: 180)* -rg (whitelist) (ASCII)* 0.082 +/- 0.002 (lines: 168) -ucg (ASCII) 0.155 +/- 0.003 (lines: 168) - -linux_word (pattern: PM_RESUME) -------------------------------- -rg (ignore) 0.091 +/- 0.002 (lines: 6) -ag (ignore) 0.461 +/- 0.020 (lines: 6) -pt (ignore) 14.223 +/- 0.038 (lines: 6) -sift (ignore) 3.226 +/- 0.043 (lines: 6) -git grep (ignore) 0.173 +/- 0.006 (lines: 6) -rg (whitelist)* 0.076 +/- 0.001 (lines: 6)* -ucg (whitelist) 0.156 +/- 0.003 (lines: 6) - -subtitles_en_alternate (pattern: Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty) ---------------------------------------------------------------------------------------------------------------- -rg (lines) 0.311 +/- 0.026 (lines: 848) -ag (lines) 2.242 +/- 0.086 (lines: 848) -ucg (lines) 1.132 +/- 0.017 (lines: 848) -grep (lines) 1.828 +/- 0.017 (lines: 848) -rg* 0.226 +/- 0.031 (lines: 848)* -grep 1.528 +/- 0.057 (lines: 848) - -subtitles_en_alternate_casei (pattern: Sherlock Holmes|John Watson|Irene Adler|Inspector Lestrade|Professor Moriarty) ---------------------------------------------------------------------------------------------------------------------- -ag (ASCII) 3.745 +/- 0.035 (lines: 862) -ucg (ASCII) 2.423 +/- 0.030 (lines: 862) -grep (ASCII) 2.969 +/- 0.040 (lines: 862) -rg* 1.952 +/- 0.049 (lines: 862)* -grep 2.928 +/- 0.012 (lines: 862) - -subtitles_en_literal (pattern: Sherlock Holmes) ------------------------------------------------ -rg* 0.130 +/- 0.014 (lines: 629)* -rg (no mmap) 0.243 +/- 0.017 (lines: 629) -pt 1.421 +/- 0.005 (lines: 629) -sift 0.243 +/- 0.015 (lines: 629) -grep 0.486 +/- 0.027 (lines: 629) -rg (lines) 0.190 +/- 0.014 (lines: 629) -ag (lines) 1.573 +/- 0.034 (lines: 629) -ucg (lines) 0.386 +/- 0.014 (lines: 629) -pt (lines) 1.452 +/- 0.055 (lines: 629) -sift (lines) 0.601 +/- 0.015 (lines: 629) -grep (lines) 0.803 +/- 0.031 (lines: 629) - -subtitles_en_literal_casei (pattern: Sherlock Holmes) ------------------------------------------------------ -rg* 0.284 +/- 0.028 (lines: 642)* -grep 1.912 +/- 0.004 (lines: 642) -grep (ASCII) 0.570 +/- 0.018 (lines: 642) -rg (lines) 0.362 +/- 0.028 (lines: 642) -ag (lines) (ASCII) 1.580 +/- 0.036 (lines: 642) -ucg (lines) (ASCII) 0.404 +/- 0.019 (lines: 642) - -subtitles_en_literal_word (pattern: Sherlock Holmes) ----------------------------------------------------- -rg (ASCII)* 0.185 +/- 0.015 (lines: 629) -ag (ASCII) 1.525 +/- 0.009 (lines: 629) -ucg (ASCII) 0.384 +/- 0.015 (lines: 629) -grep (ASCII) 0.788 +/- 0.029 (lines: 629) -rg 0.184 +/- 0.006 (lines: 629)* -grep 0.790 +/- 0.028 (lines: 629) - -subtitles_en_no_literal (pattern: \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}) ----------------------------------------------------------------------------------------- -rg 1.793 +/- 0.005 (lines: 13) -rg (ASCII)* 1.594 +/- 0.003 (lines: 13)* -ag (ASCII) 6.573 +/- 0.036 (lines: 48) -ucg (ASCII) 5.394 +/- 0.042 (lines: 13) -grep (ASCII) 3.446 +/- 0.050 (lines: 13) - -subtitles_en_surrounding_words (pattern: \w+\s+Holmes\s+\w+) ------------------------------------------------------------- -rg 0.187 +/- 0.003 (lines: 317) -grep 1.095 +/- 0.026 (lines: 317) -rg (ASCII)* 0.184 +/- 0.005 (lines: 317)* -ag (ASCII) 4.543 +/- 0.075 (lines: 323) -ucg (ASCII) 3.567 +/- 0.058 (lines: 317) -grep (ASCII) 1.070 +/- 0.012 (lines: 317) - -subtitles_ru_alternate (pattern: Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти) ------------------------------------------------------------------------------------------------------------ -rg (lines) 1.007 +/- 0.041 (lines: 691) -ag (lines) 3.830 +/- 0.035 (lines: 691) -ucg (lines) 2.043 +/- 0.034 (lines: 691) -grep (lines) 7.513 +/- 0.020 (lines: 691) -rg* 0.938 +/- 0.046 (lines: 691)* -grep 7.085 +/- 0.030 (lines: 691) - -subtitles_ru_alternate_casei (pattern: Шерлок Холмс|Джон Уотсон|Ирен Адлер|инспектор Лестрейд|профессор Мориарти) ------------------------------------------------------------------------------------------------------------------ -ag (ASCII) 3.799 +/- 0.015 (lines: 691) -ucg (ASCII)* 2.038 +/- 0.030 (lines: 691)* -grep (ASCII) 7.484 +/- 0.019 (lines: 691) -rg 11.087 +/- 0.057 (lines: 735) -grep 6.814 +/- 0.020 (lines: 735) - -subtitles_ru_literal (pattern: Шерлок Холмс) --------------------------------------------- -rg* 0.195 +/- 0.010 (lines: 583)* -rg (no mmap) 0.315 +/- 0.005 (lines: 583) -pt 5.134 +/- 0.023 (lines: 583) -sift 5.835 +/- 0.061 (lines: 583) -grep 0.698 +/- 0.008 (lines: 583) -rg (lines) 0.267 +/- 0.002 (lines: 583) -ag (lines) 2.862 +/- 0.096 (lines: 583) -ucg (lines) 2.418 +/- 0.045 (lines: 583) -pt (lines) 5.150 +/- 0.036 (lines: 583) -sift (lines) 6.374 +/- 0.056 (lines: 583) -grep (lines) 1.089 +/- 0.028 (lines: 583) - -subtitles_ru_literal_casei (pattern: Шерлок Холмс) --------------------------------------------------- -rg 0.970 +/- 0.041 (lines: 604) -grep 6.297 +/- 0.037 (lines: 604) -grep (ASCII) 0.725 +/- 0.030 (lines: 583) -rg (lines) 1.032 +/- 0.010 (lines: 604) -ag (lines) (ASCII)* 0.645 +/- 0.022 (lines: 0)* -ucg (lines) (ASCII) 0.774 +/- 0.036 (lines: 583) - -subtitles_ru_literal_word (pattern: Шерлок Холмс) -------------------------------------------------- -rg (ASCII)* 0.188 +/- 0.007 (lines: 0)* -ag (ASCII) 0.668 +/- 0.028 (lines: 0) -ucg (ASCII) 2.404 +/- 0.052 (lines: 583) -grep (ASCII) 1.114 +/- 0.048 (lines: 583) -rg 0.275 +/- 0.011 (lines: 579) -grep 1.076 +/- 0.008 (lines: 579) - -subtitles_ru_no_literal (pattern: \w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}\s+\w{5}) ----------------------------------------------------------------------------------------- -rg 3.167 +/- 0.014 (lines: 41) -rg (ASCII) 2.740 +/- 0.014 (lines: 0) -ag (ASCII) 1.963 +/- 0.069 (lines: 0) -ucg (ASCII) 2.055 +/- 0.037 (lines: 0) -grep (ASCII)* 1.634 +/- 0.009 (lines: 0)* - -subtitles_ru_surrounding_words (pattern: \w+\s+Холмс\s+\w+) ------------------------------------------------------------ -rg* 0.302 +/- 0.020 (lines: 278)* -grep 1.432 +/- 0.055 (lines: 278) -ag (ASCII) 1.908 +/- 0.023 (lines: 0) -ucg (ASCII) 2.056 +/- 0.066 (lines: 0) -grep (ASCII) 1.398 +/- 0.044 (lines: 0) diff --git a/build.rs b/build.rs deleted file mode 100644 index b7f26f1..0000000 --- a/build.rs +++ /dev/null @@ -1,184 +0,0 @@ -#[macro_use] -extern crate clap; -#[macro_use] -extern crate lazy_static; - -use std::env; -use std::fs::{self, File}; -use std::io::{self, Read, Write}; -use std::path::Path; -use std::process; - -use clap::Shell; - -use app::{RGArg, RGArgKind}; - -#[allow(dead_code)] -#[path = "src/app.rs"] -mod app; - -fn main() { - // OUT_DIR is set by Cargo and it's where any additional build artifacts - // are written. - let outdir = match env::var_os("OUT_DIR") { - Some(outdir) => outdir, - None => { - eprintln!( - "OUT_DIR environment variable not defined. \ - Please file a bug: \ - https://github.com/BurntSushi/ripgrep/issues/new"); - process::exit(1); - } - }; - fs::create_dir_all(&outdir).unwrap(); - - let stamp_path = Path::new(&outdir).join("ripgrep-stamp"); - if let Err(err) = File::create(&stamp_path) { - panic!("failed to write {}: {}", stamp_path.display(), err); - } - if let Err(err) = generate_man_page(&outdir) { - eprintln!("failed to generate man page: {}", err); - } - - // Use clap to build completion files. - let mut app = app::app(); - app.gen_completions("rg", Shell::Bash, &outdir); - app.gen_completions("rg", Shell::Fish, &outdir); - app.gen_completions("rg", Shell::PowerShell, &outdir); - // Note that we do not use clap's support for zsh. Instead, zsh completions - // are manually maintained in `complete/_rg`. - - // Make the current git hash available to the build. - if let Some(rev) = git_revision_hash() { - println!("cargo:rustc-env=RIPGREP_BUILD_GIT_HASH={}", rev); - } -} - -fn git_revision_hash() -> Option { - let result = process::Command::new("git") - .args(&["rev-parse", "--short=10", "HEAD"]) - .output(); - result.ok().and_then(|output| { - let v = String::from_utf8_lossy(&output.stdout).trim().to_string(); - if v.is_empty() { - None - } else { - Some(v) - } - }) -} - -fn generate_man_page>(outdir: P) -> io::Result<()> { - // If asciidoc isn't installed, then don't do anything. - if let Err(err) = process::Command::new("a2x").output() { - eprintln!("Could not run 'a2x' binary, skipping man page generation."); - eprintln!("Error from running 'a2x': {}", err); - return Ok(()); - } - // 1. Read asciidoc template. - // 2. Interpolate template with auto-generated docs. - // 3. Save interpolation to disk. - // 4. Use a2x (part of asciidoc) to convert to man page. - let outdir = outdir.as_ref(); - let cwd = env::current_dir()?; - let tpl_path = cwd.join("doc").join("rg.1.txt.tpl"); - let txt_path = outdir.join("rg.1.txt"); - - let mut tpl = String::new(); - File::open(&tpl_path)?.read_to_string(&mut tpl)?; - tpl = tpl.replace("{OPTIONS}", &formatted_options()?); - - let githash = git_revision_hash(); - let githash = githash.as_ref().map(|x| &**x); - tpl = tpl.replace("{VERSION}", &app::long_version(githash)); - - File::create(&txt_path)?.write_all(tpl.as_bytes())?; - let result = process::Command::new("a2x") - .arg("--no-xmllint") - .arg("--doctype").arg("manpage") - .arg("--format").arg("manpage") - .arg(&txt_path) - .spawn()? - .wait()?; - if !result.success() { - let msg = format!("'a2x' failed with exit code {:?}", result.code()); - return Err(ioerr(msg)); - } - Ok(()) -} - -fn formatted_options() -> io::Result { - let mut args = app::all_args_and_flags(); - args.sort_by(|x1, x2| x1.name.cmp(&x2.name)); - - let mut formatted = vec![]; - for arg in args { - if arg.hidden { - continue; - } - // ripgrep only has two positional arguments, and probably will only - // ever have two positional arguments, so we just hardcode them into - // the template. - if let app::RGArgKind::Positional{..} = arg.kind { - continue; - } - formatted.push(formatted_arg(&arg)?); - } - Ok(formatted.join("\n\n")) -} - -fn formatted_arg(arg: &RGArg) -> io::Result { - match arg.kind { - RGArgKind::Positional{..} => panic!("unexpected positional argument"), - RGArgKind::Switch { long, short, multiple } => { - let mut out = vec![]; - - let mut header = format!("--{}", long); - if let Some(short) = short { - header = format!("-{}, {}", short, header); - } - if multiple { - header = format!("*{}* ...::", header); - } else { - header = format!("*{}*::", header); - } - writeln!(out, "{}", header)?; - writeln!(out, "{}", formatted_doc_txt(arg)?)?; - - Ok(String::from_utf8(out).unwrap()) - } - RGArgKind::Flag { long, short, value_name, multiple, .. } => { - let mut out = vec![]; - - let mut header = format!("--{}", long); - if let Some(short) = short { - header = format!("-{}, {}", short, header); - } - if multiple { - header = format!("*{}* _{}_ ...::", header, value_name); - } else { - header = format!("*{}* _{}_::", header, value_name); - } - writeln!(out, "{}", header)?; - writeln!(out, "{}", formatted_doc_txt(arg)?)?; - - Ok(String::from_utf8(out).unwrap()) - } - } -} - -fn formatted_doc_txt(arg: &RGArg) -> io::Result { - let paragraphs: Vec<&str> = arg.doc_long.split("\n\n").collect(); - if paragraphs.is_empty() { - return Err(ioerr(format!("missing docs for --{}", arg.name))); - } - let first = format!(" {}", paragraphs[0].replace("\n", "\n ")); - if paragraphs.len() == 1 { - return Ok(first); - } - Ok(format!("{}\n+\n{}", first, paragraphs[1..].join("\n+\n"))) -} - -fn ioerr(msg: String) -> io::Error { - io::Error::new(io::ErrorKind::Other, msg) -} diff --git a/ci/before_deploy.sh b/ci/before_deploy.sh deleted file mode 100755 index c1addbc..0000000 --- a/ci/before_deploy.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/bin/bash - -# package the build artifacts - -set -ex - -. "$(dirname $0)/utils.sh" - -# Generate artifacts for release -mk_artifacts() { - cargo build --target "$TARGET" --release --features unstable -} - -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 diff --git a/ci/install.sh b/ci/install.sh deleted file mode 100755 index 37af9d7..0000000 --- a/ci/install.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/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 <&2 - exit 1 -fi -version="$1" - -# Linux and Darwin builds. -for arch in i686 x86_64; do - for target in apple-darwin unknown-linux-musl; do - url="https://github.com/BurntSushi/ripgrep/releases/download/$version/ripgrep-$version-$arch-$target.tar.gz" - sha=$(curl -sfSL "$url" | sha256sum) - echo "$version-$arch-$target $sha" - done -done - -# Source. -for ext in zip tar.gz; do - url="https://github.com/BurntSushi/ripgrep/archive/$version.$ext" - sha=$(curl -sfSL "$url" | sha256sum) - echo "source.$ext $sha" -done diff --git a/ci/test_complete.sh b/ci/test_complete.sh deleted file mode 100755 index b178e85..0000000 --- a/ci/test_complete.sh +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/env zsh - -emulate zsh -o extended_glob -o no_function_argzero -o no_unset - -## -# Compares options in `rg --help` output to options in zsh completion function - -get_comp_args() { - # Technically there are many options that the completion system sets that - # our function may rely on, but we'll trust that we've got it mostly right - setopt local_options unset - - # Our completion function recognises a special variable which tells it to - # dump the _arguments specs and then just return. But do this in a sub-shell - # anyway to avoid any weirdness - ( _RG_COMPLETE_LIST_ARGS=1 source $1 ) -} - -main() { - local diff - local rg="${0:a:h}/../target/${TARGET:-}/release/rg" - local _rg="${0:a:h}/../complete/_rg" - local -a help_args comp_args - - [[ -e $rg ]] || rg=${rg/%\/release\/rg/\/debug\/rg} - - rg=${rg:a} - _rg=${_rg:a} - - [[ -e $rg ]] || { - print -r >&2 "File not found: $rg" - return 1 - } - [[ -e $_rg ]] || { - print -r >&2 "File not found: $_rg" - return 1 - } - - print -rl - 'Comparing options:' "-$rg" "+$_rg" - - # 'Parse' options out of the `--help` output. To prevent false positives we - # only look at lines where the first non-white-space character is `-` - help_args=( ${(f)"$( - $rg --help | - $rg -- '^\s*-' | - $rg -io -- '[\t ,](-[a-z0-9]|--[a-z0-9-]+)\b' | - tr -d '\t ,' | - sort -u - )"} ) - - # 'Parse' options out of the completion function - comp_args=( ${(f)"$( get_comp_args $_rg )"} ) - - # Note that we currently exclude hidden (!...) options; matching these - # properly against the `--help` output could be irritating - comp_args=( ${comp_args#\(*\)} ) # Strip excluded options - comp_args=( ${comp_args#\*} ) # Strip repetition indicator - comp_args=( ${comp_args%%-[:[]*} ) # Strip everything after -optname- - comp_args=( ${comp_args%%[:+=[]*} ) # Strip everything after other optspecs - comp_args=( ${comp_args##[^-]*} ) # Remove non-options - - # This probably isn't necessary, but we should ensure the same order - comp_args=( ${(f)"$( print -rl - $comp_args | sort -u )"} ) - - (( $#help_args )) || { - print -r >&2 'Failed to get help_args' - return 1 - } - (( $#comp_args )) || { - print -r >&2 'Failed to get comp_args' - return 1 - } - - diff="$( - if diff --help 2>&1 | grep -qF -- '--label'; then - diff -U2 \ - --label '`rg --help`' \ - --label '`_rg`' \ - =( print -rl - $help_args ) =( print -rl - $comp_args ) - else - diff -U2 \ - -L '`rg --help`' \ - -L '`_rg`' \ - =( print -rl - $help_args ) =( print -rl - $comp_args ) - fi - )" - - (( $#diff )) && { - printf >&2 '%s\n' 'zsh completion options differ from `--help` options:' - printf >&2 '%s\n' $diff - return 1 - } - printf 'OK\n' - return 0 -} - -main "$@" diff --git a/ci/utils.sh b/ci/utils.sh deleted file mode 100644 index 2fb7fad..0000000 --- a/ci/utils.sh +++ /dev/null @@ -1,91 +0,0 @@ -#!/bin/bash - -# Various utility functions used through CI. - -# 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. -cargo_out_dir() { - # 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 -} - -host() { - case "$TRAVIS_OS_NAME" in - linux) - echo x86_64-unknown-linux-gnu - ;; - osx) - echo x86_64-apple-darwin - ;; - esac -} - -architecture() { - case "$TARGET" in - x86_64-*) - echo amd64 - ;; - i686-*|i586-*|i386-*) - echo i386 - ;; - arm*-unknown-linux-gnueabihf) - echo armhf - ;; - *) - die "architecture: unexpected target $TARGET" - ;; - esac -} - -gcc_prefix() { - case "$(architecture)" in - armhf) - echo arm-linux-gnueabihf- - ;; - *) - return - ;; - esac -} - -is_ssse3_target() { - case "$(architecture)" in - amd64) return 0 ;; - *) return 1 ;; - esac -} - -is_x86() { - case "$(architecture)" in - amd64|i386) return 0 ;; - *) return 1 ;; - esac -} - -is_arm() { - case "$(architecture)" in - armhf) return 0 ;; - *) return 1 ;; - esac -} - -is_linux() { - case "$TRAVIS_OS_NAME" in - linux) return 0 ;; - *) return 1 ;; - esac -} - -is_osx() { - case "$TRAVIS_OS_NAME" in - osx) return 0 ;; - *) return 1 ;; - esac -} diff --git a/complete/_rg b/complete/_rg deleted file mode 100644 index 586c90b..0000000 --- a/complete/_rg +++ /dev/null @@ -1,369 +0,0 @@ -#compdef rg - -## -# zsh completion function for ripgrep -# -# Run ci/test_complete.sh after building to ensure that the options supported by -# this function stay in synch with the `rg` binary. -# -# @see http://zsh.sourceforge.net/Doc/Release/Completion-System.html -# @see https://github.com/zsh-users/zsh/blob/master/Etc/completion-style-guide -# -# Originally based on code from the zsh-users project — see copyright notice -# below. - -_rg() { - local curcontext=$curcontext no='!' descr ret=1 - local -a context line state state_descr args tmp suf - local -A opt_args - - # ripgrep has many options which negate the effect of a more common one — for - # example, `--no-column` to negate `--column`, and `--messages` to negate - # `--no-messages`. There are so many of these, and they're so infrequently - # used, that some users will probably find it irritating if they're completed - # indiscriminately, so let's not do that unless either the current prefix - # matches one of those negation options or the user has the `complete-all` - # style set. Note that this prefix check has to be updated manually to account - # for all of the potential negation options listed below! - if - # (--[imn]* => --ignore*, --messages, --no-*) - [[ $PREFIX$SUFFIX == --[imn]* ]] || - zstyle -t ":complete:$curcontext:*" complete-all - then - no= - fi - - # We make heavy use of argument groups here to prevent the option specs from - # growing unwieldy. These aren't supported in zsh <5.4, though, so we'll strip - # them out below if necessary. This makes the exclusions inaccurate on those - # older versions, but oh well — it's not that big a deal - args=( - + '(exclusive)' # Misc. fully exclusive options - '(: * -)'{-h,--help}'[display help information]' - '(: * -)'{-V,--version}'[display version information]' - - + '(case)' # Case-sensitivity options - {-i,--ignore-case}'[search case-insensitively]' - {-s,--case-sensitive}'[search case-sensitively]' - {-S,--smart-case}'[search case-insensitively if pattern is all lowercase]' - - + '(context-a)' # Context (after) options - '(context-c)'{-A+,--after-context=}'[specify lines to show after each match]:number of lines' - - + '(context-b)' # Context (before) options - '(context-c)'{-B+,--before-context=}'[specify lines to show before each match]:number of lines' - - + '(context-c)' # Context (combined) options - '(context-a context-b)'{-C+,--context=}'[specify lines to show before and after each match]:number of lines' - - + '(column)' # Column options - '--column[show column numbers for matches]' - $no"--no-column[don't show column numbers for matches]" - - + '(count)' # Counting options - '(passthru)'{-c,--count}'[only show count of matching lines for each file]' - '(passthru)--count-matches[only show count of individual matches for each file]' - - + file # File-input options - '*'{-f+,--file=}'[specify file containing patterns to search for]: :_files' - - + '(file-match)' # Files with/without match options - '(stats)'{-l,--files-with-matches}'[only show names of files with matches]' - '(stats)--files-without-match[only show names of files without matches]' - - + '(file-name)' # File-name options - {-H,--with-filename}'[show file name for matches]' - "--no-filename[don't show file name for matches]" - - + '(fixed)' # Fixed-string options - {-F,--fixed-strings}'[treat pattern as literal string instead of regular expression]' - $no"--no-fixed-strings[don't treat pattern as literal string]" - - + '(follow)' # Symlink-following options - {-L,--follow}'[follow symlinks]' - $no"--no-follow[don't follow symlinks]" - - + glob # File-glob options - '*'{-g+,--glob=}'[include/exclude files matching specified glob]:glob' - '*--iglob=[include/exclude files matching specified case-insensitive glob]:glob' - - + '(heading)' # Heading options - '(pretty-vimgrep)--heading[show matches grouped by file name]' - "(pretty-vimgrep)--no-heading[don't show matches grouped by file name]" - - + '(hidden)' # Hidden-file options - '--hidden[search hidden files and directories]' - $no"--no-hidden[don't search hidden files and directories]" - - + '(ignore)' # Ignore-file options - "(--no-ignore-parent --no-ignore-vcs)--no-ignore[don't respect ignore files]" - $no'(--ignore-parent --ignore-vcs)--ignore[respect ignore files]' - - + '(ignore-parent)' # Parent ignore-file options - "--no-ignore-parent[don't respect ignore files in parent directories]" - $no'--ignore-parent[respect ignore files in parent directories]' - - + '(ignore-vcs)' # VCS ignore-file options - "--no-ignore-vcs[don't respect version control ignore files]" - $no'--ignore-vcs[respect version control ignore files]' - - + '(line)' # Line-number options - {-n,--line-number}'[show line numbers for matches]' - {-N,--no-line-number}"[don't show line numbers for matches]" - - + '(max-depth)' # Directory-depth options - '--max-depth=[specify max number of directories to descend]:number of directories' - '!--maxdepth=:number of directories' - - + '(messages)' # Error-message options - '(--no-ignore-messages)--no-messages[suppress some error messages]' - $no"--messages[don't suppress error messages affected by --no-messages]" - - + '(messages-ignore)' # Ignore-error message options - "--no-ignore-messages[don't show ignore-file parse error messages]" - $no'--ignore-messages[show ignore-file parse error messages]' - - + '(mmap)' # mmap options - '--mmap[search using memory maps when possible]' - "--no-mmap[don't search using memory maps]" - - + '(only)' # Only-match options - '(passthru replace)'{-o,--only-matching}'[show only matching part of each line]' - - + '(passthru)' # Pass-through options - '(--vimgrep count only replace)--passthru[show both matching and non-matching lines]' - '!(--vimgrep count only replace)--passthrough' - - + '(pretty-vimgrep)' # Pretty/vimgrep display options - '(heading)'{-p,--pretty}'[alias for --color=always --heading -n]' - '(heading passthru)--vimgrep[show results in vim-compatible format]' - - + regexp # Explicit pattern options - '(1 file)*'{-e+,--regexp=}'[specify pattern]:pattern' - - + '(replace)' # Replacement options - '(count only passthru)'{-r+,--replace=}'[specify string used to replace matches]:replace string' - - + '(sort)' # File-sorting options - '(threads)--sort-files[sort results by file path (disables parallelism)]' - $no"--no-sort-files[don't sort results by file path]" - - + stats # Statistics options - '(--files file-match)--stats[show search statistics]' - - + '(text)' # Binary-search options - {-a,--text}'[search binary files as if they were text]' - $no"--no-text[don't search binary files as if they were text]" - - + '(threads)' # Thread-count options - '(--sort-files)'{-j+,--threads=}'[specify approximate number of threads to use]:number of threads' - - + type # Type options - '*'{-t+,--type=}'[only search files matching specified type]: :_rg_types' - '*--type-add=[add new glob for specified file type]: :->typespec' - '*--type-clear=[clear globs previously defined for specified file type]: :_rg_types' - # This should actually be exclusive with everything but other type options - '(: *)--type-list[show all supported file types and their associated globs]' - '*'{-T+,--type-not=}"[don't search files matching specified file type]: :_rg_types" - - + '(word-line)' # Whole-word/line match options - {-w,--word-regexp}'[only show matches surrounded by word boundaries]' - {-x,--line-regexp}'[only show matches surrounded by line boundaries]' - - + '(zip)' # Compressed-file options - {-z,--search-zip}'[search in compressed files]' - $no"--no-search-zip[don't search in compressed files]" - - + misc # Other options — no need to separate these at the moment - '(-b --byte-offset)'{-b,--byte-offset}'[show 0-based byte offset for each matching line]' - '--color=[specify when to use colors in output]:when:(( - never\:"never use colors" - auto\:"use colors or not based on stdout, TERM, etc." - always\:"always use colors" - ansi\:"always use ANSI colors (even on Windows)" - ))' - '*--colors=[specify color and style settings]: :->colorspec' - '--context-separator=[specify string used to separate non-continuous context lines in output]:separator' - '--debug[show debug messages]' - '--dfa-size-limit=[specify upper size limit of generated DFA]:DFA size (bytes)' - '(-E --encoding)'{-E+,--encoding=}'[specify text encoding of files to search]: :_rg_encodings' - "(1 stats)--files[show each file that would be searched (but don't search)]" - '*--ignore-file=[specify additional ignore file]:ignore file:_files' - '(-v --invert-match)'{-v,--invert-match}'[invert matching]' - '(-M --max-columns)'{-M+,--max-columns=}'[specify max length of lines to print]:number of bytes' - '(-m --max-count)'{-m+,--max-count=}'[specify max number of matches per file]:number of matches' - '--max-filesize=[specify size above which files should be ignored]:file size (bytes)' - "--no-config[don't load configuration files]" - '(-0 --null)'{-0,--null}'[print NUL byte after file names]' - '--path-separator=[specify path separator to use when printing file names]:separator' - '(-q --quiet)'{-q,--quiet}'[suppress normal output]' - '--regex-size-limit=[specify upper size limit of compiled regex]:regex size (bytes)' - '*'{-u,--unrestricted}'[reduce level of "smart" searching]' - - + operand # Operands - '(--files --type-list file regexp)1: :_guard "^-*" pattern' - '(--type-list)*: :_files' - ) - - # 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 - [[ $_RG_COMPLETE_LIST_ARGS == (1|t*|y*) ]] && { - print -rl - $args - return 0 - } - - # Strip out argument groups where unsupported (see above) - [[ $ZSH_VERSION == (4|5.<0-3>)(.*)# ]] && - args=( ${(@)args:#(#i)(+|[a-z0-9][a-z0-9_-]#|\([a-z0-9][a-z0-9_-]#\))} ) - - _arguments -C -s -S : $args && ret=0 - - case $state in - colorspec) - if [[ ${IPREFIX#--*=}$PREFIX == [^:]# ]]; then - suf=( -qS: ) - tmp=( - 'column:specify coloring for column numbers' - 'line:specify coloring for line numbers' - 'match:specify coloring for match text' - 'path:specify coloring for file names' - ) - descr='color/style type' - elif [[ ${IPREFIX#--*=}$PREFIX == (column|line|match|path):[^:]# ]]; then - suf=( -qS: ) - tmp=( - 'none:clear color/style for type' - 'bg:specify background color' - 'fg:specify foreground color' - 'style:specify text style' - ) - descr='color/style attribute' - elif [[ ${IPREFIX#--*=}$PREFIX == [^:]##:(bg|fg):[^:]# ]]; then - tmp=( black blue green red cyan magenta yellow white ) - descr='color name or r,g,b' - elif [[ ${IPREFIX#--*=}$PREFIX == [^:]##:style:[^:]# ]]; then - tmp=( {,no}bold {,no}intense {,no}underline ) - descr='style name' - else - _message -e colorspec 'no more arguments' - fi - - (( $#tmp )) && { - compset -P '*:' - _describe -t colorspec $descr tmp $suf && ret=0 - } - ;; - - typespec) - if compset -P '[^:]##:include:'; then - _sequence -s , _rg_types && ret=0 - # @todo This bit in particular could be better, but it's a little - # complex, and attempting to solve it seems to run us up against a crash - # bug — zsh # 40362 - elif compset -P '[^:]##:'; then - _message 'glob or include directive' && ret=1 - elif [[ ! -prefix *:* ]]; then - _rg_types -qS : && ret=0 - fi - ;; - esac - - return ret -} - -# Complete encodings -_rg_encodings() { - local -a expl - local -aU _encodings - - # This is impossible to read, but these encodings rarely if ever change, so it - # probably doesn't matter. They are derived from the list given here: - # https://encoding.spec.whatwg.org/#concept-encoding-get - _encodings=( - {{,us-}ascii,arabic,chinese,cyrillic,greek{,8},hebrew,korean} - logical visual mac {,cs}macintosh x-mac-{cyrillic,roman,ukrainian} - 866 ibm{819,866} csibm866 - big5{,-hkscs} {cn-,cs}big5 x-x-big5 - cp{819,866,125{0..8}} x-cp125{0..8} - csiso2022{jp,kr} csiso8859{6,8}{e,i} - csisolatin{{1..6},9} csisolatin{arabic,cyrillic,greek,hebrew} - ecma-{114,118} asmo-708 elot_928 sun_eu_greek - euc-{jp,kr} x-euc-jp cseuckr cseucpkdfmtjapanese - {,x-}gbk csiso58gb231280 gb18030 {,cs}gb2312 gb_2312{,-80} hz-gb-2312 - iso-2022-{cn,cn-ext,jp,kr} - iso8859{,-}{{1..11},13,14,15} - iso-8859-{{1..11},{6,8}-{e,i},13,14,15,16} iso_8859-{{1..9},15} - iso_8859-{1,2,6,7}:1987 iso_8859-{3,4,5,8}:1988 iso_8859-9:1989 - iso-ir-{58,100,101,109,110,126,127,138,144,148,149,157} - koi{,8,8-r,8-ru,8-u,8_r} cskoi8r - ks_c_5601-{1987,1989} ksc{,_}5691 csksc56011987 - latin{1..6} l{{1..6},9} - shift{-,_}jis csshiftjis {,x-}sjis ms_kanji ms932 - utf{,-}8 utf-16{,be,le} unicode-1-1-utf-8 - windows-{31j,874,949,125{0..8}} dos-874 tis-620 ansi_x3.4-1968 - x-user-defined auto - ) - - _wanted encodings expl encoding compadd -a "$@" - _encodings -} - -# Complete file types -_rg_types() { - local -a expl - local -aU _types - - _types=( ${(@)${(f)"$( _call_program types rg --type-list )"}%%:*} ) - - _wanted types expl 'file type' compadd -a "$@" - _types -} - -_rg "$@" - -# ------------------------------------------------------------------------------ -# Copyright (c) 2011 Github zsh-users - http://github.com/zsh-users -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# * Neither the name of the zsh-users nor the -# names of its contributors may be used to endorse or promote products -# derived from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL ZSH-USERS BE LIABLE FOR ANY -# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# ------------------------------------------------------------------------------ -# Description -# ----------- -# -# Completion script for ripgrep -# -# ------------------------------------------------------------------------------ -# Authors -# ------- -# -# * arcizan -# * MaskRay -# -# ------------------------------------------------------------------------------ - -# Local Variables: -# mode: shell-script -# coding: utf-8-unix -# indent-tabs-mode: nil -# sh-indentation: 2 -# sh-basic-offset: 2 -# End: -# vim: ft=zsh sw=2 ts=2 et diff --git a/doc/rg.1.txt.tpl b/doc/rg.1.txt.tpl deleted file mode 100644 index fc268f8..0000000 --- a/doc/rg.1.txt.tpl +++ /dev/null @@ -1,176 +0,0 @@ -rg(1) -===== - -Name ----- -rg - recursively search current directory for lines matching a pattern - - -Synopsis --------- -*rg* [_OPTIONS_] _PATTERN_ [_PATH_...] - -*rg* [_OPTIONS_] *-e* _PATTERN_... [_PATH_...] - -*rg* [_OPTIONS_] *-f* _PATTERNFILE_... [_PATH_...] - -*rg* [_OPTIONS_] *--files* [_PATH_...] - -*rg* [_OPTIONS_] *--type-list* - -*rg* [_OPTIONS_] *--help* - -*rg* [_OPTIONS_] *--version* - - -DESCRIPTION ------------ -ripgrep (rg) recursively searches your current directory for a regex pattern. -By default, ripgrep will respect your `.gitignore` and automatically skip -hidden files/directories and binary files. - -ripgrep's regex engine uses finite automata and guarantees linear time -searching. Because of this, features like backreferences and arbitrary -lookaround are not supported. - - -REGEX SYNTAX ------------- -ripgrep uses Rust's regex engine, which documents its syntax: -https://docs.rs/regex/0.2.5/regex/#syntax - -ripgrep uses byte-oriented regexes, which has some additional documentation: -https://docs.rs/regex/0.2.5/regex/bytes/index.html#syntax - -To a first approximation, ripgrep uses Perl-like regexes without look-around or -backreferences. This makes them very similar to the "extended" (ERE) regular -expressions supported by `egrep`, but with a few additional features like -Unicode character classes. - - -POSITIONAL ARGUMENTS --------------------- -_PATTERN_:: - A regular expression used for searching. To match a pattern beginning with a - dash, use the -e/--regexp option. - -_PATH_:: - A file or directory to search. Directories are searched recursively. Paths - specified expicitly on the command line override glob and ignore rules. - - -OPTIONS -------- -{OPTIONS} - - -EXIT STATUS ------------ -If ripgrep finds a match, then the exit status of the program is 0. If no match -could be found, then the exit status is non-zero. - - -CONFIGURATION FILES -------------------- -ripgrep supports reading configuration files that change ripgrep's default -behavior. The format of the configuration file is an "rc" style and is very -simple. It is defined by two rules: - - 1. Every line is a shell argument, after trimming ASCII whitespace. - 2. Lines starting with _#_ (optionally preceded by any amount of - ASCII whitespace) are ignored. - -ripgrep will look for a single configuration file if and only if the -_RIPGREP_CONFIG_PATH_ environment variable is set and is non-empty. -ripgrep will parse shell arguments from this file on startup and will -behave as if the arguments in this file were prepended to any explicit -arguments given to ripgrep on the command line. - -For example, if your ripgreprc file contained a single line: - - --smart-case - -then the following command - - RIPGREP_CONFIG_PATH=wherever/.ripgreprc rg foo - -would behave identically to the following command - - rg --smart-case foo - -another example is adding types - - --type-add - web:*.{html,css,js}* - -would behave identically to the following command - - rg --type-add 'web:*.{html,css,js}*' foo - -same with using globs - - --glob=!git/* - -or - - --glob - !git/* - -would behave identically to the following command - - rg --glob '!git/*' foo - -ripgrep also provides a flag, *--no-config*, that when present will suppress -any and all support for configuration. This includes any future support -for auto-loading configuration files from pre-determined paths. - -Conflicts between configuration files and explicit arguments are handled -exactly like conflicts in the same command line invocation. That is, -this command: - - RIPGREP_CONFIG_PATH=wherever/.ripgreprc rg foo --case-sensitive - -is exactly equivalent to - - rg --smart-case foo --case-sensitive - -in which case, the *--case-sensitive* flag would override the *--smart-case* -flag. - - -SHELL COMPLETION ----------------- -Shell completion files are included in the release tarball for Bash, Fish, Zsh -and PowerShell. - -For *bash*, move `rg.bash` to `$XDG_CONFIG_HOME/bash_completion` -or `/etc/bash_completion.d/`. - -For *fish*, move `rg.fish` to `$HOME/.config/fish/completions`. - -For *zsh*, move `_rg` to one of your `$fpath` directories. - - -CAVEATS -------- -ripgrep may abort unexpectedly when using default settings if it searches a -file that is simultaneously truncated. This behavior can be avoided by passing -the --no-mmap flag which will forcefully disable the use of memory maps in all -cases. - - -VERSION -------- -{VERSION} - - -HOMEPAGE --------- -https://github.com/BurntSushi/ripgrep - -Please report bugs and feature requests in the issue tracker. - - -AUTHORS -------- -Andrew Gallant diff --git a/globset/COPYING b/globset/COPYING deleted file mode 100644 index bb9c20a..0000000 --- a/globset/COPYING +++ /dev/null @@ -1,3 +0,0 @@ -This project is dual-licensed under the Unlicense and MIT licenses. - -You may use this code under the terms of either license. diff --git a/globset/Cargo.toml b/globset/Cargo.toml deleted file mode 100644 index e41da40..0000000 --- a/globset/Cargo.toml +++ /dev/null @@ -1,32 +0,0 @@ -[package] -name = "globset" -version = "0.4.0" #:version -authors = ["Andrew Gallant "] -description = """ -Cross platform single glob and glob set matching. Glob set matching is the -process of matching one or more glob patterns against a single candidate path -simultaneously, and returning all of the globs that matched. -""" -documentation = "https://docs.rs/globset" -homepage = "https://github.com/BurntSushi/ripgrep/tree/master/globset" -repository = "https://github.com/BurntSushi/ripgrep/tree/master/globset" -readme = "README.md" -keywords = ["regex", "glob", "multiple", "set", "pattern"] -license = "Unlicense/MIT" - -[lib] -name = "globset" -bench = false - -[dependencies] -aho-corasick = "0.6.0" -fnv = "1.0" -log = "0.4" -memchr = "2" -regex = "1" - -[dev-dependencies] -glob = "0.2" - -[features] -simd-accel = [] diff --git a/globset/LICENSE-MIT b/globset/LICENSE-MIT deleted file mode 100644 index 3b0a5dc..0000000 --- a/globset/LICENSE-MIT +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Andrew Gallant - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/globset/README.md b/globset/README.md deleted file mode 100644 index f5caf22..0000000 --- a/globset/README.md +++ /dev/null @@ -1,122 +0,0 @@ -globset -======= -Cross platform single glob and glob set matching. Glob set matching is the -process of matching one or more glob patterns against a single candidate path -simultaneously, and returning all of the globs that matched. - -[![Linux build status](https://api.travis-ci.org/BurntSushi/ripgrep.png)](https://travis-ci.org/BurntSushi/ripgrep) -[![Windows build status](https://ci.appveyor.com/api/projects/status/github/BurntSushi/ripgrep?svg=true)](https://ci.appveyor.com/project/BurntSushi/ripgrep) -[![](https://img.shields.io/crates/v/globset.svg)](https://crates.io/crates/globset) - -Dual-licensed under MIT or the [UNLICENSE](http://unlicense.org). - -### Documentation - -[https://docs.rs/globset](https://docs.rs/globset) - -### Usage - -Add this to your `Cargo.toml`: - -```toml -[dependencies] -globset = "0.3" -``` - -and this to your crate root: - -```rust -extern crate globset; -``` - -### Example: one glob - -This example shows how to match a single glob against a single file path. - -```rust -use globset::Glob; - -let glob = Glob::new("*.rs")?.compile_matcher(); - -assert!(glob.is_match("foo.rs")); -assert!(glob.is_match("foo/bar.rs")); -assert!(!glob.is_match("Cargo.toml")); -``` - -### Example: configuring a glob matcher - -This example shows how to use a `GlobBuilder` to configure aspects of match -semantics. In this example, we prevent wildcards from matching path separators. - -```rust -use globset::GlobBuilder; - -let glob = GlobBuilder::new("*.rs") - .literal_separator(true).build()?.compile_matcher(); - -assert!(glob.is_match("foo.rs")); -assert!(!glob.is_match("foo/bar.rs")); // no longer matches -assert!(!glob.is_match("Cargo.toml")); -``` - -### Example: match multiple globs at once - -This example shows how to match multiple glob patterns at once. - -```rust -use globset::{Glob, GlobSetBuilder}; - -let mut builder = GlobSetBuilder::new(); -// A GlobBuilder can be used to configure each glob's match semantics -// independently. -builder.add(Glob::new("*.rs")?); -builder.add(Glob::new("src/lib.rs")?); -builder.add(Glob::new("src/**/foo.rs")?); -let set = builder.build()?; - -assert_eq!(set.matches("src/bar/baz/foo.rs"), vec![0, 2]); -``` - -### Performance - -This crate implements globs by converting them to regular expressions, and -executing them with the -[`regex`](https://github.com/rust-lang-nursery/regex) -crate. - -For single glob matching, performance of this crate should be roughly on par -with the performance of the -[`glob`](https://github.com/rust-lang-nursery/glob) -crate. (`*_regex` correspond to benchmarks for this library while `*_glob` -correspond to benchmarks for the `glob` library.) -Optimizations in the `regex` crate may propel this library past `glob`, -particularly when matching longer paths. - -``` -test ext_glob ... bench: 425 ns/iter (+/- 21) -test ext_regex ... bench: 175 ns/iter (+/- 10) -test long_glob ... bench: 182 ns/iter (+/- 11) -test long_regex ... bench: 173 ns/iter (+/- 10) -test short_glob ... bench: 69 ns/iter (+/- 4) -test short_regex ... bench: 83 ns/iter (+/- 2) -``` - -The primary performance advantage of this crate is when matching multiple -globs against a single path. With the `glob` crate, one must match each glob -synchronously, one after the other. In this crate, many can be matched -simultaneously. For example: - -``` -test many_short_glob ... bench: 1,063 ns/iter (+/- 47) -test many_short_regex_set ... bench: 186 ns/iter (+/- 11) -``` - -### Comparison with the [`glob`](https://github.com/rust-lang-nursery/glob) crate - -* Supports alternate "or" globs, e.g., `*.{foo,bar}`. -* Can match non-UTF-8 file paths correctly. -* Supports matching multiple globs at once. -* Doesn't provide a recursive directory iterator of matching file paths, - although I believe this crate should grow one eventually. -* Supports case insensitive and require-literal-separator match options, but - **doesn't** support the require-literal-leading-dot option. diff --git a/globset/UNLICENSE b/globset/UNLICENSE deleted file mode 100644 index 68a49da..0000000 --- a/globset/UNLICENSE +++ /dev/null @@ -1,24 +0,0 @@ -This is free and unencumbered software released into the public domain. - -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a compiled -binary, for any purpose, commercial or non-commercial, and by any -means. - -In jurisdictions that recognize copyright laws, the author or authors -of this software dedicate any and all copyright interest in the -software to the public domain. We make this dedication for the benefit -of the public at large and to the detriment of our heirs and -successors. We intend this dedication to be an overt act of -relinquishment in perpetuity of all present and future rights to this -software under copyright law. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -For more information, please refer to diff --git a/globset/benches/bench.rs b/globset/benches/bench.rs deleted file mode 100644 index e142ed7..0000000 --- a/globset/benches/bench.rs +++ /dev/null @@ -1,121 +0,0 @@ -/*! -This module benchmarks the glob implementation. For benchmarks on the ripgrep -tool itself, see the benchsuite directory. -*/ -#![feature(test)] - -extern crate glob; -extern crate globset; -#[macro_use] -extern crate lazy_static; -extern crate regex; -extern crate test; - -use std::ffi::OsStr; -use std::path::Path; - -use globset::{Candidate, Glob, GlobMatcher, GlobSet, GlobSetBuilder}; - -const EXT: &'static str = "some/a/bigger/path/to/the/crazy/needle.txt"; -const EXT_PAT: &'static str = "*.txt"; - -const SHORT: &'static str = "some/needle.txt"; -const SHORT_PAT: &'static str = "some/**/needle.txt"; - -const LONG: &'static str = "some/a/bigger/path/to/the/crazy/needle.txt"; -const LONG_PAT: &'static str = "some/**/needle.txt"; - -fn new_glob(pat: &str) -> glob::Pattern { - glob::Pattern::new(pat).unwrap() -} - -fn new_reglob(pat: &str) -> GlobMatcher { - Glob::new(pat).unwrap().compile_matcher() -} - -fn new_reglob_many(pats: &[&str]) -> GlobSet { - let mut builder = GlobSetBuilder::new(); - for pat in pats { - builder.add(Glob::new(pat).unwrap()); - } - builder.build().unwrap() -} - -#[bench] -fn ext_glob(b: &mut test::Bencher) { - let pat = new_glob(EXT_PAT); - b.iter(|| assert!(pat.matches(EXT))); -} - -#[bench] -fn ext_regex(b: &mut test::Bencher) { - let set = new_reglob(EXT_PAT); - let cand = Candidate::new(EXT); - b.iter(|| assert!(set.is_match_candidate(&cand))); -} - -#[bench] -fn short_glob(b: &mut test::Bencher) { - let pat = new_glob(SHORT_PAT); - b.iter(|| assert!(pat.matches(SHORT))); -} - -#[bench] -fn short_regex(b: &mut test::Bencher) { - let set = new_reglob(SHORT_PAT); - let cand = Candidate::new(SHORT); - b.iter(|| assert!(set.is_match_candidate(&cand))); -} - -#[bench] -fn long_glob(b: &mut test::Bencher) { - let pat = new_glob(LONG_PAT); - b.iter(|| assert!(pat.matches(LONG))); -} - -#[bench] -fn long_regex(b: &mut test::Bencher) { - let set = new_reglob(LONG_PAT); - let cand = Candidate::new(LONG); - b.iter(|| assert!(set.is_match_candidate(&cand))); -} - -const MANY_SHORT_GLOBS: &'static [&'static str] = &[ - // Taken from a random .gitignore on my system. - ".*.swp", - "tags", - "target", - "*.lock", - "tmp", - "*.csv", - "*.fst", - "*-got", - "*.csv.idx", - "words", - "98m*", - "dict", - "test", - "months", -]; - -const MANY_SHORT_SEARCH: &'static str = "98m-blah.csv.idx"; - -#[bench] -fn many_short_glob(b: &mut test::Bencher) { - let pats: Vec<_> = MANY_SHORT_GLOBS.iter().map(|&s| new_glob(s)).collect(); - b.iter(|| { - let mut count = 0; - for pat in &pats { - if pat.matches(MANY_SHORT_SEARCH) { - count += 1; - } - } - assert_eq!(2, count); - }) -} - -#[bench] -fn many_short_regex_set(b: &mut test::Bencher) { - let set = new_reglob_many(MANY_SHORT_GLOBS); - b.iter(|| assert_eq!(2, set.matches(MANY_SHORT_SEARCH).iter().count())); -} diff --git a/globset/src/glob.rs b/globset/src/glob.rs deleted file mode 100644 index 062f5a6..0000000 --- a/globset/src/glob.rs +++ /dev/null @@ -1,1439 +0,0 @@ -use std::fmt; -use std::hash; -use std::iter; -use std::ops::{Deref, DerefMut}; -use std::path::{Path, is_separator}; -use std::str; - -use regex; -use regex::bytes::Regex; - -use {Candidate, Error, ErrorKind, new_regex}; - -/// Describes a matching strategy for a particular pattern. -/// -/// This provides a way to more quickly determine whether a pattern matches -/// a particular file path in a way that scales with a large number of -/// patterns. For example, if many patterns are of the form `*.ext`, then it's -/// possible to test whether any of those patterns matches by looking up a -/// file path's extension in a hash table. -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum MatchStrategy { - /// A pattern matches if and only if the entire file path matches this - /// literal string. - Literal(String), - /// A pattern matches if and only if the file path's basename matches this - /// literal string. - BasenameLiteral(String), - /// A pattern matches if and only if the file path's extension matches this - /// literal string. - Extension(String), - /// A pattern matches if and only if this prefix literal is a prefix of the - /// candidate file path. - Prefix(String), - /// A pattern matches if and only if this prefix literal is a prefix of the - /// candidate file path. - /// - /// An exception: if `component` is true, then `suffix` must appear at the - /// beginning of a file path or immediately following a `/`. - Suffix { - /// The actual suffix. - suffix: String, - /// Whether this must start at the beginning of a path component. - component: bool, - }, - /// A pattern matches only if the given extension matches the file path's - /// extension. Note that this is a necessary but NOT sufficient criterion. - /// Namely, if the extension matches, then a full regex search is still - /// required. - RequiredExtension(String), - /// A regex needs to be used for matching. - Regex, -} - -impl MatchStrategy { - /// Returns a matching strategy for the given pattern. - pub fn new(pat: &Glob) -> MatchStrategy { - if let Some(lit) = pat.basename_literal() { - MatchStrategy::BasenameLiteral(lit) - } else if let Some(lit) = pat.literal() { - MatchStrategy::Literal(lit) - } else if let Some(ext) = pat.ext() { - MatchStrategy::Extension(ext) - } else if let Some(prefix) = pat.prefix() { - MatchStrategy::Prefix(prefix) - } else if let Some((suffix, component)) = pat.suffix() { - MatchStrategy::Suffix { suffix: suffix, component: component } - } else if let Some(ext) = pat.required_ext() { - MatchStrategy::RequiredExtension(ext) - } else { - MatchStrategy::Regex - } - } -} - -/// Glob represents a successfully parsed shell glob pattern. -/// -/// It cannot be used directly to match file paths, but it can be converted -/// to a regular expression string or a matcher. -#[derive(Clone, Debug, Eq)] -pub struct Glob { - glob: String, - re: String, - opts: GlobOptions, - tokens: Tokens, -} - -impl PartialEq for Glob { - fn eq(&self, other: &Glob) -> bool { - self.glob == other.glob && self.opts == other.opts - } -} - -impl hash::Hash for Glob { - fn hash(&self, state: &mut H) { - self.glob.hash(state); - self.opts.hash(state); - } -} - -impl fmt::Display for Glob { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.glob.fmt(f) - } -} - -/// A matcher for a single pattern. -#[derive(Clone, Debug)] -pub struct GlobMatcher { - /// The underlying pattern. - pat: Glob, - /// The pattern, as a compiled regex. - re: Regex, -} - -impl GlobMatcher { - /// Tests whether the given path matches this pattern or not. - pub fn is_match>(&self, path: P) -> bool { - self.is_match_candidate(&Candidate::new(path.as_ref())) - } - - /// Tests whether the given path matches this pattern or not. - pub fn is_match_candidate(&self, path: &Candidate) -> bool { - self.re.is_match(&path.path) - } -} - -/// A strategic matcher for a single pattern. -#[cfg(test)] -#[derive(Clone, Debug)] -struct GlobStrategic { - /// The match strategy to use. - strategy: MatchStrategy, - /// The underlying pattern. - pat: Glob, - /// The pattern, as a compiled regex. - re: Regex, -} - -#[cfg(test)] -impl GlobStrategic { - /// Tests whether the given path matches this pattern or not. - fn is_match>(&self, path: P) -> bool { - self.is_match_candidate(&Candidate::new(path.as_ref())) - } - - /// Tests whether the given path matches this pattern or not. - fn is_match_candidate(&self, candidate: &Candidate) -> bool { - let byte_path = &*candidate.path; - - match self.strategy { - MatchStrategy::Literal(ref lit) => lit.as_bytes() == byte_path, - MatchStrategy::BasenameLiteral(ref lit) => { - lit.as_bytes() == &*candidate.basename - } - MatchStrategy::Extension(ref ext) => { - ext.as_bytes() == &*candidate.ext - } - MatchStrategy::Prefix(ref pre) => { - starts_with(pre.as_bytes(), byte_path) - } - MatchStrategy::Suffix { ref suffix, component } => { - if component && byte_path == &suffix.as_bytes()[1..] { - return true; - } - ends_with(suffix.as_bytes(), byte_path) - } - MatchStrategy::RequiredExtension(ref ext) => { - let ext = ext.as_bytes(); - &*candidate.ext == ext && self.re.is_match(byte_path) - } - MatchStrategy::Regex => self.re.is_match(byte_path), - } - } -} - -/// A builder for a pattern. -/// -/// This builder enables configuring the match semantics of a pattern. For -/// example, one can make matching case insensitive. -/// -/// The lifetime `'a` refers to the lifetime of the pattern string. -#[derive(Clone, Debug)] -pub struct GlobBuilder<'a> { - /// The glob pattern to compile. - glob: &'a str, - /// Options for the pattern. - opts: GlobOptions, -} - -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -struct GlobOptions { - /// Whether to match case insensitively. - case_insensitive: bool, - /// Whether to require a literal separator to match a separator in a file - /// path. e.g., when enabled, `*` won't match `/`. - literal_separator: bool, - /// Whether or not to use `\` to escape special characters. - /// e.g., when enabled, `\*` will match a literal `*`. - backslash_escape: bool, -} - -impl GlobOptions { - fn default() -> GlobOptions { - GlobOptions { - case_insensitive: false, - literal_separator: false, - backslash_escape: !is_separator('\\'), - } - } -} - -#[derive(Clone, Debug, Default, Eq, PartialEq)] -struct Tokens(Vec); - -impl Deref for Tokens { - type Target = Vec; - fn deref(&self) -> &Vec { &self.0 } -} - -impl DerefMut for Tokens { - fn deref_mut(&mut self) -> &mut Vec { &mut self.0 } -} - -#[derive(Clone, Debug, Eq, PartialEq)] -enum Token { - Literal(char), - Any, - ZeroOrMore, - RecursivePrefix, - RecursiveSuffix, - RecursiveZeroOrMore, - Class { - negated: bool, - ranges: Vec<(char, char)>, - }, - Alternates(Vec), -} - -impl Glob { - /// Builds a new pattern with default options. - pub fn new(glob: &str) -> Result { - GlobBuilder::new(glob).build() - } - - /// Returns a matcher for this pattern. - pub fn compile_matcher(&self) -> GlobMatcher { - let re = new_regex(&self.re) - .expect("regex compilation shouldn't fail"); - GlobMatcher { - pat: self.clone(), - re: re, - } - } - - /// Returns a strategic matcher. - /// - /// This isn't exposed because it's not clear whether it's actually - /// faster than just running a regex for a *single* pattern. If it - /// is faster, then GlobMatcher should do it automatically. - #[cfg(test)] - fn compile_strategic_matcher(&self) -> GlobStrategic { - let strategy = MatchStrategy::new(self); - let re = new_regex(&self.re) - .expect("regex compilation shouldn't fail"); - GlobStrategic { - strategy: strategy, - pat: self.clone(), - re: re, - } - } - - /// Returns the original glob pattern used to build this pattern. - pub fn glob(&self) -> &str { - &self.glob - } - - /// Returns the regular expression string for this glob. - pub fn regex(&self) -> &str { - &self.re - } - - /// Returns the pattern as a literal if and only if the pattern must match - /// an entire path exactly. - /// - /// The basic format of these patterns is `{literal}`. - fn literal(&self) -> Option { - if self.opts.case_insensitive { - return None; - } - let mut lit = String::new(); - for t in &*self.tokens { - match *t { - Token::Literal(c) => lit.push(c), - _ => return None, - } - } - if lit.is_empty() { - None - } else { - Some(lit) - } - } - - /// Returns an extension if this pattern matches a file path if and only - /// if the file path has the extension returned. - /// - /// Note that this extension returned differs from the extension that - /// std::path::Path::extension returns. Namely, this extension includes - /// the '.'. Also, paths like `.rs` are considered to have an extension - /// of `.rs`. - fn ext(&self) -> Option { - if self.opts.case_insensitive { - return None; - } - let start = match self.tokens.get(0) { - Some(&Token::RecursivePrefix) => 1, - Some(_) => 0, - _ => return None, - }; - match self.tokens.get(start) { - Some(&Token::ZeroOrMore) => { - // If there was no recursive prefix, then we only permit - // `*` if `*` can match a `/`. For example, if `*` can't - // match `/`, then `*.c` doesn't match `foo/bar.c`. - if start == 0 && self.opts.literal_separator { - return None; - } - } - _ => return None, - } - match self.tokens.get(start + 1) { - Some(&Token::Literal('.')) => {} - _ => return None, - } - let mut lit = ".".to_string(); - for t in self.tokens[start + 2..].iter() { - match *t { - Token::Literal('.') | Token::Literal('/') => return None, - Token::Literal(c) => lit.push(c), - _ => return None, - } - } - if lit.is_empty() { - None - } else { - Some(lit) - } - } - - /// This is like `ext`, but returns an extension even if it isn't sufficent - /// to imply a match. Namely, if an extension is returned, then it is - /// necessary but not sufficient for a match. - fn required_ext(&self) -> Option { - if self.opts.case_insensitive { - return None; - } - // We don't care at all about the beginning of this pattern. All we - // need to check for is if it ends with a literal of the form `.ext`. - let mut ext: Vec = vec![]; // built in reverse - for t in self.tokens.iter().rev() { - match *t { - Token::Literal('/') => return None, - Token::Literal(c) => { - ext.push(c); - if c == '.' { - break; - } - } - _ => return None, - } - } - if ext.last() != Some(&'.') { - None - } else { - ext.reverse(); - Some(ext.into_iter().collect()) - } - } - - /// Returns a literal prefix of this pattern if the entire pattern matches - /// if the literal prefix matches. - fn prefix(&self) -> Option { - if self.opts.case_insensitive { - return None; - } - let end = match self.tokens.last() { - Some(&Token::ZeroOrMore) => { - if self.opts.literal_separator { - // If a trailing `*` can't match a `/`, then we can't - // assume a match of the prefix corresponds to a match - // of the overall pattern. e.g., `foo/*` with - // `literal_separator` enabled matches `foo/bar` but not - // `foo/bar/baz`, even though `foo/bar/baz` has a `foo/` - // literal prefix. - return None; - } - self.tokens.len() - 1 - } - _ => self.tokens.len(), - }; - let mut lit = String::new(); - for t in &self.tokens[0..end] { - match *t { - Token::Literal(c) => lit.push(c), - _ => return None, - } - } - if lit.is_empty() { - None - } else { - Some(lit) - } - } - - /// Returns a literal suffix of this pattern if the entire pattern matches - /// if the literal suffix matches. - /// - /// If a literal suffix is returned and it must match either the entire - /// file path or be preceded by a `/`, then also return true. This happens - /// with a pattern like `**/foo/bar`. Namely, this pattern matches - /// `foo/bar` and `baz/foo/bar`, but not `foofoo/bar`. In this case, the - /// suffix returned is `/foo/bar` (but should match the entire path - /// `foo/bar`). - /// - /// When this returns true, the suffix literal is guaranteed to start with - /// a `/`. - fn suffix(&self) -> Option<(String, bool)> { - if self.opts.case_insensitive { - return None; - } - let mut lit = String::new(); - let (start, entire) = match self.tokens.get(0) { - Some(&Token::RecursivePrefix) => { - // We only care if this follows a path component if the next - // token is a literal. - if let Some(&Token::Literal(_)) = self.tokens.get(1) { - lit.push('/'); - (1, true) - } else { - (1, false) - } - } - _ => (0, false), - }; - let start = match self.tokens.get(start) { - Some(&Token::ZeroOrMore) => { - // If literal_separator is enabled, then a `*` can't - // necessarily match everything, so reporting a suffix match - // as a match of the pattern would be a false positive. - if self.opts.literal_separator { - return None; - } - start + 1 - } - _ => start, - }; - for t in &self.tokens[start..] { - match *t { - Token::Literal(c) => lit.push(c), - _ => return None, - } - } - if lit.is_empty() || lit == "/" { - None - } else { - Some((lit, entire)) - } - } - - /// If this pattern only needs to inspect the basename of a file path, - /// then the tokens corresponding to only the basename match are returned. - /// - /// For example, given a pattern of `**/*.foo`, only the tokens - /// corresponding to `*.foo` are returned. - /// - /// Note that this will return None if any match of the basename tokens - /// doesn't correspond to a match of the entire pattern. For example, the - /// glob `foo` only matches when a file path has a basename of `foo`, but - /// doesn't *always* match when a file path has a basename of `foo`. e.g., - /// `foo` doesn't match `abc/foo`. - fn basename_tokens(&self) -> Option<&[Token]> { - if self.opts.case_insensitive { - return None; - } - let start = match self.tokens.get(0) { - Some(&Token::RecursivePrefix) => 1, - _ => { - // With nothing to gobble up the parent portion of a path, - // we can't assume that matching on only the basename is - // correct. - return None; - } - }; - if self.tokens[start..].is_empty() { - return None; - } - for t in &self.tokens[start..] { - match *t { - Token::Literal('/') => return None, - Token::Literal(_) => {} // OK - Token::Any | Token::ZeroOrMore => { - if !self.opts.literal_separator { - // In this case, `*` and `?` can match a path - // separator, which means this could reach outside - // the basename. - return None; - } - } - Token::RecursivePrefix - | Token::RecursiveSuffix - | Token::RecursiveZeroOrMore => { - return None; - } - Token::Class{..} | Token::Alternates(..) => { - // We *could* be a little smarter here, but either one - // of these is going to prevent our literal optimizations - // anyway, so give up. - return None; - } - } - } - Some(&self.tokens[start..]) - } - - /// Returns the pattern as a literal if and only if the pattern exclusively - /// matches the basename of a file path *and* is a literal. - /// - /// The basic format of these patterns is `**/{literal}`, where `{literal}` - /// does not contain a path separator. - fn basename_literal(&self) -> Option { - let tokens = match self.basename_tokens() { - None => return None, - Some(tokens) => tokens, - }; - let mut lit = String::new(); - for t in tokens { - match *t { - Token::Literal(c) => lit.push(c), - _ => return None, - } - } - Some(lit) - } -} - -impl<'a> GlobBuilder<'a> { - /// Create a new builder for the pattern given. - /// - /// The pattern is not compiled until `build` is called. - pub fn new(glob: &'a str) -> GlobBuilder<'a> { - GlobBuilder { - glob: glob, - opts: GlobOptions::default(), - } - } - - /// Parses and builds the pattern. - pub fn build(&self) -> Result { - let mut p = Parser { - glob: &self.glob, - stack: vec![Tokens::default()], - chars: self.glob.chars().peekable(), - prev: None, - cur: None, - opts: &self.opts, - }; - p.parse()?; - if p.stack.is_empty() { - Err(Error { - glob: Some(self.glob.to_string()), - kind: ErrorKind::UnopenedAlternates, - }) - } else if p.stack.len() > 1 { - Err(Error { - glob: Some(self.glob.to_string()), - kind: ErrorKind::UnclosedAlternates, - }) - } else { - let tokens = p.stack.pop().unwrap(); - Ok(Glob { - glob: self.glob.to_string(), - re: tokens.to_regex_with(&self.opts), - opts: self.opts, - tokens: tokens, - }) - } - } - - /// Toggle whether the pattern matches case insensitively or not. - /// - /// This is disabled by default. - pub fn case_insensitive(&mut self, yes: bool) -> &mut GlobBuilder<'a> { - self.opts.case_insensitive = yes; - self - } - - /// Toggle whether a literal `/` is required to match a path separator. - pub fn literal_separator(&mut self, yes: bool) -> &mut GlobBuilder<'a> { - self.opts.literal_separator = yes; - self - } - - /// When enabled, a back slash (`\`) may be used to escape - /// special characters in a glob pattern. Additionally, this will - /// prevent `\` from being interpreted as a path separator on all - /// platforms. - /// - /// This is enabled by default on platforms where `\` is not a - /// path separator and disabled by default on platforms where `\` - /// is a path separator. - pub fn backslash_escape(&mut self, yes: bool) -> &mut GlobBuilder<'a> { - self.opts.backslash_escape = yes; - self - } -} - -impl Tokens { - /// Convert this pattern to a string that is guaranteed to be a valid - /// regular expression and will represent the matching semantics of this - /// glob pattern and the options given. - fn to_regex_with(&self, options: &GlobOptions) -> String { - let mut re = String::new(); - re.push_str("(?-u)"); - if options.case_insensitive { - re.push_str("(?i)"); - } - re.push('^'); - // Special case. If the entire glob is just `**`, then it should match - // everything. - if self.len() == 1 && self[0] == Token::RecursivePrefix { - re.push_str(".*"); - re.push('$'); - return re; - } - self.tokens_to_regex(options, &self, &mut re); - re.push('$'); - re - } - - fn tokens_to_regex( - &self, - options: &GlobOptions, - tokens: &[Token], - re: &mut String, - ) { - for tok in tokens { - match *tok { - Token::Literal(c) => { - re.push_str(&char_to_escaped_literal(c)); - } - Token::Any => { - if options.literal_separator { - re.push_str("[^/]"); - } else { - re.push_str("."); - } - } - Token::ZeroOrMore => { - if options.literal_separator { - re.push_str("[^/]*"); - } else { - re.push_str(".*"); - } - } - Token::RecursivePrefix => { - re.push_str("(?:/?|.*/)"); - } - Token::RecursiveSuffix => { - re.push_str("(?:/?|/.*)"); - } - Token::RecursiveZeroOrMore => { - re.push_str("(?:/|/.*/)"); - } - Token::Class { negated, ref ranges } => { - re.push('['); - if negated { - re.push('^'); - } - for r in ranges { - if r.0 == r.1 { - // Not strictly necessary, but nicer to look at. - re.push_str(&char_to_escaped_literal(r.0)); - } else { - re.push_str(&char_to_escaped_literal(r.0)); - re.push('-'); - re.push_str(&char_to_escaped_literal(r.1)); - } - } - re.push(']'); - } - Token::Alternates(ref patterns) => { - let mut parts = vec![]; - for pat in patterns { - let mut altre = String::new(); - self.tokens_to_regex(options, &pat, &mut altre); - if !altre.is_empty() { - parts.push(altre); - } - } - - // It is possible to have an empty set in which case the - // resulting alternation '()' would be an error. - if !parts.is_empty() { - re.push('('); - re.push_str(&parts.join("|")); - re.push(')'); - } - } - } - } - } -} - -/// Convert a Unicode scalar value to an escaped string suitable for use as -/// a literal in a non-Unicode regex. -fn char_to_escaped_literal(c: char) -> String { - bytes_to_escaped_literal(&c.to_string().into_bytes()) -} - -/// Converts an arbitrary sequence of bytes to a UTF-8 string. All non-ASCII -/// code units are converted to their escaped form. -fn bytes_to_escaped_literal(bs: &[u8]) -> String { - let mut s = String::with_capacity(bs.len()); - for &b in bs { - if b <= 0x7F { - s.push_str(®ex::escape(&(b as char).to_string())); - } else { - s.push_str(&format!("\\x{:02x}", b)); - } - } - s -} - -struct Parser<'a> { - glob: &'a str, - stack: Vec, - chars: iter::Peekable>, - prev: Option, - cur: Option, - opts: &'a GlobOptions, -} - -impl<'a> Parser<'a> { - fn error(&self, kind: ErrorKind) -> Error { - Error { glob: Some(self.glob.to_string()), kind: kind } - } - - fn parse(&mut self) -> Result<(), Error> { - while let Some(c) = self.bump() { - match c { - '?' => self.push_token(Token::Any)?, - '*' => self.parse_star()?, - '[' => self.parse_class()?, - '{' => self.push_alternate()?, - '}' => self.pop_alternate()?, - ',' => self.parse_comma()?, - '\\' => self.parse_backslash()?, - c => self.push_token(Token::Literal(c))?, - } - } - Ok(()) - } - - fn push_alternate(&mut self) -> Result<(), Error> { - if self.stack.len() > 1 { - return Err(self.error(ErrorKind::NestedAlternates)); - } - Ok(self.stack.push(Tokens::default())) - } - - fn pop_alternate(&mut self) -> Result<(), Error> { - let mut alts = vec![]; - while self.stack.len() >= 2 { - alts.push(self.stack.pop().unwrap()); - } - self.push_token(Token::Alternates(alts)) - } - - fn push_token(&mut self, tok: Token) -> Result<(), Error> { - if let Some(ref mut pat) = self.stack.last_mut() { - return Ok(pat.push(tok)); - } - Err(self.error(ErrorKind::UnopenedAlternates)) - } - - fn pop_token(&mut self) -> Result { - if let Some(ref mut pat) = self.stack.last_mut() { - return Ok(pat.pop().unwrap()); - } - Err(self.error(ErrorKind::UnopenedAlternates)) - } - - fn have_tokens(&self) -> Result { - match self.stack.last() { - None => Err(self.error(ErrorKind::UnopenedAlternates)), - Some(ref pat) => Ok(!pat.is_empty()), - } - } - - fn parse_comma(&mut self) -> Result<(), Error> { - // If we aren't inside a group alternation, then don't - // treat commas specially. Otherwise, we need to start - // a new alternate. - if self.stack.len() <= 1 { - self.push_token(Token::Literal(',')) - } else { - Ok(self.stack.push(Tokens::default())) - } - } - - fn parse_backslash(&mut self) -> Result<(), Error> { - if self.opts.backslash_escape { - match self.bump() { - None => Err(self.error(ErrorKind::DanglingEscape)), - Some(c) => self.push_token(Token::Literal(c)), - } - } else if is_separator('\\') { - // Normalize all patterns to use / as a separator. - self.push_token(Token::Literal('/')) - } else { - self.push_token(Token::Literal('\\')) - } - } - - fn parse_star(&mut self) -> Result<(), Error> { - let prev = self.prev; - if self.chars.peek() != Some(&'*') { - self.push_token(Token::ZeroOrMore)?; - return Ok(()); - } - assert!(self.bump() == Some('*')); - if !self.have_tokens()? { - self.push_token(Token::RecursivePrefix)?; - let next = self.bump(); - if !next.map(is_separator).unwrap_or(true) { - return Err(self.error(ErrorKind::InvalidRecursive)); - } - return Ok(()); - } - self.pop_token()?; - if !prev.map(is_separator).unwrap_or(false) { - if self.stack.len() <= 1 - || (prev != Some(',') && prev != Some('{')) { - return Err(self.error(ErrorKind::InvalidRecursive)); - } - } - match self.chars.peek() { - None => { - assert!(self.bump().is_none()); - self.push_token(Token::RecursiveSuffix) - } - Some(&',') | Some(&'}') if self.stack.len() >= 2 => { - self.push_token(Token::RecursiveSuffix) - } - Some(&c) if is_separator(c) => { - assert!(self.bump().map(is_separator).unwrap_or(false)); - self.push_token(Token::RecursiveZeroOrMore) - } - _ => Err(self.error(ErrorKind::InvalidRecursive)), - } - } - - fn parse_class(&mut self) -> Result<(), Error> { - fn add_to_last_range( - glob: &str, - r: &mut (char, char), - add: char, - ) -> Result<(), Error> { - r.1 = add; - if r.1 < r.0 { - Err(Error { - glob: Some(glob.to_string()), - kind: ErrorKind::InvalidRange(r.0, r.1), - }) - } else { - Ok(()) - } - } - let mut ranges = vec![]; - let negated = match self.chars.peek() { - Some(&'!') | Some(&'^') => { - let bump = self.bump(); - assert!(bump == Some('!') || bump == Some('^')); - true - } - _ => false, - }; - let mut first = true; - let mut in_range = false; - loop { - let c = match self.bump() { - Some(c) => c, - // The only way to successfully break this loop is to observe - // a ']'. - None => return Err(self.error(ErrorKind::UnclosedClass)), - }; - match c { - ']' => { - if first { - ranges.push((']', ']')); - } else { - break; - } - } - '-' => { - if first { - ranges.push(('-', '-')); - } else if in_range { - // invariant: in_range is only set when there is - // already at least one character seen. - let r = ranges.last_mut().unwrap(); - add_to_last_range(&self.glob, r, '-')?; - in_range = false; - } else { - assert!(!ranges.is_empty()); - in_range = true; - } - } - c => { - if in_range { - // invariant: in_range is only set when there is - // already at least one character seen. - add_to_last_range( - &self.glob, ranges.last_mut().unwrap(), c)?; - } else { - ranges.push((c, c)); - } - in_range = false; - } - } - first = false; - } - if in_range { - // Means that the last character in the class was a '-', so add - // it as a literal. - ranges.push(('-', '-')); - } - self.push_token(Token::Class { - negated: negated, - ranges: ranges, - }) - } - - fn bump(&mut self) -> Option { - self.prev = self.cur; - self.cur = self.chars.next(); - self.cur - } -} - -#[cfg(test)] -fn starts_with(needle: &[u8], haystack: &[u8]) -> bool { - needle.len() <= haystack.len() && needle == &haystack[..needle.len()] -} - -#[cfg(test)] -fn ends_with(needle: &[u8], haystack: &[u8]) -> bool { - if needle.len() > haystack.len() { - return false; - } - needle == &haystack[haystack.len() - needle.len()..] -} - -#[cfg(test)] -mod tests { - use {GlobSetBuilder, ErrorKind}; - use super::{Glob, GlobBuilder, Token}; - use super::Token::*; - - #[derive(Clone, Copy, Debug, Default)] - struct Options { - casei: Option, - litsep: Option, - bsesc: Option, - } - - macro_rules! syntax { - ($name:ident, $pat:expr, $tokens:expr) => { - #[test] - fn $name() { - let pat = Glob::new($pat).unwrap(); - assert_eq!($tokens, pat.tokens.0); - } - } - } - - macro_rules! syntaxerr { - ($name:ident, $pat:expr, $err:expr) => { - #[test] - fn $name() { - let err = Glob::new($pat).unwrap_err(); - assert_eq!(&$err, err.kind()); - } - } - } - - macro_rules! toregex { - ($name:ident, $pat:expr, $re:expr) => { - toregex!($name, $pat, $re, Options::default()); - }; - ($name:ident, $pat:expr, $re:expr, $options:expr) => { - #[test] - fn $name() { - let mut builder = GlobBuilder::new($pat); - if let Some(casei) = $options.casei { - builder.case_insensitive(casei); - } - if let Some(litsep) = $options.litsep { - builder.literal_separator(litsep); - } - if let Some(bsesc) = $options.bsesc { - builder.backslash_escape(bsesc); - } - let pat = builder.build().unwrap(); - assert_eq!(format!("(?-u){}", $re), pat.regex()); - } - }; - } - - macro_rules! matches { - ($name:ident, $pat:expr, $path:expr) => { - matches!($name, $pat, $path, Options::default()); - }; - ($name:ident, $pat:expr, $path:expr, $options:expr) => { - #[test] - fn $name() { - let mut builder = GlobBuilder::new($pat); - if let Some(casei) = $options.casei { - builder.case_insensitive(casei); - } - if let Some(litsep) = $options.litsep { - builder.literal_separator(litsep); - } - if let Some(bsesc) = $options.bsesc { - builder.backslash_escape(bsesc); - } - let pat = builder.build().unwrap(); - let matcher = pat.compile_matcher(); - let strategic = pat.compile_strategic_matcher(); - let set = GlobSetBuilder::new().add(pat).build().unwrap(); - assert!(matcher.is_match($path)); - assert!(strategic.is_match($path)); - assert!(set.is_match($path)); - } - }; - } - - macro_rules! nmatches { - ($name:ident, $pat:expr, $path:expr) => { - nmatches!($name, $pat, $path, Options::default()); - }; - ($name:ident, $pat:expr, $path:expr, $options:expr) => { - #[test] - fn $name() { - let mut builder = GlobBuilder::new($pat); - if let Some(casei) = $options.casei { - builder.case_insensitive(casei); - } - if let Some(litsep) = $options.litsep { - builder.literal_separator(litsep); - } - if let Some(bsesc) = $options.bsesc { - builder.backslash_escape(bsesc); - } - let pat = builder.build().unwrap(); - let matcher = pat.compile_matcher(); - let strategic = pat.compile_strategic_matcher(); - let set = GlobSetBuilder::new().add(pat).build().unwrap(); - assert!(!matcher.is_match($path)); - assert!(!strategic.is_match($path)); - assert!(!set.is_match($path)); - } - }; - } - - fn s(string: &str) -> String { string.to_string() } - - fn class(s: char, e: char) -> Token { - Class { negated: false, ranges: vec![(s, e)] } - } - - fn classn(s: char, e: char) -> Token { - Class { negated: true, ranges: vec![(s, e)] } - } - - fn rclass(ranges: &[(char, char)]) -> Token { - Class { negated: false, ranges: ranges.to_vec() } - } - - fn rclassn(ranges: &[(char, char)]) -> Token { - Class { negated: true, ranges: ranges.to_vec() } - } - - syntax!(literal1, "a", vec![Literal('a')]); - syntax!(literal2, "ab", vec![Literal('a'), Literal('b')]); - syntax!(any1, "?", vec![Any]); - syntax!(any2, "a?b", vec![Literal('a'), Any, Literal('b')]); - syntax!(seq1, "*", vec![ZeroOrMore]); - syntax!(seq2, "a*b", vec![Literal('a'), ZeroOrMore, Literal('b')]); - syntax!(seq3, "*a*b*", vec![ - ZeroOrMore, Literal('a'), ZeroOrMore, Literal('b'), ZeroOrMore, - ]); - syntax!(rseq1, "**", vec![RecursivePrefix]); - syntax!(rseq2, "**/", vec![RecursivePrefix]); - syntax!(rseq3, "/**", vec![RecursiveSuffix]); - syntax!(rseq4, "/**/", vec![RecursiveZeroOrMore]); - syntax!(rseq5, "a/**/b", vec![ - Literal('a'), RecursiveZeroOrMore, Literal('b'), - ]); - syntax!(cls1, "[a]", vec![class('a', 'a')]); - syntax!(cls2, "[!a]", vec![classn('a', 'a')]); - syntax!(cls3, "[a-z]", vec![class('a', 'z')]); - syntax!(cls4, "[!a-z]", vec![classn('a', 'z')]); - syntax!(cls5, "[-]", vec![class('-', '-')]); - syntax!(cls6, "[]]", vec![class(']', ']')]); - syntax!(cls7, "[*]", vec![class('*', '*')]); - syntax!(cls8, "[!!]", vec![classn('!', '!')]); - syntax!(cls9, "[a-]", vec![rclass(&[('a', 'a'), ('-', '-')])]); - syntax!(cls10, "[-a-z]", vec![rclass(&[('-', '-'), ('a', 'z')])]); - syntax!(cls11, "[a-z-]", vec![rclass(&[('a', 'z'), ('-', '-')])]); - syntax!(cls12, "[-a-z-]", vec![ - rclass(&[('-', '-'), ('a', 'z'), ('-', '-')]), - ]); - syntax!(cls13, "[]-z]", vec![class(']', 'z')]); - syntax!(cls14, "[--z]", vec![class('-', 'z')]); - syntax!(cls15, "[ --]", vec![class(' ', '-')]); - syntax!(cls16, "[0-9a-z]", vec![rclass(&[('0', '9'), ('a', 'z')])]); - syntax!(cls17, "[a-z0-9]", vec![rclass(&[('a', 'z'), ('0', '9')])]); - syntax!(cls18, "[!0-9a-z]", vec![rclassn(&[('0', '9'), ('a', 'z')])]); - syntax!(cls19, "[!a-z0-9]", vec![rclassn(&[('a', 'z'), ('0', '9')])]); - syntax!(cls20, "[^a]", vec![classn('a', 'a')]); - syntax!(cls21, "[^a-z]", vec![classn('a', 'z')]); - - syntaxerr!(err_rseq1, "a**", ErrorKind::InvalidRecursive); - syntaxerr!(err_rseq2, "**a", ErrorKind::InvalidRecursive); - syntaxerr!(err_rseq3, "a**b", ErrorKind::InvalidRecursive); - syntaxerr!(err_rseq4, "***", ErrorKind::InvalidRecursive); - syntaxerr!(err_rseq5, "/a**", ErrorKind::InvalidRecursive); - syntaxerr!(err_rseq6, "/**a", ErrorKind::InvalidRecursive); - syntaxerr!(err_rseq7, "/a**b", ErrorKind::InvalidRecursive); - syntaxerr!(err_unclosed1, "[", ErrorKind::UnclosedClass); - syntaxerr!(err_unclosed2, "[]", ErrorKind::UnclosedClass); - syntaxerr!(err_unclosed3, "[!", ErrorKind::UnclosedClass); - syntaxerr!(err_unclosed4, "[!]", ErrorKind::UnclosedClass); - syntaxerr!(err_range1, "[z-a]", ErrorKind::InvalidRange('z', 'a')); - syntaxerr!(err_range2, "[z--]", ErrorKind::InvalidRange('z', '-')); - - const CASEI: Options = Options { - casei: Some(true), - litsep: None, - bsesc: None, - }; - const SLASHLIT: Options = Options { - casei: None, - 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_slash1, "?", r"^[^/]$", SLASHLIT); - toregex!(re_slash2, "*", r"^[^/]*$", SLASHLIT); - - toregex!(re1, "a", "^a$"); - toregex!(re2, "?", "^.$"); - toregex!(re3, "*", "^.*$"); - toregex!(re4, "a?", "^a.$"); - toregex!(re5, "?a", "^.a$"); - toregex!(re6, "a*", "^a.*$"); - toregex!(re7, "*a", "^.*a$"); - toregex!(re8, "[*]", r"^[\*]$"); - toregex!(re9, "[+]", r"^[\+]$"); - toregex!(re10, "+", r"^\+$"); - toregex!(re11, "**", r"^.*$"); - toregex!(re12, "☃", r"^\xe2\x98\x83$"); - - matches!(match1, "a", "a"); - matches!(match2, "a*b", "a_b"); - matches!(match3, "a*b*c", "abc"); - matches!(match4, "a*b*c", "a_b_c"); - matches!(match5, "a*b*c", "a___b___c"); - matches!(match6, "abc*abc*abc", "abcabcabcabcabcabcabc"); - matches!(match7, "a*a*a*a*a*a*a*a*a", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); - matches!(match8, "a*b[xyz]c*d", "abxcdbxcddd"); - matches!(match9, "*.rs", ".rs"); - matches!(match10, "☃", "☃"); - - matches!(matchrec1, "some/**/needle.txt", "some/needle.txt"); - matches!(matchrec2, "some/**/needle.txt", "some/one/needle.txt"); - matches!(matchrec3, "some/**/needle.txt", "some/one/two/needle.txt"); - matches!(matchrec4, "some/**/needle.txt", "some/other/needle.txt"); - matches!(matchrec5, "**", "abcde"); - matches!(matchrec6, "**", ""); - matches!(matchrec7, "**", ".asdf"); - matches!(matchrec8, "**", "/x/.asdf"); - matches!(matchrec9, "some/**/**/needle.txt", "some/needle.txt"); - matches!(matchrec10, "some/**/**/needle.txt", "some/one/needle.txt"); - matches!(matchrec11, "some/**/**/needle.txt", "some/one/two/needle.txt"); - matches!(matchrec12, "some/**/**/needle.txt", "some/other/needle.txt"); - matches!(matchrec13, "**/test", "one/two/test"); - matches!(matchrec14, "**/test", "one/test"); - matches!(matchrec15, "**/test", "test"); - matches!(matchrec16, "/**/test", "/one/two/test"); - matches!(matchrec17, "/**/test", "/one/test"); - matches!(matchrec18, "/**/test", "/test"); - matches!(matchrec19, "**/.*", ".abc"); - matches!(matchrec20, "**/.*", "abc/.abc"); - matches!(matchrec21, ".*/**", ".abc"); - matches!(matchrec22, ".*/**", ".abc/abc"); - matches!(matchrec23, "foo/**", "foo"); - matches!(matchrec24, "**/foo/bar", "foo/bar"); - matches!(matchrec25, "some/*/needle.txt", "some/one/needle.txt"); - - matches!(matchrange1, "a[0-9]b", "a0b"); - matches!(matchrange2, "a[0-9]b", "a9b"); - matches!(matchrange3, "a[!0-9]b", "a_b"); - matches!(matchrange4, "[a-z123]", "1"); - matches!(matchrange5, "[1a-z23]", "1"); - matches!(matchrange6, "[123a-z]", "1"); - matches!(matchrange7, "[abc-]", "-"); - matches!(matchrange8, "[-abc]", "-"); - matches!(matchrange9, "[-a-c]", "b"); - matches!(matchrange10, "[a-c-]", "b"); - matches!(matchrange11, "[-]", "-"); - matches!(matchrange12, "a[^0-9]b", "a_b"); - - matches!(matchpat1, "*hello.txt", "hello.txt"); - matches!(matchpat2, "*hello.txt", "gareth_says_hello.txt"); - matches!(matchpat3, "*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!(matchpat6, "*some/path/to/hello.txt", "some/path/to/hello.txt"); - matches!(matchpat7, "*some/path/to/hello.txt", - "a/bigger/some/path/to/hello.txt"); - - matches!(matchescape, "_[[]_[]]_[?]_[*]_!_", "_[_]_?_*_!_"); - - matches!(matchcasei1, "aBcDeFg", "aBcDeFg", CASEI); - matches!(matchcasei2, "aBcDeFg", "abcdefg", CASEI); - matches!(matchcasei3, "aBcDeFg", "ABCDEFG", CASEI); - matches!(matchcasei4, "aBcDeFg", "AbCdEfG", CASEI); - - matches!(matchalt1, "a,b", "a,b"); - matches!(matchalt2, ",", ","); - matches!(matchalt3, "{a,b}", "a"); - matches!(matchalt4, "{a,b}", "b"); - matches!(matchalt5, "{**/src/**,foo}", "abc/src/bar"); - matches!(matchalt6, "{**/src/**,foo}", "foo"); - matches!(matchalt7, "{[}],foo}", "}"); - matches!(matchalt8, "{foo}", "foo"); - matches!(matchalt9, "{}", ""); - matches!(matchalt10, "{,}", ""); - matches!(matchalt11, "{*.foo,*.bar,*.wat}", "test.foo"); - matches!(matchalt12, "{*.foo,*.bar,*.wat}", "test.bar"); - matches!(matchalt13, "{*.foo,*.bar,*.wat}", "test.wat"); - - matches!(matchslash1, "abc/def", "abc/def", SLASHLIT); - #[cfg(unix)] - nmatches!(matchslash2, "abc?def", "abc/def", SLASHLIT); - #[cfg(not(unix))] - nmatches!(matchslash2, "abc?def", "abc\\def", SLASHLIT); - nmatches!(matchslash3, "abc*def", "abc/def", SLASHLIT); - matches!(matchslash4, "abc[/]def", "abc/def", SLASHLIT); // differs - #[cfg(unix)] - nmatches!(matchslash5, "abc\\def", "abc/def", SLASHLIT); - #[cfg(not(unix))] - matches!(matchslash5, "abc\\def", "abc/def", SLASHLIT); - - matches!(matchbackslash1, "\\[", "[", BSESC); - matches!(matchbackslash2, "\\?", "?", BSESC); - matches!(matchbackslash3, "\\*", "*", BSESC); - matches!(matchbackslash4, "\\[a-z]", "\\a", NOBSESC); - matches!(matchbackslash5, "\\?", "\\a", NOBSESC); - matches!(matchbackslash6, "\\*", "\\\\", NOBSESC); - #[cfg(unix)] - matches!(matchbackslash7, "\\a", "a"); - #[cfg(not(unix))] - matches!(matchbackslash8, "\\a", "/a"); - - nmatches!(matchnot1, "a*b*c", "abcd"); - nmatches!(matchnot2, "abc*abc*abc", "abcabcabcabcabcabcabca"); - nmatches!(matchnot3, "some/**/needle.txt", "some/other/notthis.txt"); - nmatches!(matchnot4, "some/**/**/needle.txt", "some/other/notthis.txt"); - nmatches!(matchnot5, "/**/test", "test"); - nmatches!(matchnot6, "/**/test", "/one/notthis"); - nmatches!(matchnot7, "/**/test", "/notthis"); - nmatches!(matchnot8, "**/.*", "ab.c"); - nmatches!(matchnot9, "**/.*", "abc/ab.c"); - nmatches!(matchnot10, ".*/**", "a.bc"); - nmatches!(matchnot11, ".*/**", "abc/a.bc"); - nmatches!(matchnot12, "a[0-9]b", "a_b"); - nmatches!(matchnot13, "a[!0-9]b", "a0b"); - nmatches!(matchnot14, "a[!0-9]b", "a9b"); - nmatches!(matchnot15, "[!-]", "-"); - nmatches!(matchnot16, "*hello.txt", "hello.txt-and-then-some"); - nmatches!(matchnot17, "*hello.txt", "goodbye.txt"); - nmatches!(matchnot18, "*some/path/to/hello.txt", - "some/path/to/hello.txt-and-then-some"); - nmatches!(matchnot19, "*some/path/to/hello.txt", - "some/other/path/to/hello.txt"); - nmatches!(matchnot20, "a", "foo/a"); - nmatches!(matchnot21, "./foo", "foo"); - nmatches!(matchnot22, "**/foo", "foofoo"); - nmatches!(matchnot23, "**/foo/bar", "foofoo/bar"); - nmatches!(matchnot24, "/*.c", "mozilla-sha1/sha1.c"); - nmatches!(matchnot25, "*.c", "mozilla-sha1/sha1.c", SLASHLIT); - nmatches!(matchnot26, "**/m4/ltoptions.m4", - "csharp/src/packages/repositories.config", SLASHLIT); - nmatches!(matchnot27, "a[^0-9]b", "a0b"); - nmatches!(matchnot28, "a[^0-9]b", "a9b"); - nmatches!(matchnot29, "[^-]", "-"); - nmatches!(matchnot30, "some/*/needle.txt", "some/needle.txt"); - nmatches!( - matchrec31, - "some/*/needle.txt", "some/one/two/needle.txt", SLASHLIT); - nmatches!( - matchrec32, - "some/*/needle.txt", "some/one/two/three/needle.txt", SLASHLIT); - - macro_rules! extract { - ($which:ident, $name:ident, $pat:expr, $expect:expr) => { - extract!($which, $name, $pat, $expect, Options::default()); - }; - ($which:ident, $name:ident, $pat:expr, $expect:expr, $options:expr) => { - #[test] - fn $name() { - let mut builder = GlobBuilder::new($pat); - if let Some(casei) = $options.casei { - builder.case_insensitive(casei); - } - if let Some(litsep) = $options.litsep { - builder.literal_separator(litsep); - } - if let Some(bsesc) = $options.bsesc { - builder.backslash_escape(bsesc); - } - let pat = builder.build().unwrap(); - assert_eq!($expect, pat.$which()); - } - }; - } - - macro_rules! literal { - ($($tt:tt)*) => { extract!(literal, $($tt)*); } - } - - macro_rules! basetokens { - ($($tt:tt)*) => { extract!(basename_tokens, $($tt)*); } - } - - macro_rules! ext { - ($($tt:tt)*) => { extract!(ext, $($tt)*); } - } - - macro_rules! required_ext { - ($($tt:tt)*) => { extract!(required_ext, $($tt)*); } - } - - macro_rules! prefix { - ($($tt:tt)*) => { extract!(prefix, $($tt)*); } - } - - macro_rules! suffix { - ($($tt:tt)*) => { extract!(suffix, $($tt)*); } - } - - macro_rules! baseliteral { - ($($tt:tt)*) => { extract!(basename_literal, $($tt)*); } - } - - literal!(extract_lit1, "foo", Some(s("foo"))); - literal!(extract_lit2, "foo", None, CASEI); - literal!(extract_lit3, "/foo", Some(s("/foo"))); - literal!(extract_lit4, "/foo/", Some(s("/foo/"))); - literal!(extract_lit5, "/foo/bar", Some(s("/foo/bar"))); - literal!(extract_lit6, "*.foo", None); - literal!(extract_lit7, "foo/bar", Some(s("foo/bar"))); - literal!(extract_lit8, "**/foo/bar", None); - - basetokens!(extract_basetoks1, "**/foo", Some(&*vec![ - Literal('f'), Literal('o'), Literal('o'), - ])); - basetokens!(extract_basetoks2, "**/foo", None, CASEI); - basetokens!(extract_basetoks3, "**/foo", Some(&*vec![ - Literal('f'), Literal('o'), Literal('o'), - ]), SLASHLIT); - basetokens!(extract_basetoks4, "*foo", None, SLASHLIT); - basetokens!(extract_basetoks5, "*foo", None); - basetokens!(extract_basetoks6, "**/fo*o", None); - basetokens!(extract_basetoks7, "**/fo*o", Some(&*vec![ - Literal('f'), Literal('o'), ZeroOrMore, Literal('o'), - ]), SLASHLIT); - - ext!(extract_ext1, "**/*.rs", Some(s(".rs"))); - ext!(extract_ext2, "**/*.rs.bak", None); - ext!(extract_ext3, "*.rs", Some(s(".rs"))); - ext!(extract_ext4, "a*.rs", None); - ext!(extract_ext5, "/*.c", None); - ext!(extract_ext6, "*.c", None, SLASHLIT); - ext!(extract_ext7, "*.c", Some(s(".c"))); - - required_ext!(extract_req_ext1, "*.rs", Some(s(".rs"))); - required_ext!(extract_req_ext2, "/foo/bar/*.rs", Some(s(".rs"))); - required_ext!(extract_req_ext3, "/foo/bar/*.rs", Some(s(".rs"))); - required_ext!(extract_req_ext4, "/foo/bar/.rs", Some(s(".rs"))); - required_ext!(extract_req_ext5, ".rs", Some(s(".rs"))); - required_ext!(extract_req_ext6, "./rs", None); - required_ext!(extract_req_ext7, "foo", None); - required_ext!(extract_req_ext8, ".foo/", None); - required_ext!(extract_req_ext9, "foo/", None); - - prefix!(extract_prefix1, "/foo", Some(s("/foo"))); - prefix!(extract_prefix2, "/foo/*", Some(s("/foo/"))); - prefix!(extract_prefix3, "**/foo", None); - prefix!(extract_prefix4, "foo/**", None); - - suffix!(extract_suffix1, "**/foo/bar", Some((s("/foo/bar"), true))); - suffix!(extract_suffix2, "*/foo/bar", Some((s("/foo/bar"), false))); - suffix!(extract_suffix3, "*/foo/bar", None, SLASHLIT); - suffix!(extract_suffix4, "foo/bar", Some((s("foo/bar"), false))); - suffix!(extract_suffix5, "*.foo", Some((s(".foo"), false))); - suffix!(extract_suffix6, "*.foo", None, SLASHLIT); - suffix!(extract_suffix7, "**/*_test", Some((s("_test"), false))); - - baseliteral!(extract_baselit1, "**/foo", Some(s("foo"))); - baseliteral!(extract_baselit2, "foo", None); - baseliteral!(extract_baselit3, "*foo", None); - baseliteral!(extract_baselit4, "*/foo", None); -} diff --git a/globset/src/lib.rs b/globset/src/lib.rs deleted file mode 100644 index 50c92e4..0000000 --- a/globset/src/lib.rs +++ /dev/null @@ -1,867 +0,0 @@ -/*! -The globset crate provides cross platform single glob and glob set matching. - -Glob set matching is the process of matching one or more glob patterns against -a single candidate path simultaneously, and returning all of the globs that -matched. For example, given this set of globs: - -```ignore -*.rs -src/lib.rs -src/**/foo.rs -``` - -and a path `src/bar/baz/foo.rs`, then the set would report the first and third -globs as matching. - -# Example: one glob - -This example shows how to match a single glob against a single file path. - -``` -# fn example() -> Result<(), globset::Error> { -use globset::Glob; - -let glob = Glob::new("*.rs")?.compile_matcher(); - -assert!(glob.is_match("foo.rs")); -assert!(glob.is_match("foo/bar.rs")); -assert!(!glob.is_match("Cargo.toml")); -# Ok(()) } example().unwrap(); -``` - -# Example: configuring a glob matcher - -This example shows how to use a `GlobBuilder` to configure aspects of match -semantics. In this example, we prevent wildcards from matching path separators. - -``` -# fn example() -> Result<(), globset::Error> { -use globset::GlobBuilder; - -let glob = GlobBuilder::new("*.rs") - .literal_separator(true).build()?.compile_matcher(); - -assert!(glob.is_match("foo.rs")); -assert!(!glob.is_match("foo/bar.rs")); // no longer matches -assert!(!glob.is_match("Cargo.toml")); -# Ok(()) } example().unwrap(); -``` - -# Example: match multiple globs at once - -This example shows how to match multiple glob patterns at once. - -``` -# fn example() -> Result<(), globset::Error> { -use globset::{Glob, GlobSetBuilder}; - -let mut builder = GlobSetBuilder::new(); -// A GlobBuilder can be used to configure each glob's match semantics -// independently. -builder.add(Glob::new("*.rs")?); -builder.add(Glob::new("src/lib.rs")?); -builder.add(Glob::new("src/**/foo.rs")?); -let set = builder.build()?; - -assert_eq!(set.matches("src/bar/baz/foo.rs"), vec![0, 2]); -# Ok(()) } example().unwrap(); -``` - -# Syntax - -Standard Unix-style glob syntax is supported: - -* `?` matches any single character. (If the `literal_separator` option is - enabled, then `?` can never match a path separator.) -* `*` matches zero or more characters. (If the `literal_separator` option is - enabled, then `*` can never match a path separator.) -* `**` recursively matches directories but are only legal in three situations. - First, if the glob starts with \*\*/, then it matches - all directories. For example, \*\*/foo matches `foo` - and `bar/foo` but not `foo/bar`. Secondly, if the glob ends with - /\*\*, then it matches all sub-entries. For example, - foo/\*\* matches `foo/a` and `foo/a/b`, but not `foo`. - Thirdly, if the glob contains /\*\*/ anywhere within - the pattern, then it matches zero or more directories. Using `**` anywhere - else is illegal (N.B. the glob `**` is allowed and means "match everything"). -* `{a,b}` matches `a` or `b` where `a` and `b` are arbitrary glob patterns. - (N.B. Nesting `{...}` is not currently allowed.) -* `[ab]` matches `a` or `b` where `a` and `b` are characters. Use - `[!ab]` to match any character except for `a` and `b`. -* Metacharacters such as `*` and `?` can be escaped with character class - notation. e.g., `[*]` matches `*`. -* When backslash escapes are enabled, a backslash (`\`) will escape all meta - characters in a glob. If it precedes a non-meta character, then the slash is - ignored. A `\\` will match a literal `\\`. Note that this mode is only - enabled on Unix platforms by default, but can be enabled on any platform - via the `backslash_escape` setting on `Glob`. - -A `GlobBuilder` can be used to prevent wildcards from matching path separators, -or to enable case insensitive matching. -*/ - -#![deny(missing_docs)] - -extern crate aho_corasick; -extern crate fnv; -#[macro_use] -extern crate log; -extern crate memchr; -extern crate regex; - -use std::borrow::Cow; -use std::collections::{BTreeMap, HashMap}; -use std::error::Error as StdError; -use std::ffi::OsStr; -use std::fmt; -use std::hash; -use std::path::Path; -use std::str; - -use aho_corasick::{Automaton, AcAutomaton, FullAcAutomaton}; -use regex::bytes::{Regex, RegexBuilder, RegexSet}; - -use pathutil::{ - file_name, file_name_ext, normalize_path, os_str_bytes, path_bytes, -}; -use glob::MatchStrategy; -pub use glob::{Glob, GlobBuilder, GlobMatcher}; - -mod glob; -mod pathutil; - -/// Represents an error that can occur when parsing a glob pattern. -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct Error { - /// The original glob provided by the caller. - glob: Option, - /// The kind of error. - kind: ErrorKind, -} - -/// The kind of error that can occur when parsing a glob pattern. -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum ErrorKind { - /// Occurs when a use of `**` is invalid. Namely, `**` can only appear - /// adjacent to a path separator, or the beginning/end of a glob. - InvalidRecursive, - /// Occurs when a character class (e.g., `[abc]`) is not closed. - UnclosedClass, - /// Occurs when a range in a character (e.g., `[a-z]`) is invalid. For - /// example, if the range starts with a lexicographically larger character - /// than it ends with. - InvalidRange(char, char), - /// Occurs when a `}` is found without a matching `{`. - UnopenedAlternates, - /// Occurs when a `{` is found without a matching `}`. - UnclosedAlternates, - /// Occurs when an alternating group is nested inside another alternating - /// group, e.g., `{{a,b},{c,d}}`. - NestedAlternates, - /// Occurs when an unescaped '\' is found at the end of a glob. - DanglingEscape, - /// An error associated with parsing or compiling a regex. - Regex(String), - /// Hints that destructuring should not be exhaustive. - /// - /// This enum may grow additional variants, so this makes sure clients - /// don't count on exhaustive matching. (Otherwise, adding a new variant - /// could break existing code.) - #[doc(hidden)] - __Nonexhaustive, -} - -impl StdError for Error { - fn description(&self) -> &str { - self.kind.description() - } -} - -impl Error { - /// Return the glob that caused this error, if one exists. - pub fn glob(&self) -> Option<&str> { - self.glob.as_ref().map(|s| &**s) - } - - /// Return the kind of this error. - pub fn kind(&self) -> &ErrorKind { - &self.kind - } -} - -impl ErrorKind { - fn description(&self) -> &str { - match *self { - ErrorKind::InvalidRecursive => { - "invalid use of **; must be one path component" - } - ErrorKind::UnclosedClass => { - "unclosed character class; missing ']'" - } - ErrorKind::InvalidRange(_, _) => { - "invalid character range" - } - ErrorKind::UnopenedAlternates => { - "unopened alternate group; missing '{' \ - (maybe escape '}' with '[}]'?)" - } - ErrorKind::UnclosedAlternates => { - "unclosed alternate group; missing '}' \ - (maybe escape '{' with '[{]'?)" - } - ErrorKind::NestedAlternates => { - "nested alternate groups are not allowed" - } - ErrorKind::DanglingEscape => { - "dangling '\\'" - } - ErrorKind::Regex(ref err) => err, - ErrorKind::__Nonexhaustive => unreachable!(), - } - } -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self.glob { - None => self.kind.fmt(f), - Some(ref glob) => { - write!(f, "error parsing glob '{}': {}", glob, self.kind) - } - } - } -} - -impl fmt::Display for ErrorKind { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - ErrorKind::InvalidRecursive - | ErrorKind::UnclosedClass - | ErrorKind::UnopenedAlternates - | ErrorKind::UnclosedAlternates - | ErrorKind::NestedAlternates - | ErrorKind::DanglingEscape - | ErrorKind::Regex(_) => { - write!(f, "{}", self.description()) - } - ErrorKind::InvalidRange(s, e) => { - write!(f, "invalid range; '{}' > '{}'", s, e) - } - ErrorKind::__Nonexhaustive => unreachable!(), - } - } -} - -fn new_regex(pat: &str) -> Result { - RegexBuilder::new(pat) - .dot_matches_new_line(true) - .size_limit(10 * (1 << 20)) - .dfa_size_limit(10 * (1 << 20)) - .build() - .map_err(|err| { - Error { - glob: Some(pat.to_string()), - kind: ErrorKind::Regex(err.to_string()), - } - }) -} - -fn new_regex_set(pats: I) -> Result - where S: AsRef, I: IntoIterator { - RegexSet::new(pats).map_err(|err| { - Error { - glob: None, - kind: ErrorKind::Regex(err.to_string()), - } - }) -} - -type Fnv = hash::BuildHasherDefault; - -/// GlobSet represents a group of globs that can be matched together in a -/// single pass. -#[derive(Clone, Debug)] -pub struct GlobSet { - len: usize, - strats: Vec, -} - -impl GlobSet { - /// Create an empty `GlobSet`. An empty set matches nothing. - pub fn empty() -> GlobSet { - GlobSet { - len: 0, - strats: vec![], - } - } - - /// Returns true if this set is empty, and therefore matches nothing. - pub fn is_empty(&self) -> bool { - self.len == 0 - } - - /// Returns the number of globs in this set. - pub fn len(&self) -> usize { - self.len - } - - /// Returns true if any glob in this set matches the path given. - pub fn is_match>(&self, path: P) -> bool { - self.is_match_candidate(&Candidate::new(path.as_ref())) - } - - /// Returns true if any glob in this set matches the path given. - /// - /// This takes a Candidate as input, which can be used to amortize the - /// cost of preparing a path for matching. - pub fn is_match_candidate(&self, path: &Candidate) -> bool { - if self.is_empty() { - return false; - } - for strat in &self.strats { - if strat.is_match(path) { - return true; - } - } - false - } - - /// Returns the sequence number of every glob pattern that matches the - /// given path. - pub fn matches>(&self, path: P) -> Vec { - self.matches_candidate(&Candidate::new(path.as_ref())) - } - - /// Returns the sequence number of every glob pattern that matches the - /// given path. - /// - /// This takes a Candidate as input, which can be used to amortize the - /// cost of preparing a path for matching. - pub fn matches_candidate(&self, path: &Candidate) -> Vec { - let mut into = vec![]; - if self.is_empty() { - return into; - } - self.matches_candidate_into(path, &mut into); - into - } - - /// Adds the sequence number of every glob pattern that matches the given - /// path to the vec given. - /// - /// `into` is is cleared before matching begins, and contains the set of - /// sequence numbers (in ascending order) after matching ends. If no globs - /// were matched, then `into` will be empty. - pub fn matches_into>( - &self, - path: P, - into: &mut Vec, - ) { - self.matches_candidate_into(&Candidate::new(path.as_ref()), into); - } - - /// Adds the sequence number of every glob pattern that matches the given - /// path to the vec given. - /// - /// `into` is is cleared before matching begins, and contains the set of - /// sequence numbers (in ascending order) after matching ends. If no globs - /// were matched, then `into` will be empty. - /// - /// This takes a Candidate as input, which can be used to amortize the - /// cost of preparing a path for matching. - pub fn matches_candidate_into( - &self, - path: &Candidate, - into: &mut Vec, - ) { - into.clear(); - if self.is_empty() { - return; - } - for strat in &self.strats { - strat.matches_into(path, into); - } - into.sort(); - into.dedup(); - } - - fn new(pats: &[Glob]) -> Result { - if pats.is_empty() { - return Ok(GlobSet { len: 0, strats: vec![] }); - } - let mut lits = LiteralStrategy::new(); - let mut base_lits = BasenameLiteralStrategy::new(); - let mut exts = ExtensionStrategy::new(); - let mut prefixes = MultiStrategyBuilder::new(); - let mut suffixes = MultiStrategyBuilder::new(); - let mut required_exts = RequiredExtensionStrategyBuilder::new(); - let mut regexes = MultiStrategyBuilder::new(); - for (i, p) in pats.iter().enumerate() { - match MatchStrategy::new(p) { - MatchStrategy::Literal(lit) => { - lits.add(i, lit); - } - MatchStrategy::BasenameLiteral(lit) => { - base_lits.add(i, lit); - } - MatchStrategy::Extension(ext) => { - exts.add(i, ext); - } - MatchStrategy::Prefix(prefix) => { - prefixes.add(i, prefix); - } - MatchStrategy::Suffix { suffix, component } => { - if component { - lits.add(i, suffix[1..].to_string()); - } - suffixes.add(i, suffix); - } - MatchStrategy::RequiredExtension(ext) => { - required_exts.add(i, ext, p.regex().to_owned()); - } - MatchStrategy::Regex => { - debug!("glob converted to regex: {:?}", p); - regexes.add(i, p.regex().to_owned()); - } - } - } - debug!("built glob set; {} literals, {} basenames, {} extensions, \ - {} prefixes, {} suffixes, {} required extensions, {} regexes", - lits.0.len(), base_lits.0.len(), exts.0.len(), - prefixes.literals.len(), suffixes.literals.len(), - required_exts.0.len(), regexes.literals.len()); - Ok(GlobSet { - len: pats.len(), - strats: vec![ - GlobSetMatchStrategy::Extension(exts), - GlobSetMatchStrategy::BasenameLiteral(base_lits), - GlobSetMatchStrategy::Literal(lits), - GlobSetMatchStrategy::Suffix(suffixes.suffix()), - GlobSetMatchStrategy::Prefix(prefixes.prefix()), - GlobSetMatchStrategy::RequiredExtension( - required_exts.build()?), - GlobSetMatchStrategy::Regex(regexes.regex_set()?), - ], - }) - } -} - -/// GlobSetBuilder builds a group of patterns that can be used to -/// simultaneously match a file path. -#[derive(Clone, Debug)] -pub struct GlobSetBuilder { - pats: Vec, -} - -impl GlobSetBuilder { - /// Create a new GlobSetBuilder. A GlobSetBuilder can be used to add new - /// patterns. Once all patterns have been added, `build` should be called - /// to produce a `GlobSet`, which can then be used for matching. - pub fn new() -> GlobSetBuilder { - GlobSetBuilder { pats: vec![] } - } - - /// Builds a new matcher from all of the glob patterns added so far. - /// - /// Once a matcher is built, no new patterns can be added to it. - pub fn build(&self) -> Result { - GlobSet::new(&self.pats) - } - - /// Add a new pattern to this set. - #[allow(dead_code)] - pub fn add(&mut self, pat: Glob) -> &mut GlobSetBuilder { - self.pats.push(pat); - self - } -} - -/// A candidate path for matching. -/// -/// All glob matching in this crate operates on `Candidate` values. -/// Constructing candidates has a very small cost associated with it, so -/// callers may find it beneficial to amortize that cost when matching a single -/// path against multiple globs or sets of globs. -#[derive(Clone, Debug)] -pub struct Candidate<'a> { - path: Cow<'a, [u8]>, - basename: Cow<'a, [u8]>, - ext: Cow<'a, [u8]>, -} - -impl<'a> Candidate<'a> { - /// Create a new candidate for matching from the given path. - pub fn new + ?Sized>(path: &'a P) -> Candidate<'a> { - let path = path.as_ref(); - let basename = file_name(path).unwrap_or(OsStr::new("")); - Candidate { - path: normalize_path(path_bytes(path)), - basename: os_str_bytes(basename), - ext: file_name_ext(basename).unwrap_or(Cow::Borrowed(b"")), - } - } - - fn path_prefix(&self, max: usize) -> &[u8] { - if self.path.len() <= max { - &*self.path - } else { - &self.path[..max] - } - } - - fn path_suffix(&self, max: usize) -> &[u8] { - if self.path.len() <= max { - &*self.path - } else { - &self.path[self.path.len() - max..] - } - } -} - -#[derive(Clone, Debug)] -enum GlobSetMatchStrategy { - Literal(LiteralStrategy), - BasenameLiteral(BasenameLiteralStrategy), - Extension(ExtensionStrategy), - Prefix(PrefixStrategy), - Suffix(SuffixStrategy), - RequiredExtension(RequiredExtensionStrategy), - Regex(RegexSetStrategy), -} - -impl GlobSetMatchStrategy { - fn is_match(&self, candidate: &Candidate) -> bool { - use self::GlobSetMatchStrategy::*; - match *self { - Literal(ref s) => s.is_match(candidate), - BasenameLiteral(ref s) => s.is_match(candidate), - Extension(ref s) => s.is_match(candidate), - Prefix(ref s) => s.is_match(candidate), - Suffix(ref s) => s.is_match(candidate), - RequiredExtension(ref s) => s.is_match(candidate), - Regex(ref s) => s.is_match(candidate), - } - } - - fn matches_into(&self, candidate: &Candidate, matches: &mut Vec) { - use self::GlobSetMatchStrategy::*; - match *self { - Literal(ref s) => s.matches_into(candidate, matches), - BasenameLiteral(ref s) => s.matches_into(candidate, matches), - Extension(ref s) => s.matches_into(candidate, matches), - Prefix(ref s) => s.matches_into(candidate, matches), - Suffix(ref s) => s.matches_into(candidate, matches), - RequiredExtension(ref s) => s.matches_into(candidate, matches), - Regex(ref s) => s.matches_into(candidate, matches), - } - } -} - -#[derive(Clone, Debug)] -struct LiteralStrategy(BTreeMap, Vec>); - -impl LiteralStrategy { - fn new() -> LiteralStrategy { - LiteralStrategy(BTreeMap::new()) - } - - fn add(&mut self, global_index: usize, lit: String) { - self.0.entry(lit.into_bytes()).or_insert(vec![]).push(global_index); - } - - fn is_match(&self, candidate: &Candidate) -> bool { - self.0.contains_key(&*candidate.path) - } - - #[inline(never)] - fn matches_into(&self, candidate: &Candidate, matches: &mut Vec) { - if let Some(hits) = self.0.get(&*candidate.path) { - matches.extend(hits); - } - } -} - -#[derive(Clone, Debug)] -struct BasenameLiteralStrategy(BTreeMap, Vec>); - -impl BasenameLiteralStrategy { - fn new() -> BasenameLiteralStrategy { - BasenameLiteralStrategy(BTreeMap::new()) - } - - fn add(&mut self, global_index: usize, lit: String) { - self.0.entry(lit.into_bytes()).or_insert(vec![]).push(global_index); - } - - fn is_match(&self, candidate: &Candidate) -> bool { - if candidate.basename.is_empty() { - return false; - } - self.0.contains_key(&*candidate.basename) - } - - #[inline(never)] - fn matches_into(&self, candidate: &Candidate, matches: &mut Vec) { - if candidate.basename.is_empty() { - return; - } - if let Some(hits) = self.0.get(&*candidate.basename) { - matches.extend(hits); - } - } -} - -#[derive(Clone, Debug)] -struct ExtensionStrategy(HashMap, Vec, Fnv>); - -impl ExtensionStrategy { - fn new() -> ExtensionStrategy { - ExtensionStrategy(HashMap::with_hasher(Fnv::default())) - } - - fn add(&mut self, global_index: usize, ext: String) { - self.0.entry(ext.into_bytes()).or_insert(vec![]).push(global_index); - } - - fn is_match(&self, candidate: &Candidate) -> bool { - if candidate.ext.is_empty() { - return false; - } - self.0.contains_key(&*candidate.ext) - } - - #[inline(never)] - fn matches_into(&self, candidate: &Candidate, matches: &mut Vec) { - if candidate.ext.is_empty() { - return; - } - if let Some(hits) = self.0.get(&*candidate.ext) { - matches.extend(hits); - } - } -} - -#[derive(Clone, Debug)] -struct PrefixStrategy { - matcher: FullAcAutomaton>, - map: Vec, - longest: usize, -} - -impl PrefixStrategy { - fn is_match(&self, candidate: &Candidate) -> bool { - let path = candidate.path_prefix(self.longest); - for m in self.matcher.find_overlapping(path) { - if m.start == 0 { - return true; - } - } - false - } - - fn matches_into(&self, candidate: &Candidate, matches: &mut Vec) { - let path = candidate.path_prefix(self.longest); - for m in self.matcher.find_overlapping(path) { - if m.start == 0 { - matches.push(self.map[m.pati]); - } - } - } -} - -#[derive(Clone, Debug)] -struct SuffixStrategy { - matcher: FullAcAutomaton>, - map: Vec, - longest: usize, -} - -impl SuffixStrategy { - fn is_match(&self, candidate: &Candidate) -> bool { - let path = candidate.path_suffix(self.longest); - for m in self.matcher.find_overlapping(path) { - if m.end == path.len() { - return true; - } - } - false - } - - fn matches_into(&self, candidate: &Candidate, matches: &mut Vec) { - let path = candidate.path_suffix(self.longest); - for m in self.matcher.find_overlapping(path) { - if m.end == path.len() { - matches.push(self.map[m.pati]); - } - } - } -} - -#[derive(Clone, Debug)] -struct RequiredExtensionStrategy(HashMap, Vec<(usize, Regex)>, Fnv>); - -impl RequiredExtensionStrategy { - fn is_match(&self, candidate: &Candidate) -> bool { - if candidate.ext.is_empty() { - return false; - } - match self.0.get(&*candidate.ext) { - None => false, - Some(regexes) => { - for &(_, ref re) in regexes { - if re.is_match(&*candidate.path) { - return true; - } - } - false - } - } - } - - #[inline(never)] - fn matches_into(&self, candidate: &Candidate, matches: &mut Vec) { - if candidate.ext.is_empty() { - return; - } - if let Some(regexes) = self.0.get(&*candidate.ext) { - for &(global_index, ref re) in regexes { - if re.is_match(&*candidate.path) { - matches.push(global_index); - } - } - } - } -} - -#[derive(Clone, Debug)] -struct RegexSetStrategy { - matcher: RegexSet, - map: Vec, -} - -impl RegexSetStrategy { - fn is_match(&self, candidate: &Candidate) -> bool { - self.matcher.is_match(&*candidate.path) - } - - fn matches_into(&self, candidate: &Candidate, matches: &mut Vec) { - for i in self.matcher.matches(&*candidate.path) { - matches.push(self.map[i]); - } - } -} - -#[derive(Clone, Debug)] -struct MultiStrategyBuilder { - literals: Vec, - map: Vec, - longest: usize, -} - -impl MultiStrategyBuilder { - fn new() -> MultiStrategyBuilder { - MultiStrategyBuilder { - literals: vec![], - map: vec![], - longest: 0, - } - } - - fn add(&mut self, global_index: usize, literal: String) { - if literal.len() > self.longest { - self.longest = literal.len(); - } - self.map.push(global_index); - self.literals.push(literal); - } - - fn prefix(self) -> PrefixStrategy { - let it = self.literals.into_iter().map(|s| s.into_bytes()); - PrefixStrategy { - matcher: AcAutomaton::new(it).into_full(), - map: self.map, - longest: self.longest, - } - } - - fn suffix(self) -> SuffixStrategy { - let it = self.literals.into_iter().map(|s| s.into_bytes()); - SuffixStrategy { - matcher: AcAutomaton::new(it).into_full(), - map: self.map, - longest: self.longest, - } - } - - fn regex_set(self) -> Result { - Ok(RegexSetStrategy { - matcher: new_regex_set(self.literals)?, - map: self.map, - }) - } -} - -#[derive(Clone, Debug)] -struct RequiredExtensionStrategyBuilder( - HashMap, Vec<(usize, String)>>, -); - -impl RequiredExtensionStrategyBuilder { - fn new() -> RequiredExtensionStrategyBuilder { - RequiredExtensionStrategyBuilder(HashMap::new()) - } - - fn add(&mut self, global_index: usize, ext: String, regex: String) { - self.0 - .entry(ext.into_bytes()) - .or_insert(vec![]) - .push((global_index, regex)); - } - - fn build(self) -> Result { - let mut exts = HashMap::with_hasher(Fnv::default()); - for (ext, regexes) in self.0.into_iter() { - exts.insert(ext.clone(), vec![]); - for (global_index, regex) in regexes { - let compiled = new_regex(®ex)?; - exts.get_mut(&ext).unwrap().push((global_index, compiled)); - } - } - Ok(RequiredExtensionStrategy(exts)) - } -} - -#[cfg(test)] -mod tests { - use super::GlobSetBuilder; - use glob::Glob; - - #[test] - fn set_works() { - let mut builder = GlobSetBuilder::new(); - builder.add(Glob::new("src/**/*.rs").unwrap()); - builder.add(Glob::new("*.c").unwrap()); - builder.add(Glob::new("src/lib.rs").unwrap()); - let set = builder.build().unwrap(); - - assert!(set.is_match("foo.c")); - assert!(set.is_match("src/foo.c")); - assert!(!set.is_match("foo.rs")); - assert!(!set.is_match("tests/foo.rs")); - assert!(set.is_match("src/foo.rs")); - assert!(set.is_match("src/grep/src/main.rs")); - - let matches = set.matches("src/lib.rs"); - assert_eq!(2, matches.len()); - assert_eq!(0, matches[0]); - assert_eq!(2, matches[1]); - } - - #[test] - fn empty_set_works() { - let set = GlobSetBuilder::new().build().unwrap(); - assert!(!set.is_match("")); - assert!(!set.is_match("a")); - } -} diff --git a/globset/src/pathutil.rs b/globset/src/pathutil.rs deleted file mode 100644 index 4b808e8..0000000 --- a/globset/src/pathutil.rs +++ /dev/null @@ -1,172 +0,0 @@ -use std::borrow::Cow; -use std::ffi::OsStr; -use std::path::Path; - -/// The final component of the path, if it is a normal file. -/// -/// If the path terminates in ., .., or consists solely of a root of prefix, -/// file_name will return None. -#[cfg(unix)] -pub fn file_name<'a, P: AsRef + ?Sized>( - path: &'a P, -) -> Option<&'a OsStr> { - use std::os::unix::ffi::OsStrExt; - use memchr::memrchr; - - let path = path.as_ref().as_os_str().as_bytes(); - if path.is_empty() { - return None; - } else if path.len() == 1 && path[0] == b'.' { - return None; - } else if path.last() == Some(&b'.') { - return None; - } else if path.len() >= 2 && &path[path.len() - 2..] == &b".."[..] { - return None; - } - let last_slash = memrchr(b'/', path).map(|i| i + 1).unwrap_or(0); - Some(OsStr::from_bytes(&path[last_slash..])) -} - -/// The final component of the path, if it is a normal file. -/// -/// If the path terminates in ., .., or consists solely of a root of prefix, -/// file_name will return None. -#[cfg(not(unix))] -pub fn file_name<'a, P: AsRef + ?Sized>( - path: &'a P, -) -> Option<&'a OsStr> { - path.as_ref().file_name() -} - -/// Return a file extension given a path's file name. -/// -/// Note that this does NOT match the semantics of std::path::Path::extension. -/// Namely, the extension includes the `.` and matching is otherwise more -/// liberal. Specifically, the extenion is: -/// -/// * None, if the file name given is empty; -/// * None, if there is no embedded `.`; -/// * Otherwise, the portion of the file name starting with the final `.`. -/// -/// e.g., A file name of `.rs` has an extension `.rs`. -/// -/// N.B. This is done to make certain glob match optimizations easier. Namely, -/// a pattern like `*.rs` is obviously trying to match files with a `rs` -/// extension, but it also matches files like `.rs`, which doesn't have an -/// extension according to std::path::Path::extension. -pub fn file_name_ext(name: &OsStr) -> Option> { - if name.is_empty() { - return None; - } - let name = os_str_bytes(name); - let last_dot_at = { - let result = name - .iter().enumerate().rev() - .find(|&(_, &b)| b == b'.') - .map(|(i, _)| i); - match result { - None => return None, - Some(i) => i, - } - }; - Some(match name { - Cow::Borrowed(name) => Cow::Borrowed(&name[last_dot_at..]), - Cow::Owned(mut name) => { - name.drain(..last_dot_at); - Cow::Owned(name) - } - }) -} - -/// Return raw bytes of a path, transcoded to UTF-8 if necessary. -pub fn path_bytes(path: &Path) -> Cow<[u8]> { - os_str_bytes(path.as_os_str()) -} - -/// Return the raw bytes of the given OS string, possibly transcoded to UTF-8. -#[cfg(unix)] -pub fn os_str_bytes(s: &OsStr) -> Cow<[u8]> { - use std::os::unix::ffi::OsStrExt; - Cow::Borrowed(s.as_bytes()) -} - -/// Return the raw bytes of the given OS string, possibly transcoded to UTF-8. -#[cfg(not(unix))] -pub fn os_str_bytes(s: &OsStr) -> Cow<[u8]> { - // TODO(burntsushi): On Windows, OS strings are WTF-8, which is a superset - // of UTF-8, so even if we could get at the raw bytes, they wouldn't - // be useful. We *must* convert to UTF-8 before doing path matching. - // Unfortunate, but necessary. - match s.to_string_lossy() { - Cow::Owned(s) => Cow::Owned(s.into_bytes()), - Cow::Borrowed(s) => Cow::Borrowed(s.as_bytes()), - } -} - -/// Normalizes a path to use `/` as a separator everywhere, even on platforms -/// that recognize other characters as separators. -#[cfg(unix)] -pub fn normalize_path(path: Cow<[u8]>) -> Cow<[u8]> { - // UNIX only uses /, so we're good. - path -} - -/// Normalizes a path to use `/` as a separator everywhere, even on platforms -/// that recognize other characters as separators. -#[cfg(not(unix))] -pub fn normalize_path(mut path: Cow<[u8]>) -> Cow<[u8]> { - use std::path::is_separator; - - for i in 0..path.len() { - if path[i] == b'/' || !is_separator(path[i] as char) { - continue; - } - path.to_mut()[i] = b'/'; - } - path -} - -#[cfg(test)] -mod tests { - use std::borrow::Cow; - use std::ffi::OsStr; - - use super::{file_name_ext, normalize_path}; - - macro_rules! ext { - ($name:ident, $file_name:expr, $ext:expr) => { - #[test] - fn $name() { - let got = file_name_ext(OsStr::new($file_name)); - assert_eq!($ext.map(|s| Cow::Borrowed(s.as_bytes())), got); - } - }; - } - - ext!(ext1, "foo.rs", Some(".rs")); - ext!(ext2, ".rs", Some(".rs")); - ext!(ext3, "..rs", Some(".rs")); - ext!(ext4, "", None::<&str>); - ext!(ext5, "foo", None::<&str>); - - macro_rules! normalize { - ($name:ident, $path:expr, $expected:expr) => { - #[test] - fn $name() { - let got = normalize_path(Cow::Owned($path.to_vec())); - assert_eq!($expected.to_vec(), got.into_owned()); - } - }; - } - - normalize!(normal1, b"foo", b"foo"); - normalize!(normal2, b"foo/bar", b"foo/bar"); - #[cfg(unix)] - normalize!(normal3, b"foo\\bar", b"foo\\bar"); - #[cfg(not(unix))] - normalize!(normal3, b"foo\\bar", b"foo/bar"); - #[cfg(unix)] - normalize!(normal4, b"foo\\bar/baz", b"foo\\bar/baz"); - #[cfg(not(unix))] - normalize!(normal4, b"foo\\bar/baz", b"foo/bar/baz"); -} diff --git a/grep/COPYING b/grep/COPYING deleted file mode 100644 index bb9c20a..0000000 --- a/grep/COPYING +++ /dev/null @@ -1,3 +0,0 @@ -This project is dual-licensed under the Unlicense and MIT licenses. - -You may use this code under the terms of either license. diff --git a/grep/Cargo.toml b/grep/Cargo.toml deleted file mode 100644 index 89480ab..0000000 --- a/grep/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "grep" -version = "0.1.8" #:version -authors = ["Andrew Gallant "] -description = """ -Fast line oriented regex searching as a library. -""" -documentation = "http://burntsushi.net/rustdoc/grep/" -homepage = "https://github.com/BurntSushi/ripgrep" -repository = "https://github.com/BurntSushi/ripgrep" -readme = "README.md" -keywords = ["regex", "grep", "egrep", "search", "pattern"] -license = "Unlicense/MIT" - -[dependencies] -log = "0.4" -memchr = "2" -regex = "1" -regex-syntax = "0.6" diff --git a/grep/LICENSE-MIT b/grep/LICENSE-MIT deleted file mode 100644 index 3b0a5dc..0000000 --- a/grep/LICENSE-MIT +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Andrew Gallant - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/grep/README.md b/grep/README.md deleted file mode 100644 index 86cc8c2..0000000 --- a/grep/README.md +++ /dev/null @@ -1,4 +0,0 @@ -grep ----- -This is a *library* that provides grep-style line-by-line regex searching (with -comparable performance to `grep` itself). diff --git a/grep/UNLICENSE b/grep/UNLICENSE deleted file mode 100644 index 68a49da..0000000 --- a/grep/UNLICENSE +++ /dev/null @@ -1,24 +0,0 @@ -This is free and unencumbered software released into the public domain. - -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a compiled -binary, for any purpose, commercial or non-commercial, and by any -means. - -In jurisdictions that recognize copyright laws, the author or authors -of this software dedicate any and all copyright interest in the -software to the public domain. We make this dedication for the benefit -of the public at large and to the detriment of our heirs and -successors. We intend this dedication to be an overt act of -relinquishment in perpetuity of all present and future rights to this -software under copyright law. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -For more information, please refer to diff --git a/grep/src/data/sherlock.txt b/grep/src/data/sherlock.txt deleted file mode 100644 index c4c3130..0000000 --- a/grep/src/data/sherlock.txt +++ /dev/null @@ -1,13052 +0,0 @@ -Project Gutenberg's The Adventures of Sherlock Holmes, by Arthur Conan Doyle - -This eBook is for the use of anyone anywhere at no cost and with -almost no restrictions whatsoever. You may copy it, give it away or -re-use it under the terms of the Project Gutenberg License included -with this eBook or online at www.gutenberg.net - - -Title: The Adventures of Sherlock Holmes - -Author: Arthur Conan Doyle - -Posting Date: April 18, 2011 [EBook #1661] -First Posted: November 29, 2002 - -Language: English - - -*** START OF THIS PROJECT GUTENBERG EBOOK THE ADVENTURES OF SHERLOCK HOLMES *** - - - - -Produced by an anonymous Project Gutenberg volunteer and Jose Menendez - - - - - - - - - -THE ADVENTURES OF SHERLOCK HOLMES - -by - -SIR ARTHUR CONAN DOYLE - - - - I. A Scandal in Bohemia - II. The Red-headed League - III. A Case of Identity - IV. The Boscombe Valley Mystery - V. The Five Orange Pips - VI. The Man with the Twisted Lip - VII. The Adventure of the Blue Carbuncle -VIII. The Adventure of the Speckled Band - IX. The Adventure of the Engineer's Thumb - X. The Adventure of the Noble Bachelor - XI. The Adventure of the Beryl Coronet - XII. The Adventure of the Copper Beeches - - - - -ADVENTURE I. A SCANDAL IN BOHEMIA - -I. - -To Sherlock Holmes she is always THE woman. I have seldom heard -him mention her under any other name. In his eyes she eclipses -and predominates the whole of her sex. It was not that he felt -any emotion akin to love for Irene Adler. All emotions, and that -one particularly, were abhorrent to his cold, precise but -admirably balanced mind. He was, I take it, the most perfect -reasoning and observing machine that the world has seen, but as a -lover he would have placed himself in a false position. He never -spoke of the softer passions, save with a gibe and a sneer. They -were admirable things for the observer--excellent for drawing the -veil from men's motives and actions. But for the trained reasoner -to admit such intrusions into his own delicate and finely -adjusted temperament was to introduce a distracting factor which -might throw a doubt upon all his mental results. Grit in a -sensitive instrument, or a crack in one of his own high-power -lenses, would not be more disturbing than a strong emotion in a -nature such as his. And yet there was but one woman to him, and -that woman was the late Irene Adler, of dubious and questionable -memory. - -I had seen little of Holmes lately. My marriage had drifted us -away from each other. My own complete happiness, and the -home-centred interests which rise up around the man who first -finds himself master of his own establishment, were sufficient to -absorb all my attention, while Holmes, who loathed every form of -society with his whole Bohemian soul, remained in our lodgings in -Baker Street, buried among his old books, and alternating from -week to week between cocaine and ambition, the drowsiness of the -drug, and the fierce energy of his own keen nature. He was still, -as ever, deeply attracted by the study of crime, and occupied his -immense faculties and extraordinary powers of observation in -following out those clues, and clearing up those mysteries which -had been abandoned as hopeless by the official police. From time -to time I heard some vague account of his doings: of his summons -to Odessa in the case of the Trepoff murder, of his clearing up -of the singular tragedy of the Atkinson brothers at Trincomalee, -and finally of the mission which he had accomplished so -delicately and successfully for the reigning family of Holland. -Beyond these signs of his activity, however, which I merely -shared with all the readers of the daily press, I knew little of -my former friend and companion. - -One night--it was on the twentieth of March, 1888--I was -returning from a journey to a patient (for I had now returned to -civil practice), when my way led me through Baker Street. As I -passed the well-remembered door, which must always be associated -in my mind with my wooing, and with the dark incidents of the -Study in Scarlet, I was seized with a keen desire to see Holmes -again, and to know how he was employing his extraordinary powers. -His rooms were brilliantly lit, and, even as I looked up, I saw -his tall, spare figure pass twice in a dark silhouette against -the blind. He was pacing the room swiftly, eagerly, with his head -sunk upon his chest and his hands clasped behind him. To me, who -knew his every mood and habit, his attitude and manner told their -own story. He was at work again. He had risen out of his -drug-created dreams and was hot upon the scent of some new -problem. I rang the bell and was shown up to the chamber which -had formerly been in part my own. - -His manner was not effusive. It seldom was; but he was glad, I -think, to see me. With hardly a word spoken, but with a kindly -eye, he waved me to an armchair, threw across his case of cigars, -and indicated a spirit case and a gasogene in the corner. Then he -stood before the fire and looked me over in his singular -introspective fashion. - -"Wedlock suits you," he remarked. "I think, Watson, that you have -put on seven and a half pounds since I saw you." - -"Seven!" I answered. - -"Indeed, I should have thought a little more. Just a trifle more, -I fancy, Watson. And in practice again, I observe. You did not -tell me that you intended to go into harness." - -"Then, how do you know?" - -"I see it, I deduce it. How do I know that you have been getting -yourself very wet lately, and that you have a most clumsy and -careless servant girl?" - -"My dear Holmes," said I, "this is too much. You would certainly -have been burned, had you lived a few centuries ago. It is true -that I had a country walk on Thursday and came home in a dreadful -mess, but as I have changed my clothes I can't imagine how you -deduce it. As to Mary Jane, she is incorrigible, and my wife has -given her notice, but there, again, I fail to see how you work it -out." - -He chuckled to himself and rubbed his long, nervous hands -together. - -"It is simplicity itself," said he; "my eyes tell me that on the -inside of your left shoe, just where the firelight strikes it, -the leather is scored by six almost parallel cuts. Obviously they -have been caused by someone who has very carelessly scraped round -the edges of the sole in order to remove crusted mud from it. -Hence, you see, my double deduction that you had been out in vile -weather, and that you had a particularly malignant boot-slitting -specimen of the London slavey. As to your practice, if a -gentleman walks into my rooms smelling of iodoform, with a black -mark of nitrate of silver upon his right forefinger, and a bulge -on the right side of his top-hat to show where he has secreted -his stethoscope, I must be dull, indeed, if I do not pronounce -him to be an active member of the medical profession." - -I could not help laughing at the ease with which he explained his -process of deduction. "When I hear you give your reasons," I -remarked, "the thing always appears to me to be so ridiculously -simple that I could easily do it myself, though at each -successive instance of your reasoning I am baffled until you -explain your process. And yet I believe that my eyes are as good -as yours." - -"Quite so," he answered, lighting a cigarette, and throwing -himself down into an armchair. "You see, but you do not observe. -The distinction is clear. For example, you have frequently seen -the steps which lead up from the hall to this room." - -"Frequently." - -"How often?" - -"Well, some hundreds of times." - -"Then how many are there?" - -"How many? I don't know." - -"Quite so! You have not observed. And yet you have seen. That is -just my point. Now, I know that there are seventeen steps, -because I have both seen and observed. By-the-way, since you are -interested in these little problems, and since you are good -enough to chronicle one or two of my trifling experiences, you -may be interested in this." He threw over a sheet of thick, -pink-tinted note-paper which had been lying open upon the table. -"It came by the last post," said he. "Read it aloud." - -The note was undated, and without either signature or address. - -"There will call upon you to-night, at a quarter to eight -o'clock," it said, "a gentleman who desires to consult you upon a -matter of the very deepest moment. Your recent services to one of -the royal houses of Europe have shown that you are one who may -safely be trusted with matters which are of an importance which -can hardly be exaggerated. This account of you we have from all -quarters received. Be in your chamber then at that hour, and do -not take it amiss if your visitor wear a mask." - -"This is indeed a mystery," I remarked. "What do you imagine that -it means?" - -"I have no data yet. It is a capital mistake to theorize before -one has data. Insensibly one begins to twist facts to suit -theories, instead of theories to suit facts. But the note itself. -What do you deduce from it?" - -I carefully examined the writing, and the paper upon which it was -written. - -"The man who wrote it was presumably well to do," I remarked, -endeavouring to imitate my companion's processes. "Such paper -could not be bought under half a crown a packet. It is peculiarly -strong and stiff." - -"Peculiar--that is the very word," said Holmes. "It is not an -English paper at all. Hold it up to the light." - -I did so, and saw a large "E" with a small "g," a "P," and a -large "G" with a small "t" woven into the texture of the paper. - -"What do you make of that?" asked Holmes. - -"The name of the maker, no doubt; or his monogram, rather." - -"Not at all. The 'G' with the small 't' stands for -'Gesellschaft,' which is the German for 'Company.' It is a -customary contraction like our 'Co.' 'P,' of course, stands for -'Papier.' Now for the 'Eg.' Let us glance at our Continental -Gazetteer." He took down a heavy brown volume from his shelves. -"Eglow, Eglonitz--here we are, Egria. It is in a German-speaking -country--in Bohemia, not far from Carlsbad. 'Remarkable as being -the scene of the death of Wallenstein, and for its numerous -glass-factories and paper-mills.' Ha, ha, my boy, what do you -make of that?" His eyes sparkled, and he sent up a great blue -triumphant cloud from his cigarette. - -"The paper was made in Bohemia," I said. - -"Precisely. And the man who wrote the note is a German. Do you -note the peculiar construction of the sentence--'This account of -you we have from all quarters received.' A Frenchman or Russian -could not have written that. It is the German who is so -uncourteous to his verbs. It only remains, therefore, to discover -what is wanted by this German who writes upon Bohemian paper and -prefers wearing a mask to showing his face. And here he comes, if -I am not mistaken, to resolve all our doubts." - -As he spoke there was the sharp sound of horses' hoofs and -grating wheels against the curb, followed by a sharp pull at the -bell. Holmes whistled. - -"A pair, by the sound," said he. "Yes," he continued, glancing -out of the window. "A nice little brougham and a pair of -beauties. A hundred and fifty guineas apiece. There's money in -this case, Watson, if there is nothing else." - -"I think that I had better go, Holmes." - -"Not a bit, Doctor. Stay where you are. I am lost without my -Boswell. And this promises to be interesting. It would be a pity -to miss it." - -"But your client--" - -"Never mind him. I may want your help, and so may he. Here he -comes. Sit down in that armchair, Doctor, and give us your best -attention." - -A slow and heavy step, which had been heard upon the stairs and -in the passage, paused immediately outside the door. Then there -was a loud and authoritative tap. - -"Come in!" said Holmes. - -A man entered who could hardly have been less than six feet six -inches in height, with the chest and limbs of a Hercules. His -dress was rich with a richness which would, in England, be looked -upon as akin to bad taste. Heavy bands of astrakhan were slashed -across the sleeves and fronts of his double-breasted coat, while -the deep blue cloak which was thrown over his shoulders was lined -with flame-coloured silk and secured at the neck with a brooch -which consisted of a single flaming beryl. Boots which extended -halfway up his calves, and which were trimmed at the tops with -rich brown fur, completed the impression of barbaric opulence -which was suggested by his whole appearance. He carried a -broad-brimmed hat in his hand, while he wore across the upper -part of his face, extending down past the cheekbones, a black -vizard mask, which he had apparently adjusted that very moment, -for his hand was still raised to it as he entered. From the lower -part of the face he appeared to be a man of strong character, -with a thick, hanging lip, and a long, straight chin suggestive -of resolution pushed to the length of obstinacy. - -"You had my note?" he asked with a deep harsh voice and a -strongly marked German accent. "I told you that I would call." He -looked from one to the other of us, as if uncertain which to -address. - -"Pray take a seat," said Holmes. "This is my friend and -colleague, Dr. Watson, who is occasionally good enough to help me -in my cases. Whom have I the honour to address?" - -"You may address me as the Count Von Kramm, a Bohemian nobleman. -I understand that this gentleman, your friend, is a man of honour -and discretion, whom I may trust with a matter of the most -extreme importance. If not, I should much prefer to communicate -with you alone." - -I rose to go, but Holmes caught me by the wrist and pushed me -back into my chair. "It is both, or none," said he. "You may say -before this gentleman anything which you may say to me." - -The Count shrugged his broad shoulders. "Then I must begin," said -he, "by binding you both to absolute secrecy for two years; at -the end of that time the matter will be of no importance. At -present it is not too much to say that it is of such weight it -may have an influence upon European history." - -"I promise," said Holmes. - -"And I." - -"You will excuse this mask," continued our strange visitor. "The -august person who employs me wishes his agent to be unknown to -you, and I may confess at once that the title by which I have -just called myself is not exactly my own." - -"I was aware of it," said Holmes dryly. - -"The circumstances are of great delicacy, and every precaution -has to be taken to quench what might grow to be an immense -scandal and seriously compromise one of the reigning families of -Europe. To speak plainly, the matter implicates the great House -of Ormstein, hereditary kings of Bohemia." - -"I was also aware of that," murmured Holmes, settling himself -down in his armchair and closing his eyes. - -Our visitor glanced with some apparent surprise at the languid, -lounging figure of the man who had been no doubt depicted to him -as the most incisive reasoner and most energetic agent in Europe. -Holmes slowly reopened his eyes and looked impatiently at his -gigantic client. - -"If your Majesty would condescend to state your case," he -remarked, "I should be better able to advise you." - -The man sprang from his chair and paced up and down the room in -uncontrollable agitation. Then, with a gesture of desperation, he -tore the mask from his face and hurled it upon the ground. "You -are right," he cried; "I am the King. Why should I attempt to -conceal it?" - -"Why, indeed?" murmured Holmes. "Your Majesty had not spoken -before I was aware that I was addressing Wilhelm Gottsreich -Sigismond von Ormstein, Grand Duke of Cassel-Felstein, and -hereditary King of Bohemia." - -"But you can understand," said our strange visitor, sitting down -once more and passing his hand over his high white forehead, "you -can understand that I am not accustomed to doing such business in -my own person. Yet the matter was so delicate that I could not -confide it to an agent without putting myself in his power. I -have come incognito from Prague for the purpose of consulting -you." - -"Then, pray consult," said Holmes, shutting his eyes once more. - -"The facts are briefly these: Some five years ago, during a -lengthy visit to Warsaw, I made the acquaintance of the well-known -adventuress, Irene Adler. The name is no doubt familiar to you." - -"Kindly look her up in my index, Doctor," murmured Holmes without -opening his eyes. For many years he had adopted a system of -docketing all paragraphs concerning men and things, so that it -was difficult to name a subject or a person on which he could not -at once furnish information. In this case I found her biography -sandwiched in between that of a Hebrew rabbi and that of a -staff-commander who had written a monograph upon the deep-sea -fishes. - -"Let me see!" said Holmes. "Hum! Born in New Jersey in the year -1858. Contralto--hum! La Scala, hum! Prima donna Imperial Opera -of Warsaw--yes! Retired from operatic stage--ha! Living in -London--quite so! Your Majesty, as I understand, became entangled -with this young person, wrote her some compromising letters, and -is now desirous of getting those letters back." - -"Precisely so. But how--" - -"Was there a secret marriage?" - -"None." - -"No legal papers or certificates?" - -"None." - -"Then I fail to follow your Majesty. If this young person should -produce her letters for blackmailing or other purposes, how is -she to prove their authenticity?" - -"There is the writing." - -"Pooh, pooh! Forgery." - -"My private note-paper." - -"Stolen." - -"My own seal." - -"Imitated." - -"My photograph." - -"Bought." - -"We were both in the photograph." - -"Oh, dear! That is very bad! Your Majesty has indeed committed an -indiscretion." - -"I was mad--insane." - -"You have compromised yourself seriously." - -"I was only Crown Prince then. I was young. I am but thirty now." - -"It must be recovered." - -"We have tried and failed." - -"Your Majesty must pay. It must be bought." - -"She will not sell." - -"Stolen, then." - -"Five attempts have been made. Twice burglars in my pay ransacked -her house. Once we diverted her luggage when she travelled. Twice -she has been waylaid. There has been no result." - -"No sign of it?" - -"Absolutely none." - -Holmes laughed. "It is quite a pretty little problem," said he. - -"But a very serious one to me," returned the King reproachfully. - -"Very, indeed. And what does she propose to do with the -photograph?" - -"To ruin me." - -"But how?" - -"I am about to be married." - -"So I have heard." - -"To Clotilde Lothman von Saxe-Meningen, second daughter of the -King of Scandinavia. You may know the strict principles of her -family. She is herself the very soul of delicacy. A shadow of a -doubt as to my conduct would bring the matter to an end." - -"And Irene Adler?" - -"Threatens to send them the photograph. And she will do it. I -know that she will do it. You do not know her, but she has a soul -of steel. She has the face of the most beautiful of women, and -the mind of the most resolute of men. Rather than I should marry -another woman, there are no lengths to which she would not -go--none." - -"You are sure that she has not sent it yet?" - -"I am sure." - -"And why?" - -"Because she has said that she would send it on the day when the -betrothal was publicly proclaimed. That will be next Monday." - -"Oh, then we have three days yet," said Holmes with a yawn. "That -is very fortunate, as I have one or two matters of importance to -look into just at present. Your Majesty will, of course, stay in -London for the present?" - -"Certainly. You will find me at the Langham under the name of the -Count Von Kramm." - -"Then I shall drop you a line to let you know how we progress." - -"Pray do so. I shall be all anxiety." - -"Then, as to money?" - -"You have carte blanche." - -"Absolutely?" - -"I tell you that I would give one of the provinces of my kingdom -to have that photograph." - -"And for present expenses?" - -The King took a heavy chamois leather bag from under his cloak -and laid it on the table. - -"There are three hundred pounds in gold and seven hundred in -notes," he said. - -Holmes scribbled a receipt upon a sheet of his note-book and -handed it to him. - -"And Mademoiselle's address?" he asked. - -"Is Briony Lodge, Serpentine Avenue, St. John's Wood." - -Holmes took a note of it. "One other question," said he. "Was the -photograph a cabinet?" - -"It was." - -"Then, good-night, your Majesty, and I trust that we shall soon -have some good news for you. And good-night, Watson," he added, -as the wheels of the royal brougham rolled down the street. "If -you will be good enough to call to-morrow afternoon at three -o'clock I should like to chat this little matter over with you." - - -II. - -At three o'clock precisely I was at Baker Street, but Holmes had -not yet returned. The landlady informed me that he had left the -house shortly after eight o'clock in the morning. I sat down -beside the fire, however, with the intention of awaiting him, -however long he might be. I was already deeply interested in his -inquiry, for, though it was surrounded by none of the grim and -strange features which were associated with the two crimes which -I have already recorded, still, the nature of the case and the -exalted station of his client gave it a character of its own. -Indeed, apart from the nature of the investigation which my -friend had on hand, there was something in his masterly grasp of -a situation, and his keen, incisive reasoning, which made it a -pleasure to me to study his system of work, and to follow the -quick, subtle methods by which he disentangled the most -inextricable mysteries. So accustomed was I to his invariable -success that the very possibility of his failing had ceased to -enter into my head. - -It was close upon four before the door opened, and a -drunken-looking groom, ill-kempt and side-whiskered, with an -inflamed face and disreputable clothes, walked into the room. -Accustomed as I was to my friend's amazing powers in the use of -disguises, I had to look three times before I was certain that it -was indeed he. With a nod he vanished into the bedroom, whence he -emerged in five minutes tweed-suited and respectable, as of old. -Putting his hands into his pockets, he stretched out his legs in -front of the fire and laughed heartily for some minutes. - -"Well, really!" he cried, and then he choked and laughed again -until he was obliged to lie back, limp and helpless, in the -chair. - -"What is it?" - -"It's quite too funny. I am sure you could never guess how I -employed my morning, or what I ended by doing." - -"I can't imagine. I suppose that you have been watching the -habits, and perhaps the house, of Miss Irene Adler." - -"Quite so; but the sequel was rather unusual. I will tell you, -however. I left the house a little after eight o'clock this -morning in the character of a groom out of work. There is a -wonderful sympathy and freemasonry among horsey men. Be one of -them, and you will know all that there is to know. I soon found -Briony Lodge. It is a bijou villa, with a garden at the back, but -built out in front right up to the road, two stories. Chubb lock -to the door. Large sitting-room on the right side, well -furnished, with long windows almost to the floor, and those -preposterous English window fasteners which a child could open. -Behind there was nothing remarkable, save that the passage window -could be reached from the top of the coach-house. I walked round -it and examined it closely from every point of view, but without -noting anything else of interest. - -"I then lounged down the street and found, as I expected, that -there was a mews in a lane which runs down by one wall of the -garden. I lent the ostlers a hand in rubbing down their horses, -and received in exchange twopence, a glass of half and half, two -fills of shag tobacco, and as much information as I could desire -about Miss Adler, to say nothing of half a dozen other people in -the neighbourhood in whom I was not in the least interested, but -whose biographies I was compelled to listen to." - -"And what of Irene Adler?" I asked. - -"Oh, she has turned all the men's heads down in that part. She is -the daintiest thing under a bonnet on this planet. So say the -Serpentine-mews, to a man. She lives quietly, sings at concerts, -drives out at five every day, and returns at seven sharp for -dinner. Seldom goes out at other times, except when she sings. -Has only one male visitor, but a good deal of him. He is dark, -handsome, and dashing, never calls less than once a day, and -often twice. He is a Mr. Godfrey Norton, of the Inner Temple. See -the advantages of a cabman as a confidant. They had driven him -home a dozen times from Serpentine-mews, and knew all about him. -When I had listened to all they had to tell, I began to walk up -and down near Briony Lodge once more, and to think over my plan -of campaign. - -"This Godfrey Norton was evidently an important factor in the -matter. He was a lawyer. That sounded ominous. What was the -relation between them, and what the object of his repeated -visits? Was she his client, his friend, or his mistress? If the -former, she had probably transferred the photograph to his -keeping. If the latter, it was less likely. On the issue of this -question depended whether I should continue my work at Briony -Lodge, or turn my attention to the gentleman's chambers in the -Temple. It was a delicate point, and it widened the field of my -inquiry. I fear that I bore you with these details, but I have to -let you see my little difficulties, if you are to understand the -situation." - -"I am following you closely," I answered. - -"I was still balancing the matter in my mind when a hansom cab -drove up to Briony Lodge, and a gentleman sprang out. He was a -remarkably handsome man, dark, aquiline, and moustached--evidently -the man of whom I had heard. He appeared to be in a -great hurry, shouted to the cabman to wait, and brushed past the -maid who opened the door with the air of a man who was thoroughly -at home. - -"He was in the house about half an hour, and I could catch -glimpses of him in the windows of the sitting-room, pacing up and -down, talking excitedly, and waving his arms. Of her I could see -nothing. Presently he emerged, looking even more flurried than -before. As he stepped up to the cab, he pulled a gold watch from -his pocket and looked at it earnestly, 'Drive like the devil,' he -shouted, 'first to Gross & Hankey's in Regent Street, and then to -the Church of St. Monica in the Edgeware Road. Half a guinea if -you do it in twenty minutes!' - -"Away they went, and I was just wondering whether I should not do -well to follow them when up the lane came a neat little landau, -the coachman with his coat only half-buttoned, and his tie under -his ear, while all the tags of his harness were sticking out of -the buckles. It hadn't pulled up before she shot out of the hall -door and into it. I only caught a glimpse of her at the moment, -but she was a lovely woman, with a face that a man might die for. - -"'The Church of St. Monica, John,' she cried, 'and half a -sovereign if you reach it in twenty minutes.' - -"This was quite too good to lose, Watson. I was just balancing -whether I should run for it, or whether I should perch behind her -landau when a cab came through the street. The driver looked -twice at such a shabby fare, but I jumped in before he could -object. 'The Church of St. Monica,' said I, 'and half a sovereign -if you reach it in twenty minutes.' It was twenty-five minutes to -twelve, and of course it was clear enough what was in the wind. - -"My cabby drove fast. I don't think I ever drove faster, but the -others were there before us. The cab and the landau with their -steaming horses were in front of the door when I arrived. I paid -the man and hurried into the church. There was not a soul there -save the two whom I had followed and a surpliced clergyman, who -seemed to be expostulating with them. They were all three -standing in a knot in front of the altar. I lounged up the side -aisle like any other idler who has dropped into a church. -Suddenly, to my surprise, the three at the altar faced round to -me, and Godfrey Norton came running as hard as he could towards -me. - -"'Thank God,' he cried. 'You'll do. Come! Come!' - -"'What then?' I asked. - -"'Come, man, come, only three minutes, or it won't be legal.' - -"I was half-dragged up to the altar, and before I knew where I was -I found myself mumbling responses which were whispered in my ear, -and vouching for things of which I knew nothing, and generally -assisting in the secure tying up of Irene Adler, spinster, to -Godfrey Norton, bachelor. It was all done in an instant, and -there was the gentleman thanking me on the one side and the lady -on the other, while the clergyman beamed on me in front. It was -the most preposterous position in which I ever found myself in my -life, and it was the thought of it that started me laughing just -now. It seems that there had been some informality about their -license, that the clergyman absolutely refused to marry them -without a witness of some sort, and that my lucky appearance -saved the bridegroom from having to sally out into the streets in -search of a best man. The bride gave me a sovereign, and I mean -to wear it on my watch-chain in memory of the occasion." - -"This is a very unexpected turn of affairs," said I; "and what -then?" - -"Well, I found my plans very seriously menaced. It looked as if -the pair might take an immediate departure, and so necessitate -very prompt and energetic measures on my part. At the church -door, however, they separated, he driving back to the Temple, and -she to her own house. 'I shall drive out in the park at five as -usual,' she said as she left him. I heard no more. They drove -away in different directions, and I went off to make my own -arrangements." - -"Which are?" - -"Some cold beef and a glass of beer," he answered, ringing the -bell. "I have been too busy to think of food, and I am likely to -be busier still this evening. By the way, Doctor, I shall want -your co-operation." - -"I shall be delighted." - -"You don't mind breaking the law?" - -"Not in the least." - -"Nor running a chance of arrest?" - -"Not in a good cause." - -"Oh, the cause is excellent!" - -"Then I am your man." - -"I was sure that I might rely on you." - -"But what is it you wish?" - -"When Mrs. Turner has brought in the tray I will make it clear to -you. Now," he said as he turned hungrily on the simple fare that -our landlady had provided, "I must discuss it while I eat, for I -have not much time. It is nearly five now. In two hours we must -be on the scene of action. Miss Irene, or Madame, rather, returns -from her drive at seven. We must be at Briony Lodge to meet her." - -"And what then?" - -"You must leave that to me. I have already arranged what is to -occur. There is only one point on which I must insist. You must -not interfere, come what may. You understand?" - -"I am to be neutral?" - -"To do nothing whatever. There will probably be some small -unpleasantness. Do not join in it. It will end in my being -conveyed into the house. Four or five minutes afterwards the -sitting-room window will open. You are to station yourself close -to that open window." - -"Yes." - -"You are to watch me, for I will be visible to you." - -"Yes." - -"And when I raise my hand--so--you will throw into the room what -I give you to throw, and will, at the same time, raise the cry of -fire. You quite follow me?" - -"Entirely." - -"It is nothing very formidable," he said, taking a long cigar-shaped -roll from his pocket. "It is an ordinary plumber's smoke-rocket, -fitted with a cap at either end to make it self-lighting. -Your task is confined to that. When you raise your cry of fire, -it will be taken up by quite a number of people. You may then -walk to the end of the street, and I will rejoin you in ten -minutes. I hope that I have made myself clear?" - -"I am to remain neutral, to get near the window, to watch you, -and at the signal to throw in this object, then to raise the cry -of fire, and to wait you at the corner of the street." - -"Precisely." - -"Then you may entirely rely on me." - -"That is excellent. I think, perhaps, it is almost time that I -prepare for the new role I have to play." - -He disappeared into his bedroom and returned in a few minutes in -the character of an amiable and simple-minded Nonconformist -clergyman. His broad black hat, his baggy trousers, his white -tie, his sympathetic smile, and general look of peering and -benevolent curiosity were such as Mr. John Hare alone could have -equalled. It was not merely that Holmes changed his costume. His -expression, his manner, his very soul seemed to vary with every -fresh part that he assumed. The stage lost a fine actor, even as -science lost an acute reasoner, when he became a specialist in -crime. - -It was a quarter past six when we left Baker Street, and it still -wanted ten minutes to the hour when we found ourselves in -Serpentine Avenue. It was already dusk, and the lamps were just -being lighted as we paced up and down in front of Briony Lodge, -waiting for the coming of its occupant. The house was just such -as I had pictured it from Sherlock Holmes' succinct description, -but the locality appeared to be less private than I expected. On -the contrary, for a small street in a quiet neighbourhood, it was -remarkably animated. There was a group of shabbily dressed men -smoking and laughing in a corner, a scissors-grinder with his -wheel, two guardsmen who were flirting with a nurse-girl, and -several well-dressed young men who were lounging up and down with -cigars in their mouths. - -"You see," remarked Holmes, as we paced to and fro in front of -the house, "this marriage rather simplifies matters. The -photograph becomes a double-edged weapon now. The chances are -that she would be as averse to its being seen by Mr. Godfrey -Norton, as our client is to its coming to the eyes of his -princess. Now the question is, Where are we to find the -photograph?" - -"Where, indeed?" - -"It is most unlikely that she carries it about with her. It is -cabinet size. Too large for easy concealment about a woman's -dress. She knows that the King is capable of having her waylaid -and searched. Two attempts of the sort have already been made. We -may take it, then, that she does not carry it about with her." - -"Where, then?" - -"Her banker or her lawyer. There is that double possibility. But -I am inclined to think neither. Women are naturally secretive, -and they like to do their own secreting. Why should she hand it -over to anyone else? She could trust her own guardianship, but -she could not tell what indirect or political influence might be -brought to bear upon a business man. Besides, remember that she -had resolved to use it within a few days. It must be where she -can lay her hands upon it. It must be in her own house." - -"But it has twice been burgled." - -"Pshaw! They did not know how to look." - -"But how will you look?" - -"I will not look." - -"What then?" - -"I will get her to show me." - -"But she will refuse." - -"She will not be able to. But I hear the rumble of wheels. It is -her carriage. Now carry out my orders to the letter." - -As he spoke the gleam of the side-lights of a carriage came round -the curve of the avenue. It was a smart little landau which -rattled up to the door of Briony Lodge. As it pulled up, one of -the loafing men at the corner dashed forward to open the door in -the hope of earning a copper, but was elbowed away by another -loafer, who had rushed up with the same intention. A fierce -quarrel broke out, which was increased by the two guardsmen, who -took sides with one of the loungers, and by the scissors-grinder, -who was equally hot upon the other side. A blow was struck, and -in an instant the lady, who had stepped from her carriage, was -the centre of a little knot of flushed and struggling men, who -struck savagely at each other with their fists and sticks. Holmes -dashed into the crowd to protect the lady; but just as he reached -her he gave a cry and dropped to the ground, with the blood -running freely down his face. At his fall the guardsmen took to -their heels in one direction and the loungers in the other, while -a number of better-dressed people, who had watched the scuffle -without taking part in it, crowded in to help the lady and to -attend to the injured man. Irene Adler, as I will still call her, -had hurried up the steps; but she stood at the top with her -superb figure outlined against the lights of the hall, looking -back into the street. - -"Is the poor gentleman much hurt?" she asked. - -"He is dead," cried several voices. - -"No, no, there's life in him!" shouted another. "But he'll be -gone before you can get him to hospital." - -"He's a brave fellow," said a woman. "They would have had the -lady's purse and watch if it hadn't been for him. They were a -gang, and a rough one, too. Ah, he's breathing now." - -"He can't lie in the street. May we bring him in, marm?" - -"Surely. Bring him into the sitting-room. There is a comfortable -sofa. This way, please!" - -Slowly and solemnly he was borne into Briony Lodge and laid out -in the principal room, while I still observed the proceedings -from my post by the window. The lamps had been lit, but the -blinds had not been drawn, so that I could see Holmes as he lay -upon the couch. I do not know whether he was seized with -compunction at that moment for the part he was playing, but I -know that I never felt more heartily ashamed of myself in my life -than when I saw the beautiful creature against whom I was -conspiring, or the grace and kindliness with which she waited -upon the injured man. And yet it would be the blackest treachery -to Holmes to draw back now from the part which he had intrusted -to me. I hardened my heart, and took the smoke-rocket from under -my ulster. After all, I thought, we are not injuring her. We are -but preventing her from injuring another. - -Holmes had sat up upon the couch, and I saw him motion like a man -who is in need of air. A maid rushed across and threw open the -window. At the same instant I saw him raise his hand and at the -signal I tossed my rocket into the room with a cry of "Fire!" The -word was no sooner out of my mouth than the whole crowd of -spectators, well dressed and ill--gentlemen, ostlers, and -servant-maids--joined in a general shriek of "Fire!" Thick clouds -of smoke curled through the room and out at the open window. I -caught a glimpse of rushing figures, and a moment later the voice -of Holmes from within assuring them that it was a false alarm. -Slipping through the shouting crowd I made my way to the corner -of the street, and in ten minutes was rejoiced to find my -friend's arm in mine, and to get away from the scene of uproar. -He walked swiftly and in silence for some few minutes until we -had turned down one of the quiet streets which lead towards the -Edgeware Road. - -"You did it very nicely, Doctor," he remarked. "Nothing could -have been better. It is all right." - -"You have the photograph?" - -"I know where it is." - -"And how did you find out?" - -"She showed me, as I told you she would." - -"I am still in the dark." - -"I do not wish to make a mystery," said he, laughing. "The matter -was perfectly simple. You, of course, saw that everyone in the -street was an accomplice. They were all engaged for the evening." - -"I guessed as much." - -"Then, when the row broke out, I had a little moist red paint in -the palm of my hand. I rushed forward, fell down, clapped my hand -to my face, and became a piteous spectacle. It is an old trick." - -"That also I could fathom." - -"Then they carried me in. She was bound to have me in. What else -could she do? And into her sitting-room, which was the very room -which I suspected. It lay between that and her bedroom, and I was -determined to see which. They laid me on a couch, I motioned for -air, they were compelled to open the window, and you had your -chance." - -"How did that help you?" - -"It was all-important. When a woman thinks that her house is on -fire, her instinct is at once to rush to the thing which she -values most. It is a perfectly overpowering impulse, and I have -more than once taken advantage of it. In the case of the -Darlington substitution scandal it was of use to me, and also in -the Arnsworth Castle business. A married woman grabs at her baby; -an unmarried one reaches for her jewel-box. Now it was clear to -me that our lady of to-day had nothing in the house more precious -to her than what we are in quest of. She would rush to secure it. -The alarm of fire was admirably done. The smoke and shouting were -enough to shake nerves of steel. She responded beautifully. The -photograph is in a recess behind a sliding panel just above the -right bell-pull. She was there in an instant, and I caught a -glimpse of it as she half-drew it out. When I cried out that it -was a false alarm, she replaced it, glanced at the rocket, rushed -from the room, and I have not seen her since. I rose, and, making -my excuses, escaped from the house. I hesitated whether to -attempt to secure the photograph at once; but the coachman had -come in, and as he was watching me narrowly it seemed safer to -wait. A little over-precipitance may ruin all." - -"And now?" I asked. - -"Our quest is practically finished. I shall call with the King -to-morrow, and with you, if you care to come with us. We will be -shown into the sitting-room to wait for the lady, but it is -probable that when she comes she may find neither us nor the -photograph. It might be a satisfaction to his Majesty to regain -it with his own hands." - -"And when will you call?" - -"At eight in the morning. She will not be up, so that we shall -have a clear field. Besides, we must be prompt, for this marriage -may mean a complete change in her life and habits. I must wire to -the King without delay." - -We had reached Baker Street and had stopped at the door. He was -searching his pockets for the key when someone passing said: - -"Good-night, Mister Sherlock Holmes." - -There were several people on the pavement at the time, but the -greeting appeared to come from a slim youth in an ulster who had -hurried by. - -"I've heard that voice before," said Holmes, staring down the -dimly lit street. "Now, I wonder who the deuce that could have -been." - - -III. - -I slept at Baker Street that night, and we were engaged upon our -toast and coffee in the morning when the King of Bohemia rushed -into the room. - -"You have really got it!" he cried, grasping Sherlock Holmes by -either shoulder and looking eagerly into his face. - -"Not yet." - -"But you have hopes?" - -"I have hopes." - -"Then, come. I am all impatience to be gone." - -"We must have a cab." - -"No, my brougham is waiting." - -"Then that will simplify matters." We descended and started off -once more for Briony Lodge. - -"Irene Adler is married," remarked Holmes. - -"Married! When?" - -"Yesterday." - -"But to whom?" - -"To an English lawyer named Norton." - -"But she could not love him." - -"I am in hopes that she does." - -"And why in hopes?" - -"Because it would spare your Majesty all fear of future -annoyance. If the lady loves her husband, she does not love your -Majesty. If she does not love your Majesty, there is no reason -why she should interfere with your Majesty's plan." - -"It is true. And yet--Well! I wish she had been of my own -station! What a queen she would have made!" He relapsed into a -moody silence, which was not broken until we drew up in -Serpentine Avenue. - -The door of Briony Lodge was open, and an elderly woman stood -upon the steps. She watched us with a sardonic eye as we stepped -from the brougham. - -"Mr. Sherlock Holmes, I believe?" said she. - -"I am Mr. Holmes," answered my companion, looking at her with a -questioning and rather startled gaze. - -"Indeed! My mistress told me that you were likely to call. She -left this morning with her husband by the 5:15 train from Charing -Cross for the Continent." - -"What!" Sherlock Holmes staggered back, white with chagrin and -surprise. "Do you mean that she has left England?" - -"Never to return." - -"And the papers?" asked the King hoarsely. "All is lost." - -"We shall see." He pushed past the servant and rushed into the -drawing-room, followed by the King and myself. The furniture was -scattered about in every direction, with dismantled shelves and -open drawers, as if the lady had hurriedly ransacked them before -her flight. Holmes rushed at the bell-pull, tore back a small -sliding shutter, and, plunging in his hand, pulled out a -photograph and a letter. The photograph was of Irene Adler -herself in evening dress, the letter was superscribed to -"Sherlock Holmes, Esq. To be left till called for." My friend -tore it open and we all three read it together. It was dated at -midnight of the preceding night and ran in this way: - -"MY DEAR MR. SHERLOCK HOLMES,--You really did it very well. You -took me in completely. Until after the alarm of fire, I had not a -suspicion. But then, when I found how I had betrayed myself, I -began to think. I had been warned against you months ago. I had -been told that if the King employed an agent it would certainly -be you. And your address had been given me. Yet, with all this, -you made me reveal what you wanted to know. Even after I became -suspicious, I found it hard to think evil of such a dear, kind -old clergyman. But, you know, I have been trained as an actress -myself. Male costume is nothing new to me. I often take advantage -of the freedom which it gives. I sent John, the coachman, to -watch you, ran up stairs, got into my walking-clothes, as I call -them, and came down just as you departed. - -"Well, I followed you to your door, and so made sure that I was -really an object of interest to the celebrated Mr. Sherlock -Holmes. Then I, rather imprudently, wished you good-night, and -started for the Temple to see my husband. - -"We both thought the best resource was flight, when pursued by -so formidable an antagonist; so you will find the nest empty when -you call to-morrow. As to the photograph, your client may rest in -peace. I love and am loved by a better man than he. The King may -do what he will without hindrance from one whom he has cruelly -wronged. I keep it only to safeguard myself, and to preserve a -weapon which will always secure me from any steps which he might -take in the future. I leave a photograph which he might care to -possess; and I remain, dear Mr. Sherlock Holmes, - - "Very truly yours, - "IRENE NORTON, née ADLER." - -"What a woman--oh, what a woman!" cried the King of Bohemia, when -we had all three read this epistle. "Did I not tell you how quick -and resolute she was? Would she not have made an admirable queen? -Is it not a pity that she was not on my level?" - -"From what I have seen of the lady she seems indeed to be on a -very different level to your Majesty," said Holmes coldly. "I am -sorry that I have not been able to bring your Majesty's business -to a more successful conclusion." - -"On the contrary, my dear sir," cried the King; "nothing could be -more successful. I know that her word is inviolate. The -photograph is now as safe as if it were in the fire." - -"I am glad to hear your Majesty say so." - -"I am immensely indebted to you. Pray tell me in what way I can -reward you. This ring--" He slipped an emerald snake ring from -his finger and held it out upon the palm of his hand. - -"Your Majesty has something which I should value even more -highly," said Holmes. - -"You have but to name it." - -"This photograph!" - -The King stared at him in amazement. - -"Irene's photograph!" he cried. "Certainly, if you wish it." - -"I thank your Majesty. Then there is no more to be done in the -matter. I have the honour to wish you a very good-morning." He -bowed, and, turning away without observing the hand which the -King had stretched out to him, he set off in my company for his -chambers. - -And that was how a great scandal threatened to affect the kingdom -of Bohemia, and how the best plans of Mr. Sherlock Holmes were -beaten by a woman's wit. He used to make merry over the -cleverness of women, but I have not heard him do it of late. And -when he speaks of Irene Adler, or when he refers to her -photograph, it is always under the honourable title of the woman. - - - -ADVENTURE II. THE RED-HEADED LEAGUE - -I had called upon my friend, Mr. Sherlock Holmes, one day in the -autumn of last year and found him in deep conversation with a -very stout, florid-faced, elderly gentleman with fiery red hair. -With an apology for my intrusion, I was about to withdraw when -Holmes pulled me abruptly into the room and closed the door -behind me. - -"You could not possibly have come at a better time, my dear -Watson," he said cordially. - -"I was afraid that you were engaged." - -"So I am. Very much so." - -"Then I can wait in the next room." - -"Not at all. This gentleman, Mr. Wilson, has been my partner and -helper in many of my most successful cases, and I have no -doubt that he will be of the utmost use to me in yours also." - -The stout gentleman half rose from his chair and gave a bob of -greeting, with a quick little questioning glance from his small -fat-encircled eyes. - -"Try the settee," said Holmes, relapsing into his armchair and -putting his fingertips together, as was his custom when in -judicial moods. "I know, my dear Watson, that you share my love -of all that is bizarre and outside the conventions and humdrum -routine of everyday life. You have shown your relish for it by -the enthusiasm which has prompted you to chronicle, and, if you -will excuse my saying so, somewhat to embellish so many of my own -little adventures." - -"Your cases have indeed been of the greatest interest to me," I -observed. - -"You will remember that I remarked the other day, just before we -went into the very simple problem presented by Miss Mary -Sutherland, that for strange effects and extraordinary -combinations we must go to life itself, which is always far more -daring than any effort of the imagination." - -"A proposition which I took the liberty of doubting." - -"You did, Doctor, but none the less you must come round to my -view, for otherwise I shall keep on piling fact upon fact on you -until your reason breaks down under them and acknowledges me to -be right. Now, Mr. Jabez Wilson here has been good enough to call -upon me this morning, and to begin a narrative which promises to -be one of the most singular which I have listened to for some -time. You have heard me remark that the strangest and most unique -things are very often connected not with the larger but with the -smaller crimes, and occasionally, indeed, where there is room for -doubt whether any positive crime has been committed. As far as I -have heard it is impossible for me to say whether the present -case is an instance of crime or not, but the course of events is -certainly among the most singular that I have ever listened to. -Perhaps, Mr. Wilson, you would have the great kindness to -recommence your narrative. I ask you not merely because my friend -Dr. Watson has not heard the opening part but also because the -peculiar nature of the story makes me anxious to have every -possible detail from your lips. As a rule, when I have heard some -slight indication of the course of events, I am able to guide -myself by the thousands of other similar cases which occur to my -memory. In the present instance I am forced to admit that the -facts are, to the best of my belief, unique." - -The portly client puffed out his chest with an appearance of some -little pride and pulled a dirty and wrinkled newspaper from the -inside pocket of his greatcoat. As he glanced down the -advertisement column, with his head thrust forward and the paper -flattened out upon his knee, I took a good look at the man and -endeavoured, after the fashion of my companion, to read the -indications which might be presented by his dress or appearance. - -I did not gain very much, however, by my inspection. Our visitor -bore every mark of being an average commonplace British -tradesman, obese, pompous, and slow. He wore rather baggy grey -shepherd's check trousers, a not over-clean black frock-coat, -unbuttoned in the front, and a drab waistcoat with a heavy brassy -Albert chain, and a square pierced bit of metal dangling down as -an ornament. A frayed top-hat and a faded brown overcoat with a -wrinkled velvet collar lay upon a chair beside him. Altogether, -look as I would, there was nothing remarkable about the man save -his blazing red head, and the expression of extreme chagrin and -discontent upon his features. - -Sherlock Holmes' quick eye took in my occupation, and he shook -his head with a smile as he noticed my questioning glances. -"Beyond the obvious facts that he has at some time done manual -labour, that he takes snuff, that he is a Freemason, that he has -been in China, and that he has done a considerable amount of -writing lately, I can deduce nothing else." - -Mr. Jabez Wilson started up in his chair, with his forefinger -upon the paper, but his eyes upon my companion. - -"How, in the name of good-fortune, did you know all that, Mr. -Holmes?" he asked. "How did you know, for example, that I did -manual labour. It's as true as gospel, for I began as a ship's -carpenter." - -"Your hands, my dear sir. Your right hand is quite a size larger -than your left. You have worked with it, and the muscles are more -developed." - -"Well, the snuff, then, and the Freemasonry?" - -"I won't insult your intelligence by telling you how I read that, -especially as, rather against the strict rules of your order, you -use an arc-and-compass breastpin." - -"Ah, of course, I forgot that. But the writing?" - -"What else can be indicated by that right cuff so very shiny for -five inches, and the left one with the smooth patch near the -elbow where you rest it upon the desk?" - -"Well, but China?" - -"The fish that you have tattooed immediately above your right -wrist could only have been done in China. I have made a small -study of tattoo marks and have even contributed to the literature -of the subject. That trick of staining the fishes' scales of a -delicate pink is quite peculiar to China. When, in addition, I -see a Chinese coin hanging from your watch-chain, the matter -becomes even more simple." - -Mr. Jabez Wilson laughed heavily. "Well, I never!" said he. "I -thought at first that you had done something clever, but I see -that there was nothing in it, after all." - -"I begin to think, Watson," said Holmes, "that I make a mistake -in explaining. 'Omne ignotum pro magnifico,' you know, and my -poor little reputation, such as it is, will suffer shipwreck if I -am so candid. Can you not find the advertisement, Mr. Wilson?" - -"Yes, I have got it now," he answered with his thick red finger -planted halfway down the column. "Here it is. This is what began -it all. You just read it for yourself, sir." - -I took the paper from him and read as follows: - -"TO THE RED-HEADED LEAGUE: On account of the bequest of the late -Ezekiah Hopkins, of Lebanon, Pennsylvania, U. S. A., there is now -another vacancy open which entitles a member of the League to a -salary of 4 pounds a week for purely nominal services. All -red-headed men who are sound in body and mind and above the age -of twenty-one years, are eligible. Apply in person on Monday, at -eleven o'clock, to Duncan Ross, at the offices of the League, 7 -Pope's Court, Fleet Street." - -"What on earth does this mean?" I ejaculated after I had twice -read over the extraordinary announcement. - -Holmes chuckled and wriggled in his chair, as was his habit when -in high spirits. "It is a little off the beaten track, isn't it?" -said he. "And now, Mr. Wilson, off you go at scratch and tell us -all about yourself, your household, and the effect which this -advertisement had upon your fortunes. You will first make a note, -Doctor, of the paper and the date." - -"It is The Morning Chronicle of April 27, 1890. Just two months -ago." - -"Very good. Now, Mr. Wilson?" - -"Well, it is just as I have been telling you, Mr. Sherlock -Holmes," said Jabez Wilson, mopping his forehead; "I have a small -pawnbroker's business at Coburg Square, near the City. It's not a -very large affair, and of late years it has not done more than -just give me a living. I used to be able to keep two assistants, -but now I only keep one; and I would have a job to pay him but -that he is willing to come for half wages so as to learn the -business." - -"What is the name of this obliging youth?" asked Sherlock Holmes. - -"His name is Vincent Spaulding, and he's not such a youth, -either. It's hard to say his age. I should not wish a smarter -assistant, Mr. Holmes; and I know very well that he could better -himself and earn twice what I am able to give him. But, after -all, if he is satisfied, why should I put ideas in his head?" - -"Why, indeed? You seem most fortunate in having an employé who -comes under the full market price. It is not a common experience -among employers in this age. I don't know that your assistant is -not as remarkable as your advertisement." - -"Oh, he has his faults, too," said Mr. Wilson. "Never was such a -fellow for photography. Snapping away with a camera when he ought -to be improving his mind, and then diving down into the cellar -like a rabbit into its hole to develop his pictures. That is his -main fault, but on the whole he's a good worker. There's no vice -in him." - -"He is still with you, I presume?" - -"Yes, sir. He and a girl of fourteen, who does a bit of simple -cooking and keeps the place clean--that's all I have in the -house, for I am a widower and never had any family. We live very -quietly, sir, the three of us; and we keep a roof over our heads -and pay our debts, if we do nothing more. - -"The first thing that put us out was that advertisement. -Spaulding, he came down into the office just this day eight -weeks, with this very paper in his hand, and he says: - -"'I wish to the Lord, Mr. Wilson, that I was a red-headed man.' - -"'Why that?' I asks. - -"'Why,' says he, 'here's another vacancy on the League of the -Red-headed Men. It's worth quite a little fortune to any man who -gets it, and I understand that there are more vacancies than -there are men, so that the trustees are at their wits' end what -to do with the money. If my hair would only change colour, here's -a nice little crib all ready for me to step into.' - -"'Why, what is it, then?' I asked. You see, Mr. Holmes, I am a -very stay-at-home man, and as my business came to me instead of -my having to go to it, I was often weeks on end without putting -my foot over the door-mat. In that way I didn't know much of what -was going on outside, and I was always glad of a bit of news. - -"'Have you never heard of the League of the Red-headed Men?' he -asked with his eyes open. - -"'Never.' - -"'Why, I wonder at that, for you are eligible yourself for one -of the vacancies.' - -"'And what are they worth?' I asked. - -"'Oh, merely a couple of hundred a year, but the work is slight, -and it need not interfere very much with one's other -occupations.' - -"Well, you can easily think that that made me prick up my ears, -for the business has not been over-good for some years, and an -extra couple of hundred would have been very handy. - -"'Tell me all about it,' said I. - -"'Well,' said he, showing me the advertisement, 'you can see for -yourself that the League has a vacancy, and there is the address -where you should apply for particulars. As far as I can make out, -the League was founded by an American millionaire, Ezekiah -Hopkins, who was very peculiar in his ways. He was himself -red-headed, and he had a great sympathy for all red-headed men; -so when he died it was found that he had left his enormous -fortune in the hands of trustees, with instructions to apply the -interest to the providing of easy berths to men whose hair is of -that colour. From all I hear it is splendid pay and very little to -do.' - -"'But,' said I, 'there would be millions of red-headed men who -would apply.' - -"'Not so many as you might think,' he answered. 'You see it is -really confined to Londoners, and to grown men. This American had -started from London when he was young, and he wanted to do the -old town a good turn. Then, again, I have heard it is no use your -applying if your hair is light red, or dark red, or anything but -real bright, blazing, fiery red. Now, if you cared to apply, Mr. -Wilson, you would just walk in; but perhaps it would hardly be -worth your while to put yourself out of the way for the sake of a -few hundred pounds.' - -"Now, it is a fact, gentlemen, as you may see for yourselves, -that my hair is of a very full and rich tint, so that it seemed -to me that if there was to be any competition in the matter I -stood as good a chance as any man that I had ever met. Vincent -Spaulding seemed to know so much about it that I thought he might -prove useful, so I just ordered him to put up the shutters for -the day and to come right away with me. He was very willing to -have a holiday, so we shut the business up and started off for -the address that was given us in the advertisement. - -"I never hope to see such a sight as that again, Mr. Holmes. From -north, south, east, and west every man who had a shade of red in -his hair had tramped into the city to answer the advertisement. -Fleet Street was choked with red-headed folk, and Pope's Court -looked like a coster's orange barrow. I should not have thought -there were so many in the whole country as were brought together -by that single advertisement. Every shade of colour they -were--straw, lemon, orange, brick, Irish-setter, liver, clay; -but, as Spaulding said, there were not many who had the real -vivid flame-coloured tint. When I saw how many were waiting, I -would have given it up in despair; but Spaulding would not hear -of it. How he did it I could not imagine, but he pushed and -pulled and butted until he got me through the crowd, and right up -to the steps which led to the office. There was a double stream -upon the stair, some going up in hope, and some coming back -dejected; but we wedged in as well as we could and soon found -ourselves in the office." - -"Your experience has been a most entertaining one," remarked -Holmes as his client paused and refreshed his memory with a huge -pinch of snuff. "Pray continue your very interesting statement." - -"There was nothing in the office but a couple of wooden chairs -and a deal table, behind which sat a small man with a head that -was even redder than mine. He said a few words to each candidate -as he came up, and then he always managed to find some fault in -them which would disqualify them. Getting a vacancy did not seem -to be such a very easy matter, after all. However, when our turn -came the little man was much more favourable to me than to any of -the others, and he closed the door as we entered, so that he -might have a private word with us. - -"'This is Mr. Jabez Wilson,' said my assistant, 'and he is -willing to fill a vacancy in the League.' - -"'And he is admirably suited for it,' the other answered. 'He has -every requirement. I cannot recall when I have seen anything so -fine.' He took a step backward, cocked his head on one side, and -gazed at my hair until I felt quite bashful. Then suddenly he -plunged forward, wrung my hand, and congratulated me warmly on my -success. - -"'It would be injustice to hesitate,' said he. 'You will, -however, I am sure, excuse me for taking an obvious precaution.' -With that he seized my hair in both his hands, and tugged until I -yelled with the pain. 'There is water in your eyes,' said he as -he released me. 'I perceive that all is as it should be. But we -have to be careful, for we have twice been deceived by wigs and -once by paint. I could tell you tales of cobbler's wax which -would disgust you with human nature.' He stepped over to the -window and shouted through it at the top of his voice that the -vacancy was filled. A groan of disappointment came up from below, -and the folk all trooped away in different directions until there -was not a red-head to be seen except my own and that of the -manager. - -"'My name,' said he, 'is Mr. Duncan Ross, and I am myself one of -the pensioners upon the fund left by our noble benefactor. Are -you a married man, Mr. Wilson? Have you a family?' - -"I answered that I had not. - -"His face fell immediately. - -"'Dear me!' he said gravely, 'that is very serious indeed! I am -sorry to hear you say that. The fund was, of course, for the -propagation and spread of the red-heads as well as for their -maintenance. It is exceedingly unfortunate that you should be a -bachelor.' - -"My face lengthened at this, Mr. Holmes, for I thought that I was -not to have the vacancy after all; but after thinking it over for -a few minutes he said that it would be all right. - -"'In the case of another,' said he, 'the objection might be -fatal, but we must stretch a point in favour of a man with such a -head of hair as yours. When shall you be able to enter upon your -new duties?' - -"'Well, it is a little awkward, for I have a business already,' -said I. - -"'Oh, never mind about that, Mr. Wilson!' said Vincent Spaulding. -'I should be able to look after that for you.' - -"'What would be the hours?' I asked. - -"'Ten to two.' - -"Now a pawnbroker's business is mostly done of an evening, Mr. -Holmes, especially Thursday and Friday evening, which is just -before pay-day; so it would suit me very well to earn a little in -the mornings. Besides, I knew that my assistant was a good man, -and that he would see to anything that turned up. - -"'That would suit me very well,' said I. 'And the pay?' - -"'Is 4 pounds a week.' - -"'And the work?' - -"'Is purely nominal.' - -"'What do you call purely nominal?' - -"'Well, you have to be in the office, or at least in the -building, the whole time. If you leave, you forfeit your whole -position forever. The will is very clear upon that point. You -don't comply with the conditions if you budge from the office -during that time.' - -"'It's only four hours a day, and I should not think of leaving,' -said I. - -"'No excuse will avail,' said Mr. Duncan Ross; 'neither sickness -nor business nor anything else. There you must stay, or you lose -your billet.' - -"'And the work?' - -"'Is to copy out the "Encyclopaedia Britannica." There is the first -volume of it in that press. You must find your own ink, pens, and -blotting-paper, but we provide this table and chair. Will you be -ready to-morrow?' - -"'Certainly,' I answered. - -"'Then, good-bye, Mr. Jabez Wilson, and let me congratulate you -once more on the important position which you have been fortunate -enough to gain.' He bowed me out of the room and I went home with -my assistant, hardly knowing what to say or do, I was so pleased -at my own good fortune. - -"Well, I thought over the matter all day, and by evening I was in -low spirits again; for I had quite persuaded myself that the -whole affair must be some great hoax or fraud, though what its -object might be I could not imagine. It seemed altogether past -belief that anyone could make such a will, or that they would pay -such a sum for doing anything so simple as copying out the -'Encyclopaedia Britannica.' Vincent Spaulding did what he could to -cheer me up, but by bedtime I had reasoned myself out of the -whole thing. However, in the morning I determined to have a look -at it anyhow, so I bought a penny bottle of ink, and with a -quill-pen, and seven sheets of foolscap paper, I started off for -Pope's Court. - -"Well, to my surprise and delight, everything was as right as -possible. The table was set out ready for me, and Mr. Duncan Ross -was there to see that I got fairly to work. He started me off -upon the letter A, and then he left me; but he would drop in from -time to time to see that all was right with me. At two o'clock he -bade me good-day, complimented me upon the amount that I had -written, and locked the door of the office after me. - -"This went on day after day, Mr. Holmes, and on Saturday the -manager came in and planked down four golden sovereigns for my -week's work. It was the same next week, and the same the week -after. Every morning I was there at ten, and every afternoon I -left at two. By degrees Mr. Duncan Ross took to coming in only -once of a morning, and then, after a time, he did not come in at -all. Still, of course, I never dared to leave the room for an -instant, for I was not sure when he might come, and the billet -was such a good one, and suited me so well, that I would not risk -the loss of it. - -"Eight weeks passed away like this, and I had written about -Abbots and Archery and Armour and Architecture and Attica, and -hoped with diligence that I might get on to the B's before very -long. It cost me something in foolscap, and I had pretty nearly -filled a shelf with my writings. And then suddenly the whole -business came to an end." - -"To an end?" - -"Yes, sir. And no later than this morning. I went to my work as -usual at ten o'clock, but the door was shut and locked, with a -little square of cardboard hammered on to the middle of the -panel with a tack. Here it is, and you can read for yourself." - -He held up a piece of white cardboard about the size of a sheet -of note-paper. It read in this fashion: - - THE RED-HEADED LEAGUE - - IS - - DISSOLVED. - - October 9, 1890. - -Sherlock Holmes and I surveyed this curt announcement and the -rueful face behind it, until the comical side of the affair so -completely overtopped every other consideration that we both -burst out into a roar of laughter. - -"I cannot see that there is anything very funny," cried our -client, flushing up to the roots of his flaming head. "If you can -do nothing better than laugh at me, I can go elsewhere." - -"No, no," cried Holmes, shoving him back into the chair from -which he had half risen. "I really wouldn't miss your case for -the world. It is most refreshingly unusual. But there is, if you -will excuse my saying so, something just a little funny about it. -Pray what steps did you take when you found the card upon the -door?" - -"I was staggered, sir. I did not know what to do. Then I called -at the offices round, but none of them seemed to know anything -about it. Finally, I went to the landlord, who is an accountant -living on the ground-floor, and I asked him if he could tell me -what had become of the Red-headed League. He said that he had -never heard of any such body. Then I asked him who Mr. Duncan -Ross was. He answered that the name was new to him. - -"'Well,' said I, 'the gentleman at No. 4.' - -"'What, the red-headed man?' - -"'Yes.' - -"'Oh,' said he, 'his name was William Morris. He was a solicitor -and was using my room as a temporary convenience until his new -premises were ready. He moved out yesterday.' - -"'Where could I find him?' - -"'Oh, at his new offices. He did tell me the address. Yes, 17 -King Edward Street, near St. Paul's.' - -"I started off, Mr. Holmes, but when I got to that address it was -a manufactory of artificial knee-caps, and no one in it had ever -heard of either Mr. William Morris or Mr. Duncan Ross." - -"And what did you do then?" asked Holmes. - -"I went home to Saxe-Coburg Square, and I took the advice of my -assistant. But he could not help me in any way. He could only say -that if I waited I should hear by post. But that was not quite -good enough, Mr. Holmes. I did not wish to lose such a place -without a struggle, so, as I had heard that you were good enough -to give advice to poor folk who were in need of it, I came right -away to you." - -"And you did very wisely," said Holmes. "Your case is an -exceedingly remarkable one, and I shall be happy to look into it. -From what you have told me I think that it is possible that -graver issues hang from it than might at first sight appear." - -"Grave enough!" said Mr. Jabez Wilson. "Why, I have lost four -pound a week." - -"As far as you are personally concerned," remarked Holmes, "I do -not see that you have any grievance against this extraordinary -league. On the contrary, you are, as I understand, richer by some -30 pounds, to say nothing of the minute knowledge which you have -gained on every subject which comes under the letter A. You have -lost nothing by them." - -"No, sir. But I want to find out about them, and who they are, -and what their object was in playing this prank--if it was a -prank--upon me. It was a pretty expensive joke for them, for it -cost them two and thirty pounds." - -"We shall endeavour to clear up these points for you. And, first, -one or two questions, Mr. Wilson. This assistant of yours who -first called your attention to the advertisement--how long had he -been with you?" - -"About a month then." - -"How did he come?" - -"In answer to an advertisement." - -"Was he the only applicant?" - -"No, I had a dozen." - -"Why did you pick him?" - -"Because he was handy and would come cheap." - -"At half-wages, in fact." - -"Yes." - -"What is he like, this Vincent Spaulding?" - -"Small, stout-built, very quick in his ways, no hair on his face, -though he's not short of thirty. Has a white splash of acid upon -his forehead." - -Holmes sat up in his chair in considerable excitement. "I thought -as much," said he. "Have you ever observed that his ears are -pierced for earrings?" - -"Yes, sir. He told me that a gipsy had done it for him when he -was a lad." - -"Hum!" said Holmes, sinking back in deep thought. "He is still -with you?" - -"Oh, yes, sir; I have only just left him." - -"And has your business been attended to in your absence?" - -"Nothing to complain of, sir. There's never very much to do of a -morning." - -"That will do, Mr. Wilson. I shall be happy to give you an -opinion upon the subject in the course of a day or two. To-day is -Saturday, and I hope that by Monday we may come to a conclusion." - -"Well, Watson," said Holmes when our visitor had left us, "what -do you make of it all?" - -"I make nothing of it," I answered frankly. "It is a most -mysterious business." - -"As a rule," said Holmes, "the more bizarre a thing is the less -mysterious it proves to be. It is your commonplace, featureless -crimes which are really puzzling, just as a commonplace face is -the most difficult to identify. But I must be prompt over this -matter." - -"What are you going to do, then?" I asked. - -"To smoke," he answered. "It is quite a three pipe problem, and I -beg that you won't speak to me for fifty minutes." He curled -himself up in his chair, with his thin knees drawn up to his -hawk-like nose, and there he sat with his eyes closed and his -black clay pipe thrusting out like the bill of some strange bird. -I had come to the conclusion that he had dropped asleep, and -indeed was nodding myself, when he suddenly sprang out of his -chair with the gesture of a man who has made up his mind and put -his pipe down upon the mantelpiece. - -"Sarasate plays at the St. James's Hall this afternoon," he -remarked. "What do you think, Watson? Could your patients spare -you for a few hours?" - -"I have nothing to do to-day. My practice is never very -absorbing." - -"Then put on your hat and come. I am going through the City -first, and we can have some lunch on the way. I observe that -there is a good deal of German music on the programme, which is -rather more to my taste than Italian or French. It is -introspective, and I want to introspect. Come along!" - -We travelled by the Underground as far as Aldersgate; and a short -walk took us to Saxe-Coburg Square, the scene of the singular -story which we had listened to in the morning. It was a poky, -little, shabby-genteel place, where four lines of dingy -two-storied brick houses looked out into a small railed-in -enclosure, where a lawn of weedy grass and a few clumps of faded -laurel-bushes made a hard fight against a smoke-laden and -uncongenial atmosphere. Three gilt balls and a brown board with -"JABEZ WILSON" in white letters, upon a corner house, announced -the place where our red-headed client carried on his business. -Sherlock Holmes stopped in front of it with his head on one side -and looked it all over, with his eyes shining brightly between -puckered lids. Then he walked slowly up the street, and then down -again to the corner, still looking keenly at the houses. Finally -he returned to the pawnbroker's, and, having thumped vigorously -upon the pavement with his stick two or three times, he went up -to the door and knocked. It was instantly opened by a -bright-looking, clean-shaven young fellow, who asked him to step -in. - -"Thank you," said Holmes, "I only wished to ask you how you would -go from here to the Strand." - -"Third right, fourth left," answered the assistant promptly, -closing the door. - -"Smart fellow, that," observed Holmes as we walked away. "He is, -in my judgment, the fourth smartest man in London, and for daring -I am not sure that he has not a claim to be third. I have known -something of him before." - -"Evidently," said I, "Mr. Wilson's assistant counts for a good -deal in this mystery of the Red-headed League. I am sure that you -inquired your way merely in order that you might see him." - -"Not him." - -"What then?" - -"The knees of his trousers." - -"And what did you see?" - -"What I expected to see." - -"Why did you beat the pavement?" - -"My dear doctor, this is a time for observation, not for talk. We -are spies in an enemy's country. We know something of Saxe-Coburg -Square. Let us now explore the parts which lie behind it." - -The road in which we found ourselves as we turned round the -corner from the retired Saxe-Coburg Square presented as great a -contrast to it as the front of a picture does to the back. It was -one of the main arteries which conveyed the traffic of the City -to the north and west. The roadway was blocked with the immense -stream of commerce flowing in a double tide inward and outward, -while the footpaths were black with the hurrying swarm of -pedestrians. It was difficult to realise as we looked at the line -of fine shops and stately business premises that they really -abutted on the other side upon the faded and stagnant square -which we had just quitted. - -"Let me see," said Holmes, standing at the corner and glancing -along the line, "I should like just to remember the order of the -houses here. It is a hobby of mine to have an exact knowledge of -London. There is Mortimer's, the tobacconist, the little -newspaper shop, the Coburg branch of the City and Suburban Bank, -the Vegetarian Restaurant, and McFarlane's carriage-building -depot. That carries us right on to the other block. And now, -Doctor, we've done our work, so it's time we had some play. A -sandwich and a cup of coffee, and then off to violin-land, where -all is sweetness and delicacy and harmony, and there are no -red-headed clients to vex us with their conundrums." - -My friend was an enthusiastic musician, being himself not only a -very capable performer but a composer of no ordinary merit. All -the afternoon he sat in the stalls wrapped in the most perfect -happiness, gently waving his long, thin fingers in time to the -music, while his gently smiling face and his languid, dreamy eyes -were as unlike those of Holmes the sleuth-hound, Holmes the -relentless, keen-witted, ready-handed criminal agent, as it was -possible to conceive. In his singular character the dual nature -alternately asserted itself, and his extreme exactness and -astuteness represented, as I have often thought, the reaction -against the poetic and contemplative mood which occasionally -predominated in him. The swing of his nature took him from -extreme languor to devouring energy; and, as I knew well, he was -never so truly formidable as when, for days on end, he had been -lounging in his armchair amid his improvisations and his -black-letter editions. Then it was that the lust of the chase -would suddenly come upon him, and that his brilliant reasoning -power would rise to the level of intuition, until those who were -unacquainted with his methods would look askance at him as on a -man whose knowledge was not that of other mortals. When I saw him -that afternoon so enwrapped in the music at St. James's Hall I -felt that an evil time might be coming upon those whom he had set -himself to hunt down. - -"You want to go home, no doubt, Doctor," he remarked as we -emerged. - -"Yes, it would be as well." - -"And I have some business to do which will take some hours. This -business at Coburg Square is serious." - -"Why serious?" - -"A considerable crime is in contemplation. I have every reason to -believe that we shall be in time to stop it. But to-day being -Saturday rather complicates matters. I shall want your help -to-night." - -"At what time?" - -"Ten will be early enough." - -"I shall be at Baker Street at ten." - -"Very well. And, I say, Doctor, there may be some little danger, -so kindly put your army revolver in your pocket." He waved his -hand, turned on his heel, and disappeared in an instant among the -crowd. - -I trust that I am not more dense than my neighbours, but I was -always oppressed with a sense of my own stupidity in my dealings -with Sherlock Holmes. Here I had heard what he had heard, I had -seen what he had seen, and yet from his words it was evident that -he saw clearly not only what had happened but what was about to -happen, while to me the whole business was still confused and -grotesque. As I drove home to my house in Kensington I thought -over it all, from the extraordinary story of the red-headed -copier of the "Encyclopaedia" down to the visit to Saxe-Coburg -Square, and the ominous words with which he had parted from me. -What was this nocturnal expedition, and why should I go armed? -Where were we going, and what were we to do? I had the hint from -Holmes that this smooth-faced pawnbroker's assistant was a -formidable man--a man who might play a deep game. I tried to -puzzle it out, but gave it up in despair and set the matter aside -until night should bring an explanation. - -It was a quarter-past nine when I started from home and made my -way across the Park, and so through Oxford Street to Baker -Street. Two hansoms were standing at the door, and as I entered -the passage I heard the sound of voices from above. On entering -his room I found Holmes in animated conversation with two men, -one of whom I recognised as Peter Jones, the official police -agent, while the other was a long, thin, sad-faced man, with a -very shiny hat and oppressively respectable frock-coat. - -"Ha! Our party is complete," said Holmes, buttoning up his -pea-jacket and taking his heavy hunting crop from the rack. -"Watson, I think you know Mr. Jones, of Scotland Yard? Let me -introduce you to Mr. Merryweather, who is to be our companion in -to-night's adventure." - -"We're hunting in couples again, Doctor, you see," said Jones in -his consequential way. "Our friend here is a wonderful man for -starting a chase. All he wants is an old dog to help him to do -the running down." - -"I hope a wild goose may not prove to be the end of our chase," -observed Mr. Merryweather gloomily. - -"You may place considerable confidence in Mr. Holmes, sir," said -the police agent loftily. "He has his own little methods, which -are, if he won't mind my saying so, just a little too theoretical -and fantastic, but he has the makings of a detective in him. It -is not too much to say that once or twice, as in that business of -the Sholto murder and the Agra treasure, he has been more nearly -correct than the official force." - -"Oh, if you say so, Mr. Jones, it is all right," said the -stranger with deference. "Still, I confess that I miss my rubber. -It is the first Saturday night for seven-and-twenty years that I -have not had my rubber." - -"I think you will find," said Sherlock Holmes, "that you will -play for a higher stake to-night than you have ever done yet, and -that the play will be more exciting. For you, Mr. Merryweather, -the stake will be some 30,000 pounds; and for you, Jones, it will -be the man upon whom you wish to lay your hands." - -"John Clay, the murderer, thief, smasher, and forger. He's a -young man, Mr. Merryweather, but he is at the head of his -profession, and I would rather have my bracelets on him than on -any criminal in London. He's a remarkable man, is young John -Clay. His grandfather was a royal duke, and he himself has been -to Eton and Oxford. His brain is as cunning as his fingers, and -though we meet signs of him at every turn, we never know where to -find the man himself. He'll crack a crib in Scotland one week, -and be raising money to build an orphanage in Cornwall the next. -I've been on his track for years and have never set eyes on him -yet." - -"I hope that I may have the pleasure of introducing you to-night. -I've had one or two little turns also with Mr. John Clay, and I -agree with you that he is at the head of his profession. It is -past ten, however, and quite time that we started. If you two -will take the first hansom, Watson and I will follow in the -second." - -Sherlock Holmes was not very communicative during the long drive -and lay back in the cab humming the tunes which he had heard in -the afternoon. We rattled through an endless labyrinth of gas-lit -streets until we emerged into Farrington Street. - -"We are close there now," my friend remarked. "This fellow -Merryweather is a bank director, and personally interested in the -matter. I thought it as well to have Jones with us also. He is -not a bad fellow, though an absolute imbecile in his profession. -He has one positive virtue. He is as brave as a bulldog and as -tenacious as a lobster if he gets his claws upon anyone. Here we -are, and they are waiting for us." - -We had reached the same crowded thoroughfare in which we had -found ourselves in the morning. Our cabs were dismissed, and, -following the guidance of Mr. Merryweather, we passed down a -narrow passage and through a side door, which he opened for us. -Within there was a small corridor, which ended in a very massive -iron gate. This also was opened, and led down a flight of winding -stone steps, which terminated at another formidable gate. Mr. -Merryweather stopped to light a lantern, and then conducted us -down a dark, earth-smelling passage, and so, after opening a -third door, into a huge vault or cellar, which was piled all -round with crates and massive boxes. - -"You are not very vulnerable from above," Holmes remarked as he -held up the lantern and gazed about him. - -"Nor from below," said Mr. Merryweather, striking his stick upon -the flags which lined the floor. "Why, dear me, it sounds quite -hollow!" he remarked, looking up in surprise. - -"I must really ask you to be a little more quiet!" said Holmes -severely. "You have already imperilled the whole success of our -expedition. Might I beg that you would have the goodness to sit -down upon one of those boxes, and not to interfere?" - -The solemn Mr. Merryweather perched himself upon a crate, with a -very injured expression upon his face, while Holmes fell upon his -knees upon the floor and, with the lantern and a magnifying lens, -began to examine minutely the cracks between the stones. A few -seconds sufficed to satisfy him, for he sprang to his feet again -and put his glass in his pocket. - -"We have at least an hour before us," he remarked, "for they can -hardly take any steps until the good pawnbroker is safely in bed. -Then they will not lose a minute, for the sooner they do their -work the longer time they will have for their escape. We are at -present, Doctor--as no doubt you have divined--in the cellar of -the City branch of one of the principal London banks. Mr. -Merryweather is the chairman of directors, and he will explain to -you that there are reasons why the more daring criminals of -London should take a considerable interest in this cellar at -present." - -"It is our French gold," whispered the director. "We have had -several warnings that an attempt might be made upon it." - -"Your French gold?" - -"Yes. We had occasion some months ago to strengthen our resources -and borrowed for that purpose 30,000 napoleons from the Bank of -France. It has become known that we have never had occasion to -unpack the money, and that it is still lying in our cellar. The -crate upon which I sit contains 2,000 napoleons packed between -layers of lead foil. Our reserve of bullion is much larger at -present than is usually kept in a single branch office, and the -directors have had misgivings upon the subject." - -"Which were very well justified," observed Holmes. "And now it is -time that we arranged our little plans. I expect that within an -hour matters will come to a head. In the meantime Mr. -Merryweather, we must put the screen over that dark lantern." - -"And sit in the dark?" - -"I am afraid so. I had brought a pack of cards in my pocket, and -I thought that, as we were a partie carrée, you might have your -rubber after all. But I see that the enemy's preparations have -gone so far that we cannot risk the presence of a light. And, -first of all, we must choose our positions. These are daring men, -and though we shall take them at a disadvantage, they may do us -some harm unless we are careful. I shall stand behind this crate, -and do you conceal yourselves behind those. Then, when I flash a -light upon them, close in swiftly. If they fire, Watson, have no -compunction about shooting them down." - -I placed my revolver, cocked, upon the top of the wooden case -behind which I crouched. Holmes shot the slide across the front -of his lantern and left us in pitch darkness--such an absolute -darkness as I have never before experienced. The smell of hot -metal remained to assure us that the light was still there, ready -to flash out at a moment's notice. To me, with my nerves worked -up to a pitch of expectancy, there was something depressing and -subduing in the sudden gloom, and in the cold dank air of the -vault. - -"They have but one retreat," whispered Holmes. "That is back -through the house into Saxe-Coburg Square. I hope that you have -done what I asked you, Jones?" - -"I have an inspector and two officers waiting at the front door." - -"Then we have stopped all the holes. And now we must be silent -and wait." - -What a time it seemed! From comparing notes afterwards it was but -an hour and a quarter, yet it appeared to me that the night must -have almost gone and the dawn be breaking above us. My limbs -were weary and stiff, for I feared to change my position; yet my -nerves were worked up to the highest pitch of tension, and my -hearing was so acute that I could not only hear the gentle -breathing of my companions, but I could distinguish the deeper, -heavier in-breath of the bulky Jones from the thin, sighing note -of the bank director. From my position I could look over the case -in the direction of the floor. Suddenly my eyes caught the glint -of a light. - -At first it was but a lurid spark upon the stone pavement. Then -it lengthened out until it became a yellow line, and then, -without any warning or sound, a gash seemed to open and a hand -appeared, a white, almost womanly hand, which felt about in the -centre of the little area of light. For a minute or more the -hand, with its writhing fingers, protruded out of the floor. Then -it was withdrawn as suddenly as it appeared, and all was dark -again save the single lurid spark which marked a chink between -the stones. - -Its disappearance, however, was but momentary. With a rending, -tearing sound, one of the broad, white stones turned over upon -its side and left a square, gaping hole, through which streamed -the light of a lantern. Over the edge there peeped a clean-cut, -boyish face, which looked keenly about it, and then, with a hand -on either side of the aperture, drew itself shoulder-high and -waist-high, until one knee rested upon the edge. In another -instant he stood at the side of the hole and was hauling after -him a companion, lithe and small like himself, with a pale face -and a shock of very red hair. - -"It's all clear," he whispered. "Have you the chisel and the -bags? Great Scott! Jump, Archie, jump, and I'll swing for it!" - -Sherlock Holmes had sprung out and seized the intruder by the -collar. The other dived down the hole, and I heard the sound of -rending cloth as Jones clutched at his skirts. The light flashed -upon the barrel of a revolver, but Holmes' hunting crop came -down on the man's wrist, and the pistol clinked upon the stone -floor. - -"It's no use, John Clay," said Holmes blandly. "You have no -chance at all." - -"So I see," the other answered with the utmost coolness. "I fancy -that my pal is all right, though I see you have got his -coat-tails." - -"There are three men waiting for him at the door," said Holmes. - -"Oh, indeed! You seem to have done the thing very completely. I -must compliment you." - -"And I you," Holmes answered. "Your red-headed idea was very new -and effective." - -"You'll see your pal again presently," said Jones. "He's quicker -at climbing down holes than I am. Just hold out while I fix the -derbies." - -"I beg that you will not touch me with your filthy hands," -remarked our prisoner as the handcuffs clattered upon his wrists. -"You may not be aware that I have royal blood in my veins. Have -the goodness, also, when you address me always to say 'sir' and -'please.'" - -"All right," said Jones with a stare and a snigger. "Well, would -you please, sir, march upstairs, where we can get a cab to carry -your Highness to the police-station?" - -"That is better," said John Clay serenely. He made a sweeping bow -to the three of us and walked quietly off in the custody of the -detective. - -"Really, Mr. Holmes," said Mr. Merryweather as we followed them -from the cellar, "I do not know how the bank can thank you or -repay you. There is no doubt that you have detected and defeated -in the most complete manner one of the most determined attempts -at bank robbery that have ever come within my experience." - -"I have had one or two little scores of my own to settle with Mr. -John Clay," said Holmes. "I have been at some small expense over -this matter, which I shall expect the bank to refund, but beyond -that I am amply repaid by having had an experience which is in -many ways unique, and by hearing the very remarkable narrative of -the Red-headed League." - - -"You see, Watson," he explained in the early hours of the morning -as we sat over a glass of whisky and soda in Baker Street, "it -was perfectly obvious from the first that the only possible -object of this rather fantastic business of the advertisement of -the League, and the copying of the 'Encyclopaedia,' must be to get -this not over-bright pawnbroker out of the way for a number of -hours every day. It was a curious way of managing it, but, -really, it would be difficult to suggest a better. The method was -no doubt suggested to Clay's ingenious mind by the colour of his -accomplice's hair. The 4 pounds a week was a lure which must draw -him, and what was it to them, who were playing for thousands? -They put in the advertisement, one rogue has the temporary -office, the other rogue incites the man to apply for it, and -together they manage to secure his absence every morning in the -week. From the time that I heard of the assistant having come for -half wages, it was obvious to me that he had some strong motive -for securing the situation." - -"But how could you guess what the motive was?" - -"Had there been women in the house, I should have suspected a -mere vulgar intrigue. That, however, was out of the question. The -man's business was a small one, and there was nothing in his -house which could account for such elaborate preparations, and -such an expenditure as they were at. It must, then, be something -out of the house. What could it be? I thought of the assistant's -fondness for photography, and his trick of vanishing into the -cellar. The cellar! There was the end of this tangled clue. Then -I made inquiries as to this mysterious assistant and found that I -had to deal with one of the coolest and most daring criminals in -London. He was doing something in the cellar--something which -took many hours a day for months on end. What could it be, once -more? I could think of nothing save that he was running a tunnel -to some other building. - -"So far I had got when we went to visit the scene of action. I -surprised you by beating upon the pavement with my stick. I was -ascertaining whether the cellar stretched out in front or behind. -It was not in front. Then I rang the bell, and, as I hoped, the -assistant answered it. We have had some skirmishes, but we had -never set eyes upon each other before. I hardly looked at his -face. His knees were what I wished to see. You must yourself have -remarked how worn, wrinkled, and stained they were. They spoke of -those hours of burrowing. The only remaining point was what they -were burrowing for. I walked round the corner, saw the City and -Suburban Bank abutted on our friend's premises, and felt that I -had solved my problem. When you drove home after the concert I -called upon Scotland Yard and upon the chairman of the bank -directors, with the result that you have seen." - -"And how could you tell that they would make their attempt -to-night?" I asked. - -"Well, when they closed their League offices that was a sign that -they cared no longer about Mr. Jabez Wilson's presence--in other -words, that they had completed their tunnel. But it was essential -that they should use it soon, as it might be discovered, or the -bullion might be removed. Saturday would suit them better than -any other day, as it would give them two days for their escape. -For all these reasons I expected them to come to-night." - -"You reasoned it out beautifully," I exclaimed in unfeigned -admiration. "It is so long a chain, and yet every link rings -true." - -"It saved me from ennui," he answered, yawning. "Alas! I already -feel it closing in upon me. My life is spent in one long effort -to escape from the commonplaces of existence. These little -problems help me to do so." - -"And you are a benefactor of the race," said I. - -He shrugged his shoulders. "Well, perhaps, after all, it is of -some little use," he remarked. "'L'homme c'est rien--l'oeuvre -c'est tout,' as Gustave Flaubert wrote to George Sand." - - - -ADVENTURE III. A CASE OF IDENTITY - -"My dear fellow," said Sherlock Holmes as we sat on either side -of the fire in his lodgings at Baker Street, "life is infinitely -stranger than anything which the mind of man could invent. We -would not dare to conceive the things which are really mere -commonplaces of existence. If we could fly out of that window -hand in hand, hover over this great city, gently remove the -roofs, and peep in at the queer things which are going on, the -strange coincidences, the plannings, the cross-purposes, the -wonderful chains of events, working through generations, and -leading to the most outré results, it would make all fiction with -its conventionalities and foreseen conclusions most stale and -unprofitable." - -"And yet I am not convinced of it," I answered. "The cases which -come to light in the papers are, as a rule, bald enough, and -vulgar enough. We have in our police reports realism pushed to -its extreme limits, and yet the result is, it must be confessed, -neither fascinating nor artistic." - -"A certain selection and discretion must be used in producing a -realistic effect," remarked Holmes. "This is wanting in the -police report, where more stress is laid, perhaps, upon the -platitudes of the magistrate than upon the details, which to an -observer contain the vital essence of the whole matter. Depend -upon it, there is nothing so unnatural as the commonplace." - -I smiled and shook my head. "I can quite understand your thinking -so," I said. "Of course, in your position of unofficial adviser -and helper to everybody who is absolutely puzzled, throughout -three continents, you are brought in contact with all that is -strange and bizarre. But here"--I picked up the morning paper -from the ground--"let us put it to a practical test. Here is the -first heading upon which I come. 'A husband's cruelty to his -wife.' There is half a column of print, but I know without -reading it that it is all perfectly familiar to me. There is, of -course, the other woman, the drink, the push, the blow, the -bruise, the sympathetic sister or landlady. The crudest of -writers could invent nothing more crude." - -"Indeed, your example is an unfortunate one for your argument," -said Holmes, taking the paper and glancing his eye down it. "This -is the Dundas separation case, and, as it happens, I was engaged -in clearing up some small points in connection with it. The -husband was a teetotaler, there was no other woman, and the -conduct complained of was that he had drifted into the habit of -winding up every meal by taking out his false teeth and hurling -them at his wife, which, you will allow, is not an action likely -to occur to the imagination of the average story-teller. Take a -pinch of snuff, Doctor, and acknowledge that I have scored over -you in your example." - -He held out his snuffbox of old gold, with a great amethyst in -the centre of the lid. Its splendour was in such contrast to his -homely ways and simple life that I could not help commenting upon -it. - -"Ah," said he, "I forgot that I had not seen you for some weeks. -It is a little souvenir from the King of Bohemia in return for my -assistance in the case of the Irene Adler papers." - -"And the ring?" I asked, glancing at a remarkable brilliant which -sparkled upon his finger. - -"It was from the reigning family of Holland, though the matter in -which I served them was of such delicacy that I cannot confide it -even to you, who have been good enough to chronicle one or two of -my little problems." - -"And have you any on hand just now?" I asked with interest. - -"Some ten or twelve, but none which present any feature of -interest. They are important, you understand, without being -interesting. Indeed, I have found that it is usually in -unimportant matters that there is a field for the observation, -and for the quick analysis of cause and effect which gives the -charm to an investigation. The larger crimes are apt to be the -simpler, for the bigger the crime the more obvious, as a rule, is -the motive. In these cases, save for one rather intricate matter -which has been referred to me from Marseilles, there is nothing -which presents any features of interest. It is possible, however, -that I may have something better before very many minutes are -over, for this is one of my clients, or I am much mistaken." - -He had risen from his chair and was standing between the parted -blinds gazing down into the dull neutral-tinted London street. -Looking over his shoulder, I saw that on the pavement opposite -there stood a large woman with a heavy fur boa round her neck, -and a large curling red feather in a broad-brimmed hat which was -tilted in a coquettish Duchess of Devonshire fashion over her -ear. From under this great panoply she peeped up in a nervous, -hesitating fashion at our windows, while her body oscillated -backward and forward, and her fingers fidgeted with her glove -buttons. Suddenly, with a plunge, as of the swimmer who leaves -the bank, she hurried across the road, and we heard the sharp -clang of the bell. - -"I have seen those symptoms before," said Holmes, throwing his -cigarette into the fire. "Oscillation upon the pavement always -means an affaire de coeur. She would like advice, but is not sure -that the matter is not too delicate for communication. And yet -even here we may discriminate. When a woman has been seriously -wronged by a man she no longer oscillates, and the usual symptom -is a broken bell wire. Here we may take it that there is a love -matter, but that the maiden is not so much angry as perplexed, or -grieved. But here she comes in person to resolve our doubts." - -As he spoke there was a tap at the door, and the boy in buttons -entered to announce Miss Mary Sutherland, while the lady herself -loomed behind his small black figure like a full-sailed -merchant-man behind a tiny pilot boat. Sherlock Holmes welcomed -her with the easy courtesy for which he was remarkable, and, -having closed the door and bowed her into an armchair, he looked -her over in the minute and yet abstracted fashion which was -peculiar to him. - -"Do you not find," he said, "that with your short sight it is a -little trying to do so much typewriting?" - -"I did at first," she answered, "but now I know where the letters -are without looking." Then, suddenly realising the full purport -of his words, she gave a violent start and looked up, with fear -and astonishment upon her broad, good-humoured face. "You've -heard about me, Mr. Holmes," she cried, "else how could you know -all that?" - -"Never mind," said Holmes, laughing; "it is my business to know -things. Perhaps I have trained myself to see what others -overlook. If not, why should you come to consult me?" - -"I came to you, sir, because I heard of you from Mrs. Etherege, -whose husband you found so easy when the police and everyone had -given him up for dead. Oh, Mr. Holmes, I wish you would do as -much for me. I'm not rich, but still I have a hundred a year in -my own right, besides the little that I make by the machine, and -I would give it all to know what has become of Mr. Hosmer Angel." - -"Why did you come away to consult me in such a hurry?" asked -Sherlock Holmes, with his finger-tips together and his eyes to -the ceiling. - -Again a startled look came over the somewhat vacuous face of Miss -Mary Sutherland. "Yes, I did bang out of the house," she said, -"for it made me angry to see the easy way in which Mr. -Windibank--that is, my father--took it all. He would not go to -the police, and he would not go to you, and so at last, as he -would do nothing and kept on saying that there was no harm done, -it made me mad, and I just on with my things and came right away -to you." - -"Your father," said Holmes, "your stepfather, surely, since the -name is different." - -"Yes, my stepfather. I call him father, though it sounds funny, -too, for he is only five years and two months older than myself." - -"And your mother is alive?" - -"Oh, yes, mother is alive and well. I wasn't best pleased, Mr. -Holmes, when she married again so soon after father's death, and -a man who was nearly fifteen years younger than herself. Father -was a plumber in the Tottenham Court Road, and he left a tidy -business behind him, which mother carried on with Mr. Hardy, the -foreman; but when Mr. Windibank came he made her sell the -business, for he was very superior, being a traveller in wines. -They got 4700 pounds for the goodwill and interest, which wasn't -near as much as father could have got if he had been alive." - -I had expected to see Sherlock Holmes impatient under this -rambling and inconsequential narrative, but, on the contrary, he -had listened with the greatest concentration of attention. - -"Your own little income," he asked, "does it come out of the -business?" - -"Oh, no, sir. It is quite separate and was left me by my uncle -Ned in Auckland. It is in New Zealand stock, paying 4 1/2 per -cent. Two thousand five hundred pounds was the amount, but I can -only touch the interest." - -"You interest me extremely," said Holmes. "And since you draw so -large a sum as a hundred a year, with what you earn into the -bargain, you no doubt travel a little and indulge yourself in -every way. I believe that a single lady can get on very nicely -upon an income of about 60 pounds." - -"I could do with much less than that, Mr. Holmes, but you -understand that as long as I live at home I don't wish to be a -burden to them, and so they have the use of the money just while -I am staying with them. Of course, that is only just for the -time. Mr. Windibank draws my interest every quarter and pays it -over to mother, and I find that I can do pretty well with what I -earn at typewriting. It brings me twopence a sheet, and I can -often do from fifteen to twenty sheets in a day." - -"You have made your position very clear to me," said Holmes. -"This is my friend, Dr. Watson, before whom you can speak as -freely as before myself. Kindly tell us now all about your -connection with Mr. Hosmer Angel." - -A flush stole over Miss Sutherland's face, and she picked -nervously at the fringe of her jacket. "I met him first at the -gasfitters' ball," she said. "They used to send father tickets -when he was alive, and then afterwards they remembered us, and -sent them to mother. Mr. Windibank did not wish us to go. He -never did wish us to go anywhere. He would get quite mad if I -wanted so much as to join a Sunday-school treat. But this time I -was set on going, and I would go; for what right had he to -prevent? He said the folk were not fit for us to know, when all -father's friends were to be there. And he said that I had nothing -fit to wear, when I had my purple plush that I had never so much -as taken out of the drawer. At last, when nothing else would do, -he went off to France upon the business of the firm, but we went, -mother and I, with Mr. Hardy, who used to be our foreman, and it -was there I met Mr. Hosmer Angel." - -"I suppose," said Holmes, "that when Mr. Windibank came back from -France he was very annoyed at your having gone to the ball." - -"Oh, well, he was very good about it. He laughed, I remember, and -shrugged his shoulders, and said there was no use denying -anything to a woman, for she would have her way." - -"I see. Then at the gasfitters' ball you met, as I understand, a -gentleman called Mr. Hosmer Angel." - -"Yes, sir. I met him that night, and he called next day to ask if -we had got home all safe, and after that we met him--that is to -say, Mr. Holmes, I met him twice for walks, but after that father -came back again, and Mr. Hosmer Angel could not come to the house -any more." - -"No?" - -"Well, you know father didn't like anything of the sort. He -wouldn't have any visitors if he could help it, and he used to -say that a woman should be happy in her own family circle. But -then, as I used to say to mother, a woman wants her own circle to -begin with, and I had not got mine yet." - -"But how about Mr. Hosmer Angel? Did he make no attempt to see -you?" - -"Well, father was going off to France again in a week, and Hosmer -wrote and said that it would be safer and better not to see each -other until he had gone. We could write in the meantime, and he -used to write every day. I took the letters in in the morning, so -there was no need for father to know." - -"Were you engaged to the gentleman at this time?" - -"Oh, yes, Mr. Holmes. We were engaged after the first walk that -we took. Hosmer--Mr. Angel--was a cashier in an office in -Leadenhall Street--and--" - -"What office?" - -"That's the worst of it, Mr. Holmes, I don't know." - -"Where did he live, then?" - -"He slept on the premises." - -"And you don't know his address?" - -"No--except that it was Leadenhall Street." - -"Where did you address your letters, then?" - -"To the Leadenhall Street Post Office, to be left till called -for. He said that if they were sent to the office he would be -chaffed by all the other clerks about having letters from a lady, -so I offered to typewrite them, like he did his, but he wouldn't -have that, for he said that when I wrote them they seemed to come -from me, but when they were typewritten he always felt that the -machine had come between us. That will just show you how fond he -was of me, Mr. Holmes, and the little things that he would think -of." - -"It was most suggestive," said Holmes. "It has long been an axiom -of mine that the little things are infinitely the most important. -Can you remember any other little things about Mr. Hosmer Angel?" - -"He was a very shy man, Mr. Holmes. He would rather walk with me -in the evening than in the daylight, for he said that he hated to -be conspicuous. Very retiring and gentlemanly he was. Even his -voice was gentle. He'd had the quinsy and swollen glands when he -was young, he told me, and it had left him with a weak throat, -and a hesitating, whispering fashion of speech. He was always -well dressed, very neat and plain, but his eyes were weak, just -as mine are, and he wore tinted glasses against the glare." - -"Well, and what happened when Mr. Windibank, your stepfather, -returned to France?" - -"Mr. Hosmer Angel came to the house again and proposed that we -should marry before father came back. He was in dreadful earnest -and made me swear, with my hands on the Testament, that whatever -happened I would always be true to him. Mother said he was quite -right to make me swear, and that it was a sign of his passion. -Mother was all in his favour from the first and was even fonder -of him than I was. Then, when they talked of marrying within the -week, I began to ask about father; but they both said never to -mind about father, but just to tell him afterwards, and mother -said she would make it all right with him. I didn't quite like -that, Mr. Holmes. It seemed funny that I should ask his leave, as -he was only a few years older than me; but I didn't want to do -anything on the sly, so I wrote to father at Bordeaux, where the -company has its French offices, but the letter came back to me on -the very morning of the wedding." - -"It missed him, then?" - -"Yes, sir; for he had started to England just before it arrived." - -"Ha! that was unfortunate. Your wedding was arranged, then, for -the Friday. Was it to be in church?" - -"Yes, sir, but very quietly. It was to be at St. Saviour's, near -King's Cross, and we were to have breakfast afterwards at the St. -Pancras Hotel. Hosmer came for us in a hansom, but as there were -two of us he put us both into it and stepped himself into a -four-wheeler, which happened to be the only other cab in the -street. We got to the church first, and when the four-wheeler -drove up we waited for him to step out, but he never did, and -when the cabman got down from the box and looked there was no one -there! The cabman said that he could not imagine what had become -of him, for he had seen him get in with his own eyes. That was -last Friday, Mr. Holmes, and I have never seen or heard anything -since then to throw any light upon what became of him." - -"It seems to me that you have been very shamefully treated," said -Holmes. - -"Oh, no, sir! He was too good and kind to leave me so. Why, all -the morning he was saying to me that, whatever happened, I was to -be true; and that even if something quite unforeseen occurred to -separate us, I was always to remember that I was pledged to him, -and that he would claim his pledge sooner or later. It seemed -strange talk for a wedding-morning, but what has happened since -gives a meaning to it." - -"Most certainly it does. Your own opinion is, then, that some -unforeseen catastrophe has occurred to him?" - -"Yes, sir. I believe that he foresaw some danger, or else he -would not have talked so. And then I think that what he foresaw -happened." - -"But you have no notion as to what it could have been?" - -"None." - -"One more question. How did your mother take the matter?" - -"She was angry, and said that I was never to speak of the matter -again." - -"And your father? Did you tell him?" - -"Yes; and he seemed to think, with me, that something had -happened, and that I should hear of Hosmer again. As he said, -what interest could anyone have in bringing me to the doors of -the church, and then leaving me? Now, if he had borrowed my -money, or if he had married me and got my money settled on him, -there might be some reason, but Hosmer was very independent about -money and never would look at a shilling of mine. And yet, what -could have happened? And why could he not write? Oh, it drives me -half-mad to think of it, and I can't sleep a wink at night." She -pulled a little handkerchief out of her muff and began to sob -heavily into it. - -"I shall glance into the case for you," said Holmes, rising, "and -I have no doubt that we shall reach some definite result. Let the -weight of the matter rest upon me now, and do not let your mind -dwell upon it further. Above all, try to let Mr. Hosmer Angel -vanish from your memory, as he has done from your life." - -"Then you don't think I'll see him again?" - -"I fear not." - -"Then what has happened to him?" - -"You will leave that question in my hands. I should like an -accurate description of him and any letters of his which you can -spare." - -"I advertised for him in last Saturday's Chronicle," said she. -"Here is the slip and here are four letters from him." - -"Thank you. And your address?" - -"No. 31 Lyon Place, Camberwell." - -"Mr. Angel's address you never had, I understand. Where is your -father's place of business?" - -"He travels for Westhouse & Marbank, the great claret importers -of Fenchurch Street." - -"Thank you. You have made your statement very clearly. You will -leave the papers here, and remember the advice which I have given -you. Let the whole incident be a sealed book, and do not allow it -to affect your life." - -"You are very kind, Mr. Holmes, but I cannot do that. I shall be -true to Hosmer. He shall find me ready when he comes back." - -For all the preposterous hat and the vacuous face, there was -something noble in the simple faith of our visitor which -compelled our respect. She laid her little bundle of papers upon -the table and went her way, with a promise to come again whenever -she might be summoned. - -Sherlock Holmes sat silent for a few minutes with his fingertips -still pressed together, his legs stretched out in front of him, -and his gaze directed upward to the ceiling. Then he took down -from the rack the old and oily clay pipe, which was to him as a -counsellor, and, having lit it, he leaned back in his chair, with -the thick blue cloud-wreaths spinning up from him, and a look of -infinite languor in his face. - -"Quite an interesting study, that maiden," he observed. "I found -her more interesting than her little problem, which, by the way, -is rather a trite one. You will find parallel cases, if you -consult my index, in Andover in '77, and there was something of -the sort at The Hague last year. Old as is the idea, however, -there were one or two details which were new to me. But the -maiden herself was most instructive." - -"You appeared to read a good deal upon her which was quite -invisible to me," I remarked. - -"Not invisible but unnoticed, Watson. You did not know where to -look, and so you missed all that was important. I can never bring -you to realise the importance of sleeves, the suggestiveness of -thumb-nails, or the great issues that may hang from a boot-lace. -Now, what did you gather from that woman's appearance? Describe -it." - -"Well, she had a slate-coloured, broad-brimmed straw hat, with a -feather of a brickish red. Her jacket was black, with black beads -sewn upon it, and a fringe of little black jet ornaments. Her -dress was brown, rather darker than coffee colour, with a little -purple plush at the neck and sleeves. Her gloves were greyish and -were worn through at the right forefinger. Her boots I didn't -observe. She had small round, hanging gold earrings, and a -general air of being fairly well-to-do in a vulgar, comfortable, -easy-going way." - -Sherlock Holmes clapped his hands softly together and chuckled. - -"'Pon my word, Watson, you are coming along wonderfully. You have -really done very well indeed. It is true that you have missed -everything of importance, but you have hit upon the method, and -you have a quick eye for colour. Never trust to general -impressions, my boy, but concentrate yourself upon details. My -first glance is always at a woman's sleeve. In a man it is -perhaps better first to take the knee of the trouser. As you -observe, this woman had plush upon her sleeves, which is a most -useful material for showing traces. The double line a little -above the wrist, where the typewritist presses against the table, -was beautifully defined. The sewing-machine, of the hand type, -leaves a similar mark, but only on the left arm, and on the side -of it farthest from the thumb, instead of being right across the -broadest part, as this was. I then glanced at her face, and, -observing the dint of a pince-nez at either side of her nose, I -ventured a remark upon short sight and typewriting, which seemed -to surprise her." - -"It surprised me." - -"But, surely, it was obvious. I was then much surprised and -interested on glancing down to observe that, though the boots -which she was wearing were not unlike each other, they were -really odd ones; the one having a slightly decorated toe-cap, and -the other a plain one. One was buttoned only in the two lower -buttons out of five, and the other at the first, third, and -fifth. Now, when you see that a young lady, otherwise neatly -dressed, has come away from home with odd boots, half-buttoned, -it is no great deduction to say that she came away in a hurry." - -"And what else?" I asked, keenly interested, as I always was, by -my friend's incisive reasoning. - -"I noted, in passing, that she had written a note before leaving -home but after being fully dressed. You observed that her right -glove was torn at the forefinger, but you did not apparently see -that both glove and finger were stained with violet ink. She had -written in a hurry and dipped her pen too deep. It must have been -this morning, or the mark would not remain clear upon the finger. -All this is amusing, though rather elementary, but I must go back -to business, Watson. Would you mind reading me the advertised -description of Mr. Hosmer Angel?" - -I held the little printed slip to the light. - -"Missing," it said, "on the morning of the fourteenth, a gentleman -named Hosmer Angel. About five ft. seven in. in height; -strongly built, sallow complexion, black hair, a little bald in -the centre, bushy, black side-whiskers and moustache; tinted -glasses, slight infirmity of speech. Was dressed, when last seen, -in black frock-coat faced with silk, black waistcoat, gold Albert -chain, and grey Harris tweed trousers, with brown gaiters over -elastic-sided boots. Known to have been employed in an office in -Leadenhall Street. Anybody bringing--" - -"That will do," said Holmes. "As to the letters," he continued, -glancing over them, "they are very commonplace. Absolutely no -clue in them to Mr. Angel, save that he quotes Balzac once. There -is one remarkable point, however, which will no doubt strike -you." - -"They are typewritten," I remarked. - -"Not only that, but the signature is typewritten. Look at the -neat little 'Hosmer Angel' at the bottom. There is a date, you -see, but no superscription except Leadenhall Street, which is -rather vague. The point about the signature is very suggestive--in -fact, we may call it conclusive." - -"Of what?" - -"My dear fellow, is it possible you do not see how strongly it -bears upon the case?" - -"I cannot say that I do unless it were that he wished to be able -to deny his signature if an action for breach of promise were -instituted." - -"No, that was not the point. However, I shall write two letters, -which should settle the matter. One is to a firm in the City, the -other is to the young lady's stepfather, Mr. Windibank, asking -him whether he could meet us here at six o'clock tomorrow -evening. It is just as well that we should do business with the -male relatives. And now, Doctor, we can do nothing until the -answers to those letters come, so we may put our little problem -upon the shelf for the interim." - -I had had so many reasons to believe in my friend's subtle powers -of reasoning and extraordinary energy in action that I felt that -he must have some solid grounds for the assured and easy -demeanour with which he treated the singular mystery which he had -been called upon to fathom. Once only had I known him to fail, in -the case of the King of Bohemia and of the Irene Adler -photograph; but when I looked back to the weird business of the -Sign of Four, and the extraordinary circumstances connected with -the Study in Scarlet, I felt that it would be a strange tangle -indeed which he could not unravel. - -I left him then, still puffing at his black clay pipe, with the -conviction that when I came again on the next evening I would -find that he held in his hands all the clues which would lead up -to the identity of the disappearing bridegroom of Miss Mary -Sutherland. - -A professional case of great gravity was engaging my own -attention at the time, and the whole of next day I was busy at -the bedside of the sufferer. It was not until close upon six -o'clock that I found myself free and was able to spring into a -hansom and drive to Baker Street, half afraid that I might be too -late to assist at the dénouement of the little mystery. I found -Sherlock Holmes alone, however, half asleep, with his long, thin -form curled up in the recesses of his armchair. A formidable -array of bottles and test-tubes, with the pungent cleanly smell -of hydrochloric acid, told me that he had spent his day in the -chemical work which was so dear to him. - -"Well, have you solved it?" I asked as I entered. - -"Yes. It was the bisulphate of baryta." - -"No, no, the mystery!" I cried. - -"Oh, that! I thought of the salt that I have been working upon. -There was never any mystery in the matter, though, as I said -yesterday, some of the details are of interest. The only drawback -is that there is no law, I fear, that can touch the scoundrel." - -"Who was he, then, and what was his object in deserting Miss -Sutherland?" - -The question was hardly out of my mouth, and Holmes had not yet -opened his lips to reply, when we heard a heavy footfall in the -passage and a tap at the door. - -"This is the girl's stepfather, Mr. James Windibank," said -Holmes. "He has written to me to say that he would be here at -six. Come in!" - -The man who entered was a sturdy, middle-sized fellow, some -thirty years of age, clean-shaven, and sallow-skinned, with a -bland, insinuating manner, and a pair of wonderfully sharp and -penetrating grey eyes. He shot a questioning glance at each of -us, placed his shiny top-hat upon the sideboard, and with a -slight bow sidled down into the nearest chair. - -"Good-evening, Mr. James Windibank," said Holmes. "I think that -this typewritten letter is from you, in which you made an -appointment with me for six o'clock?" - -"Yes, sir. I am afraid that I am a little late, but I am not -quite my own master, you know. I am sorry that Miss Sutherland -has troubled you about this little matter, for I think it is far -better not to wash linen of the sort in public. It was quite -against my wishes that she came, but she is a very excitable, -impulsive girl, as you may have noticed, and she is not easily -controlled when she has made up her mind on a point. Of course, I -did not mind you so much, as you are not connected with the -official police, but it is not pleasant to have a family -misfortune like this noised abroad. Besides, it is a useless -expense, for how could you possibly find this Hosmer Angel?" - -"On the contrary," said Holmes quietly; "I have every reason to -believe that I will succeed in discovering Mr. Hosmer Angel." - -Mr. Windibank gave a violent start and dropped his gloves. "I am -delighted to hear it," he said. - -"It is a curious thing," remarked Holmes, "that a typewriter has -really quite as much individuality as a man's handwriting. Unless -they are quite new, no two of them write exactly alike. Some -letters get more worn than others, and some wear only on one -side. Now, you remark in this note of yours, Mr. Windibank, that -in every case there is some little slurring over of the 'e,' and -a slight defect in the tail of the 'r.' There are fourteen other -characteristics, but those are the more obvious." - -"We do all our correspondence with this machine at the office, -and no doubt it is a little worn," our visitor answered, glancing -keenly at Holmes with his bright little eyes. - -"And now I will show you what is really a very interesting study, -Mr. Windibank," Holmes continued. "I think of writing another -little monograph some of these days on the typewriter and its -relation to crime. It is a subject to which I have devoted some -little attention. I have here four letters which purport to come -from the missing man. They are all typewritten. In each case, not -only are the 'e's' slurred and the 'r's' tailless, but you will -observe, if you care to use my magnifying lens, that the fourteen -other characteristics to which I have alluded are there as well." - -Mr. Windibank sprang out of his chair and picked up his hat. "I -cannot waste time over this sort of fantastic talk, Mr. Holmes," -he said. "If you can catch the man, catch him, and let me know -when you have done it." - -"Certainly," said Holmes, stepping over and turning the key in -the door. "I let you know, then, that I have caught him!" - -"What! where?" shouted Mr. Windibank, turning white to his lips -and glancing about him like a rat in a trap. - -"Oh, it won't do--really it won't," said Holmes suavely. "There -is no possible getting out of it, Mr. Windibank. It is quite too -transparent, and it was a very bad compliment when you said that -it was impossible for me to solve so simple a question. That's -right! Sit down and let us talk it over." - -Our visitor collapsed into a chair, with a ghastly face and a -glitter of moisture on his brow. "It--it's not actionable," he -stammered. - -"I am very much afraid that it is not. But between ourselves, -Windibank, it was as cruel and selfish and heartless a trick in a -petty way as ever came before me. Now, let me just run over the -course of events, and you will contradict me if I go wrong." - -The man sat huddled up in his chair, with his head sunk upon his -breast, like one who is utterly crushed. Holmes stuck his feet up -on the corner of the mantelpiece and, leaning back with his hands -in his pockets, began talking, rather to himself, as it seemed, -than to us. - -"The man married a woman very much older than himself for her -money," said he, "and he enjoyed the use of the money of the -daughter as long as she lived with them. It was a considerable -sum, for people in their position, and the loss of it would have -made a serious difference. It was worth an effort to preserve it. -The daughter was of a good, amiable disposition, but affectionate -and warm-hearted in her ways, so that it was evident that with -her fair personal advantages, and her little income, she would -not be allowed to remain single long. Now her marriage would -mean, of course, the loss of a hundred a year, so what does her -stepfather do to prevent it? He takes the obvious course of -keeping her at home and forbidding her to seek the company of -people of her own age. But soon he found that that would not -answer forever. She became restive, insisted upon her rights, and -finally announced her positive intention of going to a certain -ball. What does her clever stepfather do then? He conceives an -idea more creditable to his head than to his heart. With the -connivance and assistance of his wife he disguised himself, -covered those keen eyes with tinted glasses, masked the face with -a moustache and a pair of bushy whiskers, sunk that clear voice -into an insinuating whisper, and doubly secure on account of the -girl's short sight, he appears as Mr. Hosmer Angel, and keeps off -other lovers by making love himself." - -"It was only a joke at first," groaned our visitor. "We never -thought that she would have been so carried away." - -"Very likely not. However that may be, the young lady was very -decidedly carried away, and, having quite made up her mind that -her stepfather was in France, the suspicion of treachery never -for an instant entered her mind. She was flattered by the -gentleman's attentions, and the effect was increased by the -loudly expressed admiration of her mother. Then Mr. Angel began -to call, for it was obvious that the matter should be pushed as -far as it would go if a real effect were to be produced. There -were meetings, and an engagement, which would finally secure the -girl's affections from turning towards anyone else. But the -deception could not be kept up forever. These pretended journeys -to France were rather cumbrous. The thing to do was clearly to -bring the business to an end in such a dramatic manner that it -would leave a permanent impression upon the young lady's mind and -prevent her from looking upon any other suitor for some time to -come. Hence those vows of fidelity exacted upon a Testament, and -hence also the allusions to a possibility of something happening -on the very morning of the wedding. James Windibank wished Miss -Sutherland to be so bound to Hosmer Angel, and so uncertain as to -his fate, that for ten years to come, at any rate, she would not -listen to another man. As far as the church door he brought her, -and then, as he could go no farther, he conveniently vanished -away by the old trick of stepping in at one door of a -four-wheeler and out at the other. I think that was the chain of -events, Mr. Windibank!" - -Our visitor had recovered something of his assurance while Holmes -had been talking, and he rose from his chair now with a cold -sneer upon his pale face. - -"It may be so, or it may not, Mr. Holmes," said he, "but if you -are so very sharp you ought to be sharp enough to know that it is -you who are breaking the law now, and not me. I have done nothing -actionable from the first, but as long as you keep that door -locked you lay yourself open to an action for assault and illegal -constraint." - -"The law cannot, as you say, touch you," said Holmes, unlocking -and throwing open the door, "yet there never was a man who -deserved punishment more. If the young lady has a brother or a -friend, he ought to lay a whip across your shoulders. By Jove!" -he continued, flushing up at the sight of the bitter sneer upon -the man's face, "it is not part of my duties to my client, but -here's a hunting crop handy, and I think I shall just treat -myself to--" He took two swift steps to the whip, but before he -could grasp it there was a wild clatter of steps upon the stairs, -the heavy hall door banged, and from the window we could see Mr. -James Windibank running at the top of his speed down the road. - -"There's a cold-blooded scoundrel!" said Holmes, laughing, as he -threw himself down into his chair once more. "That fellow will -rise from crime to crime until he does something very bad, and -ends on a gallows. The case has, in some respects, been not -entirely devoid of interest." - -"I cannot now entirely see all the steps of your reasoning," I -remarked. - -"Well, of course it was obvious from the first that this Mr. -Hosmer Angel must have some strong object for his curious -conduct, and it was equally clear that the only man who really -profited by the incident, as far as we could see, was the -stepfather. Then the fact that the two men were never together, -but that the one always appeared when the other was away, was -suggestive. So were the tinted spectacles and the curious voice, -which both hinted at a disguise, as did the bushy whiskers. My -suspicions were all confirmed by his peculiar action in -typewriting his signature, which, of course, inferred that his -handwriting was so familiar to her that she would recognise even -the smallest sample of it. You see all these isolated facts, -together with many minor ones, all pointed in the same -direction." - -"And how did you verify them?" - -"Having once spotted my man, it was easy to get corroboration. I -knew the firm for which this man worked. Having taken the printed -description. I eliminated everything from it which could be the -result of a disguise--the whiskers, the glasses, the voice, and I -sent it to the firm, with a request that they would inform me -whether it answered to the description of any of their -travellers. I had already noticed the peculiarities of the -typewriter, and I wrote to the man himself at his business -address asking him if he would come here. As I expected, his -reply was typewritten and revealed the same trivial but -characteristic defects. The same post brought me a letter from -Westhouse & Marbank, of Fenchurch Street, to say that the -description tallied in every respect with that of their employé, -James Windibank. Voilà tout!" - -"And Miss Sutherland?" - -"If I tell her she will not believe me. You may remember the old -Persian saying, 'There is danger for him who taketh the tiger -cub, and danger also for whoso snatches a delusion from a woman.' -There is as much sense in Hafiz as in Horace, and as much -knowledge of the world." - - - -ADVENTURE IV. THE BOSCOMBE VALLEY MYSTERY - -We were seated at breakfast one morning, my wife and I, when the -maid brought in a telegram. It was from Sherlock Holmes and ran -in this way: - -"Have you a couple of days to spare? Have just been wired for from -the west of England in connection with Boscombe Valley tragedy. -Shall be glad if you will come with me. Air and scenery perfect. -Leave Paddington by the 11:15." - -"What do you say, dear?" said my wife, looking across at me. -"Will you go?" - -"I really don't know what to say. I have a fairly long list at -present." - -"Oh, Anstruther would do your work for you. You have been looking -a little pale lately. I think that the change would do you good, -and you are always so interested in Mr. Sherlock Holmes' cases." - -"I should be ungrateful if I were not, seeing what I gained -through one of them," I answered. "But if I am to go, I must pack -at once, for I have only half an hour." - -My experience of camp life in Afghanistan had at least had the -effect of making me a prompt and ready traveller. My wants were -few and simple, so that in less than the time stated I was in a -cab with my valise, rattling away to Paddington Station. Sherlock -Holmes was pacing up and down the platform, his tall, gaunt -figure made even gaunter and taller by his long grey -travelling-cloak and close-fitting cloth cap. - -"It is really very good of you to come, Watson," said he. "It -makes a considerable difference to me, having someone with me on -whom I can thoroughly rely. Local aid is always either worthless -or else biassed. If you will keep the two corner seats I shall -get the tickets." - -We had the carriage to ourselves save for an immense litter of -papers which Holmes had brought with him. Among these he rummaged -and read, with intervals of note-taking and of meditation, until -we were past Reading. Then he suddenly rolled them all into a -gigantic ball and tossed them up onto the rack. - -"Have you heard anything of the case?" he asked. - -"Not a word. I have not seen a paper for some days." - -"The London press has not had very full accounts. I have just -been looking through all the recent papers in order to master the -particulars. It seems, from what I gather, to be one of those -simple cases which are so extremely difficult." - -"That sounds a little paradoxical." - -"But it is profoundly true. Singularity is almost invariably a -clue. The more featureless and commonplace a crime is, the more -difficult it is to bring it home. In this case, however, they -have established a very serious case against the son of the -murdered man." - -"It is a murder, then?" - -"Well, it is conjectured to be so. I shall take nothing for -granted until I have the opportunity of looking personally into -it. I will explain the state of things to you, as far as I have -been able to understand it, in a very few words. - -"Boscombe Valley is a country district not very far from Ross, in -Herefordshire. The largest landed proprietor in that part is a -Mr. John Turner, who made his money in Australia and returned -some years ago to the old country. One of the farms which he -held, that of Hatherley, was let to Mr. Charles McCarthy, who was -also an ex-Australian. The men had known each other in the -colonies, so that it was not unnatural that when they came to -settle down they should do so as near each other as possible. -Turner was apparently the richer man, so McCarthy became his -tenant but still remained, it seems, upon terms of perfect -equality, as they were frequently together. McCarthy had one son, -a lad of eighteen, and Turner had an only daughter of the same -age, but neither of them had wives living. They appear to have -avoided the society of the neighbouring English families and to -have led retired lives, though both the McCarthys were fond of -sport and were frequently seen at the race-meetings of the -neighbourhood. McCarthy kept two servants--a man and a girl. -Turner had a considerable household, some half-dozen at the -least. That is as much as I have been able to gather about the -families. Now for the facts. - -"On June 3rd, that is, on Monday last, McCarthy left his house at -Hatherley about three in the afternoon and walked down to the -Boscombe Pool, which is a small lake formed by the spreading out -of the stream which runs down the Boscombe Valley. He had been -out with his serving-man in the morning at Ross, and he had told -the man that he must hurry, as he had an appointment of -importance to keep at three. From that appointment he never came -back alive. - -"From Hatherley Farm-house to the Boscombe Pool is a quarter of a -mile, and two people saw him as he passed over this ground. One -was an old woman, whose name is not mentioned, and the other was -William Crowder, a game-keeper in the employ of Mr. Turner. Both -these witnesses depose that Mr. McCarthy was walking alone. The -game-keeper adds that within a few minutes of his seeing Mr. -McCarthy pass he had seen his son, Mr. James McCarthy, going the -same way with a gun under his arm. To the best of his belief, the -father was actually in sight at the time, and the son was -following him. He thought no more of the matter until he heard in -the evening of the tragedy that had occurred. - -"The two McCarthys were seen after the time when William Crowder, -the game-keeper, lost sight of them. The Boscombe Pool is thickly -wooded round, with just a fringe of grass and of reeds round the -edge. A girl of fourteen, Patience Moran, who is the daughter of -the lodge-keeper of the Boscombe Valley estate, was in one of the -woods picking flowers. She states that while she was there she -saw, at the border of the wood and close by the lake, Mr. -McCarthy and his son, and that they appeared to be having a -violent quarrel. She heard Mr. McCarthy the elder using very -strong language to his son, and she saw the latter raise up his -hand as if to strike his father. She was so frightened by their -violence that she ran away and told her mother when she reached -home that she had left the two McCarthys quarrelling near -Boscombe Pool, and that she was afraid that they were going to -fight. She had hardly said the words when young Mr. McCarthy came -running up to the lodge to say that he had found his father dead -in the wood, and to ask for the help of the lodge-keeper. He was -much excited, without either his gun or his hat, and his right -hand and sleeve were observed to be stained with fresh blood. On -following him they found the dead body stretched out upon the -grass beside the pool. The head had been beaten in by repeated -blows of some heavy and blunt weapon. The injuries were such as -might very well have been inflicted by the butt-end of his son's -gun, which was found lying on the grass within a few paces of the -body. Under these circumstances the young man was instantly -arrested, and a verdict of 'wilful murder' having been returned -at the inquest on Tuesday, he was on Wednesday brought before the -magistrates at Ross, who have referred the case to the next -Assizes. Those are the main facts of the case as they came out -before the coroner and the police-court." - -"I could hardly imagine a more damning case," I remarked. "If -ever circumstantial evidence pointed to a criminal it does so -here." - -"Circumstantial evidence is a very tricky thing," answered Holmes -thoughtfully. "It may seem to point very straight to one thing, -but if you shift your own point of view a little, you may find it -pointing in an equally uncompromising manner to something -entirely different. It must be confessed, however, that the case -looks exceedingly grave against the young man, and it is very -possible that he is indeed the culprit. There are several people -in the neighbourhood, however, and among them Miss Turner, the -daughter of the neighbouring landowner, who believe in his -innocence, and who have retained Lestrade, whom you may recollect -in connection with the Study in Scarlet, to work out the case in -his interest. Lestrade, being rather puzzled, has referred the -case to me, and hence it is that two middle-aged gentlemen are -flying westward at fifty miles an hour instead of quietly -digesting their breakfasts at home." - -"I am afraid," said I, "that the facts are so obvious that you -will find little credit to be gained out of this case." - -"There is nothing more deceptive than an obvious fact," he -answered, laughing. "Besides, we may chance to hit upon some -other obvious facts which may have been by no means obvious to -Mr. Lestrade. You know me too well to think that I am boasting -when I say that I shall either confirm or destroy his theory by -means which he is quite incapable of employing, or even of -understanding. To take the first example to hand, I very clearly -perceive that in your bedroom the window is upon the right-hand -side, and yet I question whether Mr. Lestrade would have noted -even so self-evident a thing as that." - -"How on earth--" - -"My dear fellow, I know you well. I know the military neatness -which characterises you. You shave every morning, and in this -season you shave by the sunlight; but since your shaving is less -and less complete as we get farther back on the left side, until -it becomes positively slovenly as we get round the angle of the -jaw, it is surely very clear that that side is less illuminated -than the other. I could not imagine a man of your habits looking -at himself in an equal light and being satisfied with such a -result. I only quote this as a trivial example of observation and -inference. Therein lies my métier, and it is just possible that -it may be of some service in the investigation which lies before -us. There are one or two minor points which were brought out in -the inquest, and which are worth considering." - -"What are they?" - -"It appears that his arrest did not take place at once, but after -the return to Hatherley Farm. On the inspector of constabulary -informing him that he was a prisoner, he remarked that he was not -surprised to hear it, and that it was no more than his deserts. -This observation of his had the natural effect of removing any -traces of doubt which might have remained in the minds of the -coroner's jury." - -"It was a confession," I ejaculated. - -"No, for it was followed by a protestation of innocence." - -"Coming on the top of such a damning series of events, it was at -least a most suspicious remark." - -"On the contrary," said Holmes, "it is the brightest rift which I -can at present see in the clouds. However innocent he might be, -he could not be such an absolute imbecile as not to see that the -circumstances were very black against him. Had he appeared -surprised at his own arrest, or feigned indignation at it, I -should have looked upon it as highly suspicious, because such -surprise or anger would not be natural under the circumstances, -and yet might appear to be the best policy to a scheming man. His -frank acceptance of the situation marks him as either an innocent -man, or else as a man of considerable self-restraint and -firmness. As to his remark about his deserts, it was also not -unnatural if you consider that he stood beside the dead body of -his father, and that there is no doubt that he had that very day -so far forgotten his filial duty as to bandy words with him, and -even, according to the little girl whose evidence is so -important, to raise his hand as if to strike him. The -self-reproach and contrition which are displayed in his remark -appear to me to be the signs of a healthy mind rather than of a -guilty one." - -I shook my head. "Many men have been hanged on far slighter -evidence," I remarked. - -"So they have. And many men have been wrongfully hanged." - -"What is the young man's own account of the matter?" - -"It is, I am afraid, not very encouraging to his supporters, -though there are one or two points in it which are suggestive. -You will find it here, and may read it for yourself." - -He picked out from his bundle a copy of the local Herefordshire -paper, and having turned down the sheet he pointed out the -paragraph in which the unfortunate young man had given his own -statement of what had occurred. I settled myself down in the -corner of the carriage and read it very carefully. It ran in this -way: - -"Mr. James McCarthy, the only son of the deceased, was then called -and gave evidence as follows: 'I had been away from home for -three days at Bristol, and had only just returned upon the -morning of last Monday, the 3rd. My father was absent from home at -the time of my arrival, and I was informed by the maid that he -had driven over to Ross with John Cobb, the groom. Shortly after -my return I heard the wheels of his trap in the yard, and, -looking out of my window, I saw him get out and walk rapidly out -of the yard, though I was not aware in which direction he was -going. I then took my gun and strolled out in the direction of -the Boscombe Pool, with the intention of visiting the rabbit -warren which is upon the other side. On my way I saw William -Crowder, the game-keeper, as he had stated in his evidence; but -he is mistaken in thinking that I was following my father. I had -no idea that he was in front of me. When about a hundred yards -from the pool I heard a cry of "Cooee!" which was a usual signal -between my father and myself. I then hurried forward, and found -him standing by the pool. He appeared to be much surprised at -seeing me and asked me rather roughly what I was doing there. A -conversation ensued which led to high words and almost to blows, -for my father was a man of a very violent temper. Seeing that his -passion was becoming ungovernable, I left him and returned -towards Hatherley Farm. I had not gone more than 150 yards, -however, when I heard a hideous outcry behind me, which caused me -to run back again. I found my father expiring upon the ground, -with his head terribly injured. I dropped my gun and held him in -my arms, but he almost instantly expired. I knelt beside him for -some minutes, and then made my way to Mr. Turner's lodge-keeper, -his house being the nearest, to ask for assistance. I saw no one -near my father when I returned, and I have no idea how he came by -his injuries. He was not a popular man, being somewhat cold and -forbidding in his manners, but he had, as far as I know, no -active enemies. I know nothing further of the matter.' - -"The Coroner: Did your father make any statement to you before -he died? - -"Witness: He mumbled a few words, but I could only catch some -allusion to a rat. - -"The Coroner: What did you understand by that? - -"Witness: It conveyed no meaning to me. I thought that he was -delirious. - -"The Coroner: What was the point upon which you and your father -had this final quarrel? - -"Witness: I should prefer not to answer. - -"The Coroner: I am afraid that I must press it. - -"Witness: It is really impossible for me to tell you. I can -assure you that it has nothing to do with the sad tragedy which -followed. - -"The Coroner: That is for the court to decide. I need not point -out to you that your refusal to answer will prejudice your case -considerably in any future proceedings which may arise. - -"Witness: I must still refuse. - -"The Coroner: I understand that the cry of 'Cooee' was a common -signal between you and your father? - -"Witness: It was. - -"The Coroner: How was it, then, that he uttered it before he saw -you, and before he even knew that you had returned from Bristol? - -"Witness (with considerable confusion): I do not know. - -"A Juryman: Did you see nothing which aroused your suspicions -when you returned on hearing the cry and found your father -fatally injured? - -"Witness: Nothing definite. - -"The Coroner: What do you mean? - -"Witness: I was so disturbed and excited as I rushed out into -the open, that I could think of nothing except of my father. Yet -I have a vague impression that as I ran forward something lay -upon the ground to the left of me. It seemed to me to be -something grey in colour, a coat of some sort, or a plaid perhaps. -When I rose from my father I looked round for it, but it was -gone. - -"'Do you mean that it disappeared before you went for help?' - -"'Yes, it was gone.' - -"'You cannot say what it was?' - -"'No, I had a feeling something was there.' - -"'How far from the body?' - -"'A dozen yards or so.' - -"'And how far from the edge of the wood?' - -"'About the same.' - -"'Then if it was removed it was while you were within a dozen -yards of it?' - -"'Yes, but with my back towards it.' - -"This concluded the examination of the witness." - -"I see," said I as I glanced down the column, "that the coroner -in his concluding remarks was rather severe upon young McCarthy. -He calls attention, and with reason, to the discrepancy about his -father having signalled to him before seeing him, also to his -refusal to give details of his conversation with his father, and -his singular account of his father's dying words. They are all, -as he remarks, very much against the son." - -Holmes laughed softly to himself and stretched himself out upon -the cushioned seat. "Both you and the coroner have been at some -pains," said he, "to single out the very strongest points in the -young man's favour. Don't you see that you alternately give him -credit for having too much imagination and too little? Too -little, if he could not invent a cause of quarrel which would -give him the sympathy of the jury; too much, if he evolved from -his own inner consciousness anything so outré as a dying -reference to a rat, and the incident of the vanishing cloth. No, -sir, I shall approach this case from the point of view that what -this young man says is true, and we shall see whither that -hypothesis will lead us. And now here is my pocket Petrarch, and -not another word shall I say of this case until we are on the -scene of action. We lunch at Swindon, and I see that we shall be -there in twenty minutes." - -It was nearly four o'clock when we at last, after passing through -the beautiful Stroud Valley, and over the broad gleaming Severn, -found ourselves at the pretty little country-town of Ross. A -lean, ferret-like man, furtive and sly-looking, was waiting for -us upon the platform. In spite of the light brown dustcoat and -leather-leggings which he wore in deference to his rustic -surroundings, I had no difficulty in recognising Lestrade, of -Scotland Yard. With him we drove to the Hereford Arms where a -room had already been engaged for us. - -"I have ordered a carriage," said Lestrade as we sat over a cup -of tea. "I knew your energetic nature, and that you would not be -happy until you had been on the scene of the crime." - -"It was very nice and complimentary of you," Holmes answered. "It -is entirely a question of barometric pressure." - -Lestrade looked startled. "I do not quite follow," he said. - -"How is the glass? Twenty-nine, I see. No wind, and not a cloud -in the sky. I have a caseful of cigarettes here which need -smoking, and the sofa is very much superior to the usual country -hotel abomination. I do not think that it is probable that I -shall use the carriage to-night." - -Lestrade laughed indulgently. "You have, no doubt, already formed -your conclusions from the newspapers," he said. "The case is as -plain as a pikestaff, and the more one goes into it the plainer -it becomes. Still, of course, one can't refuse a lady, and such a -very positive one, too. She has heard of you, and would have your -opinion, though I repeatedly told her that there was nothing -which you could do which I had not already done. Why, bless my -soul! here is her carriage at the door." - -He had hardly spoken before there rushed into the room one of the -most lovely young women that I have ever seen in my life. Her -violet eyes shining, her lips parted, a pink flush upon her -cheeks, all thought of her natural reserve lost in her -overpowering excitement and concern. - -"Oh, Mr. Sherlock Holmes!" she cried, glancing from one to the -other of us, and finally, with a woman's quick intuition, -fastening upon my companion, "I am so glad that you have come. I -have driven down to tell you so. I know that James didn't do it. -I know it, and I want you to start upon your work knowing it, -too. Never let yourself doubt upon that point. We have known each -other since we were little children, and I know his faults as no -one else does; but he is too tender-hearted to hurt a fly. Such a -charge is absurd to anyone who really knows him." - -"I hope we may clear him, Miss Turner," said Sherlock Holmes. -"You may rely upon my doing all that I can." - -"But you have read the evidence. You have formed some conclusion? -Do you not see some loophole, some flaw? Do you not yourself -think that he is innocent?" - -"I think that it is very probable." - -"There, now!" she cried, throwing back her head and looking -defiantly at Lestrade. "You hear! He gives me hopes." - -Lestrade shrugged his shoulders. "I am afraid that my colleague -has been a little quick in forming his conclusions," he said. - -"But he is right. Oh! I know that he is right. James never did -it. And about his quarrel with his father, I am sure that the -reason why he would not speak about it to the coroner was because -I was concerned in it." - -"In what way?" asked Holmes. - -"It is no time for me to hide anything. James and his father had -many disagreements about me. Mr. McCarthy was very anxious that -there should be a marriage between us. James and I have always -loved each other as brother and sister; but of course he is young -and has seen very little of life yet, and--and--well, he -naturally did not wish to do anything like that yet. So there -were quarrels, and this, I am sure, was one of them." - -"And your father?" asked Holmes. "Was he in favour of such a -union?" - -"No, he was averse to it also. No one but Mr. McCarthy was in -favour of it." A quick blush passed over her fresh young face as -Holmes shot one of his keen, questioning glances at her. - -"Thank you for this information," said he. "May I see your father -if I call to-morrow?" - -"I am afraid the doctor won't allow it." - -"The doctor?" - -"Yes, have you not heard? Poor father has never been strong for -years back, but this has broken him down completely. He has taken -to his bed, and Dr. Willows says that he is a wreck and that his -nervous system is shattered. Mr. McCarthy was the only man alive -who had known dad in the old days in Victoria." - -"Ha! In Victoria! That is important." - -"Yes, at the mines." - -"Quite so; at the gold-mines, where, as I understand, Mr. Turner -made his money." - -"Yes, certainly." - -"Thank you, Miss Turner. You have been of material assistance to -me." - -"You will tell me if you have any news to-morrow. No doubt you -will go to the prison to see James. Oh, if you do, Mr. Holmes, do -tell him that I know him to be innocent." - -"I will, Miss Turner." - -"I must go home now, for dad is very ill, and he misses me so if -I leave him. Good-bye, and God help you in your undertaking." She -hurried from the room as impulsively as she had entered, and we -heard the wheels of her carriage rattle off down the street. - -"I am ashamed of you, Holmes," said Lestrade with dignity after a -few minutes' silence. "Why should you raise up hopes which you -are bound to disappoint? I am not over-tender of heart, but I -call it cruel." - -"I think that I see my way to clearing James McCarthy," said -Holmes. "Have you an order to see him in prison?" - -"Yes, but only for you and me." - -"Then I shall reconsider my resolution about going out. We have -still time to take a train to Hereford and see him to-night?" - -"Ample." - -"Then let us do so. Watson, I fear that you will find it very -slow, but I shall only be away a couple of hours." - -I walked down to the station with them, and then wandered through -the streets of the little town, finally returning to the hotel, -where I lay upon the sofa and tried to interest myself in a -yellow-backed novel. The puny plot of the story was so thin, -however, when compared to the deep mystery through which we were -groping, and I found my attention wander so continually from the -action to the fact, that I at last flung it across the room and -gave myself up entirely to a consideration of the events of the -day. Supposing that this unhappy young man's story were -absolutely true, then what hellish thing, what absolutely -unforeseen and extraordinary calamity could have occurred between -the time when he parted from his father, and the moment when, -drawn back by his screams, he rushed into the glade? It was -something terrible and deadly. What could it be? Might not the -nature of the injuries reveal something to my medical instincts? -I rang the bell and called for the weekly county paper, which -contained a verbatim account of the inquest. In the surgeon's -deposition it was stated that the posterior third of the left -parietal bone and the left half of the occipital bone had been -shattered by a heavy blow from a blunt weapon. I marked the spot -upon my own head. Clearly such a blow must have been struck from -behind. That was to some extent in favour of the accused, as when -seen quarrelling he was face to face with his father. Still, it -did not go for very much, for the older man might have turned his -back before the blow fell. Still, it might be worth while to call -Holmes' attention to it. Then there was the peculiar dying -reference to a rat. What could that mean? It could not be -delirium. A man dying from a sudden blow does not commonly become -delirious. No, it was more likely to be an attempt to explain how -he met his fate. But what could it indicate? I cudgelled my -brains to find some possible explanation. And then the incident -of the grey cloth seen by young McCarthy. If that were true the -murderer must have dropped some part of his dress, presumably his -overcoat, in his flight, and must have had the hardihood to -return and to carry it away at the instant when the son was -kneeling with his back turned not a dozen paces off. What a -tissue of mysteries and improbabilities the whole thing was! I -did not wonder at Lestrade's opinion, and yet I had so much faith -in Sherlock Holmes' insight that I could not lose hope as long -as every fresh fact seemed to strengthen his conviction of young -McCarthy's innocence. - -It was late before Sherlock Holmes returned. He came back alone, -for Lestrade was staying in lodgings in the town. - -"The glass still keeps very high," he remarked as he sat down. -"It is of importance that it should not rain before we are able -to go over the ground. On the other hand, a man should be at his -very best and keenest for such nice work as that, and I did not -wish to do it when fagged by a long journey. I have seen young -McCarthy." - -"And what did you learn from him?" - -"Nothing." - -"Could he throw no light?" - -"None at all. I was inclined to think at one time that he knew -who had done it and was screening him or her, but I am convinced -now that he is as puzzled as everyone else. He is not a very -quick-witted youth, though comely to look at and, I should think, -sound at heart." - -"I cannot admire his taste," I remarked, "if it is indeed a fact -that he was averse to a marriage with so charming a young lady as -this Miss Turner." - -"Ah, thereby hangs a rather painful tale. This fellow is madly, -insanely, in love with her, but some two years ago, when he was -only a lad, and before he really knew her, for she had been away -five years at a boarding-school, what does the idiot do but get -into the clutches of a barmaid in Bristol and marry her at a -registry office? No one knows a word of the matter, but you can -imagine how maddening it must be to him to be upbraided for not -doing what he would give his very eyes to do, but what he knows -to be absolutely impossible. It was sheer frenzy of this sort -which made him throw his hands up into the air when his father, -at their last interview, was goading him on to propose to Miss -Turner. On the other hand, he had no means of supporting himself, -and his father, who was by all accounts a very hard man, would -have thrown him over utterly had he known the truth. It was with -his barmaid wife that he had spent the last three days in -Bristol, and his father did not know where he was. Mark that -point. It is of importance. Good has come out of evil, however, -for the barmaid, finding from the papers that he is in serious -trouble and likely to be hanged, has thrown him over utterly and -has written to him to say that she has a husband already in the -Bermuda Dockyard, so that there is really no tie between them. I -think that that bit of news has consoled young McCarthy for all -that he has suffered." - -"But if he is innocent, who has done it?" - -"Ah! who? I would call your attention very particularly to two -points. One is that the murdered man had an appointment with -someone at the pool, and that the someone could not have been his -son, for his son was away, and he did not know when he would -return. The second is that the murdered man was heard to cry -'Cooee!' before he knew that his son had returned. Those are the -crucial points upon which the case depends. And now let us talk -about George Meredith, if you please, and we shall leave all -minor matters until to-morrow." - -There was no rain, as Holmes had foretold, and the morning broke -bright and cloudless. At nine o'clock Lestrade called for us with -the carriage, and we set off for Hatherley Farm and the Boscombe -Pool. - -"There is serious news this morning," Lestrade observed. "It is -said that Mr. Turner, of the Hall, is so ill that his life is -despaired of." - -"An elderly man, I presume?" said Holmes. - -"About sixty; but his constitution has been shattered by his life -abroad, and he has been in failing health for some time. This -business has had a very bad effect upon him. He was an old friend -of McCarthy's, and, I may add, a great benefactor to him, for I -have learned that he gave him Hatherley Farm rent free." - -"Indeed! That is interesting," said Holmes. - -"Oh, yes! In a hundred other ways he has helped him. Everybody -about here speaks of his kindness to him." - -"Really! Does it not strike you as a little singular that this -McCarthy, who appears to have had little of his own, and to have -been under such obligations to Turner, should still talk of -marrying his son to Turner's daughter, who is, presumably, -heiress to the estate, and that in such a very cocksure manner, -as if it were merely a case of a proposal and all else would -follow? It is the more strange, since we know that Turner himself -was averse to the idea. The daughter told us as much. Do you not -deduce something from that?" - -"We have got to the deductions and the inferences," said -Lestrade, winking at me. "I find it hard enough to tackle facts, -Holmes, without flying away after theories and fancies." - -"You are right," said Holmes demurely; "you do find it very hard -to tackle the facts." - -"Anyhow, I have grasped one fact which you seem to find it -difficult to get hold of," replied Lestrade with some warmth. - -"And that is--" - -"That McCarthy senior met his death from McCarthy junior and that -all theories to the contrary are the merest moonshine." - -"Well, moonshine is a brighter thing than fog," said Holmes, -laughing. "But I am very much mistaken if this is not Hatherley -Farm upon the left." - -"Yes, that is it." It was a widespread, comfortable-looking -building, two-storied, slate-roofed, with great yellow blotches -of lichen upon the grey walls. The drawn blinds and the smokeless -chimneys, however, gave it a stricken look, as though the weight -of this horror still lay heavy upon it. We called at the door, -when the maid, at Holmes' request, showed us the boots which her -master wore at the time of his death, and also a pair of the -son's, though not the pair which he had then had. Having measured -these very carefully from seven or eight different points, Holmes -desired to be led to the court-yard, from which we all followed -the winding track which led to Boscombe Pool. - -Sherlock Holmes was transformed when he was hot upon such a scent -as this. Men who had only known the quiet thinker and logician of -Baker Street would have failed to recognise him. His face flushed -and darkened. His brows were drawn into two hard black lines, -while his eyes shone out from beneath them with a steely glitter. -His face was bent downward, his shoulders bowed, his lips -compressed, and the veins stood out like whipcord in his long, -sinewy neck. His nostrils seemed to dilate with a purely animal -lust for the chase, and his mind was so absolutely concentrated -upon the matter before him that a question or remark fell -unheeded upon his ears, or, at the most, only provoked a quick, -impatient snarl in reply. Swiftly and silently he made his way -along the track which ran through the meadows, and so by way of -the woods to the Boscombe Pool. It was damp, marshy ground, as is -all that district, and there were marks of many feet, both upon -the path and amid the short grass which bounded it on either -side. Sometimes Holmes would hurry on, sometimes stop dead, and -once he made quite a little detour into the meadow. Lestrade and -I walked behind him, the detective indifferent and contemptuous, -while I watched my friend with the interest which sprang from the -conviction that every one of his actions was directed towards a -definite end. - -The Boscombe Pool, which is a little reed-girt sheet of water -some fifty yards across, is situated at the boundary between the -Hatherley Farm and the private park of the wealthy Mr. Turner. -Above the woods which lined it upon the farther side we could see -the red, jutting pinnacles which marked the site of the rich -landowner's dwelling. On the Hatherley side of the pool the woods -grew very thick, and there was a narrow belt of sodden grass -twenty paces across between the edge of the trees and the reeds -which lined the lake. Lestrade showed us the exact spot at which -the body had been found, and, indeed, so moist was the ground, -that I could plainly see the traces which had been left by the -fall of the stricken man. To Holmes, as I could see by his eager -face and peering eyes, very many other things were to be read -upon the trampled grass. He ran round, like a dog who is picking -up a scent, and then turned upon my companion. - -"What did you go into the pool for?" he asked. - -"I fished about with a rake. I thought there might be some weapon -or other trace. But how on earth--" - -"Oh, tut, tut! I have no time! That left foot of yours with its -inward twist is all over the place. A mole could trace it, and -there it vanishes among the reeds. Oh, how simple it would all -have been had I been here before they came like a herd of buffalo -and wallowed all over it. Here is where the party with the -lodge-keeper came, and they have covered all tracks for six or -eight feet round the body. But here are three separate tracks of -the same feet." He drew out a lens and lay down upon his -waterproof to have a better view, talking all the time rather to -himself than to us. "These are young McCarthy's feet. Twice he -was walking, and once he ran swiftly, so that the soles are -deeply marked and the heels hardly visible. That bears out his -story. He ran when he saw his father on the ground. Then here are -the father's feet as he paced up and down. What is this, then? It -is the butt-end of the gun as the son stood listening. And this? -Ha, ha! What have we here? Tiptoes! tiptoes! Square, too, quite -unusual boots! They come, they go, they come again--of course -that was for the cloak. Now where did they come from?" He ran up -and down, sometimes losing, sometimes finding the track until we -were well within the edge of the wood and under the shadow of a -great beech, the largest tree in the neighbourhood. Holmes traced -his way to the farther side of this and lay down once more upon -his face with a little cry of satisfaction. For a long time he -remained there, turning over the leaves and dried sticks, -gathering up what seemed to me to be dust into an envelope and -examining with his lens not only the ground but even the bark of -the tree as far as he could reach. A jagged stone was lying among -the moss, and this also he carefully examined and retained. Then -he followed a pathway through the wood until he came to the -highroad, where all traces were lost. - -"It has been a case of considerable interest," he remarked, -returning to his natural manner. "I fancy that this grey house on -the right must be the lodge. I think that I will go in and have a -word with Moran, and perhaps write a little note. Having done -that, we may drive back to our luncheon. You may walk to the cab, -and I shall be with you presently." - -It was about ten minutes before we regained our cab and drove -back into Ross, Holmes still carrying with him the stone which he -had picked up in the wood. - -"This may interest you, Lestrade," he remarked, holding it out. -"The murder was done with it." - -"I see no marks." - -"There are none." - -"How do you know, then?" - -"The grass was growing under it. It had only lain there a few -days. There was no sign of a place whence it had been taken. It -corresponds with the injuries. There is no sign of any other -weapon." - -"And the murderer?" - -"Is a tall man, left-handed, limps with the right leg, wears -thick-soled shooting-boots and a grey cloak, smokes Indian -cigars, uses a cigar-holder, and carries a blunt pen-knife in his -pocket. There are several other indications, but these may be -enough to aid us in our search." - -Lestrade laughed. "I am afraid that I am still a sceptic," he -said. "Theories are all very well, but we have to deal with a -hard-headed British jury." - -"Nous verrons," answered Holmes calmly. "You work your own -method, and I shall work mine. I shall be busy this afternoon, -and shall probably return to London by the evening train." - -"And leave your case unfinished?" - -"No, finished." - -"But the mystery?" - -"It is solved." - -"Who was the criminal, then?" - -"The gentleman I describe." - -"But who is he?" - -"Surely it would not be difficult to find out. This is not such a -populous neighbourhood." - -Lestrade shrugged his shoulders. "I am a practical man," he said, -"and I really cannot undertake to go about the country looking -for a left-handed gentleman with a game leg. I should become the -laughing-stock of Scotland Yard." - -"All right," said Holmes quietly. "I have given you the chance. -Here are your lodgings. Good-bye. I shall drop you a line before -I leave." - -Having left Lestrade at his rooms, we drove to our hotel, where -we found lunch upon the table. Holmes was silent and buried in -thought with a pained expression upon his face, as one who finds -himself in a perplexing position. - -"Look here, Watson," he said when the cloth was cleared "just sit -down in this chair and let me preach to you for a little. I don't -know quite what to do, and I should value your advice. Light a -cigar and let me expound." - - "Pray do so." - -"Well, now, in considering this case there are two points about -young McCarthy's narrative which struck us both instantly, -although they impressed me in his favour and you against him. One -was the fact that his father should, according to his account, -cry 'Cooee!' before seeing him. The other was his singular dying -reference to a rat. He mumbled several words, you understand, but -that was all that caught the son's ear. Now from this double -point our research must commence, and we will begin it by -presuming that what the lad says is absolutely true." - -"What of this 'Cooee!' then?" - -"Well, obviously it could not have been meant for the son. The -son, as far as he knew, was in Bristol. It was mere chance that -he was within earshot. The 'Cooee!' was meant to attract the -attention of whoever it was that he had the appointment with. But -'Cooee' is a distinctly Australian cry, and one which is used -between Australians. There is a strong presumption that the -person whom McCarthy expected to meet him at Boscombe Pool was -someone who had been in Australia." - -"What of the rat, then?" - -Sherlock Holmes took a folded paper from his pocket and flattened -it out on the table. "This is a map of the Colony of Victoria," -he said. "I wired to Bristol for it last night." He put his hand -over part of the map. "What do you read?" - -"ARAT," I read. - -"And now?" He raised his hand. - -"BALLARAT." - -"Quite so. That was the word the man uttered, and of which his -son only caught the last two syllables. He was trying to utter -the name of his murderer. So and so, of Ballarat." - -"It is wonderful!" I exclaimed. - -"It is obvious. And now, you see, I had narrowed the field down -considerably. The possession of a grey garment was a third point -which, granting the son's statement to be correct, was a -certainty. We have come now out of mere vagueness to the definite -conception of an Australian from Ballarat with a grey cloak." - -"Certainly." - -"And one who was at home in the district, for the pool can only -be approached by the farm or by the estate, where strangers could -hardly wander." - -"Quite so." - -"Then comes our expedition of to-day. By an examination of the -ground I gained the trifling details which I gave to that -imbecile Lestrade, as to the personality of the criminal." - -"But how did you gain them?" - -"You know my method. It is founded upon the observation of -trifles." - -"His height I know that you might roughly judge from the length -of his stride. His boots, too, might be told from their traces." - -"Yes, they were peculiar boots." - -"But his lameness?" - -"The impression of his right foot was always less distinct than -his left. He put less weight upon it. Why? Because he limped--he -was lame." - -"But his left-handedness." - -"You were yourself struck by the nature of the injury as recorded -by the surgeon at the inquest. The blow was struck from -immediately behind, and yet was upon the left side. Now, how can -that be unless it were by a left-handed man? He had stood behind -that tree during the interview between the father and son. He had -even smoked there. I found the ash of a cigar, which my special -knowledge of tobacco ashes enables me to pronounce as an Indian -cigar. I have, as you know, devoted some attention to this, and -written a little monograph on the ashes of 140 different -varieties of pipe, cigar, and cigarette tobacco. Having found the -ash, I then looked round and discovered the stump among the moss -where he had tossed it. It was an Indian cigar, of the variety -which are rolled in Rotterdam." - -"And the cigar-holder?" - -"I could see that the end had not been in his mouth. Therefore he -used a holder. The tip had been cut off, not bitten off, but the -cut was not a clean one, so I deduced a blunt pen-knife." - -"Holmes," I said, "you have drawn a net round this man from which -he cannot escape, and you have saved an innocent human life as -truly as if you had cut the cord which was hanging him. I see the -direction in which all this points. The culprit is--" - -"Mr. John Turner," cried the hotel waiter, opening the door of -our sitting-room, and ushering in a visitor. - -The man who entered was a strange and impressive figure. His -slow, limping step and bowed shoulders gave the appearance of -decrepitude, and yet his hard, deep-lined, craggy features, and -his enormous limbs showed that he was possessed of unusual -strength of body and of character. His tangled beard, grizzled -hair, and outstanding, drooping eyebrows combined to give an air -of dignity and power to his appearance, but his face was of an -ashen white, while his lips and the corners of his nostrils were -tinged with a shade of blue. It was clear to me at a glance that -he was in the grip of some deadly and chronic disease. - -"Pray sit down on the sofa," said Holmes gently. "You had my -note?" - -"Yes, the lodge-keeper brought it up. You said that you wished to -see me here to avoid scandal." - -"I thought people would talk if I went to the Hall." - -"And why did you wish to see me?" He looked across at my -companion with despair in his weary eyes, as though his question -was already answered. - -"Yes," said Holmes, answering the look rather than the words. "It -is so. I know all about McCarthy." - -The old man sank his face in his hands. "God help me!" he cried. -"But I would not have let the young man come to harm. I give you -my word that I would have spoken out if it went against him at -the Assizes." - -"I am glad to hear you say so," said Holmes gravely. - -"I would have spoken now had it not been for my dear girl. It -would break her heart--it will break her heart when she hears -that I am arrested." - -"It may not come to that," said Holmes. - -"What?" - -"I am no official agent. I understand that it was your daughter -who required my presence here, and I am acting in her interests. -Young McCarthy must be got off, however." - -"I am a dying man," said old Turner. "I have had diabetes for -years. My doctor says it is a question whether I shall live a -month. Yet I would rather die under my own roof than in a gaol." - -Holmes rose and sat down at the table with his pen in his hand -and a bundle of paper before him. "Just tell us the truth," he -said. "I shall jot down the facts. You will sign it, and Watson -here can witness it. Then I could produce your confession at the -last extremity to save young McCarthy. I promise you that I shall -not use it unless it is absolutely needed." - -"It's as well," said the old man; "it's a question whether I -shall live to the Assizes, so it matters little to me, but I -should wish to spare Alice the shock. And now I will make the -thing clear to you; it has been a long time in the acting, but -will not take me long to tell. - -"You didn't know this dead man, McCarthy. He was a devil -incarnate. I tell you that. God keep you out of the clutches of -such a man as he. His grip has been upon me these twenty years, -and he has blasted my life. I'll tell you first how I came to be -in his power. - -"It was in the early '60's at the diggings. I was a young chap -then, hot-blooded and reckless, ready to turn my hand at -anything; I got among bad companions, took to drink, had no luck -with my claim, took to the bush, and in a word became what you -would call over here a highway robber. There were six of us, and -we had a wild, free life of it, sticking up a station from time -to time, or stopping the wagons on the road to the diggings. -Black Jack of Ballarat was the name I went under, and our party -is still remembered in the colony as the Ballarat Gang. - -"One day a gold convoy came down from Ballarat to Melbourne, and -we lay in wait for it and attacked it. There were six troopers -and six of us, so it was a close thing, but we emptied four of -their saddles at the first volley. Three of our boys were killed, -however, before we got the swag. I put my pistol to the head of -the wagon-driver, who was this very man McCarthy. I wish to the -Lord that I had shot him then, but I spared him, though I saw his -wicked little eyes fixed on my face, as though to remember every -feature. We got away with the gold, became wealthy men, and made -our way over to England without being suspected. There I parted -from my old pals and determined to settle down to a quiet and -respectable life. I bought this estate, which chanced to be in -the market, and I set myself to do a little good with my money, -to make up for the way in which I had earned it. I married, too, -and though my wife died young she left me my dear little Alice. -Even when she was just a baby her wee hand seemed to lead me down -the right path as nothing else had ever done. In a word, I turned -over a new leaf and did my best to make up for the past. All was -going well when McCarthy laid his grip upon me. - -"I had gone up to town about an investment, and I met him in -Regent Street with hardly a coat to his back or a boot to his -foot. - -"'Here we are, Jack,' says he, touching me on the arm; 'we'll be -as good as a family to you. There's two of us, me and my son, and -you can have the keeping of us. If you don't--it's a fine, -law-abiding country is England, and there's always a policeman -within hail.' - -"Well, down they came to the west country, there was no shaking -them off, and there they have lived rent free on my best land -ever since. There was no rest for me, no peace, no forgetfulness; -turn where I would, there was his cunning, grinning face at my -elbow. It grew worse as Alice grew up, for he soon saw I was more -afraid of her knowing my past than of the police. Whatever he -wanted he must have, and whatever it was I gave him without -question, land, money, houses, until at last he asked a thing -which I could not give. He asked for Alice. - -"His son, you see, had grown up, and so had my girl, and as I was -known to be in weak health, it seemed a fine stroke to him that -his lad should step into the whole property. But there I was -firm. I would not have his cursed stock mixed with mine; not that -I had any dislike to the lad, but his blood was in him, and that -was enough. I stood firm. McCarthy threatened. I braved him to do -his worst. We were to meet at the pool midway between our houses -to talk it over. - -"When I went down there I found him talking with his son, so I -smoked a cigar and waited behind a tree until he should be alone. -But as I listened to his talk all that was black and bitter in -me seemed to come uppermost. He was urging his son to marry my -daughter with as little regard for what she might think as if she -were a slut from off the streets. It drove me mad to think that I -and all that I held most dear should be in the power of such a -man as this. Could I not snap the bond? I was already a dying and -a desperate man. Though clear of mind and fairly strong of limb, -I knew that my own fate was sealed. But my memory and my girl! -Both could be saved if I could but silence that foul tongue. I -did it, Mr. Holmes. I would do it again. Deeply as I have sinned, -I have led a life of martyrdom to atone for it. But that my girl -should be entangled in the same meshes which held me was more -than I could suffer. I struck him down with no more compunction -than if he had been some foul and venomous beast. His cry brought -back his son; but I had gained the cover of the wood, though I -was forced to go back to fetch the cloak which I had dropped in -my flight. That is the true story, gentlemen, of all that -occurred." - -"Well, it is not for me to judge you," said Holmes as the old man -signed the statement which had been drawn out. "I pray that we -may never be exposed to such a temptation." - -"I pray not, sir. And what do you intend to do?" - -"In view of your health, nothing. You are yourself aware that you -will soon have to answer for your deed at a higher court than the -Assizes. I will keep your confession, and if McCarthy is -condemned I shall be forced to use it. If not, it shall never be -seen by mortal eye; and your secret, whether you be alive or -dead, shall be safe with us." - -"Farewell, then," said the old man solemnly. "Your own deathbeds, -when they come, will be the easier for the thought of the peace -which you have given to mine." Tottering and shaking in all his -giant frame, he stumbled slowly from the room. - -"God help us!" said Holmes after a long silence. "Why does fate -play such tricks with poor, helpless worms? I never hear of such -a case as this that I do not think of Baxter's words, and say, -'There, but for the grace of God, goes Sherlock Holmes.'" - -James McCarthy was acquitted at the Assizes on the strength of a -number of objections which had been drawn out by Holmes and -submitted to the defending counsel. Old Turner lived for seven -months after our interview, but he is now dead; and there is -every prospect that the son and daughter may come to live happily -together in ignorance of the black cloud which rests upon their -past. - - - -ADVENTURE V. THE FIVE ORANGE PIPS - -When I glance over my notes and records of the Sherlock Holmes -cases between the years '82 and '90, I am faced by so many which -present strange and interesting features that it is no easy -matter to know which to choose and which to leave. Some, however, -have already gained publicity through the papers, and others have -not offered a field for those peculiar qualities which my friend -possessed in so high a degree, and which it is the object of -these papers to illustrate. Some, too, have baffled his -analytical skill, and would be, as narratives, beginnings without -an ending, while others have been but partially cleared up, and -have their explanations founded rather upon conjecture and -surmise than on that absolute logical proof which was so dear to -him. There is, however, one of these last which was so remarkable -in its details and so startling in its results that I am tempted -to give some account of it in spite of the fact that there are -points in connection with it which never have been, and probably -never will be, entirely cleared up. - -The year '87 furnished us with a long series of cases of greater -or less interest, of which I retain the records. Among my -headings under this one twelve months I find an account of the -adventure of the Paradol Chamber, of the Amateur Mendicant -Society, who held a luxurious club in the lower vault of a -furniture warehouse, of the facts connected with the loss of the -British barque "Sophy Anderson", of the singular adventures of the -Grice Patersons in the island of Uffa, and finally of the -Camberwell poisoning case. In the latter, as may be remembered, -Sherlock Holmes was able, by winding up the dead man's watch, to -prove that it had been wound up two hours before, and that -therefore the deceased had gone to bed within that time--a -deduction which was of the greatest importance in clearing up the -case. All these I may sketch out at some future date, but none of -them present such singular features as the strange train of -circumstances which I have now taken up my pen to describe. - -It was in the latter days of September, and the equinoctial gales -had set in with exceptional violence. All day the wind had -screamed and the rain had beaten against the windows, so that -even here in the heart of great, hand-made London we were forced -to raise our minds for the instant from the routine of life and -to recognise the presence of those great elemental forces which -shriek at mankind through the bars of his civilisation, like -untamed beasts in a cage. As evening drew in, the storm grew -higher and louder, and the wind cried and sobbed like a child in -the chimney. Sherlock Holmes sat moodily at one side of the -fireplace cross-indexing his records of crime, while I at the -other was deep in one of Clark Russell's fine sea-stories until -the howl of the gale from without seemed to blend with the text, -and the splash of the rain to lengthen out into the long swash of -the sea waves. My wife was on a visit to her mother's, and for a -few days I was a dweller once more in my old quarters at Baker -Street. - -"Why," said I, glancing up at my companion, "that was surely the -bell. Who could come to-night? Some friend of yours, perhaps?" - -"Except yourself I have none," he answered. "I do not encourage -visitors." - -"A client, then?" - -"If so, it is a serious case. Nothing less would bring a man out -on such a day and at such an hour. But I take it that it is more -likely to be some crony of the landlady's." - -Sherlock Holmes was wrong in his conjecture, however, for there -came a step in the passage and a tapping at the door. He -stretched out his long arm to turn the lamp away from himself and -towards the vacant chair upon which a newcomer must sit. - -"Come in!" said he. - -The man who entered was young, some two-and-twenty at the -outside, well-groomed and trimly clad, with something of -refinement and delicacy in his bearing. The streaming umbrella -which he held in his hand, and his long shining waterproof told -of the fierce weather through which he had come. He looked about -him anxiously in the glare of the lamp, and I could see that his -face was pale and his eyes heavy, like those of a man who is -weighed down with some great anxiety. - -"I owe you an apology," he said, raising his golden pince-nez to -his eyes. "I trust that I am not intruding. I fear that I have -brought some traces of the storm and rain into your snug -chamber." - -"Give me your coat and umbrella," said Holmes. "They may rest -here on the hook and will be dry presently. You have come up from -the south-west, I see." - -"Yes, from Horsham." - -"That clay and chalk mixture which I see upon your toe caps is -quite distinctive." - -"I have come for advice." - -"That is easily got." - -"And help." - -"That is not always so easy." - -"I have heard of you, Mr. Holmes. I heard from Major Prendergast -how you saved him in the Tankerville Club scandal." - -"Ah, of course. He was wrongfully accused of cheating at cards." - -"He said that you could solve anything." - -"He said too much." - -"That you are never beaten." - -"I have been beaten four times--three times by men, and once by a -woman." - -"But what is that compared with the number of your successes?" - -"It is true that I have been generally successful." - -"Then you may be so with me." - -"I beg that you will draw your chair up to the fire and favour me -with some details as to your case." - -"It is no ordinary one." - -"None of those which come to me are. I am the last court of -appeal." - -"And yet I question, sir, whether, in all your experience, you -have ever listened to a more mysterious and inexplicable chain of -events than those which have happened in my own family." - -"You fill me with interest," said Holmes. "Pray give us the -essential facts from the commencement, and I can afterwards -question you as to those details which seem to me to be most -important." - -The young man pulled his chair up and pushed his wet feet out -towards the blaze. - -"My name," said he, "is John Openshaw, but my own affairs have, -as far as I can understand, little to do with this awful -business. It is a hereditary matter; so in order to give you an -idea of the facts, I must go back to the commencement of the -affair. - -"You must know that my grandfather had two sons--my uncle Elias -and my father Joseph. My father had a small factory at Coventry, -which he enlarged at the time of the invention of bicycling. He -was a patentee of the Openshaw unbreakable tire, and his business -met with such success that he was able to sell it and to retire -upon a handsome competence. - -"My uncle Elias emigrated to America when he was a young man and -became a planter in Florida, where he was reported to have done -very well. At the time of the war he fought in Jackson's army, -and afterwards under Hood, where he rose to be a colonel. When -Lee laid down his arms my uncle returned to his plantation, where -he remained for three or four years. About 1869 or 1870 he came -back to Europe and took a small estate in Sussex, near Horsham. -He had made a very considerable fortune in the States, and his -reason for leaving them was his aversion to the negroes, and his -dislike of the Republican policy in extending the franchise to -them. He was a singular man, fierce and quick-tempered, very -foul-mouthed when he was angry, and of a most retiring -disposition. During all the years that he lived at Horsham, I -doubt if ever he set foot in the town. He had a garden and two or -three fields round his house, and there he would take his -exercise, though very often for weeks on end he would never leave -his room. He drank a great deal of brandy and smoked very -heavily, but he would see no society and did not want any -friends, not even his own brother. - -"He didn't mind me; in fact, he took a fancy to me, for at the -time when he saw me first I was a youngster of twelve or so. This -would be in the year 1878, after he had been eight or nine years -in England. He begged my father to let me live with him and he -was very kind to me in his way. When he was sober he used to be -fond of playing backgammon and draughts with me, and he would -make me his representative both with the servants and with the -tradespeople, so that by the time that I was sixteen I was quite -master of the house. I kept all the keys and could go where I -liked and do what I liked, so long as I did not disturb him in -his privacy. There was one singular exception, however, for he -had a single room, a lumber-room up among the attics, which was -invariably locked, and which he would never permit either me or -anyone else to enter. With a boy's curiosity I have peeped -through the keyhole, but I was never able to see more than such a -collection of old trunks and bundles as would be expected in such -a room. - -"One day--it was in March, 1883--a letter with a foreign stamp -lay upon the table in front of the colonel's plate. It was not a -common thing for him to receive letters, for his bills were all -paid in ready money, and he had no friends of any sort. 'From -India!' said he as he took it up, 'Pondicherry postmark! What can -this be?' Opening it hurriedly, out there jumped five little -dried orange pips, which pattered down upon his plate. I began to -laugh at this, but the laugh was struck from my lips at the sight -of his face. His lip had fallen, his eyes were protruding, his -skin the colour of putty, and he glared at the envelope which he -still held in his trembling hand, 'K. K. K.!' he shrieked, and -then, 'My God, my God, my sins have overtaken me!' - -"'What is it, uncle?' I cried. - -"'Death,' said he, and rising from the table he retired to his -room, leaving me palpitating with horror. I took up the envelope -and saw scrawled in red ink upon the inner flap, just above the -gum, the letter K three times repeated. There was nothing else -save the five dried pips. What could be the reason of his -overpowering terror? I left the breakfast-table, and as I -ascended the stair I met him coming down with an old rusty key, -which must have belonged to the attic, in one hand, and a small -brass box, like a cashbox, in the other. - -"'They may do what they like, but I'll checkmate them still,' -said he with an oath. 'Tell Mary that I shall want a fire in my -room to-day, and send down to Fordham, the Horsham lawyer.' - -"I did as he ordered, and when the lawyer arrived I was asked to -step up to the room. The fire was burning brightly, and in the -grate there was a mass of black, fluffy ashes, as of burned -paper, while the brass box stood open and empty beside it. As I -glanced at the box I noticed, with a start, that upon the lid was -printed the treble K which I had read in the morning upon the -envelope. - -"'I wish you, John,' said my uncle, 'to witness my will. I leave -my estate, with all its advantages and all its disadvantages, to -my brother, your father, whence it will, no doubt, descend to -you. If you can enjoy it in peace, well and good! If you find you -cannot, take my advice, my boy, and leave it to your deadliest -enemy. I am sorry to give you such a two-edged thing, but I can't -say what turn things are going to take. Kindly sign the paper -where Mr. Fordham shows you.' - -"I signed the paper as directed, and the lawyer took it away with -him. The singular incident made, as you may think, the deepest -impression upon me, and I pondered over it and turned it every -way in my mind without being able to make anything of it. Yet I -could not shake off the vague feeling of dread which it left -behind, though the sensation grew less keen as the weeks passed -and nothing happened to disturb the usual routine of our lives. I -could see a change in my uncle, however. He drank more than ever, -and he was less inclined for any sort of society. Most of his -time he would spend in his room, with the door locked upon the -inside, but sometimes he would emerge in a sort of drunken frenzy -and would burst out of the house and tear about the garden with a -revolver in his hand, screaming out that he was afraid of no man, -and that he was not to be cooped up, like a sheep in a pen, by -man or devil. When these hot fits were over, however, he would -rush tumultuously in at the door and lock and bar it behind him, -like a man who can brazen it out no longer against the terror -which lies at the roots of his soul. At such times I have seen -his face, even on a cold day, glisten with moisture, as though it -were new raised from a basin. - -"Well, to come to an end of the matter, Mr. Holmes, and not to -abuse your patience, there came a night when he made one of those -drunken sallies from which he never came back. We found him, when -we went to search for him, face downward in a little -green-scummed pool, which lay at the foot of the garden. There -was no sign of any violence, and the water was but two feet deep, -so that the jury, having regard to his known eccentricity, -brought in a verdict of 'suicide.' But I, who knew how he winced -from the very thought of death, had much ado to persuade myself -that he had gone out of his way to meet it. The matter passed, -however, and my father entered into possession of the estate, and -of some 14,000 pounds, which lay to his credit at the bank." - -"One moment," Holmes interposed, "your statement is, I foresee, -one of the most remarkable to which I have ever listened. Let me -have the date of the reception by your uncle of the letter, and -the date of his supposed suicide." - -"The letter arrived on March 10, 1883. His death was seven weeks -later, upon the night of May 2nd." - -"Thank you. Pray proceed." - -"When my father took over the Horsham property, he, at my -request, made a careful examination of the attic, which had been -always locked up. We found the brass box there, although its -contents had been destroyed. On the inside of the cover was a -paper label, with the initials of K. K. K. repeated upon it, and -'Letters, memoranda, receipts, and a register' written beneath. -These, we presume, indicated the nature of the papers which had -been destroyed by Colonel Openshaw. For the rest, there was -nothing of much importance in the attic save a great many -scattered papers and note-books bearing upon my uncle's life in -America. Some of them were of the war time and showed that he had -done his duty well and had borne the repute of a brave soldier. -Others were of a date during the reconstruction of the Southern -states, and were mostly concerned with politics, for he had -evidently taken a strong part in opposing the carpet-bag -politicians who had been sent down from the North. - -"Well, it was the beginning of '84 when my father came to live at -Horsham, and all went as well as possible with us until the -January of '85. On the fourth day after the new year I heard my -father give a sharp cry of surprise as we sat together at the -breakfast-table. There he was, sitting with a newly opened -envelope in one hand and five dried orange pips in the -outstretched palm of the other one. He had always laughed at what -he called my cock-and-bull story about the colonel, but he looked -very scared and puzzled now that the same thing had come upon -himself. - -"'Why, what on earth does this mean, John?' he stammered. - -"My heart had turned to lead. 'It is K. K. K.,' said I. - -"He looked inside the envelope. 'So it is,' he cried. 'Here are -the very letters. But what is this written above them?' - -"'Put the papers on the sundial,' I read, peeping over his -shoulder. - -"'What papers? What sundial?' he asked. - -"'The sundial in the garden. There is no other,' said I; 'but the -papers must be those that are destroyed.' - -"'Pooh!' said he, gripping hard at his courage. 'We are in a -civilised land here, and we can't have tomfoolery of this kind. -Where does the thing come from?' - -"'From Dundee,' I answered, glancing at the postmark. - -"'Some preposterous practical joke,' said he. 'What have I to do -with sundials and papers? I shall take no notice of such -nonsense.' - -"'I should certainly speak to the police,' I said. - -"'And be laughed at for my pains. Nothing of the sort.' - -"'Then let me do so?' - -"'No, I forbid you. I won't have a fuss made about such -nonsense.' - -"It was in vain to argue with him, for he was a very obstinate -man. I went about, however, with a heart which was full of -forebodings. - -"On the third day after the coming of the letter my father went -from home to visit an old friend of his, Major Freebody, who is -in command of one of the forts upon Portsdown Hill. I was glad -that he should go, for it seemed to me that he was farther from -danger when he was away from home. In that, however, I was in -error. Upon the second day of his absence I received a telegram -from the major, imploring me to come at once. My father had -fallen over one of the deep chalk-pits which abound in the -neighbourhood, and was lying senseless, with a shattered skull. I -hurried to him, but he passed away without having ever recovered -his consciousness. He had, as it appears, been returning from -Fareham in the twilight, and as the country was unknown to him, -and the chalk-pit unfenced, the jury had no hesitation in -bringing in a verdict of 'death from accidental causes.' -Carefully as I examined every fact connected with his death, I -was unable to find anything which could suggest the idea of -murder. There were no signs of violence, no footmarks, no -robbery, no record of strangers having been seen upon the roads. -And yet I need not tell you that my mind was far from at ease, -and that I was well-nigh certain that some foul plot had been -woven round him. - -"In this sinister way I came into my inheritance. You will ask me -why I did not dispose of it? I answer, because I was well -convinced that our troubles were in some way dependent upon an -incident in my uncle's life, and that the danger would be as -pressing in one house as in another. - -"It was in January, '85, that my poor father met his end, and two -years and eight months have elapsed since then. During that time -I have lived happily at Horsham, and I had begun to hope that -this curse had passed away from the family, and that it had ended -with the last generation. I had begun to take comfort too soon, -however; yesterday morning the blow fell in the very shape in -which it had come upon my father." - -The young man took from his waistcoat a crumpled envelope, and -turning to the table he shook out upon it five little dried -orange pips. - -"This is the envelope," he continued. "The postmark is -London--eastern division. Within are the very words which were -upon my father's last message: 'K. K. K.'; and then 'Put the -papers on the sundial.'" - -"What have you done?" asked Holmes. - -"Nothing." - -"Nothing?" - -"To tell the truth"--he sank his face into his thin, white -hands--"I have felt helpless. I have felt like one of those poor -rabbits when the snake is writhing towards it. I seem to be in -the grasp of some resistless, inexorable evil, which no foresight -and no precautions can guard against." - -"Tut! tut!" cried Sherlock Holmes. "You must act, man, or you are -lost. Nothing but energy can save you. This is no time for -despair." - -"I have seen the police." - -"Ah!" - -"But they listened to my story with a smile. I am convinced that -the inspector has formed the opinion that the letters are all -practical jokes, and that the deaths of my relations were really -accidents, as the jury stated, and were not to be connected with -the warnings." - -Holmes shook his clenched hands in the air. "Incredible -imbecility!" he cried. - -"They have, however, allowed me a policeman, who may remain in -the house with me." - -"Has he come with you to-night?" - -"No. His orders were to stay in the house." - -Again Holmes raved in the air. - -"Why did you come to me," he cried, "and, above all, why did you -not come at once?" - -"I did not know. It was only to-day that I spoke to Major -Prendergast about my troubles and was advised by him to come to -you." - -"It is really two days since you had the letter. We should have -acted before this. You have no further evidence, I suppose, than -that which you have placed before us--no suggestive detail which -might help us?" - -"There is one thing," said John Openshaw. He rummaged in his coat -pocket, and, drawing out a piece of discoloured, blue-tinted -paper, he laid it out upon the table. "I have some remembrance," -said he, "that on the day when my uncle burned the papers I -observed that the small, unburned margins which lay amid the -ashes were of this particular colour. I found this single sheet -upon the floor of his room, and I am inclined to think that it -may be one of the papers which has, perhaps, fluttered out from -among the others, and in that way has escaped destruction. Beyond -the mention of pips, I do not see that it helps us much. I think -myself that it is a page from some private diary. The writing is -undoubtedly my uncle's." - -Holmes moved the lamp, and we both bent over the sheet of paper, -which showed by its ragged edge that it had indeed been torn from -a book. It was headed, "March, 1869," and beneath were the -following enigmatical notices: - -"4th. Hudson came. Same old platform. - -"7th. Set the pips on McCauley, Paramore, and - John Swain, of St. Augustine. - -"9th. McCauley cleared. - -"10th. John Swain cleared. - -"12th. Visited Paramore. All well." - -"Thank you!" said Holmes, folding up the paper and returning it -to our visitor. "And now you must on no account lose another -instant. We cannot spare time even to discuss what you have told -me. You must get home instantly and act." - -"What shall I do?" - -"There is but one thing to do. It must be done at once. You must -put this piece of paper which you have shown us into the brass -box which you have described. You must also put in a note to say -that all the other papers were burned by your uncle, and that -this is the only one which remains. You must assert that in such -words as will carry conviction with them. Having done this, you -must at once put the box out upon the sundial, as directed. Do -you understand?" - -"Entirely." - -"Do not think of revenge, or anything of the sort, at present. I -think that we may gain that by means of the law; but we have our -web to weave, while theirs is already woven. The first -consideration is to remove the pressing danger which threatens -you. The second is to clear up the mystery and to punish the -guilty parties." - -"I thank you," said the young man, rising and pulling on his -overcoat. "You have given me fresh life and hope. I shall -certainly do as you advise." - -"Do not lose an instant. And, above all, take care of yourself in -the meanwhile, for I do not think that there can be a doubt that -you are threatened by a very real and imminent danger. How do you -go back?" - -"By train from Waterloo." - -"It is not yet nine. The streets will be crowded, so I trust that -you may be in safety. And yet you cannot guard yourself too -closely." - -"I am armed." - -"That is well. To-morrow I shall set to work upon your case." - -"I shall see you at Horsham, then?" - -"No, your secret lies in London. It is there that I shall seek -it." - -"Then I shall call upon you in a day, or in two days, with news -as to the box and the papers. I shall take your advice in every -particular." He shook hands with us and took his leave. Outside -the wind still screamed and the rain splashed and pattered -against the windows. This strange, wild story seemed to have come -to us from amid the mad elements--blown in upon us like a sheet -of sea-weed in a gale--and now to have been reabsorbed by them -once more. - -Sherlock Holmes sat for some time in silence, with his head sunk -forward and his eyes bent upon the red glow of the fire. Then he -lit his pipe, and leaning back in his chair he watched the blue -smoke-rings as they chased each other up to the ceiling. - -"I think, Watson," he remarked at last, "that of all our cases we -have had none more fantastic than this." - -"Save, perhaps, the Sign of Four." - -"Well, yes. Save, perhaps, that. And yet this John Openshaw seems -to me to be walking amid even greater perils than did the -Sholtos." - -"But have you," I asked, "formed any definite conception as to -what these perils are?" - -"There can be no question as to their nature," he answered. - -"Then what are they? Who is this K. K. K., and why does he pursue -this unhappy family?" - -Sherlock Holmes closed his eyes and placed his elbows upon the -arms of his chair, with his finger-tips together. "The ideal -reasoner," he remarked, "would, when he had once been shown a -single fact in all its bearings, deduce from it not only all the -chain of events which led up to it but also all the results which -would follow from it. As Cuvier could correctly describe a whole -animal by the contemplation of a single bone, so the observer who -has thoroughly understood one link in a series of incidents -should be able to accurately state all the other ones, both -before and after. We have not yet grasped the results which the -reason alone can attain to. Problems may be solved in the study -which have baffled all those who have sought a solution by the -aid of their senses. To carry the art, however, to its highest -pitch, it is necessary that the reasoner should be able to -utilise all the facts which have come to his knowledge; and this -in itself implies, as you will readily see, a possession of all -knowledge, which, even in these days of free education and -encyclopaedias, is a somewhat rare accomplishment. It is not so -impossible, however, that a man should possess all knowledge -which is likely to be useful to him in his work, and this I have -endeavoured in my case to do. If I remember rightly, you on one -occasion, in the early days of our friendship, defined my limits -in a very precise fashion." - -"Yes," I answered, laughing. "It was a singular document. -Philosophy, astronomy, and politics were marked at zero, I -remember. Botany variable, geology profound as regards the -mud-stains from any region within fifty miles of town, chemistry -eccentric, anatomy unsystematic, sensational literature and crime -records unique, violin-player, boxer, swordsman, lawyer, and -self-poisoner by cocaine and tobacco. Those, I think, were the -main points of my analysis." - -Holmes grinned at the last item. "Well," he said, "I say now, as -I said then, that a man should keep his little brain-attic -stocked with all the furniture that he is likely to use, and the -rest he can put away in the lumber-room of his library, where he -can get it if he wants it. Now, for such a case as the one which -has been submitted to us to-night, we need certainly to muster -all our resources. Kindly hand me down the letter K of the -'American Encyclopaedia' which stands upon the shelf beside you. -Thank you. Now let us consider the situation and see what may be -deduced from it. In the first place, we may start with a strong -presumption that Colonel Openshaw had some very strong reason for -leaving America. Men at his time of life do not change all their -habits and exchange willingly the charming climate of Florida for -the lonely life of an English provincial town. His extreme love -of solitude in England suggests the idea that he was in fear of -someone or something, so we may assume as a working hypothesis -that it was fear of someone or something which drove him from -America. As to what it was he feared, we can only deduce that by -considering the formidable letters which were received by himself -and his successors. Did you remark the postmarks of those -letters?" - -"The first was from Pondicherry, the second from Dundee, and the -third from London." - -"From East London. What do you deduce from that?" - -"They are all seaports. That the writer was on board of a ship." - -"Excellent. We have already a clue. There can be no doubt that -the probability--the strong probability--is that the writer was -on board of a ship. And now let us consider another point. In the -case of Pondicherry, seven weeks elapsed between the threat and -its fulfilment, in Dundee it was only some three or four days. -Does that suggest anything?" - -"A greater distance to travel." - -"But the letter had also a greater distance to come." - -"Then I do not see the point." - -"There is at least a presumption that the vessel in which the man -or men are is a sailing-ship. It looks as if they always send -their singular warning or token before them when starting upon -their mission. You see how quickly the deed followed the sign -when it came from Dundee. If they had come from Pondicherry in a -steamer they would have arrived almost as soon as their letter. -But, as a matter of fact, seven weeks elapsed. I think that those -seven weeks represented the difference between the mail-boat which -brought the letter and the sailing vessel which brought the -writer." - -"It is possible." - -"More than that. It is probable. And now you see the deadly -urgency of this new case, and why I urged young Openshaw to -caution. The blow has always fallen at the end of the time which -it would take the senders to travel the distance. But this one -comes from London, and therefore we cannot count upon delay." - -"Good God!" I cried. "What can it mean, this relentless -persecution?" - -"The papers which Openshaw carried are obviously of vital -importance to the person or persons in the sailing-ship. I think -that it is quite clear that there must be more than one of them. -A single man could not have carried out two deaths in such a way -as to deceive a coroner's jury. There must have been several in -it, and they must have been men of resource and determination. -Their papers they mean to have, be the holder of them who it may. -In this way you see K. K. K. ceases to be the initials of an -individual and becomes the badge of a society." - -"But of what society?" - -"Have you never--" said Sherlock Holmes, bending forward and -sinking his voice--"have you never heard of the Ku Klux Klan?" - -"I never have." - -Holmes turned over the leaves of the book upon his knee. "Here it -is," said he presently: - -"'Ku Klux Klan. A name derived from the fanciful resemblance to -the sound produced by cocking a rifle. This terrible secret -society was formed by some ex-Confederate soldiers in the -Southern states after the Civil War, and it rapidly formed local -branches in different parts of the country, notably in Tennessee, -Louisiana, the Carolinas, Georgia, and Florida. Its power was -used for political purposes, principally for the terrorising of -the negro voters and the murdering and driving from the country -of those who were opposed to its views. Its outrages were usually -preceded by a warning sent to the marked man in some fantastic -but generally recognised shape--a sprig of oak-leaves in some -parts, melon seeds or orange pips in others. On receiving this -the victim might either openly abjure his former ways, or might -fly from the country. If he braved the matter out, death would -unfailingly come upon him, and usually in some strange and -unforeseen manner. So perfect was the organisation of the -society, and so systematic its methods, that there is hardly a -case upon record where any man succeeded in braving it with -impunity, or in which any of its outrages were traced home to the -perpetrators. For some years the organisation flourished in spite -of the efforts of the United States government and of the better -classes of the community in the South. Eventually, in the year -1869, the movement rather suddenly collapsed, although there have -been sporadic outbreaks of the same sort since that date.' - -"You will observe," said Holmes, laying down the volume, "that -the sudden breaking up of the society was coincident with the -disappearance of Openshaw from America with their papers. It may -well have been cause and effect. It is no wonder that he and his -family have some of the more implacable spirits upon their track. -You can understand that this register and diary may implicate -some of the first men in the South, and that there may be many -who will not sleep easy at night until it is recovered." - -"Then the page we have seen--" - -"Is such as we might expect. It ran, if I remember right, 'sent -the pips to A, B, and C'--that is, sent the society's warning to -them. Then there are successive entries that A and B cleared, or -left the country, and finally that C was visited, with, I fear, a -sinister result for C. Well, I think, Doctor, that we may let -some light into this dark place, and I believe that the only -chance young Openshaw has in the meantime is to do what I have -told him. There is nothing more to be said or to be done -to-night, so hand me over my violin and let us try to forget for -half an hour the miserable weather and the still more miserable -ways of our fellow-men." - - -It had cleared in the morning, and the sun was shining with a -subdued brightness through the dim veil which hangs over the -great city. Sherlock Holmes was already at breakfast when I came -down. - -"You will excuse me for not waiting for you," said he; "I have, I -foresee, a very busy day before me in looking into this case of -young Openshaw's." - -"What steps will you take?" I asked. - -"It will very much depend upon the results of my first inquiries. -I may have to go down to Horsham, after all." - -"You will not go there first?" - -"No, I shall commence with the City. Just ring the bell and the -maid will bring up your coffee." - -As I waited, I lifted the unopened newspaper from the table and -glanced my eye over it. It rested upon a heading which sent a -chill to my heart. - -"Holmes," I cried, "you are too late." - -"Ah!" said he, laying down his cup, "I feared as much. How was it -done?" He spoke calmly, but I could see that he was deeply moved. - -"My eye caught the name of Openshaw, and the heading 'Tragedy -Near Waterloo Bridge.' Here is the account: - -"Between nine and ten last night Police-Constable Cook, of the H -Division, on duty near Waterloo Bridge, heard a cry for help and -a splash in the water. The night, however, was extremely dark and -stormy, so that, in spite of the help of several passers-by, it -was quite impossible to effect a rescue. The alarm, however, was -given, and, by the aid of the water-police, the body was -eventually recovered. It proved to be that of a young gentleman -whose name, as it appears from an envelope which was found in his -pocket, was John Openshaw, and whose residence is near Horsham. -It is conjectured that he may have been hurrying down to catch -the last train from Waterloo Station, and that in his haste and -the extreme darkness he missed his path and walked over the edge -of one of the small landing-places for river steamboats. The body -exhibited no traces of violence, and there can be no doubt that -the deceased had been the victim of an unfortunate accident, -which should have the effect of calling the attention of the -authorities to the condition of the riverside landing-stages." - -We sat in silence for some minutes, Holmes more depressed and -shaken than I had ever seen him. - -"That hurts my pride, Watson," he said at last. "It is a petty -feeling, no doubt, but it hurts my pride. It becomes a personal -matter with me now, and, if God sends me health, I shall set my -hand upon this gang. That he should come to me for help, and that -I should send him away to his death--!" He sprang from his chair -and paced about the room in uncontrollable agitation, with a -flush upon his sallow cheeks and a nervous clasping and -unclasping of his long thin hands. - -"They must be cunning devils," he exclaimed at last. "How could -they have decoyed him down there? The Embankment is not on the -direct line to the station. The bridge, no doubt, was too -crowded, even on such a night, for their purpose. Well, Watson, -we shall see who will win in the long run. I am going out now!" - -"To the police?" - -"No; I shall be my own police. When I have spun the web they may -take the flies, but not before." - -All day I was engaged in my professional work, and it was late in -the evening before I returned to Baker Street. Sherlock Holmes -had not come back yet. It was nearly ten o'clock before he -entered, looking pale and worn. He walked up to the sideboard, -and tearing a piece from the loaf he devoured it voraciously, -washing it down with a long draught of water. - -"You are hungry," I remarked. - -"Starving. It had escaped my memory. I have had nothing since -breakfast." - -"Nothing?" - -"Not a bite. I had no time to think of it." - -"And how have you succeeded?" - -"Well." - -"You have a clue?" - -"I have them in the hollow of my hand. Young Openshaw shall not -long remain unavenged. Why, Watson, let us put their own devilish -trade-mark upon them. It is well thought of!" - -"What do you mean?" - -He took an orange from the cupboard, and tearing it to pieces he -squeezed out the pips upon the table. Of these he took five and -thrust them into an envelope. On the inside of the flap he wrote -"S. H. for J. O." Then he sealed it and addressed it to "Captain -James Calhoun, Barque 'Lone Star,' Savannah, Georgia." - -"That will await him when he enters port," said he, chuckling. -"It may give him a sleepless night. He will find it as sure a -precursor of his fate as Openshaw did before him." - -"And who is this Captain Calhoun?" - -"The leader of the gang. I shall have the others, but he first." - -"How did you trace it, then?" - -He took a large sheet of paper from his pocket, all covered with -dates and names. - -"I have spent the whole day," said he, "over Lloyd's registers -and files of the old papers, following the future career of every -vessel which touched at Pondicherry in January and February in -'83. There were thirty-six ships of fair tonnage which were -reported there during those months. Of these, one, the 'Lone Star,' -instantly attracted my attention, since, although it was reported -as having cleared from London, the name is that which is given to -one of the states of the Union." - -"Texas, I think." - -"I was not and am not sure which; but I knew that the ship must -have an American origin." - -"What then?" - -"I searched the Dundee records, and when I found that the barque -'Lone Star' was there in January, '85, my suspicion became a -certainty. I then inquired as to the vessels which lay at present -in the port of London." - -"Yes?" - -"The 'Lone Star' had arrived here last week. I went down to the -Albert Dock and found that she had been taken down the river by -the early tide this morning, homeward bound to Savannah. I wired -to Gravesend and learned that she had passed some time ago, and -as the wind is easterly I have no doubt that she is now past the -Goodwins and not very far from the Isle of Wight." - -"What will you do, then?" - -"Oh, I have my hand upon him. He and the two mates, are as I -learn, the only native-born Americans in the ship. The others are -Finns and Germans. I know, also, that they were all three away -from the ship last night. I had it from the stevedore who has -been loading their cargo. By the time that their sailing-ship -reaches Savannah the mail-boat will have carried this letter, and -the cable will have informed the police of Savannah that these -three gentlemen are badly wanted here upon a charge of murder." - -There is ever a flaw, however, in the best laid of human plans, -and the murderers of John Openshaw were never to receive the -orange pips which would show them that another, as cunning and as -resolute as themselves, was upon their track. Very long and very -severe were the equinoctial gales that year. We waited long for -news of the "Lone Star" of Savannah, but none ever reached us. We -did at last hear that somewhere far out in the Atlantic a -shattered stern-post of a boat was seen swinging in the trough -of a wave, with the letters "L. S." carved upon it, and that is -all which we shall ever know of the fate of the "Lone Star." - - - -ADVENTURE VI. THE MAN WITH THE TWISTED LIP - -Isa Whitney, brother of the late Elias Whitney, D.D., Principal -of the Theological College of St. George's, was much addicted to -opium. The habit grew upon him, as I understand, from some -foolish freak when he was at college; for having read De -Quincey's description of his dreams and sensations, he had -drenched his tobacco with laudanum in an attempt to produce the -same effects. He found, as so many more have done, that the -practice is easier to attain than to get rid of, and for many -years he continued to be a slave to the drug, an object of -mingled horror and pity to his friends and relatives. I can see -him now, with yellow, pasty face, drooping lids, and pin-point -pupils, all huddled in a chair, the wreck and ruin of a noble -man. - -One night--it was in June, '89--there came a ring to my bell, -about the hour when a man gives his first yawn and glances at the -clock. I sat up in my chair, and my wife laid her needle-work -down in her lap and made a little face of disappointment. - -"A patient!" said she. "You'll have to go out." - -I groaned, for I was newly come back from a weary day. - -We heard the door open, a few hurried words, and then quick steps -upon the linoleum. Our own door flew open, and a lady, clad in -some dark-coloured stuff, with a black veil, entered the room. - -"You will excuse my calling so late," she began, and then, -suddenly losing her self-control, she ran forward, threw her arms -about my wife's neck, and sobbed upon her shoulder. "Oh, I'm in -such trouble!" she cried; "I do so want a little help." - -"Why," said my wife, pulling up her veil, "it is Kate Whitney. -How you startled me, Kate! I had not an idea who you were when -you came in." - -"I didn't know what to do, so I came straight to you." That was -always the way. Folk who were in grief came to my wife like birds -to a light-house. - -"It was very sweet of you to come. Now, you must have some wine -and water, and sit here comfortably and tell us all about it. Or -should you rather that I sent James off to bed?" - -"Oh, no, no! I want the doctor's advice and help, too. It's about -Isa. He has not been home for two days. I am so frightened about -him!" - -It was not the first time that she had spoken to us of her -husband's trouble, to me as a doctor, to my wife as an old friend -and school companion. We soothed and comforted her by such words -as we could find. Did she know where her husband was? Was it -possible that we could bring him back to her? - -It seems that it was. She had the surest information that of late -he had, when the fit was on him, made use of an opium den in the -farthest east of the City. Hitherto his orgies had always been -confined to one day, and he had come back, twitching and -shattered, in the evening. But now the spell had been upon him -eight-and-forty hours, and he lay there, doubtless among the -dregs of the docks, breathing in the poison or sleeping off the -effects. There he was to be found, she was sure of it, at the Bar -of Gold, in Upper Swandam Lane. But what was she to do? How could -she, a young and timid woman, make her way into such a place and -pluck her husband out from among the ruffians who surrounded him? - -There was the case, and of course there was but one way out of -it. Might I not escort her to this place? And then, as a second -thought, why should she come at all? I was Isa Whitney's medical -adviser, and as such I had influence over him. I could manage it -better if I were alone. I promised her on my word that I would -send him home in a cab within two hours if he were indeed at the -address which she had given me. And so in ten minutes I had left -my armchair and cheery sitting-room behind me, and was speeding -eastward in a hansom on a strange errand, as it seemed to me at -the time, though the future only could show how strange it was to -be. - -But there was no great difficulty in the first stage of my -adventure. Upper Swandam Lane is a vile alley lurking behind the -high wharves which line the north side of the river to the east -of London Bridge. Between a slop-shop and a gin-shop, approached -by a steep flight of steps leading down to a black gap like the -mouth of a cave, I found the den of which I was in search. -Ordering my cab to wait, I passed down the steps, worn hollow in -the centre by the ceaseless tread of drunken feet; and by the -light of a flickering oil-lamp above the door I found the latch -and made my way into a long, low room, thick and heavy with the -brown opium smoke, and terraced with wooden berths, like the -forecastle of an emigrant ship. - -Through the gloom one could dimly catch a glimpse of bodies lying -in strange fantastic poses, bowed shoulders, bent knees, heads -thrown back, and chins pointing upward, with here and there a -dark, lack-lustre eye turned upon the newcomer. Out of the black -shadows there glimmered little red circles of light, now bright, -now faint, as the burning poison waxed or waned in the bowls of -the metal pipes. The most lay silent, but some muttered to -themselves, and others talked together in a strange, low, -monotonous voice, their conversation coming in gushes, and then -suddenly tailing off into silence, each mumbling out his own -thoughts and paying little heed to the words of his neighbour. At -the farther end was a small brazier of burning charcoal, beside -which on a three-legged wooden stool there sat a tall, thin old -man, with his jaw resting upon his two fists, and his elbows upon -his knees, staring into the fire. - -As I entered, a sallow Malay attendant had hurried up with a pipe -for me and a supply of the drug, beckoning me to an empty berth. - -"Thank you. I have not come to stay," said I. "There is a friend -of mine here, Mr. Isa Whitney, and I wish to speak with him." - -There was a movement and an exclamation from my right, and -peering through the gloom, I saw Whitney, pale, haggard, and -unkempt, staring out at me. - -"My God! It's Watson," said he. He was in a pitiable state of -reaction, with every nerve in a twitter. "I say, Watson, what -o'clock is it?" - -"Nearly eleven." - -"Of what day?" - -"Of Friday, June 19th." - -"Good heavens! I thought it was Wednesday. It is Wednesday. What -d'you want to frighten a chap for?" He sank his face onto his -arms and began to sob in a high treble key. - -"I tell you that it is Friday, man. Your wife has been waiting -this two days for you. You should be ashamed of yourself!" - -"So I am. But you've got mixed, Watson, for I have only been here -a few hours, three pipes, four pipes--I forget how many. But I'll -go home with you. I wouldn't frighten Kate--poor little Kate. -Give me your hand! Have you a cab?" - -"Yes, I have one waiting." - -"Then I shall go in it. But I must owe something. Find what I -owe, Watson. I am all off colour. I can do nothing for myself." - -I walked down the narrow passage between the double row of -sleepers, holding my breath to keep out the vile, stupefying -fumes of the drug, and looking about for the manager. As I passed -the tall man who sat by the brazier I felt a sudden pluck at my -skirt, and a low voice whispered, "Walk past me, and then look -back at me." The words fell quite distinctly upon my ear. I -glanced down. They could only have come from the old man at my -side, and yet he sat now as absorbed as ever, very thin, very -wrinkled, bent with age, an opium pipe dangling down from between -his knees, as though it had dropped in sheer lassitude from his -fingers. I took two steps forward and looked back. It took all my -self-control to prevent me from breaking out into a cry of -astonishment. He had turned his back so that none could see him -but I. His form had filled out, his wrinkles were gone, the dull -eyes had regained their fire, and there, sitting by the fire and -grinning at my surprise, was none other than Sherlock Holmes. He -made a slight motion to me to approach him, and instantly, as he -turned his face half round to the company once more, subsided -into a doddering, loose-lipped senility. - -"Holmes!" I whispered, "what on earth are you doing in this den?" - -"As low as you can," he answered; "I have excellent ears. If you -would have the great kindness to get rid of that sottish friend -of yours I should be exceedingly glad to have a little talk with -you." - -"I have a cab outside." - -"Then pray send him home in it. You may safely trust him, for he -appears to be too limp to get into any mischief. I should -recommend you also to send a note by the cabman to your wife to -say that you have thrown in your lot with me. If you will wait -outside, I shall be with you in five minutes." - -It was difficult to refuse any of Sherlock Holmes' requests, for -they were always so exceedingly definite, and put forward with -such a quiet air of mastery. I felt, however, that when Whitney -was once confined in the cab my mission was practically -accomplished; and for the rest, I could not wish anything better -than to be associated with my friend in one of those singular -adventures which were the normal condition of his existence. In a -few minutes I had written my note, paid Whitney's bill, led him -out to the cab, and seen him driven through the darkness. In a -very short time a decrepit figure had emerged from the opium den, -and I was walking down the street with Sherlock Holmes. For two -streets he shuffled along with a bent back and an uncertain foot. -Then, glancing quickly round, he straightened himself out and -burst into a hearty fit of laughter. - -"I suppose, Watson," said he, "that you imagine that I have added -opium-smoking to cocaine injections, and all the other little -weaknesses on which you have favoured me with your medical -views." - -"I was certainly surprised to find you there." - -"But not more so than I to find you." - -"I came to find a friend." - -"And I to find an enemy." - -"An enemy?" - -"Yes; one of my natural enemies, or, shall I say, my natural -prey. Briefly, Watson, I am in the midst of a very remarkable -inquiry, and I have hoped to find a clue in the incoherent -ramblings of these sots, as I have done before now. Had I been -recognised in that den my life would not have been worth an -hour's purchase; for I have used it before now for my own -purposes, and the rascally Lascar who runs it has sworn to have -vengeance upon me. There is a trap-door at the back of that -building, near the corner of Paul's Wharf, which could tell some -strange tales of what has passed through it upon the moonless -nights." - -"What! You do not mean bodies?" - -"Ay, bodies, Watson. We should be rich men if we had 1000 pounds -for every poor devil who has been done to death in that den. It -is the vilest murder-trap on the whole riverside, and I fear that -Neville St. Clair has entered it never to leave it more. But our -trap should be here." He put his two forefingers between his -teeth and whistled shrilly--a signal which was answered by a -similar whistle from the distance, followed shortly by the rattle -of wheels and the clink of horses' hoofs. - -"Now, Watson," said Holmes, as a tall dog-cart dashed up through -the gloom, throwing out two golden tunnels of yellow light from -its side lanterns. "You'll come with me, won't you?" - -"If I can be of use." - -"Oh, a trusty comrade is always of use; and a chronicler still -more so. My room at The Cedars is a double-bedded one." - -"The Cedars?" - -"Yes; that is Mr. St. Clair's house. I am staying there while I -conduct the inquiry." - -"Where is it, then?" - -"Near Lee, in Kent. We have a seven-mile drive before us." - -"But I am all in the dark." - -"Of course you are. You'll know all about it presently. Jump up -here. All right, John; we shall not need you. Here's half a -crown. Look out for me to-morrow, about eleven. Give her her -head. So long, then!" - -He flicked the horse with his whip, and we dashed away through -the endless succession of sombre and deserted streets, which -widened gradually, until we were flying across a broad -balustraded bridge, with the murky river flowing sluggishly -beneath us. Beyond lay another dull wilderness of bricks and -mortar, its silence broken only by the heavy, regular footfall of -the policeman, or the songs and shouts of some belated party of -revellers. A dull wrack was drifting slowly across the sky, and a -star or two twinkled dimly here and there through the rifts of -the clouds. Holmes drove in silence, with his head sunk upon his -breast, and the air of a man who is lost in thought, while I sat -beside him, curious to learn what this new quest might be which -seemed to tax his powers so sorely, and yet afraid to break in -upon the current of his thoughts. We had driven several miles, -and were beginning to get to the fringe of the belt of suburban -villas, when he shook himself, shrugged his shoulders, and lit up -his pipe with the air of a man who has satisfied himself that he -is acting for the best. - -"You have a grand gift of silence, Watson," said he. "It makes -you quite invaluable as a companion. 'Pon my word, it is a great -thing for me to have someone to talk to, for my own thoughts are -not over-pleasant. I was wondering what I should say to this dear -little woman to-night when she meets me at the door." - -"You forget that I know nothing about it." - -"I shall just have time to tell you the facts of the case before -we get to Lee. It seems absurdly simple, and yet, somehow I can -get nothing to go upon. There's plenty of thread, no doubt, but I -can't get the end of it into my hand. Now, I'll state the case -clearly and concisely to you, Watson, and maybe you can see a -spark where all is dark to me." - -"Proceed, then." - -"Some years ago--to be definite, in May, 1884--there came to Lee -a gentleman, Neville St. Clair by name, who appeared to have -plenty of money. He took a large villa, laid out the grounds very -nicely, and lived generally in good style. By degrees he made -friends in the neighbourhood, and in 1887 he married the daughter -of a local brewer, by whom he now has two children. He had no -occupation, but was interested in several companies and went into -town as a rule in the morning, returning by the 5:14 from Cannon -Street every night. Mr. St. Clair is now thirty-seven years of -age, is a man of temperate habits, a good husband, a very -affectionate father, and a man who is popular with all who know -him. I may add that his whole debts at the present moment, as far -as we have been able to ascertain, amount to 88 pounds 10s., while -he has 220 pounds standing to his credit in the Capital and -Counties Bank. There is no reason, therefore, to think that money -troubles have been weighing upon his mind. - -"Last Monday Mr. Neville St. Clair went into town rather earlier -than usual, remarking before he started that he had two important -commissions to perform, and that he would bring his little boy -home a box of bricks. Now, by the merest chance, his wife -received a telegram upon this same Monday, very shortly after his -departure, to the effect that a small parcel of considerable -value which she had been expecting was waiting for her at the -offices of the Aberdeen Shipping Company. Now, if you are well up -in your London, you will know that the office of the company is -in Fresno Street, which branches out of Upper Swandam Lane, where -you found me to-night. Mrs. St. Clair had her lunch, started for -the City, did some shopping, proceeded to the company's office, -got her packet, and found herself at exactly 4:35 walking through -Swandam Lane on her way back to the station. Have you followed me -so far?" - -"It is very clear." - -"If you remember, Monday was an exceedingly hot day, and Mrs. St. -Clair walked slowly, glancing about in the hope of seeing a cab, -as she did not like the neighbourhood in which she found herself. -While she was walking in this way down Swandam Lane, she suddenly -heard an ejaculation or cry, and was struck cold to see her -husband looking down at her and, as it seemed to her, beckoning -to her from a second-floor window. The window was open, and she -distinctly saw his face, which she describes as being terribly -agitated. He waved his hands frantically to her, and then -vanished from the window so suddenly that it seemed to her that -he had been plucked back by some irresistible force from behind. -One singular point which struck her quick feminine eye was that -although he wore some dark coat, such as he had started to town -in, he had on neither collar nor necktie. - -"Convinced that something was amiss with him, she rushed down the -steps--for the house was none other than the opium den in which -you found me to-night--and running through the front room she -attempted to ascend the stairs which led to the first floor. At -the foot of the stairs, however, she met this Lascar scoundrel of -whom I have spoken, who thrust her back and, aided by a Dane, who -acts as assistant there, pushed her out into the street. Filled -with the most maddening doubts and fears, she rushed down the -lane and, by rare good-fortune, met in Fresno Street a number of -constables with an inspector, all on their way to their beat. The -inspector and two men accompanied her back, and in spite of the -continued resistance of the proprietor, they made their way to -the room in which Mr. St. Clair had last been seen. There was no -sign of him there. In fact, in the whole of that floor there was -no one to be found save a crippled wretch of hideous aspect, who, -it seems, made his home there. Both he and the Lascar stoutly -swore that no one else had been in the front room during the -afternoon. So determined was their denial that the inspector was -staggered, and had almost come to believe that Mrs. St. Clair had -been deluded when, with a cry, she sprang at a small deal box -which lay upon the table and tore the lid from it. Out there fell -a cascade of children's bricks. It was the toy which he had -promised to bring home. - -"This discovery, and the evident confusion which the cripple -showed, made the inspector realise that the matter was serious. -The rooms were carefully examined, and results all pointed to an -abominable crime. The front room was plainly furnished as a -sitting-room and led into a small bedroom, which looked out upon -the back of one of the wharves. Between the wharf and the bedroom -window is a narrow strip, which is dry at low tide but is covered -at high tide with at least four and a half feet of water. The -bedroom window was a broad one and opened from below. On -examination traces of blood were to be seen upon the windowsill, -and several scattered drops were visible upon the wooden floor of -the bedroom. Thrust away behind a curtain in the front room were -all the clothes of Mr. Neville St. Clair, with the exception of -his coat. His boots, his socks, his hat, and his watch--all were -there. There were no signs of violence upon any of these -garments, and there were no other traces of Mr. Neville St. -Clair. Out of the window he must apparently have gone for no -other exit could be discovered, and the ominous bloodstains upon -the sill gave little promise that he could save himself by -swimming, for the tide was at its very highest at the moment of -the tragedy. - -"And now as to the villains who seemed to be immediately -implicated in the matter. The Lascar was known to be a man of the -vilest antecedents, but as, by Mrs. St. Clair's story, he was -known to have been at the foot of the stair within a very few -seconds of her husband's appearance at the window, he could -hardly have been more than an accessory to the crime. His defence -was one of absolute ignorance, and he protested that he had no -knowledge as to the doings of Hugh Boone, his lodger, and that he -could not account in any way for the presence of the missing -gentleman's clothes. - -"So much for the Lascar manager. Now for the sinister cripple who -lives upon the second floor of the opium den, and who was -certainly the last human being whose eyes rested upon Neville St. -Clair. His name is Hugh Boone, and his hideous face is one which -is familiar to every man who goes much to the City. He is a -professional beggar, though in order to avoid the police -regulations he pretends to a small trade in wax vestas. Some -little distance down Threadneedle Street, upon the left-hand -side, there is, as you may have remarked, a small angle in the -wall. Here it is that this creature takes his daily seat, -cross-legged with his tiny stock of matches on his lap, and as he -is a piteous spectacle a small rain of charity descends into the -greasy leather cap which lies upon the pavement beside him. I -have watched the fellow more than once before ever I thought of -making his professional acquaintance, and I have been surprised -at the harvest which he has reaped in a short time. His -appearance, you see, is so remarkable that no one can pass him -without observing him. A shock of orange hair, a pale face -disfigured by a horrible scar, which, by its contraction, has -turned up the outer edge of his upper lip, a bulldog chin, and a -pair of very penetrating dark eyes, which present a singular -contrast to the colour of his hair, all mark him out from amid -the common crowd of mendicants and so, too, does his wit, for he -is ever ready with a reply to any piece of chaff which may be -thrown at him by the passers-by. This is the man whom we now -learn to have been the lodger at the opium den, and to have been -the last man to see the gentleman of whom we are in quest." - -"But a cripple!" said I. "What could he have done single-handed -against a man in the prime of life?" - -"He is a cripple in the sense that he walks with a limp; but in -other respects he appears to be a powerful and well-nurtured man. -Surely your medical experience would tell you, Watson, that -weakness in one limb is often compensated for by exceptional -strength in the others." - -"Pray continue your narrative." - -"Mrs. St. Clair had fainted at the sight of the blood upon the -window, and she was escorted home in a cab by the police, as her -presence could be of no help to them in their investigations. -Inspector Barton, who had charge of the case, made a very careful -examination of the premises, but without finding anything which -threw any light upon the matter. One mistake had been made in not -arresting Boone instantly, as he was allowed some few minutes -during which he might have communicated with his friend the -Lascar, but this fault was soon remedied, and he was seized and -searched, without anything being found which could incriminate -him. There were, it is true, some blood-stains upon his right -shirt-sleeve, but he pointed to his ring-finger, which had been -cut near the nail, and explained that the bleeding came from -there, adding that he had been to the window not long before, and -that the stains which had been observed there came doubtless from -the same source. He denied strenuously having ever seen Mr. -Neville St. Clair and swore that the presence of the clothes in -his room was as much a mystery to him as to the police. As to -Mrs. St. Clair's assertion that she had actually seen her husband -at the window, he declared that she must have been either mad or -dreaming. He was removed, loudly protesting, to the -police-station, while the inspector remained upon the premises in -the hope that the ebbing tide might afford some fresh clue. - -"And it did, though they hardly found upon the mud-bank what they -had feared to find. It was Neville St. Clair's coat, and not -Neville St. Clair, which lay uncovered as the tide receded. And -what do you think they found in the pockets?" - -"I cannot imagine." - -"No, I don't think you would guess. Every pocket stuffed with -pennies and half-pennies--421 pennies and 270 half-pennies. It -was no wonder that it had not been swept away by the tide. But a -human body is a different matter. There is a fierce eddy between -the wharf and the house. It seemed likely enough that the -weighted coat had remained when the stripped body had been sucked -away into the river." - -"But I understand that all the other clothes were found in the -room. Would the body be dressed in a coat alone?" - -"No, sir, but the facts might be met speciously enough. Suppose -that this man Boone had thrust Neville St. Clair through the -window, there is no human eye which could have seen the deed. -What would he do then? It would of course instantly strike him -that he must get rid of the tell-tale garments. He would seize -the coat, then, and be in the act of throwing it out, when it -would occur to him that it would swim and not sink. He has little -time, for he has heard the scuffle downstairs when the wife tried -to force her way up, and perhaps he has already heard from his -Lascar confederate that the police are hurrying up the street. -There is not an instant to be lost. He rushes to some secret -hoard, where he has accumulated the fruits of his beggary, and he -stuffs all the coins upon which he can lay his hands into the -pockets to make sure of the coat's sinking. He throws it out, and -would have done the same with the other garments had not he heard -the rush of steps below, and only just had time to close the -window when the police appeared." - -"It certainly sounds feasible." - -"Well, we will take it as a working hypothesis for want of a -better. Boone, as I have told you, was arrested and taken to the -station, but it could not be shown that there had ever before -been anything against him. He had for years been known as a -professional beggar, but his life appeared to have been a very -quiet and innocent one. There the matter stands at present, and -the questions which have to be solved--what Neville St. Clair was -doing in the opium den, what happened to him when there, where is -he now, and what Hugh Boone had to do with his disappearance--are -all as far from a solution as ever. I confess that I cannot -recall any case within my experience which looked at the first -glance so simple and yet which presented such difficulties." - -While Sherlock Holmes had been detailing this singular series of -events, we had been whirling through the outskirts of the great -town until the last straggling houses had been left behind, and -we rattled along with a country hedge upon either side of us. -Just as he finished, however, we drove through two scattered -villages, where a few lights still glimmered in the windows. - -"We are on the outskirts of Lee," said my companion. "We have -touched on three English counties in our short drive, starting in -Middlesex, passing over an angle of Surrey, and ending in Kent. -See that light among the trees? That is The Cedars, and beside -that lamp sits a woman whose anxious ears have already, I have -little doubt, caught the clink of our horse's feet." - -"But why are you not conducting the case from Baker Street?" I -asked. - -"Because there are many inquiries which must be made out here. -Mrs. St. Clair has most kindly put two rooms at my disposal, and -you may rest assured that she will have nothing but a welcome for -my friend and colleague. I hate to meet her, Watson, when I have -no news of her husband. Here we are. Whoa, there, whoa!" - -We had pulled up in front of a large villa which stood within its -own grounds. A stable-boy had run out to the horse's head, and -springing down, I followed Holmes up the small, winding -gravel-drive which led to the house. As we approached, the door -flew open, and a little blonde woman stood in the opening, clad -in some sort of light mousseline de soie, with a touch of fluffy -pink chiffon at her neck and wrists. She stood with her figure -outlined against the flood of light, one hand upon the door, one -half-raised in her eagerness, her body slightly bent, her head -and face protruded, with eager eyes and parted lips, a standing -question. - -"Well?" she cried, "well?" And then, seeing that there were two -of us, she gave a cry of hope which sank into a groan as she saw -that my companion shook his head and shrugged his shoulders. - -"No good news?" - -"None." - -"No bad?" - -"No." - -"Thank God for that. But come in. You must be weary, for you have -had a long day." - -"This is my friend, Dr. Watson. He has been of most vital use to -me in several of my cases, and a lucky chance has made it -possible for me to bring him out and associate him with this -investigation." - -"I am delighted to see you," said she, pressing my hand warmly. -"You will, I am sure, forgive anything that may be wanting in our -arrangements, when you consider the blow which has come so -suddenly upon us." - -"My dear madam," said I, "I am an old campaigner, and if I were -not I can very well see that no apology is needed. If I can be of -any assistance, either to you or to my friend here, I shall be -indeed happy." - -"Now, Mr. Sherlock Holmes," said the lady as we entered a -well-lit dining-room, upon the table of which a cold supper had -been laid out, "I should very much like to ask you one or two -plain questions, to which I beg that you will give a plain -answer." - -"Certainly, madam." - -"Do not trouble about my feelings. I am not hysterical, nor given -to fainting. I simply wish to hear your real, real opinion." - -"Upon what point?" - -"In your heart of hearts, do you think that Neville is alive?" - -Sherlock Holmes seemed to be embarrassed by the question. -"Frankly, now!" she repeated, standing upon the rug and looking -keenly down at him as he leaned back in a basket-chair. - -"Frankly, then, madam, I do not." - -"You think that he is dead?" - -"I do." - -"Murdered?" - -"I don't say that. Perhaps." - -"And on what day did he meet his death?" - -"On Monday." - -"Then perhaps, Mr. Holmes, you will be good enough to explain how -it is that I have received a letter from him to-day." - -Sherlock Holmes sprang out of his chair as if he had been -galvanised. - -"What!" he roared. - -"Yes, to-day." She stood smiling, holding up a little slip of -paper in the air. - -"May I see it?" - -"Certainly." - -He snatched it from her in his eagerness, and smoothing it out -upon the table he drew over the lamp and examined it intently. I -had left my chair and was gazing at it over his shoulder. The -envelope was a very coarse one and was stamped with the Gravesend -postmark and with the date of that very day, or rather of the day -before, for it was considerably after midnight. - -"Coarse writing," murmured Holmes. "Surely this is not your -husband's writing, madam." - -"No, but the enclosure is." - -"I perceive also that whoever addressed the envelope had to go -and inquire as to the address." - -"How can you tell that?" - -"The name, you see, is in perfectly black ink, which has dried -itself. The rest is of the greyish colour, which shows that -blotting-paper has been used. If it had been written straight -off, and then blotted, none would be of a deep black shade. This -man has written the name, and there has then been a pause before -he wrote the address, which can only mean that he was not -familiar with it. It is, of course, a trifle, but there is -nothing so important as trifles. Let us now see the letter. Ha! -there has been an enclosure here!" - -"Yes, there was a ring. His signet-ring." - -"And you are sure that this is your husband's hand?" - -"One of his hands." - -"One?" - -"His hand when he wrote hurriedly. It is very unlike his usual -writing, and yet I know it well." - -"'Dearest do not be frightened. All will come well. There is a -huge error which it may take some little time to rectify. -Wait in patience.--NEVILLE.' Written in pencil upon the fly-leaf -of a book, octavo size, no water-mark. Hum! Posted to-day in -Gravesend by a man with a dirty thumb. Ha! And the flap has been -gummed, if I am not very much in error, by a person who had been -chewing tobacco. And you have no doubt that it is your husband's -hand, madam?" - -"None. Neville wrote those words." - -"And they were posted to-day at Gravesend. Well, Mrs. St. Clair, -the clouds lighten, though I should not venture to say that the -danger is over." - -"But he must be alive, Mr. Holmes." - -"Unless this is a clever forgery to put us on the wrong scent. -The ring, after all, proves nothing. It may have been taken from -him." - -"No, no; it is, it is his very own writing!" - -"Very well. It may, however, have been written on Monday and only -posted to-day." - -"That is possible." - -"If so, much may have happened between." - -"Oh, you must not discourage me, Mr. Holmes. I know that all is -well with him. There is so keen a sympathy between us that I -should know if evil came upon him. On the very day that I saw him -last he cut himself in the bedroom, and yet I in the dining-room -rushed upstairs instantly with the utmost certainty that -something had happened. Do you think that I would respond to such -a trifle and yet be ignorant of his death?" - -"I have seen too much not to know that the impression of a woman -may be more valuable than the conclusion of an analytical -reasoner. And in this letter you certainly have a very strong -piece of evidence to corroborate your view. But if your husband -is alive and able to write letters, why should he remain away -from you?" - -"I cannot imagine. It is unthinkable." - -"And on Monday he made no remarks before leaving you?" - -"No." - -"And you were surprised to see him in Swandam Lane?" - -"Very much so." - -"Was the window open?" - -"Yes." - -"Then he might have called to you?" - -"He might." - -"He only, as I understand, gave an inarticulate cry?" - -"Yes." - -"A call for help, you thought?" - -"Yes. He waved his hands." - -"But it might have been a cry of surprise. Astonishment at the -unexpected sight of you might cause him to throw up his hands?" - -"It is possible." - -"And you thought he was pulled back?" - -"He disappeared so suddenly." - -"He might have leaped back. You did not see anyone else in the -room?" - -"No, but this horrible man confessed to having been there, and -the Lascar was at the foot of the stairs." - -"Quite so. Your husband, as far as you could see, had his -ordinary clothes on?" - -"But without his collar or tie. I distinctly saw his bare -throat." - -"Had he ever spoken of Swandam Lane?" - -"Never." - -"Had he ever showed any signs of having taken opium?" - -"Never." - -"Thank you, Mrs. St. Clair. Those are the principal points about -which I wished to be absolutely clear. We shall now have a little -supper and then retire, for we may have a very busy day -to-morrow." - -A large and comfortable double-bedded room had been placed at our -disposal, and I was quickly between the sheets, for I was weary -after my night of adventure. Sherlock Holmes was a man, however, -who, when he had an unsolved problem upon his mind, would go for -days, and even for a week, without rest, turning it over, -rearranging his facts, looking at it from every point of view -until he had either fathomed it or convinced himself that his -data were insufficient. It was soon evident to me that he was now -preparing for an all-night sitting. He took off his coat and -waistcoat, put on a large blue dressing-gown, and then wandered -about the room collecting pillows from his bed and cushions from -the sofa and armchairs. With these he constructed a sort of -Eastern divan, upon which he perched himself cross-legged, with -an ounce of shag tobacco and a box of matches laid out in front -of him. In the dim light of the lamp I saw him sitting there, an -old briar pipe between his lips, his eyes fixed vacantly upon the -corner of the ceiling, the blue smoke curling up from him, -silent, motionless, with the light shining upon his strong-set -aquiline features. So he sat as I dropped off to sleep, and so he -sat when a sudden ejaculation caused me to wake up, and I found -the summer sun shining into the apartment. The pipe was still -between his lips, the smoke still curled upward, and the room was -full of a dense tobacco haze, but nothing remained of the heap of -shag which I had seen upon the previous night. - -"Awake, Watson?" he asked. - -"Yes." - -"Game for a morning drive?" - -"Certainly." - -"Then dress. No one is stirring yet, but I know where the -stable-boy sleeps, and we shall soon have the trap out." He -chuckled to himself as he spoke, his eyes twinkled, and he seemed -a different man to the sombre thinker of the previous night. - -As I dressed I glanced at my watch. It was no wonder that no one -was stirring. It was twenty-five minutes past four. I had hardly -finished when Holmes returned with the news that the boy was -putting in the horse. - -"I want to test a little theory of mine," said he, pulling on his -boots. "I think, Watson, that you are now standing in the -presence of one of the most absolute fools in Europe. I deserve -to be kicked from here to Charing Cross. But I think I have the -key of the affair now." - -"And where is it?" I asked, smiling. - -"In the bathroom," he answered. "Oh, yes, I am not joking," he -continued, seeing my look of incredulity. "I have just been -there, and I have taken it out, and I have got it in this -Gladstone bag. Come on, my boy, and we shall see whether it will -not fit the lock." - -We made our way downstairs as quietly as possible, and out into -the bright morning sunshine. In the road stood our horse and -trap, with the half-clad stable-boy waiting at the head. We both -sprang in, and away we dashed down the London Road. A few country -carts were stirring, bearing in vegetables to the metropolis, but -the lines of villas on either side were as silent and lifeless as -some city in a dream. - -"It has been in some points a singular case," said Holmes, -flicking the horse on into a gallop. "I confess that I have been -as blind as a mole, but it is better to learn wisdom late than -never to learn it at all." - -In town the earliest risers were just beginning to look sleepily -from their windows as we drove through the streets of the Surrey -side. Passing down the Waterloo Bridge Road we crossed over the -river, and dashing up Wellington Street wheeled sharply to the -right and found ourselves in Bow Street. Sherlock Holmes was well -known to the force, and the two constables at the door saluted -him. One of them held the horse's head while the other led us in. - -"Who is on duty?" asked Holmes. - -"Inspector Bradstreet, sir." - -"Ah, Bradstreet, how are you?" A tall, stout official had come -down the stone-flagged passage, in a peaked cap and frogged -jacket. "I wish to have a quiet word with you, Bradstreet." -"Certainly, Mr. Holmes. Step into my room here." It was a small, -office-like room, with a huge ledger upon the table, and a -telephone projecting from the wall. The inspector sat down at his -desk. - -"What can I do for you, Mr. Holmes?" - -"I called about that beggarman, Boone--the one who was charged -with being concerned in the disappearance of Mr. Neville St. -Clair, of Lee." - -"Yes. He was brought up and remanded for further inquiries." - -"So I heard. You have him here?" - -"In the cells." - -"Is he quiet?" - -"Oh, he gives no trouble. But he is a dirty scoundrel." - -"Dirty?" - -"Yes, it is all we can do to make him wash his hands, and his -face is as black as a tinker's. Well, when once his case has been -settled, he will have a regular prison bath; and I think, if you -saw him, you would agree with me that he needed it." - -"I should like to see him very much." - -"Would you? That is easily done. Come this way. You can leave -your bag." - -"No, I think that I'll take it." - -"Very good. Come this way, if you please." He led us down a -passage, opened a barred door, passed down a winding stair, and -brought us to a whitewashed corridor with a line of doors on each -side. - -"The third on the right is his," said the inspector. "Here it -is!" He quietly shot back a panel in the upper part of the door -and glanced through. - -"He is asleep," said he. "You can see him very well." - -We both put our eyes to the grating. The prisoner lay with his -face towards us, in a very deep sleep, breathing slowly and -heavily. He was a middle-sized man, coarsely clad as became his -calling, with a coloured shirt protruding through the rent in his -tattered coat. He was, as the inspector had said, extremely -dirty, but the grime which covered his face could not conceal its -repulsive ugliness. A broad wheal from an old scar ran right -across it from eye to chin, and by its contraction had turned up -one side of the upper lip, so that three teeth were exposed in a -perpetual snarl. A shock of very bright red hair grew low over -his eyes and forehead. - -"He's a beauty, isn't he?" said the inspector. - -"He certainly needs a wash," remarked Holmes. "I had an idea that -he might, and I took the liberty of bringing the tools with me." -He opened the Gladstone bag as he spoke, and took out, to my -astonishment, a very large bath-sponge. - -"He! he! You are a funny one," chuckled the inspector. - -"Now, if you will have the great goodness to open that door very -quietly, we will soon make him cut a much more respectable -figure." - -"Well, I don't know why not," said the inspector. "He doesn't -look a credit to the Bow Street cells, does he?" He slipped his -key into the lock, and we all very quietly entered the cell. The -sleeper half turned, and then settled down once more into a deep -slumber. Holmes stooped to the water-jug, moistened his sponge, -and then rubbed it twice vigorously across and down the -prisoner's face. - -"Let me introduce you," he shouted, "to Mr. Neville St. Clair, of -Lee, in the county of Kent." - -Never in my life have I seen such a sight. The man's face peeled -off under the sponge like the bark from a tree. Gone was the -coarse brown tint! Gone, too, was the horrid scar which had -seamed it across, and the twisted lip which had given the -repulsive sneer to the face! A twitch brought away the tangled -red hair, and there, sitting up in his bed, was a pale, -sad-faced, refined-looking man, black-haired and smooth-skinned, -rubbing his eyes and staring about him with sleepy bewilderment. -Then suddenly realising the exposure, he broke into a scream and -threw himself down with his face to the pillow. - -"Great heavens!" cried the inspector, "it is, indeed, the missing -man. I know him from the photograph." - -The prisoner turned with the reckless air of a man who abandons -himself to his destiny. "Be it so," said he. "And pray what am I -charged with?" - -"With making away with Mr. Neville St.-- Oh, come, you can't be -charged with that unless they make a case of attempted suicide of -it," said the inspector with a grin. "Well, I have been -twenty-seven years in the force, but this really takes the cake." - -"If I am Mr. Neville St. Clair, then it is obvious that no crime -has been committed, and that, therefore, I am illegally -detained." - -"No crime, but a very great error has been committed," said -Holmes. "You would have done better to have trusted your wife." - -"It was not the wife; it was the children," groaned the prisoner. -"God help me, I would not have them ashamed of their father. My -God! What an exposure! What can I do?" - -Sherlock Holmes sat down beside him on the couch and patted him -kindly on the shoulder. - -"If you leave it to a court of law to clear the matter up," said -he, "of course you can hardly avoid publicity. On the other hand, -if you convince the police authorities that there is no possible -case against you, I do not know that there is any reason that the -details should find their way into the papers. Inspector -Bradstreet would, I am sure, make notes upon anything which you -might tell us and submit it to the proper authorities. The case -would then never go into court at all." - -"God bless you!" cried the prisoner passionately. "I would have -endured imprisonment, ay, even execution, rather than have left -my miserable secret as a family blot to my children. - -"You are the first who have ever heard my story. My father was a -schoolmaster in Chesterfield, where I received an excellent -education. I travelled in my youth, took to the stage, and -finally became a reporter on an evening paper in London. One day -my editor wished to have a series of articles upon begging in the -metropolis, and I volunteered to supply them. There was the point -from which all my adventures started. It was only by trying -begging as an amateur that I could get the facts upon which to -base my articles. When an actor I had, of course, learned all the -secrets of making up, and had been famous in the green-room for -my skill. I took advantage now of my attainments. I painted my -face, and to make myself as pitiable as possible I made a good -scar and fixed one side of my lip in a twist by the aid of a -small slip of flesh-coloured plaster. Then with a red head of -hair, and an appropriate dress, I took my station in the business -part of the city, ostensibly as a match-seller but really as a -beggar. For seven hours I plied my trade, and when I returned -home in the evening I found to my surprise that I had received no -less than 26s. 4d. - -"I wrote my articles and thought little more of the matter until, -some time later, I backed a bill for a friend and had a writ -served upon me for 25 pounds. I was at my wit's end where to get -the money, but a sudden idea came to me. I begged a fortnight's -grace from the creditor, asked for a holiday from my employers, -and spent the time in begging in the City under my disguise. In -ten days I had the money and had paid the debt. - -"Well, you can imagine how hard it was to settle down to arduous -work at 2 pounds a week when I knew that I could earn as much in -a day by smearing my face with a little paint, laying my cap on -the ground, and sitting still. It was a long fight between my -pride and the money, but the dollars won at last, and I threw up -reporting and sat day after day in the corner which I had first -chosen, inspiring pity by my ghastly face and filling my pockets -with coppers. Only one man knew my secret. He was the keeper of a -low den in which I used to lodge in Swandam Lane, where I could -every morning emerge as a squalid beggar and in the evenings -transform myself into a well-dressed man about town. This fellow, -a Lascar, was well paid by me for his rooms, so that I knew that -my secret was safe in his possession. - -"Well, very soon I found that I was saving considerable sums of -money. I do not mean that any beggar in the streets of London -could earn 700 pounds a year--which is less than my average -takings--but I had exceptional advantages in my power of making -up, and also in a facility of repartee, which improved by -practice and made me quite a recognised character in the City. -All day a stream of pennies, varied by silver, poured in upon me, -and it was a very bad day in which I failed to take 2 pounds. - -"As I grew richer I grew more ambitious, took a house in the -country, and eventually married, without anyone having a -suspicion as to my real occupation. My dear wife knew that I had -business in the City. She little knew what. - -"Last Monday I had finished for the day and was dressing in my -room above the opium den when I looked out of my window and saw, -to my horror and astonishment, that my wife was standing in the -street, with her eyes fixed full upon me. I gave a cry of -surprise, threw up my arms to cover my face, and, rushing to my -confidant, the Lascar, entreated him to prevent anyone from -coming up to me. I heard her voice downstairs, but I knew that -she could not ascend. Swiftly I threw off my clothes, pulled on -those of a beggar, and put on my pigments and wig. Even a wife's -eyes could not pierce so complete a disguise. But then it -occurred to me that there might be a search in the room, and that -the clothes might betray me. I threw open the window, reopening -by my violence a small cut which I had inflicted upon myself in -the bedroom that morning. Then I seized my coat, which was -weighted by the coppers which I had just transferred to it from -the leather bag in which I carried my takings. I hurled it out of -the window, and it disappeared into the Thames. The other clothes -would have followed, but at that moment there was a rush of -constables up the stair, and a few minutes after I found, rather, -I confess, to my relief, that instead of being identified as Mr. -Neville St. Clair, I was arrested as his murderer. - -"I do not know that there is anything else for me to explain. I -was determined to preserve my disguise as long as possible, and -hence my preference for a dirty face. Knowing that my wife would -be terribly anxious, I slipped off my ring and confided it to the -Lascar at a moment when no constable was watching me, together -with a hurried scrawl, telling her that she had no cause to -fear." - -"That note only reached her yesterday," said Holmes. - -"Good God! What a week she must have spent!" - -"The police have watched this Lascar," said Inspector Bradstreet, -"and I can quite understand that he might find it difficult to -post a letter unobserved. Probably he handed it to some sailor -customer of his, who forgot all about it for some days." - -"That was it," said Holmes, nodding approvingly; "I have no doubt -of it. But have you never been prosecuted for begging?" - -"Many times; but what was a fine to me?" - -"It must stop here, however," said Bradstreet. "If the police are -to hush this thing up, there must be no more of Hugh Boone." - -"I have sworn it by the most solemn oaths which a man can take." - -"In that case I think that it is probable that no further steps -may be taken. But if you are found again, then all must come out. -I am sure, Mr. Holmes, that we are very much indebted to you for -having cleared the matter up. I wish I knew how you reach your -results." - -"I reached this one," said my friend, "by sitting upon five -pillows and consuming an ounce of shag. I think, Watson, that if -we drive to Baker Street we shall just be in time for breakfast." - - - -VII. THE ADVENTURE OF THE BLUE CARBUNCLE - -I had called upon my friend Sherlock Holmes upon the second -morning after Christmas, with the intention of wishing him the -compliments of the season. He was lounging upon the sofa in a -purple dressing-gown, a pipe-rack within his reach upon the -right, and a pile of crumpled morning papers, evidently newly -studied, near at hand. Beside the couch was a wooden chair, and -on the angle of the back hung a very seedy and disreputable -hard-felt hat, much the worse for wear, and cracked in several -places. A lens and a forceps lying upon the seat of the chair -suggested that the hat had been suspended in this manner for the -purpose of examination. - -"You are engaged," said I; "perhaps I interrupt you." - -"Not at all. I am glad to have a friend with whom I can discuss -my results. The matter is a perfectly trivial one"--he jerked his -thumb in the direction of the old hat--"but there are points in -connection with it which are not entirely devoid of interest and -even of instruction." - -I seated myself in his armchair and warmed my hands before his -crackling fire, for a sharp frost had set in, and the windows -were thick with the ice crystals. "I suppose," I remarked, "that, -homely as it looks, this thing has some deadly story linked on to -it--that it is the clue which will guide you in the solution of -some mystery and the punishment of some crime." - -"No, no. No crime," said Sherlock Holmes, laughing. "Only one of -those whimsical little incidents which will happen when you have -four million human beings all jostling each other within the -space of a few square miles. Amid the action and reaction of so -dense a swarm of humanity, every possible combination of events -may be expected to take place, and many a little problem will be -presented which may be striking and bizarre without being -criminal. We have already had experience of such." - -"So much so," I remarked, "that of the last six cases which I -have added to my notes, three have been entirely free of any -legal crime." - -"Precisely. You allude to my attempt to recover the Irene Adler -papers, to the singular case of Miss Mary Sutherland, and to the -adventure of the man with the twisted lip. Well, I have no doubt -that this small matter will fall into the same innocent category. -You know Peterson, the commissionaire?" - -"Yes." - -"It is to him that this trophy belongs." - -"It is his hat." - -"No, no, he found it. Its owner is unknown. I beg that you will -look upon it not as a battered billycock but as an intellectual -problem. And, first, as to how it came here. It arrived upon -Christmas morning, in company with a good fat goose, which is, I -have no doubt, roasting at this moment in front of Peterson's -fire. The facts are these: about four o'clock on Christmas -morning, Peterson, who, as you know, is a very honest fellow, was -returning from some small jollification and was making his way -homeward down Tottenham Court Road. In front of him he saw, in -the gaslight, a tallish man, walking with a slight stagger, and -carrying a white goose slung over his shoulder. As he reached the -corner of Goodge Street, a row broke out between this stranger -and a little knot of roughs. One of the latter knocked off the -man's hat, on which he raised his stick to defend himself and, -swinging it over his head, smashed the shop window behind him. -Peterson had rushed forward to protect the stranger from his -assailants; but the man, shocked at having broken the window, and -seeing an official-looking person in uniform rushing towards him, -dropped his goose, took to his heels, and vanished amid the -labyrinth of small streets which lie at the back of Tottenham -Court Road. The roughs had also fled at the appearance of -Peterson, so that he was left in possession of the field of -battle, and also of the spoils of victory in the shape of this -battered hat and a most unimpeachable Christmas goose." - -"Which surely he restored to their owner?" - -"My dear fellow, there lies the problem. It is true that 'For -Mrs. Henry Baker' was printed upon a small card which was tied to -the bird's left leg, and it is also true that the initials 'H. -B.' are legible upon the lining of this hat, but as there are -some thousands of Bakers, and some hundreds of Henry Bakers in -this city of ours, it is not easy to restore lost property to any -one of them." - -"What, then, did Peterson do?" - -"He brought round both hat and goose to me on Christmas morning, -knowing that even the smallest problems are of interest to me. -The goose we retained until this morning, when there were signs -that, in spite of the slight frost, it would be well that it -should be eaten without unnecessary delay. Its finder has carried -it off, therefore, to fulfil the ultimate destiny of a goose, -while I continue to retain the hat of the unknown gentleman who -lost his Christmas dinner." - -"Did he not advertise?" - -"No." - -"Then, what clue could you have as to his identity?" - -"Only as much as we can deduce." - -"From his hat?" - -"Precisely." - -"But you are joking. What can you gather from this old battered -felt?" - -"Here is my lens. You know my methods. What can you gather -yourself as to the individuality of the man who has worn this -article?" - -I took the tattered object in my hands and turned it over rather -ruefully. It was a very ordinary black hat of the usual round -shape, hard and much the worse for wear. The lining had been of -red silk, but was a good deal discoloured. There was no maker's -name; but, as Holmes had remarked, the initials "H. B." were -scrawled upon one side. It was pierced in the brim for a -hat-securer, but the elastic was missing. For the rest, it was -cracked, exceedingly dusty, and spotted in several places, -although there seemed to have been some attempt to hide the -discoloured patches by smearing them with ink. - -"I can see nothing," said I, handing it back to my friend. - -"On the contrary, Watson, you can see everything. You fail, -however, to reason from what you see. You are too timid in -drawing your inferences." - -"Then, pray tell me what it is that you can infer from this hat?" - -He picked it up and gazed at it in the peculiar introspective -fashion which was characteristic of him. "It is perhaps less -suggestive than it might have been," he remarked, "and yet there -are a few inferences which are very distinct, and a few others -which represent at least a strong balance of probability. That -the man was highly intellectual is of course obvious upon the -face of it, and also that he was fairly well-to-do within the -last three years, although he has now fallen upon evil days. He -had foresight, but has less now than formerly, pointing to a -moral retrogression, which, when taken with the decline of his -fortunes, seems to indicate some evil influence, probably drink, -at work upon him. This may account also for the obvious fact that -his wife has ceased to love him." - -"My dear Holmes!" - -"He has, however, retained some degree of self-respect," he -continued, disregarding my remonstrance. "He is a man who leads a -sedentary life, goes out little, is out of training entirely, is -middle-aged, has grizzled hair which he has had cut within the -last few days, and which he anoints with lime-cream. These are -the more patent facts which are to be deduced from his hat. Also, -by the way, that it is extremely improbable that he has gas laid -on in his house." - -"You are certainly joking, Holmes." - -"Not in the least. Is it possible that even now, when I give you -these results, you are unable to see how they are attained?" - -"I have no doubt that I am very stupid, but I must confess that I -am unable to follow you. For example, how did you deduce that -this man was intellectual?" - -For answer Holmes clapped the hat upon his head. It came right -over the forehead and settled upon the bridge of his nose. "It is -a question of cubic capacity," said he; "a man with so large a -brain must have something in it." - -"The decline of his fortunes, then?" - -"This hat is three years old. These flat brims curled at the edge -came in then. It is a hat of the very best quality. Look at the -band of ribbed silk and the excellent lining. If this man could -afford to buy so expensive a hat three years ago, and has had no -hat since, then he has assuredly gone down in the world." - -"Well, that is clear enough, certainly. But how about the -foresight and the moral retrogression?" - -Sherlock Holmes laughed. "Here is the foresight," said he putting -his finger upon the little disc and loop of the hat-securer. -"They are never sold upon hats. If this man ordered one, it is a -sign of a certain amount of foresight, since he went out of his -way to take this precaution against the wind. But since we see -that he has broken the elastic and has not troubled to replace -it, it is obvious that he has less foresight now than formerly, -which is a distinct proof of a weakening nature. On the other -hand, he has endeavoured to conceal some of these stains upon the -felt by daubing them with ink, which is a sign that he has not -entirely lost his self-respect." - -"Your reasoning is certainly plausible." - -"The further points, that he is middle-aged, that his hair is -grizzled, that it has been recently cut, and that he uses -lime-cream, are all to be gathered from a close examination of the -lower part of the lining. The lens discloses a large number of -hair-ends, clean cut by the scissors of the barber. They all -appear to be adhesive, and there is a distinct odour of -lime-cream. This dust, you will observe, is not the gritty, grey -dust of the street but the fluffy brown dust of the house, -showing that it has been hung up indoors most of the time, while -the marks of moisture upon the inside are proof positive that the -wearer perspired very freely, and could therefore, hardly be in -the best of training." - -"But his wife--you said that she had ceased to love him." - -"This hat has not been brushed for weeks. When I see you, my dear -Watson, with a week's accumulation of dust upon your hat, and -when your wife allows you to go out in such a state, I shall fear -that you also have been unfortunate enough to lose your wife's -affection." - -"But he might be a bachelor." - -"Nay, he was bringing home the goose as a peace-offering to his -wife. Remember the card upon the bird's leg." - -"You have an answer to everything. But how on earth do you deduce -that the gas is not laid on in his house?" - -"One tallow stain, or even two, might come by chance; but when I -see no less than five, I think that there can be little doubt -that the individual must be brought into frequent contact with -burning tallow--walks upstairs at night probably with his hat in -one hand and a guttering candle in the other. Anyhow, he never -got tallow-stains from a gas-jet. Are you satisfied?" - -"Well, it is very ingenious," said I, laughing; "but since, as -you said just now, there has been no crime committed, and no harm -done save the loss of a goose, all this seems to be rather a -waste of energy." - -Sherlock Holmes had opened his mouth to reply, when the door flew -open, and Peterson, the commissionaire, rushed into the apartment -with flushed cheeks and the face of a man who is dazed with -astonishment. - -"The goose, Mr. Holmes! The goose, sir!" he gasped. - -"Eh? What of it, then? Has it returned to life and flapped off -through the kitchen window?" Holmes twisted himself round upon -the sofa to get a fairer view of the man's excited face. - -"See here, sir! See what my wife found in its crop!" He held out -his hand and displayed upon the centre of the palm a brilliantly -scintillating blue stone, rather smaller than a bean in size, but -of such purity and radiance that it twinkled like an electric -point in the dark hollow of his hand. - -Sherlock Holmes sat up with a whistle. "By Jove, Peterson!" said -he, "this is treasure trove indeed. I suppose you know what you -have got?" - -"A diamond, sir? A precious stone. It cuts into glass as though -it were putty." - -"It's more than a precious stone. It is the precious stone." - -"Not the Countess of Morcar's blue carbuncle!" I ejaculated. - -"Precisely so. I ought to know its size and shape, seeing that I -have read the advertisement about it in The Times every day -lately. It is absolutely unique, and its value can only be -conjectured, but the reward offered of 1000 pounds is certainly -not within a twentieth part of the market price." - -"A thousand pounds! Great Lord of mercy!" The commissionaire -plumped down into a chair and stared from one to the other of us. - -"That is the reward, and I have reason to know that there are -sentimental considerations in the background which would induce -the Countess to part with half her fortune if she could but -recover the gem." - -"It was lost, if I remember aright, at the Hotel Cosmopolitan," I -remarked. - -"Precisely so, on December 22nd, just five days ago. John Horner, -a plumber, was accused of having abstracted it from the lady's -jewel-case. The evidence against him was so strong that the case -has been referred to the Assizes. I have some account of the -matter here, I believe." He rummaged amid his newspapers, -glancing over the dates, until at last he smoothed one out, -doubled it over, and read the following paragraph: - -"Hotel Cosmopolitan Jewel Robbery. John Horner, 26, plumber, was -brought up upon the charge of having upon the 22nd inst., -abstracted from the jewel-case of the Countess of Morcar the -valuable gem known as the blue carbuncle. James Ryder, -upper-attendant at the hotel, gave his evidence to the effect -that he had shown Horner up to the dressing-room of the Countess -of Morcar upon the day of the robbery in order that he might -solder the second bar of the grate, which was loose. He had -remained with Horner some little time, but had finally been -called away. On returning, he found that Horner had disappeared, -that the bureau had been forced open, and that the small morocco -casket in which, as it afterwards transpired, the Countess was -accustomed to keep her jewel, was lying empty upon the -dressing-table. Ryder instantly gave the alarm, and Horner was -arrested the same evening; but the stone could not be found -either upon his person or in his rooms. Catherine Cusack, maid to -the Countess, deposed to having heard Ryder's cry of dismay on -discovering the robbery, and to having rushed into the room, -where she found matters as described by the last witness. -Inspector Bradstreet, B division, gave evidence as to the arrest -of Horner, who struggled frantically, and protested his innocence -in the strongest terms. Evidence of a previous conviction for -robbery having been given against the prisoner, the magistrate -refused to deal summarily with the offence, but referred it to -the Assizes. Horner, who had shown signs of intense emotion -during the proceedings, fainted away at the conclusion and was -carried out of court." - -"Hum! So much for the police-court," said Holmes thoughtfully, -tossing aside the paper. "The question for us now to solve is the -sequence of events leading from a rifled jewel-case at one end to -the crop of a goose in Tottenham Court Road at the other. You -see, Watson, our little deductions have suddenly assumed a much -more important and less innocent aspect. Here is the stone; the -stone came from the goose, and the goose came from Mr. Henry -Baker, the gentleman with the bad hat and all the other -characteristics with which I have bored you. So now we must set -ourselves very seriously to finding this gentleman and -ascertaining what part he has played in this little mystery. To -do this, we must try the simplest means first, and these lie -undoubtedly in an advertisement in all the evening papers. If -this fail, I shall have recourse to other methods." - -"What will you say?" - -"Give me a pencil and that slip of paper. Now, then: 'Found at -the corner of Goodge Street, a goose and a black felt hat. Mr. -Henry Baker can have the same by applying at 6:30 this evening at -221B, Baker Street.' That is clear and concise." - -"Very. But will he see it?" - -"Well, he is sure to keep an eye on the papers, since, to a poor -man, the loss was a heavy one. He was clearly so scared by his -mischance in breaking the window and by the approach of Peterson -that he thought of nothing but flight, but since then he must -have bitterly regretted the impulse which caused him to drop his -bird. Then, again, the introduction of his name will cause him to -see it, for everyone who knows him will direct his attention to -it. Here you are, Peterson, run down to the advertising agency -and have this put in the evening papers." - -"In which, sir?" - -"Oh, in the Globe, Star, Pall Mall, St. James's, Evening News, -Standard, Echo, and any others that occur to you." - -"Very well, sir. And this stone?" - -"Ah, yes, I shall keep the stone. Thank you. And, I say, -Peterson, just buy a goose on your way back and leave it here -with me, for we must have one to give to this gentleman in place -of the one which your family is now devouring." - -When the commissionaire had gone, Holmes took up the stone and -held it against the light. "It's a bonny thing," said he. "Just -see how it glints and sparkles. Of course it is a nucleus and -focus of crime. Every good stone is. They are the devil's pet -baits. In the larger and older jewels every facet may stand for a -bloody deed. This stone is not yet twenty years old. It was found -in the banks of the Amoy River in southern China and is remarkable -in having every characteristic of the carbuncle, save that it is -blue in shade instead of ruby red. In spite of its youth, it has -already a sinister history. There have been two murders, a -vitriol-throwing, a suicide, and several robberies brought about -for the sake of this forty-grain weight of crystallised charcoal. -Who would think that so pretty a toy would be a purveyor to the -gallows and the prison? I'll lock it up in my strong box now and -drop a line to the Countess to say that we have it." - -"Do you think that this man Horner is innocent?" - -"I cannot tell." - -"Well, then, do you imagine that this other one, Henry Baker, had -anything to do with the matter?" - -"It is, I think, much more likely that Henry Baker is an -absolutely innocent man, who had no idea that the bird which he -was carrying was of considerably more value than if it were made -of solid gold. That, however, I shall determine by a very simple -test if we have an answer to our advertisement." - -"And you can do nothing until then?" - -"Nothing." - -"In that case I shall continue my professional round. But I shall -come back in the evening at the hour you have mentioned, for I -should like to see the solution of so tangled a business." - -"Very glad to see you. I dine at seven. There is a woodcock, I -believe. By the way, in view of recent occurrences, perhaps I -ought to ask Mrs. Hudson to examine its crop." - -I had been delayed at a case, and it was a little after half-past -six when I found myself in Baker Street once more. As I -approached the house I saw a tall man in a Scotch bonnet with a -coat which was buttoned up to his chin waiting outside in the -bright semicircle which was thrown from the fanlight. Just as I -arrived the door was opened, and we were shown up together to -Holmes' room. - -"Mr. Henry Baker, I believe," said he, rising from his armchair -and greeting his visitor with the easy air of geniality which he -could so readily assume. "Pray take this chair by the fire, Mr. -Baker. It is a cold night, and I observe that your circulation is -more adapted for summer than for winter. Ah, Watson, you have -just come at the right time. Is that your hat, Mr. Baker?" - -"Yes, sir, that is undoubtedly my hat." - -He was a large man with rounded shoulders, a massive head, and a -broad, intelligent face, sloping down to a pointed beard of -grizzled brown. A touch of red in nose and cheeks, with a slight -tremor of his extended hand, recalled Holmes' surmise as to his -habits. His rusty black frock-coat was buttoned right up in -front, with the collar turned up, and his lank wrists protruded -from his sleeves without a sign of cuff or shirt. He spoke in a -slow staccato fashion, choosing his words with care, and gave the -impression generally of a man of learning and letters who had had -ill-usage at the hands of fortune. - -"We have retained these things for some days," said Holmes, -"because we expected to see an advertisement from you giving your -address. I am at a loss to know now why you did not advertise." - -Our visitor gave a rather shamefaced laugh. "Shillings have not -been so plentiful with me as they once were," he remarked. "I had -no doubt that the gang of roughs who assaulted me had carried off -both my hat and the bird. I did not care to spend more money in a -hopeless attempt at recovering them." - -"Very naturally. By the way, about the bird, we were compelled to -eat it." - -"To eat it!" Our visitor half rose from his chair in his -excitement. - -"Yes, it would have been of no use to anyone had we not done so. -But I presume that this other goose upon the sideboard, which is -about the same weight and perfectly fresh, will answer your -purpose equally well?" - -"Oh, certainly, certainly," answered Mr. Baker with a sigh of -relief. - -"Of course, we still have the feathers, legs, crop, and so on of -your own bird, so if you wish--" - -The man burst into a hearty laugh. "They might be useful to me as -relics of my adventure," said he, "but beyond that I can hardly -see what use the disjecta membra of my late acquaintance are -going to be to me. No, sir, I think that, with your permission, I -will confine my attentions to the excellent bird which I perceive -upon the sideboard." - -Sherlock Holmes glanced sharply across at me with a slight shrug -of his shoulders. - -"There is your hat, then, and there your bird," said he. "By the -way, would it bore you to tell me where you got the other one -from? I am somewhat of a fowl fancier, and I have seldom seen a -better grown goose." - -"Certainly, sir," said Baker, who had risen and tucked his newly -gained property under his arm. "There are a few of us who -frequent the Alpha Inn, near the Museum--we are to be found in -the Museum itself during the day, you understand. This year our -good host, Windigate by name, instituted a goose club, by which, -on consideration of some few pence every week, we were each to -receive a bird at Christmas. My pence were duly paid, and the -rest is familiar to you. I am much indebted to you, sir, for a -Scotch bonnet is fitted neither to my years nor my gravity." With -a comical pomposity of manner he bowed solemnly to both of us and -strode off upon his way. - -"So much for Mr. Henry Baker," said Holmes when he had closed the -door behind him. "It is quite certain that he knows nothing -whatever about the matter. Are you hungry, Watson?" - -"Not particularly." - -"Then I suggest that we turn our dinner into a supper and follow -up this clue while it is still hot." - -"By all means." - -It was a bitter night, so we drew on our ulsters and wrapped -cravats about our throats. Outside, the stars were shining coldly -in a cloudless sky, and the breath of the passers-by blew out -into smoke like so many pistol shots. Our footfalls rang out -crisply and loudly as we swung through the doctors' quarter, -Wimpole Street, Harley Street, and so through Wigmore Street into -Oxford Street. In a quarter of an hour we were in Bloomsbury at -the Alpha Inn, which is a small public-house at the corner of one -of the streets which runs down into Holborn. Holmes pushed open -the door of the private bar and ordered two glasses of beer from -the ruddy-faced, white-aproned landlord. - -"Your beer should be excellent if it is as good as your geese," -said he. - -"My geese!" The man seemed surprised. - -"Yes. I was speaking only half an hour ago to Mr. Henry Baker, -who was a member of your goose club." - -"Ah! yes, I see. But you see, sir, them's not our geese." - -"Indeed! Whose, then?" - -"Well, I got the two dozen from a salesman in Covent Garden." - -"Indeed? I know some of them. Which was it?" - -"Breckinridge is his name." - -"Ah! I don't know him. Well, here's your good health landlord, -and prosperity to your house. Good-night." - -"Now for Mr. Breckinridge," he continued, buttoning up his coat -as we came out into the frosty air. "Remember, Watson that though -we have so homely a thing as a goose at one end of this chain, we -have at the other a man who will certainly get seven years' penal -servitude unless we can establish his innocence. It is possible -that our inquiry may but confirm his guilt; but, in any case, we -have a line of investigation which has been missed by the police, -and which a singular chance has placed in our hands. Let us -follow it out to the bitter end. Faces to the south, then, and -quick march!" - -We passed across Holborn, down Endell Street, and so through a -zigzag of slums to Covent Garden Market. One of the largest -stalls bore the name of Breckinridge upon it, and the proprietor -a horsey-looking man, with a sharp face and trim side-whiskers was -helping a boy to put up the shutters. - -"Good-evening. It's a cold night," said Holmes. - -The salesman nodded and shot a questioning glance at my -companion. - -"Sold out of geese, I see," continued Holmes, pointing at the -bare slabs of marble. - -"Let you have five hundred to-morrow morning." - -"That's no good." - -"Well, there are some on the stall with the gas-flare." - -"Ah, but I was recommended to you." - -"Who by?" - -"The landlord of the Alpha." - -"Oh, yes; I sent him a couple of dozen." - -"Fine birds they were, too. Now where did you get them from?" - -To my surprise the question provoked a burst of anger from the -salesman. - -"Now, then, mister," said he, with his head cocked and his arms -akimbo, "what are you driving at? Let's have it straight, now." - -"It is straight enough. I should like to know who sold you the -geese which you supplied to the Alpha." - -"Well then, I shan't tell you. So now!" - -"Oh, it is a matter of no importance; but I don't know why you -should be so warm over such a trifle." - -"Warm! You'd be as warm, maybe, if you were as pestered as I am. -When I pay good money for a good article there should be an end -of the business; but it's 'Where are the geese?' and 'Who did you -sell the geese to?' and 'What will you take for the geese?' One -would think they were the only geese in the world, to hear the -fuss that is made over them." - -"Well, I have no connection with any other people who have been -making inquiries," said Holmes carelessly. "If you won't tell us -the bet is off, that is all. But I'm always ready to back my -opinion on a matter of fowls, and I have a fiver on it that the -bird I ate is country bred." - -"Well, then, you've lost your fiver, for it's town bred," snapped -the salesman. - -"It's nothing of the kind." - -"I say it is." - -"I don't believe it." - -"D'you think you know more about fowls than I, who have handled -them ever since I was a nipper? I tell you, all those birds that -went to the Alpha were town bred." - -"You'll never persuade me to believe that." - -"Will you bet, then?" - -"It's merely taking your money, for I know that I am right. But -I'll have a sovereign on with you, just to teach you not to be -obstinate." - -The salesman chuckled grimly. "Bring me the books, Bill," said -he. - -The small boy brought round a small thin volume and a great -greasy-backed one, laying them out together beneath the hanging -lamp. - -"Now then, Mr. Cocksure," said the salesman, "I thought that I -was out of geese, but before I finish you'll find that there is -still one left in my shop. You see this little book?" - -"Well?" - -"That's the list of the folk from whom I buy. D'you see? Well, -then, here on this page are the country folk, and the numbers -after their names are where their accounts are in the big ledger. -Now, then! You see this other page in red ink? Well, that is a -list of my town suppliers. Now, look at that third name. Just -read it out to me." - -"Mrs. Oakshott, 117, Brixton Road--249," read Holmes. - -"Quite so. Now turn that up in the ledger." - -Holmes turned to the page indicated. "Here you are, 'Mrs. -Oakshott, 117, Brixton Road, egg and poultry supplier.'" - -"Now, then, what's the last entry?" - -"'December 22nd. Twenty-four geese at 7s. 6d.'" - -"Quite so. There you are. And underneath?" - -"'Sold to Mr. Windigate of the Alpha, at 12s.'" - -"What have you to say now?" - -Sherlock Holmes looked deeply chagrined. He drew a sovereign from -his pocket and threw it down upon the slab, turning away with the -air of a man whose disgust is too deep for words. A few yards off -he stopped under a lamp-post and laughed in the hearty, noiseless -fashion which was peculiar to him. - -"When you see a man with whiskers of that cut and the 'Pink 'un' -protruding out of his pocket, you can always draw him by a bet," -said he. "I daresay that if I had put 100 pounds down in front of -him, that man would not have given me such complete information -as was drawn from him by the idea that he was doing me on a -wager. Well, Watson, we are, I fancy, nearing the end of our -quest, and the only point which remains to be determined is -whether we should go on to this Mrs. Oakshott to-night, or -whether we should reserve it for to-morrow. It is clear from what -that surly fellow said that there are others besides ourselves -who are anxious about the matter, and I should--" - -His remarks were suddenly cut short by a loud hubbub which broke -out from the stall which we had just left. Turning round we saw a -little rat-faced fellow standing in the centre of the circle of -yellow light which was thrown by the swinging lamp, while -Breckinridge, the salesman, framed in the door of his stall, was -shaking his fists fiercely at the cringing figure. - -"I've had enough of you and your geese," he shouted. "I wish you -were all at the devil together. If you come pestering me any more -with your silly talk I'll set the dog at you. You bring Mrs. -Oakshott here and I'll answer her, but what have you to do with -it? Did I buy the geese off you?" - -"No; but one of them was mine all the same," whined the little -man. - -"Well, then, ask Mrs. Oakshott for it." - -"She told me to ask you." - -"Well, you can ask the King of Proosia, for all I care. I've had -enough of it. Get out of this!" He rushed fiercely forward, and -the inquirer flitted away into the darkness. - -"Ha! this may save us a visit to Brixton Road," whispered Holmes. -"Come with me, and we will see what is to be made of this -fellow." Striding through the scattered knots of people who -lounged round the flaring stalls, my companion speedily overtook -the little man and touched him upon the shoulder. He sprang -round, and I could see in the gas-light that every vestige of -colour had been driven from his face. - -"Who are you, then? What do you want?" he asked in a quavering -voice. - -"You will excuse me," said Holmes blandly, "but I could not help -overhearing the questions which you put to the salesman just now. -I think that I could be of assistance to you." - -"You? Who are you? How could you know anything of the matter?" - -"My name is Sherlock Holmes. It is my business to know what other -people don't know." - -"But you can know nothing of this?" - -"Excuse me, I know everything of it. You are endeavouring to -trace some geese which were sold by Mrs. Oakshott, of Brixton -Road, to a salesman named Breckinridge, by him in turn to Mr. -Windigate, of the Alpha, and by him to his club, of which Mr. -Henry Baker is a member." - -"Oh, sir, you are the very man whom I have longed to meet," cried -the little fellow with outstretched hands and quivering fingers. -"I can hardly explain to you how interested I am in this matter." - -Sherlock Holmes hailed a four-wheeler which was passing. "In that -case we had better discuss it in a cosy room rather than in this -wind-swept market-place," said he. "But pray tell me, before we -go farther, who it is that I have the pleasure of assisting." - -The man hesitated for an instant. "My name is John Robinson," he -answered with a sidelong glance. - -"No, no; the real name," said Holmes sweetly. "It is always -awkward doing business with an alias." - -A flush sprang to the white cheeks of the stranger. "Well then," -said he, "my real name is James Ryder." - -"Precisely so. Head attendant at the Hotel Cosmopolitan. Pray -step into the cab, and I shall soon be able to tell you -everything which you would wish to know." - -The little man stood glancing from one to the other of us with -half-frightened, half-hopeful eyes, as one who is not sure -whether he is on the verge of a windfall or of a catastrophe. -Then he stepped into the cab, and in half an hour we were back in -the sitting-room at Baker Street. Nothing had been said during -our drive, but the high, thin breathing of our new companion, and -the claspings and unclaspings of his hands, spoke of the nervous -tension within him. - -"Here we are!" said Holmes cheerily as we filed into the room. -"The fire looks very seasonable in this weather. You look cold, -Mr. Ryder. Pray take the basket-chair. I will just put on my -slippers before we settle this little matter of yours. Now, then! -You want to know what became of those geese?" - -"Yes, sir." - -"Or rather, I fancy, of that goose. It was one bird, I imagine in -which you were interested--white, with a black bar across the -tail." - -Ryder quivered with emotion. "Oh, sir," he cried, "can you tell -me where it went to?" - -"It came here." - -"Here?" - -"Yes, and a most remarkable bird it proved. I don't wonder that -you should take an interest in it. It laid an egg after it was -dead--the bonniest, brightest little blue egg that ever was seen. -I have it here in my museum." - -Our visitor staggered to his feet and clutched the mantelpiece -with his right hand. Holmes unlocked his strong-box and held up -the blue carbuncle, which shone out like a star, with a cold, -brilliant, many-pointed radiance. Ryder stood glaring with a -drawn face, uncertain whether to claim or to disown it. - -"The game's up, Ryder," said Holmes quietly. "Hold up, man, or -you'll be into the fire! Give him an arm back into his chair, -Watson. He's not got blood enough to go in for felony with -impunity. Give him a dash of brandy. So! Now he looks a little -more human. What a shrimp it is, to be sure!" - -For a moment he had staggered and nearly fallen, but the brandy -brought a tinge of colour into his cheeks, and he sat staring -with frightened eyes at his accuser. - -"I have almost every link in my hands, and all the proofs which I -could possibly need, so there is little which you need tell me. -Still, that little may as well be cleared up to make the case -complete. You had heard, Ryder, of this blue stone of the -Countess of Morcar's?" - -"It was Catherine Cusack who told me of it," said he in a -crackling voice. - -"I see--her ladyship's waiting-maid. Well, the temptation of -sudden wealth so easily acquired was too much for you, as it has -been for better men before you; but you were not very scrupulous -in the means you used. It seems to me, Ryder, that there is the -making of a very pretty villain in you. You knew that this man -Horner, the plumber, had been concerned in some such matter -before, and that suspicion would rest the more readily upon him. -What did you do, then? You made some small job in my lady's -room--you and your confederate Cusack--and you managed that he -should be the man sent for. Then, when he had left, you rifled -the jewel-case, raised the alarm, and had this unfortunate man -arrested. You then--" - -Ryder threw himself down suddenly upon the rug and clutched at my -companion's knees. "For God's sake, have mercy!" he shrieked. -"Think of my father! Of my mother! It would break their hearts. I -never went wrong before! I never will again. I swear it. I'll -swear it on a Bible. Oh, don't bring it into court! For Christ's -sake, don't!" - -"Get back into your chair!" said Holmes sternly. "It is very well -to cringe and crawl now, but you thought little enough of this -poor Horner in the dock for a crime of which he knew nothing." - -"I will fly, Mr. Holmes. I will leave the country, sir. Then the -charge against him will break down." - -"Hum! We will talk about that. And now let us hear a true account -of the next act. How came the stone into the goose, and how came -the goose into the open market? Tell us the truth, for there lies -your only hope of safety." - -Ryder passed his tongue over his parched lips. "I will tell you -it just as it happened, sir," said he. "When Horner had been -arrested, it seemed to me that it would be best for me to get -away with the stone at once, for I did not know at what moment -the police might not take it into their heads to search me and my -room. There was no place about the hotel where it would be safe. -I went out, as if on some commission, and I made for my sister's -house. She had married a man named Oakshott, and lived in Brixton -Road, where she fattened fowls for the market. All the way there -every man I met seemed to me to be a policeman or a detective; -and, for all that it was a cold night, the sweat was pouring down -my face before I came to the Brixton Road. My sister asked me -what was the matter, and why I was so pale; but I told her that I -had been upset by the jewel robbery at the hotel. Then I went -into the back yard and smoked a pipe and wondered what it would -be best to do. - -"I had a friend once called Maudsley, who went to the bad, and -has just been serving his time in Pentonville. One day he had met -me, and fell into talk about the ways of thieves, and how they -could get rid of what they stole. I knew that he would be true to -me, for I knew one or two things about him; so I made up my mind -to go right on to Kilburn, where he lived, and take him into my -confidence. He would show me how to turn the stone into money. -But how to get to him in safety? I thought of the agonies I had -gone through in coming from the hotel. I might at any moment be -seized and searched, and there would be the stone in my waistcoat -pocket. I was leaning against the wall at the time and looking at -the geese which were waddling about round my feet, and suddenly -an idea came into my head which showed me how I could beat the -best detective that ever lived. - -"My sister had told me some weeks before that I might have the -pick of her geese for a Christmas present, and I knew that she -was always as good as her word. I would take my goose now, and in -it I would carry my stone to Kilburn. There was a little shed in -the yard, and behind this I drove one of the birds--a fine big -one, white, with a barred tail. I caught it, and prying its bill -open, I thrust the stone down its throat as far as my finger -could reach. The bird gave a gulp, and I felt the stone pass -along its gullet and down into its crop. But the creature flapped -and struggled, and out came my sister to know what was the -matter. As I turned to speak to her the brute broke loose and -fluttered off among the others. - -"'Whatever were you doing with that bird, Jem?' says she. - -"'Well,' said I, 'you said you'd give me one for Christmas, and I -was feeling which was the fattest.' - -"'Oh,' says she, 'we've set yours aside for you--Jem's bird, we -call it. It's the big white one over yonder. There's twenty-six -of them, which makes one for you, and one for us, and two dozen -for the market.' - -"'Thank you, Maggie,' says I; 'but if it is all the same to you, -I'd rather have that one I was handling just now.' - -"'The other is a good three pound heavier,' said she, 'and we -fattened it expressly for you.' - -"'Never mind. I'll have the other, and I'll take it now,' said I. - -"'Oh, just as you like,' said she, a little huffed. 'Which is it -you want, then?' - -"'That white one with the barred tail, right in the middle of the -flock.' - -"'Oh, very well. Kill it and take it with you.' - -"Well, I did what she said, Mr. Holmes, and I carried the bird -all the way to Kilburn. I told my pal what I had done, for he was -a man that it was easy to tell a thing like that to. He laughed -until he choked, and we got a knife and opened the goose. My -heart turned to water, for there was no sign of the stone, and I -knew that some terrible mistake had occurred. I left the bird, -rushed back to my sister's, and hurried into the back yard. There -was not a bird to be seen there. - -"'Where are they all, Maggie?' I cried. - -"'Gone to the dealer's, Jem.' - -"'Which dealer's?' - -"'Breckinridge, of Covent Garden.' - -"'But was there another with a barred tail?' I asked, 'the same -as the one I chose?' - -"'Yes, Jem; there were two barred-tailed ones, and I could never -tell them apart.' - -"Well, then, of course I saw it all, and I ran off as hard as my -feet would carry me to this man Breckinridge; but he had sold the -lot at once, and not one word would he tell me as to where they -had gone. You heard him yourselves to-night. Well, he has always -answered me like that. My sister thinks that I am going mad. -Sometimes I think that I am myself. And now--and now I am myself -a branded thief, without ever having touched the wealth for which -I sold my character. God help me! God help me!" He burst into -convulsive sobbing, with his face buried in his hands. - -There was a long silence, broken only by his heavy breathing and -by the measured tapping of Sherlock Holmes' finger-tips upon the -edge of the table. Then my friend rose and threw open the door. - -"Get out!" said he. - -"What, sir! Oh, Heaven bless you!" - -"No more words. Get out!" - -And no more words were needed. There was a rush, a clatter upon -the stairs, the bang of a door, and the crisp rattle of running -footfalls from the street. - -"After all, Watson," said Holmes, reaching up his hand for his -clay pipe, "I am not retained by the police to supply their -deficiencies. If Horner were in danger it would be another thing; -but this fellow will not appear against him, and the case must -collapse. I suppose that I am commuting a felony, but it is just -possible that I am saving a soul. This fellow will not go wrong -again; he is too terribly frightened. Send him to gaol now, and -you make him a gaol-bird for life. Besides, it is the season of -forgiveness. Chance has put in our way a most singular and -whimsical problem, and its solution is its own reward. If you -will have the goodness to touch the bell, Doctor, we will begin -another investigation, in which, also a bird will be the chief -feature." - - - -VIII. THE ADVENTURE OF THE SPECKLED BAND - -On glancing over my notes of the seventy odd cases in which I -have during the last eight years studied the methods of my friend -Sherlock Holmes, I find many tragic, some comic, a large number -merely strange, but none commonplace; for, working as he did -rather for the love of his art than for the acquirement of -wealth, he refused to associate himself with any investigation -which did not tend towards the unusual, and even the fantastic. -Of all these varied cases, however, I cannot recall any which -presented more singular features than that which was associated -with the well-known Surrey family of the Roylotts of Stoke Moran. -The events in question occurred in the early days of my -association with Holmes, when we were sharing rooms as bachelors -in Baker Street. It is possible that I might have placed them -upon record before, but a promise of secrecy was made at the -time, from which I have only been freed during the last month by -the untimely death of the lady to whom the pledge was given. It -is perhaps as well that the facts should now come to light, for I -have reasons to know that there are widespread rumours as to the -death of Dr. Grimesby Roylott which tend to make the matter even -more terrible than the truth. - -It was early in April in the year '83 that I woke one morning to -find Sherlock Holmes standing, fully dressed, by the side of my -bed. He was a late riser, as a rule, and as the clock on the -mantelpiece showed me that it was only a quarter-past seven, I -blinked up at him in some surprise, and perhaps just a little -resentment, for I was myself regular in my habits. - -"Very sorry to knock you up, Watson," said he, "but it's the -common lot this morning. Mrs. Hudson has been knocked up, she -retorted upon me, and I on you." - -"What is it, then--a fire?" - -"No; a client. It seems that a young lady has arrived in a -considerable state of excitement, who insists upon seeing me. She -is waiting now in the sitting-room. Now, when young ladies wander -about the metropolis at this hour of the morning, and knock -sleepy people up out of their beds, I presume that it is -something very pressing which they have to communicate. Should it -prove to be an interesting case, you would, I am sure, wish to -follow it from the outset. I thought, at any rate, that I should -call you and give you the chance." - -"My dear fellow, I would not miss it for anything." - -I had no keener pleasure than in following Holmes in his -professional investigations, and in admiring the rapid -deductions, as swift as intuitions, and yet always founded on a -logical basis with which he unravelled the problems which were -submitted to him. I rapidly threw on my clothes and was ready in -a few minutes to accompany my friend down to the sitting-room. A -lady dressed in black and heavily veiled, who had been sitting in -the window, rose as we entered. - -"Good-morning, madam," said Holmes cheerily. "My name is Sherlock -Holmes. This is my intimate friend and associate, Dr. Watson, -before whom you can speak as freely as before myself. Ha! I am -glad to see that Mrs. Hudson has had the good sense to light the -fire. Pray draw up to it, and I shall order you a cup of hot -coffee, for I observe that you are shivering." - -"It is not cold which makes me shiver," said the woman in a low -voice, changing her seat as requested. - -"What, then?" - -"It is fear, Mr. Holmes. It is terror." She raised her veil as -she spoke, and we could see that she was indeed in a pitiable -state of agitation, her face all drawn and grey, with restless -frightened eyes, like those of some hunted animal. Her features -and figure were those of a woman of thirty, but her hair was shot -with premature grey, and her expression was weary and haggard. -Sherlock Holmes ran her over with one of his quick, -all-comprehensive glances. - -"You must not fear," said he soothingly, bending forward and -patting her forearm. "We shall soon set matters right, I have no -doubt. You have come in by train this morning, I see." - -"You know me, then?" - -"No, but I observe the second half of a return ticket in the palm -of your left glove. You must have started early, and yet you had -a good drive in a dog-cart, along heavy roads, before you reached -the station." - -The lady gave a violent start and stared in bewilderment at my -companion. - -"There is no mystery, my dear madam," said he, smiling. "The left -arm of your jacket is spattered with mud in no less than seven -places. The marks are perfectly fresh. There is no vehicle save a -dog-cart which throws up mud in that way, and then only when you -sit on the left-hand side of the driver." - -"Whatever your reasons may be, you are perfectly correct," said -she. "I started from home before six, reached Leatherhead at -twenty past, and came in by the first train to Waterloo. Sir, I -can stand this strain no longer; I shall go mad if it continues. -I have no one to turn to--none, save only one, who cares for me, -and he, poor fellow, can be of little aid. I have heard of you, -Mr. Holmes; I have heard of you from Mrs. Farintosh, whom you -helped in the hour of her sore need. It was from her that I had -your address. Oh, sir, do you not think that you could help me, -too, and at least throw a little light through the dense darkness -which surrounds me? At present it is out of my power to reward -you for your services, but in a month or six weeks I shall be -married, with the control of my own income, and then at least you -shall not find me ungrateful." - -Holmes turned to his desk and, unlocking it, drew out a small -case-book, which he consulted. - -"Farintosh," said he. "Ah yes, I recall the case; it was -concerned with an opal tiara. I think it was before your time, -Watson. I can only say, madam, that I shall be happy to devote -the same care to your case as I did to that of your friend. As to -reward, my profession is its own reward; but you are at liberty -to defray whatever expenses I may be put to, at the time which -suits you best. And now I beg that you will lay before us -everything that may help us in forming an opinion upon the -matter." - -"Alas!" replied our visitor, "the very horror of my situation -lies in the fact that my fears are so vague, and my suspicions -depend so entirely upon small points, which might seem trivial to -another, that even he to whom of all others I have a right to -look for help and advice looks upon all that I tell him about it -as the fancies of a nervous woman. He does not say so, but I can -read it from his soothing answers and averted eyes. But I have -heard, Mr. Holmes, that you can see deeply into the manifold -wickedness of the human heart. You may advise me how to walk amid -the dangers which encompass me." - -"I am all attention, madam." - -"My name is Helen Stoner, and I am living with my stepfather, who -is the last survivor of one of the oldest Saxon families in -England, the Roylotts of Stoke Moran, on the western border of -Surrey." - -Holmes nodded his head. "The name is familiar to me," said he. - -"The family was at one time among the richest in England, and the -estates extended over the borders into Berkshire in the north, -and Hampshire in the west. In the last century, however, four -successive heirs were of a dissolute and wasteful disposition, -and the family ruin was eventually completed by a gambler in the -days of the Regency. Nothing was left save a few acres of ground, -and the two-hundred-year-old house, which is itself crushed under -a heavy mortgage. The last squire dragged out his existence -there, living the horrible life of an aristocratic pauper; but -his only son, my stepfather, seeing that he must adapt himself to -the new conditions, obtained an advance from a relative, which -enabled him to take a medical degree and went out to Calcutta, -where, by his professional skill and his force of character, he -established a large practice. In a fit of anger, however, caused -by some robberies which had been perpetrated in the house, he -beat his native butler to death and narrowly escaped a capital -sentence. As it was, he suffered a long term of imprisonment and -afterwards returned to England a morose and disappointed man. - -"When Dr. Roylott was in India he married my mother, Mrs. Stoner, -the young widow of Major-General Stoner, of the Bengal Artillery. -My sister Julia and I were twins, and we were only two years old -at the time of my mother's re-marriage. She had a considerable -sum of money--not less than 1000 pounds a year--and this she -bequeathed to Dr. Roylott entirely while we resided with him, -with a provision that a certain annual sum should be allowed to -each of us in the event of our marriage. Shortly after our return -to England my mother died--she was killed eight years ago in a -railway accident near Crewe. Dr. Roylott then abandoned his -attempts to establish himself in practice in London and took us -to live with him in the old ancestral house at Stoke Moran. The -money which my mother had left was enough for all our wants, and -there seemed to be no obstacle to our happiness. - -"But a terrible change came over our stepfather about this time. -Instead of making friends and exchanging visits with our -neighbours, who had at first been overjoyed to see a Roylott of -Stoke Moran back in the old family seat, he shut himself up in -his house and seldom came out save to indulge in ferocious -quarrels with whoever might cross his path. Violence of temper -approaching to mania has been hereditary in the men of the -family, and in my stepfather's case it had, I believe, been -intensified by his long residence in the tropics. A series of -disgraceful brawls took place, two of which ended in the -police-court, until at last he became the terror of the village, -and the folks would fly at his approach, for he is a man of -immense strength, and absolutely uncontrollable in his anger. - -"Last week he hurled the local blacksmith over a parapet into a -stream, and it was only by paying over all the money which I -could gather together that I was able to avert another public -exposure. He had no friends at all save the wandering gipsies, -and he would give these vagabonds leave to encamp upon the few -acres of bramble-covered land which represent the family estate, -and would accept in return the hospitality of their tents, -wandering away with them sometimes for weeks on end. He has a -passion also for Indian animals, which are sent over to him by a -correspondent, and he has at this moment a cheetah and a baboon, -which wander freely over his grounds and are feared by the -villagers almost as much as their master. - -"You can imagine from what I say that my poor sister Julia and I -had no great pleasure in our lives. No servant would stay with -us, and for a long time we did all the work of the house. She was -but thirty at the time of her death, and yet her hair had already -begun to whiten, even as mine has." - -"Your sister is dead, then?" - -"She died just two years ago, and it is of her death that I wish -to speak to you. You can understand that, living the life which I -have described, we were little likely to see anyone of our own -age and position. We had, however, an aunt, my mother's maiden -sister, Miss Honoria Westphail, who lives near Harrow, and we -were occasionally allowed to pay short visits at this lady's -house. Julia went there at Christmas two years ago, and met there -a half-pay major of marines, to whom she became engaged. My -stepfather learned of the engagement when my sister returned and -offered no objection to the marriage; but within a fortnight of -the day which had been fixed for the wedding, the terrible event -occurred which has deprived me of my only companion." - -Sherlock Holmes had been leaning back in his chair with his eyes -closed and his head sunk in a cushion, but he half opened his -lids now and glanced across at his visitor. - -"Pray be precise as to details," said he. - -"It is easy for me to be so, for every event of that dreadful -time is seared into my memory. The manor-house is, as I have -already said, very old, and only one wing is now inhabited. The -bedrooms in this wing are on the ground floor, the sitting-rooms -being in the central block of the buildings. Of these bedrooms -the first is Dr. Roylott's, the second my sister's, and the third -my own. There is no communication between them, but they all open -out into the same corridor. Do I make myself plain?" - -"Perfectly so." - -"The windows of the three rooms open out upon the lawn. That -fatal night Dr. Roylott had gone to his room early, though we -knew that he had not retired to rest, for my sister was troubled -by the smell of the strong Indian cigars which it was his custom -to smoke. She left her room, therefore, and came into mine, where -she sat for some time, chatting about her approaching wedding. At -eleven o'clock she rose to leave me, but she paused at the door -and looked back. - -"'Tell me, Helen,' said she, 'have you ever heard anyone whistle -in the dead of the night?' - -"'Never,' said I. - -"'I suppose that you could not possibly whistle, yourself, in -your sleep?' - -"'Certainly not. But why?' - -"'Because during the last few nights I have always, about three -in the morning, heard a low, clear whistle. I am a light sleeper, -and it has awakened me. I cannot tell where it came from--perhaps -from the next room, perhaps from the lawn. I thought that I would -just ask you whether you had heard it.' - -"'No, I have not. It must be those wretched gipsies in the -plantation.' - -"'Very likely. And yet if it were on the lawn, I wonder that you -did not hear it also.' - -"'Ah, but I sleep more heavily than you.' - -"'Well, it is of no great consequence, at any rate.' She smiled -back at me, closed my door, and a few moments later I heard her -key turn in the lock." - -"Indeed," said Holmes. "Was it your custom always to lock -yourselves in at night?" - -"Always." - -"And why?" - -"I think that I mentioned to you that the doctor kept a cheetah -and a baboon. We had no feeling of security unless our doors were -locked." - -"Quite so. Pray proceed with your statement." - -"I could not sleep that night. A vague feeling of impending -misfortune impressed me. My sister and I, you will recollect, -were twins, and you know how subtle are the links which bind two -souls which are so closely allied. It was a wild night. The wind -was howling outside, and the rain was beating and splashing -against the windows. Suddenly, amid all the hubbub of the gale, -there burst forth the wild scream of a terrified woman. I knew -that it was my sister's voice. I sprang from my bed, wrapped a -shawl round me, and rushed into the corridor. As I opened my door -I seemed to hear a low whistle, such as my sister described, and -a few moments later a clanging sound, as if a mass of metal had -fallen. As I ran down the passage, my sister's door was unlocked, -and revolved slowly upon its hinges. I stared at it -horror-stricken, not knowing what was about to issue from it. By -the light of the corridor-lamp I saw my sister appear at the -opening, her face blanched with terror, her hands groping for -help, her whole figure swaying to and fro like that of a -drunkard. I ran to her and threw my arms round her, but at that -moment her knees seemed to give way and she fell to the ground. -She writhed as one who is in terrible pain, and her limbs were -dreadfully convulsed. At first I thought that she had not -recognised me, but as I bent over her she suddenly shrieked out -in a voice which I shall never forget, 'Oh, my God! Helen! It was -the band! The speckled band!' There was something else which she -would fain have said, and she stabbed with her finger into the -air in the direction of the doctor's room, but a fresh convulsion -seized her and choked her words. I rushed out, calling loudly for -my stepfather, and I met him hastening from his room in his -dressing-gown. When he reached my sister's side she was -unconscious, and though he poured brandy down her throat and sent -for medical aid from the village, all efforts were in vain, for -she slowly sank and died without having recovered her -consciousness. Such was the dreadful end of my beloved sister." - -"One moment," said Holmes, "are you sure about this whistle and -metallic sound? Could you swear to it?" - -"That was what the county coroner asked me at the inquiry. It is -my strong impression that I heard it, and yet, among the crash of -the gale and the creaking of an old house, I may possibly have -been deceived." - -"Was your sister dressed?" - -"No, she was in her night-dress. In her right hand was found the -charred stump of a match, and in her left a match-box." - -"Showing that she had struck a light and looked about her when -the alarm took place. That is important. And what conclusions did -the coroner come to?" - -"He investigated the case with great care, for Dr. Roylott's -conduct had long been notorious in the county, but he was unable -to find any satisfactory cause of death. My evidence showed that -the door had been fastened upon the inner side, and the windows -were blocked by old-fashioned shutters with broad iron bars, -which were secured every night. The walls were carefully sounded, -and were shown to be quite solid all round, and the flooring was -also thoroughly examined, with the same result. The chimney is -wide, but is barred up by four large staples. It is certain, -therefore, that my sister was quite alone when she met her end. -Besides, there were no marks of any violence upon her." - -"How about poison?" - -"The doctors examined her for it, but without success." - -"What do you think that this unfortunate lady died of, then?" - -"It is my belief that she died of pure fear and nervous shock, -though what it was that frightened her I cannot imagine." - -"Were there gipsies in the plantation at the time?" - -"Yes, there are nearly always some there." - -"Ah, and what did you gather from this allusion to a band--a -speckled band?" - -"Sometimes I have thought that it was merely the wild talk of -delirium, sometimes that it may have referred to some band of -people, perhaps to these very gipsies in the plantation. I do not -know whether the spotted handkerchiefs which so many of them wear -over their heads might have suggested the strange adjective which -she used." - -Holmes shook his head like a man who is far from being satisfied. - -"These are very deep waters," said he; "pray go on with your -narrative." - -"Two years have passed since then, and my life has been until -lately lonelier than ever. A month ago, however, a dear friend, -whom I have known for many years, has done me the honour to ask -my hand in marriage. His name is Armitage--Percy Armitage--the -second son of Mr. Armitage, of Crane Water, near Reading. My -stepfather has offered no opposition to the match, and we are to -be married in the course of the spring. Two days ago some repairs -were started in the west wing of the building, and my bedroom -wall has been pierced, so that I have had to move into the -chamber in which my sister died, and to sleep in the very bed in -which she slept. Imagine, then, my thrill of terror when last -night, as I lay awake, thinking over her terrible fate, I -suddenly heard in the silence of the night the low whistle which -had been the herald of her own death. I sprang up and lit the -lamp, but nothing was to be seen in the room. I was too shaken to -go to bed again, however, so I dressed, and as soon as it was -daylight I slipped down, got a dog-cart at the Crown Inn, which -is opposite, and drove to Leatherhead, from whence I have come on -this morning with the one object of seeing you and asking your -advice." - -"You have done wisely," said my friend. "But have you told me -all?" - -"Yes, all." - -"Miss Roylott, you have not. You are screening your stepfather." - -"Why, what do you mean?" - -For answer Holmes pushed back the frill of black lace which -fringed the hand that lay upon our visitor's knee. Five little -livid spots, the marks of four fingers and a thumb, were printed -upon the white wrist. - -"You have been cruelly used," said Holmes. - -The lady coloured deeply and covered over her injured wrist. "He -is a hard man," she said, "and perhaps he hardly knows his own -strength." - -There was a long silence, during which Holmes leaned his chin -upon his hands and stared into the crackling fire. - -"This is a very deep business," he said at last. "There are a -thousand details which I should desire to know before I decide -upon our course of action. Yet we have not a moment to lose. If -we were to come to Stoke Moran to-day, would it be possible for -us to see over these rooms without the knowledge of your -stepfather?" - -"As it happens, he spoke of coming into town to-day upon some -most important business. It is probable that he will be away all -day, and that there would be nothing to disturb you. We have a -housekeeper now, but she is old and foolish, and I could easily -get her out of the way." - -"Excellent. You are not averse to this trip, Watson?" - -"By no means." - -"Then we shall both come. What are you going to do yourself?" - -"I have one or two things which I would wish to do now that I am -in town. But I shall return by the twelve o'clock train, so as to -be there in time for your coming." - -"And you may expect us early in the afternoon. I have myself some -small business matters to attend to. Will you not wait and -breakfast?" - -"No, I must go. My heart is lightened already since I have -confided my trouble to you. I shall look forward to seeing you -again this afternoon." She dropped her thick black veil over her -face and glided from the room. - -"And what do you think of it all, Watson?" asked Sherlock Holmes, -leaning back in his chair. - -"It seems to me to be a most dark and sinister business." - -"Dark enough and sinister enough." - -"Yet if the lady is correct in saying that the flooring and walls -are sound, and that the door, window, and chimney are impassable, -then her sister must have been undoubtedly alone when she met her -mysterious end." - -"What becomes, then, of these nocturnal whistles, and what of the -very peculiar words of the dying woman?" - -"I cannot think." - -"When you combine the ideas of whistles at night, the presence of -a band of gipsies who are on intimate terms with this old doctor, -the fact that we have every reason to believe that the doctor has -an interest in preventing his stepdaughter's marriage, the dying -allusion to a band, and, finally, the fact that Miss Helen Stoner -heard a metallic clang, which might have been caused by one of -those metal bars that secured the shutters falling back into its -place, I think that there is good ground to think that the -mystery may be cleared along those lines." - -"But what, then, did the gipsies do?" - -"I cannot imagine." - -"I see many objections to any such theory." - -"And so do I. It is precisely for that reason that we are going -to Stoke Moran this day. I want to see whether the objections are -fatal, or if they may be explained away. But what in the name of -the devil!" - -The ejaculation had been drawn from my companion by the fact that -our door had been suddenly dashed open, and that a huge man had -framed himself in the aperture. His costume was a peculiar -mixture of the professional and of the agricultural, having a -black top-hat, a long frock-coat, and a pair of high gaiters, -with a hunting-crop swinging in his hand. So tall was he that his -hat actually brushed the cross bar of the doorway, and his -breadth seemed to span it across from side to side. A large face, -seared with a thousand wrinkles, burned yellow with the sun, and -marked with every evil passion, was turned from one to the other -of us, while his deep-set, bile-shot eyes, and his high, thin, -fleshless nose, gave him somewhat the resemblance to a fierce old -bird of prey. - -"Which of you is Holmes?" asked this apparition. - -"My name, sir; but you have the advantage of me," said my -companion quietly. - -"I am Dr. Grimesby Roylott, of Stoke Moran." - -"Indeed, Doctor," said Holmes blandly. "Pray take a seat." - -"I will do nothing of the kind. My stepdaughter has been here. I -have traced her. What has she been saying to you?" - -"It is a little cold for the time of the year," said Holmes. - -"What has she been saying to you?" screamed the old man -furiously. - -"But I have heard that the crocuses promise well," continued my -companion imperturbably. - -"Ha! You put me off, do you?" said our new visitor, taking a step -forward and shaking his hunting-crop. "I know you, you scoundrel! -I have heard of you before. You are Holmes, the meddler." - -My friend smiled. - -"Holmes, the busybody!" - -His smile broadened. - -"Holmes, the Scotland Yard Jack-in-office!" - -Holmes chuckled heartily. "Your conversation is most -entertaining," said he. "When you go out close the door, for -there is a decided draught." - -"I will go when I have said my say. Don't you dare to meddle with -my affairs. I know that Miss Stoner has been here. I traced her! -I am a dangerous man to fall foul of! See here." He stepped -swiftly forward, seized the poker, and bent it into a curve with -his huge brown hands. - -"See that you keep yourself out of my grip," he snarled, and -hurling the twisted poker into the fireplace he strode out of the -room. - -"He seems a very amiable person," said Holmes, laughing. "I am -not quite so bulky, but if he had remained I might have shown him -that my grip was not much more feeble than his own." As he spoke -he picked up the steel poker and, with a sudden effort, -straightened it out again. - -"Fancy his having the insolence to confound me with the official -detective force! This incident gives zest to our investigation, -however, and I only trust that our little friend will not suffer -from her imprudence in allowing this brute to trace her. And now, -Watson, we shall order breakfast, and afterwards I shall walk -down to Doctors' Commons, where I hope to get some data which may -help us in this matter." - - -It was nearly one o'clock when Sherlock Holmes returned from his -excursion. He held in his hand a sheet of blue paper, scrawled -over with notes and figures. - -"I have seen the will of the deceased wife," said he. "To -determine its exact meaning I have been obliged to work out the -present prices of the investments with which it is concerned. The -total income, which at the time of the wife's death was little -short of 1100 pounds, is now, through the fall in agricultural -prices, not more than 750 pounds. Each daughter can claim an -income of 250 pounds, in case of marriage. It is evident, -therefore, that if both girls had married, this beauty would have -had a mere pittance, while even one of them would cripple him to -a very serious extent. My morning's work has not been wasted, -since it has proved that he has the very strongest motives for -standing in the way of anything of the sort. And now, Watson, -this is too serious for dawdling, especially as the old man is -aware that we are interesting ourselves in his affairs; so if you -are ready, we shall call a cab and drive to Waterloo. I should be -very much obliged if you would slip your revolver into your -pocket. An Eley's No. 2 is an excellent argument with gentlemen -who can twist steel pokers into knots. That and a tooth-brush -are, I think, all that we need." - -At Waterloo we were fortunate in catching a train for -Leatherhead, where we hired a trap at the station inn and drove -for four or five miles through the lovely Surrey lanes. It was a -perfect day, with a bright sun and a few fleecy clouds in the -heavens. The trees and wayside hedges were just throwing out -their first green shoots, and the air was full of the pleasant -smell of the moist earth. To me at least there was a strange -contrast between the sweet promise of the spring and this -sinister quest upon which we were engaged. My companion sat in -the front of the trap, his arms folded, his hat pulled down over -his eyes, and his chin sunk upon his breast, buried in the -deepest thought. Suddenly, however, he started, tapped me on the -shoulder, and pointed over the meadows. - -"Look there!" said he. - -A heavily timbered park stretched up in a gentle slope, -thickening into a grove at the highest point. From amid the -branches there jutted out the grey gables and high roof-tree of a -very old mansion. - -"Stoke Moran?" said he. - -"Yes, sir, that be the house of Dr. Grimesby Roylott," remarked -the driver. - -"There is some building going on there," said Holmes; "that is -where we are going." - -"There's the village," said the driver, pointing to a cluster of -roofs some distance to the left; "but if you want to get to the -house, you'll find it shorter to get over this stile, and so by -the foot-path over the fields. There it is, where the lady is -walking." - -"And the lady, I fancy, is Miss Stoner," observed Holmes, shading -his eyes. "Yes, I think we had better do as you suggest." - -We got off, paid our fare, and the trap rattled back on its way -to Leatherhead. - -"I thought it as well," said Holmes as we climbed the stile, -"that this fellow should think we had come here as architects, or -on some definite business. It may stop his gossip. -Good-afternoon, Miss Stoner. You see that we have been as good as -our word." - -Our client of the morning had hurried forward to meet us with a -face which spoke her joy. "I have been waiting so eagerly for -you," she cried, shaking hands with us warmly. "All has turned -out splendidly. Dr. Roylott has gone to town, and it is unlikely -that he will be back before evening." - -"We have had the pleasure of making the doctor's acquaintance," -said Holmes, and in a few words he sketched out what had -occurred. Miss Stoner turned white to the lips as she listened. - -"Good heavens!" she cried, "he has followed me, then." - -"So it appears." - -"He is so cunning that I never know when I am safe from him. What -will he say when he returns?" - -"He must guard himself, for he may find that there is someone -more cunning than himself upon his track. You must lock yourself -up from him to-night. If he is violent, we shall take you away to -your aunt's at Harrow. Now, we must make the best use of our -time, so kindly take us at once to the rooms which we are to -examine." - -The building was of grey, lichen-blotched stone, with a high -central portion and two curving wings, like the claws of a crab, -thrown out on each side. In one of these wings the windows were -broken and blocked with wooden boards, while the roof was partly -caved in, a picture of ruin. The central portion was in little -better repair, but the right-hand block was comparatively modern, -and the blinds in the windows, with the blue smoke curling up -from the chimneys, showed that this was where the family resided. -Some scaffolding had been erected against the end wall, and the -stone-work had been broken into, but there were no signs of any -workmen at the moment of our visit. Holmes walked slowly up and -down the ill-trimmed lawn and examined with deep attention the -outsides of the windows. - -"This, I take it, belongs to the room in which you used to sleep, -the centre one to your sister's, and the one next to the main -building to Dr. Roylott's chamber?" - -"Exactly so. But I am now sleeping in the middle one." - -"Pending the alterations, as I understand. By the way, there does -not seem to be any very pressing need for repairs at that end -wall." - -"There were none. I believe that it was an excuse to move me from -my room." - -"Ah! that is suggestive. Now, on the other side of this narrow -wing runs the corridor from which these three rooms open. There -are windows in it, of course?" - -"Yes, but very small ones. Too narrow for anyone to pass -through." - -"As you both locked your doors at night, your rooms were -unapproachable from that side. Now, would you have the kindness -to go into your room and bar your shutters?" - -Miss Stoner did so, and Holmes, after a careful examination -through the open window, endeavoured in every way to force the -shutter open, but without success. There was no slit through -which a knife could be passed to raise the bar. Then with his -lens he tested the hinges, but they were of solid iron, built -firmly into the massive masonry. "Hum!" said he, scratching his -chin in some perplexity, "my theory certainly presents some -difficulties. No one could pass these shutters if they were -bolted. Well, we shall see if the inside throws any light upon -the matter." - -A small side door led into the whitewashed corridor from which -the three bedrooms opened. Holmes refused to examine the third -chamber, so we passed at once to the second, that in which Miss -Stoner was now sleeping, and in which her sister had met with her -fate. It was a homely little room, with a low ceiling and a -gaping fireplace, after the fashion of old country-houses. A -brown chest of drawers stood in one corner, a narrow -white-counterpaned bed in another, and a dressing-table on the -left-hand side of the window. These articles, with two small -wicker-work chairs, made up all the furniture in the room save -for a square of Wilton carpet in the centre. The boards round and -the panelling of the walls were of brown, worm-eaten oak, so old -and discoloured that it may have dated from the original building -of the house. Holmes drew one of the chairs into a corner and sat -silent, while his eyes travelled round and round and up and down, -taking in every detail of the apartment. - -"Where does that bell communicate with?" he asked at last -pointing to a thick bell-rope which hung down beside the bed, the -tassel actually lying upon the pillow. - -"It goes to the housekeeper's room." - -"It looks newer than the other things?" - -"Yes, it was only put there a couple of years ago." - -"Your sister asked for it, I suppose?" - -"No, I never heard of her using it. We used always to get what we -wanted for ourselves." - -"Indeed, it seemed unnecessary to put so nice a bell-pull there. -You will excuse me for a few minutes while I satisfy myself as to -this floor." He threw himself down upon his face with his lens in -his hand and crawled swiftly backward and forward, examining -minutely the cracks between the boards. Then he did the same with -the wood-work with which the chamber was panelled. Finally he -walked over to the bed and spent some time in staring at it and -in running his eye up and down the wall. Finally he took the -bell-rope in his hand and gave it a brisk tug. - -"Why, it's a dummy," said he. - -"Won't it ring?" - -"No, it is not even attached to a wire. This is very interesting. -You can see now that it is fastened to a hook just above where -the little opening for the ventilator is." - -"How very absurd! I never noticed that before." - -"Very strange!" muttered Holmes, pulling at the rope. "There are -one or two very singular points about this room. For example, -what a fool a builder must be to open a ventilator into another -room, when, with the same trouble, he might have communicated -with the outside air!" - -"That is also quite modern," said the lady. - -"Done about the same time as the bell-rope?" remarked Holmes. - -"Yes, there were several little changes carried out about that -time." - -"They seem to have been of a most interesting character--dummy -bell-ropes, and ventilators which do not ventilate. With your -permission, Miss Stoner, we shall now carry our researches into -the inner apartment." - -Dr. Grimesby Roylott's chamber was larger than that of his -step-daughter, but was as plainly furnished. A camp-bed, a small -wooden shelf full of books, mostly of a technical character, an -armchair beside the bed, a plain wooden chair against the wall, a -round table, and a large iron safe were the principal things -which met the eye. Holmes walked slowly round and examined each -and all of them with the keenest interest. - -"What's in here?" he asked, tapping the safe. - -"My stepfather's business papers." - -"Oh! you have seen inside, then?" - -"Only once, some years ago. I remember that it was full of -papers." - -"There isn't a cat in it, for example?" - -"No. What a strange idea!" - -"Well, look at this!" He took up a small saucer of milk which -stood on the top of it. - -"No; we don't keep a cat. But there is a cheetah and a baboon." - -"Ah, yes, of course! Well, a cheetah is just a big cat, and yet a -saucer of milk does not go very far in satisfying its wants, I -daresay. There is one point which I should wish to determine." He -squatted down in front of the wooden chair and examined the seat -of it with the greatest attention. - -"Thank you. That is quite settled," said he, rising and putting -his lens in his pocket. "Hullo! Here is something interesting!" - -The object which had caught his eye was a small dog lash hung on -one corner of the bed. The lash, however, was curled upon itself -and tied so as to make a loop of whipcord. - -"What do you make of that, Watson?" - -"It's a common enough lash. But I don't know why it should be -tied." - -"That is not quite so common, is it? Ah, me! it's a wicked world, -and when a clever man turns his brains to crime it is the worst -of all. I think that I have seen enough now, Miss Stoner, and -with your permission we shall walk out upon the lawn." - -I had never seen my friend's face so grim or his brow so dark as -it was when we turned from the scene of this investigation. We -had walked several times up and down the lawn, neither Miss -Stoner nor myself liking to break in upon his thoughts before he -roused himself from his reverie. - -"It is very essential, Miss Stoner," said he, "that you should -absolutely follow my advice in every respect." - -"I shall most certainly do so." - -"The matter is too serious for any hesitation. Your life may -depend upon your compliance." - -"I assure you that I am in your hands." - -"In the first place, both my friend and I must spend the night in -your room." - -Both Miss Stoner and I gazed at him in astonishment. - -"Yes, it must be so. Let me explain. I believe that that is the -village inn over there?" - -"Yes, that is the Crown." - -"Very good. Your windows would be visible from there?" - -"Certainly." - -"You must confine yourself to your room, on pretence of a -headache, when your stepfather comes back. Then when you hear him -retire for the night, you must open the shutters of your window, -undo the hasp, put your lamp there as a signal to us, and then -withdraw quietly with everything which you are likely to want -into the room which you used to occupy. I have no doubt that, in -spite of the repairs, you could manage there for one night." - -"Oh, yes, easily." - -"The rest you will leave in our hands." - -"But what will you do?" - -"We shall spend the night in your room, and we shall investigate -the cause of this noise which has disturbed you." - -"I believe, Mr. Holmes, that you have already made up your mind," -said Miss Stoner, laying her hand upon my companion's sleeve. - -"Perhaps I have." - -"Then, for pity's sake, tell me what was the cause of my sister's -death." - -"I should prefer to have clearer proofs before I speak." - -"You can at least tell me whether my own thought is correct, and -if she died from some sudden fright." - -"No, I do not think so. I think that there was probably some more -tangible cause. And now, Miss Stoner, we must leave you for if -Dr. Roylott returned and saw us our journey would be in vain. -Good-bye, and be brave, for if you will do what I have told you, -you may rest assured that we shall soon drive away the dangers -that threaten you." - -Sherlock Holmes and I had no difficulty in engaging a bedroom and -sitting-room at the Crown Inn. They were on the upper floor, and -from our window we could command a view of the avenue gate, and -of the inhabited wing of Stoke Moran Manor House. At dusk we saw -Dr. Grimesby Roylott drive past, his huge form looming up beside -the little figure of the lad who drove him. The boy had some -slight difficulty in undoing the heavy iron gates, and we heard -the hoarse roar of the doctor's voice and saw the fury with which -he shook his clinched fists at him. The trap drove on, and a few -minutes later we saw a sudden light spring up among the trees as -the lamp was lit in one of the sitting-rooms. - -"Do you know, Watson," said Holmes as we sat together in the -gathering darkness, "I have really some scruples as to taking you -to-night. There is a distinct element of danger." - -"Can I be of assistance?" - -"Your presence might be invaluable." - -"Then I shall certainly come." - -"It is very kind of you." - -"You speak of danger. You have evidently seen more in these rooms -than was visible to me." - -"No, but I fancy that I may have deduced a little more. I imagine -that you saw all that I did." - -"I saw nothing remarkable save the bell-rope, and what purpose -that could answer I confess is more than I can imagine." - -"You saw the ventilator, too?" - -"Yes, but I do not think that it is such a very unusual thing to -have a small opening between two rooms. It was so small that a -rat could hardly pass through." - -"I knew that we should find a ventilator before ever we came to -Stoke Moran." - -"My dear Holmes!" - -"Oh, yes, I did. You remember in her statement she said that her -sister could smell Dr. Roylott's cigar. Now, of course that -suggested at once that there must be a communication between the -two rooms. It could only be a small one, or it would have been -remarked upon at the coroner's inquiry. I deduced a ventilator." - -"But what harm can there be in that?" - -"Well, there is at least a curious coincidence of dates. A -ventilator is made, a cord is hung, and a lady who sleeps in the -bed dies. Does not that strike you?" - -"I cannot as yet see any connection." - -"Did you observe anything very peculiar about that bed?" - -"No." - -"It was clamped to the floor. Did you ever see a bed fastened -like that before?" - -"I cannot say that I have." - -"The lady could not move her bed. It must always be in the same -relative position to the ventilator and to the rope--or so we may -call it, since it was clearly never meant for a bell-pull." - -"Holmes," I cried, "I seem to see dimly what you are hinting at. -We are only just in time to prevent some subtle and horrible -crime." - -"Subtle enough and horrible enough. When a doctor does go wrong -he is the first of criminals. He has nerve and he has knowledge. -Palmer and Pritchard were among the heads of their profession. -This man strikes even deeper, but I think, Watson, that we shall -be able to strike deeper still. But we shall have horrors enough -before the night is over; for goodness' sake let us have a quiet -pipe and turn our minds for a few hours to something more -cheerful." - - -About nine o'clock the light among the trees was extinguished, -and all was dark in the direction of the Manor House. Two hours -passed slowly away, and then, suddenly, just at the stroke of -eleven, a single bright light shone out right in front of us. - -"That is our signal," said Holmes, springing to his feet; "it -comes from the middle window." - -As we passed out he exchanged a few words with the landlord, -explaining that we were going on a late visit to an acquaintance, -and that it was possible that we might spend the night there. A -moment later we were out on the dark road, a chill wind blowing -in our faces, and one yellow light twinkling in front of us -through the gloom to guide us on our sombre errand. - -There was little difficulty in entering the grounds, for -unrepaired breaches gaped in the old park wall. Making our way -among the trees, we reached the lawn, crossed it, and were about -to enter through the window when out from a clump of laurel -bushes there darted what seemed to be a hideous and distorted -child, who threw itself upon the grass with writhing limbs and -then ran swiftly across the lawn into the darkness. - -"My God!" I whispered; "did you see it?" - -Holmes was for the moment as startled as I. His hand closed like -a vice upon my wrist in his agitation. Then he broke into a low -laugh and put his lips to my ear. - -"It is a nice household," he murmured. "That is the baboon." - -I had forgotten the strange pets which the doctor affected. There -was a cheetah, too; perhaps we might find it upon our shoulders -at any moment. I confess that I felt easier in my mind when, -after following Holmes' example and slipping off my shoes, I -found myself inside the bedroom. My companion noiselessly closed -the shutters, moved the lamp onto the table, and cast his eyes -round the room. All was as we had seen it in the daytime. Then -creeping up to me and making a trumpet of his hand, he whispered -into my ear again so gently that it was all that I could do to -distinguish the words: - -"The least sound would be fatal to our plans." - -I nodded to show that I had heard. - -"We must sit without light. He would see it through the -ventilator." - -I nodded again. - -"Do not go asleep; your very life may depend upon it. Have your -pistol ready in case we should need it. I will sit on the side of -the bed, and you in that chair." - -I took out my revolver and laid it on the corner of the table. - -Holmes had brought up a long thin cane, and this he placed upon -the bed beside him. By it he laid the box of matches and the -stump of a candle. Then he turned down the lamp, and we were left -in darkness. - -How shall I ever forget that dreadful vigil? I could not hear a -sound, not even the drawing of a breath, and yet I knew that my -companion sat open-eyed, within a few feet of me, in the same -state of nervous tension in which I was myself. The shutters cut -off the least ray of light, and we waited in absolute darkness. - -From outside came the occasional cry of a night-bird, and once at -our very window a long drawn catlike whine, which told us that -the cheetah was indeed at liberty. Far away we could hear the -deep tones of the parish clock, which boomed out every quarter of -an hour. How long they seemed, those quarters! Twelve struck, and -one and two and three, and still we sat waiting silently for -whatever might befall. - -Suddenly there was the momentary gleam of a light up in the -direction of the ventilator, which vanished immediately, but was -succeeded by a strong smell of burning oil and heated metal. -Someone in the next room had lit a dark-lantern. I heard a gentle -sound of movement, and then all was silent once more, though the -smell grew stronger. For half an hour I sat with straining ears. -Then suddenly another sound became audible--a very gentle, -soothing sound, like that of a small jet of steam escaping -continually from a kettle. The instant that we heard it, Holmes -sprang from the bed, struck a match, and lashed furiously with -his cane at the bell-pull. - -"You see it, Watson?" he yelled. "You see it?" - -But I saw nothing. At the moment when Holmes struck the light I -heard a low, clear whistle, but the sudden glare flashing into my -weary eyes made it impossible for me to tell what it was at which -my friend lashed so savagely. I could, however, see that his face -was deadly pale and filled with horror and loathing. He had -ceased to strike and was gazing up at the ventilator when -suddenly there broke from the silence of the night the most -horrible cry to which I have ever listened. It swelled up louder -and louder, a hoarse yell of pain and fear and anger all mingled -in the one dreadful shriek. They say that away down in the -village, and even in the distant parsonage, that cry raised the -sleepers from their beds. It struck cold to our hearts, and I -stood gazing at Holmes, and he at me, until the last echoes of it -had died away into the silence from which it rose. - -"What can it mean?" I gasped. - -"It means that it is all over," Holmes answered. "And perhaps, -after all, it is for the best. Take your pistol, and we will -enter Dr. Roylott's room." - -With a grave face he lit the lamp and led the way down the -corridor. Twice he struck at the chamber door without any reply -from within. Then he turned the handle and entered, I at his -heels, with the cocked pistol in my hand. - -It was a singular sight which met our eyes. On the table stood a -dark-lantern with the shutter half open, throwing a brilliant -beam of light upon the iron safe, the door of which was ajar. -Beside this table, on the wooden chair, sat Dr. Grimesby Roylott -clad in a long grey dressing-gown, his bare ankles protruding -beneath, and his feet thrust into red heelless Turkish slippers. -Across his lap lay the short stock with the long lash which we -had noticed during the day. His chin was cocked upward and his -eyes were fixed in a dreadful, rigid stare at the corner of the -ceiling. Round his brow he had a peculiar yellow band, with -brownish speckles, which seemed to be bound tightly round his -head. As we entered he made neither sound nor motion. - -"The band! the speckled band!" whispered Holmes. - -I took a step forward. In an instant his strange headgear began -to move, and there reared itself from among his hair the squat -diamond-shaped head and puffed neck of a loathsome serpent. - -"It is a swamp adder!" cried Holmes; "the deadliest snake in -India. He has died within ten seconds of being bitten. Violence -does, in truth, recoil upon the violent, and the schemer falls -into the pit which he digs for another. Let us thrust this -creature back into its den, and we can then remove Miss Stoner to -some place of shelter and let the county police know what has -happened." - -As he spoke he drew the dog-whip swiftly from the dead man's lap, -and throwing the noose round the reptile's neck he drew it from -its horrid perch and, carrying it at arm's length, threw it into -the iron safe, which he closed upon it. - -Such are the true facts of the death of Dr. Grimesby Roylott, of -Stoke Moran. It is not necessary that I should prolong a -narrative which has already run to too great a length by telling -how we broke the sad news to the terrified girl, how we conveyed -her by the morning train to the care of her good aunt at Harrow, -of how the slow process of official inquiry came to the -conclusion that the doctor met his fate while indiscreetly -playing with a dangerous pet. The little which I had yet to learn -of the case was told me by Sherlock Holmes as we travelled back -next day. - -"I had," said he, "come to an entirely erroneous conclusion which -shows, my dear Watson, how dangerous it always is to reason from -insufficient data. The presence of the gipsies, and the use of -the word 'band,' which was used by the poor girl, no doubt, to -explain the appearance which she had caught a hurried glimpse of -by the light of her match, were sufficient to put me upon an -entirely wrong scent. I can only claim the merit that I instantly -reconsidered my position when, however, it became clear to me -that whatever danger threatened an occupant of the room could not -come either from the window or the door. My attention was -speedily drawn, as I have already remarked to you, to this -ventilator, and to the bell-rope which hung down to the bed. The -discovery that this was a dummy, and that the bed was clamped to -the floor, instantly gave rise to the suspicion that the rope was -there as a bridge for something passing through the hole and -coming to the bed. The idea of a snake instantly occurred to me, -and when I coupled it with my knowledge that the doctor was -furnished with a supply of creatures from India, I felt that I -was probably on the right track. The idea of using a form of -poison which could not possibly be discovered by any chemical -test was just such a one as would occur to a clever and ruthless -man who had had an Eastern training. The rapidity with which such -a poison would take effect would also, from his point of view, be -an advantage. It would be a sharp-eyed coroner, indeed, who could -distinguish the two little dark punctures which would show where -the poison fangs had done their work. Then I thought of the -whistle. Of course he must recall the snake before the morning -light revealed it to the victim. He had trained it, probably by -the use of the milk which we saw, to return to him when summoned. -He would put it through this ventilator at the hour that he -thought best, with the certainty that it would crawl down the -rope and land on the bed. It might or might not bite the -occupant, perhaps she might escape every night for a week, but -sooner or later she must fall a victim. - -"I had come to these conclusions before ever I had entered his -room. An inspection of his chair showed me that he had been in -the habit of standing on it, which of course would be necessary -in order that he should reach the ventilator. The sight of the -safe, the saucer of milk, and the loop of whipcord were enough to -finally dispel any doubts which may have remained. The metallic -clang heard by Miss Stoner was obviously caused by her stepfather -hastily closing the door of his safe upon its terrible occupant. -Having once made up my mind, you know the steps which I took in -order to put the matter to the proof. I heard the creature hiss -as I have no doubt that you did also, and I instantly lit the -light and attacked it." - -"With the result of driving it through the ventilator." - -"And also with the result of causing it to turn upon its master -at the other side. Some of the blows of my cane came home and -roused its snakish temper, so that it flew upon the first person -it saw. In this way I am no doubt indirectly responsible for Dr. -Grimesby Roylott's death, and I cannot say that it is likely to -weigh very heavily upon my conscience." - - - -IX. THE ADVENTURE OF THE ENGINEER'S THUMB - -Of all the problems which have been submitted to my friend, Mr. -Sherlock Holmes, for solution during the years of our intimacy, -there were only two which I was the means of introducing to his -notice--that of Mr. Hatherley's thumb, and that of Colonel -Warburton's madness. Of these the latter may have afforded a -finer field for an acute and original observer, but the other was -so strange in its inception and so dramatic in its details that -it may be the more worthy of being placed upon record, even if it -gave my friend fewer openings for those deductive methods of -reasoning by which he achieved such remarkable results. The story -has, I believe, been told more than once in the newspapers, but, -like all such narratives, its effect is much less striking when -set forth en bloc in a single half-column of print than when the -facts slowly evolve before your own eyes, and the mystery clears -gradually away as each new discovery furnishes a step which leads -on to the complete truth. At the time the circumstances made a -deep impression upon me, and the lapse of two years has hardly -served to weaken the effect. - -It was in the summer of '89, not long after my marriage, that the -events occurred which I am now about to summarise. I had returned -to civil practice and had finally abandoned Holmes in his Baker -Street rooms, although I continually visited him and occasionally -even persuaded him to forgo his Bohemian habits so far as to come -and visit us. My practice had steadily increased, and as I -happened to live at no very great distance from Paddington -Station, I got a few patients from among the officials. One of -these, whom I had cured of a painful and lingering disease, was -never weary of advertising my virtues and of endeavouring to send -me on every sufferer over whom he might have any influence. - -One morning, at a little before seven o'clock, I was awakened by -the maid tapping at the door to announce that two men had come -from Paddington and were waiting in the consulting-room. I -dressed hurriedly, for I knew by experience that railway cases -were seldom trivial, and hastened downstairs. As I descended, my -old ally, the guard, came out of the room and closed the door -tightly behind him. - -"I've got him here," he whispered, jerking his thumb over his -shoulder; "he's all right." - -"What is it, then?" I asked, for his manner suggested that it was -some strange creature which he had caged up in my room. - -"It's a new patient," he whispered. "I thought I'd bring him -round myself; then he couldn't slip away. There he is, all safe -and sound. I must go now, Doctor; I have my dooties, just the -same as you." And off he went, this trusty tout, without even -giving me time to thank him. - -I entered my consulting-room and found a gentleman seated by the -table. He was quietly dressed in a suit of heather tweed with a -soft cloth cap which he had laid down upon my books. Round one of -his hands he had a handkerchief wrapped, which was mottled all -over with bloodstains. He was young, not more than -five-and-twenty, I should say, with a strong, masculine face; but -he was exceedingly pale and gave me the impression of a man who -was suffering from some strong agitation, which it took all his -strength of mind to control. - -"I am sorry to knock you up so early, Doctor," said he, "but I -have had a very serious accident during the night. I came in by -train this morning, and on inquiring at Paddington as to where I -might find a doctor, a worthy fellow very kindly escorted me -here. I gave the maid a card, but I see that she has left it upon -the side-table." - -I took it up and glanced at it. "Mr. Victor Hatherley, hydraulic -engineer, 16A, Victoria Street (3rd floor)." That was the name, -style, and abode of my morning visitor. "I regret that I have -kept you waiting," said I, sitting down in my library-chair. "You -are fresh from a night journey, I understand, which is in itself -a monotonous occupation." - -"Oh, my night could not be called monotonous," said he, and -laughed. He laughed very heartily, with a high, ringing note, -leaning back in his chair and shaking his sides. All my medical -instincts rose up against that laugh. - -"Stop it!" I cried; "pull yourself together!" and I poured out -some water from a caraffe. - -It was useless, however. He was off in one of those hysterical -outbursts which come upon a strong nature when some great crisis -is over and gone. Presently he came to himself once more, very -weary and pale-looking. - -"I have been making a fool of myself," he gasped. - -"Not at all. Drink this." I dashed some brandy into the water, -and the colour began to come back to his bloodless cheeks. - -"That's better!" said he. "And now, Doctor, perhaps you would -kindly attend to my thumb, or rather to the place where my thumb -used to be." - -He unwound the handkerchief and held out his hand. It gave even -my hardened nerves a shudder to look at it. There were four -protruding fingers and a horrid red, spongy surface where the -thumb should have been. It had been hacked or torn right out from -the roots. - -"Good heavens!" I cried, "this is a terrible injury. It must have -bled considerably." - -"Yes, it did. I fainted when it was done, and I think that I must -have been senseless for a long time. When I came to I found that -it was still bleeding, so I tied one end of my handkerchief very -tightly round the wrist and braced it up with a twig." - -"Excellent! You should have been a surgeon." - -"It is a question of hydraulics, you see, and came within my own -province." - -"This has been done," said I, examining the wound, "by a very -heavy and sharp instrument." - -"A thing like a cleaver," said he. - -"An accident, I presume?" - -"By no means." - -"What! a murderous attack?" - -"Very murderous indeed." - -"You horrify me." - -I sponged the wound, cleaned it, dressed it, and finally covered -it over with cotton wadding and carbolised bandages. He lay back -without wincing, though he bit his lip from time to time. - -"How is that?" I asked when I had finished. - -"Capital! Between your brandy and your bandage, I feel a new man. -I was very weak, but I have had a good deal to go through." - -"Perhaps you had better not speak of the matter. It is evidently -trying to your nerves." - -"Oh, no, not now. I shall have to tell my tale to the police; -but, between ourselves, if it were not for the convincing -evidence of this wound of mine, I should be surprised if they -believed my statement, for it is a very extraordinary one, and I -have not much in the way of proof with which to back it up; and, -even if they believe me, the clues which I can give them are so -vague that it is a question whether justice will be done." - -"Ha!" cried I, "if it is anything in the nature of a problem -which you desire to see solved, I should strongly recommend you -to come to my friend, Mr. Sherlock Holmes, before you go to the -official police." - -"Oh, I have heard of that fellow," answered my visitor, "and I -should be very glad if he would take the matter up, though of -course I must use the official police as well. Would you give me -an introduction to him?" - -"I'll do better. I'll take you round to him myself." - -"I should be immensely obliged to you." - -"We'll call a cab and go together. We shall just be in time to -have a little breakfast with him. Do you feel equal to it?" - -"Yes; I shall not feel easy until I have told my story." - -"Then my servant will call a cab, and I shall be with you in an -instant." I rushed upstairs, explained the matter shortly to my -wife, and in five minutes was inside a hansom, driving with my -new acquaintance to Baker Street. - -Sherlock Holmes was, as I expected, lounging about his -sitting-room in his dressing-gown, reading the agony column of The -Times and smoking his before-breakfast pipe, which was composed -of all the plugs and dottles left from his smokes of the day -before, all carefully dried and collected on the corner of the -mantelpiece. He received us in his quietly genial fashion, -ordered fresh rashers and eggs, and joined us in a hearty meal. -When it was concluded he settled our new acquaintance upon the -sofa, placed a pillow beneath his head, and laid a glass of -brandy and water within his reach. - -"It is easy to see that your experience has been no common one, -Mr. Hatherley," said he. "Pray, lie down there and make yourself -absolutely at home. Tell us what you can, but stop when you are -tired and keep up your strength with a little stimulant." - -"Thank you," said my patient, "but I have felt another man since -the doctor bandaged me, and I think that your breakfast has -completed the cure. I shall take up as little of your valuable -time as possible, so I shall start at once upon my peculiar -experiences." - -Holmes sat in his big armchair with the weary, heavy-lidded -expression which veiled his keen and eager nature, while I sat -opposite to him, and we listened in silence to the strange story -which our visitor detailed to us. - -"You must know," said he, "that I am an orphan and a bachelor, -residing alone in lodgings in London. By profession I am a -hydraulic engineer, and I have had considerable experience of my -work during the seven years that I was apprenticed to Venner & -Matheson, the well-known firm, of Greenwich. Two years ago, -having served my time, and having also come into a fair sum of -money through my poor father's death, I determined to start in -business for myself and took professional chambers in Victoria -Street. - -"I suppose that everyone finds his first independent start in -business a dreary experience. To me it has been exceptionally so. -During two years I have had three consultations and one small -job, and that is absolutely all that my profession has brought -me. My gross takings amount to 27 pounds 10s. Every day, from -nine in the morning until four in the afternoon, I waited in my -little den, until at last my heart began to sink, and I came to -believe that I should never have any practice at all. - -"Yesterday, however, just as I was thinking of leaving the -office, my clerk entered to say there was a gentleman waiting who -wished to see me upon business. He brought up a card, too, with -the name of 'Colonel Lysander Stark' engraved upon it. Close at -his heels came the colonel himself, a man rather over the middle -size, but of an exceeding thinness. I do not think that I have -ever seen so thin a man. His whole face sharpened away into nose -and chin, and the skin of his cheeks was drawn quite tense over -his outstanding bones. Yet this emaciation seemed to be his -natural habit, and due to no disease, for his eye was bright, his -step brisk, and his bearing assured. He was plainly but neatly -dressed, and his age, I should judge, would be nearer forty than -thirty. - -"'Mr. Hatherley?' said he, with something of a German accent. -'You have been recommended to me, Mr. Hatherley, as being a man -who is not only proficient in his profession but is also discreet -and capable of preserving a secret.' - -"I bowed, feeling as flattered as any young man would at such an -address. 'May I ask who it was who gave me so good a character?' - -"'Well, perhaps it is better that I should not tell you that just -at this moment. I have it from the same source that you are both -an orphan and a bachelor and are residing alone in London.' - -"'That is quite correct,' I answered; 'but you will excuse me if -I say that I cannot see how all this bears upon my professional -qualifications. I understand that it was on a professional matter -that you wished to speak to me?' - -"'Undoubtedly so. But you will find that all I say is really to -the point. I have a professional commission for you, but absolute -secrecy is quite essential--absolute secrecy, you understand, and -of course we may expect that more from a man who is alone than -from one who lives in the bosom of his family.' - -"'If I promise to keep a secret,' said I, 'you may absolutely -depend upon my doing so.' - -"He looked very hard at me as I spoke, and it seemed to me that I -had never seen so suspicious and questioning an eye. - -"'Do you promise, then?' said he at last. - -"'Yes, I promise.' - -"'Absolute and complete silence before, during, and after? No -reference to the matter at all, either in word or writing?' - -"'I have already given you my word.' - -"'Very good.' He suddenly sprang up, and darting like lightning -across the room he flung open the door. The passage outside was -empty. - -"'That's all right,' said he, coming back. 'I know that clerks are -sometimes curious as to their master's affairs. Now we can talk -in safety.' He drew up his chair very close to mine and began to -stare at me again with the same questioning and thoughtful look. - -"A feeling of repulsion, and of something akin to fear had begun -to rise within me at the strange antics of this fleshless man. -Even my dread of losing a client could not restrain me from -showing my impatience. - -"'I beg that you will state your business, sir,' said I; 'my time -is of value.' Heaven forgive me for that last sentence, but the -words came to my lips. - -"'How would fifty guineas for a night's work suit you?' he asked. - -"'Most admirably.' - -"'I say a night's work, but an hour's would be nearer the mark. I -simply want your opinion about a hydraulic stamping machine which -has got out of gear. If you show us what is wrong we shall soon -set it right ourselves. What do you think of such a commission as -that?' - -"'The work appears to be light and the pay munificent.' - -"'Precisely so. We shall want you to come to-night by the last -train.' - -"'Where to?' - -"'To Eyford, in Berkshire. It is a little place near the borders -of Oxfordshire, and within seven miles of Reading. There is a -train from Paddington which would bring you there at about -11:15.' - -"'Very good.' - -"'I shall come down in a carriage to meet you.' - -"'There is a drive, then?' - -"'Yes, our little place is quite out in the country. It is a good -seven miles from Eyford Station.' - -"'Then we can hardly get there before midnight. I suppose there -would be no chance of a train back. I should be compelled to stop -the night.' - -"'Yes, we could easily give you a shake-down.' - -"'That is very awkward. Could I not come at some more convenient -hour?' - -"'We have judged it best that you should come late. It is to -recompense you for any inconvenience that we are paying to you, a -young and unknown man, a fee which would buy an opinion from the -very heads of your profession. Still, of course, if you would -like to draw out of the business, there is plenty of time to do -so.' - -"I thought of the fifty guineas, and of how very useful they -would be to me. 'Not at all,' said I, 'I shall be very happy to -accommodate myself to your wishes. I should like, however, to -understand a little more clearly what it is that you wish me to -do.' - -"'Quite so. It is very natural that the pledge of secrecy which -we have exacted from you should have aroused your curiosity. I -have no wish to commit you to anything without your having it all -laid before you. I suppose that we are absolutely safe from -eavesdroppers?' - -"'Entirely.' - -"'Then the matter stands thus. You are probably aware that -fuller's-earth is a valuable product, and that it is only found -in one or two places in England?' - -"'I have heard so.' - -"'Some little time ago I bought a small place--a very small -place--within ten miles of Reading. I was fortunate enough to -discover that there was a deposit of fuller's-earth in one of my -fields. On examining it, however, I found that this deposit was a -comparatively small one, and that it formed a link between two -very much larger ones upon the right and left--both of them, -however, in the grounds of my neighbours. These good people were -absolutely ignorant that their land contained that which was -quite as valuable as a gold-mine. Naturally, it was to my -interest to buy their land before they discovered its true value, -but unfortunately I had no capital by which I could do this. I -took a few of my friends into the secret, however, and they -suggested that we should quietly and secretly work our own little -deposit and that in this way we should earn the money which would -enable us to buy the neighbouring fields. This we have now been -doing for some time, and in order to help us in our operations we -erected a hydraulic press. This press, as I have already -explained, has got out of order, and we wish your advice upon the -subject. We guard our secret very jealously, however, and if it -once became known that we had hydraulic engineers coming to our -little house, it would soon rouse inquiry, and then, if the facts -came out, it would be good-bye to any chance of getting these -fields and carrying out our plans. That is why I have made you -promise me that you will not tell a human being that you are -going to Eyford to-night. I hope that I make it all plain?' - -"'I quite follow you,' said I. 'The only point which I could not -quite understand was what use you could make of a hydraulic press -in excavating fuller's-earth, which, as I understand, is dug out -like gravel from a pit.' - -"'Ah!' said he carelessly, 'we have our own process. We compress -the earth into bricks, so as to remove them without revealing -what they are. But that is a mere detail. I have taken you fully -into my confidence now, Mr. Hatherley, and I have shown you how I -trust you.' He rose as he spoke. 'I shall expect you, then, at -Eyford at 11:15.' - -"'I shall certainly be there.' - -"'And not a word to a soul.' He looked at me with a last long, -questioning gaze, and then, pressing my hand in a cold, dank -grasp, he hurried from the room. - -"Well, when I came to think it all over in cool blood I was very -much astonished, as you may both think, at this sudden commission -which had been intrusted to me. On the one hand, of course, I was -glad, for the fee was at least tenfold what I should have asked -had I set a price upon my own services, and it was possible that -this order might lead to other ones. On the other hand, the face -and manner of my patron had made an unpleasant impression upon -me, and I could not think that his explanation of the -fuller's-earth was sufficient to explain the necessity for my -coming at midnight, and his extreme anxiety lest I should tell -anyone of my errand. However, I threw all fears to the winds, ate -a hearty supper, drove to Paddington, and started off, having -obeyed to the letter the injunction as to holding my tongue. - -"At Reading I had to change not only my carriage but my station. -However, I was in time for the last train to Eyford, and I -reached the little dim-lit station after eleven o'clock. I was the -only passenger who got out there, and there was no one upon the -platform save a single sleepy porter with a lantern. As I passed -out through the wicket gate, however, I found my acquaintance of -the morning waiting in the shadow upon the other side. Without a -word he grasped my arm and hurried me into a carriage, the door -of which was standing open. He drew up the windows on either -side, tapped on the wood-work, and away we went as fast as the -horse could go." - -"One horse?" interjected Holmes. - -"Yes, only one." - -"Did you observe the colour?" - -"Yes, I saw it by the side-lights when I was stepping into the -carriage. It was a chestnut." - -"Tired-looking or fresh?" - -"Oh, fresh and glossy." - -"Thank you. I am sorry to have interrupted you. Pray continue -your most interesting statement." - -"Away we went then, and we drove for at least an hour. Colonel -Lysander Stark had said that it was only seven miles, but I -should think, from the rate that we seemed to go, and from the -time that we took, that it must have been nearer twelve. He sat -at my side in silence all the time, and I was aware, more than -once when I glanced in his direction, that he was looking at me -with great intensity. The country roads seem to be not very good -in that part of the world, for we lurched and jolted terribly. I -tried to look out of the windows to see something of where we -were, but they were made of frosted glass, and I could make out -nothing save the occasional bright blur of a passing light. Now -and then I hazarded some remark to break the monotony of the -journey, but the colonel answered only in monosyllables, and the -conversation soon flagged. At last, however, the bumping of the -road was exchanged for the crisp smoothness of a gravel-drive, -and the carriage came to a stand. Colonel Lysander Stark sprang -out, and, as I followed after him, pulled me swiftly into a porch -which gaped in front of us. We stepped, as it were, right out of -the carriage and into the hall, so that I failed to catch the -most fleeting glance of the front of the house. The instant that -I had crossed the threshold the door slammed heavily behind us, -and I heard faintly the rattle of the wheels as the carriage -drove away. - -"It was pitch dark inside the house, and the colonel fumbled -about looking for matches and muttering under his breath. -Suddenly a door opened at the other end of the passage, and a -long, golden bar of light shot out in our direction. It grew -broader, and a woman appeared with a lamp in her hand, which she -held above her head, pushing her face forward and peering at us. -I could see that she was pretty, and from the gloss with which -the light shone upon her dark dress I knew that it was a rich -material. She spoke a few words in a foreign tongue in a tone as -though asking a question, and when my companion answered in a -gruff monosyllable she gave such a start that the lamp nearly -fell from her hand. Colonel Stark went up to her, whispered -something in her ear, and then, pushing her back into the room -from whence she had come, he walked towards me again with the -lamp in his hand. - -"'Perhaps you will have the kindness to wait in this room for a -few minutes,' said he, throwing open another door. It was a -quiet, little, plainly furnished room, with a round table in the -centre, on which several German books were scattered. Colonel -Stark laid down the lamp on the top of a harmonium beside the -door. 'I shall not keep you waiting an instant,' said he, and -vanished into the darkness. - -"I glanced at the books upon the table, and in spite of my -ignorance of German I could see that two of them were treatises -on science, the others being volumes of poetry. Then I walked -across to the window, hoping that I might catch some glimpse of -the country-side, but an oak shutter, heavily barred, was folded -across it. It was a wonderfully silent house. There was an old -clock ticking loudly somewhere in the passage, but otherwise -everything was deadly still. A vague feeling of uneasiness began -to steal over me. Who were these German people, and what were -they doing living in this strange, out-of-the-way place? And -where was the place? I was ten miles or so from Eyford, that was -all I knew, but whether north, south, east, or west I had no -idea. For that matter, Reading, and possibly other large towns, -were within that radius, so the place might not be so secluded, -after all. Yet it was quite certain, from the absolute stillness, -that we were in the country. I paced up and down the room, -humming a tune under my breath to keep up my spirits and feeling -that I was thoroughly earning my fifty-guinea fee. - -"Suddenly, without any preliminary sound in the midst of the -utter stillness, the door of my room swung slowly open. The woman -was standing in the aperture, the darkness of the hall behind -her, the yellow light from my lamp beating upon her eager and -beautiful face. I could see at a glance that she was sick with -fear, and the sight sent a chill to my own heart. She held up one -shaking finger to warn me to be silent, and she shot a few -whispered words of broken English at me, her eyes glancing back, -like those of a frightened horse, into the gloom behind her. - -"'I would go,' said she, trying hard, as it seemed to me, to -speak calmly; 'I would go. I should not stay here. There is no -good for you to do.' - -"'But, madam,' said I, 'I have not yet done what I came for. I -cannot possibly leave until I have seen the machine.' - -"'It is not worth your while to wait,' she went on. 'You can pass -through the door; no one hinders.' And then, seeing that I smiled -and shook my head, she suddenly threw aside her constraint and -made a step forward, with her hands wrung together. 'For the love -of Heaven!' she whispered, 'get away from here before it is too -late!' - -"But I am somewhat headstrong by nature, and the more ready to -engage in an affair when there is some obstacle in the way. I -thought of my fifty-guinea fee, of my wearisome journey, and of -the unpleasant night which seemed to be before me. Was it all to -go for nothing? Why should I slink away without having carried -out my commission, and without the payment which was my due? This -woman might, for all I knew, be a monomaniac. With a stout -bearing, therefore, though her manner had shaken me more than I -cared to confess, I still shook my head and declared my intention -of remaining where I was. She was about to renew her entreaties -when a door slammed overhead, and the sound of several footsteps -was heard upon the stairs. She listened for an instant, threw up -her hands with a despairing gesture, and vanished as suddenly and -as noiselessly as she had come. - -"The newcomers were Colonel Lysander Stark and a short thick man -with a chinchilla beard growing out of the creases of his double -chin, who was introduced to me as Mr. Ferguson. - -"'This is my secretary and manager,' said the colonel. 'By the -way, I was under the impression that I left this door shut just -now. I fear that you have felt the draught.' - -"'On the contrary,' said I, 'I opened the door myself because I -felt the room to be a little close.' - -"He shot one of his suspicious looks at me. 'Perhaps we had -better proceed to business, then,' said he. 'Mr. Ferguson and I -will take you up to see the machine.' - -"'I had better put my hat on, I suppose.' - -"'Oh, no, it is in the house.' - -"'What, you dig fuller's-earth in the house?' - -"'No, no. This is only where we compress it. But never mind that. -All we wish you to do is to examine the machine and to let us -know what is wrong with it.' - -"We went upstairs together, the colonel first with the lamp, the -fat manager and I behind him. It was a labyrinth of an old house, -with corridors, passages, narrow winding staircases, and little -low doors, the thresholds of which were hollowed out by the -generations who had crossed them. There were no carpets and no -signs of any furniture above the ground floor, while the plaster -was peeling off the walls, and the damp was breaking through in -green, unhealthy blotches. I tried to put on as unconcerned an -air as possible, but I had not forgotten the warnings of the -lady, even though I disregarded them, and I kept a keen eye upon -my two companions. Ferguson appeared to be a morose and silent -man, but I could see from the little that he said that he was at -least a fellow-countryman. - -"Colonel Lysander Stark stopped at last before a low door, which -he unlocked. Within was a small, square room, in which the three -of us could hardly get at one time. Ferguson remained outside, -and the colonel ushered me in. - -"'We are now,' said he, 'actually within the hydraulic press, and -it would be a particularly unpleasant thing for us if anyone were -to turn it on. The ceiling of this small chamber is really the -end of the descending piston, and it comes down with the force of -many tons upon this metal floor. There are small lateral columns -of water outside which receive the force, and which transmit and -multiply it in the manner which is familiar to you. The machine -goes readily enough, but there is some stiffness in the working -of it, and it has lost a little of its force. Perhaps you will -have the goodness to look it over and to show us how we can set -it right.' - -"I took the lamp from him, and I examined the machine very -thoroughly. It was indeed a gigantic one, and capable of -exercising enormous pressure. When I passed outside, however, and -pressed down the levers which controlled it, I knew at once by -the whishing sound that there was a slight leakage, which allowed -a regurgitation of water through one of the side cylinders. An -examination showed that one of the india-rubber bands which was -round the head of a driving-rod had shrunk so as not quite to -fill the socket along which it worked. This was clearly the cause -of the loss of power, and I pointed it out to my companions, who -followed my remarks very carefully and asked several practical -questions as to how they should proceed to set it right. When I -had made it clear to them, I returned to the main chamber of the -machine and took a good look at it to satisfy my own curiosity. -It was obvious at a glance that the story of the fuller's-earth -was the merest fabrication, for it would be absurd to suppose -that so powerful an engine could be designed for so inadequate a -purpose. The walls were of wood, but the floor consisted of a -large iron trough, and when I came to examine it I could see a -crust of metallic deposit all over it. I had stooped and was -scraping at this to see exactly what it was when I heard a -muttered exclamation in German and saw the cadaverous face of the -colonel looking down at me. - -"'What are you doing there?' he asked. - -"I felt angry at having been tricked by so elaborate a story as -that which he had told me. 'I was admiring your fuller's-earth,' -said I; 'I think that I should be better able to advise you as to -your machine if I knew what the exact purpose was for which it -was used.' - -"The instant that I uttered the words I regretted the rashness of -my speech. His face set hard, and a baleful light sprang up in -his grey eyes. - -"'Very well,' said he, 'you shall know all about the machine.' He -took a step backward, slammed the little door, and turned the key -in the lock. I rushed towards it and pulled at the handle, but it -was quite secure, and did not give in the least to my kicks and -shoves. 'Hullo!' I yelled. 'Hullo! Colonel! Let me out!' - -"And then suddenly in the silence I heard a sound which sent my -heart into my mouth. It was the clank of the levers and the swish -of the leaking cylinder. He had set the engine at work. The lamp -still stood upon the floor where I had placed it when examining -the trough. By its light I saw that the black ceiling was coming -down upon me, slowly, jerkily, but, as none knew better than -myself, with a force which must within a minute grind me to a -shapeless pulp. I threw myself, screaming, against the door, and -dragged with my nails at the lock. I implored the colonel to let -me out, but the remorseless clanking of the levers drowned my -cries. The ceiling was only a foot or two above my head, and with -my hand upraised I could feel its hard, rough surface. Then it -flashed through my mind that the pain of my death would depend -very much upon the position in which I met it. If I lay on my -face the weight would come upon my spine, and I shuddered to -think of that dreadful snap. Easier the other way, perhaps; and -yet, had I the nerve to lie and look up at that deadly black -shadow wavering down upon me? Already I was unable to stand -erect, when my eye caught something which brought a gush of hope -back to my heart. - -"I have said that though the floor and ceiling were of iron, the -walls were of wood. As I gave a last hurried glance around, I saw -a thin line of yellow light between two of the boards, which -broadened and broadened as a small panel was pushed backward. For -an instant I could hardly believe that here was indeed a door -which led away from death. The next instant I threw myself -through, and lay half-fainting upon the other side. The panel had -closed again behind me, but the crash of the lamp, and a few -moments afterwards the clang of the two slabs of metal, told me -how narrow had been my escape. - -"I was recalled to myself by a frantic plucking at my wrist, and -I found myself lying upon the stone floor of a narrow corridor, -while a woman bent over me and tugged at me with her left hand, -while she held a candle in her right. It was the same good friend -whose warning I had so foolishly rejected. - -"'Come! come!' she cried breathlessly. 'They will be here in a -moment. They will see that you are not there. Oh, do not waste -the so-precious time, but come!' - -"This time, at least, I did not scorn her advice. I staggered to -my feet and ran with her along the corridor and down a winding -stair. The latter led to another broad passage, and just as we -reached it we heard the sound of running feet and the shouting of -two voices, one answering the other from the floor on which we -were and from the one beneath. My guide stopped and looked about -her like one who is at her wit's end. Then she threw open a door -which led into a bedroom, through the window of which the moon -was shining brightly. - -"'It is your only chance,' said she. 'It is high, but it may be -that you can jump it.' - -"As she spoke a light sprang into view at the further end of the -passage, and I saw the lean figure of Colonel Lysander Stark -rushing forward with a lantern in one hand and a weapon like a -butcher's cleaver in the other. I rushed across the bedroom, -flung open the window, and looked out. How quiet and sweet and -wholesome the garden looked in the moonlight, and it could not be -more than thirty feet down. I clambered out upon the sill, but I -hesitated to jump until I should have heard what passed between -my saviour and the ruffian who pursued me. If she were ill-used, -then at any risks I was determined to go back to her assistance. -The thought had hardly flashed through my mind before he was at -the door, pushing his way past her; but she threw her arms round -him and tried to hold him back. - -"'Fritz! Fritz!' she cried in English, 'remember your promise -after the last time. You said it should not be again. He will be -silent! Oh, he will be silent!' - -"'You are mad, Elise!' he shouted, struggling to break away from -her. 'You will be the ruin of us. He has seen too much. Let me -pass, I say!' He dashed her to one side, and, rushing to the -window, cut at me with his heavy weapon. I had let myself go, and -was hanging by the hands to the sill, when his blow fell. I was -conscious of a dull pain, my grip loosened, and I fell into the -garden below. - -"I was shaken but not hurt by the fall; so I picked myself up and -rushed off among the bushes as hard as I could run, for I -understood that I was far from being out of danger yet. Suddenly, -however, as I ran, a deadly dizziness and sickness came over me. -I glanced down at my hand, which was throbbing painfully, and -then, for the first time, saw that my thumb had been cut off and -that the blood was pouring from my wound. I endeavoured to tie my -handkerchief round it, but there came a sudden buzzing in my -ears, and next moment I fell in a dead faint among the -rose-bushes. - -"How long I remained unconscious I cannot tell. It must have been -a very long time, for the moon had sunk, and a bright morning was -breaking when I came to myself. My clothes were all sodden with -dew, and my coat-sleeve was drenched with blood from my wounded -thumb. The smarting of it recalled in an instant all the -particulars of my night's adventure, and I sprang to my feet with -the feeling that I might hardly yet be safe from my pursuers. But -to my astonishment, when I came to look round me, neither house -nor garden were to be seen. I had been lying in an angle of the -hedge close by the highroad, and just a little lower down was a -long building, which proved, upon my approaching it, to be the -very station at which I had arrived upon the previous night. Were -it not for the ugly wound upon my hand, all that had passed -during those dreadful hours might have been an evil dream. - -"Half dazed, I went into the station and asked about the morning -train. There would be one to Reading in less than an hour. The -same porter was on duty, I found, as had been there when I -arrived. I inquired of him whether he had ever heard of Colonel -Lysander Stark. The name was strange to him. Had he observed a -carriage the night before waiting for me? No, he had not. Was -there a police-station anywhere near? There was one about three -miles off. - -"It was too far for me to go, weak and ill as I was. I determined -to wait until I got back to town before telling my story to the -police. It was a little past six when I arrived, so I went first -to have my wound dressed, and then the doctor was kind enough to -bring me along here. I put the case into your hands and shall do -exactly what you advise." - -We both sat in silence for some little time after listening to -this extraordinary narrative. Then Sherlock Holmes pulled down -from the shelf one of the ponderous commonplace books in which he -placed his cuttings. - -"Here is an advertisement which will interest you," said he. "It -appeared in all the papers about a year ago. Listen to this: -'Lost, on the 9th inst., Mr. Jeremiah Hayling, aged -twenty-six, a hydraulic engineer. Left his lodgings at ten -o'clock at night, and has not been heard of since. Was -dressed in,' etc., etc. Ha! That represents the last time that -the colonel needed to have his machine overhauled, I fancy." - -"Good heavens!" cried my patient. "Then that explains what the -girl said." - -"Undoubtedly. It is quite clear that the colonel was a cool and -desperate man, who was absolutely determined that nothing should -stand in the way of his little game, like those out-and-out -pirates who will leave no survivor from a captured ship. Well, -every moment now is precious, so if you feel equal to it we shall -go down to Scotland Yard at once as a preliminary to starting for -Eyford." - -Some three hours or so afterwards we were all in the train -together, bound from Reading to the little Berkshire village. -There were Sherlock Holmes, the hydraulic engineer, Inspector -Bradstreet, of Scotland Yard, a plain-clothes man, and myself. -Bradstreet had spread an ordnance map of the county out upon the -seat and was busy with his compasses drawing a circle with Eyford -for its centre. - -"There you are," said he. "That circle is drawn at a radius of -ten miles from the village. The place we want must be somewhere -near that line. You said ten miles, I think, sir." - -"It was an hour's good drive." - -"And you think that they brought you back all that way when you -were unconscious?" - -"They must have done so. I have a confused memory, too, of having -been lifted and conveyed somewhere." - -"What I cannot understand," said I, "is why they should have -spared you when they found you lying fainting in the garden. -Perhaps the villain was softened by the woman's entreaties." - -"I hardly think that likely. I never saw a more inexorable face -in my life." - -"Oh, we shall soon clear up all that," said Bradstreet. "Well, I -have drawn my circle, and I only wish I knew at what point upon -it the folk that we are in search of are to be found." - -"I think I could lay my finger on it," said Holmes quietly. - -"Really, now!" cried the inspector, "you have formed your -opinion! Come, now, we shall see who agrees with you. I say it is -south, for the country is more deserted there." - -"And I say east," said my patient. - -"I am for west," remarked the plain-clothes man. "There are -several quiet little villages up there." - -"And I am for north," said I, "because there are no hills there, -and our friend says that he did not notice the carriage go up -any." - -"Come," cried the inspector, laughing; "it's a very pretty -diversity of opinion. We have boxed the compass among us. Who do -you give your casting vote to?" - -"You are all wrong." - -"But we can't all be." - -"Oh, yes, you can. This is my point." He placed his finger in the -centre of the circle. "This is where we shall find them." - -"But the twelve-mile drive?" gasped Hatherley. - -"Six out and six back. Nothing simpler. You say yourself that the -horse was fresh and glossy when you got in. How could it be that -if it had gone twelve miles over heavy roads?" - -"Indeed, it is a likely ruse enough," observed Bradstreet -thoughtfully. "Of course there can be no doubt as to the nature -of this gang." - -"None at all," said Holmes. "They are coiners on a large scale, -and have used the machine to form the amalgam which has taken the -place of silver." - -"We have known for some time that a clever gang was at work," -said the inspector. "They have been turning out half-crowns by -the thousand. We even traced them as far as Reading, but could -get no farther, for they had covered their traces in a way that -showed that they were very old hands. But now, thanks to this -lucky chance, I think that we have got them right enough." - -But the inspector was mistaken, for those criminals were not -destined to fall into the hands of justice. As we rolled into -Eyford Station we saw a gigantic column of smoke which streamed -up from behind a small clump of trees in the neighbourhood and -hung like an immense ostrich feather over the landscape. - -"A house on fire?" asked Bradstreet as the train steamed off -again on its way. - -"Yes, sir!" said the station-master. - -"When did it break out?" - -"I hear that it was during the night, sir, but it has got worse, -and the whole place is in a blaze." - -"Whose house is it?" - -"Dr. Becher's." - -"Tell me," broke in the engineer, "is Dr. Becher a German, very -thin, with a long, sharp nose?" - -The station-master laughed heartily. "No, sir, Dr. Becher is an -Englishman, and there isn't a man in the parish who has a -better-lined waistcoat. But he has a gentleman staying with him, -a patient, as I understand, who is a foreigner, and he looks as -if a little good Berkshire beef would do him no harm." - -The station-master had not finished his speech before we were all -hastening in the direction of the fire. The road topped a low -hill, and there was a great widespread whitewashed building in -front of us, spouting fire at every chink and window, while in -the garden in front three fire-engines were vainly striving to -keep the flames under. - -"That's it!" cried Hatherley, in intense excitement. "There is -the gravel-drive, and there are the rose-bushes where I lay. That -second window is the one that I jumped from." - -"Well, at least," said Holmes, "you have had your revenge upon -them. There can be no question that it was your oil-lamp which, -when it was crushed in the press, set fire to the wooden walls, -though no doubt they were too excited in the chase after you to -observe it at the time. Now keep your eyes open in this crowd for -your friends of last night, though I very much fear that they are -a good hundred miles off by now." - -And Holmes' fears came to be realised, for from that day to this -no word has ever been heard either of the beautiful woman, the -sinister German, or the morose Englishman. Early that morning a -peasant had met a cart containing several people and some very -bulky boxes driving rapidly in the direction of Reading, but -there all traces of the fugitives disappeared, and even Holmes' -ingenuity failed ever to discover the least clue as to their -whereabouts. - -The firemen had been much perturbed at the strange arrangements -which they had found within, and still more so by discovering a -newly severed human thumb upon a window-sill of the second floor. -About sunset, however, their efforts were at last successful, and -they subdued the flames, but not before the roof had fallen in, -and the whole place been reduced to such absolute ruin that, save -some twisted cylinders and iron piping, not a trace remained of -the machinery which had cost our unfortunate acquaintance so -dearly. Large masses of nickel and of tin were discovered stored -in an out-house, but no coins were to be found, which may have -explained the presence of those bulky boxes which have been -already referred to. - -How our hydraulic engineer had been conveyed from the garden to -the spot where he recovered his senses might have remained -forever a mystery were it not for the soft mould, which told us a -very plain tale. He had evidently been carried down by two -persons, one of whom had remarkably small feet and the other -unusually large ones. On the whole, it was most probable that the -silent Englishman, being less bold or less murderous than his -companion, had assisted the woman to bear the unconscious man out -of the way of danger. - -"Well," said our engineer ruefully as we took our seats to return -once more to London, "it has been a pretty business for me! I -have lost my thumb and I have lost a fifty-guinea fee, and what -have I gained?" - -"Experience," said Holmes, laughing. "Indirectly it may be of -value, you know; you have only to put it into words to gain the -reputation of being excellent company for the remainder of your -existence." - - - -X. THE ADVENTURE OF THE NOBLE BACHELOR - -The Lord St. Simon marriage, and its curious termination, have -long ceased to be a subject of interest in those exalted circles -in which the unfortunate bridegroom moves. Fresh scandals have -eclipsed it, and their more piquant details have drawn the -gossips away from this four-year-old drama. As I have reason to -believe, however, that the full facts have never been revealed to -the general public, and as my friend Sherlock Holmes had a -considerable share in clearing the matter up, I feel that no -memoir of him would be complete without some little sketch of -this remarkable episode. - -It was a few weeks before my own marriage, during the days when I -was still sharing rooms with Holmes in Baker Street, that he came -home from an afternoon stroll to find a letter on the table -waiting for him. I had remained indoors all day, for the weather -had taken a sudden turn to rain, with high autumnal winds, and -the Jezail bullet which I had brought back in one of my limbs as -a relic of my Afghan campaign throbbed with dull persistence. -With my body in one easy-chair and my legs upon another, I had -surrounded myself with a cloud of newspapers until at last, -saturated with the news of the day, I tossed them all aside and -lay listless, watching the huge crest and monogram upon the -envelope upon the table and wondering lazily who my friend's -noble correspondent could be. - -"Here is a very fashionable epistle," I remarked as he entered. -"Your morning letters, if I remember right, were from a -fish-monger and a tide-waiter." - -"Yes, my correspondence has certainly the charm of variety," he -answered, smiling, "and the humbler are usually the more -interesting. This looks like one of those unwelcome social -summonses which call upon a man either to be bored or to lie." - -He broke the seal and glanced over the contents. - -"Oh, come, it may prove to be something of interest, after all." - -"Not social, then?" - -"No, distinctly professional." - -"And from a noble client?" - -"One of the highest in England." - -"My dear fellow, I congratulate you." - -"I assure you, Watson, without affectation, that the status of my -client is a matter of less moment to me than the interest of his -case. It is just possible, however, that that also may not be -wanting in this new investigation. You have been reading the -papers diligently of late, have you not?" - -"It looks like it," said I ruefully, pointing to a huge bundle in -the corner. "I have had nothing else to do." - -"It is fortunate, for you will perhaps be able to post me up. I -read nothing except the criminal news and the agony column. The -latter is always instructive. But if you have followed recent -events so closely you must have read about Lord St. Simon and his -wedding?" - -"Oh, yes, with the deepest interest." - -"That is well. The letter which I hold in my hand is from Lord -St. Simon. I will read it to you, and in return you must turn -over these papers and let me have whatever bears upon the matter. -This is what he says: - -"'MY DEAR MR. SHERLOCK HOLMES:--Lord Backwater tells me that I -may place implicit reliance upon your judgment and discretion. I -have determined, therefore, to call upon you and to consult you -in reference to the very painful event which has occurred in -connection with my wedding. Mr. Lestrade, of Scotland Yard, is -acting already in the matter, but he assures me that he sees no -objection to your co-operation, and that he even thinks that -it might be of some assistance. I will call at four o'clock in -the afternoon, and, should you have any other engagement at that -time, I hope that you will postpone it, as this matter is of -paramount importance. Yours faithfully, ST. SIMON.' - -"It is dated from Grosvenor Mansions, written with a quill pen, -and the noble lord has had the misfortune to get a smear of ink -upon the outer side of his right little finger," remarked Holmes -as he folded up the epistle. - -"He says four o'clock. It is three now. He will be here in an -hour." - -"Then I have just time, with your assistance, to get clear upon -the subject. Turn over those papers and arrange the extracts in -their order of time, while I take a glance as to who our client -is." He picked a red-covered volume from a line of books of -reference beside the mantelpiece. "Here he is," said he, sitting -down and flattening it out upon his knee. "'Lord Robert Walsingham -de Vere St. Simon, second son of the Duke of Balmoral.' Hum! 'Arms: -Azure, three caltrops in chief over a fess sable. Born in 1846.' -He's forty-one years of age, which is mature for marriage. Was -Under-Secretary for the colonies in a late administration. The -Duke, his father, was at one time Secretary for Foreign Affairs. -They inherit Plantagenet blood by direct descent, and Tudor on -the distaff side. Ha! Well, there is nothing very instructive in -all this. I think that I must turn to you Watson, for something -more solid." - -"I have very little difficulty in finding what I want," said I, -"for the facts are quite recent, and the matter struck me as -remarkable. I feared to refer them to you, however, as I knew -that you had an inquiry on hand and that you disliked the -intrusion of other matters." - -"Oh, you mean the little problem of the Grosvenor Square -furniture van. That is quite cleared up now--though, indeed, it -was obvious from the first. Pray give me the results of your -newspaper selections." - -"Here is the first notice which I can find. It is in the personal -column of the Morning Post, and dates, as you see, some weeks -back: 'A marriage has been arranged,' it says, 'and will, if -rumour is correct, very shortly take place, between Lord Robert -St. Simon, second son of the Duke of Balmoral, and Miss Hatty -Doran, the only daughter of Aloysius Doran. Esq., of San -Francisco, Cal., U.S.A.' That is all." - -"Terse and to the point," remarked Holmes, stretching his long, -thin legs towards the fire. - -"There was a paragraph amplifying this in one of the society -papers of the same week. Ah, here it is: 'There will soon be a -call for protection in the marriage market, for the present -free-trade principle appears to tell heavily against our home -product. One by one the management of the noble houses of Great -Britain is passing into the hands of our fair cousins from across -the Atlantic. An important addition has been made during the last -week to the list of the prizes which have been borne away by -these charming invaders. Lord St. Simon, who has shown himself -for over twenty years proof against the little god's arrows, has -now definitely announced his approaching marriage with Miss Hatty -Doran, the fascinating daughter of a California millionaire. Miss -Doran, whose graceful figure and striking face attracted much -attention at the Westbury House festivities, is an only child, -and it is currently reported that her dowry will run to -considerably over the six figures, with expectancies for the -future. As it is an open secret that the Duke of Balmoral has -been compelled to sell his pictures within the last few years, -and as Lord St. Simon has no property of his own save the small -estate of Birchmoor, it is obvious that the Californian heiress -is not the only gainer by an alliance which will enable her to -make the easy and common transition from a Republican lady to a -British peeress.'" - -"Anything else?" asked Holmes, yawning. - -"Oh, yes; plenty. Then there is another note in the Morning Post -to say that the marriage would be an absolutely quiet one, that it -would be at St. George's, Hanover Square, that only half a dozen -intimate friends would be invited, and that the party would -return to the furnished house at Lancaster Gate which has been -taken by Mr. Aloysius Doran. Two days later--that is, on -Wednesday last--there is a curt announcement that the wedding had -taken place, and that the honeymoon would be passed at Lord -Backwater's place, near Petersfield. Those are all the notices -which appeared before the disappearance of the bride." - -"Before the what?" asked Holmes with a start. - -"The vanishing of the lady." - -"When did she vanish, then?" - -"At the wedding breakfast." - -"Indeed. This is more interesting than it promised to be; quite -dramatic, in fact." - -"Yes; it struck me as being a little out of the common." - -"They often vanish before the ceremony, and occasionally during -the honeymoon; but I cannot call to mind anything quite so prompt -as this. Pray let me have the details." - -"I warn you that they are very incomplete." - -"Perhaps we may make them less so." - -"Such as they are, they are set forth in a single article of a -morning paper of yesterday, which I will read to you. It is -headed, 'Singular Occurrence at a Fashionable Wedding': - -"'The family of Lord Robert St. Simon has been thrown into the -greatest consternation by the strange and painful episodes which -have taken place in connection with his wedding. The ceremony, as -shortly announced in the papers of yesterday, occurred on the -previous morning; but it is only now that it has been possible to -confirm the strange rumours which have been so persistently -floating about. In spite of the attempts of the friends to hush -the matter up, so much public attention has now been drawn to it -that no good purpose can be served by affecting to disregard what -is a common subject for conversation. - -"'The ceremony, which was performed at St. George's, Hanover -Square, was a very quiet one, no one being present save the -father of the bride, Mr. Aloysius Doran, the Duchess of Balmoral, -Lord Backwater, Lord Eustace and Lady Clara St. Simon (the -younger brother and sister of the bridegroom), and Lady Alicia -Whittington. The whole party proceeded afterwards to the house of -Mr. Aloysius Doran, at Lancaster Gate, where breakfast had been -prepared. It appears that some little trouble was caused by a -woman, whose name has not been ascertained, who endeavoured to -force her way into the house after the bridal party, alleging -that she had some claim upon Lord St. Simon. It was only after a -painful and prolonged scene that she was ejected by the butler -and the footman. The bride, who had fortunately entered the house -before this unpleasant interruption, had sat down to breakfast -with the rest, when she complained of a sudden indisposition and -retired to her room. Her prolonged absence having caused some -comment, her father followed her, but learned from her maid that -she had only come up to her chamber for an instant, caught up an -ulster and bonnet, and hurried down to the passage. One of the -footmen declared that he had seen a lady leave the house thus -apparelled, but had refused to credit that it was his mistress, -believing her to be with the company. On ascertaining that his -daughter had disappeared, Mr. Aloysius Doran, in conjunction with -the bridegroom, instantly put themselves in communication with -the police, and very energetic inquiries are being made, which -will probably result in a speedy clearing up of this very -singular business. Up to a late hour last night, however, nothing -had transpired as to the whereabouts of the missing lady. There -are rumours of foul play in the matter, and it is said that the -police have caused the arrest of the woman who had caused the -original disturbance, in the belief that, from jealousy or some -other motive, she may have been concerned in the strange -disappearance of the bride.'" - -"And is that all?" - -"Only one little item in another of the morning papers, but it is -a suggestive one." - -"And it is--" - -"That Miss Flora Millar, the lady who had caused the disturbance, -has actually been arrested. It appears that she was formerly a -danseuse at the Allegro, and that she has known the bridegroom -for some years. There are no further particulars, and the whole -case is in your hands now--so far as it has been set forth in the -public press." - -"And an exceedingly interesting case it appears to be. I would -not have missed it for worlds. But there is a ring at the bell, -Watson, and as the clock makes it a few minutes after four, I -have no doubt that this will prove to be our noble client. Do not -dream of going, Watson, for I very much prefer having a witness, -if only as a check to my own memory." - -"Lord Robert St. Simon," announced our page-boy, throwing open -the door. A gentleman entered, with a pleasant, cultured face, -high-nosed and pale, with something perhaps of petulance about -the mouth, and with the steady, well-opened eye of a man whose -pleasant lot it had ever been to command and to be obeyed. His -manner was brisk, and yet his general appearance gave an undue -impression of age, for he had a slight forward stoop and a little -bend of the knees as he walked. His hair, too, as he swept off -his very curly-brimmed hat, was grizzled round the edges and thin -upon the top. As to his dress, it was careful to the verge of -foppishness, with high collar, black frock-coat, white waistcoat, -yellow gloves, patent-leather shoes, and light-coloured gaiters. -He advanced slowly into the room, turning his head from left to -right, and swinging in his right hand the cord which held his -golden eyeglasses. - -"Good-day, Lord St. Simon," said Holmes, rising and bowing. "Pray -take the basket-chair. This is my friend and colleague, Dr. -Watson. Draw up a little to the fire, and we will talk this -matter over." - -"A most painful matter to me, as you can most readily imagine, -Mr. Holmes. I have been cut to the quick. I understand that you -have already managed several delicate cases of this sort, sir, -though I presume that they were hardly from the same class of -society." - -"No, I am descending." - -"I beg pardon." - -"My last client of the sort was a king." - -"Oh, really! I had no idea. And which king?" - -"The King of Scandinavia." - -"What! Had he lost his wife?" - -"You can understand," said Holmes suavely, "that I extend to the -affairs of my other clients the same secrecy which I promise to -you in yours." - -"Of course! Very right! very right! I'm sure I beg pardon. As to -my own case, I am ready to give you any information which may -assist you in forming an opinion." - -"Thank you. I have already learned all that is in the public -prints, nothing more. I presume that I may take it as correct--this -article, for example, as to the disappearance of the bride." - -Lord St. Simon glanced over it. "Yes, it is correct, as far as it -goes." - -"But it needs a great deal of supplementing before anyone could -offer an opinion. I think that I may arrive at my facts most -directly by questioning you." - -"Pray do so." - -"When did you first meet Miss Hatty Doran?" - -"In San Francisco, a year ago." - -"You were travelling in the States?" - -"Yes." - -"Did you become engaged then?" - -"No." - -"But you were on a friendly footing?" - -"I was amused by her society, and she could see that I was -amused." - -"Her father is very rich?" - -"He is said to be the richest man on the Pacific slope." - -"And how did he make his money?" - -"In mining. He had nothing a few years ago. Then he struck gold, -invested it, and came up by leaps and bounds." - -"Now, what is your own impression as to the young lady's--your -wife's character?" - -The nobleman swung his glasses a little faster and stared down -into the fire. "You see, Mr. Holmes," said he, "my wife was -twenty before her father became a rich man. During that time she -ran free in a mining camp and wandered through woods or -mountains, so that her education has come from Nature rather than -from the schoolmaster. She is what we call in England a tomboy, -with a strong nature, wild and free, unfettered by any sort of -traditions. She is impetuous--volcanic, I was about to say. She -is swift in making up her mind and fearless in carrying out her -resolutions. On the other hand, I would not have given her the -name which I have the honour to bear"--he gave a little stately -cough--"had not I thought her to be at bottom a noble woman. I -believe that she is capable of heroic self-sacrifice and that -anything dishonourable would be repugnant to her." - -"Have you her photograph?" - -"I brought this with me." He opened a locket and showed us the -full face of a very lovely woman. It was not a photograph but an -ivory miniature, and the artist had brought out the full effect -of the lustrous black hair, the large dark eyes, and the -exquisite mouth. Holmes gazed long and earnestly at it. Then he -closed the locket and handed it back to Lord St. Simon. - -"The young lady came to London, then, and you renewed your -acquaintance?" - -"Yes, her father brought her over for this last London season. I -met her several times, became engaged to her, and have now -married her." - -"She brought, I understand, a considerable dowry?" - -"A fair dowry. Not more than is usual in my family." - -"And this, of course, remains to you, since the marriage is a -fait accompli?" - -"I really have made no inquiries on the subject." - -"Very naturally not. Did you see Miss Doran on the day before the -wedding?" - -"Yes." - -"Was she in good spirits?" - -"Never better. She kept talking of what we should do in our -future lives." - -"Indeed! That is very interesting. And on the morning of the -wedding?" - -"She was as bright as possible--at least until after the -ceremony." - -"And did you observe any change in her then?" - -"Well, to tell the truth, I saw then the first signs that I had -ever seen that her temper was just a little sharp. The incident -however, was too trivial to relate and can have no possible -bearing upon the case." - -"Pray let us have it, for all that." - -"Oh, it is childish. She dropped her bouquet as we went towards -the vestry. She was passing the front pew at the time, and it -fell over into the pew. There was a moment's delay, but the -gentleman in the pew handed it up to her again, and it did not -appear to be the worse for the fall. Yet when I spoke to her of -the matter, she answered me abruptly; and in the carriage, on our -way home, she seemed absurdly agitated over this trifling cause." - -"Indeed! You say that there was a gentleman in the pew. Some of -the general public were present, then?" - -"Oh, yes. It is impossible to exclude them when the church is -open." - -"This gentleman was not one of your wife's friends?" - -"No, no; I call him a gentleman by courtesy, but he was quite a -common-looking person. I hardly noticed his appearance. But -really I think that we are wandering rather far from the point." - -"Lady St. Simon, then, returned from the wedding in a less -cheerful frame of mind than she had gone to it. What did she do -on re-entering her father's house?" - -"I saw her in conversation with her maid." - -"And who is her maid?" - -"Alice is her name. She is an American and came from California -with her." - -"A confidential servant?" - -"A little too much so. It seemed to me that her mistress allowed -her to take great liberties. Still, of course, in America they -look upon these things in a different way." - -"How long did she speak to this Alice?" - -"Oh, a few minutes. I had something else to think of." - -"You did not overhear what they said?" - -"Lady St. Simon said something about 'jumping a claim.' She was -accustomed to use slang of the kind. I have no idea what she -meant." - -"American slang is very expressive sometimes. And what did your -wife do when she finished speaking to her maid?" - -"She walked into the breakfast-room." - -"On your arm?" - -"No, alone. She was very independent in little matters like that. -Then, after we had sat down for ten minutes or so, she rose -hurriedly, muttered some words of apology, and left the room. She -never came back." - -"But this maid, Alice, as I understand, deposes that she went to -her room, covered her bride's dress with a long ulster, put on a -bonnet, and went out." - -"Quite so. And she was afterwards seen walking into Hyde Park in -company with Flora Millar, a woman who is now in custody, and who -had already made a disturbance at Mr. Doran's house that -morning." - -"Ah, yes. I should like a few particulars as to this young lady, -and your relations to her." - -Lord St. Simon shrugged his shoulders and raised his eyebrows. -"We have been on a friendly footing for some years--I may say on -a very friendly footing. She used to be at the Allegro. I have -not treated her ungenerously, and she had no just cause of -complaint against me, but you know what women are, Mr. Holmes. -Flora was a dear little thing, but exceedingly hot-headed and -devotedly attached to me. She wrote me dreadful letters when she -heard that I was about to be married, and, to tell the truth, the -reason why I had the marriage celebrated so quietly was that I -feared lest there might be a scandal in the church. She came to -Mr. Doran's door just after we returned, and she endeavoured to -push her way in, uttering very abusive expressions towards my -wife, and even threatening her, but I had foreseen the -possibility of something of the sort, and I had two police -fellows there in private clothes, who soon pushed her out again. -She was quiet when she saw that there was no good in making a -row." - -"Did your wife hear all this?" - -"No, thank goodness, she did not." - -"And she was seen walking with this very woman afterwards?" - -"Yes. That is what Mr. Lestrade, of Scotland Yard, looks upon as -so serious. It is thought that Flora decoyed my wife out and laid -some terrible trap for her." - -"Well, it is a possible supposition." - -"You think so, too?" - -"I did not say a probable one. But you do not yourself look upon -this as likely?" - -"I do not think Flora would hurt a fly." - -"Still, jealousy is a strange transformer of characters. Pray -what is your own theory as to what took place?" - -"Well, really, I came to seek a theory, not to propound one. I -have given you all the facts. Since you ask me, however, I may -say that it has occurred to me as possible that the excitement of -this affair, the consciousness that she had made so immense a -social stride, had the effect of causing some little nervous -disturbance in my wife." - -"In short, that she had become suddenly deranged?" - -"Well, really, when I consider that she has turned her back--I -will not say upon me, but upon so much that many have aspired to -without success--I can hardly explain it in any other fashion." - -"Well, certainly that is also a conceivable hypothesis," said -Holmes, smiling. "And now, Lord St. Simon, I think that I have -nearly all my data. May I ask whether you were seated at the -breakfast-table so that you could see out of the window?" - -"We could see the other side of the road and the Park." - -"Quite so. Then I do not think that I need to detain you longer. -I shall communicate with you." - -"Should you be fortunate enough to solve this problem," said our -client, rising. - -"I have solved it." - -"Eh? What was that?" - -"I say that I have solved it." - -"Where, then, is my wife?" - -"That is a detail which I shall speedily supply." - -Lord St. Simon shook his head. "I am afraid that it will take -wiser heads than yours or mine," he remarked, and bowing in a -stately, old-fashioned manner he departed. - -"It is very good of Lord St. Simon to honour my head by putting -it on a level with his own," said Sherlock Holmes, laughing. "I -think that I shall have a whisky and soda and a cigar after all -this cross-questioning. I had formed my conclusions as to the -case before our client came into the room." - -"My dear Holmes!" - -"I have notes of several similar cases, though none, as I -remarked before, which were quite as prompt. My whole examination -served to turn my conjecture into a certainty. Circumstantial -evidence is occasionally very convincing, as when you find a -trout in the milk, to quote Thoreau's example." - -"But I have heard all that you have heard." - -"Without, however, the knowledge of pre-existing cases which -serves me so well. There was a parallel instance in Aberdeen some -years back, and something on very much the same lines at Munich -the year after the Franco-Prussian War. It is one of these -cases--but, hullo, here is Lestrade! Good-afternoon, Lestrade! -You will find an extra tumbler upon the sideboard, and there are -cigars in the box." - -The official detective was attired in a pea-jacket and cravat, -which gave him a decidedly nautical appearance, and he carried a -black canvas bag in his hand. With a short greeting he seated -himself and lit the cigar which had been offered to him. - -"What's up, then?" asked Holmes with a twinkle in his eye. "You -look dissatisfied." - -"And I feel dissatisfied. It is this infernal St. Simon marriage -case. I can make neither head nor tail of the business." - -"Really! You surprise me." - -"Who ever heard of such a mixed affair? Every clue seems to slip -through my fingers. I have been at work upon it all day." - -"And very wet it seems to have made you," said Holmes laying his -hand upon the arm of the pea-jacket. - -"Yes, I have been dragging the Serpentine." - -"In heaven's name, what for?" - -"In search of the body of Lady St. Simon." - -Sherlock Holmes leaned back in his chair and laughed heartily. - -"Have you dragged the basin of Trafalgar Square fountain?" he -asked. - -"Why? What do you mean?" - -"Because you have just as good a chance of finding this lady in -the one as in the other." - -Lestrade shot an angry glance at my companion. "I suppose you -know all about it," he snarled. - -"Well, I have only just heard the facts, but my mind is made up." - -"Oh, indeed! Then you think that the Serpentine plays no part in -the matter?" - -"I think it very unlikely." - -"Then perhaps you will kindly explain how it is that we found -this in it?" He opened his bag as he spoke, and tumbled onto the -floor a wedding-dress of watered silk, a pair of white satin -shoes and a bride's wreath and veil, all discoloured and soaked -in water. "There," said he, putting a new wedding-ring upon the -top of the pile. "There is a little nut for you to crack, Master -Holmes." - -"Oh, indeed!" said my friend, blowing blue rings into the air. -"You dragged them from the Serpentine?" - -"No. They were found floating near the margin by a park-keeper. -They have been identified as her clothes, and it seemed to me -that if the clothes were there the body would not be far off." - -"By the same brilliant reasoning, every man's body is to be found -in the neighbourhood of his wardrobe. And pray what did you hope -to arrive at through this?" - -"At some evidence implicating Flora Millar in the disappearance." - -"I am afraid that you will find it difficult." - -"Are you, indeed, now?" cried Lestrade with some bitterness. "I -am afraid, Holmes, that you are not very practical with your -deductions and your inferences. You have made two blunders in as -many minutes. This dress does implicate Miss Flora Millar." - -"And how?" - -"In the dress is a pocket. In the pocket is a card-case. In the -card-case is a note. And here is the very note." He slapped it -down upon the table in front of him. "Listen to this: 'You will -see me when all is ready. Come at once. F.H.M.' Now my theory all -along has been that Lady St. Simon was decoyed away by Flora -Millar, and that she, with confederates, no doubt, was -responsible for her disappearance. Here, signed with her -initials, is the very note which was no doubt quietly slipped -into her hand at the door and which lured her within their -reach." - -"Very good, Lestrade," said Holmes, laughing. "You really are -very fine indeed. Let me see it." He took up the paper in a -listless way, but his attention instantly became riveted, and he -gave a little cry of satisfaction. "This is indeed important," -said he. - -"Ha! you find it so?" - -"Extremely so. I congratulate you warmly." - -Lestrade rose in his triumph and bent his head to look. "Why," he -shrieked, "you're looking at the wrong side!" - -"On the contrary, this is the right side." - -"The right side? You're mad! Here is the note written in pencil -over here." - -"And over here is what appears to be the fragment of a hotel -bill, which interests me deeply." - -"There's nothing in it. I looked at it before," said Lestrade. -"'Oct. 4th, rooms 8s., breakfast 2s. 6d., cocktail 1s., lunch 2s. -6d., glass sherry, 8d.' I see nothing in that." - -"Very likely not. It is most important, all the same. As to the -note, it is important also, or at least the initials are, so I -congratulate you again." - -"I've wasted time enough," said Lestrade, rising. "I believe in -hard work and not in sitting by the fire spinning fine theories. -Good-day, Mr. Holmes, and we shall see which gets to the bottom -of the matter first." He gathered up the garments, thrust them -into the bag, and made for the door. - -"Just one hint to you, Lestrade," drawled Holmes before his rival -vanished; "I will tell you the true solution of the matter. Lady -St. Simon is a myth. There is not, and there never has been, any -such person." - -Lestrade looked sadly at my companion. Then he turned to me, -tapped his forehead three times, shook his head solemnly, and -hurried away. - -He had hardly shut the door behind him when Holmes rose to put on -his overcoat. "There is something in what the fellow says about -outdoor work," he remarked, "so I think, Watson, that I must -leave you to your papers for a little." - -It was after five o'clock when Sherlock Holmes left me, but I had -no time to be lonely, for within an hour there arrived a -confectioner's man with a very large flat box. This he unpacked -with the help of a youth whom he had brought with him, and -presently, to my very great astonishment, a quite epicurean -little cold supper began to be laid out upon our humble -lodging-house mahogany. There were a couple of brace of cold -woodcock, a pheasant, a pâté de foie gras pie with a group of -ancient and cobwebby bottles. Having laid out all these luxuries, -my two visitors vanished away, like the genii of the Arabian -Nights, with no explanation save that the things had been paid -for and were ordered to this address. - -Just before nine o'clock Sherlock Holmes stepped briskly into the -room. His features were gravely set, but there was a light in his -eye which made me think that he had not been disappointed in his -conclusions. - -"They have laid the supper, then," he said, rubbing his hands. - -"You seem to expect company. They have laid for five." - -"Yes, I fancy we may have some company dropping in," said he. "I -am surprised that Lord St. Simon has not already arrived. Ha! I -fancy that I hear his step now upon the stairs." - -It was indeed our visitor of the afternoon who came bustling in, -dangling his glasses more vigorously than ever, and with a very -perturbed expression upon his aristocratic features. - -"My messenger reached you, then?" asked Holmes. - -"Yes, and I confess that the contents startled me beyond measure. -Have you good authority for what you say?" - -"The best possible." - -Lord St. Simon sank into a chair and passed his hand over his -forehead. - -"What will the Duke say," he murmured, "when he hears that one of -the family has been subjected to such humiliation?" - -"It is the purest accident. I cannot allow that there is any -humiliation." - -"Ah, you look on these things from another standpoint." - -"I fail to see that anyone is to blame. I can hardly see how the -lady could have acted otherwise, though her abrupt method of -doing it was undoubtedly to be regretted. Having no mother, she -had no one to advise her at such a crisis." - -"It was a slight, sir, a public slight," said Lord St. Simon, -tapping his fingers upon the table. - -"You must make allowance for this poor girl, placed in so -unprecedented a position." - -"I will make no allowance. I am very angry indeed, and I have -been shamefully used." - -"I think that I heard a ring," said Holmes. "Yes, there are steps -on the landing. If I cannot persuade you to take a lenient view -of the matter, Lord St. Simon, I have brought an advocate here -who may be more successful." He opened the door and ushered in a -lady and gentleman. "Lord St. Simon," said he "allow me to -introduce you to Mr. and Mrs. Francis Hay Moulton. The lady, I -think, you have already met." - -At the sight of these newcomers our client had sprung from his -seat and stood very erect, with his eyes cast down and his hand -thrust into the breast of his frock-coat, a picture of offended -dignity. The lady had taken a quick step forward and had held out -her hand to him, but he still refused to raise his eyes. It was -as well for his resolution, perhaps, for her pleading face was -one which it was hard to resist. - -"You're angry, Robert," said she. "Well, I guess you have every -cause to be." - -"Pray make no apology to me," said Lord St. Simon bitterly. - -"Oh, yes, I know that I have treated you real bad and that I -should have spoken to you before I went; but I was kind of -rattled, and from the time when I saw Frank here again I just -didn't know what I was doing or saying. I only wonder I didn't -fall down and do a faint right there before the altar." - -"Perhaps, Mrs. Moulton, you would like my friend and me to leave -the room while you explain this matter?" - -"If I may give an opinion," remarked the strange gentleman, -"we've had just a little too much secrecy over this business -already. For my part, I should like all Europe and America to -hear the rights of it." He was a small, wiry, sunburnt man, -clean-shaven, with a sharp face and alert manner. - -"Then I'll tell our story right away," said the lady. "Frank here -and I met in '84, in McQuire's camp, near the Rockies, where pa -was working a claim. We were engaged to each other, Frank and I; -but then one day father struck a rich pocket and made a pile, -while poor Frank here had a claim that petered out and came to -nothing. The richer pa grew the poorer was Frank; so at last pa -wouldn't hear of our engagement lasting any longer, and he took -me away to 'Frisco. Frank wouldn't throw up his hand, though; so -he followed me there, and he saw me without pa knowing anything -about it. It would only have made him mad to know, so we just -fixed it all up for ourselves. Frank said that he would go and -make his pile, too, and never come back to claim me until he had -as much as pa. So then I promised to wait for him to the end of -time and pledged myself not to marry anyone else while he lived. -'Why shouldn't we be married right away, then,' said he, 'and -then I will feel sure of you; and I won't claim to be your -husband until I come back?' Well, we talked it over, and he had -fixed it all up so nicely, with a clergyman all ready in waiting, -that we just did it right there; and then Frank went off to seek -his fortune, and I went back to pa. - -"The next I heard of Frank was that he was in Montana, and then -he went prospecting in Arizona, and then I heard of him from New -Mexico. After that came a long newspaper story about how a -miners' camp had been attacked by Apache Indians, and there was -my Frank's name among the killed. I fainted dead away, and I was -very sick for months after. Pa thought I had a decline and took -me to half the doctors in 'Frisco. Not a word of news came for a -year and more, so that I never doubted that Frank was really -dead. Then Lord St. Simon came to 'Frisco, and we came to London, -and a marriage was arranged, and pa was very pleased, but I felt -all the time that no man on this earth would ever take the place -in my heart that had been given to my poor Frank. - -"Still, if I had married Lord St. Simon, of course I'd have done -my duty by him. We can't command our love, but we can our -actions. I went to the altar with him with the intention to make -him just as good a wife as it was in me to be. But you may -imagine what I felt when, just as I came to the altar rails, I -glanced back and saw Frank standing and looking at me out of the -first pew. I thought it was his ghost at first; but when I looked -again there he was still, with a kind of question in his eyes, as -if to ask me whether I were glad or sorry to see him. I wonder I -didn't drop. I know that everything was turning round, and the -words of the clergyman were just like the buzz of a bee in my -ear. I didn't know what to do. Should I stop the service and make -a scene in the church? I glanced at him again, and he seemed to -know what I was thinking, for he raised his finger to his lips to -tell me to be still. Then I saw him scribble on a piece of paper, -and I knew that he was writing me a note. As I passed his pew on -the way out I dropped my bouquet over to him, and he slipped the -note into my hand when he returned me the flowers. It was only a -line asking me to join him when he made the sign to me to do so. -Of course I never doubted for a moment that my first duty was now -to him, and I determined to do just whatever he might direct. - -"When I got back I told my maid, who had known him in California, -and had always been his friend. I ordered her to say nothing, but -to get a few things packed and my ulster ready. I know I ought to -have spoken to Lord St. Simon, but it was dreadful hard before -his mother and all those great people. I just made up my mind to -run away and explain afterwards. I hadn't been at the table ten -minutes before I saw Frank out of the window at the other side of -the road. He beckoned to me and then began walking into the Park. -I slipped out, put on my things, and followed him. Some woman -came talking something or other about Lord St. Simon to -me--seemed to me from the little I heard as if he had a little -secret of his own before marriage also--but I managed to get away -from her and soon overtook Frank. We got into a cab together, and -away we drove to some lodgings he had taken in Gordon Square, and -that was my true wedding after all those years of waiting. Frank -had been a prisoner among the Apaches, had escaped, came on to -'Frisco, found that I had given him up for dead and had gone to -England, followed me there, and had come upon me at last on the -very morning of my second wedding." - -"I saw it in a paper," explained the American. "It gave the name -and the church but not where the lady lived." - -"Then we had a talk as to what we should do, and Frank was all -for openness, but I was so ashamed of it all that I felt as if I -should like to vanish away and never see any of them again--just -sending a line to pa, perhaps, to show him that I was alive. It -was awful to me to think of all those lords and ladies sitting -round that breakfast-table and waiting for me to come back. So -Frank took my wedding-clothes and things and made a bundle of -them, so that I should not be traced, and dropped them away -somewhere where no one could find them. It is likely that we -should have gone on to Paris to-morrow, only that this good -gentleman, Mr. Holmes, came round to us this evening, though how -he found us is more than I can think, and he showed us very -clearly and kindly that I was wrong and that Frank was right, and -that we should be putting ourselves in the wrong if we were so -secret. Then he offered to give us a chance of talking to Lord -St. Simon alone, and so we came right away round to his rooms at -once. Now, Robert, you have heard it all, and I am very sorry if -I have given you pain, and I hope that you do not think very -meanly of me." - -Lord St. Simon had by no means relaxed his rigid attitude, but -had listened with a frowning brow and a compressed lip to this -long narrative. - -"Excuse me," he said, "but it is not my custom to discuss my most -intimate personal affairs in this public manner." - -"Then you won't forgive me? You won't shake hands before I go?" - -"Oh, certainly, if it would give you any pleasure." He put out -his hand and coldly grasped that which she extended to him. - -"I had hoped," suggested Holmes, "that you would have joined us -in a friendly supper." - -"I think that there you ask a little too much," responded his -Lordship. "I may be forced to acquiesce in these recent -developments, but I can hardly be expected to make merry over -them. I think that with your permission I will now wish you all a -very good-night." He included us all in a sweeping bow and -stalked out of the room. - -"Then I trust that you at least will honour me with your -company," said Sherlock Holmes. "It is always a joy to meet an -American, Mr. Moulton, for I am one of those who believe that the -folly of a monarch and the blundering of a minister in far-gone -years will not prevent our children from being some day citizens -of the same world-wide country under a flag which shall be a -quartering of the Union Jack with the Stars and Stripes." - -"The case has been an interesting one," remarked Holmes when our -visitors had left us, "because it serves to show very clearly how -simple the explanation may be of an affair which at first sight -seems to be almost inexplicable. Nothing could be more natural -than the sequence of events as narrated by this lady, and nothing -stranger than the result when viewed, for instance, by Mr. -Lestrade of Scotland Yard." - -"You were not yourself at fault at all, then?" - -"From the first, two facts were very obvious to me, the one that -the lady had been quite willing to undergo the wedding ceremony, -the other that she had repented of it within a few minutes of -returning home. Obviously something had occurred during the -morning, then, to cause her to change her mind. What could that -something be? She could not have spoken to anyone when she was -out, for she had been in the company of the bridegroom. Had she -seen someone, then? If she had, it must be someone from America -because she had spent so short a time in this country that she -could hardly have allowed anyone to acquire so deep an influence -over her that the mere sight of him would induce her to change -her plans so completely. You see we have already arrived, by a -process of exclusion, at the idea that she might have seen an -American. Then who could this American be, and why should he -possess so much influence over her? It might be a lover; it might -be a husband. Her young womanhood had, I knew, been spent in -rough scenes and under strange conditions. So far I had got -before I ever heard Lord St. Simon's narrative. When he told us -of a man in a pew, of the change in the bride's manner, of so -transparent a device for obtaining a note as the dropping of a -bouquet, of her resort to her confidential maid, and of her very -significant allusion to claim-jumping--which in miners' parlance -means taking possession of that which another person has a prior -claim to--the whole situation became absolutely clear. She had -gone off with a man, and the man was either a lover or was a -previous husband--the chances being in favour of the latter." - -"And how in the world did you find them?" - -"It might have been difficult, but friend Lestrade held -information in his hands the value of which he did not himself -know. The initials were, of course, of the highest importance, -but more valuable still was it to know that within a week he had -settled his bill at one of the most select London hotels." - -"How did you deduce the select?" - -"By the select prices. Eight shillings for a bed and eightpence -for a glass of sherry pointed to one of the most expensive -hotels. There are not many in London which charge at that rate. -In the second one which I visited in Northumberland Avenue, I -learned by an inspection of the book that Francis H. Moulton, an -American gentleman, had left only the day before, and on looking -over the entries against him, I came upon the very items which I -had seen in the duplicate bill. His letters were to be forwarded -to 226 Gordon Square; so thither I travelled, and being fortunate -enough to find the loving couple at home, I ventured to give them -some paternal advice and to point out to them that it would be -better in every way that they should make their position a little -clearer both to the general public and to Lord St. Simon in -particular. I invited them to meet him here, and, as you see, I -made him keep the appointment." - -"But with no very good result," I remarked. "His conduct was -certainly not very gracious." - -"Ah, Watson," said Holmes, smiling, "perhaps you would not be -very gracious either, if, after all the trouble of wooing and -wedding, you found yourself deprived in an instant of wife and of -fortune. I think that we may judge Lord St. Simon very mercifully -and thank our stars that we are never likely to find ourselves in -the same position. Draw your chair up and hand me my violin, for -the only problem we have still to solve is how to while away -these bleak autumnal evenings." - - - -XI. THE ADVENTURE OF THE BERYL CORONET - -"Holmes," said I as I stood one morning in our bow-window looking -down the street, "here is a madman coming along. It seems rather -sad that his relatives should allow him to come out alone." - -My friend rose lazily from his armchair and stood with his hands -in the pockets of his dressing-gown, looking over my shoulder. It -was a bright, crisp February morning, and the snow of the day -before still lay deep upon the ground, shimmering brightly in the -wintry sun. Down the centre of Baker Street it had been ploughed -into a brown crumbly band by the traffic, but at either side and -on the heaped-up edges of the foot-paths it still lay as white as -when it fell. The grey pavement had been cleaned and scraped, but -was still dangerously slippery, so that there were fewer -passengers than usual. Indeed, from the direction of the -Metropolitan Station no one was coming save the single gentleman -whose eccentric conduct had drawn my attention. - -He was a man of about fifty, tall, portly, and imposing, with a -massive, strongly marked face and a commanding figure. He was -dressed in a sombre yet rich style, in black frock-coat, shining -hat, neat brown gaiters, and well-cut pearl-grey trousers. Yet -his actions were in absurd contrast to the dignity of his dress -and features, for he was running hard, with occasional little -springs, such as a weary man gives who is little accustomed to -set any tax upon his legs. As he ran he jerked his hands up and -down, waggled his head, and writhed his face into the most -extraordinary contortions. - -"What on earth can be the matter with him?" I asked. "He is -looking up at the numbers of the houses." - -"I believe that he is coming here," said Holmes, rubbing his -hands. - -"Here?" - -"Yes; I rather think he is coming to consult me professionally. I -think that I recognise the symptoms. Ha! did I not tell you?" As -he spoke, the man, puffing and blowing, rushed at our door and -pulled at our bell until the whole house resounded with the -clanging. - -A few moments later he was in our room, still puffing, still -gesticulating, but with so fixed a look of grief and despair in -his eyes that our smiles were turned in an instant to horror and -pity. For a while he could not get his words out, but swayed his -body and plucked at his hair like one who has been driven to the -extreme limits of his reason. Then, suddenly springing to his -feet, he beat his head against the wall with such force that we -both rushed upon him and tore him away to the centre of the room. -Sherlock Holmes pushed him down into the easy-chair and, sitting -beside him, patted his hand and chatted with him in the easy, -soothing tones which he knew so well how to employ. - -"You have come to me to tell your story, have you not?" said he. -"You are fatigued with your haste. Pray wait until you have -recovered yourself, and then I shall be most happy to look into -any little problem which you may submit to me." - -The man sat for a minute or more with a heaving chest, fighting -against his emotion. Then he passed his handkerchief over his -brow, set his lips tight, and turned his face towards us. - -"No doubt you think me mad?" said he. - -"I see that you have had some great trouble," responded Holmes. - -"God knows I have!--a trouble which is enough to unseat my -reason, so sudden and so terrible is it. Public disgrace I might -have faced, although I am a man whose character has never yet -borne a stain. Private affliction also is the lot of every man; -but the two coming together, and in so frightful a form, have -been enough to shake my very soul. Besides, it is not I alone. -The very noblest in the land may suffer unless some way be found -out of this horrible affair." - -"Pray compose yourself, sir," said Holmes, "and let me have a -clear account of who you are and what it is that has befallen -you." - -"My name," answered our visitor, "is probably familiar to your -ears. I am Alexander Holder, of the banking firm of Holder & -Stevenson, of Threadneedle Street." - -The name was indeed well known to us as belonging to the senior -partner in the second largest private banking concern in the City -of London. What could have happened, then, to bring one of the -foremost citizens of London to this most pitiable pass? We -waited, all curiosity, until with another effort he braced -himself to tell his story. - -"I feel that time is of value," said he; "that is why I hastened -here when the police inspector suggested that I should secure -your co-operation. I came to Baker Street by the Underground and -hurried from there on foot, for the cabs go slowly through this -snow. That is why I was so out of breath, for I am a man who -takes very little exercise. I feel better now, and I will put the -facts before you as shortly and yet as clearly as I can. - -"It is, of course, well known to you that in a successful banking -business as much depends upon our being able to find remunerative -investments for our funds as upon our increasing our connection -and the number of our depositors. One of our most lucrative means -of laying out money is in the shape of loans, where the security -is unimpeachable. We have done a good deal in this direction -during the last few years, and there are many noble families to -whom we have advanced large sums upon the security of their -pictures, libraries, or plate. - -"Yesterday morning I was seated in my office at the bank when a -card was brought in to me by one of the clerks. I started when I -saw the name, for it was that of none other than--well, perhaps -even to you I had better say no more than that it was a name -which is a household word all over the earth--one of the highest, -noblest, most exalted names in England. I was overwhelmed by the -honour and attempted, when he entered, to say so, but he plunged -at once into business with the air of a man who wishes to hurry -quickly through a disagreeable task. - -"'Mr. Holder,' said he, 'I have been informed that you are in the -habit of advancing money.' - -"'The firm does so when the security is good.' I answered. - -"'It is absolutely essential to me,' said he, 'that I should have -50,000 pounds at once. I could, of course, borrow so trifling a -sum ten times over from my friends, but I much prefer to make it -a matter of business and to carry out that business myself. In my -position you can readily understand that it is unwise to place -one's self under obligations.' - -"'For how long, may I ask, do you want this sum?' I asked. - -"'Next Monday I have a large sum due to me, and I shall then most -certainly repay what you advance, with whatever interest you -think it right to charge. But it is very essential to me that the -money should be paid at once.' - -"'I should be happy to advance it without further parley from my -own private purse,' said I, 'were it not that the strain would be -rather more than it could bear. If, on the other hand, I am to do -it in the name of the firm, then in justice to my partner I must -insist that, even in your case, every businesslike precaution -should be taken.' - -"'I should much prefer to have it so,' said he, raising up a -square, black morocco case which he had laid beside his chair. -'You have doubtless heard of the Beryl Coronet?' - -"'One of the most precious public possessions of the empire,' -said I. - -"'Precisely.' He opened the case, and there, imbedded in soft, -flesh-coloured velvet, lay the magnificent piece of jewellery -which he had named. 'There are thirty-nine enormous beryls,' said -he, 'and the price of the gold chasing is incalculable. The -lowest estimate would put the worth of the coronet at double the -sum which I have asked. I am prepared to leave it with you as my -security.' - -"I took the precious case into my hands and looked in some -perplexity from it to my illustrious client. - -"'You doubt its value?' he asked. - -"'Not at all. I only doubt--' - -"'The propriety of my leaving it. You may set your mind at rest -about that. I should not dream of doing so were it not absolutely -certain that I should be able in four days to reclaim it. It is a -pure matter of form. Is the security sufficient?' - -"'Ample.' - -"'You understand, Mr. Holder, that I am giving you a strong proof -of the confidence which I have in you, founded upon all that I -have heard of you. I rely upon you not only to be discreet and to -refrain from all gossip upon the matter but, above all, to -preserve this coronet with every possible precaution because I -need not say that a great public scandal would be caused if any -harm were to befall it. Any injury to it would be almost as -serious as its complete loss, for there are no beryls in the -world to match these, and it would be impossible to replace them. -I leave it with you, however, with every confidence, and I shall -call for it in person on Monday morning.' - -"Seeing that my client was anxious to leave, I said no more but, -calling for my cashier, I ordered him to pay over fifty 1000 -pound notes. When I was alone once more, however, with the -precious case lying upon the table in front of me, I could not -but think with some misgivings of the immense responsibility -which it entailed upon me. There could be no doubt that, as it -was a national possession, a horrible scandal would ensue if any -misfortune should occur to it. I already regretted having ever -consented to take charge of it. However, it was too late to alter -the matter now, so I locked it up in my private safe and turned -once more to my work. - -"When evening came I felt that it would be an imprudence to leave -so precious a thing in the office behind me. Bankers' safes had -been forced before now, and why should not mine be? If so, how -terrible would be the position in which I should find myself! I -determined, therefore, that for the next few days I would always -carry the case backward and forward with me, so that it might -never be really out of my reach. With this intention, I called a -cab and drove out to my house at Streatham, carrying the jewel -with me. I did not breathe freely until I had taken it upstairs -and locked it in the bureau of my dressing-room. - -"And now a word as to my household, Mr. Holmes, for I wish you to -thoroughly understand the situation. My groom and my page sleep -out of the house, and may be set aside altogether. I have three -maid-servants who have been with me a number of years and whose -absolute reliability is quite above suspicion. Another, Lucy -Parr, the second waiting-maid, has only been in my service a few -months. She came with an excellent character, however, and has -always given me satisfaction. She is a very pretty girl and has -attracted admirers who have occasionally hung about the place. -That is the only drawback which we have found to her, but we -believe her to be a thoroughly good girl in every way. - -"So much for the servants. My family itself is so small that it -will not take me long to describe it. I am a widower and have an -only son, Arthur. He has been a disappointment to me, Mr. -Holmes--a grievous disappointment. I have no doubt that I am -myself to blame. People tell me that I have spoiled him. Very -likely I have. When my dear wife died I felt that he was all I -had to love. I could not bear to see the smile fade even for a -moment from his face. I have never denied him a wish. Perhaps it -would have been better for both of us had I been sterner, but I -meant it for the best. - -"It was naturally my intention that he should succeed me in my -business, but he was not of a business turn. He was wild, -wayward, and, to speak the truth, I could not trust him in the -handling of large sums of money. When he was young he became a -member of an aristocratic club, and there, having charming -manners, he was soon the intimate of a number of men with long -purses and expensive habits. He learned to play heavily at cards -and to squander money on the turf, until he had again and again -to come to me and implore me to give him an advance upon his -allowance, that he might settle his debts of honour. He tried -more than once to break away from the dangerous company which he -was keeping, but each time the influence of his friend, Sir -George Burnwell, was enough to draw him back again. - -"And, indeed, I could not wonder that such a man as Sir George -Burnwell should gain an influence over him, for he has frequently -brought him to my house, and I have found myself that I could -hardly resist the fascination of his manner. He is older than -Arthur, a man of the world to his finger-tips, one who had been -everywhere, seen everything, a brilliant talker, and a man of -great personal beauty. Yet when I think of him in cold blood, far -away from the glamour of his presence, I am convinced from his -cynical speech and the look which I have caught in his eyes that -he is one who should be deeply distrusted. So I think, and so, -too, thinks my little Mary, who has a woman's quick insight into -character. - -"And now there is only she to be described. She is my niece; but -when my brother died five years ago and left her alone in the -world I adopted her, and have looked upon her ever since as my -daughter. She is a sunbeam in my house--sweet, loving, beautiful, -a wonderful manager and housekeeper, yet as tender and quiet and -gentle as a woman could be. She is my right hand. I do not know -what I could do without her. In only one matter has she ever gone -against my wishes. Twice my boy has asked her to marry him, for -he loves her devotedly, but each time she has refused him. I -think that if anyone could have drawn him into the right path it -would have been she, and that his marriage might have changed his -whole life; but now, alas! it is too late--forever too late! - -"Now, Mr. Holmes, you know the people who live under my roof, and -I shall continue with my miserable story. - -"When we were taking coffee in the drawing-room that night after -dinner, I told Arthur and Mary my experience, and of the precious -treasure which we had under our roof, suppressing only the name -of my client. Lucy Parr, who had brought in the coffee, had, I am -sure, left the room; but I cannot swear that the door was closed. -Mary and Arthur were much interested and wished to see the famous -coronet, but I thought it better not to disturb it. - -"'Where have you put it?' asked Arthur. - -"'In my own bureau.' - -"'Well, I hope to goodness the house won't be burgled during the -night.' said he. - -"'It is locked up,' I answered. - -"'Oh, any old key will fit that bureau. When I was a youngster I -have opened it myself with the key of the box-room cupboard.' - -"He often had a wild way of talking, so that I thought little of -what he said. He followed me to my room, however, that night with -a very grave face. - -"'Look here, dad,' said he with his eyes cast down, 'can you let -me have 200 pounds?' - -"'No, I cannot!' I answered sharply. 'I have been far too -generous with you in money matters.' - -"'You have been very kind,' said he, 'but I must have this money, -or else I can never show my face inside the club again.' - -"'And a very good thing, too!' I cried. - -"'Yes, but you would not have me leave it a dishonoured man,' -said he. 'I could not bear the disgrace. I must raise the money -in some way, and if you will not let me have it, then I must try -other means.' - -"I was very angry, for this was the third demand during the -month. 'You shall not have a farthing from me,' I cried, on which -he bowed and left the room without another word. - -"When he was gone I unlocked my bureau, made sure that my -treasure was safe, and locked it again. Then I started to go -round the house to see that all was secure--a duty which I -usually leave to Mary but which I thought it well to perform -myself that night. As I came down the stairs I saw Mary herself -at the side window of the hall, which she closed and fastened as -I approached. - -"'Tell me, dad,' said she, looking, I thought, a little -disturbed, 'did you give Lucy, the maid, leave to go out -to-night?' - -"'Certainly not.' - -"'She came in just now by the back door. I have no doubt that she -has only been to the side gate to see someone, but I think that -it is hardly safe and should be stopped.' - -"'You must speak to her in the morning, or I will if you prefer -it. Are you sure that everything is fastened?' - -"'Quite sure, dad.' - -"'Then, good-night.' I kissed her and went up to my bedroom -again, where I was soon asleep. - -"I am endeavouring to tell you everything, Mr. Holmes, which may -have any bearing upon the case, but I beg that you will question -me upon any point which I do not make clear." - -"On the contrary, your statement is singularly lucid." - -"I come to a part of my story now in which I should wish to be -particularly so. I am not a very heavy sleeper, and the anxiety -in my mind tended, no doubt, to make me even less so than usual. -About two in the morning, then, I was awakened by some sound in -the house. It had ceased ere I was wide awake, but it had left an -impression behind it as though a window had gently closed -somewhere. I lay listening with all my ears. Suddenly, to my -horror, there was a distinct sound of footsteps moving softly in -the next room. I slipped out of bed, all palpitating with fear, -and peeped round the corner of my dressing-room door. - -"'Arthur!' I screamed, 'you villain! you thief! How dare you -touch that coronet?' - -"The gas was half up, as I had left it, and my unhappy boy, -dressed only in his shirt and trousers, was standing beside the -light, holding the coronet in his hands. He appeared to be -wrenching at it, or bending it with all his strength. At my cry -he dropped it from his grasp and turned as pale as death. I -snatched it up and examined it. One of the gold corners, with -three of the beryls in it, was missing. - -"'You blackguard!' I shouted, beside myself with rage. 'You have -destroyed it! You have dishonoured me forever! Where are the -jewels which you have stolen?' - -"'Stolen!' he cried. - -"'Yes, thief!' I roared, shaking him by the shoulder. - -"'There are none missing. There cannot be any missing,' said he. - -"'There are three missing. And you know where they are. Must I -call you a liar as well as a thief? Did I not see you trying to -tear off another piece?' - -"'You have called me names enough,' said he, 'I will not stand it -any longer. I shall not say another word about this business, -since you have chosen to insult me. I will leave your house in -the morning and make my own way in the world.' - -"'You shall leave it in the hands of the police!' I cried -half-mad with grief and rage. 'I shall have this matter probed to -the bottom.' - -"'You shall learn nothing from me,' said he with a passion such -as I should not have thought was in his nature. 'If you choose to -call the police, let the police find what they can.' - -"By this time the whole house was astir, for I had raised my -voice in my anger. Mary was the first to rush into my room, and, -at the sight of the coronet and of Arthur's face, she read the -whole story and, with a scream, fell down senseless on the -ground. I sent the house-maid for the police and put the -investigation into their hands at once. When the inspector and a -constable entered the house, Arthur, who had stood sullenly with -his arms folded, asked me whether it was my intention to charge -him with theft. I answered that it had ceased to be a private -matter, but had become a public one, since the ruined coronet was -national property. I was determined that the law should have its -way in everything. - -"'At least,' said he, 'you will not have me arrested at once. It -would be to your advantage as well as mine if I might leave the -house for five minutes.' - -"'That you may get away, or perhaps that you may conceal what you -have stolen,' said I. And then, realising the dreadful position -in which I was placed, I implored him to remember that not only -my honour but that of one who was far greater than I was at -stake; and that he threatened to raise a scandal which would -convulse the nation. He might avert it all if he would but tell -me what he had done with the three missing stones. - -"'You may as well face the matter,' said I; 'you have been caught -in the act, and no confession could make your guilt more heinous. -If you but make such reparation as is in your power, by telling -us where the beryls are, all shall be forgiven and forgotten.' - -"'Keep your forgiveness for those who ask for it,' he answered, -turning away from me with a sneer. I saw that he was too hardened -for any words of mine to influence him. There was but one way for -it. I called in the inspector and gave him into custody. A search -was made at once not only of his person but of his room and of -every portion of the house where he could possibly have concealed -the gems; but no trace of them could be found, nor would the -wretched boy open his mouth for all our persuasions and our -threats. This morning he was removed to a cell, and I, after -going through all the police formalities, have hurried round to -you to implore you to use your skill in unravelling the matter. -The police have openly confessed that they can at present make -nothing of it. You may go to any expense which you think -necessary. I have already offered a reward of 1000 pounds. My -God, what shall I do! I have lost my honour, my gems, and my son -in one night. Oh, what shall I do!" - -He put a hand on either side of his head and rocked himself to -and fro, droning to himself like a child whose grief has got -beyond words. - -Sherlock Holmes sat silent for some few minutes, with his brows -knitted and his eyes fixed upon the fire. - -"Do you receive much company?" he asked. - -"None save my partner with his family and an occasional friend of -Arthur's. Sir George Burnwell has been several times lately. No -one else, I think." - -"Do you go out much in society?" - -"Arthur does. Mary and I stay at home. We neither of us care for -it." - -"That is unusual in a young girl." - -"She is of a quiet nature. Besides, she is not so very young. She -is four-and-twenty." - -"This matter, from what you say, seems to have been a shock to -her also." - -"Terrible! She is even more affected than I." - -"You have neither of you any doubt as to your son's guilt?" - -"How can we have when I saw him with my own eyes with the coronet -in his hands." - -"I hardly consider that a conclusive proof. Was the remainder of -the coronet at all injured?" - -"Yes, it was twisted." - -"Do you not think, then, that he might have been trying to -straighten it?" - -"God bless you! You are doing what you can for him and for me. -But it is too heavy a task. What was he doing there at all? If -his purpose were innocent, why did he not say so?" - -"Precisely. And if it were guilty, why did he not invent a lie? -His silence appears to me to cut both ways. There are several -singular points about the case. What did the police think of the -noise which awoke you from your sleep?" - -"They considered that it might be caused by Arthur's closing his -bedroom door." - -"A likely story! As if a man bent on felony would slam his door -so as to wake a household. What did they say, then, of the -disappearance of these gems?" - -"They are still sounding the planking and probing the furniture -in the hope of finding them." - -"Have they thought of looking outside the house?" - -"Yes, they have shown extraordinary energy. The whole garden has -already been minutely examined." - -"Now, my dear sir," said Holmes, "is it not obvious to you now -that this matter really strikes very much deeper than either you -or the police were at first inclined to think? It appeared to you -to be a simple case; to me it seems exceedingly complex. Consider -what is involved by your theory. You suppose that your son came -down from his bed, went, at great risk, to your dressing-room, -opened your bureau, took out your coronet, broke off by main -force a small portion of it, went off to some other place, -concealed three gems out of the thirty-nine, with such skill that -nobody can find them, and then returned with the other thirty-six -into the room in which he exposed himself to the greatest danger -of being discovered. I ask you now, is such a theory tenable?" - -"But what other is there?" cried the banker with a gesture of -despair. "If his motives were innocent, why does he not explain -them?" - -"It is our task to find that out," replied Holmes; "so now, if -you please, Mr. Holder, we will set off for Streatham together, -and devote an hour to glancing a little more closely into -details." - -My friend insisted upon my accompanying them in their expedition, -which I was eager enough to do, for my curiosity and sympathy -were deeply stirred by the story to which we had listened. I -confess that the guilt of the banker's son appeared to me to be -as obvious as it did to his unhappy father, but still I had such -faith in Holmes' judgment that I felt that there must be some -grounds for hope as long as he was dissatisfied with the accepted -explanation. He hardly spoke a word the whole way out to the -southern suburb, but sat with his chin upon his breast and his -hat drawn over his eyes, sunk in the deepest thought. Our client -appeared to have taken fresh heart at the little glimpse of hope -which had been presented to him, and he even broke into a -desultory chat with me over his business affairs. A short railway -journey and a shorter walk brought us to Fairbank, the modest -residence of the great financier. - -Fairbank was a good-sized square house of white stone, standing -back a little from the road. A double carriage-sweep, with a -snow-clad lawn, stretched down in front to two large iron gates -which closed the entrance. On the right side was a small wooden -thicket, which led into a narrow path between two neat hedges -stretching from the road to the kitchen door, and forming the -tradesmen's entrance. On the left ran a lane which led to the -stables, and was not itself within the grounds at all, being a -public, though little used, thoroughfare. Holmes left us standing -at the door and walked slowly all round the house, across the -front, down the tradesmen's path, and so round by the garden -behind into the stable lane. So long was he that Mr. Holder and I -went into the dining-room and waited by the fire until he should -return. We were sitting there in silence when the door opened and -a young lady came in. She was rather above the middle height, -slim, with dark hair and eyes, which seemed the darker against -the absolute pallor of her skin. I do not think that I have ever -seen such deadly paleness in a woman's face. Her lips, too, were -bloodless, but her eyes were flushed with crying. As she swept -silently into the room she impressed me with a greater sense of -grief than the banker had done in the morning, and it was the -more striking in her as she was evidently a woman of strong -character, with immense capacity for self-restraint. Disregarding -my presence, she went straight to her uncle and passed her hand -over his head with a sweet womanly caress. - -"You have given orders that Arthur should be liberated, have you -not, dad?" she asked. - -"No, no, my girl, the matter must be probed to the bottom." - -"But I am so sure that he is innocent. You know what woman's -instincts are. I know that he has done no harm and that you will -be sorry for having acted so harshly." - -"Why is he silent, then, if he is innocent?" - -"Who knows? Perhaps because he was so angry that you should -suspect him." - -"How could I help suspecting him, when I actually saw him with -the coronet in his hand?" - -"Oh, but he had only picked it up to look at it. Oh, do, do take -my word for it that he is innocent. Let the matter drop and say -no more. It is so dreadful to think of our dear Arthur in -prison!" - -"I shall never let it drop until the gems are found--never, Mary! -Your affection for Arthur blinds you as to the awful consequences -to me. Far from hushing the thing up, I have brought a gentleman -down from London to inquire more deeply into it." - -"This gentleman?" she asked, facing round to me. - -"No, his friend. He wished us to leave him alone. He is round in -the stable lane now." - -"The stable lane?" She raised her dark eyebrows. "What can he -hope to find there? Ah! this, I suppose, is he. I trust, sir, -that you will succeed in proving, what I feel sure is the truth, -that my cousin Arthur is innocent of this crime." - -"I fully share your opinion, and I trust, with you, that we may -prove it," returned Holmes, going back to the mat to knock the -snow from his shoes. "I believe I have the honour of addressing -Miss Mary Holder. Might I ask you a question or two?" - -"Pray do, sir, if it may help to clear this horrible affair up." - -"You heard nothing yourself last night?" - -"Nothing, until my uncle here began to speak loudly. I heard -that, and I came down." - -"You shut up the windows and doors the night before. Did you -fasten all the windows?" - -"Yes." - -"Were they all fastened this morning?" - -"Yes." - -"You have a maid who has a sweetheart? I think that you remarked -to your uncle last night that she had been out to see him?" - -"Yes, and she was the girl who waited in the drawing-room, and -who may have heard uncle's remarks about the coronet." - -"I see. You infer that she may have gone out to tell her -sweetheart, and that the two may have planned the robbery." - -"But what is the good of all these vague theories," cried the -banker impatiently, "when I have told you that I saw Arthur with -the coronet in his hands?" - -"Wait a little, Mr. Holder. We must come back to that. About this -girl, Miss Holder. You saw her return by the kitchen door, I -presume?" - -"Yes; when I went to see if the door was fastened for the night I -met her slipping in. I saw the man, too, in the gloom." - -"Do you know him?" - -"Oh, yes! he is the green-grocer who brings our vegetables round. -His name is Francis Prosper." - -"He stood," said Holmes, "to the left of the door--that is to -say, farther up the path than is necessary to reach the door?" - -"Yes, he did." - -"And he is a man with a wooden leg?" - -Something like fear sprang up in the young lady's expressive -black eyes. "Why, you are like a magician," said she. "How do you -know that?" She smiled, but there was no answering smile in -Holmes' thin, eager face. - -"I should be very glad now to go upstairs," said he. "I shall -probably wish to go over the outside of the house again. Perhaps -I had better take a look at the lower windows before I go up." - -He walked swiftly round from one to the other, pausing only at -the large one which looked from the hall onto the stable lane. -This he opened and made a very careful examination of the sill -with his powerful magnifying lens. "Now we shall go upstairs," -said he at last. - -The banker's dressing-room was a plainly furnished little -chamber, with a grey carpet, a large bureau, and a long mirror. -Holmes went to the bureau first and looked hard at the lock. - -"Which key was used to open it?" he asked. - -"That which my son himself indicated--that of the cupboard of the -lumber-room." - -"Have you it here?" - -"That is it on the dressing-table." - -Sherlock Holmes took it up and opened the bureau. - -"It is a noiseless lock," said he. "It is no wonder that it did -not wake you. This case, I presume, contains the coronet. We must -have a look at it." He opened the case, and taking out the diadem -he laid it upon the table. It was a magnificent specimen of the -jeweller's art, and the thirty-six stones were the finest that I -have ever seen. At one side of the coronet was a cracked edge, -where a corner holding three gems had been torn away. - -"Now, Mr. Holder," said Holmes, "here is the corner which -corresponds to that which has been so unfortunately lost. Might I -beg that you will break it off." - -The banker recoiled in horror. "I should not dream of trying," -said he. - -"Then I will." Holmes suddenly bent his strength upon it, but -without result. "I feel it give a little," said he; "but, though -I am exceptionally strong in the fingers, it would take me all my -time to break it. An ordinary man could not do it. Now, what do -you think would happen if I did break it, Mr. Holder? There would -be a noise like a pistol shot. Do you tell me that all this -happened within a few yards of your bed and that you heard -nothing of it?" - -"I do not know what to think. It is all dark to me." - -"But perhaps it may grow lighter as we go. What do you think, -Miss Holder?" - -"I confess that I still share my uncle's perplexity." - -"Your son had no shoes or slippers on when you saw him?" - -"He had nothing on save only his trousers and shirt." - -"Thank you. We have certainly been favoured with extraordinary -luck during this inquiry, and it will be entirely our own fault -if we do not succeed in clearing the matter up. With your -permission, Mr. Holder, I shall now continue my investigations -outside." - -He went alone, at his own request, for he explained that any -unnecessary footmarks might make his task more difficult. For an -hour or more he was at work, returning at last with his feet -heavy with snow and his features as inscrutable as ever. - -"I think that I have seen now all that there is to see, Mr. -Holder," said he; "I can serve you best by returning to my -rooms." - -"But the gems, Mr. Holmes. Where are they?" - -"I cannot tell." - -The banker wrung his hands. "I shall never see them again!" he -cried. "And my son? You give me hopes?" - -"My opinion is in no way altered." - -"Then, for God's sake, what was this dark business which was -acted in my house last night?" - -"If you can call upon me at my Baker Street rooms to-morrow -morning between nine and ten I shall be happy to do what I can to -make it clearer. I understand that you give me carte blanche to -act for you, provided only that I get back the gems, and that you -place no limit on the sum I may draw." - -"I would give my fortune to have them back." - -"Very good. I shall look into the matter between this and then. -Good-bye; it is just possible that I may have to come over here -again before evening." - -It was obvious to me that my companion's mind was now made up -about the case, although what his conclusions were was more than -I could even dimly imagine. Several times during our homeward -journey I endeavoured to sound him upon the point, but he always -glided away to some other topic, until at last I gave it over in -despair. It was not yet three when we found ourselves in our -rooms once more. He hurried to his chamber and was down again in -a few minutes dressed as a common loafer. With his collar turned -up, his shiny, seedy coat, his red cravat, and his worn boots, he -was a perfect sample of the class. - -"I think that this should do," said he, glancing into the glass -above the fireplace. "I only wish that you could come with me, -Watson, but I fear that it won't do. I may be on the trail in -this matter, or I may be following a will-o'-the-wisp, but I -shall soon know which it is. I hope that I may be back in a few -hours." He cut a slice of beef from the joint upon the sideboard, -sandwiched it between two rounds of bread, and thrusting this -rude meal into his pocket he started off upon his expedition. - -I had just finished my tea when he returned, evidently in -excellent spirits, swinging an old elastic-sided boot in his -hand. He chucked it down into a corner and helped himself to a -cup of tea. - -"I only looked in as I passed," said he. "I am going right on." - -"Where to?" - -"Oh, to the other side of the West End. It may be some time -before I get back. Don't wait up for me in case I should be -late." - -"How are you getting on?" - -"Oh, so so. Nothing to complain of. I have been out to Streatham -since I saw you last, but I did not call at the house. It is a -very sweet little problem, and I would not have missed it for a -good deal. However, I must not sit gossiping here, but must get -these disreputable clothes off and return to my highly -respectable self." - -I could see by his manner that he had stronger reasons for -satisfaction than his words alone would imply. His eyes twinkled, -and there was even a touch of colour upon his sallow cheeks. He -hastened upstairs, and a few minutes later I heard the slam of -the hall door, which told me that he was off once more upon his -congenial hunt. - -I waited until midnight, but there was no sign of his return, so -I retired to my room. It was no uncommon thing for him to be away -for days and nights on end when he was hot upon a scent, so that -his lateness caused me no surprise. I do not know at what hour he -came in, but when I came down to breakfast in the morning there -he was with a cup of coffee in one hand and the paper in the -other, as fresh and trim as possible. - -"You will excuse my beginning without you, Watson," said he, "but -you remember that our client has rather an early appointment this -morning." - -"Why, it is after nine now," I answered. "I should not be -surprised if that were he. I thought I heard a ring." - -It was, indeed, our friend the financier. I was shocked by the -change which had come over him, for his face which was naturally -of a broad and massive mould, was now pinched and fallen in, -while his hair seemed to me at least a shade whiter. He entered -with a weariness and lethargy which was even more painful than -his violence of the morning before, and he dropped heavily into -the armchair which I pushed forward for him. - -"I do not know what I have done to be so severely tried," said -he. "Only two days ago I was a happy and prosperous man, without -a care in the world. Now I am left to a lonely and dishonoured -age. One sorrow comes close upon the heels of another. My niece, -Mary, has deserted me." - -"Deserted you?" - -"Yes. Her bed this morning had not been slept in, her room was -empty, and a note for me lay upon the hall table. I had said to -her last night, in sorrow and not in anger, that if she had -married my boy all might have been well with him. Perhaps it was -thoughtless of me to say so. It is to that remark that she refers -in this note: - -"'MY DEAREST UNCLE:--I feel that I have brought trouble upon you, -and that if I had acted differently this terrible misfortune -might never have occurred. I cannot, with this thought in my -mind, ever again be happy under your roof, and I feel that I must -leave you forever. Do not worry about my future, for that is -provided for; and, above all, do not search for me, for it will -be fruitless labour and an ill-service to me. In life or in -death, I am ever your loving,--MARY.' - -"What could she mean by that note, Mr. Holmes? Do you think it -points to suicide?" - -"No, no, nothing of the kind. It is perhaps the best possible -solution. I trust, Mr. Holder, that you are nearing the end of -your troubles." - -"Ha! You say so! You have heard something, Mr. Holmes; you have -learned something! Where are the gems?" - -"You would not think 1000 pounds apiece an excessive sum for -them?" - -"I would pay ten." - -"That would be unnecessary. Three thousand will cover the matter. -And there is a little reward, I fancy. Have you your check-book? -Here is a pen. Better make it out for 4000 pounds." - -With a dazed face the banker made out the required check. Holmes -walked over to his desk, took out a little triangular piece of -gold with three gems in it, and threw it down upon the table. - -With a shriek of joy our client clutched it up. - -"You have it!" he gasped. "I am saved! I am saved!" - -The reaction of joy was as passionate as his grief had been, and -he hugged his recovered gems to his bosom. - -"There is one other thing you owe, Mr. Holder," said Sherlock -Holmes rather sternly. - -"Owe!" He caught up a pen. "Name the sum, and I will pay it." - -"No, the debt is not to me. You owe a very humble apology to that -noble lad, your son, who has carried himself in this matter as I -should be proud to see my own son do, should I ever chance to -have one." - -"Then it was not Arthur who took them?" - -"I told you yesterday, and I repeat to-day, that it was not." - -"You are sure of it! Then let us hurry to him at once to let him -know that the truth is known." - -"He knows it already. When I had cleared it all up I had an -interview with him, and finding that he would not tell me the -story, I told it to him, on which he had to confess that I was -right and to add the very few details which were not yet quite -clear to me. Your news of this morning, however, may open his -lips." - -"For heaven's sake, tell me, then, what is this extraordinary -mystery!" - -"I will do so, and I will show you the steps by which I reached -it. And let me say to you, first, that which it is hardest for me -to say and for you to hear: there has been an understanding -between Sir George Burnwell and your niece Mary. They have now -fled together." - -"My Mary? Impossible!" - -"It is unfortunately more than possible; it is certain. Neither -you nor your son knew the true character of this man when you -admitted him into your family circle. He is one of the most -dangerous men in England--a ruined gambler, an absolutely -desperate villain, a man without heart or conscience. Your niece -knew nothing of such men. When he breathed his vows to her, as he -had done to a hundred before her, she flattered herself that she -alone had touched his heart. The devil knows best what he said, -but at least she became his tool and was in the habit of seeing -him nearly every evening." - -"I cannot, and I will not, believe it!" cried the banker with an -ashen face. - -"I will tell you, then, what occurred in your house last night. -Your niece, when you had, as she thought, gone to your room, -slipped down and talked to her lover through the window which -leads into the stable lane. His footmarks had pressed right -through the snow, so long had he stood there. She told him of the -coronet. His wicked lust for gold kindled at the news, and he -bent her to his will. I have no doubt that she loved you, but -there are women in whom the love of a lover extinguishes all -other loves, and I think that she must have been one. She had -hardly listened to his instructions when she saw you coming -downstairs, on which she closed the window rapidly and told you -about one of the servants' escapade with her wooden-legged lover, -which was all perfectly true. - -"Your boy, Arthur, went to bed after his interview with you but -he slept badly on account of his uneasiness about his club debts. -In the middle of the night he heard a soft tread pass his door, -so he rose and, looking out, was surprised to see his cousin -walking very stealthily along the passage until she disappeared -into your dressing-room. Petrified with astonishment, the lad -slipped on some clothes and waited there in the dark to see what -would come of this strange affair. Presently she emerged from the -room again, and in the light of the passage-lamp your son saw -that she carried the precious coronet in her hands. She passed -down the stairs, and he, thrilling with horror, ran along and -slipped behind the curtain near your door, whence he could see -what passed in the hall beneath. He saw her stealthily open the -window, hand out the coronet to someone in the gloom, and then -closing it once more hurry back to her room, passing quite close -to where he stood hid behind the curtain. - -"As long as she was on the scene he could not take any action -without a horrible exposure of the woman whom he loved. But the -instant that she was gone he realised how crushing a misfortune -this would be for you, and how all-important it was to set it -right. He rushed down, just as he was, in his bare feet, opened -the window, sprang out into the snow, and ran down the lane, -where he could see a dark figure in the moonlight. Sir George -Burnwell tried to get away, but Arthur caught him, and there was -a struggle between them, your lad tugging at one side of the -coronet, and his opponent at the other. In the scuffle, your son -struck Sir George and cut him over the eye. Then something -suddenly snapped, and your son, finding that he had the coronet -in his hands, rushed back, closed the window, ascended to your -room, and had just observed that the coronet had been twisted in -the struggle and was endeavouring to straighten it when you -appeared upon the scene." - -"Is it possible?" gasped the banker. - -"You then roused his anger by calling him names at a moment when -he felt that he had deserved your warmest thanks. He could not -explain the true state of affairs without betraying one who -certainly deserved little enough consideration at his hands. He -took the more chivalrous view, however, and preserved her -secret." - -"And that was why she shrieked and fainted when she saw the -coronet," cried Mr. Holder. "Oh, my God! what a blind fool I have -been! And his asking to be allowed to go out for five minutes! -The dear fellow wanted to see if the missing piece were at the -scene of the struggle. How cruelly I have misjudged him!" - -"When I arrived at the house," continued Holmes, "I at once went -very carefully round it to observe if there were any traces in -the snow which might help me. I knew that none had fallen since -the evening before, and also that there had been a strong frost -to preserve impressions. I passed along the tradesmen's path, but -found it all trampled down and indistinguishable. Just beyond it, -however, at the far side of the kitchen door, a woman had stood -and talked with a man, whose round impressions on one side showed -that he had a wooden leg. I could even tell that they had been -disturbed, for the woman had run back swiftly to the door, as was -shown by the deep toe and light heel marks, while Wooden-leg had -waited a little, and then had gone away. I thought at the time -that this might be the maid and her sweetheart, of whom you had -already spoken to me, and inquiry showed it was so. I passed -round the garden without seeing anything more than random tracks, -which I took to be the police; but when I got into the stable -lane a very long and complex story was written in the snow in -front of me. - -"There was a double line of tracks of a booted man, and a second -double line which I saw with delight belonged to a man with naked -feet. I was at once convinced from what you had told me that the -latter was your son. The first had walked both ways, but the -other had run swiftly, and as his tread was marked in places over -the depression of the boot, it was obvious that he had passed -after the other. I followed them up and found they led to the -hall window, where Boots had worn all the snow away while -waiting. Then I walked to the other end, which was a hundred -yards or more down the lane. I saw where Boots had faced round, -where the snow was cut up as though there had been a struggle, -and, finally, where a few drops of blood had fallen, to show me -that I was not mistaken. Boots had then run down the lane, and -another little smudge of blood showed that it was he who had been -hurt. When he came to the highroad at the other end, I found that -the pavement had been cleared, so there was an end to that clue. - -"On entering the house, however, I examined, as you remember, the -sill and framework of the hall window with my lens, and I could -at once see that someone had passed out. I could distinguish the -outline of an instep where the wet foot had been placed in coming -in. I was then beginning to be able to form an opinion as to what -had occurred. A man had waited outside the window; someone had -brought the gems; the deed had been overseen by your son; he had -pursued the thief; had struggled with him; they had each tugged -at the coronet, their united strength causing injuries which -neither alone could have effected. He had returned with the -prize, but had left a fragment in the grasp of his opponent. So -far I was clear. The question now was, who was the man and who -was it brought him the coronet? - -"It is an old maxim of mine that when you have excluded the -impossible, whatever remains, however improbable, must be the -truth. Now, I knew that it was not you who had brought it down, -so there only remained your niece and the maids. But if it were -the maids, why should your son allow himself to be accused in -their place? There could be no possible reason. As he loved his -cousin, however, there was an excellent explanation why he should -retain her secret--the more so as the secret was a disgraceful -one. When I remembered that you had seen her at that window, and -how she had fainted on seeing the coronet again, my conjecture -became a certainty. - -"And who could it be who was her confederate? A lover evidently, -for who else could outweigh the love and gratitude which she must -feel to you? I knew that you went out little, and that your -circle of friends was a very limited one. But among them was Sir -George Burnwell. I had heard of him before as being a man of evil -reputation among women. It must have been he who wore those boots -and retained the missing gems. Even though he knew that Arthur -had discovered him, he might still flatter himself that he was -safe, for the lad could not say a word without compromising his -own family. - -"Well, your own good sense will suggest what measures I took -next. I went in the shape of a loafer to Sir George's house, -managed to pick up an acquaintance with his valet, learned that -his master had cut his head the night before, and, finally, at -the expense of six shillings, made all sure by buying a pair of -his cast-off shoes. With these I journeyed down to Streatham and -saw that they exactly fitted the tracks." - -"I saw an ill-dressed vagabond in the lane yesterday evening," -said Mr. Holder. - -"Precisely. It was I. I found that I had my man, so I came home -and changed my clothes. It was a delicate part which I had to -play then, for I saw that a prosecution must be avoided to avert -scandal, and I knew that so astute a villain would see that our -hands were tied in the matter. I went and saw him. At first, of -course, he denied everything. But when I gave him every -particular that had occurred, he tried to bluster and took down a -life-preserver from the wall. I knew my man, however, and I -clapped a pistol to his head before he could strike. Then he -became a little more reasonable. I told him that we would give -him a price for the stones he held--1000 pounds apiece. That -brought out the first signs of grief that he had shown. 'Why, -dash it all!' said he, 'I've let them go at six hundred for the -three!' I soon managed to get the address of the receiver who had -them, on promising him that there would be no prosecution. Off I -set to him, and after much chaffering I got our stones at 1000 -pounds apiece. Then I looked in upon your son, told him that all -was right, and eventually got to my bed about two o'clock, after -what I may call a really hard day's work." - -"A day which has saved England from a great public scandal," said -the banker, rising. "Sir, I cannot find words to thank you, but -you shall not find me ungrateful for what you have done. Your -skill has indeed exceeded all that I have heard of it. And now I -must fly to my dear boy to apologise to him for the wrong which I -have done him. As to what you tell me of poor Mary, it goes to my -very heart. Not even your skill can inform me where she is now." - -"I think that we may safely say," returned Holmes, "that she is -wherever Sir George Burnwell is. It is equally certain, too, that -whatever her sins are, they will soon receive a more than -sufficient punishment." - - - -XII. THE ADVENTURE OF THE COPPER BEECHES - -"To the man who loves art for its own sake," remarked Sherlock -Holmes, tossing aside the advertisement sheet of the Daily -Telegraph, "it is frequently in its least important and lowliest -manifestations that the keenest pleasure is to be derived. It is -pleasant to me to observe, Watson, that you have so far grasped -this truth that in these little records of our cases which you -have been good enough to draw up, and, I am bound to say, -occasionally to embellish, you have given prominence not so much -to the many causes célèbres and sensational trials in which I -have figured but rather to those incidents which may have been -trivial in themselves, but which have given room for those -faculties of deduction and of logical synthesis which I have made -my special province." - -"And yet," said I, smiling, "I cannot quite hold myself absolved -from the charge of sensationalism which has been urged against my -records." - -"You have erred, perhaps," he observed, taking up a glowing -cinder with the tongs and lighting with it the long cherry-wood -pipe which was wont to replace his clay when he was in a -disputatious rather than a meditative mood--"you have erred -perhaps in attempting to put colour and life into each of your -statements instead of confining yourself to the task of placing -upon record that severe reasoning from cause to effect which is -really the only notable feature about the thing." - -"It seems to me that I have done you full justice in the matter," -I remarked with some coldness, for I was repelled by the egotism -which I had more than once observed to be a strong factor in my -friend's singular character. - -"No, it is not selfishness or conceit," said he, answering, as -was his wont, my thoughts rather than my words. "If I claim full -justice for my art, it is because it is an impersonal thing--a -thing beyond myself. Crime is common. Logic is rare. Therefore it -is upon the logic rather than upon the crime that you should -dwell. You have degraded what should have been a course of -lectures into a series of tales." - -It was a cold morning of the early spring, and we sat after -breakfast on either side of a cheery fire in the old room at -Baker Street. A thick fog rolled down between the lines of -dun-coloured houses, and the opposing windows loomed like dark, -shapeless blurs through the heavy yellow wreaths. Our gas was lit -and shone on the white cloth and glimmer of china and metal, for -the table had not been cleared yet. Sherlock Holmes had been -silent all the morning, dipping continuously into the -advertisement columns of a succession of papers until at last, -having apparently given up his search, he had emerged in no very -sweet temper to lecture me upon my literary shortcomings. - -"At the same time," he remarked after a pause, during which he -had sat puffing at his long pipe and gazing down into the fire, -"you can hardly be open to a charge of sensationalism, for out of -these cases which you have been so kind as to interest yourself -in, a fair proportion do not treat of crime, in its legal sense, -at all. The small matter in which I endeavoured to help the King -of Bohemia, the singular experience of Miss Mary Sutherland, the -problem connected with the man with the twisted lip, and the -incident of the noble bachelor, were all matters which are -outside the pale of the law. But in avoiding the sensational, I -fear that you may have bordered on the trivial." - -"The end may have been so," I answered, "but the methods I hold -to have been novel and of interest." - -"Pshaw, my dear fellow, what do the public, the great unobservant -public, who could hardly tell a weaver by his tooth or a -compositor by his left thumb, care about the finer shades of -analysis and deduction! But, indeed, if you are trivial, I cannot -blame you, for the days of the great cases are past. Man, or at -least criminal man, has lost all enterprise and originality. As -to my own little practice, it seems to be degenerating into an -agency for recovering lost lead pencils and giving advice to -young ladies from boarding-schools. I think that I have touched -bottom at last, however. This note I had this morning marks my -zero-point, I fancy. Read it!" He tossed a crumpled letter across -to me. - -It was dated from Montague Place upon the preceding evening, and -ran thus: - -"DEAR MR. HOLMES:--I am very anxious to consult you as to whether -I should or should not accept a situation which has been offered -to me as governess. I shall call at half-past ten to-morrow if I -do not inconvenience you. Yours faithfully, - "VIOLET HUNTER." - -"Do you know the young lady?" I asked. - -"Not I." - -"It is half-past ten now." - -"Yes, and I have no doubt that is her ring." - -"It may turn out to be of more interest than you think. You -remember that the affair of the blue carbuncle, which appeared to -be a mere whim at first, developed into a serious investigation. -It may be so in this case, also." - -"Well, let us hope so. But our doubts will very soon be solved, -for here, unless I am much mistaken, is the person in question." - -As he spoke the door opened and a young lady entered the room. -She was plainly but neatly dressed, with a bright, quick face, -freckled like a plover's egg, and with the brisk manner of a -woman who has had her own way to make in the world. - -"You will excuse my troubling you, I am sure," said she, as my -companion rose to greet her, "but I have had a very strange -experience, and as I have no parents or relations of any sort -from whom I could ask advice, I thought that perhaps you would be -kind enough to tell me what I should do." - -"Pray take a seat, Miss Hunter. I shall be happy to do anything -that I can to serve you." - -I could see that Holmes was favourably impressed by the manner -and speech of his new client. He looked her over in his searching -fashion, and then composed himself, with his lids drooping and -his finger-tips together, to listen to her story. - -"I have been a governess for five years," said she, "in the -family of Colonel Spence Munro, but two months ago the colonel -received an appointment at Halifax, in Nova Scotia, and took his -children over to America with him, so that I found myself without -a situation. I advertised, and I answered advertisements, but -without success. At last the little money which I had saved began -to run short, and I was at my wit's end as to what I should do. - -"There is a well-known agency for governesses in the West End -called Westaway's, and there I used to call about once a week in -order to see whether anything had turned up which might suit me. -Westaway was the name of the founder of the business, but it is -really managed by Miss Stoper. She sits in her own little office, -and the ladies who are seeking employment wait in an anteroom, -and are then shown in one by one, when she consults her ledgers -and sees whether she has anything which would suit them. - -"Well, when I called last week I was shown into the little office -as usual, but I found that Miss Stoper was not alone. A -prodigiously stout man with a very smiling face and a great heavy -chin which rolled down in fold upon fold over his throat sat at -her elbow with a pair of glasses on his nose, looking very -earnestly at the ladies who entered. As I came in he gave quite a -jump in his chair and turned quickly to Miss Stoper. - -"'That will do,' said he; 'I could not ask for anything better. -Capital! capital!' He seemed quite enthusiastic and rubbed his -hands together in the most genial fashion. He was such a -comfortable-looking man that it was quite a pleasure to look at -him. - -"'You are looking for a situation, miss?' he asked. - -"'Yes, sir.' - -"'As governess?' - -"'Yes, sir.' - -"'And what salary do you ask?' - -"'I had 4 pounds a month in my last place with Colonel Spence -Munro.' - -"'Oh, tut, tut! sweating--rank sweating!' he cried, throwing his -fat hands out into the air like a man who is in a boiling -passion. 'How could anyone offer so pitiful a sum to a lady with -such attractions and accomplishments?' - -"'My accomplishments, sir, may be less than you imagine,' said I. -'A little French, a little German, music, and drawing--' - -"'Tut, tut!' he cried. 'This is all quite beside the question. -The point is, have you or have you not the bearing and deportment -of a lady? There it is in a nutshell. If you have not, you are -not fitted for the rearing of a child who may some day play a -considerable part in the history of the country. But if you have -why, then, how could any gentleman ask you to condescend to -accept anything under the three figures? Your salary with me, -madam, would commence at 100 pounds a year.' - -"You may imagine, Mr. Holmes, that to me, destitute as I was, -such an offer seemed almost too good to be true. The gentleman, -however, seeing perhaps the look of incredulity upon my face, -opened a pocket-book and took out a note. - -"'It is also my custom,' said he, smiling in the most pleasant -fashion until his eyes were just two little shining slits amid -the white creases of his face, 'to advance to my young ladies -half their salary beforehand, so that they may meet any little -expenses of their journey and their wardrobe.' - -"It seemed to me that I had never met so fascinating and so -thoughtful a man. As I was already in debt to my tradesmen, the -advance was a great convenience, and yet there was something -unnatural about the whole transaction which made me wish to know -a little more before I quite committed myself. - -"'May I ask where you live, sir?' said I. - -"'Hampshire. Charming rural place. The Copper Beeches, five miles -on the far side of Winchester. It is the most lovely country, my -dear young lady, and the dearest old country-house.' - -"'And my duties, sir? I should be glad to know what they would -be.' - -"'One child--one dear little romper just six years old. Oh, if -you could see him killing cockroaches with a slipper! Smack! -smack! smack! Three gone before you could wink!' He leaned back -in his chair and laughed his eyes into his head again. - -"I was a little startled at the nature of the child's amusement, -but the father's laughter made me think that perhaps he was -joking. - -"'My sole duties, then,' I asked, 'are to take charge of a single -child?' - -"'No, no, not the sole, not the sole, my dear young lady,' he -cried. 'Your duty would be, as I am sure your good sense would -suggest, to obey any little commands my wife might give, provided -always that they were such commands as a lady might with -propriety obey. You see no difficulty, heh?' - -"'I should be happy to make myself useful.' - -"'Quite so. In dress now, for example. We are faddy people, you -know--faddy but kind-hearted. If you were asked to wear any dress -which we might give you, you would not object to our little whim. -Heh?' - -"'No,' said I, considerably astonished at his words. - -"'Or to sit here, or sit there, that would not be offensive to -you?' - -"'Oh, no.' - -"'Or to cut your hair quite short before you come to us?' - -"I could hardly believe my ears. As you may observe, Mr. Holmes, -my hair is somewhat luxuriant, and of a rather peculiar tint of -chestnut. It has been considered artistic. I could not dream of -sacrificing it in this offhand fashion. - -"'I am afraid that that is quite impossible,' said I. He had been -watching me eagerly out of his small eyes, and I could see a -shadow pass over his face as I spoke. - -"'I am afraid that it is quite essential,' said he. 'It is a -little fancy of my wife's, and ladies' fancies, you know, madam, -ladies' fancies must be consulted. And so you won't cut your -hair?' - -"'No, sir, I really could not,' I answered firmly. - -"'Ah, very well; then that quite settles the matter. It is a -pity, because in other respects you would really have done very -nicely. In that case, Miss Stoper, I had best inspect a few more -of your young ladies.' - -"The manageress had sat all this while busy with her papers -without a word to either of us, but she glanced at me now with so -much annoyance upon her face that I could not help suspecting -that she had lost a handsome commission through my refusal. - -"'Do you desire your name to be kept upon the books?' she asked. - -"'If you please, Miss Stoper.' - -"'Well, really, it seems rather useless, since you refuse the -most excellent offers in this fashion,' said she sharply. 'You -can hardly expect us to exert ourselves to find another such -opening for you. Good-day to you, Miss Hunter.' She struck a gong -upon the table, and I was shown out by the page. - -"Well, Mr. Holmes, when I got back to my lodgings and found -little enough in the cupboard, and two or three bills upon the -table, I began to ask myself whether I had not done a very -foolish thing. After all, if these people had strange fads and -expected obedience on the most extraordinary matters, they were -at least ready to pay for their eccentricity. Very few -governesses in England are getting 100 pounds a year. Besides, -what use was my hair to me? Many people are improved by wearing -it short and perhaps I should be among the number. Next day I was -inclined to think that I had made a mistake, and by the day after -I was sure of it. I had almost overcome my pride so far as to go -back to the agency and inquire whether the place was still open -when I received this letter from the gentleman himself. I have it -here and I will read it to you: - - "'The Copper Beeches, near Winchester. -"'DEAR MISS HUNTER:--Miss Stoper has very kindly given me your -address, and I write from here to ask you whether you have -reconsidered your decision. My wife is very anxious that you -should come, for she has been much attracted by my description of -you. We are willing to give 30 pounds a quarter, or 120 pounds a -year, so as to recompense you for any little inconvenience which -our fads may cause you. They are not very exacting, after all. My -wife is fond of a particular shade of electric blue and would -like you to wear such a dress indoors in the morning. You need -not, however, go to the expense of purchasing one, as we have one -belonging to my dear daughter Alice (now in Philadelphia), which -would, I should think, fit you very well. Then, as to sitting -here or there, or amusing yourself in any manner indicated, that -need cause you no inconvenience. As regards your hair, it is no -doubt a pity, especially as I could not help remarking its beauty -during our short interview, but I am afraid that I must remain -firm upon this point, and I only hope that the increased salary -may recompense you for the loss. Your duties, as far as the child -is concerned, are very light. Now do try to come, and I shall -meet you with the dog-cart at Winchester. Let me know your train. -Yours faithfully, JEPHRO RUCASTLE.' - -"That is the letter which I have just received, Mr. Holmes, and -my mind is made up that I will accept it. I thought, however, -that before taking the final step I should like to submit the -whole matter to your consideration." - -"Well, Miss Hunter, if your mind is made up, that settles the -question," said Holmes, smiling. - -"But you would not advise me to refuse?" - -"I confess that it is not the situation which I should like to -see a sister of mine apply for." - -"What is the meaning of it all, Mr. Holmes?" - -"Ah, I have no data. I cannot tell. Perhaps you have yourself -formed some opinion?" - -"Well, there seems to me to be only one possible solution. Mr. -Rucastle seemed to be a very kind, good-natured man. Is it not -possible that his wife is a lunatic, that he desires to keep the -matter quiet for fear she should be taken to an asylum, and that -he humours her fancies in every way in order to prevent an -outbreak?" - -"That is a possible solution--in fact, as matters stand, it is -the most probable one. But in any case it does not seem to be a -nice household for a young lady." - -"But the money, Mr. Holmes, the money!" - -"Well, yes, of course the pay is good--too good. That is what -makes me uneasy. Why should they give you 120 pounds a year, when -they could have their pick for 40 pounds? There must be some -strong reason behind." - -"I thought that if I told you the circumstances you would -understand afterwards if I wanted your help. I should feel so -much stronger if I felt that you were at the back of me." - -"Oh, you may carry that feeling away with you. I assure you that -your little problem promises to be the most interesting which has -come my way for some months. There is something distinctly novel -about some of the features. If you should find yourself in doubt -or in danger--" - -"Danger! What danger do you foresee?" - -Holmes shook his head gravely. "It would cease to be a danger if -we could define it," said he. "But at any time, day or night, a -telegram would bring me down to your help." - -"That is enough." She rose briskly from her chair with the -anxiety all swept from her face. "I shall go down to Hampshire -quite easy in my mind now. I shall write to Mr. Rucastle at once, -sacrifice my poor hair to-night, and start for Winchester -to-morrow." With a few grateful words to Holmes she bade us both -good-night and bustled off upon her way. - -"At least," said I as we heard her quick, firm steps descending -the stairs, "she seems to be a young lady who is very well able -to take care of herself." - -"And she would need to be," said Holmes gravely. "I am much -mistaken if we do not hear from her before many days are past." - -It was not very long before my friend's prediction was fulfilled. -A fortnight went by, during which I frequently found my thoughts -turning in her direction and wondering what strange side-alley of -human experience this lonely woman had strayed into. The unusual -salary, the curious conditions, the light duties, all pointed to -something abnormal, though whether a fad or a plot, or whether -the man were a philanthropist or a villain, it was quite beyond -my powers to determine. As to Holmes, I observed that he sat -frequently for half an hour on end, with knitted brows and an -abstracted air, but he swept the matter away with a wave of his -hand when I mentioned it. "Data! data! data!" he cried -impatiently. "I can't make bricks without clay." And yet he would -always wind up by muttering that no sister of his should ever -have accepted such a situation. - -The telegram which we eventually received came late one night -just as I was thinking of turning in and Holmes was settling down -to one of those all-night chemical researches which he frequently -indulged in, when I would leave him stooping over a retort and a -test-tube at night and find him in the same position when I came -down to breakfast in the morning. He opened the yellow envelope, -and then, glancing at the message, threw it across to me. - -"Just look up the trains in Bradshaw," said he, and turned back -to his chemical studies. - -The summons was a brief and urgent one. - -"Please be at the Black Swan Hotel at Winchester at midday -to-morrow," it said. "Do come! I am at my wit's end. HUNTER." - -"Will you come with me?" asked Holmes, glancing up. - -"I should wish to." - -"Just look it up, then." - -"There is a train at half-past nine," said I, glancing over my -Bradshaw. "It is due at Winchester at 11:30." - -"That will do very nicely. Then perhaps I had better postpone my -analysis of the acetones, as we may need to be at our best in the -morning." - -By eleven o'clock the next day we were well upon our way to the -old English capital. Holmes had been buried in the morning papers -all the way down, but after we had passed the Hampshire border he -threw them down and began to admire the scenery. It was an ideal -spring day, a light blue sky, flecked with little fleecy white -clouds drifting across from west to east. The sun was shining -very brightly, and yet there was an exhilarating nip in the air, -which set an edge to a man's energy. All over the countryside, -away to the rolling hills around Aldershot, the little red and -grey roofs of the farm-steadings peeped out from amid the light -green of the new foliage. - -"Are they not fresh and beautiful?" I cried with all the -enthusiasm of a man fresh from the fogs of Baker Street. - -But Holmes shook his head gravely. - -"Do you know, Watson," said he, "that it is one of the curses of -a mind with a turn like mine that I must look at everything with -reference to my own special subject. You look at these scattered -houses, and you are impressed by their beauty. I look at them, -and the only thought which comes to me is a feeling of their -isolation and of the impunity with which crime may be committed -there." - -"Good heavens!" I cried. "Who would associate crime with these -dear old homesteads?" - -"They always fill me with a certain horror. It is my belief, -Watson, founded upon my experience, that the lowest and vilest -alleys in London do not present a more dreadful record of sin -than does the smiling and beautiful countryside." - -"You horrify me!" - -"But the reason is very obvious. The pressure of public opinion -can do in the town what the law cannot accomplish. There is no -lane so vile that the scream of a tortured child, or the thud of -a drunkard's blow, does not beget sympathy and indignation among -the neighbours, and then the whole machinery of justice is ever -so close that a word of complaint can set it going, and there is -but a step between the crime and the dock. But look at these -lonely houses, each in its own fields, filled for the most part -with poor ignorant folk who know little of the law. Think of the -deeds of hellish cruelty, the hidden wickedness which may go on, -year in, year out, in such places, and none the wiser. Had this -lady who appeals to us for help gone to live in Winchester, I -should never have had a fear for her. It is the five miles of -country which makes the danger. Still, it is clear that she is -not personally threatened." - -"No. If she can come to Winchester to meet us she can get away." - -"Quite so. She has her freedom." - -"What CAN be the matter, then? Can you suggest no explanation?" - -"I have devised seven separate explanations, each of which would -cover the facts as far as we know them. But which of these is -correct can only be determined by the fresh information which we -shall no doubt find waiting for us. Well, there is the tower of -the cathedral, and we shall soon learn all that Miss Hunter has -to tell." - -The Black Swan is an inn of repute in the High Street, at no -distance from the station, and there we found the young lady -waiting for us. She had engaged a sitting-room, and our lunch -awaited us upon the table. - -"I am so delighted that you have come," she said earnestly. "It -is so very kind of you both; but indeed I do not know what I -should do. Your advice will be altogether invaluable to me." - -"Pray tell us what has happened to you." - -"I will do so, and I must be quick, for I have promised Mr. -Rucastle to be back before three. I got his leave to come into -town this morning, though he little knew for what purpose." - -"Let us have everything in its due order." Holmes thrust his long -thin legs out towards the fire and composed himself to listen. - -"In the first place, I may say that I have met, on the whole, -with no actual ill-treatment from Mr. and Mrs. Rucastle. It is -only fair to them to say that. But I cannot understand them, and -I am not easy in my mind about them." - -"What can you not understand?" - -"Their reasons for their conduct. But you shall have it all just -as it occurred. When I came down, Mr. Rucastle met me here and -drove me in his dog-cart to the Copper Beeches. It is, as he -said, beautifully situated, but it is not beautiful in itself, -for it is a large square block of a house, whitewashed, but all -stained and streaked with damp and bad weather. There are grounds -round it, woods on three sides, and on the fourth a field which -slopes down to the Southampton highroad, which curves past about -a hundred yards from the front door. This ground in front belongs -to the house, but the woods all round are part of Lord -Southerton's preserves. A clump of copper beeches immediately in -front of the hall door has given its name to the place. - -"I was driven over by my employer, who was as amiable as ever, -and was introduced by him that evening to his wife and the child. -There was no truth, Mr. Holmes, in the conjecture which seemed to -us to be probable in your rooms at Baker Street. Mrs. Rucastle is -not mad. I found her to be a silent, pale-faced woman, much -younger than her husband, not more than thirty, I should think, -while he can hardly be less than forty-five. From their -conversation I have gathered that they have been married about -seven years, that he was a widower, and that his only child by -the first wife was the daughter who has gone to Philadelphia. Mr. -Rucastle told me in private that the reason why she had left them -was that she had an unreasoning aversion to her stepmother. As -the daughter could not have been less than twenty, I can quite -imagine that her position must have been uncomfortable with her -father's young wife. - -"Mrs. Rucastle seemed to me to be colourless in mind as well as -in feature. She impressed me neither favourably nor the reverse. -She was a nonentity. It was easy to see that she was passionately -devoted both to her husband and to her little son. Her light grey -eyes wandered continually from one to the other, noting every -little want and forestalling it if possible. He was kind to her -also in his bluff, boisterous fashion, and on the whole they -seemed to be a happy couple. And yet she had some secret sorrow, -this woman. She would often be lost in deep thought, with the -saddest look upon her face. More than once I have surprised her -in tears. I have thought sometimes that it was the disposition of -her child which weighed upon her mind, for I have never met so -utterly spoiled and so ill-natured a little creature. He is small -for his age, with a head which is quite disproportionately large. -His whole life appears to be spent in an alternation between -savage fits of passion and gloomy intervals of sulking. Giving -pain to any creature weaker than himself seems to be his one idea -of amusement, and he shows quite remarkable talent in planning -the capture of mice, little birds, and insects. But I would -rather not talk about the creature, Mr. Holmes, and, indeed, he -has little to do with my story." - -"I am glad of all details," remarked my friend, "whether they -seem to you to be relevant or not." - -"I shall try not to miss anything of importance. The one -unpleasant thing about the house, which struck me at once, was -the appearance and conduct of the servants. There are only two, a -man and his wife. Toller, for that is his name, is a rough, -uncouth man, with grizzled hair and whiskers, and a perpetual -smell of drink. Twice since I have been with them he has been -quite drunk, and yet Mr. Rucastle seemed to take no notice of it. -His wife is a very tall and strong woman with a sour face, as -silent as Mrs. Rucastle and much less amiable. They are a most -unpleasant couple, but fortunately I spend most of my time in the -nursery and my own room, which are next to each other in one -corner of the building. - -"For two days after my arrival at the Copper Beeches my life was -very quiet; on the third, Mrs. Rucastle came down just after -breakfast and whispered something to her husband. - -"'Oh, yes,' said he, turning to me, 'we are very much obliged to -you, Miss Hunter, for falling in with our whims so far as to cut -your hair. I assure you that it has not detracted in the tiniest -iota from your appearance. We shall now see how the electric-blue -dress will become you. You will find it laid out upon the bed in -your room, and if you would be so good as to put it on we should -both be extremely obliged.' - -"The dress which I found waiting for me was of a peculiar shade -of blue. It was of excellent material, a sort of beige, but it -bore unmistakable signs of having been worn before. It could not -have been a better fit if I had been measured for it. Both Mr. -and Mrs. Rucastle expressed a delight at the look of it, which -seemed quite exaggerated in its vehemence. They were waiting for -me in the drawing-room, which is a very large room, stretching -along the entire front of the house, with three long windows -reaching down to the floor. A chair had been placed close to the -central window, with its back turned towards it. In this I was -asked to sit, and then Mr. Rucastle, walking up and down on the -other side of the room, began to tell me a series of the funniest -stories that I have ever listened to. You cannot imagine how -comical he was, and I laughed until I was quite weary. Mrs. -Rucastle, however, who has evidently no sense of humour, never so -much as smiled, but sat with her hands in her lap, and a sad, -anxious look upon her face. After an hour or so, Mr. Rucastle -suddenly remarked that it was time to commence the duties of the -day, and that I might change my dress and go to little Edward in -the nursery. - -"Two days later this same performance was gone through under -exactly similar circumstances. Again I changed my dress, again I -sat in the window, and again I laughed very heartily at the funny -stories of which my employer had an immense répertoire, and which -he told inimitably. Then he handed me a yellow-backed novel, and -moving my chair a little sideways, that my own shadow might not -fall upon the page, he begged me to read aloud to him. I read for -about ten minutes, beginning in the heart of a chapter, and then -suddenly, in the middle of a sentence, he ordered me to cease and -to change my dress. - -"You can easily imagine, Mr. Holmes, how curious I became as to -what the meaning of this extraordinary performance could possibly -be. They were always very careful, I observed, to turn my face -away from the window, so that I became consumed with the desire -to see what was going on behind my back. At first it seemed to be -impossible, but I soon devised a means. My hand-mirror had been -broken, so a happy thought seized me, and I concealed a piece of -the glass in my handkerchief. On the next occasion, in the midst -of my laughter, I put my handkerchief up to my eyes, and was able -with a little management to see all that there was behind me. I -confess that I was disappointed. There was nothing. At least that -was my first impression. At the second glance, however, I -perceived that there was a man standing in the Southampton Road, -a small bearded man in a grey suit, who seemed to be looking in -my direction. The road is an important highway, and there are -usually people there. This man, however, was leaning against the -railings which bordered our field and was looking earnestly up. I -lowered my handkerchief and glanced at Mrs. Rucastle to find her -eyes fixed upon me with a most searching gaze. She said nothing, -but I am convinced that she had divined that I had a mirror in my -hand and had seen what was behind me. She rose at once. - -"'Jephro,' said she, 'there is an impertinent fellow upon the -road there who stares up at Miss Hunter.' - -"'No friend of yours, Miss Hunter?' he asked. - -"'No, I know no one in these parts.' - -"'Dear me! How very impertinent! Kindly turn round and motion to -him to go away.' - -"'Surely it would be better to take no notice.' - -"'No, no, we should have him loitering here always. Kindly turn -round and wave him away like that.' - -"I did as I was told, and at the same instant Mrs. Rucastle drew -down the blind. That was a week ago, and from that time I have -not sat again in the window, nor have I worn the blue dress, nor -seen the man in the road." - -"Pray continue," said Holmes. "Your narrative promises to be a -most interesting one." - -"You will find it rather disconnected, I fear, and there may -prove to be little relation between the different incidents of -which I speak. On the very first day that I was at the Copper -Beeches, Mr. Rucastle took me to a small outhouse which stands -near the kitchen door. As we approached it I heard the sharp -rattling of a chain, and the sound as of a large animal moving -about. - -"'Look in here!' said Mr. Rucastle, showing me a slit between two -planks. 'Is he not a beauty?' - -"I looked through and was conscious of two glowing eyes, and of a -vague figure huddled up in the darkness. - -"'Don't be frightened,' said my employer, laughing at the start -which I had given. 'It's only Carlo, my mastiff. I call him mine, -but really old Toller, my groom, is the only man who can do -anything with him. We feed him once a day, and not too much then, -so that he is always as keen as mustard. Toller lets him loose -every night, and God help the trespasser whom he lays his fangs -upon. For goodness' sake don't you ever on any pretext set your -foot over the threshold at night, for it's as much as your life -is worth.' - -"The warning was no idle one, for two nights later I happened to -look out of my bedroom window about two o'clock in the morning. -It was a beautiful moonlight night, and the lawn in front of the -house was silvered over and almost as bright as day. I was -standing, rapt in the peaceful beauty of the scene, when I was -aware that something was moving under the shadow of the copper -beeches. As it emerged into the moonshine I saw what it was. It -was a giant dog, as large as a calf, tawny tinted, with hanging -jowl, black muzzle, and huge projecting bones. It walked slowly -across the lawn and vanished into the shadow upon the other side. -That dreadful sentinel sent a chill to my heart which I do not -think that any burglar could have done. - -"And now I have a very strange experience to tell you. I had, as -you know, cut off my hair in London, and I had placed it in a -great coil at the bottom of my trunk. One evening, after the -child was in bed, I began to amuse myself by examining the -furniture of my room and by rearranging my own little things. -There was an old chest of drawers in the room, the two upper ones -empty and open, the lower one locked. I had filled the first two -with my linen, and as I had still much to pack away I was -naturally annoyed at not having the use of the third drawer. It -struck me that it might have been fastened by a mere oversight, -so I took out my bunch of keys and tried to open it. The very -first key fitted to perfection, and I drew the drawer open. There -was only one thing in it, but I am sure that you would never -guess what it was. It was my coil of hair. - -"I took it up and examined it. It was of the same peculiar tint, -and the same thickness. But then the impossibility of the thing -obtruded itself upon me. How could my hair have been locked in -the drawer? With trembling hands I undid my trunk, turned out the -contents, and drew from the bottom my own hair. I laid the two -tresses together, and I assure you that they were identical. Was -it not extraordinary? Puzzle as I would, I could make nothing at -all of what it meant. I returned the strange hair to the drawer, -and I said nothing of the matter to the Rucastles as I felt that -I had put myself in the wrong by opening a drawer which they had -locked. - -"I am naturally observant, as you may have remarked, Mr. Holmes, -and I soon had a pretty good plan of the whole house in my head. -There was one wing, however, which appeared not to be inhabited -at all. A door which faced that which led into the quarters of -the Tollers opened into this suite, but it was invariably locked. -One day, however, as I ascended the stair, I met Mr. Rucastle -coming out through this door, his keys in his hand, and a look on -his face which made him a very different person to the round, -jovial man to whom I was accustomed. His cheeks were red, his -brow was all crinkled with anger, and the veins stood out at his -temples with passion. He locked the door and hurried past me -without a word or a look. - -"This aroused my curiosity, so when I went out for a walk in the -grounds with my charge, I strolled round to the side from which I -could see the windows of this part of the house. There were four -of them in a row, three of which were simply dirty, while the -fourth was shuttered up. They were evidently all deserted. As I -strolled up and down, glancing at them occasionally, Mr. Rucastle -came out to me, looking as merry and jovial as ever. - -"'Ah!' said he, 'you must not think me rude if I passed you -without a word, my dear young lady. I was preoccupied with -business matters.' - -"I assured him that I was not offended. 'By the way,' said I, -'you seem to have quite a suite of spare rooms up there, and one -of them has the shutters up.' - -"He looked surprised and, as it seemed to me, a little startled -at my remark. - -"'Photography is one of my hobbies,' said he. 'I have made my -dark room up there. But, dear me! what an observant young lady we -have come upon. Who would have believed it? Who would have ever -believed it?' He spoke in a jesting tone, but there was no jest -in his eyes as he looked at me. I read suspicion there and -annoyance, but no jest. - -"Well, Mr. Holmes, from the moment that I understood that there -was something about that suite of rooms which I was not to know, -I was all on fire to go over them. It was not mere curiosity, -though I have my share of that. It was more a feeling of duty--a -feeling that some good might come from my penetrating to this -place. They talk of woman's instinct; perhaps it was woman's -instinct which gave me that feeling. At any rate, it was there, -and I was keenly on the lookout for any chance to pass the -forbidden door. - -"It was only yesterday that the chance came. I may tell you that, -besides Mr. Rucastle, both Toller and his wife find something to -do in these deserted rooms, and I once saw him carrying a large -black linen bag with him through the door. Recently he has been -drinking hard, and yesterday evening he was very drunk; and when -I came upstairs there was the key in the door. I have no doubt at -all that he had left it there. Mr. and Mrs. Rucastle were both -downstairs, and the child was with them, so that I had an -admirable opportunity. I turned the key gently in the lock, -opened the door, and slipped through. - -"There was a little passage in front of me, unpapered and -uncarpeted, which turned at a right angle at the farther end. -Round this corner were three doors in a line, the first and third -of which were open. They each led into an empty room, dusty and -cheerless, with two windows in the one and one in the other, so -thick with dirt that the evening light glimmered dimly through -them. The centre door was closed, and across the outside of it -had been fastened one of the broad bars of an iron bed, padlocked -at one end to a ring in the wall, and fastened at the other with -stout cord. The door itself was locked as well, and the key was -not there. This barricaded door corresponded clearly with the -shuttered window outside, and yet I could see by the glimmer from -beneath it that the room was not in darkness. Evidently there was -a skylight which let in light from above. As I stood in the -passage gazing at the sinister door and wondering what secret it -might veil, I suddenly heard the sound of steps within the room -and saw a shadow pass backward and forward against the little -slit of dim light which shone out from under the door. A mad, -unreasoning terror rose up in me at the sight, Mr. Holmes. My -overstrung nerves failed me suddenly, and I turned and ran--ran -as though some dreadful hand were behind me clutching at the -skirt of my dress. I rushed down the passage, through the door, -and straight into the arms of Mr. Rucastle, who was waiting -outside. - -"'So,' said he, smiling, 'it was you, then. I thought that it -must be when I saw the door open.' - -"'Oh, I am so frightened!' I panted. - -"'My dear young lady! my dear young lady!'--you cannot think how -caressing and soothing his manner was--'and what has frightened -you, my dear young lady?' - -"But his voice was just a little too coaxing. He overdid it. I -was keenly on my guard against him. - -"'I was foolish enough to go into the empty wing,' I answered. -'But it is so lonely and eerie in this dim light that I was -frightened and ran out again. Oh, it is so dreadfully still in -there!' - -"'Only that?' said he, looking at me keenly. - -"'Why, what did you think?' I asked. - -"'Why do you think that I lock this door?' - -"'I am sure that I do not know.' - -"'It is to keep people out who have no business there. Do you -see?' He was still smiling in the most amiable manner. - -"'I am sure if I had known--' - -"'Well, then, you know now. And if you ever put your foot over -that threshold again'--here in an instant the smile hardened into -a grin of rage, and he glared down at me with the face of a -demon--'I'll throw you to the mastiff.' - -"I was so terrified that I do not know what I did. I suppose that -I must have rushed past him into my room. I remember nothing -until I found myself lying on my bed trembling all over. Then I -thought of you, Mr. Holmes. I could not live there longer without -some advice. I was frightened of the house, of the man, of the -woman, of the servants, even of the child. They were all horrible -to me. If I could only bring you down all would be well. Of -course I might have fled from the house, but my curiosity was -almost as strong as my fears. My mind was soon made up. I would -send you a wire. I put on my hat and cloak, went down to the -office, which is about half a mile from the house, and then -returned, feeling very much easier. A horrible doubt came into my -mind as I approached the door lest the dog might be loose, but I -remembered that Toller had drunk himself into a state of -insensibility that evening, and I knew that he was the only one -in the household who had any influence with the savage creature, -or who would venture to set him free. I slipped in in safety and -lay awake half the night in my joy at the thought of seeing you. -I had no difficulty in getting leave to come into Winchester this -morning, but I must be back before three o'clock, for Mr. and -Mrs. Rucastle are going on a visit, and will be away all the -evening, so that I must look after the child. Now I have told you -all my adventures, Mr. Holmes, and I should be very glad if you -could tell me what it all means, and, above all, what I should -do." - -Holmes and I had listened spellbound to this extraordinary story. -My friend rose now and paced up and down the room, his hands in -his pockets, and an expression of the most profound gravity upon -his face. - -"Is Toller still drunk?" he asked. - -"Yes. I heard his wife tell Mrs. Rucastle that she could do -nothing with him." - -"That is well. And the Rucastles go out to-night?" - -"Yes." - -"Is there a cellar with a good strong lock?" - -"Yes, the wine-cellar." - -"You seem to me to have acted all through this matter like a very -brave and sensible girl, Miss Hunter. Do you think that you could -perform one more feat? I should not ask it of you if I did not -think you a quite exceptional woman." - -"I will try. What is it?" - -"We shall be at the Copper Beeches by seven o'clock, my friend -and I. The Rucastles will be gone by that time, and Toller will, -we hope, be incapable. There only remains Mrs. Toller, who might -give the alarm. If you could send her into the cellar on some -errand, and then turn the key upon her, you would facilitate -matters immensely." - -"I will do it." - -"Excellent! We shall then look thoroughly into the affair. Of -course there is only one feasible explanation. You have been -brought there to personate someone, and the real person is -imprisoned in this chamber. That is obvious. As to who this -prisoner is, I have no doubt that it is the daughter, Miss Alice -Rucastle, if I remember right, who was said to have gone to -America. You were chosen, doubtless, as resembling her in height, -figure, and the colour of your hair. Hers had been cut off, very -possibly in some illness through which she has passed, and so, of -course, yours had to be sacrificed also. By a curious chance you -came upon her tresses. The man in the road was undoubtedly some -friend of hers--possibly her fiancé--and no doubt, as you wore -the girl's dress and were so like her, he was convinced from your -laughter, whenever he saw you, and afterwards from your gesture, -that Miss Rucastle was perfectly happy, and that she no longer -desired his attentions. The dog is let loose at night to prevent -him from endeavouring to communicate with her. So much is fairly -clear. The most serious point in the case is the disposition of -the child." - -"What on earth has that to do with it?" I ejaculated. - -"My dear Watson, you as a medical man are continually gaining -light as to the tendencies of a child by the study of the -parents. Don't you see that the converse is equally valid. I have -frequently gained my first real insight into the character of -parents by studying their children. This child's disposition is -abnormally cruel, merely for cruelty's sake, and whether he -derives this from his smiling father, as I should suspect, or -from his mother, it bodes evil for the poor girl who is in their -power." - -"I am sure that you are right, Mr. Holmes," cried our client. "A -thousand things come back to me which make me certain that you -have hit it. Oh, let us lose not an instant in bringing help to -this poor creature." - -"We must be circumspect, for we are dealing with a very cunning -man. We can do nothing until seven o'clock. At that hour we shall -be with you, and it will not be long before we solve the -mystery." - -We were as good as our word, for it was just seven when we -reached the Copper Beeches, having put up our trap at a wayside -public-house. The group of trees, with their dark leaves shining -like burnished metal in the light of the setting sun, were -sufficient to mark the house even had Miss Hunter not been -standing smiling on the door-step. - -"Have you managed it?" asked Holmes. - -A loud thudding noise came from somewhere downstairs. "That is -Mrs. Toller in the cellar," said she. "Her husband lies snoring -on the kitchen rug. Here are his keys, which are the duplicates -of Mr. Rucastle's." - -"You have done well indeed!" cried Holmes with enthusiasm. "Now -lead the way, and we shall soon see the end of this black -business." - -We passed up the stair, unlocked the door, followed on down a -passage, and found ourselves in front of the barricade which Miss -Hunter had described. Holmes cut the cord and removed the -transverse bar. Then he tried the various keys in the lock, but -without success. No sound came from within, and at the silence -Holmes' face clouded over. - -"I trust that we are not too late," said he. "I think, Miss -Hunter, that we had better go in without you. Now, Watson, put -your shoulder to it, and we shall see whether we cannot make our -way in." - -It was an old rickety door and gave at once before our united -strength. Together we rushed into the room. It was empty. There -was no furniture save a little pallet bed, a small table, and a -basketful of linen. The skylight above was open, and the prisoner -gone. - -"There has been some villainy here," said Holmes; "this beauty -has guessed Miss Hunter's intentions and has carried his victim -off." - -"But how?" - -"Through the skylight. We shall soon see how he managed it." He -swung himself up onto the roof. "Ah, yes," he cried, "here's the -end of a long light ladder against the eaves. That is how he did -it." - -"But it is impossible," said Miss Hunter; "the ladder was not -there when the Rucastles went away." - -"He has come back and done it. I tell you that he is a clever and -dangerous man. I should not be very much surprised if this were -he whose step I hear now upon the stair. I think, Watson, that it -would be as well for you to have your pistol ready." - -The words were hardly out of his mouth before a man appeared at -the door of the room, a very fat and burly man, with a heavy -stick in his hand. Miss Hunter screamed and shrunk against the -wall at the sight of him, but Sherlock Holmes sprang forward and -confronted him. - -"You villain!" said he, "where's your daughter?" - -The fat man cast his eyes round, and then up at the open -skylight. - -"It is for me to ask you that," he shrieked, "you thieves! Spies -and thieves! I have caught you, have I? You are in my power. I'll -serve you!" He turned and clattered down the stairs as hard as he -could go. - -"He's gone for the dog!" cried Miss Hunter. - -"I have my revolver," said I. - -"Better close the front door," cried Holmes, and we all rushed -down the stairs together. We had hardly reached the hall when we -heard the baying of a hound, and then a scream of agony, with a -horrible worrying sound which it was dreadful to listen to. An -elderly man with a red face and shaking limbs came staggering out -at a side door. - -"My God!" he cried. "Someone has loosed the dog. It's not been -fed for two days. Quick, quick, or it'll be too late!" - -Holmes and I rushed out and round the angle of the house, with -Toller hurrying behind us. There was the huge famished brute, its -black muzzle buried in Rucastle's throat, while he writhed and -screamed upon the ground. Running up, I blew its brains out, and -it fell over with its keen white teeth still meeting in the great -creases of his neck. With much labour we separated them and -carried him, living but horribly mangled, into the house. We laid -him upon the drawing-room sofa, and having dispatched the sobered -Toller to bear the news to his wife, I did what I could to -relieve his pain. We were all assembled round him when the door -opened, and a tall, gaunt woman entered the room. - -"Mrs. Toller!" cried Miss Hunter. - -"Yes, miss. Mr. Rucastle let me out when he came back before he -went up to you. Ah, miss, it is a pity you didn't let me know -what you were planning, for I would have told you that your pains -were wasted." - -"Ha!" said Holmes, looking keenly at her. "It is clear that Mrs. -Toller knows more about this matter than anyone else." - -"Yes, sir, I do, and I am ready enough to tell what I know." - -"Then, pray, sit down, and let us hear it for there are several -points on which I must confess that I am still in the dark." - -"I will soon make it clear to you," said she; "and I'd have done -so before now if I could ha' got out from the cellar. If there's -police-court business over this, you'll remember that I was the -one that stood your friend, and that I was Miss Alice's friend -too. - -"She was never happy at home, Miss Alice wasn't, from the time -that her father married again. She was slighted like and had no -say in anything, but it never really became bad for her until -after she met Mr. Fowler at a friend's house. As well as I could -learn, Miss Alice had rights of her own by will, but she was so -quiet and patient, she was, that she never said a word about them -but just left everything in Mr. Rucastle's hands. He knew he was -safe with her; but when there was a chance of a husband coming -forward, who would ask for all that the law would give him, then -her father thought it time to put a stop on it. He wanted her to -sign a paper, so that whether she married or not, he could use -her money. When she wouldn't do it, he kept on worrying her until -she got brain-fever, and for six weeks was at death's door. Then -she got better at last, all worn to a shadow, and with her -beautiful hair cut off; but that didn't make no change in her -young man, and he stuck to her as true as man could be." - -"Ah," said Holmes, "I think that what you have been good enough -to tell us makes the matter fairly clear, and that I can deduce -all that remains. Mr. Rucastle then, I presume, took to this -system of imprisonment?" - -"Yes, sir." - -"And brought Miss Hunter down from London in order to get rid of -the disagreeable persistence of Mr. Fowler." - -"That was it, sir." - -"But Mr. Fowler being a persevering man, as a good seaman should -be, blockaded the house, and having met you succeeded by certain -arguments, metallic or otherwise, in convincing you that your -interests were the same as his." - -"Mr. Fowler was a very kind-spoken, free-handed gentleman," said -Mrs. Toller serenely. - -"And in this way he managed that your good man should have no -want of drink, and that a ladder should be ready at the moment -when your master had gone out." - -"You have it, sir, just as it happened." - -"I am sure we owe you an apology, Mrs. Toller," said Holmes, "for -you have certainly cleared up everything which puzzled us. And -here comes the country surgeon and Mrs. Rucastle, so I think, -Watson, that we had best escort Miss Hunter back to Winchester, -as it seems to me that our locus standi now is rather a -questionable one." - -And thus was solved the mystery of the sinister house with the -copper beeches in front of the door. Mr. Rucastle survived, but -was always a broken man, kept alive solely through the care of -his devoted wife. They still live with their old servants, who -probably know so much of Rucastle's past life that he finds it -difficult to part from them. Mr. Fowler and Miss Rucastle were -married, by special license, in Southampton the day after their -flight, and he is now the holder of a government appointment in -the island of Mauritius. As to Miss Violet Hunter, my friend -Holmes, rather to my disappointment, manifested no further -interest in her when once she had ceased to be the centre of one -of his problems, and she is now the head of a private school at -Walsall, where I believe that she has met with considerable success. - - - - - - - - - -End of the Project Gutenberg EBook of The Adventures of Sherlock Holmes, by -Arthur Conan Doyle - -*** END OF THIS PROJECT GUTENBERG EBOOK THE ADVENTURES OF SHERLOCK HOLMES *** - -***** This file should be named 1661-8.txt or 1661-8.zip ***** -This and all associated files of various formats will be found in: - http://www.gutenberg.org/1/6/6/1661/ - -Produced by an anonymous Project Gutenberg volunteer and Jose Menendez - -Updated editions will replace the previous one--the old editions -will be renamed. - -Creating the works from public domain print editions means that no -one owns a United States copyright in these works, so the Foundation -(and you!) can copy and distribute it in the United States without -permission and without paying copyright royalties. Special rules, -set forth in the General Terms of Use part of this license, apply to -copying and distributing Project Gutenberg-tm electronic works to -protect the PROJECT GUTENBERG-tm concept and trademark. Project -Gutenberg is a registered trademark, and may not be used if you -charge for the eBooks, unless you receive specific permission. If you -do not charge anything for copies of this eBook, complying with the -rules is very easy. You may use this eBook for nearly any purpose -such as creation of derivative works, reports, performances and -research. They may be modified and printed and given away--you may do -practically ANYTHING with public domain eBooks. Redistribution is -subject to the trademark license, especially commercial -redistribution. - - - -*** START: FULL LICENSE *** - -THE FULL PROJECT GUTENBERG LICENSE -PLEASE READ THIS BEFORE YOU DISTRIBUTE OR USE THIS WORK - -To protect the Project Gutenberg-tm mission of promoting the free -distribution of electronic works, by using or distributing this work -(or any other work associated in any way with the phrase "Project -Gutenberg"), you agree to comply with all the terms of the Full Project -Gutenberg-tm License (available with this file or online at -http://gutenberg.net/license). - - -Section 1. General Terms of Use and Redistributing Project Gutenberg-tm -electronic works - -1.A. By reading or using any part of this Project Gutenberg-tm -electronic work, you indicate that you have read, understand, agree to -and accept all the terms of this license and intellectual property -(trademark/copyright) agreement. If you do not agree to abide by all -the terms of this agreement, you must cease using and return or destroy -all copies of Project Gutenberg-tm electronic works in your possession. -If you paid a fee for obtaining a copy of or access to a Project -Gutenberg-tm electronic work and you do not agree to be bound by the -terms of this agreement, you may obtain a refund from the person or -entity to whom you paid the fee as set forth in paragraph 1.E.8. - -1.B. "Project Gutenberg" is a registered trademark. It may only be -used on or associated in any way with an electronic work by people who -agree to be bound by the terms of this agreement. There are a few -things that you can do with most Project Gutenberg-tm electronic works -even without complying with the full terms of this agreement. See -paragraph 1.C below. There are a lot of things you can do with Project -Gutenberg-tm electronic works if you follow the terms of this agreement -and help preserve free future access to Project Gutenberg-tm electronic -works. See paragraph 1.E below. - -1.C. The Project Gutenberg Literary Archive Foundation ("the Foundation" -or PGLAF), owns a compilation copyright in the collection of Project -Gutenberg-tm electronic works. Nearly all the individual works in the -collection are in the public domain in the United States. If an -individual work is in the public domain in the United States and you are -located in the United States, we do not claim a right to prevent you from -copying, distributing, performing, displaying or creating derivative -works based on the work as long as all references to Project Gutenberg -are removed. Of course, we hope that you will support the Project -Gutenberg-tm mission of promoting free access to electronic works by -freely sharing Project Gutenberg-tm works in compliance with the terms of -this agreement for keeping the Project Gutenberg-tm name associated with -the work. You can easily comply with the terms of this agreement by -keeping this work in the same format with its attached full Project -Gutenberg-tm License when you share it without charge with others. - -1.D. The copyright laws of the place where you are located also govern -what you can do with this work. Copyright laws in most countries are in -a constant state of change. If you are outside the United States, check -the laws of your country in addition to the terms of this agreement -before downloading, copying, displaying, performing, distributing or -creating derivative works based on this work or any other Project -Gutenberg-tm work. The Foundation makes no representations concerning -the copyright status of any work in any country outside the United -States. - -1.E. Unless you have removed all references to Project Gutenberg: - -1.E.1. The following sentence, with active links to, or other immediate -access to, the full Project Gutenberg-tm License must appear prominently -whenever any copy of a Project Gutenberg-tm work (any work on which the -phrase "Project Gutenberg" appears, or with which the phrase "Project -Gutenberg" is associated) is accessed, displayed, performed, viewed, -copied or distributed: - -This eBook is for the use of anyone anywhere at no cost and with -almost no restrictions whatsoever. You may copy it, give it away or -re-use it under the terms of the Project Gutenberg License included -with this eBook or online at www.gutenberg.net - -1.E.2. If an individual Project Gutenberg-tm electronic work is derived -from the public domain (does not contain a notice indicating that it is -posted with permission of the copyright holder), the work can be copied -and distributed to anyone in the United States without paying any fees -or charges. If you are redistributing or providing access to a work -with the phrase "Project Gutenberg" associated with or appearing on the -work, you must comply either with the requirements of paragraphs 1.E.1 -through 1.E.7 or obtain permission for the use of the work and the -Project Gutenberg-tm trademark as set forth in paragraphs 1.E.8 or -1.E.9. - -1.E.3. If an individual Project Gutenberg-tm electronic work is posted -with the permission of the copyright holder, your use and distribution -must comply with both paragraphs 1.E.1 through 1.E.7 and any additional -terms imposed by the copyright holder. Additional terms will be linked -to the Project Gutenberg-tm License for all works posted with the -permission of the copyright holder found at the beginning of this work. - -1.E.4. Do not unlink or detach or remove the full Project Gutenberg-tm -License terms from this work, or any files containing a part of this -work or any other work associated with Project Gutenberg-tm. - -1.E.5. Do not copy, display, perform, distribute or redistribute this -electronic work, or any part of this electronic work, without -prominently displaying the sentence set forth in paragraph 1.E.1 with -active links or immediate access to the full terms of the Project -Gutenberg-tm License. - -1.E.6. You may convert to and distribute this work in any binary, -compressed, marked up, nonproprietary or proprietary form, including any -word processing or hypertext form. However, if you provide access to or -distribute copies of a Project Gutenberg-tm work in a format other than -"Plain Vanilla ASCII" or other format used in the official version -posted on the official Project Gutenberg-tm web site (www.gutenberg.net), -you must, at no additional cost, fee or expense to the user, provide a -copy, a means of exporting a copy, or a means of obtaining a copy upon -request, of the work in its original "Plain Vanilla ASCII" or other -form. Any alternate format must include the full Project Gutenberg-tm -License as specified in paragraph 1.E.1. - -1.E.7. Do not charge a fee for access to, viewing, displaying, -performing, copying or distributing any Project Gutenberg-tm works -unless you comply with paragraph 1.E.8 or 1.E.9. - -1.E.8. You may charge a reasonable fee for copies of or providing -access to or distributing Project Gutenberg-tm electronic works provided -that - -- You pay a royalty fee of 20% of the gross profits you derive from - the use of Project Gutenberg-tm works calculated using the method - you already use to calculate your applicable taxes. The fee is - owed to the owner of the Project Gutenberg-tm trademark, but he - has agreed to donate royalties under this paragraph to the - Project Gutenberg Literary Archive Foundation. Royalty payments - must be paid within 60 days following each date on which you - prepare (or are legally required to prepare) your periodic tax - returns. Royalty payments should be clearly marked as such and - sent to the Project Gutenberg Literary Archive Foundation at the - address specified in Section 4, "Information about donations to - the Project Gutenberg Literary Archive Foundation." - -- You provide a full refund of any money paid by a user who notifies - you in writing (or by e-mail) within 30 days of receipt that s/he - does not agree to the terms of the full Project Gutenberg-tm - License. You must require such a user to return or - destroy all copies of the works possessed in a physical medium - and discontinue all use of and all access to other copies of - Project Gutenberg-tm works. - -- You provide, in accordance with paragraph 1.F.3, a full refund of any - money paid for a work or a replacement copy, if a defect in the - electronic work is discovered and reported to you within 90 days - of receipt of the work. - -- You comply with all other terms of this agreement for free - distribution of Project Gutenberg-tm works. - -1.E.9. If you wish to charge a fee or distribute a Project Gutenberg-tm -electronic work or group of works on different terms than are set -forth in this agreement, you must obtain permission in writing from -both the Project Gutenberg Literary Archive Foundation and Michael -Hart, the owner of the Project Gutenberg-tm trademark. Contact the -Foundation as set forth in Section 3 below. - -1.F. - -1.F.1. Project Gutenberg volunteers and employees expend considerable -effort to identify, do copyright research on, transcribe and proofread -public domain works in creating the Project Gutenberg-tm -collection. Despite these efforts, Project Gutenberg-tm electronic -works, and the medium on which they may be stored, may contain -"Defects," such as, but not limited to, incomplete, inaccurate or -corrupt data, transcription errors, a copyright or other intellectual -property infringement, a defective or damaged disk or other medium, a -computer virus, or computer codes that damage or cannot be read by -your equipment. - -1.F.2. LIMITED WARRANTY, DISCLAIMER OF DAMAGES - Except for the "Right -of Replacement or Refund" described in paragraph 1.F.3, the Project -Gutenberg Literary Archive Foundation, the owner of the Project -Gutenberg-tm trademark, and any other party distributing a Project -Gutenberg-tm electronic work under this agreement, disclaim all -liability to you for damages, costs and expenses, including legal -fees. YOU AGREE THAT YOU HAVE NO REMEDIES FOR NEGLIGENCE, STRICT -LIABILITY, BREACH OF WARRANTY OR BREACH OF CONTRACT EXCEPT THOSE -PROVIDED IN PARAGRAPH 1.F.3. YOU AGREE THAT THE FOUNDATION, THE -TRADEMARK OWNER, AND ANY DISTRIBUTOR UNDER THIS AGREEMENT WILL NOT BE -LIABLE TO YOU FOR ACTUAL, DIRECT, INDIRECT, CONSEQUENTIAL, PUNITIVE OR -INCIDENTAL DAMAGES EVEN IF YOU GIVE NOTICE OF THE POSSIBILITY OF SUCH -DAMAGE. - -1.F.3. LIMITED RIGHT OF REPLACEMENT OR REFUND - If you discover a -defect in this electronic work within 90 days of receiving it, you can -receive a refund of the money (if any) you paid for it by sending a -written explanation to the person you received the work from. If you -received the work on a physical medium, you must return the medium with -your written explanation. The person or entity that provided you with -the defective work may elect to provide a replacement copy in lieu of a -refund. If you received the work electronically, the person or entity -providing it to you may choose to give you a second opportunity to -receive the work electronically in lieu of a refund. If the second copy -is also defective, you may demand a refund in writing without further -opportunities to fix the problem. - -1.F.4. Except for the limited right of replacement or refund set forth -in paragraph 1.F.3, this work is provided to you 'AS-IS' WITH NO OTHER -WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -WARRANTIES OF MERCHANTIBILITY OR FITNESS FOR ANY PURPOSE. - -1.F.5. Some states do not allow disclaimers of certain implied -warranties or the exclusion or limitation of certain types of damages. -If any disclaimer or limitation set forth in this agreement violates the -law of the state applicable to this agreement, the agreement shall be -interpreted to make the maximum disclaimer or limitation permitted by -the applicable state law. The invalidity or unenforceability of any -provision of this agreement shall not void the remaining provisions. - -1.F.6. INDEMNITY - You agree to indemnify and hold the Foundation, the -trademark owner, any agent or employee of the Foundation, anyone -providing copies of Project Gutenberg-tm electronic works in accordance -with this agreement, and any volunteers associated with the production, -promotion and distribution of Project Gutenberg-tm electronic works, -harmless from all liability, costs and expenses, including legal fees, -that arise directly or indirectly from any of the following which you do -or cause to occur: (a) distribution of this or any Project Gutenberg-tm -work, (b) alteration, modification, or additions or deletions to any -Project Gutenberg-tm work, and (c) any Defect you cause. - - -Section 2. Information about the Mission of Project Gutenberg-tm - -Project Gutenberg-tm is synonymous with the free distribution of -electronic works in formats readable by the widest variety of computers -including obsolete, old, middle-aged and new computers. It exists -because of the efforts of hundreds of volunteers and donations from -people in all walks of life. - -Volunteers and financial support to provide volunteers with the -assistance they need are critical to reaching Project Gutenberg-tm's -goals and ensuring that the Project Gutenberg-tm collection will -remain freely available for generations to come. In 2001, the Project -Gutenberg Literary Archive Foundation was created to provide a secure -and permanent future for Project Gutenberg-tm and future generations. -To learn more about the Project Gutenberg Literary Archive Foundation -and how your efforts and donations can help, see Sections 3 and 4 -and the Foundation web page at http://www.pglaf.org. - - -Section 3. Information about the Project Gutenberg Literary Archive -Foundation - -The Project Gutenberg Literary Archive Foundation is a non profit -501(c)(3) educational corporation organized under the laws of the -state of Mississippi and granted tax exempt status by the Internal -Revenue Service. The Foundation's EIN or federal tax identification -number is 64-6221541. Its 501(c)(3) letter is posted at -http://pglaf.org/fundraising. Contributions to the Project Gutenberg -Literary Archive Foundation are tax deductible to the full extent -permitted by U.S. federal laws and your state's laws. - -The Foundation's principal office is located at 4557 Melan Dr. S. -Fairbanks, AK, 99712., but its volunteers and employees are scattered -throughout numerous locations. Its business office is located at -809 North 1500 West, Salt Lake City, UT 84116, (801) 596-1887, email -business@pglaf.org. Email contact links and up to date contact -information can be found at the Foundation's web site and official -page at http://pglaf.org - -For additional contact information: - Dr. Gregory B. Newby - Chief Executive and Director - gbnewby@pglaf.org - - -Section 4. Information about Donations to the Project Gutenberg -Literary Archive Foundation - -Project Gutenberg-tm depends upon and cannot survive without wide -spread public support and donations to carry out its mission of -increasing the number of public domain and licensed works that can be -freely distributed in machine readable form accessible by the widest -array of equipment including outdated equipment. Many small donations -($1 to $5,000) are particularly important to maintaining tax exempt -status with the IRS. - -The Foundation is committed to complying with the laws regulating -charities and charitable donations in all 50 states of the United -States. Compliance requirements are not uniform and it takes a -considerable effort, much paperwork and many fees to meet and keep up -with these requirements. We do not solicit donations in locations -where we have not received written confirmation of compliance. To -SEND DONATIONS or determine the status of compliance for any -particular state visit http://pglaf.org - -While we cannot and do not solicit contributions from states where we -have not met the solicitation requirements, we know of no prohibition -against accepting unsolicited donations from donors in such states who -approach us with offers to donate. - -International donations are gratefully accepted, but we cannot make -any statements concerning tax treatment of donations received from -outside the United States. U.S. laws alone swamp our small staff. - -Please check the Project Gutenberg Web pages for current donation -methods and addresses. Donations are accepted in a number of other -ways including including checks, online payments and credit card -donations. To donate, please visit: http://pglaf.org/donate - - -Section 5. General Information About Project Gutenberg-tm electronic -works. - -Professor Michael S. Hart is the originator of the Project Gutenberg-tm -concept of a library of electronic works that could be freely shared -with anyone. For thirty years, he produced and distributed Project -Gutenberg-tm eBooks with only a loose network of volunteer support. - - -Project Gutenberg-tm eBooks are often created from several printed -editions, all of which are confirmed as Public Domain in the U.S. -unless a copyright notice is included. Thus, we do not necessarily -keep eBooks in compliance with any particular paper edition. - - -Most people start at our Web site which has the main PG search facility: - - http://www.gutenberg.net - -This Web site includes information about Project Gutenberg-tm, -including how to make donations to the Project Gutenberg Literary -Archive Foundation, how to help produce our new eBooks, and how to -subscribe to our email newsletter to hear about new eBooks. diff --git a/grep/src/lib.rs b/grep/src/lib.rs deleted file mode 100644 index 023cd64..0000000 --- a/grep/src/lib.rs +++ /dev/null @@ -1,84 +0,0 @@ -#![deny(missing_docs)] - -/*! -A fast line oriented regex searcher. -*/ - -#[macro_use] -extern crate log; -extern crate memchr; -extern crate regex; -extern crate regex_syntax as syntax; - -use std::error; -use std::fmt; -use std::result; - -pub use search::{Grep, GrepBuilder, Iter, Match}; - -mod literals; -mod nonl; -mod search; -mod smart_case; -mod word_boundary; - -/// Result is a convenient type alias that fixes the type of the error to -/// the `Error` type defined in this crate. -pub type Result = result::Result; - -/// Error enumerates the list of possible error conditions when building or -/// using a `Grep` line searcher. -#[derive(Debug)] -pub enum Error { - /// An error from parsing or compiling a regex. - Regex(regex::Error), - /// This error occurs when an illegal literal was found in the regex - /// pattern. For example, if the line terminator is `\n` and the regex - /// pattern is `\w+\n\w+`, then the presence of `\n` will cause this error. - LiteralNotAllowed(char), - /// An unused enum variant that indicates this enum may be expanded in - /// the future and therefore should not be exhaustively matched. - #[doc(hidden)] - __Nonexhaustive, -} - -impl error::Error for Error { - fn description(&self) -> &str { - match *self { - Error::Regex(ref err) => err.description(), - Error::LiteralNotAllowed(_) => "use of forbidden literal", - Error::__Nonexhaustive => unreachable!(), - } - } - - fn cause(&self) -> Option<&error::Error> { - match *self { - Error::Regex(ref err) => err.cause(), - _ => None, - } - } -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Error::Regex(ref err) => err.fmt(f), - Error::LiteralNotAllowed(chr) => { - write!(f, "Literal {:?} not allowed.", chr) - } - Error::__Nonexhaustive => unreachable!(), - } - } -} - -impl From for Error { - fn from(err: regex::Error) -> Error { - Error::Regex(err) - } -} - -impl From for Error { - fn from(err: syntax::Error) -> Error { - Error::Regex(regex::Error::Syntax(err.to_string())) - } -} diff --git a/grep/src/literals.rs b/grep/src/literals.rs deleted file mode 100644 index 3e1c385..0000000 --- a/grep/src/literals.rs +++ /dev/null @@ -1,264 +0,0 @@ -/*! -The literals module is responsible for extracting *inner* literals out of the -AST of a regular expression. Normally this is the job of the regex engine -itself, but 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. - -Note that this implementation is incredibly suspicious. We need something more -principled. -*/ -use std::cmp; - -use regex::bytes::RegexBuilder; -use syntax::hir::{self, Hir, HirKind}; -use syntax::hir::literal::{Literal, Literals}; - -#[derive(Clone, Debug)] -pub struct LiteralSets { - prefixes: Literals, - suffixes: Literals, - required: Literals, -} - -impl LiteralSets { - pub fn create(expr: &Hir) -> Self { - let mut required = Literals::empty(); - union_required(expr, &mut required); - LiteralSets { - prefixes: Literals::prefixes(expr), - suffixes: Literals::suffixes(expr), - required: required, - } - } - - pub fn to_regex_builder(&self) -> Option { - if self.prefixes.all_complete() && !self.prefixes.is_empty() { - debug!("literal prefixes detected: {:?}", self.prefixes); - // When this is true, the regex engine will do a literal scan. - return None; - } - - // Out of inner required literals, prefixes and suffixes, which one - // is the longest? We pick the longest to do fast literal scan under - // the assumption that a longer literal will have a lower false - // positive rate. - let pre_lcp = self.prefixes.longest_common_prefix(); - let pre_lcs = self.prefixes.longest_common_suffix(); - let suf_lcp = self.suffixes.longest_common_prefix(); - let suf_lcs = self.suffixes.longest_common_suffix(); - - let req_lits = self.required.literals(); - let req = match req_lits.iter().max_by_key(|lit| lit.len()) { - None => &[], - Some(req) => &***req, - }; - - let mut lit = pre_lcp; - if pre_lcs.len() > lit.len() { - lit = pre_lcs; - } - if suf_lcp.len() > lit.len() { - lit = suf_lcp; - } - if suf_lcs.len() > lit.len() { - lit = suf_lcs; - } - if req_lits.len() == 1 && req.len() > lit.len() { - lit = req; - } - - // Special case: if we detected an alternation of inner required - // literals and its longest literal is bigger than the longest - // prefix/suffix, then choose the alternation. In practice, this - // helps with case insensitive matching, which can generate lots of - // inner required literals. - let any_empty = req_lits.iter().any(|lit| lit.is_empty()); - if req.len() > lit.len() && req_lits.len() > 1 && !any_empty { - debug!("required literals found: {:?}", req_lits); - let alts: Vec = - req_lits.into_iter().map(|x| bytes_to_regex(x)).collect(); - let mut builder = RegexBuilder::new(&alts.join("|")); - builder.unicode(false); - Some(builder) - } else if lit.is_empty() { - None - } else { - debug!("required literal found: {:?}", show(lit)); - let mut builder = RegexBuilder::new(&bytes_to_regex(&lit)); - builder.unicode(false); - Some(builder) - } - } -} - -fn union_required(expr: &Hir, lits: &mut Literals) { - match *expr.kind() { - HirKind::Literal(hir::Literal::Unicode(c)) => { - let mut buf = [0u8; 4]; - lits.cross_add(c.encode_utf8(&mut buf).as_bytes()); - } - HirKind::Literal(hir::Literal::Byte(b)) => { - lits.cross_add(&[b]); - } - HirKind::Class(hir::Class::Unicode(ref cls)) => { - if count_unicode_class(cls) >= 5 || !lits.add_char_class(cls) { - lits.cut(); - } - } - HirKind::Class(hir::Class::Bytes(ref cls)) => { - if count_byte_class(cls) >= 5 || !lits.add_byte_class(cls) { - lits.cut(); - } - } - HirKind::Group(hir::Group { ref hir, .. }) => { - union_required(&**hir, lits); - } - HirKind::Repetition(ref x) => { - match x.kind { - hir::RepetitionKind::ZeroOrOne => lits.cut(), - hir::RepetitionKind::ZeroOrMore => lits.cut(), - 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); - } - } - } - HirKind::Concat(ref es) if es.is_empty() => {} - HirKind::Concat(ref es) if es.len() == 1 => { - union_required(&es[0], lits) - } - HirKind::Concat(ref es) => { - for e in es { - let mut lits2 = lits.to_empty(); - union_required(e, &mut lits2); - if lits2.is_empty() { - lits.cut(); - continue; - } - if lits2.contains_empty() { - lits.cut(); - } - if !lits.cross_product(&lits2) { - // If this expression couldn't yield any literal that - // could be extended, then we need to quit. Since we're - // short-circuiting, we also need to freeze every member. - lits.cut(); - break; - } - } - } - HirKind::Alternation(ref es) => { - alternate_literals(es, lits, union_required); - } - _ => lits.cut(), - } -} - -fn repeat_range_literals( - e: &Hir, - min: u32, - max: Option, - _greedy: bool, - lits: &mut Literals, - mut f: F, -) { - if min == 0 { - // This is a bit conservative. If `max` is set, then we could - // treat this as a finite set of alternations. For now, we - // just treat it as `e*`. - lits.cut(); - } else { - let n = cmp::min(lits.limit_size(), min as usize); - // We only extract literals from a single repetition, even though - // 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 - // across repetitions. e.g., extracting `foofoofoo` from `(\w+foo){3}` - // is wrong. - f(e, lits); - if n < min as usize { - lits.cut(); - } - if max.map_or(true, |max| min < max) { - lits.cut(); - } - } -} - -fn alternate_literals( - es: &[Hir], - lits: &mut Literals, - mut f: F, -) { - let mut lits2 = lits.to_empty(); - for e in es { - let mut lits3 = lits.to_empty(); - lits3.set_limit_size(lits.limit_size() / 5); - f(e, &mut lits3); - if lits3.is_empty() || !lits2.union(lits3) { - // If we couldn't find suffixes for *any* of the - // alternates, then the entire alternation has to be thrown - // away and any existing members must be frozen. Similarly, - // if the union couldn't complete, stop and freeze. - lits.cut(); - return; - } - } - // All we do at the moment is look for prefixes and suffixes. If both - // are empty, then we report nothing. We should be able to do better than - // this, but we'll need something more expressive than just a "set of - // literals." - let lcp = lits2.longest_common_prefix(); - let lcs = lits2.longest_common_suffix(); - if !lcp.is_empty() { - lits.cross_add(lcp); - } - lits.cut(); - if !lcs.is_empty() { - lits.add(Literal::empty()); - lits.add(Literal::new(lcs.to_vec())); - } -} - -/// Return the number of characters in the given class. -fn count_unicode_class(cls: &hir::ClassUnicode) -> u32 { - cls.iter().map(|r| 1 + (r.end() as u32 - r.start() as u32)).sum() -} - -/// Return the number of bytes in the given class. -fn count_byte_class(cls: &hir::ClassBytes) -> u32 { - cls.iter().map(|r| 1 + (r.end() as u32 - r.start() as u32)).sum() -} - -/// Converts an arbitrary sequence of bytes to a literal suitable for building -/// a regular expression. -fn bytes_to_regex(bs: &[u8]) -> String { - let mut s = String::with_capacity(bs.len()); - for &b in bs { - s.push_str(&format!("\\x{:02x}", b)); - } - s -} - -/// Converts arbitrary bytes to a nice string. -fn show(bs: &[u8]) -> String { - // Why aren't we using this to feed to the regex? Doesn't really matter - // I guess. ---AG - use std::ascii::escape_default; - use std::str; - - let mut nice = String::new(); - for &b in bs { - let part: Vec = escape_default(b).collect(); - nice.push_str(str::from_utf8(&part).unwrap()); - } - nice -} diff --git a/grep/src/nonl.rs b/grep/src/nonl.rs deleted file mode 100644 index 3beb5f6..0000000 --- a/grep/src/nonl.rs +++ /dev/null @@ -1,74 +0,0 @@ -use syntax::hir::{self, Hir, HirKind}; - -use {Error, Result}; - -/// Returns a new expression that is guaranteed to never match the given -/// ASCII character. -/// -/// If the expression contains the literal byte, then an error is returned. -/// -/// If `byte` is not an ASCII character (i.e., greater than `0x7F`), then this -/// function panics. -pub fn remove(expr: Hir, byte: u8) -> Result { - assert!(byte <= 0x7F); - let chr = byte as char; - assert!(chr.len_utf8() == 1); - - Ok(match expr.into_kind() { - HirKind::Empty => Hir::empty(), - HirKind::Literal(hir::Literal::Unicode(c)) => { - if c == chr { - return Err(Error::LiteralNotAllowed(chr)); - } - Hir::literal(hir::Literal::Unicode(c)) - } - HirKind::Literal(hir::Literal::Byte(b)) => { - if b as char == chr { - return Err(Error::LiteralNotAllowed(chr)); - } - Hir::literal(hir::Literal::Byte(b)) - } - HirKind::Class(hir::Class::Unicode(mut cls)) => { - let remove = hir::ClassUnicode::new(Some( - hir::ClassUnicodeRange::new(chr, chr), - )); - cls.difference(&remove); - if cls.iter().next().is_none() { - return Err(Error::LiteralNotAllowed(chr)); - } - Hir::class(hir::Class::Unicode(cls)) - } - HirKind::Class(hir::Class::Bytes(mut cls)) => { - let remove = hir::ClassBytes::new(Some( - hir::ClassBytesRange::new(byte, byte), - )); - cls.difference(&remove); - if cls.iter().next().is_none() { - return Err(Error::LiteralNotAllowed(chr)); - } - Hir::class(hir::Class::Bytes(cls)) - } - HirKind::Anchor(x) => Hir::anchor(x), - HirKind::WordBoundary(x) => Hir::word_boundary(x), - HirKind::Repetition(mut x) => { - x.hir = Box::new(remove(*x.hir, byte)?); - Hir::repetition(x) - } - HirKind::Group(mut x) => { - x.hir = Box::new(remove(*x.hir, byte)?); - Hir::group(x) - } - HirKind::Concat(xs) => { - let xs = xs.into_iter() - .map(|e| remove(e, byte)) - .collect::>>()?; - Hir::concat(xs) - } - HirKind::Alternation(xs) => { - let xs = xs.into_iter() - .map(|e| remove(e, byte)) - .collect::>>()?; - Hir::alternation(xs) - } - }) -} diff --git a/grep/src/search.rs b/grep/src/search.rs deleted file mode 100644 index 49ddf1f..0000000 --- a/grep/src/search.rs +++ /dev/null @@ -1,356 +0,0 @@ -use memchr::{memchr, memrchr}; -use syntax::ParserBuilder; -use syntax::hir::Hir; -use regex::bytes::{Regex, RegexBuilder}; - -use literals::LiteralSets; -use nonl; -use smart_case::Cased; -use word_boundary::strip_unicode_word_boundaries; -use Result; - -/// A matched line. -#[derive(Clone, Debug, Default, Eq, PartialEq)] -pub struct Match { - start: usize, - end: usize, -} - -impl Match { - /// Create a new empty match value. - pub fn new() -> Match { - Match::default() - } - - /// Return the starting byte offset of the line that matched. - #[inline] - pub fn start(&self) -> usize { - self.start - } - - /// Return the ending byte offset of the line that matched. - #[inline] - pub fn end(&self) -> usize { - self.end - } -} - -/// A fast line oriented regex searcher. -#[derive(Clone, Debug)] -pub struct Grep { - re: Regex, - required: Option, - opts: Options, -} - -/// A builder for a grep searcher. -#[derive(Clone, Debug)] -pub struct GrepBuilder { - pattern: String, - opts: Options, -} - -#[derive(Clone, Debug)] -struct Options { - case_insensitive: bool, - case_smart: bool, - line_terminator: u8, - size_limit: usize, - dfa_size_limit: usize, -} - -impl Default for Options { - fn default() -> Options { - Options { - case_insensitive: false, - case_smart: false, - line_terminator: b'\n', - size_limit: 10 * (1 << 20), - dfa_size_limit: 10 * (1 << 20), - } - } -} - -impl GrepBuilder { - /// Create a new builder for line searching. - /// - /// The pattern given should be a regular expression. The precise syntax - /// supported is documented on the regex crate. - pub fn new(pattern: &str) -> GrepBuilder { - GrepBuilder { - pattern: pattern.to_string(), - opts: Options::default(), - } - } - - /// Set the line terminator. - /// - /// The line terminator can be any ASCII character and serves to delineate - /// the match boundaries in the text searched. - /// - /// This panics if `ascii_byte` is greater than `0x7F` (i.e., not ASCII). - pub fn line_terminator(mut self, ascii_byte: u8) -> GrepBuilder { - assert!(ascii_byte <= 0x7F); - self.opts.line_terminator = ascii_byte; - self - } - - /// Set the case sensitive flag (`i`) on the regex. - pub fn case_insensitive(mut self, yes: bool) -> GrepBuilder { - self.opts.case_insensitive = yes; - self - } - - /// Whether to enable smart case search or not (disabled by default). - /// - /// Smart case uses case insensitive search if the pattern contains only - /// lowercase characters (ignoring any characters which immediately follow - /// a '\'). Otherwise, a case sensitive search is used instead. - /// - /// Enabling the case_insensitive flag overrides this. - pub fn case_smart(mut self, yes: bool) -> GrepBuilder { - self.opts.case_smart = yes; - self - } - - /// Set the approximate size limit of the compiled regular expression. - /// - /// This roughly corresponds to the number of bytes occupied by a - /// single compiled program. If the program exceeds this number, then a - /// compilation error is returned. - pub fn size_limit(mut self, limit: usize) -> GrepBuilder { - self.opts.size_limit = limit; - self - } - - /// Set the approximate size of the cache used by the DFA. - /// - /// This roughly corresponds to the number of bytes that the DFA will use - /// while searching. - /// - /// Note that this is a per thread limit. There is no way to set a global - /// limit. In particular, if a regex is used from multiple threads - /// simulanteously, then each thread may use up to the number of bytes - /// specified here. - pub fn dfa_size_limit(mut self, limit: usize) -> GrepBuilder { - self.opts.dfa_size_limit = limit; - self - } - - /// Create a line searcher. - /// - /// If there was a problem parsing or compiling the regex with the given - /// options, then an error is returned. - pub fn build(self) -> Result { - let expr = self.parse()?; - let literals = LiteralSets::create(&expr); - let re = self.regex(&expr)?; - let required = match literals.to_regex_builder() { - Some(builder) => Some(self.regex_build(builder)?), - None => { - match strip_unicode_word_boundaries(&expr) { - None => None, - Some(expr) => { - debug!("Stripped Unicode word boundaries. \ - New AST:\n{:?}", expr); - self.regex(&expr).ok() - } - } - } - }; - Ok(Grep { - re: re, - required: required, - opts: self.opts, - }) - } - - /// Creates a new regex from the given expression with the current - /// configuration. - fn regex(&self, expr: &Hir) -> Result { - let mut builder = RegexBuilder::new(&expr.to_string()); - builder.unicode(true); - self.regex_build(builder) - } - - /// Builds a new regex from the given builder using the caller's settings. - fn regex_build(&self, mut builder: RegexBuilder) -> Result { - builder - .multi_line(true) - .size_limit(self.opts.size_limit) - .dfa_size_limit(self.opts.dfa_size_limit) - .build() - .map_err(From::from) - } - - /// Parses the underlying pattern and ensures the pattern can never match - /// the line terminator. - fn parse(&self) -> Result { - let expr = ParserBuilder::new() - .allow_invalid_utf8(true) - .case_insensitive(self.is_case_insensitive()?) - .multi_line(true) - .build() - .parse(&self.pattern)?; - debug!("original regex HIR pattern:\n{}", expr); - let expr = nonl::remove(expr, self.opts.line_terminator)?; - debug!("transformed regex HIR pattern:\n{}", expr); - Ok(expr) - } - - /// Determines whether the case insensitive flag should be enabled or not. - fn is_case_insensitive(&self) -> Result { - if self.opts.case_insensitive { - return Ok(true); - } - if !self.opts.case_smart { - return Ok(false); - } - let cased = match Cased::from_pattern(&self.pattern) { - None => return Ok(false), - Some(cased) => cased, - }; - Ok(cased.any_literal && !cased.any_uppercase) - } -} - -impl Grep { - /// Returns a reference to the underlying regex used by the searcher. - pub fn regex(&self) -> &Regex { - &self.re - } - - /// Returns an iterator over all matches in the given buffer. - pub fn iter<'b, 's>(&'s self, buf: &'b [u8]) -> Iter<'b, 's> { - Iter { - searcher: self, - buf: buf, - start: 0, - } - } - - /// Fills in the next line that matches in the given buffer starting at - /// the position given. - /// - /// If no match could be found, `false` is returned, otherwise, `true` is - /// returned. - pub fn read_match( - &self, - mat: &mut Match, - buf: &[u8], - mut start: usize, - ) -> bool { - if start >= buf.len() { - return false; - } - if let Some(ref req) = self.required { - while start < buf.len() { - let e = match req.shortest_match(&buf[start..]) { - None => return false, - Some(e) => start + e, - }; - let (prevnl, nextnl) = self.find_line(buf, e, e); - match self.re.shortest_match(&buf[prevnl..nextnl]) { - None => { - start = nextnl; - continue; - } - Some(_) => { - self.fill_match(mat, prevnl, nextnl); - return true; - } - } - } - false - } else { - let e = match self.re.shortest_match(&buf[start..]) { - None => return false, - Some(e) => start + e, - }; - let (s, e) = self.find_line(buf, e, e); - self.fill_match(mat, s, e); - true - } - } - - fn fill_match(&self, mat: &mut Match, start: usize, end: usize) { - mat.start = start; - mat.end = end; - } - - fn find_line(&self, buf: &[u8], s: usize, e: usize) -> (usize, usize) { - (self.find_line_start(buf, s), self.find_line_end(buf, e)) - } - - fn find_line_start(&self, buf: &[u8], pos: usize) -> usize { - memrchr(self.opts.line_terminator, &buf[0..pos]).map_or(0, |i| i + 1) - } - - fn find_line_end(&self, buf: &[u8], pos: usize) -> usize { - memchr(self.opts.line_terminator, &buf[pos..]) - .map_or(buf.len(), |i| pos + i + 1) - } -} - -/// An iterator over all matches in a particular buffer. -/// -/// `'b` refers to the lifetime of the buffer, and `'s` refers to the lifetime -/// of the searcher. -pub struct Iter<'b, 's> { - searcher: &'s Grep, - buf: &'b [u8], - start: usize, -} - -impl<'b, 's> Iterator for Iter<'b, 's> { - type Item = Match; - - fn next(&mut self) -> Option { - let mut mat = Match::default(); - if !self.searcher.read_match(&mut mat, self.buf, self.start) { - self.start = self.buf.len(); - return None; - } - self.start = mat.end; - Some(mat) - } -} - -#[cfg(test)] -mod tests { - use memchr::{memchr, memrchr}; - use regex::bytes::Regex; - - use super::{GrepBuilder, Match}; - - static SHERLOCK: &'static [u8] = include_bytes!("./data/sherlock.txt"); - - fn find_lines(pat: &str, haystack: &[u8]) -> Vec { - let re = Regex::new(pat).unwrap(); - let mut lines = vec![]; - for m in re.find_iter(haystack) { - let start = memrchr(b'\n', &haystack[..m.start()]) - .map_or(0, |i| i + 1); - let end = memchr(b'\n', &haystack[m.end()..]) - .map_or(haystack.len(), |i| m.end() + i + 1); - lines.push(Match { - start: start, - end: end, - }); - } - lines - } - - fn grep_lines(pat: &str, haystack: &[u8]) -> Vec { - let g = GrepBuilder::new(pat).build().unwrap(); - g.iter(haystack).collect() - } - - #[test] - fn buffered_literal() { - let expected = find_lines("Sherlock Holmes", SHERLOCK); - let got = grep_lines("Sherlock Holmes", SHERLOCK); - assert_eq!(expected.len(), got.len()); - assert_eq!(expected, got); - } -} diff --git a/grep/src/smart_case.rs b/grep/src/smart_case.rs deleted file mode 100644 index 1379b32..0000000 --- a/grep/src/smart_case.rs +++ /dev/null @@ -1,191 +0,0 @@ -use syntax::ast::{self, Ast}; -use syntax::ast::parse::Parser; - -/// The results of analyzing a regex for cased literals. -#[derive(Clone, Debug, Default)] -pub struct Cased { - /// True if and only if a literal uppercase character occurs in the regex. - /// - /// A regex like `\pL` contains no uppercase literals, even though `L` - /// is uppercase and the `\pL` class contains uppercase characters. - pub any_uppercase: bool, - /// True if and only if the regex contains any literal at all. A regex like - /// `\pL` has this set to false. - pub any_literal: bool, -} - -impl Cased { - /// Returns a `Cased` value by doing analysis on the AST of `pattern`. - /// - /// If `pattern` is not a valid regular expression, then `None` is - /// returned. - pub fn from_pattern(pattern: &str) -> Option { - Parser::new() - .parse(pattern) - .map(|ast| Cased::from_ast(&ast)) - .ok() - } - - fn from_ast(ast: &Ast) -> Cased { - let mut cased = Cased::default(); - cased.from_ast_impl(ast); - cased - } - - fn from_ast_impl(&mut self, ast: &Ast) { - if self.done() { - return; - } - match *ast { - Ast::Empty(_) - | Ast::Flags(_) - | Ast::Dot(_) - | Ast::Assertion(_) - | Ast::Class(ast::Class::Unicode(_)) - | Ast::Class(ast::Class::Perl(_)) => {} - Ast::Literal(ref x) => { - self.from_ast_literal(x); - } - Ast::Class(ast::Class::Bracketed(ref x)) => { - self.from_ast_class_set(&x.kind); - } - Ast::Repetition(ref x) => { - self.from_ast_impl(&x.ast); - } - Ast::Group(ref x) => { - self.from_ast_impl(&x.ast); - } - Ast::Alternation(ref alt) => { - for x in &alt.asts { - self.from_ast_impl(x); - } - } - Ast::Concat(ref alt) => { - for x in &alt.asts { - self.from_ast_impl(x); - } - } - } - } - - fn from_ast_class_set(&mut self, ast: &ast::ClassSet) { - if self.done() { - return; - } - match *ast { - ast::ClassSet::Item(ref item) => { - self.from_ast_class_set_item(item); - } - ast::ClassSet::BinaryOp(ref x) => { - self.from_ast_class_set(&x.lhs); - self.from_ast_class_set(&x.rhs); - } - } - } - - fn from_ast_class_set_item(&mut self, ast: &ast::ClassSetItem) { - if self.done() { - return; - } - match *ast { - ast::ClassSetItem::Empty(_) - | ast::ClassSetItem::Ascii(_) - | ast::ClassSetItem::Unicode(_) - | ast::ClassSetItem::Perl(_) => {} - ast::ClassSetItem::Literal(ref x) => { - self.from_ast_literal(x); - } - ast::ClassSetItem::Range(ref x) => { - self.from_ast_literal(&x.start); - self.from_ast_literal(&x.end); - } - ast::ClassSetItem::Bracketed(ref x) => { - self.from_ast_class_set(&x.kind); - } - ast::ClassSetItem::Union(ref union) => { - for x in &union.items { - self.from_ast_class_set_item(x); - } - } - } - } - - fn from_ast_literal(&mut self, ast: &ast::Literal) { - self.any_literal = true; - self.any_uppercase = self.any_uppercase || ast.c.is_uppercase(); - } - - /// Returns true if and only if the attributes can never change no matter - /// what other AST it might see. - fn done(&self) -> bool { - self.any_uppercase && self.any_literal - } -} - -#[cfg(test)] -mod tests { - use super::*; - - fn cased(pattern: &str) -> Cased { - Cased::from_pattern(pattern).unwrap() - } - - #[test] - fn various() { - let x = cased(""); - assert!(!x.any_uppercase); - assert!(!x.any_literal); - - let x = cased("foo"); - assert!(!x.any_uppercase); - assert!(x.any_literal); - - let x = cased("Foo"); - assert!(x.any_uppercase); - assert!(x.any_literal); - - let x = cased("foO"); - assert!(x.any_uppercase); - assert!(x.any_literal); - - let x = cased(r"foo\\"); - assert!(!x.any_uppercase); - assert!(x.any_literal); - - let x = cased(r"foo\w"); - assert!(!x.any_uppercase); - assert!(x.any_literal); - - let x = cased(r"foo\S"); - assert!(!x.any_uppercase); - assert!(x.any_literal); - - let x = cased(r"foo\p{Ll}"); - assert!(!x.any_uppercase); - assert!(x.any_literal); - - let x = cased(r"foo[a-z]"); - assert!(!x.any_uppercase); - assert!(x.any_literal); - - let x = cased(r"foo[A-Z]"); - assert!(x.any_uppercase); - assert!(x.any_literal); - - let x = cased(r"foo[\S\t]"); - assert!(!x.any_uppercase); - assert!(x.any_literal); - - let x = cased(r"foo\\S"); - assert!(x.any_uppercase); - assert!(x.any_literal); - - let x = cased(r"\p{Ll}"); - assert!(!x.any_uppercase); - assert!(!x.any_literal); - - let x = cased(r"aBc\w"); - assert!(x.any_uppercase); - assert!(x.any_literal); - } -} diff --git a/grep/src/word_boundary.rs b/grep/src/word_boundary.rs deleted file mode 100644 index 8e6b86d..0000000 --- a/grep/src/word_boundary.rs +++ /dev/null @@ -1,53 +0,0 @@ -use syntax::hir::{self, Hir, HirKind}; - -/// Strips Unicode word boundaries from the given expression. -/// -/// The key invariant this maintains is that the expression returned will match -/// *at least* every where the expression given will match. Namely, a match of -/// the returned expression can report false positives but it will never report -/// false negatives. -/// -/// If no word boundaries could be stripped, then None is returned. -pub fn strip_unicode_word_boundaries(expr: &Hir) -> Option { - // The real reason we do this is because Unicode word boundaries are the - // one thing that Rust's regex DFA engine can't handle. When it sees a - // Unicode word boundary among non-ASCII text, it falls back to one of the - // slower engines. We work around this limitation by attempting to use - // a regex to find candidate matches without a Unicode word boundary. We'll - // only then use the full (and slower) regex to confirm a candidate as a - // match or not during search. - // - // It looks like we only check the outer edges for `\b`? I guess this is - // an attempt to optimize for the `-w/--word-regexp` flag? ---AG - match *expr.kind() { - HirKind::Concat(ref es) if !es.is_empty() => { - let first = is_unicode_word_boundary(&es[0]); - let last = is_unicode_word_boundary(es.last().unwrap()); - // Be careful not to strip word boundaries if there are no other - // expressions to match. - match (first, last) { - (true, false) if es.len() > 1 => { - Some(Hir::concat(es[1..].to_vec())) - } - (false, true) if es.len() > 1 => { - Some(Hir::concat(es[..es.len() - 1].to_vec())) - } - (true, true) if es.len() > 2 => { - Some(Hir::concat(es[1..es.len() - 1].to_vec())) - } - _ => None, - } - } - _ => None, - } -} - -/// Returns true if the given expression is a Unicode word boundary. -fn is_unicode_word_boundary(expr: &Hir) -> bool { - match *expr.kind() { - HirKind::WordBoundary(hir::WordBoundary::Unicode) => true, - HirKind::WordBoundary(hir::WordBoundary::UnicodeNegate) => true, - HirKind::Group(ref x) => is_unicode_word_boundary(&x.hir), - _ => false, - } -} diff --git a/ignore/COPYING b/ignore/COPYING deleted file mode 100644 index bb9c20a..0000000 --- a/ignore/COPYING +++ /dev/null @@ -1,3 +0,0 @@ -This project is dual-licensed under the Unlicense and MIT licenses. - -You may use this code under the terms of either license. diff --git a/ignore/Cargo.toml b/ignore/Cargo.toml deleted file mode 100644 index 07efa22..0000000 --- a/ignore/Cargo.toml +++ /dev/null @@ -1,39 +0,0 @@ -[package] -name = "ignore" -version = "0.4.2" #:version -authors = ["Andrew Gallant "] -description = """ -A fast library for efficiently matching ignore files such as `.gitignore` -against file paths. -""" -documentation = "https://docs.rs/ignore" -homepage = "https://github.com/BurntSushi/ripgrep/tree/master/ignore" -repository = "https://github.com/BurntSushi/ripgrep/tree/master/ignore" -readme = "README.md" -keywords = ["glob", "ignore", "gitignore", "pattern", "file"] -license = "Unlicense/MIT" - -[lib] -name = "ignore" -bench = false - -[dependencies] -crossbeam = "0.3" -globset = { version = "0.4.0", path = "../globset" } -lazy_static = "1" -log = "0.4" -memchr = "2" -regex = "1" -same-file = "1" -thread_local = "0.3.2" -walkdir = "2" - -[target.'cfg(windows)'.dependencies.winapi] -version = "0.3" -features = ["std", "winnt"] - -[dev-dependencies] -tempdir = "0.3.5" - -[features] -simd-accel = ["globset/simd-accel"] diff --git a/ignore/LICENSE-MIT b/ignore/LICENSE-MIT deleted file mode 100644 index 3b0a5dc..0000000 --- a/ignore/LICENSE-MIT +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Andrew Gallant - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/ignore/README.md b/ignore/README.md deleted file mode 100644 index f527da4..0000000 --- a/ignore/README.md +++ /dev/null @@ -1,66 +0,0 @@ -ignore -====== -The ignore crate provides a fast recursive directory iterator that respects -various filters such as globs, file types and `.gitignore` files. This crate -also provides lower level direct access to gitignore and file type matchers. - -[![Linux build status](https://api.travis-ci.org/BurntSushi/ripgrep.png)](https://travis-ci.org/BurntSushi/ripgrep) -[![Windows build status](https://ci.appveyor.com/api/projects/status/github/BurntSushi/ripgrep?svg=true)](https://ci.appveyor.com/project/BurntSushi/ripgrep) -[![](https://img.shields.io/crates/v/ignore.svg)](https://crates.io/crates/ignore) - -Dual-licensed under MIT or the [UNLICENSE](http://unlicense.org). - -### Documentation - -[https://docs.rs/ignore](https://docs.rs/ignore) - -### Usage - -Add this to your `Cargo.toml`: - -```toml -[dependencies] -ignore = "0.4" -``` - -and this to your crate root: - -```rust -extern crate ignore; -``` - -### Example - -This example shows the most basic usage of this crate. This code will -recursively traverse the current directory while automatically filtering out -files and directories according to ignore globs found in files like -`.ignore` and `.gitignore`: - - -```rust,no_run -use ignore::Walk; - -for result in Walk::new("./") { - // Each item yielded by the iterator is either a directory entry or an - // error, so either print the path or the error. - match result { - Ok(entry) => println!("{}", entry.path().display()), - Err(err) => println!("ERROR: {}", err), - } -} -``` - -### Example: advanced - -By default, the recursive directory iterator will ignore hidden files and -directories. This can be disabled by building the iterator with `WalkBuilder`: - -```rust,no_run -use ignore::WalkBuilder; - -for result in WalkBuilder::new("./").hidden(false).build() { - println!("{:?}", result); -} -``` - -See the documentation for `WalkBuilder` for many other options. diff --git a/ignore/UNLICENSE b/ignore/UNLICENSE deleted file mode 100644 index 68a49da..0000000 --- a/ignore/UNLICENSE +++ /dev/null @@ -1,24 +0,0 @@ -This is free and unencumbered software released into the public domain. - -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a compiled -binary, for any purpose, commercial or non-commercial, and by any -means. - -In jurisdictions that recognize copyright laws, the author or authors -of this software dedicate any and all copyright interest in the -software to the public domain. We make this dedication for the benefit -of the public at large and to the detriment of our heirs and -successors. We intend this dedication to be an overt act of -relinquishment in perpetuity of all present and future rights to this -software under copyright law. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -For more information, please refer to diff --git a/ignore/examples/walk.rs b/ignore/examples/walk.rs deleted file mode 100644 index 0ff4ea9..0000000 --- a/ignore/examples/walk.rs +++ /dev/null @@ -1,92 +0,0 @@ -#![allow(dead_code, unused_imports, unused_mut, unused_variables)] - -extern crate crossbeam; -extern crate ignore; -extern crate walkdir; - -use std::env; -use std::io::{self, Write}; -use std::path::Path; -use std::sync::Arc; -use std::sync::atomic::{AtomicUsize, Ordering}; -use std::thread; - -use crossbeam::sync::MsQueue; -use ignore::WalkBuilder; -use walkdir::WalkDir; - -fn main() { - let mut path = env::args().nth(1).unwrap(); - let mut parallel = false; - let mut simple = false; - let queue: Arc>> = Arc::new(MsQueue::new()); - if path == "parallel" { - path = env::args().nth(2).unwrap(); - parallel = true; - } else if path == "walkdir" { - path = env::args().nth(2).unwrap(); - simple = true; - } - - let stdout_queue = queue.clone(); - let stdout_thread = thread::spawn(move || { - let mut stdout = io::BufWriter::new(io::stdout()); - while let Some(dent) = stdout_queue.pop() { - write_path(&mut stdout, dent.path()); - } - }); - - if parallel { - let walker = WalkBuilder::new(path).threads(6).build_parallel(); - walker.run(|| { - let queue = queue.clone(); - Box::new(move |result| { - use ignore::WalkState::*; - - queue.push(Some(DirEntry::Y(result.unwrap()))); - Continue - }) - }); - } else if simple { - let mut stdout = io::BufWriter::new(io::stdout()); - let walker = WalkDir::new(path); - for result in walker { - queue.push(Some(DirEntry::X(result.unwrap()))); - } - } else { - let mut stdout = io::BufWriter::new(io::stdout()); - let walker = WalkBuilder::new(path).build(); - for result in walker { - queue.push(Some(DirEntry::Y(result.unwrap()))); - } - } - queue.push(None); - stdout_thread.join().unwrap(); -} - -enum DirEntry { - X(walkdir::DirEntry), - Y(ignore::DirEntry), -} - -impl DirEntry { - fn path(&self) -> &Path { - match *self { - DirEntry::X(ref x) => x.path(), - DirEntry::Y(ref y) => y.path(), - } - } -} - -#[cfg(unix)] -fn write_path(mut wtr: W, path: &Path) { - use std::os::unix::ffi::OsStrExt; - wtr.write(path.as_os_str().as_bytes()).unwrap(); - wtr.write(b"\n").unwrap(); -} - -#[cfg(not(unix))] -fn write_path(mut wtr: W, path: &Path) { - wtr.write(path.to_string_lossy().as_bytes()).unwrap(); - wtr.write(b"\n").unwrap(); -} diff --git a/ignore/src/dir.rs b/ignore/src/dir.rs deleted file mode 100644 index 2e1b82e..0000000 --- a/ignore/src/dir.rs +++ /dev/null @@ -1,891 +0,0 @@ -// This module provides a data structure, `Ignore`, that connects "directory -// traversal" with "ignore matchers." Specifically, it knows about gitignore -// semantics and precedence, and is organized based on directory hierarchy. -// Namely, every matcher logically corresponds to ignore rules from a single -// directory, and points to the matcher for its corresponding parent directory. -// In this sense, `Ignore` is a *persistent* data structure. -// -// This design was specifically chosen to make it possible to use this data -// structure in a parallel directory iterator. -// -// My initial intention was to expose this module as part of this crate's -// public API, but I think the data structure's public API is too complicated -// with non-obvious failure modes. Alas, such things haven't been documented -// well. - -use std::collections::HashMap; -use std::ffi::{OsString, OsStr}; -use std::path::{Path, PathBuf}; -use std::sync::{Arc, RwLock}; - -use gitignore::{self, Gitignore, GitignoreBuilder}; -use pathutil::{is_hidden, strip_prefix}; -use overrides::{self, Override}; -use types::{self, Types}; -use {Error, Match, PartialErrorBuilder}; - -/// IgnoreMatch represents information about where a match came from when using -/// the `Ignore` matcher. -#[derive(Clone, Debug)] -pub struct IgnoreMatch<'a>(IgnoreMatchInner<'a>); - -/// IgnoreMatchInner describes precisely where the match information came from. -/// This is private to allow expansion to more matchers in the future. -#[derive(Clone, Debug)] -enum IgnoreMatchInner<'a> { - Override(overrides::Glob<'a>), - Gitignore(&'a gitignore::Glob), - Types(types::Glob<'a>), - Hidden, -} - -impl<'a> IgnoreMatch<'a> { - fn overrides(x: overrides::Glob<'a>) -> IgnoreMatch<'a> { - IgnoreMatch(IgnoreMatchInner::Override(x)) - } - - fn gitignore(x: &'a gitignore::Glob) -> IgnoreMatch<'a> { - IgnoreMatch(IgnoreMatchInner::Gitignore(x)) - } - - fn types(x: types::Glob<'a>) -> IgnoreMatch<'a> { - IgnoreMatch(IgnoreMatchInner::Types(x)) - } - - fn hidden() -> IgnoreMatch<'static> { - IgnoreMatch(IgnoreMatchInner::Hidden) - } -} - -/// Options for the ignore matcher, shared between the matcher itself and the -/// builder. -#[derive(Clone, Copy, Debug)] -struct IgnoreOptions { - /// Whether to ignore hidden file paths or not. - hidden: bool, - /// Whether to read .ignore files. - ignore: bool, - /// Whether to read git's global gitignore file. - git_global: bool, - /// Whether to read .gitignore files. - git_ignore: bool, - /// Whether to read .git/info/exclude files. - git_exclude: bool, -} - -/// Ignore is a matcher useful for recursively walking one or more directories. -#[derive(Clone, Debug)] -pub struct Ignore(Arc); - -#[derive(Clone, Debug)] -struct IgnoreInner { - /// A map of all existing directories that have already been - /// compiled into matchers. - /// - /// Note that this is never used during matching, only when adding new - /// parent directory matchers. This avoids needing to rebuild glob sets for - /// parent directories if many paths are being searched. - compiled: Arc>>, - /// The path to the directory that this matcher was built from. - dir: PathBuf, - /// An override matcher (default is empty). - overrides: Arc, - /// A file type matcher. - types: Arc, - /// The parent directory to match next. - /// - /// If this is the root directory or there are otherwise no more - /// directories to match, then `parent` is `None`. - parent: Option, - /// Whether this is an absolute parent matcher, as added by add_parent. - is_absolute_parent: bool, - /// The absolute base path of this matcher. Populated only if parent - /// directories are added. - absolute_base: Option>, - /// Explicit global ignore matchers specified by the caller. - explicit_ignores: Arc>, - /// Ignore files used in addition to `.ignore` - custom_ignore_filenames: Arc>, - /// The matcher for custom ignore files - custom_ignore_matcher: Gitignore, - /// The matcher for .ignore files. - ignore_matcher: Gitignore, - /// A global gitignore matcher, usually from $XDG_CONFIG_HOME/git/ignore. - git_global_matcher: Arc, - /// The matcher for .gitignore files. - git_ignore_matcher: Gitignore, - /// Special matcher for `.git/info/exclude` files. - git_exclude_matcher: Gitignore, - /// Whether this directory contains a .git sub-directory. - has_git: bool, - /// Ignore config. - opts: IgnoreOptions, -} - -impl Ignore { - /// Return the directory path of this matcher. - pub fn path(&self) -> &Path { - &self.0.dir - } - - /// Return true if this matcher has no parent. - pub fn is_root(&self) -> bool { - self.0.parent.is_none() - } - - /// Returns true if this matcher was added via the `add_parents` method. - pub fn is_absolute_parent(&self) -> bool { - self.0.is_absolute_parent - } - - /// Return this matcher's parent, if one exists. - pub fn parent(&self) -> Option { - self.0.parent.clone() - } - - /// Create a new `Ignore` matcher with the parent directories of `dir`. - /// - /// Note that this can only be called on an `Ignore` matcher with no - /// parents (i.e., `is_root` returns `true`). This will panic otherwise. - pub fn add_parents>( - &self, - path: P, - ) -> (Ignore, Option) { - if !self.is_root() { - panic!("Ignore::add_parents called on non-root matcher"); - } - let absolute_base = match path.as_ref().canonicalize() { - Ok(path) => Arc::new(path), - Err(_) => { - // There's not much we can do here, so just return our - // existing matcher. We drop the error to be consistent - // with our general pattern of ignoring I/O errors when - // processing ignore files. - return (self.clone(), None); - } - }; - // List of parents, from child to root. - let mut parents = vec![]; - let mut path = &**absolute_base; - while let Some(parent) = path.parent() { - parents.push(parent); - path = parent; - } - let mut errs = PartialErrorBuilder::default(); - let mut ig = self.clone(); - for parent in parents.into_iter().rev() { - let mut compiled = self.0.compiled.write().unwrap(); - if let Some(prebuilt) = compiled.get(parent.as_os_str()) { - ig = prebuilt.clone(); - continue; - } - let (mut igtmp, err) = ig.add_child_path(parent); - errs.maybe_push(err); - igtmp.is_absolute_parent = true; - igtmp.absolute_base = Some(absolute_base.clone()); - ig = Ignore(Arc::new(igtmp)); - compiled.insert(parent.as_os_str().to_os_string(), ig.clone()); - } - (ig, errs.into_error_option()) - } - - /// Create a new `Ignore` matcher for the given child directory. - /// - /// Since building the matcher may require reading from multiple - /// files, it's possible that this method partially succeeds. Therefore, - /// a matcher is always returned (which may match nothing) and an error is - /// returned if it exists. - /// - /// Note that all I/O errors are completely ignored. - pub fn add_child>( - &self, - dir: P, - ) -> (Ignore, Option) { - let (ig, err) = self.add_child_path(dir.as_ref()); - (Ignore(Arc::new(ig)), err) - } - - /// Like add_child, but takes a full path and returns an IgnoreInner. - fn add_child_path(&self, dir: &Path) -> (IgnoreInner, Option) { - let mut errs = PartialErrorBuilder::default(); - let custom_ig_matcher = - if self.0.custom_ignore_filenames.is_empty() { - Gitignore::empty() - } else { - let (m, err) = - create_gitignore(&dir, &self.0.custom_ignore_filenames); - errs.maybe_push(err); - m - }; - let ig_matcher = - if !self.0.opts.ignore { - Gitignore::empty() - } else { - let (m, err) = create_gitignore(&dir, &[".ignore"]); - errs.maybe_push(err); - m - }; - let gi_matcher = - if !self.0.opts.git_ignore { - Gitignore::empty() - } else { - let (m, err) = create_gitignore(&dir, &[".gitignore"]); - errs.maybe_push(err); - m - }; - let gi_exclude_matcher = - if !self.0.opts.git_exclude { - Gitignore::empty() - } else { - let (m, err) = create_gitignore(&dir, &[".git/info/exclude"]); - errs.maybe_push(err); - m - }; - let ig = IgnoreInner { - compiled: self.0.compiled.clone(), - dir: dir.to_path_buf(), - overrides: self.0.overrides.clone(), - types: self.0.types.clone(), - parent: Some(self.clone()), - is_absolute_parent: false, - absolute_base: self.0.absolute_base.clone(), - explicit_ignores: self.0.explicit_ignores.clone(), - custom_ignore_filenames: self.0.custom_ignore_filenames.clone(), - custom_ignore_matcher: custom_ig_matcher, - ignore_matcher: ig_matcher, - git_global_matcher: self.0.git_global_matcher.clone(), - git_ignore_matcher: gi_matcher, - git_exclude_matcher: gi_exclude_matcher, - has_git: dir.join(".git").exists(), - opts: self.0.opts, - }; - (ig, errs.into_error_option()) - } - - /// Returns true if at least one type of ignore rule should be matched. - fn has_any_ignore_rules(&self) -> bool { - let opts = self.0.opts; - let has_custom_ignore_files = !self.0.custom_ignore_filenames.is_empty(); - - opts.ignore || opts.git_global || opts.git_ignore - || opts.git_exclude || has_custom_ignore_files - } - - /// Returns a match indicating whether the given file path should be - /// ignored or not. - /// - /// The match contains information about its origin. - pub fn matched<'a, P: AsRef>( - &'a self, - path: P, - is_dir: bool, - ) -> Match> { - // We need to be careful with our path. If it has a leading ./, then - // strip it because it causes nothing but trouble. - let mut path = path.as_ref(); - if let Some(p) = strip_prefix("./", path) { - path = p; - } - // Match against the override patterns. If an override matches - // regardless of whether it's whitelist/ignore, then we quit and - // return that result immediately. Overrides have the highest - // precedence. - if !self.0.overrides.is_empty() { - let mat = - self.0.overrides.matched(path, is_dir) - .map(IgnoreMatch::overrides); - if !mat.is_none() { - return mat; - } - } - let mut whitelisted = Match::None; - if self.has_any_ignore_rules() { - let mat = self.matched_ignore(path, is_dir); - if mat.is_ignore() { - return mat; - } else if mat.is_whitelist() { - whitelisted = mat; - } - } - if !self.0.types.is_empty() { - let mat = - self.0.types.matched(path, is_dir).map(IgnoreMatch::types); - if mat.is_ignore() { - return mat; - } else if mat.is_whitelist() { - whitelisted = mat; - } - } - if whitelisted.is_none() && self.0.opts.hidden && is_hidden(path) { - return Match::Ignore(IgnoreMatch::hidden()); - } - whitelisted - } - - /// Performs matching only on the ignore files for this directory and - /// all parent directories. - fn matched_ignore<'a>( - &'a self, - path: &Path, - is_dir: bool, - ) -> Match> { - let (mut m_custom_ignore, mut m_ignore, mut m_gi, mut m_gi_exclude, mut m_explicit) = - (Match::None, Match::None, Match::None, Match::None, Match::None); - let mut saw_git = false; - for ig in self.parents().take_while(|ig| !ig.0.is_absolute_parent) { - if m_custom_ignore.is_none() { - m_custom_ignore = - ig.0.custom_ignore_matcher.matched(path, is_dir) - .map(IgnoreMatch::gitignore); - } - if m_ignore.is_none() { - m_ignore = - ig.0.ignore_matcher.matched(path, is_dir) - .map(IgnoreMatch::gitignore); - } - if !saw_git && m_gi.is_none() { - m_gi = - ig.0.git_ignore_matcher.matched(path, is_dir) - .map(IgnoreMatch::gitignore); - } - if !saw_git && m_gi_exclude.is_none() { - m_gi_exclude = - ig.0.git_exclude_matcher.matched(path, is_dir) - .map(IgnoreMatch::gitignore); - } - saw_git = saw_git || ig.0.has_git; - } - if let Some(abs_parent_path) = self.absolute_base() { - let path = abs_parent_path.join(path); - for ig in self.parents().skip_while(|ig|!ig.0.is_absolute_parent) { - if m_custom_ignore.is_none() { - m_custom_ignore = - ig.0.custom_ignore_matcher.matched(&path, is_dir) - .map(IgnoreMatch::gitignore); - } - if m_ignore.is_none() { - m_ignore = - ig.0.ignore_matcher.matched(&path, is_dir) - .map(IgnoreMatch::gitignore); - } - if !saw_git && m_gi.is_none() { - m_gi = - ig.0.git_ignore_matcher.matched(&path, is_dir) - .map(IgnoreMatch::gitignore); - } - if !saw_git && m_gi_exclude.is_none() { - m_gi_exclude = - ig.0.git_exclude_matcher.matched(&path, is_dir) - .map(IgnoreMatch::gitignore); - } - saw_git = saw_git || ig.0.has_git; - } - } - for gi in self.0.explicit_ignores.iter().rev() { - if !m_explicit.is_none() { - break; - } - m_explicit = gi.matched(&path, is_dir).map(IgnoreMatch::gitignore); - } - let m_global = self.0.git_global_matcher.matched(&path, is_dir) - .map(IgnoreMatch::gitignore); - - m_custom_ignore.or(m_ignore).or(m_gi).or(m_gi_exclude).or(m_global).or(m_explicit) - } - - /// Returns an iterator over parent ignore matchers, including this one. - pub fn parents(&self) -> Parents { - Parents(Some(self)) - } - - /// Returns the first absolute path of the first absolute parent, if - /// one exists. - fn absolute_base(&self) -> Option<&Path> { - self.0.absolute_base.as_ref().map(|p| &***p) - } -} - -/// An iterator over all parents of an ignore matcher, including itself. -/// -/// The lifetime `'a` refers to the lifetime of the initial `Ignore` matcher. -pub struct Parents<'a>(Option<&'a Ignore>); - -impl<'a> Iterator for Parents<'a> { - type Item = &'a Ignore; - - fn next(&mut self) -> Option<&'a Ignore> { - match self.0.take() { - None => None, - Some(ig) => { - self.0 = ig.0.parent.as_ref(); - Some(ig) - } - } - } -} - -/// A builder for creating an Ignore matcher. -#[derive(Clone, Debug)] -pub struct IgnoreBuilder { - /// The root directory path for this ignore matcher. - dir: PathBuf, - /// An override matcher (default is empty). - overrides: Arc, - /// A type matcher (default is empty). - types: Arc, - /// Explicit global ignore matchers. - explicit_ignores: Vec, - /// Ignore files in addition to .ignore. - custom_ignore_filenames: Vec, - /// Ignore config. - opts: IgnoreOptions, -} - -impl IgnoreBuilder { - /// Create a new builder for an `Ignore` matcher. - /// - /// All relative file paths are resolved with respect to the current - /// working directory. - pub fn new() -> IgnoreBuilder { - IgnoreBuilder { - dir: Path::new("").to_path_buf(), - overrides: Arc::new(Override::empty()), - types: Arc::new(Types::empty()), - explicit_ignores: vec![], - custom_ignore_filenames: vec![], - opts: IgnoreOptions { - hidden: true, - ignore: true, - git_global: true, - git_ignore: true, - git_exclude: true, - }, - } - } - - /// Builds a new `Ignore` matcher. - /// - /// The matcher returned won't match anything until ignore rules from - /// directories are added to it. - pub fn build(&self) -> Ignore { - let git_global_matcher = - if !self.opts.git_global { - Gitignore::empty() - } else { - let (gi, err) = Gitignore::global(); - if let Some(err) = err { - debug!("{}", err); - } - gi - }; - - Ignore(Arc::new(IgnoreInner { - compiled: Arc::new(RwLock::new(HashMap::new())), - dir: self.dir.clone(), - overrides: self.overrides.clone(), - types: self.types.clone(), - parent: None, - is_absolute_parent: true, - absolute_base: None, - explicit_ignores: Arc::new(self.explicit_ignores.clone()), - custom_ignore_filenames: Arc::new(self.custom_ignore_filenames.clone()), - custom_ignore_matcher: Gitignore::empty(), - ignore_matcher: Gitignore::empty(), - git_global_matcher: Arc::new(git_global_matcher), - git_ignore_matcher: Gitignore::empty(), - git_exclude_matcher: Gitignore::empty(), - has_git: false, - opts: self.opts, - })) - } - - /// Add an override matcher. - /// - /// By default, no override matcher is used. - /// - /// This overrides any previous setting. - pub fn overrides(&mut self, overrides: Override) -> &mut IgnoreBuilder { - self.overrides = Arc::new(overrides); - self - } - - /// Add a file type matcher. - /// - /// By default, no file type matcher is used. - /// - /// This overrides any previous setting. - pub fn types(&mut self, types: Types) -> &mut IgnoreBuilder { - self.types = Arc::new(types); - self - } - - /// Adds a new global ignore matcher from the ignore file path given. - pub fn add_ignore(&mut self, ig: Gitignore) -> &mut IgnoreBuilder { - self.explicit_ignores.push(ig); - self - } - - /// Add a custom ignore file name - /// - /// These ignore files have higher precedence than all other ignore files. - /// - /// When specifying multiple names, earlier names have lower precedence than - /// later names. - pub fn add_custom_ignore_filename>( - &mut self, - file_name: S - ) -> &mut IgnoreBuilder { - self.custom_ignore_filenames.push(file_name.as_ref().to_os_string()); - self - } - - /// Enables ignoring hidden files. - /// - /// This is enabled by default. - pub fn hidden(&mut self, yes: bool) -> &mut IgnoreBuilder { - self.opts.hidden = yes; - self - } - - /// Enables reading `.ignore` files. - /// - /// `.ignore` files have the same semantics as `gitignore` files and are - /// supported by search tools such as ripgrep and The Silver Searcher. - /// - /// This is enabled by default. - pub fn ignore(&mut self, yes: bool) -> &mut IgnoreBuilder { - self.opts.ignore = yes; - self - } - - /// Add a global gitignore matcher. - /// - /// Its precedence is lower than both normal `.gitignore` files and - /// `.git/info/exclude` files. - /// - /// This overwrites any previous global gitignore setting. - /// - /// This is enabled by default. - pub fn git_global(&mut self, yes: bool) -> &mut IgnoreBuilder { - self.opts.git_global = yes; - self - } - - /// Enables reading `.gitignore` files. - /// - /// `.gitignore` files have match semantics as described in the `gitignore` - /// man page. - /// - /// This is enabled by default. - pub fn git_ignore(&mut self, yes: bool) -> &mut IgnoreBuilder { - self.opts.git_ignore = yes; - self - } - - /// Enables reading `.git/info/exclude` files. - /// - /// `.git/info/exclude` files have match semantics as described in the - /// `gitignore` man page. - /// - /// This is enabled by default. - pub fn git_exclude(&mut self, yes: bool) -> &mut IgnoreBuilder { - self.opts.git_exclude = yes; - self - } -} - -/// Creates a new gitignore matcher for the directory given. -/// -/// Ignore globs are extracted from each of the file names in `dir` in the -/// order given (earlier names have lower precedence than later names). -/// -/// I/O errors are ignored. -pub fn create_gitignore>( - dir: &Path, - names: &[T], -) -> (Gitignore, Option) { - let mut builder = GitignoreBuilder::new(dir); - let mut errs = PartialErrorBuilder::default(); - for name in names { - let gipath = dir.join(name.as_ref()); - errs.maybe_push_ignore_io(builder.add(gipath)); - } - let gi = match builder.build() { - Ok(gi) => gi, - Err(err) => { - errs.push(err); - GitignoreBuilder::new(dir).build().unwrap() - } - }; - (gi, errs.into_error_option()) -} - -#[cfg(test)] -mod tests { - use std::fs::{self, File}; - use std::io::Write; - use std::path::Path; - - use tempdir::TempDir; - - use dir::IgnoreBuilder; - use gitignore::Gitignore; - use Error; - - fn wfile>(path: P, contents: &str) { - let mut file = File::create(path).unwrap(); - file.write_all(contents.as_bytes()).unwrap(); - } - - fn mkdirp>(path: P) { - fs::create_dir_all(path).unwrap(); - } - - fn partial(err: Error) -> Vec { - match err { - Error::Partial(errs) => errs, - _ => panic!("expected partial error but got {:?}", err), - } - } - - #[test] - fn explicit_ignore() { - let td = TempDir::new("ignore-test-").unwrap(); - wfile(td.path().join("not-an-ignore"), "foo\n!bar"); - - let (gi, err) = Gitignore::new(td.path().join("not-an-ignore")); - assert!(err.is_none()); - let (ig, err) = IgnoreBuilder::new() - .add_ignore(gi).build().add_child(td.path()); - assert!(err.is_none()); - assert!(ig.matched("foo", false).is_ignore()); - assert!(ig.matched("bar", false).is_whitelist()); - assert!(ig.matched("baz", false).is_none()); - } - - #[test] - fn git_exclude() { - let td = TempDir::new("ignore-test-").unwrap(); - mkdirp(td.path().join(".git/info")); - wfile(td.path().join(".git/info/exclude"), "foo\n!bar"); - - let (ig, err) = IgnoreBuilder::new().build().add_child(td.path()); - assert!(err.is_none()); - assert!(ig.matched("foo", false).is_ignore()); - assert!(ig.matched("bar", false).is_whitelist()); - assert!(ig.matched("baz", false).is_none()); - } - - #[test] - fn gitignore() { - let td = TempDir::new("ignore-test-").unwrap(); - wfile(td.path().join(".gitignore"), "foo\n!bar"); - - let (ig, err) = IgnoreBuilder::new().build().add_child(td.path()); - assert!(err.is_none()); - assert!(ig.matched("foo", false).is_ignore()); - assert!(ig.matched("bar", false).is_whitelist()); - assert!(ig.matched("baz", false).is_none()); - } - - #[test] - fn ignore() { - let td = TempDir::new("ignore-test-").unwrap(); - wfile(td.path().join(".ignore"), "foo\n!bar"); - - let (ig, err) = IgnoreBuilder::new().build().add_child(td.path()); - assert!(err.is_none()); - assert!(ig.matched("foo", false).is_ignore()); - assert!(ig.matched("bar", false).is_whitelist()); - assert!(ig.matched("baz", false).is_none()); - } - - #[test] - fn custom_ignore() { - let td = TempDir::new("ignore-test-").unwrap(); - let custom_ignore = ".customignore"; - wfile(td.path().join(custom_ignore), "foo\n!bar"); - - let (ig, err) = IgnoreBuilder::new() - .add_custom_ignore_filename(custom_ignore) - .build().add_child(td.path()); - assert!(err.is_none()); - assert!(ig.matched("foo", false).is_ignore()); - assert!(ig.matched("bar", false).is_whitelist()); - assert!(ig.matched("baz", false).is_none()); - } - - // Tests that a custom ignore file will override an .ignore. - #[test] - fn custom_ignore_over_ignore() { - let td = TempDir::new("ignore-test-").unwrap(); - let custom_ignore = ".customignore"; - wfile(td.path().join(".ignore"), "foo"); - wfile(td.path().join(custom_ignore), "!foo"); - - let (ig, err) = IgnoreBuilder::new() - .add_custom_ignore_filename(custom_ignore) - .build().add_child(td.path()); - assert!(err.is_none()); - assert!(ig.matched("foo", false).is_whitelist()); - } - - // Tests that earlier custom ignore files have lower precedence than later. - #[test] - fn custom_ignore_precedence() { - let td = TempDir::new("ignore-test-").unwrap(); - let custom_ignore1 = ".customignore1"; - let custom_ignore2 = ".customignore2"; - wfile(td.path().join(custom_ignore1), "foo"); - wfile(td.path().join(custom_ignore2), "!foo"); - - let (ig, err) = IgnoreBuilder::new() - .add_custom_ignore_filename(custom_ignore1) - .add_custom_ignore_filename(custom_ignore2) - .build().add_child(td.path()); - assert!(err.is_none()); - assert!(ig.matched("foo", false).is_whitelist()); - } - - // Tests that an .ignore will override a .gitignore. - #[test] - fn ignore_over_gitignore() { - let td = TempDir::new("ignore-test-").unwrap(); - wfile(td.path().join(".gitignore"), "foo"); - wfile(td.path().join(".ignore"), "!foo"); - - let (ig, err) = IgnoreBuilder::new().build().add_child(td.path()); - assert!(err.is_none()); - assert!(ig.matched("foo", false).is_whitelist()); - } - - // Tests that exclude has lower precedent than both .ignore and .gitignore. - #[test] - fn exclude_lowest() { - let td = TempDir::new("ignore-test-").unwrap(); - wfile(td.path().join(".gitignore"), "!foo"); - wfile(td.path().join(".ignore"), "!bar"); - mkdirp(td.path().join(".git/info")); - wfile(td.path().join(".git/info/exclude"), "foo\nbar\nbaz"); - - let (ig, err) = IgnoreBuilder::new().build().add_child(td.path()); - assert!(err.is_none()); - assert!(ig.matched("baz", false).is_ignore()); - assert!(ig.matched("foo", false).is_whitelist()); - assert!(ig.matched("bar", false).is_whitelist()); - } - - #[test] - fn errored() { - let td = TempDir::new("ignore-test-").unwrap(); - wfile(td.path().join(".gitignore"), "f**oo"); - - let (_, err) = IgnoreBuilder::new().build().add_child(td.path()); - assert!(err.is_some()); - } - - #[test] - fn errored_both() { - let td = TempDir::new("ignore-test-").unwrap(); - wfile(td.path().join(".gitignore"), "f**oo"); - wfile(td.path().join(".ignore"), "fo**o"); - - let (_, err) = IgnoreBuilder::new().build().add_child(td.path()); - assert_eq!(2, partial(err.expect("an error")).len()); - } - - #[test] - fn errored_partial() { - let td = TempDir::new("ignore-test-").unwrap(); - wfile(td.path().join(".gitignore"), "f**oo\nbar"); - - let (ig, err) = IgnoreBuilder::new().build().add_child(td.path()); - assert!(err.is_some()); - assert!(ig.matched("bar", false).is_ignore()); - } - - #[test] - fn errored_partial_and_ignore() { - let td = TempDir::new("ignore-test-").unwrap(); - wfile(td.path().join(".gitignore"), "f**oo\nbar"); - wfile(td.path().join(".ignore"), "!bar"); - - let (ig, err) = IgnoreBuilder::new().build().add_child(td.path()); - assert!(err.is_some()); - assert!(ig.matched("bar", false).is_whitelist()); - } - - #[test] - fn not_present_empty() { - let td = TempDir::new("ignore-test-").unwrap(); - - let (_, err) = IgnoreBuilder::new().build().add_child(td.path()); - assert!(err.is_none()); - } - - #[test] - fn stops_at_git_dir() { - // This tests that .gitignore files beyond a .git barrier aren't - // matched, but .ignore files are. - let td = TempDir::new("ignore-test-").unwrap(); - mkdirp(td.path().join(".git")); - mkdirp(td.path().join("foo/.git")); - wfile(td.path().join(".gitignore"), "foo"); - wfile(td.path().join(".ignore"), "bar"); - - let ig0 = IgnoreBuilder::new().build(); - let (ig1, err) = ig0.add_child(td.path()); - assert!(err.is_none()); - let (ig2, err) = ig1.add_child(ig1.path().join("foo")); - assert!(err.is_none()); - - assert!(ig1.matched("foo", false).is_ignore()); - assert!(ig2.matched("foo", false).is_none()); - - assert!(ig1.matched("bar", false).is_ignore()); - assert!(ig2.matched("bar", false).is_ignore()); - } - - #[test] - fn absolute_parent() { - let td = TempDir::new("ignore-test-").unwrap(); - mkdirp(td.path().join(".git")); - mkdirp(td.path().join("foo")); - wfile(td.path().join(".gitignore"), "bar"); - - // First, check that the parent gitignore file isn't detected if the - // parent isn't added. This establishes a baseline. - let ig0 = IgnoreBuilder::new().build(); - let (ig1, err) = ig0.add_child(td.path().join("foo")); - assert!(err.is_none()); - assert!(ig1.matched("bar", false).is_none()); - - // Second, check that adding a parent directory actually works. - let ig0 = IgnoreBuilder::new().build(); - let (ig1, err) = ig0.add_parents(td.path().join("foo")); - assert!(err.is_none()); - let (ig2, err) = ig1.add_child(td.path().join("foo")); - assert!(err.is_none()); - assert!(ig2.matched("bar", false).is_ignore()); - } - - #[test] - fn absolute_parent_anchored() { - let td = TempDir::new("ignore-test-").unwrap(); - mkdirp(td.path().join(".git")); - mkdirp(td.path().join("src/llvm")); - wfile(td.path().join(".gitignore"), "/llvm/\nfoo"); - - let ig0 = IgnoreBuilder::new().build(); - let (ig1, err) = ig0.add_parents(td.path().join("src")); - assert!(err.is_none()); - let (ig2, err) = ig1.add_child("src"); - assert!(err.is_none()); - - assert!(ig1.matched("llvm", true).is_none()); - assert!(ig2.matched("llvm", true).is_none()); - assert!(ig2.matched("src/llvm", true).is_none()); - assert!(ig2.matched("foo", false).is_ignore()); - assert!(ig2.matched("src/foo", false).is_ignore()); - } -} diff --git a/ignore/src/gitignore.rs b/ignore/src/gitignore.rs deleted file mode 100644 index bcfe8b5..0000000 --- a/ignore/src/gitignore.rs +++ /dev/null @@ -1,729 +0,0 @@ -/*! -The gitignore module provides a way to match globs from a gitignore file -against file paths. - -Note that this module implements the specification as described in the -`gitignore` man page from scratch. That is, this module does *not* shell out to -the `git` command line tool. -*/ - -use std::cell::RefCell; -use std::env; -use std::fs::File; -use std::io::{self, BufRead, Read}; -use std::path::{Path, PathBuf}; -use std::str; -use std::sync::Arc; - -use globset::{Candidate, GlobBuilder, GlobSet, GlobSetBuilder}; -use regex::bytes::Regex; -use thread_local::ThreadLocal; - -use pathutil::{is_file_name, strip_prefix}; -use {Error, Match, PartialErrorBuilder}; - -/// Glob represents a single glob in a gitignore file. -/// -/// This is used to report information about the highest precedent glob that -/// matched in one or more gitignore files. -#[derive(Clone, Debug)] -pub struct Glob { - /// The file path that this glob was extracted from. - from: Option, - /// The original glob string. - original: String, - /// The actual glob string used to convert to a regex. - actual: String, - /// Whether this is a whitelisted glob or not. - is_whitelist: bool, - /// Whether this glob should only match directories or not. - is_only_dir: bool, -} - -impl Glob { - /// Returns the file path that defined this glob. - pub fn from(&self) -> Option<&Path> { - self.from.as_ref().map(|p| &**p) - } - - /// The original glob as it was defined in a gitignore file. - pub fn original(&self) -> &str { - &self.original - } - - /// The actual glob that was compiled to respect gitignore - /// semantics. - pub fn actual(&self) -> &str { - &self.actual - } - - /// Whether this was a whitelisted glob or not. - pub fn is_whitelist(&self) -> bool { - self.is_whitelist - } - - /// Whether this glob must match a directory or not. - pub fn is_only_dir(&self) -> bool { - self.is_only_dir - } - - /// Returns true if and only if this glob has a `**/` prefix. - fn has_doublestar_prefix(&self) -> bool { - self.actual.starts_with("**/") - || (self.actual == "**" && self.is_only_dir) - } -} - -/// Gitignore is a matcher for the globs in one or more gitignore files -/// in the same directory. -#[derive(Clone, Debug)] -pub struct Gitignore { - set: GlobSet, - root: PathBuf, - globs: Vec, - num_ignores: u64, - num_whitelists: u64, - matches: Option>>>>, -} - -impl Gitignore { - /// Creates a new gitignore matcher from the gitignore file path given. - /// - /// If it's desirable to include multiple gitignore files in a single - /// matcher, or read gitignore globs from a different source, then - /// use `GitignoreBuilder`. - /// - /// This always returns a valid matcher, even if it's empty. In particular, - /// a Gitignore file can be partially valid, e.g., when one glob is invalid - /// but the rest aren't. - /// - /// Note that I/O errors are ignored. For more granular control over - /// errors, use `GitignoreBuilder`. - pub fn new>( - gitignore_path: P, - ) -> (Gitignore, Option) { - let path = gitignore_path.as_ref(); - let parent = path.parent().unwrap_or(Path::new("/")); - let mut builder = GitignoreBuilder::new(parent); - let mut errs = PartialErrorBuilder::default(); - errs.maybe_push_ignore_io(builder.add(path)); - match builder.build() { - Ok(gi) => (gi, errs.into_error_option()), - Err(err) => { - errs.push(err); - (Gitignore::empty(), errs.into_error_option()) - } - } - } - - /// Creates a new gitignore matcher from the global ignore file, if one - /// exists. - /// - /// The global config file path is specified by git's `core.excludesFile` - /// config option. - /// - /// Git's config file location is `$HOME/.gitconfig`. If `$HOME/.gitconfig` - /// does not exist or does not specify `core.excludesFile`, then - /// `$XDG_CONFIG_HOME/git/ignore` is read. If `$XDG_CONFIG_HOME` is not - /// set or is empty, then `$HOME/.config/git/ignore` is used instead. - pub fn global() -> (Gitignore, Option) { - match gitconfig_excludes_path() { - None => (Gitignore::empty(), None), - Some(path) => { - if !path.is_file() { - (Gitignore::empty(), None) - } else { - Gitignore::new(path) - } - } - } - } - - /// Creates a new empty gitignore matcher that never matches anything. - /// - /// Its path is empty. - pub fn empty() -> Gitignore { - Gitignore { - set: GlobSet::empty(), - root: PathBuf::from(""), - globs: vec![], - num_ignores: 0, - num_whitelists: 0, - matches: None, - } - } - - /// Returns the directory containing this gitignore matcher. - /// - /// All matches are done relative to this path. - pub fn path(&self) -> &Path { - &*self.root - } - - /// Returns true if and only if this gitignore has zero globs, and - /// therefore never matches any file path. - pub fn is_empty(&self) -> bool { - self.set.is_empty() - } - - /// Returns the total number of globs, which should be equivalent to - /// `num_ignores + num_whitelists`. - pub fn len(&self) -> usize { - self.set.len() - } - - /// Returns the total number of ignore globs. - pub fn num_ignores(&self) -> u64 { - self.num_ignores - } - - /// Returns the total number of whitelisted globs. - pub fn num_whitelists(&self) -> u64 { - self.num_whitelists - } - - /// Returns whether the given path (file or directory) matched a pattern in - /// this gitignore matcher. - /// - /// `is_dir` should be true if the path refers to a directory and false - /// otherwise. - /// - /// The given path is matched relative to the path given when building - /// the matcher. Specifically, before matching `path`, its prefix (as - /// determined by a common suffix of the directory containing this - /// gitignore) is stripped. If there is no common suffix/prefix overlap, - /// then `path` is assumed to be relative to this matcher. - pub fn matched>( - &self, - path: P, - is_dir: bool, - ) -> Match<&Glob> { - if self.is_empty() { - return Match::None; - } - self.matched_stripped(self.strip(path.as_ref()), is_dir) - } - - /// Returns whether the given path (file or directory, and expected to be - /// under the root) or any of its parent directories (up to the root) - /// matched a pattern in this gitignore matcher. - /// - /// NOTE: This method is more expensive than walking the directory hierarchy - /// top-to-bottom and matching the entries. But, is easier to use in cases - /// when a list of paths are available without a hierarchy. - /// - /// `is_dir` should be true if the path refers to a directory and false - /// otherwise. - /// - /// The given path is matched relative to the path given when building - /// the matcher. Specifically, before matching `path`, its prefix (as - /// determined by a common suffix of the directory containing this - /// gitignore) is stripped. If there is no common suffix/prefix overlap, - /// then `path` is assumed to be relative to this matcher. - pub fn matched_path_or_any_parents>( - &self, - path: P, - is_dir: bool, - ) -> Match<&Glob> { - if self.is_empty() { - return Match::None; - } - let mut path = self.strip(path.as_ref()); - debug_assert!( - !path.has_root(), - "path is expect to be under the root" - ); - match self.matched_stripped(path, is_dir) { - Match::None => (), // walk up - a_match => return a_match, - } - while let Some(parent) = path.parent() { - match self.matched_stripped(parent, /* is_dir */ true) { - Match::None => path = parent, // walk up - a_match => return a_match, - } - } - Match::None - } - - /// Like matched, but takes a path that has already been stripped. - fn matched_stripped>( - &self, - path: P, - is_dir: bool, - ) -> Match<&Glob> { - if self.is_empty() { - return Match::None; - } - let path = path.as_ref(); - let _matches = self.matches.as_ref().unwrap().get_default(); - let mut matches = _matches.borrow_mut(); - let candidate = Candidate::new(path); - self.set.matches_candidate_into(&candidate, &mut *matches); - for &i in matches.iter().rev() { - let glob = &self.globs[i]; - if !glob.is_only_dir() || is_dir { - return if glob.is_whitelist() { - Match::Whitelist(glob) - } else { - Match::Ignore(glob) - }; - } - } - Match::None - } - - /// Strips the given path such that it's suitable for matching with this - /// gitignore matcher. - fn strip<'a, P: 'a + AsRef + ?Sized>( - &'a self, - path: &'a P, - ) -> &'a Path { - let mut path = path.as_ref(); - // A leading ./ is completely superfluous. We also strip it from - // our gitignore root path, so we need to strip it from our candidate - // path too. - if let Some(p) = strip_prefix("./", path) { - path = p; - } - // Strip any common prefix between the candidate path and the root - // of the gitignore, to make sure we get relative matching right. - // BUT, a file name might not have any directory components to it, - // in which case, we don't want to accidentally strip any part of the - // file name. - // - // As an additional special case, if the root is just `.`, then we - // shouldn't try to strip anything, e.g., when path begins with a `.`. - if self.root != Path::new(".") && !is_file_name(path) { - if let Some(p) = strip_prefix(&self.root, path) { - path = p; - // If we're left with a leading slash, get rid of it. - if let Some(p) = strip_prefix("/", path) { - path = p; - } - } - } - path - } -} - -/// Builds a matcher for a single set of globs from a .gitignore file. -#[derive(Clone, Debug)] -pub struct GitignoreBuilder { - builder: GlobSetBuilder, - root: PathBuf, - globs: Vec, - case_insensitive: bool, -} - -impl GitignoreBuilder { - /// Create a new builder for a gitignore file. - /// - /// The path given should be the path at which the globs for this gitignore - /// file should be matched. Note that paths are always matched relative - /// to the root path given here. Generally, the root path should correspond - /// to the *directory* containing a `.gitignore` file. - pub fn new>(root: P) -> GitignoreBuilder { - let root = root.as_ref(); - GitignoreBuilder { - builder: GlobSetBuilder::new(), - root: strip_prefix("./", root).unwrap_or(root).to_path_buf(), - globs: vec![], - case_insensitive: false, - } - } - - /// Builds a new matcher from the globs added so far. - /// - /// Once a matcher is built, no new globs can be added to it. - pub fn build(&self) -> Result { - let nignore = self.globs.iter().filter(|g| !g.is_whitelist()).count(); - let nwhite = self.globs.iter().filter(|g| g.is_whitelist()).count(); - let set = - self.builder.build().map_err(|err| { - Error::Glob { - glob: None, - err: err.to_string(), - } - })?; - Ok(Gitignore { - set: set, - root: self.root.clone(), - globs: self.globs.clone(), - num_ignores: nignore as u64, - num_whitelists: nwhite as u64, - matches: Some(Arc::new(ThreadLocal::default())), - }) - } - - /// Add each glob from the file path given. - /// - /// The file given should be formatted as a `gitignore` file. - /// - /// Note that partial errors can be returned. For example, if there was - /// a problem adding one glob, an error for that will be returned, but - /// all other valid globs will still be added. - pub fn add>(&mut self, path: P) -> Option { - let path = path.as_ref(); - let file = match File::open(path) { - Err(err) => return Some(Error::Io(err).with_path(path)), - Ok(file) => file, - }; - let rdr = io::BufReader::new(file); - let mut errs = PartialErrorBuilder::default(); - for (i, line) in rdr.lines().enumerate() { - let lineno = (i + 1) as u64; - let line = match line { - Ok(line) => line, - Err(err) => { - errs.push(Error::Io(err).tagged(path, lineno)); - break; - } - }; - if let Err(err) = self.add_line(Some(path.to_path_buf()), &line) { - errs.push(err.tagged(path, lineno)); - } - } - errs.into_error_option() - } - - /// Add each glob line from the string given. - /// - /// If this string came from a particular `gitignore` file, then its path - /// should be provided here. - /// - /// The string given should be formatted as a `gitignore` file. - #[cfg(test)] - fn add_str( - &mut self, - from: Option, - gitignore: &str, - ) -> Result<&mut GitignoreBuilder, Error> { - for line in gitignore.lines() { - self.add_line(from.clone(), line)?; - } - Ok(self) - } - - /// Add a line from a gitignore file to this builder. - /// - /// If this line came from a particular `gitignore` file, then its path - /// should be provided here. - /// - /// If the line could not be parsed as a glob, then an error is returned. - pub fn add_line( - &mut self, - from: Option, - mut line: &str, - ) -> Result<&mut GitignoreBuilder, Error> { - if line.starts_with("#") { - return Ok(self); - } - if !line.ends_with("\\ ") { - line = line.trim_right(); - } - if line.is_empty() { - return Ok(self); - } - let mut glob = Glob { - from: from, - original: line.to_string(), - actual: String::new(), - is_whitelist: false, - is_only_dir: false, - }; - let mut literal_separator = false; - let mut is_absolute = false; - if line.starts_with("\\!") || line.starts_with("\\#") { - line = &line[1..]; - is_absolute = line.chars().nth(0) == Some('/'); - } else { - if line.starts_with("!") { - glob.is_whitelist = true; - line = &line[1..]; - } - if line.starts_with("/") { - // `man gitignore` says that if a glob starts with a slash, - // then the glob can only match the beginning of a path - // (relative to the location of gitignore). We achieve this by - // simply banning wildcards from matching /. - literal_separator = true; - line = &line[1..]; - is_absolute = true; - } - } - // If it ends with a slash, then this should only match directories, - // but the slash should otherwise not be used while globbing. - if let Some((i, c)) = line.char_indices().rev().nth(0) { - if c == '/' { - glob.is_only_dir = true; - line = &line[..i]; - } - } - // If there is a literal slash, then we note that so that globbing - // doesn't let wildcards match slashes. - glob.actual = line.to_string(); - if is_absolute || line.chars().any(|c| c == '/') { - literal_separator = true; - } - // If there was a slash, then this is a glob that must match the entire - // path name. Otherwise, we should let it match anywhere, so use a **/ - // prefix. - if !literal_separator { - // ... but only if we don't already have a **/ prefix. - if !glob.has_doublestar_prefix() { - glob.actual = format!("**/{}", glob.actual); - } - } - // If the glob ends with `/**`, then we should only match everything - // inside a directory, but not the directory itself. Standard globs - // will match the directory. So we add `/*` to force the issue. - if glob.actual.ends_with("/**") { - glob.actual = format!("{}/*", glob.actual); - } - let parsed = - GlobBuilder::new(&glob.actual) - .literal_separator(literal_separator) - .case_insensitive(self.case_insensitive) - .backslash_escape(true) - .build() - .map_err(|err| { - Error::Glob { - glob: Some(glob.original.clone()), - err: err.kind().to_string(), - } - })?; - self.builder.add(parsed); - self.globs.push(glob); - Ok(self) - } - - /// Toggle whether the globs should be matched case insensitively or not. - /// - /// When this option is changed, only globs added after the change will be affected. - /// - /// This is disabled by default. - pub fn case_insensitive( - &mut self, yes: bool - ) -> Result<&mut GitignoreBuilder, Error> { - self.case_insensitive = yes; - Ok(self) - } -} - -/// Return the file path of the current environment's global gitignore file. -/// -/// Note that the file path returned may not exist. -fn gitconfig_excludes_path() -> Option { - gitconfig_contents() - .and_then(|data| parse_excludes_file(&data)) - .or_else(excludes_file_default) -} - -/// Returns the file contents of git's global config file, if one exists. -fn gitconfig_contents() -> Option> { - let home = match env::var_os("HOME") { - None => return None, - Some(home) => PathBuf::from(home), - }; - let mut file = match File::open(home.join(".gitconfig")) { - Err(_) => return None, - Ok(file) => io::BufReader::new(file), - }; - let mut contents = vec![]; - file.read_to_end(&mut contents).ok().map(|_| contents) -} - -/// Returns the default file path for a global .gitignore file. -/// -/// Specifically, this respects XDG_CONFIG_HOME. -fn excludes_file_default() -> Option { - // We're fine with using env::home_dir for now. Its bugs are, IMO, pretty - // minor corner cases. We should still probably eventually migrate to - // the `dirs` crate to get a proper implementation. - #![allow(deprecated)] - env::var_os("XDG_CONFIG_HOME") - .and_then(|x| if x.is_empty() { None } else { Some(PathBuf::from(x)) }) - .or_else(|| env::home_dir().map(|p| p.join(".config"))) - .map(|x| x.join("git/ignore")) -} - -/// Extract git's `core.excludesfile` config setting from the raw file contents -/// given. -fn parse_excludes_file(data: &[u8]) -> Option { - // N.B. This is the lazy approach, and isn't technically correct, but - // probably works in more circumstances. I guess we would ideally have - // a full INI parser. Yuck. - lazy_static! { - static ref RE: Regex = Regex::new( - r"(?ium)^\s*excludesfile\s*=\s*(.+)\s*$").unwrap(); - }; - let caps = match RE.captures(data) { - None => return None, - Some(caps) => caps, - }; - str::from_utf8(&caps[1]).ok().map(|s| PathBuf::from(expand_tilde(s))) -} - -/// Expands ~ in file paths to the value of $HOME. -fn expand_tilde(path: &str) -> String { - let home = match env::var("HOME") { - Err(_) => return path.to_string(), - Ok(home) => home, - }; - path.replace("~", &home) -} - -#[cfg(test)] -mod tests { - use std::path::Path; - use super::{Gitignore, GitignoreBuilder}; - - fn gi_from_str>(root: P, s: &str) -> Gitignore { - let mut builder = GitignoreBuilder::new(root); - builder.add_str(None, s).unwrap(); - builder.build().unwrap() - } - - macro_rules! ignored { - ($name:ident, $root:expr, $gi:expr, $path:expr) => { - ignored!($name, $root, $gi, $path, false); - }; - ($name:ident, $root:expr, $gi:expr, $path:expr, $is_dir:expr) => { - #[test] - fn $name() { - let gi = gi_from_str($root, $gi); - assert!(gi.matched($path, $is_dir).is_ignore()); - } - }; - } - - macro_rules! not_ignored { - ($name:ident, $root:expr, $gi:expr, $path:expr) => { - not_ignored!($name, $root, $gi, $path, false); - }; - ($name:ident, $root:expr, $gi:expr, $path:expr, $is_dir:expr) => { - #[test] - fn $name() { - let gi = gi_from_str($root, $gi); - assert!(!gi.matched($path, $is_dir).is_ignore()); - } - }; - } - - const ROOT: &'static str = "/home/foobar/rust/rg"; - - ignored!(ig1, ROOT, "months", "months"); - ignored!(ig2, ROOT, "*.lock", "Cargo.lock"); - ignored!(ig3, ROOT, "*.rs", "src/main.rs"); - ignored!(ig4, ROOT, "src/*.rs", "src/main.rs"); - ignored!(ig5, ROOT, "/*.c", "cat-file.c"); - ignored!(ig6, ROOT, "/src/*.rs", "src/main.rs"); - ignored!(ig7, ROOT, "!src/main.rs\n*.rs", "src/main.rs"); - ignored!(ig8, ROOT, "foo/", "foo", true); - ignored!(ig9, ROOT, "**/foo", "foo"); - ignored!(ig10, ROOT, "**/foo", "src/foo"); - ignored!(ig11, ROOT, "**/foo/**", "src/foo/bar"); - ignored!(ig12, ROOT, "**/foo/**", "wat/src/foo/bar/baz"); - ignored!(ig13, ROOT, "**/foo/bar", "foo/bar"); - ignored!(ig14, ROOT, "**/foo/bar", "src/foo/bar"); - ignored!(ig15, ROOT, "abc/**", "abc/x"); - ignored!(ig16, ROOT, "abc/**", "abc/x/y"); - ignored!(ig17, ROOT, "abc/**", "abc/x/y/z"); - ignored!(ig18, ROOT, "a/**/b", "a/b"); - ignored!(ig19, ROOT, "a/**/b", "a/x/b"); - ignored!(ig20, ROOT, "a/**/b", "a/x/y/b"); - ignored!(ig21, ROOT, r"\!xy", "!xy"); - ignored!(ig22, ROOT, r"\#foo", "#foo"); - ignored!(ig23, ROOT, "foo", "./foo"); - ignored!(ig24, ROOT, "target", "grep/target"); - ignored!(ig25, ROOT, "Cargo.lock", "./tabwriter-bin/Cargo.lock"); - ignored!(ig26, ROOT, "/foo/bar/baz", "./foo/bar/baz"); - ignored!(ig27, ROOT, "foo/", "xyz/foo", true); - ignored!(ig28, "./src", "/llvm/", "./src/llvm", true); - ignored!(ig29, ROOT, "node_modules/ ", "node_modules", true); - ignored!(ig30, ROOT, "**/", "foo/bar", true); - ignored!(ig31, ROOT, "path1/*", "path1/foo"); - ignored!(ig32, ROOT, ".a/b", ".a/b"); - ignored!(ig33, "./", ".a/b", ".a/b"); - ignored!(ig34, ".", ".a/b", ".a/b"); - ignored!(ig35, "./.", ".a/b", ".a/b"); - ignored!(ig36, "././", ".a/b", ".a/b"); - ignored!(ig37, "././.", ".a/b", ".a/b"); - ignored!(ig38, ROOT, "\\[", "["); - ignored!(ig39, ROOT, "\\?", "?"); - ignored!(ig40, ROOT, "\\*", "*"); - ignored!(ig41, ROOT, "\\a", "a"); - - not_ignored!(ignot1, ROOT, "amonths", "months"); - not_ignored!(ignot2, ROOT, "monthsa", "months"); - not_ignored!(ignot3, ROOT, "/src/*.rs", "src/grep/src/main.rs"); - not_ignored!(ignot4, ROOT, "/*.c", "mozilla-sha1/sha1.c"); - not_ignored!(ignot5, ROOT, "/src/*.rs", "src/grep/src/main.rs"); - not_ignored!(ignot6, ROOT, "*.rs\n!src/main.rs", "src/main.rs"); - not_ignored!(ignot7, ROOT, "foo/", "foo", false); - not_ignored!(ignot8, ROOT, "**/foo/**", "wat/src/afoo/bar/baz"); - not_ignored!(ignot9, ROOT, "**/foo/**", "wat/src/fooa/bar/baz"); - not_ignored!(ignot10, ROOT, "**/foo/bar", "foo/src/bar"); - not_ignored!(ignot11, ROOT, "#foo", "#foo"); - not_ignored!(ignot12, ROOT, "\n\n\n", "foo"); - not_ignored!(ignot13, ROOT, "foo/**", "foo", true); - not_ignored!( - ignot14, "./third_party/protobuf", "m4/ltoptions.m4", - "./third_party/protobuf/csharp/src/packages/repositories.config"); - not_ignored!(ignot15, ROOT, "!/bar", "foo/bar"); - not_ignored!(ignot16, ROOT, "*\n!**/", "foo", true); - not_ignored!(ignot17, ROOT, "src/*.rs", "src/grep/src/main.rs"); - not_ignored!(ignot18, ROOT, "path1/*", "path2/path1/foo"); - - fn bytes(s: &str) -> Vec { - s.to_string().into_bytes() - } - - fn path_string>(path: P) -> String { - path.as_ref().to_str().unwrap().to_string() - } - - #[test] - fn parse_excludes_file1() { - let data = bytes("[core]\nexcludesFile = /foo/bar"); - let got = super::parse_excludes_file(&data).unwrap(); - assert_eq!(path_string(got), "/foo/bar"); - } - - #[test] - fn parse_excludes_file2() { - let data = bytes("[core]\nexcludesFile = ~/foo/bar"); - let got = super::parse_excludes_file(&data).unwrap(); - assert_eq!(path_string(got), super::expand_tilde("~/foo/bar")); - } - - #[test] - fn parse_excludes_file3() { - let data = bytes("[core]\nexcludeFile = /foo/bar"); - assert!(super::parse_excludes_file(&data).is_none()); - } - - // See: https://github.com/BurntSushi/ripgrep/issues/106 - #[test] - fn regression_106() { - gi_from_str("/", " "); - } - - #[test] - fn case_insensitive() { - let gi = GitignoreBuilder::new(ROOT) - .case_insensitive(true).unwrap() - .add_str(None, "*.html").unwrap() - .build().unwrap(); - assert!(gi.matched("foo.html", false).is_ignore()); - assert!(gi.matched("foo.HTML", false).is_ignore()); - assert!(!gi.matched("foo.htm", false).is_ignore()); - assert!(!gi.matched("foo.HTM", false).is_ignore()); - } - - ignored!(cs1, ROOT, "*.html", "foo.html"); - not_ignored!(cs2, ROOT, "*.html", "foo.HTML"); - not_ignored!(cs3, ROOT, "*.html", "foo.htm"); - not_ignored!(cs4, ROOT, "*.html", "foo.HTM"); -} diff --git a/ignore/src/lib.rs b/ignore/src/lib.rs deleted file mode 100644 index b97e267..0000000 --- a/ignore/src/lib.rs +++ /dev/null @@ -1,444 +0,0 @@ -/*! -The ignore crate provides a fast recursive directory iterator that respects -various filters such as globs, file types and `.gitignore` files. The precise -matching rules and precedence is explained in the documentation for -`WalkBuilder`. - -Secondarily, this crate exposes gitignore and file type matchers for use cases -that demand more fine-grained control. - -# Example - -This example shows the most basic usage of this crate. This code will -recursively traverse the current directory while automatically filtering out -files and directories according to ignore globs found in files like -`.ignore` and `.gitignore`: - - -```rust,no_run -use ignore::Walk; - -for result in Walk::new("./") { - // Each item yielded by the iterator is either a directory entry or an - // error, so either print the path or the error. - match result { - Ok(entry) => println!("{}", entry.path().display()), - Err(err) => println!("ERROR: {}", err), - } -} -``` - -# Example: advanced - -By default, the recursive directory iterator will ignore hidden files and -directories. This can be disabled by building the iterator with `WalkBuilder`: - -```rust,no_run -use ignore::WalkBuilder; - -for result in WalkBuilder::new("./").hidden(false).build() { - println!("{:?}", result); -} -``` - -See the documentation for `WalkBuilder` for many other options. -*/ - -#![deny(missing_docs)] - -extern crate crossbeam; -extern crate globset; -#[macro_use] -extern crate lazy_static; -#[macro_use] -extern crate log; -extern crate memchr; -extern crate regex; -extern crate same_file; -#[cfg(test)] -extern crate tempdir; -extern crate thread_local; -extern crate walkdir; -#[cfg(windows)] -extern crate winapi; - -use std::error; -use std::fmt; -use std::io; -use std::path::{Path, PathBuf}; - -pub use walk::{DirEntry, Walk, WalkBuilder, WalkParallel, WalkState}; - -mod dir; -pub mod gitignore; -mod pathutil; -pub mod overrides; -pub mod types; -mod walk; - -/// Represents an error that can occur when parsing a gitignore file. -#[derive(Debug)] -pub enum Error { - /// A collection of "soft" errors. These occur when adding an ignore - /// file partially succeeded. - Partial(Vec), - /// An error associated with a specific line number. - WithLineNumber { - /// The line number. - line: u64, - /// The underlying error. - err: Box, - }, - /// An error associated with a particular file path. - WithPath { - /// The file path. - path: PathBuf, - /// The underlying error. - err: Box, - }, - /// An error associated with a particular directory depth when recursively - /// walking a directory. - WithDepth { - /// The directory depth. - depth: usize, - /// The underlying error. - err: Box, - }, - /// An error that occurs when a file loop is detected when traversing - /// symbolic links. - Loop { - /// The ancestor file path in the loop. - ancestor: PathBuf, - /// The child file path in the loop. - child: PathBuf, - }, - /// An error that occurs when doing I/O, such as reading an ignore file. - Io(io::Error), - /// An error that occurs when trying to parse a glob. - Glob { - /// The original glob that caused this error. This glob, when - /// available, always corresponds to the glob provided by an end user. - /// e.g., It is the glob as written in a `.gitignore` file. - /// - /// (This glob may be distinct from the glob that is actually - /// compiled, after accounting for `gitignore` semantics.) - glob: Option, - /// The underlying glob error as a string. - err: String, - }, - /// A type selection for a file type that is not defined. - UnrecognizedFileType(String), - /// A user specified file type definition could not be parsed. - InvalidDefinition, -} - -impl Clone for Error { - fn clone(&self) -> Error { - match *self { - Error::Partial(ref errs) => Error::Partial(errs.clone()), - Error::WithLineNumber { line, ref err } => { - Error::WithLineNumber { line: line, err: err.clone() } - } - Error::WithPath { ref path, ref err } => { - Error::WithPath { path: path.clone(), err: err.clone() } - } - Error::WithDepth { depth, ref err } => { - Error::WithDepth { depth: depth, err: err.clone() } - } - Error::Loop { ref ancestor, ref child } => { - Error::Loop { - ancestor: ancestor.clone(), - child: child.clone() - } - } - Error::Io(ref err) => { - match err.raw_os_error() { - Some(e) => Error::Io(io::Error::from_raw_os_error(e)), - None => { - Error::Io(io::Error::new(err.kind(), err.to_string())) - } - } - } - Error::Glob { ref glob, ref err } => { - Error::Glob { glob: glob.clone(), err: err.clone() } - } - Error::UnrecognizedFileType(ref err) => { - Error::UnrecognizedFileType(err.clone()) - } - Error::InvalidDefinition => Error::InvalidDefinition, - } - } -} - -impl Error { - /// Returns true if this is a partial error. - /// - /// A partial error occurs when only some operations failed while others - /// may have succeeded. For example, an ignore file may contain an invalid - /// glob among otherwise valid globs. - pub fn is_partial(&self) -> bool { - match *self { - Error::Partial(_) => true, - Error::WithLineNumber { ref err, .. } => err.is_partial(), - Error::WithPath { ref err, .. } => err.is_partial(), - Error::WithDepth { ref err, .. } => err.is_partial(), - _ => false, - } - } - - /// Returns true if this error is exclusively an I/O error. - pub fn is_io(&self) -> bool { - match *self { - Error::Partial(ref errs) => errs.len() == 1 && errs[0].is_io(), - Error::WithLineNumber { ref err, .. } => err.is_io(), - Error::WithPath { ref err, .. } => err.is_io(), - Error::WithDepth { ref err, .. } => err.is_io(), - Error::Loop { .. } => false, - Error::Io(_) => true, - Error::Glob { .. } => false, - Error::UnrecognizedFileType(_) => false, - Error::InvalidDefinition => false, - } - } - - /// Returns a depth associated with recursively walking a directory (if - /// this error was generated from a recursive directory iterator). - pub fn depth(&self) -> Option { - match *self { - Error::WithPath { ref err, .. } => err.depth(), - Error::WithDepth { depth, .. } => Some(depth), - _ => None, - } - } - - /// Turn an error into a tagged error with the given file path. - fn with_path>(self, path: P) -> Error { - Error::WithPath { - path: path.as_ref().to_path_buf(), - err: Box::new(self), - } - } - - /// Turn an error into a tagged error with the given depth. - fn with_depth(self, depth: usize) -> Error { - Error::WithDepth { - depth: depth, - err: Box::new(self), - } - } - - /// Turn an error into a tagged error with the given file path and line - /// number. If path is empty, then it is omitted from the error. - fn tagged>(self, path: P, lineno: u64) -> Error { - let errline = Error::WithLineNumber { - line: lineno, - err: Box::new(self), - }; - if path.as_ref().as_os_str().is_empty() { - return errline; - } - errline.with_path(path) - } - - /// Build an error from a walkdir error. - fn from_walkdir(err: walkdir::Error) -> Error { - let depth = err.depth(); - if let (Some(anc), Some(child)) = (err.loop_ancestor(), err.path()) { - return Error::WithDepth { - depth: depth, - err: Box::new(Error::Loop { - ancestor: anc.to_path_buf(), - child: child.to_path_buf(), - }), - }; - } - let path = err.path().map(|p| p.to_path_buf()); - let mut ig_err = Error::Io(io::Error::from(err)); - if let Some(path) = path { - ig_err = Error::WithPath { - path: path, - err: Box::new(ig_err), - }; - } - ig_err - } -} - -impl error::Error for Error { - fn description(&self) -> &str { - match *self { - Error::Partial(_) => "partial error", - Error::WithLineNumber { ref err, .. } => err.description(), - Error::WithPath { ref err, .. } => err.description(), - Error::WithDepth { ref err, .. } => err.description(), - Error::Loop { .. } => "file system loop found", - Error::Io(ref err) => err.description(), - Error::Glob { ref err, .. } => err, - Error::UnrecognizedFileType(_) => "unrecognized file type", - Error::InvalidDefinition => "invalid definition", - } - } -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Error::Partial(ref errs) => { - let msgs: Vec = - errs.iter().map(|err| err.to_string()).collect(); - write!(f, "{}", msgs.join("\n")) - } - Error::WithLineNumber { line, ref err } => { - write!(f, "line {}: {}", line, err) - } - Error::WithPath { ref path, ref err } => { - write!(f, "{}: {}", path.display(), err) - } - Error::WithDepth { ref err, .. } => err.fmt(f), - Error::Loop { ref ancestor, ref child } => { - write!(f, "File system loop found: \ - {} points to an ancestor {}", - child.display(), ancestor.display()) - } - Error::Io(ref err) => err.fmt(f), - Error::Glob { glob: None, ref err } => write!(f, "{}", err), - Error::Glob { glob: Some(ref glob), ref err } => { - write!(f, "error parsing glob '{}': {}", glob, err) - } - Error::UnrecognizedFileType(ref ty) => { - write!(f, "unrecognized file type: {}", ty) - } - Error::InvalidDefinition => { - write!(f, "invalid definition (format is type:glob, e.g., \ - html:*.html)") - } - } - } -} - -impl From for Error { - fn from(err: io::Error) -> Error { - Error::Io(err) - } -} - -#[derive(Debug, Default)] -struct PartialErrorBuilder(Vec); - -impl PartialErrorBuilder { - fn push(&mut self, err: Error) { - self.0.push(err); - } - - fn push_ignore_io(&mut self, err: Error) { - if !err.is_io() { - self.push(err); - } - } - - fn maybe_push(&mut self, err: Option) { - if let Some(err) = err { - self.push(err); - } - } - - fn maybe_push_ignore_io(&mut self, err: Option) { - if let Some(err) = err { - self.push_ignore_io(err); - } - } - - fn into_error_option(mut self) -> Option { - if self.0.is_empty() { - None - } else if self.0.len() == 1 { - Some(self.0.pop().unwrap()) - } else { - Some(Error::Partial(self.0)) - } - } -} - -/// The result of a glob match. -/// -/// The type parameter `T` typically refers to a type that provides more -/// information about a particular match. For example, it might identify -/// the specific gitignore file and the specific glob pattern that caused -/// the match. -#[derive(Clone, Debug)] -pub enum Match { - /// The path didn't match any glob. - None, - /// The highest precedent glob matched indicates the path should be - /// ignored. - Ignore(T), - /// The highest precedent glob matched indicates the path should be - /// whitelisted. - Whitelist(T), -} - -impl Match { - /// Returns true if the match result didn't match any globs. - pub fn is_none(&self) -> bool { - match *self { - Match::None => true, - Match::Ignore(_) | Match::Whitelist(_) => false, - } - } - - /// Returns true if the match result implies the path should be ignored. - pub fn is_ignore(&self) -> bool { - match *self { - Match::Ignore(_) => true, - Match::None | Match::Whitelist(_) => false, - } - } - - /// Returns true if the match result implies the path should be - /// whitelisted. - pub fn is_whitelist(&self) -> bool { - match *self { - Match::Whitelist(_) => true, - Match::None | Match::Ignore(_) => false, - } - } - - /// Inverts the match so that `Ignore` becomes `Whitelist` and - /// `Whitelist` becomes `Ignore`. A non-match remains the same. - pub fn invert(self) -> Match { - match self { - Match::None => Match::None, - Match::Ignore(t) => Match::Whitelist(t), - Match::Whitelist(t) => Match::Ignore(t), - } - } - - /// Return the value inside this match if it exists. - pub fn inner(&self) -> Option<&T> { - match *self { - Match::None => None, - Match::Ignore(ref t) => Some(t), - Match::Whitelist(ref t) => Some(t), - } - } - - /// Apply the given function to the value inside this match. - /// - /// If the match has no value, then return the match unchanged. - pub fn map U>(self, f: F) -> Match { - match self { - Match::None => Match::None, - Match::Ignore(t) => Match::Ignore(f(t)), - Match::Whitelist(t) => Match::Whitelist(f(t)), - } - } - - /// Return the match if it is not none. Otherwise, return other. - pub fn or(self, other: Self) -> Self { - if self.is_none() { - other - } else { - self - } - } -} diff --git a/ignore/src/overrides.rs b/ignore/src/overrides.rs deleted file mode 100644 index c63532a..0000000 --- a/ignore/src/overrides.rs +++ /dev/null @@ -1,259 +0,0 @@ -/*! -The overrides module provides a way to specify a set of override globs. -This provides functionality similar to `--include` or `--exclude` in command -line tools. -*/ - -use std::path::Path; - -use gitignore::{self, Gitignore, GitignoreBuilder}; -use {Error, Match}; - -/// Glob represents a single glob in an override matcher. -/// -/// This is used to report information about the highest precedent glob -/// that matched. -/// -/// Note that not all matches necessarily correspond to a specific glob. For -/// example, if there are one or more whitelist globs and a file path doesn't -/// match any glob in the set, then the file path is considered to be ignored. -/// -/// The lifetime `'a` refers to the lifetime of the matcher that produced -/// this glob. -#[derive(Clone, Debug)] -pub struct Glob<'a>(GlobInner<'a>); - -#[derive(Clone, Debug)] -enum GlobInner<'a> { - /// No glob matched, but the file path should still be ignored. - UnmatchedIgnore, - /// A glob matched. - Matched(&'a gitignore::Glob), -} - -impl<'a> Glob<'a> { - fn unmatched() -> Glob<'a> { - Glob(GlobInner::UnmatchedIgnore) - } -} - -/// Manages a set of overrides provided explicitly by the end user. -#[derive(Clone, Debug)] -pub struct Override(Gitignore); - -impl Override { - /// Returns an empty matcher that never matches any file path. - pub fn empty() -> Override { - Override(Gitignore::empty()) - } - - /// Returns the directory of this override set. - /// - /// All matches are done relative to this path. - pub fn path(&self) -> &Path { - self.0.path() - } - - /// Returns true if and only if this matcher is empty. - /// - /// When a matcher is empty, it will never match any file path. - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } - - /// Returns the total number of ignore globs. - pub fn num_ignores(&self) -> u64 { - self.0.num_whitelists() - } - - /// Returns the total number of whitelisted globs. - pub fn num_whitelists(&self) -> u64 { - self.0.num_ignores() - } - - /// Returns whether the given file path matched a pattern in this override - /// matcher. - /// - /// `is_dir` should be true if the path refers to a directory and false - /// otherwise. - /// - /// If there are no overrides, then this always returns `Match::None`. - /// - /// If there is at least one whitelist override and `is_dir` is false, then - /// this never returns `Match::None`, since non-matches are interpreted as - /// ignored. - /// - /// The given path is matched to the globs relative to the path given - /// when building the override matcher. Specifically, before matching - /// `path`, its prefix (as determined by a common suffix of the directory - /// given) is stripped. If there is no common suffix/prefix overlap, then - /// `path` is assumed to reside in the same directory as the root path for - /// this set of overrides. - pub fn matched<'a, P: AsRef>( - &'a self, - path: P, - is_dir: bool, - ) -> Match> { - if self.is_empty() { - return Match::None; - } - let mat = self.0.matched(path, is_dir).invert(); - if mat.is_none() && self.num_whitelists() > 0 && !is_dir { - return Match::Ignore(Glob::unmatched()); - } - mat.map(move |giglob| Glob(GlobInner::Matched(giglob))) - } -} - -/// Builds a matcher for a set of glob overrides. -pub struct OverrideBuilder { - builder: GitignoreBuilder, -} - -impl OverrideBuilder { - /// Create a new override builder. - /// - /// Matching is done relative to the directory path provided. - pub fn new>(path: P) -> OverrideBuilder { - OverrideBuilder { - builder: GitignoreBuilder::new(path), - } - } - - /// Builds a new override matcher from the globs added so far. - /// - /// Once a matcher is built, no new globs can be added to it. - pub fn build(&self) -> Result { - Ok(Override(self.builder.build()?)) - } - - /// Add a glob to the set of overrides. - /// - /// Globs provided here have precisely the same semantics as a single - /// line in a `gitignore` file, where the meaning of `!` is inverted: - /// namely, `!` at the beginning of a glob will ignore a file. Without `!`, - /// all matches of the glob provided are treated as whitelist matches. - pub fn add(&mut self, glob: &str) -> Result<&mut OverrideBuilder, Error> { - self.builder.add_line(None, glob)?; - Ok(self) - } - - /// Toggle whether the globs should be matched case insensitively or not. - /// - /// When this option is changed, only globs added after the change will be affected. - /// - /// This is disabled by default. - pub fn case_insensitive( - &mut self, yes: bool - ) -> Result<&mut OverrideBuilder, Error> { - self.builder.case_insensitive(yes)?; - Ok(self) - } -} - -#[cfg(test)] -mod tests { - use super::{Override, OverrideBuilder}; - - const ROOT: &'static str = "/home/andrew/foo"; - - fn ov(globs: &[&str]) -> Override { - let mut builder = OverrideBuilder::new(ROOT); - for glob in globs { - builder.add(glob).unwrap(); - } - builder.build().unwrap() - } - - #[test] - fn empty() { - let ov = ov(&[]); - assert!(ov.matched("a.foo", false).is_none()); - assert!(ov.matched("a", false).is_none()); - assert!(ov.matched("", false).is_none()); - } - - #[test] - fn simple() { - let ov = ov(&["*.foo", "!*.bar"]); - assert!(ov.matched("a.foo", false).is_whitelist()); - assert!(ov.matched("a.foo", true).is_whitelist()); - assert!(ov.matched("a.rs", false).is_ignore()); - assert!(ov.matched("a.rs", true).is_none()); - assert!(ov.matched("a.bar", false).is_ignore()); - assert!(ov.matched("a.bar", true).is_ignore()); - } - - #[test] - fn only_ignores() { - let ov = ov(&["!*.bar"]); - assert!(ov.matched("a.rs", false).is_none()); - assert!(ov.matched("a.rs", true).is_none()); - assert!(ov.matched("a.bar", false).is_ignore()); - assert!(ov.matched("a.bar", true).is_ignore()); - } - - #[test] - fn precedence() { - let ov = ov(&["*.foo", "!*.bar.foo"]); - assert!(ov.matched("a.foo", false).is_whitelist()); - assert!(ov.matched("a.baz", false).is_ignore()); - assert!(ov.matched("a.bar.foo", false).is_ignore()); - } - - #[test] - fn gitignore() { - let ov = ov(&["/foo", "bar/*.rs", "baz/**"]); - assert!(ov.matched("bar/lib.rs", false).is_whitelist()); - assert!(ov.matched("bar/wat/lib.rs", false).is_ignore()); - assert!(ov.matched("wat/bar/lib.rs", false).is_ignore()); - assert!(ov.matched("foo", false).is_whitelist()); - assert!(ov.matched("wat/foo", false).is_ignore()); - assert!(ov.matched("baz", false).is_ignore()); - assert!(ov.matched("baz/a", false).is_whitelist()); - assert!(ov.matched("baz/a/b", false).is_whitelist()); - } - - #[test] - fn allow_directories() { - // This tests that directories are NOT ignored when they are unmatched. - let ov = ov(&["*.rs"]); - assert!(ov.matched("foo.rs", false).is_whitelist()); - assert!(ov.matched("foo.c", false).is_ignore()); - assert!(ov.matched("foo", false).is_ignore()); - assert!(ov.matched("foo", true).is_none()); - assert!(ov.matched("src/foo.rs", false).is_whitelist()); - assert!(ov.matched("src/foo.c", false).is_ignore()); - assert!(ov.matched("src/foo", false).is_ignore()); - assert!(ov.matched("src/foo", true).is_none()); - } - - #[test] - fn absolute_path() { - let ov = ov(&["!/bar"]); - assert!(ov.matched("./foo/bar", false).is_none()); - } - - #[test] - fn case_insensitive() { - let ov = OverrideBuilder::new(ROOT) - .case_insensitive(true).unwrap() - .add("*.html").unwrap() - .build().unwrap(); - assert!(ov.matched("foo.html", false).is_whitelist()); - assert!(ov.matched("foo.HTML", false).is_whitelist()); - assert!(ov.matched("foo.htm", false).is_ignore()); - assert!(ov.matched("foo.HTM", false).is_ignore()); - } - - #[test] - fn default_case_sensitive() { - let ov = OverrideBuilder::new(ROOT) - .add("*.html").unwrap() - .build().unwrap(); - assert!(ov.matched("foo.html", false).is_whitelist()); - assert!(ov.matched("foo.HTML", false).is_ignore()); - assert!(ov.matched("foo.htm", false).is_ignore()); - assert!(ov.matched("foo.HTM", false).is_ignore()); - } -} diff --git a/ignore/src/pathutil.rs b/ignore/src/pathutil.rs deleted file mode 100644 index bfd43de..0000000 --- a/ignore/src/pathutil.rs +++ /dev/null @@ -1,108 +0,0 @@ -use std::ffi::OsStr; -use std::path::Path; - -/// Returns true if and only if this file path is considered to be hidden. -#[cfg(unix)] -pub fn is_hidden>(path: P) -> bool { - use std::os::unix::ffi::OsStrExt; - - if let Some(name) = file_name(path.as_ref()) { - name.as_bytes().get(0) == Some(&b'.') - } else { - false - } -} - -/// Returns true if and only if this file path is considered to be hidden. -#[cfg(not(unix))] -pub fn is_hidden>(path: P) -> bool { - if let Some(name) = file_name(path.as_ref()) { - name.to_str().map(|s| s.starts_with(".")).unwrap_or(false) - } else { - false - } -} - -/// Strip `prefix` from the `path` and return the remainder. -/// -/// If `path` doesn't have a prefix `prefix`, then return `None`. -#[cfg(unix)] -pub fn strip_prefix<'a, P: AsRef + ?Sized>( - prefix: &'a P, - path: &'a Path, -) -> Option<&'a Path> { - use std::os::unix::ffi::OsStrExt; - - let prefix = prefix.as_ref().as_os_str().as_bytes(); - let path = path.as_os_str().as_bytes(); - if prefix.len() > path.len() || prefix != &path[0..prefix.len()] { - None - } else { - Some(&Path::new(OsStr::from_bytes(&path[prefix.len()..]))) - } -} - -/// Strip `prefix` from the `path` and return the remainder. -/// -/// If `path` doesn't have a prefix `prefix`, then return `None`. -#[cfg(not(unix))] -pub fn strip_prefix<'a, P: AsRef + ?Sized>( - prefix: &'a P, - path: &'a Path, -) -> Option<&'a Path> { - path.strip_prefix(prefix).ok() -} - -/// Returns true if this file path is just a file name. i.e., Its parent is -/// the empty string. -#[cfg(unix)] -pub fn is_file_name>(path: P) -> bool { - use std::os::unix::ffi::OsStrExt; - use memchr::memchr; - - let path = path.as_ref().as_os_str().as_bytes(); - memchr(b'/', path).is_none() -} - -/// Returns true if this file path is just a file name. i.e., Its parent is -/// the empty string. -#[cfg(not(unix))] -pub fn is_file_name>(path: P) -> bool { - path.as_ref().parent().map(|p| p.as_os_str().is_empty()).unwrap_or(false) -} - -/// The final component of the path, if it is a normal file. -/// -/// If the path terminates in ., .., or consists solely of a root of prefix, -/// file_name will return None. -#[cfg(unix)] -pub fn file_name<'a, P: AsRef + ?Sized>( - path: &'a P, -) -> Option<&'a OsStr> { - use std::os::unix::ffi::OsStrExt; - use memchr::memrchr; - - let path = path.as_ref().as_os_str().as_bytes(); - if path.is_empty() { - return None; - } else if path.len() == 1 && path[0] == b'.' { - return None; - } else if path.last() == Some(&b'.') { - return None; - } else if path.len() >= 2 && &path[path.len() - 2..] == &b".."[..] { - return None; - } - let last_slash = memrchr(b'/', path).map(|i| i + 1).unwrap_or(0); - Some(OsStr::from_bytes(&path[last_slash..])) -} - -/// The final component of the path, if it is a normal file. -/// -/// If the path terminates in ., .., or consists solely of a root of prefix, -/// file_name will return None. -#[cfg(not(unix))] -pub fn file_name<'a, P: AsRef + ?Sized>( - path: &'a P, -) -> Option<&'a OsStr> { - path.as_ref().file_name() -} diff --git a/ignore/src/types.rs b/ignore/src/types.rs deleted file mode 100644 index 3f96f8e..0000000 --- a/ignore/src/types.rs +++ /dev/null @@ -1,780 +0,0 @@ -/*! -The types module provides a way of associating globs on file names to file -types. - -This can be used to match specific types of files. For example, among -the default file types provided, the Rust file type is defined to be `*.rs` -with name `rust`. Similarly, the C file type is defined to be `*.{c,h}` with -name `c`. - -Note that the set of default types may change over time. - -# Example - -This shows how to create and use a simple file type matcher using the default -file types defined in this crate. - -``` -use ignore::types::TypesBuilder; - -let mut builder = TypesBuilder::new(); -builder.add_defaults(); -builder.select("rust"); -let matcher = builder.build().unwrap(); - -assert!(matcher.matched("foo.rs", false).is_whitelist()); -assert!(matcher.matched("foo.c", false).is_ignore()); -``` - -# Example: negation - -This is like the previous example, but shows how negating a file type works. -That is, this will let us match file paths that *don't* correspond to a -particular file type. - -``` -use ignore::types::TypesBuilder; - -let mut builder = TypesBuilder::new(); -builder.add_defaults(); -builder.negate("c"); -let matcher = builder.build().unwrap(); - -assert!(matcher.matched("foo.rs", false).is_none()); -assert!(matcher.matched("foo.c", false).is_ignore()); -``` - -# Example: custom file type definitions - -This shows how to extend this library default file type definitions with -your own. - -``` -use ignore::types::TypesBuilder; - -let mut builder = TypesBuilder::new(); -builder.add_defaults(); -builder.add("foo", "*.foo"); -// Another way of adding a file type definition. -// This is useful when accepting input from an end user. -builder.add_def("bar:*.bar"); -// Note: we only select `foo`, not `bar`. -builder.select("foo"); -let matcher = builder.build().unwrap(); - -assert!(matcher.matched("x.foo", false).is_whitelist()); -// This is ignored because we only selected the `foo` file type. -assert!(matcher.matched("x.bar", false).is_ignore()); -``` - -We can also add file type definitions based on other definitions. - -``` -use ignore::types::TypesBuilder; - -let mut builder = TypesBuilder::new(); -builder.add_defaults(); -builder.add("foo", "*.foo"); -builder.add_def("bar:include:foo,cpp"); -builder.select("bar"); -let matcher = builder.build().unwrap(); - -assert!(matcher.matched("x.foo", false).is_whitelist()); -assert!(matcher.matched("y.cpp", false).is_whitelist()); -``` -*/ - -use std::cell::RefCell; -use std::collections::HashMap; -use std::path::Path; -use std::sync::Arc; - -use globset::{GlobBuilder, GlobSet, GlobSetBuilder}; -use regex::Regex; -use thread_local::ThreadLocal; - -use pathutil::file_name; -use {Error, Match}; - -const DEFAULT_TYPES: &'static [(&'static str, &'static [&'static str])] = &[ - ("agda", &["*.agda", "*.lagda"]), - ("aidl", &["*.aidl"]), - ("amake", &["*.mk", "*.bp"]), - ("asciidoc", &["*.adoc", "*.asc", "*.asciidoc"]), - ("asm", &["*.asm", "*.s", "*.S"]), - ("avro", &["*.avdl", "*.avpr", "*.avsc"]), - ("awk", &["*.awk"]), - ("bazel", &["*.bzl", "WORKSPACE", "BUILD"]), - ("bitbake", &["*.bb", "*.bbappend", "*.bbclass", "*.conf", "*.inc"]), - ("bzip2", &["*.bz2"]), - ("c", &["*.c", "*.h", "*.H"]), - ("cabal", &["*.cabal"]), - ("cbor", &["*.cbor"]), - ("ceylon", &["*.ceylon"]), - ("clojure", &["*.clj", "*.cljc", "*.cljs", "*.cljx"]), - ("cmake", &["*.cmake", "CMakeLists.txt"]), - ("coffeescript", &["*.coffee"]), - ("creole", &["*.creole"]), - ("config", &["*.cfg", "*.conf", "*.config", "*.ini"]), - ("cpp", &[ - "*.C", "*.cc", "*.cpp", "*.cxx", - "*.h", "*.H", "*.hh", "*.hpp", "*.hxx", "*.inl", - ]), - ("crystal", &["Projectfile", "*.cr"]), - ("cs", &["*.cs"]), - ("csharp", &["*.cs"]), - ("cshtml", &["*.cshtml"]), - ("css", &["*.css", "*.scss"]), - ("csv", &["*.csv"]), - ("cython", &["*.pyx"]), - ("dart", &["*.dart"]), - ("d", &["*.d"]), - ("docker", &["*Dockerfile*"]), - ("elisp", &["*.el"]), - ("elixir", &["*.ex", "*.eex", "*.exs"]), - ("elm", &["*.elm"]), - ("erlang", &["*.erl", "*.hrl"]), - ("fidl", &["*.fidl"]), - ("fish", &["*.fish"]), - ("fortran", &[ - "*.f", "*.F", "*.f77", "*.F77", "*.pfo", - "*.f90", "*.F90", "*.f95", "*.F95", - ]), - ("fsharp", &["*.fs", "*.fsx", "*.fsi"]), - ("gn", &["*.gn", "*.gni"]), - ("go", &["*.go"]), - ("gzip", &["*.gz"]), - ("groovy", &["*.groovy", "*.gradle"]), - ("h", &["*.h", "*.hpp"]), - ("hbs", &["*.hbs"]), - ("haskell", &["*.hs", "*.lhs"]), - ("hs", &["*.hs", "*.lhs"]), - ("html", &["*.htm", "*.html", "*.ejs"]), - ("java", &["*.java", "*.jsp"]), - ("jinja", &["*.j2", "*.jinja", "*.jinja2"]), - ("js", &[ - "*.js", "*.jsx", "*.vue", - ]), - ("json", &["*.json", "composer.lock"]), - ("jsonl", &["*.jsonl"]), - ("julia", &["*.jl"]), - ("jupyter", &["*.ipynb", "*.jpynb"]), - ("jl", &["*.jl"]), - ("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"]), - ("log", &["*.log"]), - ("lua", &["*.lua"]), - ("lzma", &["*.lzma"]), - ("m4", &["*.ac", "*.m4"]), - ("make", &[ - "gnumakefile", "Gnumakefile", "GNUmakefile", - "makefile", "Makefile", - "*.mk", "*.mak" - ]), - ("markdown", &["*.markdown", "*.md", "*.mdown", "*.mkdn"]), - ("md", &["*.markdown", "*.md", "*.mdown", "*.mkdn"]), - ("man", &["*.[0-9lnpx]", "*.[0-9][cEFMmpSx]"]), - ("matlab", &["*.m"]), - ("mk", &["mkfile"]), - ("ml", &["*.ml"]), - ("msbuild", &[ - "*.csproj", "*.fsproj", "*.vcxproj", "*.proj", "*.props", "*.targets" - ]), - ("nim", &["*.nim"]), - ("nix", &["*.nix"]), - ("objc", &["*.h", "*.m"]), - ("objcpp", &["*.h", "*.mm"]), - ("ocaml", &["*.ml", "*.mli", "*.mll", "*.mly"]), - ("org", &["*.org"]), - ("perl", &["*.perl", "*.pl", "*.PL", "*.plh", "*.plx", "*.pm", "*.t"]), - ("pdf", &["*.pdf"]), - ("php", &["*.php", "*.php3", "*.php4", "*.php5", "*.phtml"]), - ("pod", &["*.pod"]), - ("protobuf", &["*.proto"]), - ("ps", &["*.cdxml", "*.ps1", "*.ps1xml", "*.psd1", "*.psm1"]), - ("puppet", &["*.erb", "*.pp", "*.rb"]), - ("purs", &["*.purs"]), - ("py", &["*.py"]), - ("qmake", &["*.pro", "*.pri", "*.prf"]), - ("readme", &["README*", "*README"]), - ("r", &["*.R", "*.r", "*.Rmd", "*.Rnw"]), - ("rdoc", &["*.rdoc"]), - ("rst", &["*.rst"]), - ("ruby", &["Gemfile", "*.gemspec", ".irbrc", "Rakefile", "*.rb"]), - ("rust", &["*.rs"]), - ("sass", &["*.sass", "*.scss"]), - ("scala", &["*.scala"]), - ("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", - ]), - ("smarty", &["*.tpl"]), - ("sml", &["*.sml", "*.sig"]), - ("soy", &["*.soy"]), - ("spark", &["*.spark"]), - ("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"]), - ("textile", &["*.textile"]), - ("tf", &["*.tf"]), - ("ts", &["*.ts", "*.tsx"]), - ("txt", &["*.txt"]), - ("toml", &["*.toml", "Cargo.lock"]), - ("twig", &["*.twig"]), - ("vala", &["*.vala"]), - ("vb", &["*.vb"]), - ("verilog", &["*.v", "*.vh", "*.sv", "*.svh"]), - ("vhdl", &["*.vhd", "*.vhdl"]), - ("vim", &["*.vim"]), - ("vimscript", &["*.vim"]), - ("wiki", &["*.mediawiki", "*.wiki"]), - ("webidl", &["*.idl", "*.webidl", "*.widl"]), - ("xml", &["*.xml", "*.xml.dist"]), - ("xz", &["*.xz"]), - ("yacc", &["*.y"]), - ("yaml", &["*.yaml", "*.yml"]), - ("zsh", &[ - ".zshenv", "zshenv", - ".zlogin", "zlogin", - ".zlogout", "zlogout", - ".zprofile", "zprofile", - ".zshrc", "zshrc", - "*.zsh", - ]), -]; - -/// Glob represents a single glob in a set of file type definitions. -/// -/// There may be more than one glob for a particular file type. -/// -/// This is used to report information about the highest precedent glob -/// that matched. -/// -/// Note that not all matches necessarily correspond to a specific glob. -/// For example, if there are one or more selections and a file path doesn't -/// match any of those selections, then the file path is considered to be -/// ignored. -/// -/// The lifetime `'a` refers to the lifetime of the underlying file type -/// definition, which corresponds to the lifetime of the file type matcher. -#[derive(Clone, Debug)] -pub struct Glob<'a>(GlobInner<'a>); - -#[derive(Clone, Debug)] -enum GlobInner<'a> { - /// No glob matched, but the file path should still be ignored. - UnmatchedIgnore, - /// A glob matched. - Matched { - /// The file type definition which provided the glob. - def: &'a FileTypeDef, - /// The index of the glob that matched inside the file type definition. - which: usize, - /// Whether the selection was negated or not. - negated: bool, - } -} - -impl<'a> Glob<'a> { - fn unmatched() -> Glob<'a> { - Glob(GlobInner::UnmatchedIgnore) - } -} - -/// A single file type definition. -/// -/// File type definitions can be retrieved in aggregate from a file type -/// matcher. File type definitions are also reported when its responsible -/// for a match. -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct FileTypeDef { - name: String, - globs: Vec, -} - -impl FileTypeDef { - /// Return the name of this file type. - pub fn name(&self) -> &str { - &self.name - } - - /// Return the globs used to recognize this file type. - pub fn globs(&self) -> &[String] { - &self.globs - } -} - -/// Types is a file type matcher. -#[derive(Clone, Debug)] -pub struct Types { - /// All of the file type definitions, sorted lexicographically by name. - defs: Vec, - /// All of the selections made by the user. - selections: Vec>, - /// Whether there is at least one Selection::Select in our selections. - /// When this is true, a Match::None is converted to Match::Ignore. - has_selected: bool, - /// A mapping from glob index in the set to two indices. The first is an - /// index into `selections` and the second is an index into the - /// corresponding file type definition's list of globs. - glob_to_selection: Vec<(usize, usize)>, - /// The set of all glob selections, used for actual matching. - set: GlobSet, - /// Temporary storage for globs that match. - matches: Arc>>>, -} - -/// Indicates the type of a selection for a particular file type. -#[derive(Clone, Debug)] -enum Selection { - Select(String, T), - Negate(String, T), -} - -impl Selection { - fn is_negated(&self) -> bool { - match *self { - Selection::Select(..) => false, - Selection::Negate(..) => true, - } - } - - fn name(&self) -> &str { - match *self { - Selection::Select(ref name, _) => name, - Selection::Negate(ref name, _) => name, - } - } - - fn map U>(self, f: F) -> Selection { - match self { - Selection::Select(name, inner) => { - Selection::Select(name, f(inner)) - } - Selection::Negate(name, inner) => { - Selection::Negate(name, f(inner)) - } - } - } - - fn inner(&self) -> &T { - match *self { - Selection::Select(_, ref inner) => inner, - Selection::Negate(_, ref inner) => inner, - } - } -} - -impl Types { - /// Creates a new file type matcher that never matches any path and - /// contains no file type definitions. - pub fn empty() -> Types { - Types { - defs: vec![], - selections: vec![], - has_selected: false, - glob_to_selection: vec![], - set: GlobSetBuilder::new().build().unwrap(), - matches: Arc::new(ThreadLocal::default()), - } - } - - /// Returns true if and only if this matcher has zero selections. - pub fn is_empty(&self) -> bool { - self.selections.is_empty() - } - - /// Returns the number of selections used in this matcher. - pub fn len(&self) -> usize { - self.selections.len() - } - - /// Return the set of current file type definitions. - /// - /// Definitions and globs are sorted. - pub fn definitions(&self) -> &[FileTypeDef] { - &self.defs - } - - /// Returns a match for the given path against this file type matcher. - /// - /// The path is considered whitelisted if it matches a selected file type. - /// The path is considered ignored if it matches a negated file type. - /// If at least one file type is selected and `path` doesn't match, then - /// the path is also considered ignored. - pub fn matched<'a, P: AsRef>( - &'a self, - path: P, - is_dir: bool, - ) -> Match> { - // File types don't apply to directories, and we can't do anything - // if our glob set is empty. - if is_dir || self.set.is_empty() { - return Match::None; - } - // We only want to match against the file name, so extract it. - // If one doesn't exist, then we can't match it. - let name = match file_name(path.as_ref()) { - Some(name) => name, - None if self.has_selected => { - return Match::Ignore(Glob::unmatched()); - } - None => { - return Match::None; - } - }; - let mut matches = self.matches.get_default().borrow_mut(); - self.set.matches_into(name, &mut *matches); - // The highest precedent match is the last one. - if let Some(&i) = matches.last() { - let (isel, iglob) = self.glob_to_selection[i]; - let sel = &self.selections[isel]; - let glob = Glob(GlobInner::Matched { - def: sel.inner(), - which: iglob, - negated: sel.is_negated(), - }); - return if sel.is_negated() { - Match::Ignore(glob) - } else { - Match::Whitelist(glob) - }; - } - if self.has_selected { - Match::Ignore(Glob::unmatched()) - } else { - Match::None - } - } -} - -/// TypesBuilder builds a type matcher from a set of file type definitions and -/// a set of file type selections. -pub struct TypesBuilder { - types: HashMap, - selections: Vec>, -} - -impl TypesBuilder { - /// Create a new builder for a file type matcher. - /// - /// The builder contains *no* type definitions to start with. A set - /// of default type definitions can be added with `add_defaults`, and - /// additional type definitions can be added with `select` and `negate`. - pub fn new() -> TypesBuilder { - TypesBuilder { - types: HashMap::new(), - selections: vec![], - } - } - - /// Build the current set of file type definitions *and* selections into - /// a file type matcher. - pub fn build(&self) -> Result { - let defs = self.definitions(); - let has_selected = self.selections.iter().any(|s| !s.is_negated()); - - let mut selections = vec![]; - let mut glob_to_selection = vec![]; - let mut build_set = GlobSetBuilder::new(); - for (isel, selection) in self.selections.iter().enumerate() { - let def = match self.types.get(selection.name()) { - Some(def) => def.clone(), - None => { - let name = selection.name().to_string(); - return Err(Error::UnrecognizedFileType(name)); - } - }; - for (iglob, glob) in def.globs.iter().enumerate() { - build_set.add( - GlobBuilder::new(glob) - .literal_separator(true) - .build() - .map_err(|err| { - Error::Glob { - glob: Some(glob.to_string()), - err: err.kind().to_string(), - } - })?); - glob_to_selection.push((isel, iglob)); - } - selections.push(selection.clone().map(move |_| def)); - } - let set = build_set.build().map_err(|err| { - Error::Glob { glob: None, err: err.to_string() } - })?; - Ok(Types { - defs: defs, - selections: selections, - has_selected: has_selected, - glob_to_selection: glob_to_selection, - set: set, - matches: Arc::new(ThreadLocal::default()), - }) - } - - /// Return the set of current file type definitions. - /// - /// Definitions and globs are sorted. - pub fn definitions(&self) -> Vec { - let mut defs = vec![]; - for def in self.types.values() { - let mut def = def.clone(); - def.globs.sort(); - defs.push(def); - } - defs.sort_by(|def1, def2| def1.name().cmp(def2.name())); - defs - } - - /// Select the file type given by `name`. - /// - /// If `name` is `all`, then all file types currently defined are selected. - pub fn select(&mut self, name: &str) -> &mut TypesBuilder { - if name == "all" { - for name in self.types.keys() { - self.selections.push(Selection::Select(name.to_string(), ())); - } - } else { - self.selections.push(Selection::Select(name.to_string(), ())); - } - self - } - - /// Ignore the file type given by `name`. - /// - /// If `name` is `all`, then all file types currently defined are negated. - pub fn negate(&mut self, name: &str) -> &mut TypesBuilder { - if name == "all" { - for name in self.types.keys() { - self.selections.push(Selection::Negate(name.to_string(), ())); - } - } else { - self.selections.push(Selection::Negate(name.to_string(), ())); - } - self - } - - /// Clear any file type definitions for the type name given. - pub fn clear(&mut self, name: &str) -> &mut TypesBuilder { - self.types.remove(name); - self - } - - /// Add a new file type definition. `name` can be arbitrary and `pat` - /// should be a glob recognizing file paths belonging to the `name` type. - /// - /// If `name` is `all` or otherwise contains any character that is not a - /// Unicode letter or number, then an error is returned. - pub fn add(&mut self, name: &str, glob: &str) -> Result<(), Error> { - lazy_static! { - static ref RE: Regex = Regex::new(r"^[\pL\pN]+$").unwrap(); - }; - if name == "all" || !RE.is_match(name) { - return Err(Error::InvalidDefinition); - } - let (key, glob) = (name.to_string(), glob.to_string()); - self.types.entry(key).or_insert_with(|| { - FileTypeDef { name: name.to_string(), globs: vec![] } - }).globs.push(glob); - Ok(()) - } - - /// Add a new file type definition specified in string form. There are two - /// valid formats: - /// 1. `{name}:{glob}`. This defines a 'root' definition that associates the - /// given name with the given glob. - /// 2. `{name}:include:{comma-separated list of already defined names}. - /// This defines an 'include' definition that associates the given name - /// with the definitions of the given existing types. - /// Names may not include any characters that are not - /// Unicode letters or numbers. - pub fn add_def(&mut self, def: &str) -> Result<(), Error> { - let parts: Vec<&str> = def.split(':').collect(); - match parts.len() { - 2 => { - let name = parts[0]; - let glob = parts[1]; - if name.is_empty() || glob.is_empty() { - return Err(Error::InvalidDefinition); - } - self.add(name, glob) - } - 3 => { - let name = parts[0]; - let types_string = parts[2]; - if name.is_empty() || parts[1] != "include" || types_string.is_empty() { - return Err(Error::InvalidDefinition); - } - let types = types_string.split(','); - // Check ahead of time to ensure that all types specified are - // present and fail fast if not. - if types.clone().any(|t| !self.types.contains_key(t)) { - return Err(Error::InvalidDefinition); - } - for type_name in types { - let globs = self.types.get(type_name).unwrap().globs.clone(); - for glob in globs { - self.add(name, &glob)?; - } - } - Ok(()) - } - _ => Err(Error::InvalidDefinition) - } - } - - /// Add a set of default file type definitions. - pub fn add_defaults(&mut self) -> &mut TypesBuilder { - static MSG: &'static str = "adding a default type should never fail"; - for &(name, exts) in DEFAULT_TYPES { - for ext in exts { - self.add(name, ext).expect(MSG); - } - } - self - } -} - -#[cfg(test)] -mod tests { - use super::TypesBuilder; - - macro_rules! matched { - ($name:ident, $types:expr, $sel:expr, $selnot:expr, - $path:expr) => { - matched!($name, $types, $sel, $selnot, $path, true); - }; - (not, $name:ident, $types:expr, $sel:expr, $selnot:expr, - $path:expr) => { - matched!($name, $types, $sel, $selnot, $path, false); - }; - ($name:ident, $types:expr, $sel:expr, $selnot:expr, - $path:expr, $matched:expr) => { - #[test] - fn $name() { - let mut btypes = TypesBuilder::new(); - for tydef in $types { - btypes.add_def(tydef).unwrap(); - } - for sel in $sel { - btypes.select(sel); - } - for selnot in $selnot { - btypes.negate(selnot); - } - let types = btypes.build().unwrap(); - let mat = types.matched($path, false); - assert_eq!($matched, !mat.is_ignore()); - } - }; - } - - fn types() -> Vec<&'static str> { - vec![ - "html:*.html", - "html:*.htm", - "rust:*.rs", - "js:*.js", - "foo:*.{rs,foo}", - "combo:include:html,rust" - ] - } - - matched!(match1, types(), vec!["rust"], vec![], "lib.rs"); - matched!(match2, types(), vec!["html"], vec![], "index.html"); - matched!(match3, types(), vec!["html"], vec![], "index.htm"); - matched!(match4, types(), vec!["html", "rust"], vec![], "main.rs"); - matched!(match5, types(), vec![], vec![], "index.html"); - matched!(match6, types(), vec![], vec!["rust"], "index.html"); - matched!(match7, types(), vec!["foo"], vec!["rust"], "main.foo"); - matched!(match8, types(), vec!["combo"], vec![], "index.html"); - matched!(match9, types(), vec!["combo"], vec![], "lib.rs"); - - matched!(not, matchnot1, types(), vec!["rust"], vec![], "index.html"); - matched!(not, matchnot2, types(), vec![], vec!["rust"], "main.rs"); - matched!(not, matchnot3, types(), vec!["foo"], vec!["rust"], "main.rs"); - matched!(not, matchnot4, types(), vec!["rust"], vec!["foo"], "main.rs"); - matched!(not, matchnot5, types(), vec!["rust"], vec!["foo"], "main.foo"); - matched!(not, matchnot6, types(), vec!["combo"], vec![], "leftpad.js"); - - #[test] - fn test_invalid_defs() { - let mut btypes = TypesBuilder::new(); - for tydef in types() { - btypes.add_def(tydef).unwrap(); - } - // Preserve the original definitions for later comparison. - let original_defs = btypes.definitions(); - let bad_defs = vec![ - // Reference to type that does not exist - "combo:include:html,python", - // Bad format - "combo:foobar:html,rust", - "" - ]; - for def in bad_defs { - assert!(btypes.add_def(def).is_err()); - // Ensure that nothing changed, even if some of the includes were valid. - assert_eq!(btypes.definitions(), original_defs); - } - } -} diff --git a/ignore/src/walk.rs b/ignore/src/walk.rs deleted file mode 100644 index 74a37f5..0000000 --- a/ignore/src/walk.rs +++ /dev/null @@ -1,1766 +0,0 @@ -use std::cmp; -use std::ffi::OsStr; -use std::fmt; -use std::fs::{self, FileType, Metadata}; -use std::io; -use std::path::{Path, PathBuf}; -use std::sync::Arc; -use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; -use std::thread; -use std::time::Duration; -use std::vec; - -use crossbeam::sync::MsQueue; -use same_file::Handle; -use walkdir::{self, WalkDir}; - -use dir::{Ignore, IgnoreBuilder}; -use gitignore::GitignoreBuilder; -use overrides::Override; -use types::Types; -use {Error, PartialErrorBuilder}; - -/// A directory entry with a possible error attached. -/// -/// The error typically refers to a problem parsing ignore files in a -/// particular directory. -#[derive(Clone, Debug)] -pub struct DirEntry { - dent: DirEntryInner, - err: Option, -} - -impl DirEntry { - /// The full path that this entry represents. - pub fn path(&self) -> &Path { - self.dent.path() - } - - /// Whether this entry corresponds to a symbolic link or not. - pub fn path_is_symlink(&self) -> bool { - self.dent.path_is_symlink() - } - - /// Returns true if and only if this entry corresponds to stdin. - /// - /// i.e., The entry has depth 0 and its file name is `-`. - pub fn is_stdin(&self) -> bool { - self.dent.is_stdin() - } - - /// Return the metadata for the file that this entry points to. - pub fn metadata(&self) -> Result { - self.dent.metadata() - } - - /// Return the file type for the file that this entry points to. - /// - /// This entry doesn't have a file type if it corresponds to stdin. - pub fn file_type(&self) -> Option { - self.dent.file_type() - } - - /// Return the file name of this entry. - /// - /// If this entry has no file name (e.g., `/`), then the full path is - /// returned. - pub fn file_name(&self) -> &OsStr { - self.dent.file_name() - } - - /// Returns the depth at which this entry was created relative to the root. - pub fn depth(&self) -> usize { - self.dent.depth() - } - - /// Returns the underlying inode number if one exists. - /// - /// If this entry doesn't have an inode number, then `None` is returned. - #[cfg(unix)] - pub fn ino(&self) -> Option { - self.dent.ino() - } - - /// Returns an error, if one exists, associated with processing this entry. - /// - /// An example of an error is one that occurred while parsing an ignore - /// file. - pub fn error(&self) -> Option<&Error> { - self.err.as_ref() - } - - /// Returns true if and only if this entry points to a directory. - fn is_dir(&self) -> bool { - self.dent.is_dir() - } - - fn new_stdin() -> DirEntry { - DirEntry { - dent: DirEntryInner::Stdin, - err: None, - } - } - - fn new_walkdir(dent: walkdir::DirEntry, err: Option) -> DirEntry { - DirEntry { - dent: DirEntryInner::Walkdir(dent), - err: err, - } - } - - fn new_raw(dent: DirEntryRaw, err: Option) -> DirEntry { - DirEntry { - dent: DirEntryInner::Raw(dent), - err: err, - } - } -} - -/// DirEntryInner is the implementation of DirEntry. -/// -/// It specifically represents three distinct sources of directory entries: -/// -/// 1. From the walkdir crate. -/// 2. Special entries that represent things like stdin. -/// 3. From a path. -/// -/// Specifically, (3) has to essentially re-create the DirEntry implementation -/// from WalkDir. -#[derive(Clone, Debug)] -enum DirEntryInner { - Stdin, - Walkdir(walkdir::DirEntry), - Raw(DirEntryRaw), -} - -impl DirEntryInner { - fn path(&self) -> &Path { - use self::DirEntryInner::*; - match *self { - Stdin => Path::new(""), - Walkdir(ref x) => x.path(), - Raw(ref x) => x.path(), - } - } - - fn path_is_symlink(&self) -> bool { - use self::DirEntryInner::*; - match *self { - Stdin => false, - Walkdir(ref x) => x.path_is_symlink(), - Raw(ref x) => x.path_is_symlink(), - } - } - - fn is_stdin(&self) -> bool { - match *self { - DirEntryInner::Stdin => true, - _ => false, - } - } - - fn metadata(&self) -> Result { - use self::DirEntryInner::*; - match *self { - Stdin => { - let err = Error::Io(io::Error::new( - io::ErrorKind::Other, " has no metadata")); - Err(err.with_path("")) - } - Walkdir(ref x) => { - x.metadata().map_err(|err| { - Error::Io(io::Error::from(err)).with_path(x.path()) - }) - } - Raw(ref x) => x.metadata(), - } - } - - fn file_type(&self) -> Option { - use self::DirEntryInner::*; - match *self { - Stdin => None, - Walkdir(ref x) => Some(x.file_type()), - Raw(ref x) => Some(x.file_type()), - } - } - - fn file_name(&self) -> &OsStr { - use self::DirEntryInner::*; - match *self { - Stdin => OsStr::new(""), - Walkdir(ref x) => x.file_name(), - Raw(ref x) => x.file_name(), - } - } - - fn depth(&self) -> usize { - use self::DirEntryInner::*; - match *self { - Stdin => 0, - Walkdir(ref x) => x.depth(), - Raw(ref x) => x.depth(), - } - } - - #[cfg(unix)] - fn ino(&self) -> Option { - use walkdir::DirEntryExt; - use self::DirEntryInner::*; - match *self { - Stdin => None, - Walkdir(ref x) => Some(x.ino()), - Raw(ref x) => Some(x.ino()), - } - } - - /// Returns true if and only if this entry points to a directory. - /// - /// This works around a bug in Rust's standard library: - /// https://github.com/rust-lang/rust/issues/46484 - #[cfg(windows)] - fn is_dir(&self) -> bool { - self.metadata().map(|md| metadata_is_dir(&md)).unwrap_or(false) - } - - /// Returns true if and only if this entry points to a directory. - /// - /// This works around a bug in Rust's standard library: - /// https://github.com/rust-lang/rust/issues/46484 - #[cfg(not(windows))] - fn is_dir(&self) -> bool { - self.file_type().map(|ft| ft.is_dir()).unwrap_or(false) - } -} - -/// DirEntryRaw is essentially copied from the walkdir crate so that we can -/// build `DirEntry`s from whole cloth in the parallel iterator. -#[derive(Clone)] -struct DirEntryRaw { - /// The path as reported by the `fs::ReadDir` iterator (even if it's a - /// symbolic link). - path: PathBuf, - /// The file type. Necessary for recursive iteration, so store it. - ty: FileType, - /// Is set when this entry was created from a symbolic link and the user - /// expects the iterator to follow symbolic links. - follow_link: bool, - /// The depth at which this entry was generated relative to the root. - depth: usize, - /// The underlying inode number (Unix only). - #[cfg(unix)] - ino: u64, - /// The underlying metadata (Windows only). We store this on Windows - /// because this comes for free while reading a directory. - /// - /// We use this to determine whether an entry is a directory or not, which - /// works around a bug in Rust's standard library: - /// https://github.com/rust-lang/rust/issues/46484 - #[cfg(windows)] - metadata: fs::Metadata, -} - -impl fmt::Debug for DirEntryRaw { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // Leaving out FileType because it doesn't have a debug impl - // in Rust 1.9. We could add it if we really wanted to by manually - // querying each possibly file type. Meh. ---AG - f.debug_struct("DirEntryRaw") - .field("path", &self.path) - .field("follow_link", &self.follow_link) - .field("depth", &self.depth) - .finish() - } -} - -impl DirEntryRaw { - fn path(&self) -> &Path { - &self.path - } - - fn path_is_symlink(&self) -> bool { - self.ty.is_symlink() || self.follow_link - } - - fn metadata(&self) -> Result { - self.metadata_internal() - } - - #[cfg(windows)] - fn metadata_internal(&self) -> Result { - if self.follow_link { - fs::metadata(&self.path) - } else { - Ok(self.metadata.clone()) - }.map_err(|err| Error::Io(io::Error::from(err)).with_path(&self.path)) - } - - #[cfg(not(windows))] - fn metadata_internal(&self) -> Result { - if self.follow_link { - fs::metadata(&self.path) - } else { - fs::symlink_metadata(&self.path) - }.map_err(|err| Error::Io(io::Error::from(err)).with_path(&self.path)) - } - - fn file_type(&self) -> FileType { - self.ty - } - - fn file_name(&self) -> &OsStr { - self.path.file_name().unwrap_or_else(|| self.path.as_os_str()) - } - - fn depth(&self) -> usize { - self.depth - } - - #[cfg(unix)] - fn ino(&self) -> u64 { - self.ino - } - - fn from_entry( - depth: usize, - ent: &fs::DirEntry, - ) -> Result { - let ty = ent.file_type().map_err(|err| { - let err = Error::Io(io::Error::from(err)).with_path(ent.path()); - Error::WithDepth { - depth: depth, - err: Box::new(err), - } - })?; - DirEntryRaw::from_entry_os(depth, ent, ty) - } - - #[cfg(windows)] - fn from_entry_os( - depth: usize, - ent: &fs::DirEntry, - ty: fs::FileType, - ) -> Result { - let md = ent.metadata().map_err(|err| { - let err = Error::Io(io::Error::from(err)).with_path(ent.path()); - Error::WithDepth { - depth: depth, - err: Box::new(err), - } - })?; - Ok(DirEntryRaw { - path: ent.path(), - ty: ty, - follow_link: false, - depth: depth, - metadata: md, - }) - } - - #[cfg(unix)] - fn from_entry_os( - depth: usize, - ent: &fs::DirEntry, - ty: fs::FileType, - ) -> Result { - use std::os::unix::fs::DirEntryExt; - - Ok(DirEntryRaw { - path: ent.path(), - ty: ty, - follow_link: false, - depth: depth, - ino: ent.ino(), - }) - } - - #[cfg(not(unix))] - fn from_link(depth: usize, pb: PathBuf) -> Result { - let md = fs::metadata(&pb).map_err(|err| { - Error::Io(err).with_path(&pb) - })?; - Ok(DirEntryRaw { - path: pb, - ty: md.file_type(), - follow_link: true, - depth: depth, - metadata: md, - }) - } - - #[cfg(unix)] - fn from_link(depth: usize, pb: PathBuf) -> Result { - use std::os::unix::fs::MetadataExt; - - let md = fs::metadata(&pb).map_err(|err| { - Error::Io(err).with_path(&pb) - })?; - Ok(DirEntryRaw { - path: pb, - ty: md.file_type(), - follow_link: true, - depth: depth, - ino: md.ino(), - }) - } -} - -/// WalkBuilder builds a recursive directory iterator. -/// -/// The builder supports a large number of configurable options. This includes -/// specific glob overrides, file type matching, toggling whether hidden -/// files are ignored or not, and of course, support for respecting gitignore -/// files. -/// -/// By default, all ignore files found are respected. This includes `.ignore`, -/// `.gitignore`, `.git/info/exclude` and even your global gitignore -/// globs, usually found in `$XDG_CONFIG_HOME/git/ignore`. -/// -/// Some standard recursive directory options are also supported, such as -/// limiting the recursive depth or whether to follow symbolic links (disabled -/// by default). -/// -/// # Ignore rules -/// -/// There are many rules that influence whether a particular file or directory -/// is skipped by this iterator. Those rules are documented here. Note that -/// the rules assume a default configuration. -/// -/// * First, glob overrides are checked. If a path matches a glob override, -/// then matching stops. The path is then only skipped if the glob that matched -/// the path is an ignore glob. (An override glob is a whitelist glob unless it -/// starts with a `!`, in which case it is an ignore glob.) -/// * Second, ignore files are checked. Ignore files currently only come from -/// git ignore files (`.gitignore`, `.git/info/exclude` and the configured -/// global gitignore file), plain `.ignore` files, which have the same format -/// as gitignore files, or explicitly added ignore files. The precedence order -/// is: `.ignore`, `.gitignore`, `.git/info/exclude`, global gitignore and -/// finally explicitly added ignore files. Note that precedence between -/// different types of ignore files is not impacted by the directory hierarchy; -/// any `.ignore` file overrides all `.gitignore` files. Within each precedence -/// level, more nested ignore files have a higher precedence than less nested -/// ignore files. -/// * Third, if the previous step yields an ignore match, then all matching -/// is stopped and the path is skipped. If it yields a whitelist match, then -/// matching continues. A whitelist match can be overridden by a later matcher. -/// * Fourth, unless the path is a directory, the file type matcher is run on -/// the path. As above, if it yields an ignore match, then all matching is -/// stopped and the path is skipped. If it yields a whitelist match, then -/// matching continues. -/// * Fifth, if the path hasn't been whitelisted and it is hidden, then the -/// path is skipped. -/// * Sixth, unless the path is a directory, the size of the file is compared -/// against the max filesize limit. If it exceeds the limit, it is skipped. -/// * Seventh, if the path has made it this far then it is yielded in the -/// iterator. -#[derive(Clone)] -pub struct WalkBuilder { - paths: Vec, - ig_builder: IgnoreBuilder, - parents: bool, - max_depth: Option, - max_filesize: Option, - follow_links: bool, - sorter: Option cmp::Ordering + Send + Sync + 'static - >>, - threads: usize, -} - -impl fmt::Debug for WalkBuilder { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("WalkBuilder") - .field("paths", &self.paths) - .field("ig_builder", &self.ig_builder) - .field("parents", &self.parents) - .field("max_depth", &self.max_depth) - .field("max_filesize", &self.max_filesize) - .field("follow_links", &self.follow_links) - .field("threads", &self.threads) - .finish() - } -} - -impl WalkBuilder { - /// Create a new builder for a recursive directory iterator for the - /// directory given. - /// - /// Note that if you want to traverse multiple different directories, it - /// is better to call `add` on this builder than to create multiple - /// `Walk` values. - pub fn new>(path: P) -> WalkBuilder { - WalkBuilder { - paths: vec![path.as_ref().to_path_buf()], - ig_builder: IgnoreBuilder::new(), - parents: true, - max_depth: None, - max_filesize: None, - follow_links: false, - sorter: None, - threads: 0, - } - } - - /// Build a new `Walk` iterator. - pub fn build(&self) -> Walk { - let follow_links = self.follow_links; - let max_depth = self.max_depth; - let cmp = self.sorter.clone(); - let its = self.paths.iter().map(move |p| { - if p == Path::new("-") { - (p.to_path_buf(), None) - } else { - let mut wd = WalkDir::new(p); - wd = wd.follow_links(follow_links || path_is_file(p)); - if let Some(max_depth) = max_depth { - wd = wd.max_depth(max_depth); - } - if let Some(ref cmp) = cmp { - let cmp = cmp.clone(); - wd = wd.sort_by(move |a, b| { - cmp(a.file_name(), b.file_name()) - }); - } - (p.to_path_buf(), Some(WalkEventIter::from(wd))) - } - }).collect::>().into_iter(); - let ig_root = self.ig_builder.build(); - Walk { - its: its, - it: None, - ig_root: ig_root.clone(), - ig: ig_root.clone(), - max_filesize: self.max_filesize, - parents: self.parents, - } - } - - /// Build a new `WalkParallel` iterator. - /// - /// Note that this *doesn't* return something that implements `Iterator`. - /// Instead, the returned value must be run with a closure. e.g., - /// `builder.build_parallel().run(|| |path| println!("{:?}", path))`. - pub fn build_parallel(&self) -> WalkParallel { - WalkParallel { - paths: self.paths.clone().into_iter(), - ig_root: self.ig_builder.build(), - max_depth: self.max_depth, - max_filesize: self.max_filesize, - follow_links: self.follow_links, - parents: self.parents, - threads: self.threads, - } - } - - /// Add a file path to the iterator. - /// - /// Each additional file path added is traversed recursively. This should - /// be preferred over building multiple `Walk` iterators since this - /// enables reusing resources across iteration. - pub fn add>(&mut self, path: P) -> &mut WalkBuilder { - self.paths.push(path.as_ref().to_path_buf()); - self - } - - /// The maximum depth to recurse. - /// - /// The default, `None`, imposes no depth restriction. - pub fn max_depth(&mut self, depth: Option) -> &mut WalkBuilder { - self.max_depth = depth; - self - } - - /// Whether to follow symbolic links or not. - pub fn follow_links(&mut self, yes: bool) -> &mut WalkBuilder { - self.follow_links = yes; - self - } - - /// Whether to ignore files above the specified limit. - pub fn max_filesize(&mut self, filesize: Option) -> &mut WalkBuilder { - self.max_filesize = filesize; - self - } - - /// The number of threads to use for traversal. - /// - /// Note that this only has an effect when using `build_parallel`. - /// - /// The default setting is `0`, which chooses the number of threads - /// automatically using heuristics. - pub fn threads(&mut self, n: usize) -> &mut WalkBuilder { - self.threads = n; - self - } - - /// Add a global ignore file to the matcher. - /// - /// This has lower precedence than all other sources of ignore rules. - /// - /// If there was a problem adding the ignore file, then an error is - /// returned. Note that the error may indicate *partial* failure. For - /// example, if an ignore file contains an invalid glob, all other globs - /// are still applied. - pub fn add_ignore>(&mut self, path: P) -> Option { - let mut builder = GitignoreBuilder::new(""); - let mut errs = PartialErrorBuilder::default(); - errs.maybe_push(builder.add(path)); - match builder.build() { - Ok(gi) => { self.ig_builder.add_ignore(gi); } - Err(err) => { errs.push(err); } - } - errs.into_error_option() - } - - /// Add a custom ignore file name - /// - /// These ignore files have higher precedence than all other ignore files. - /// - /// When specifying multiple names, earlier names have lower precedence than - /// later names. - pub fn add_custom_ignore_filename>( - &mut self, - file_name: S - ) -> &mut WalkBuilder { - self.ig_builder.add_custom_ignore_filename(file_name); - self - } - - /// Add an override matcher. - /// - /// By default, no override matcher is used. - /// - /// This overrides any previous setting. - pub fn overrides(&mut self, overrides: Override) -> &mut WalkBuilder { - self.ig_builder.overrides(overrides); - self - } - - /// Add a file type matcher. - /// - /// By default, no file type matcher is used. - /// - /// This overrides any previous setting. - pub fn types(&mut self, types: Types) -> &mut WalkBuilder { - self.ig_builder.types(types); - self - } - - /// Enables all the standard ignore filters. - /// - /// This toggles, as a group, all the filters that are enabled by default: - /// - /// - [hidden()](#method.hidden) - /// - [parents()](#method.parents) - /// - [ignore()](#method.ignore) - /// - [git_ignore()](#method.git_ignore) - /// - [git_global()](#method.git_global) - /// - [git_exclude()](#method.git_exclude) - /// - /// They may still be toggled individually after calling this function. - /// - /// This is (by definition) enabled by default. - pub fn standard_filters(&mut self, yes: bool) -> &mut WalkBuilder { - self.hidden(yes) - .parents(yes) - .ignore(yes) - .git_ignore(yes) - .git_global(yes) - .git_exclude(yes) - } - - /// Enables ignoring hidden files. - /// - /// This is enabled by default. - pub fn hidden(&mut self, yes: bool) -> &mut WalkBuilder { - self.ig_builder.hidden(yes); - self - } - - /// Enables reading ignore files from parent directories. - /// - /// If this is enabled, then the parent directories of each file path given - /// are traversed for ignore files (subject to the ignore settings on - /// this builder). Note that file paths are canonicalized with respect to - /// the current working directory in order to determine parent directories. - /// - /// This is enabled by default. - pub fn parents(&mut self, yes: bool) -> &mut WalkBuilder { - self.parents = yes; - self - } - - /// Enables reading `.ignore` files. - /// - /// `.ignore` files have the same semantics as `gitignore` files and are - /// supported by search tools such as ripgrep and The Silver Searcher. - /// - /// This is enabled by default. - pub fn ignore(&mut self, yes: bool) -> &mut WalkBuilder { - self.ig_builder.ignore(yes); - self - } - - /// Enables reading a global gitignore file, whose path is specified in - /// git's `core.excludesFile` config option. - /// - /// Git's config file location is `$HOME/.gitconfig`. If `$HOME/.gitconfig` - /// does not exist or does not specify `core.excludesFile`, then - /// `$XDG_CONFIG_HOME/git/ignore` is read. If `$XDG_CONFIG_HOME` is not - /// set or is empty, then `$HOME/.config/git/ignore` is used instead. - /// - /// This is enabled by default. - pub fn git_global(&mut self, yes: bool) -> &mut WalkBuilder { - self.ig_builder.git_global(yes); - self - } - - /// Enables reading `.gitignore` files. - /// - /// `.gitignore` files have match semantics as described in the `gitignore` - /// man page. - /// - /// This is enabled by default. - pub fn git_ignore(&mut self, yes: bool) -> &mut WalkBuilder { - self.ig_builder.git_ignore(yes); - self - } - - /// Enables reading `.git/info/exclude` files. - /// - /// `.git/info/exclude` files have match semantics as described in the - /// `gitignore` man page. - /// - /// This is enabled by default. - pub fn git_exclude(&mut self, yes: bool) -> &mut WalkBuilder { - self.ig_builder.git_exclude(yes); - self - } - - /// Set a function for sorting directory entries by file name. - /// - /// If a compare function is set, the resulting iterator will return all - /// paths in sorted order. The compare function will be called to compare - /// names from entries from the same directory using only the name of the - /// entry. - /// - /// Note that this is not used in the parallel iterator. - pub fn sort_by_file_name(&mut self, cmp: F) -> &mut WalkBuilder - where F: Fn(&OsStr, &OsStr) -> cmp::Ordering + Send + Sync + 'static - { - self.sorter = Some(Arc::new(cmp)); - self - } -} - -/// Walk is a recursive directory iterator over file paths in one or more -/// directories. -/// -/// Only file and directory paths matching the rules are returned. By default, -/// ignore files like `.gitignore` are respected. The precise matching rules -/// and precedence is explained in the documentation for `WalkBuilder`. -pub struct Walk { - its: vec::IntoIter<(PathBuf, Option)>, - it: Option, - ig_root: Ignore, - ig: Ignore, - max_filesize: Option, - parents: bool, -} - -impl Walk { - /// Creates a new recursive directory iterator for the file path given. - /// - /// Note that this uses default settings, which include respecting - /// `.gitignore` files. To configure the iterator, use `WalkBuilder` - /// instead. - pub fn new>(path: P) -> Walk { - WalkBuilder::new(path).build() - } - - fn skip_entry(&self, ent: &walkdir::DirEntry) -> bool { - if ent.depth() == 0 { - return false; - } - - let is_dir = walkdir_entry_is_dir(ent); - let max_size = self.max_filesize; - let should_skip_path = skip_path(&self.ig, ent.path(), is_dir); - let should_skip_filesize = if !is_dir && max_size.is_some() { - skip_filesize(max_size.unwrap(), ent.path(), &ent.metadata().ok()) - } else { - false - }; - - should_skip_path || should_skip_filesize - } -} - -impl Iterator for Walk { - type Item = Result; - - #[inline(always)] - fn next(&mut self) -> Option> { - loop { - let ev = match self.it.as_mut().and_then(|it| it.next()) { - Some(ev) => ev, - None => { - match self.its.next() { - None => return None, - Some((_, None)) => { - return Some(Ok(DirEntry::new_stdin())); - } - Some((path, Some(it))) => { - self.it = Some(it); - if self.parents && path_is_dir(&path) { - let (ig, err) = self.ig_root.add_parents(path); - self.ig = ig; - if let Some(err) = err { - return Some(Err(err)); - } - } else { - self.ig = self.ig_root.clone(); - } - } - } - continue; - } - }; - match ev { - Err(err) => { - return Some(Err(Error::from_walkdir(err))); - } - Ok(WalkEvent::Exit) => { - self.ig = self.ig.parent().unwrap(); - } - Ok(WalkEvent::Dir(ent)) => { - if self.skip_entry(&ent) { - self.it.as_mut().unwrap().it.skip_current_dir(); - // Still need to push this on the stack because - // we'll get a WalkEvent::Exit event for this dir. - // We don't care if it errors though. - let (igtmp, _) = self.ig.add_child(ent.path()); - self.ig = igtmp; - continue; - } - let (igtmp, err) = self.ig.add_child(ent.path()); - self.ig = igtmp; - return Some(Ok(DirEntry::new_walkdir(ent, err))); - } - Ok(WalkEvent::File(ent)) => { - if self.skip_entry(&ent) { - continue; - } - return Some(Ok(DirEntry::new_walkdir(ent, None))); - } - } - } - } -} - -/// WalkEventIter transforms a WalkDir iterator into an iterator that more -/// accurately describes the directory tree. Namely, it emits events that are -/// one of three types: directory, file or "exit." An "exit" event means that -/// the entire contents of a directory have been enumerated. -struct WalkEventIter { - depth: usize, - it: walkdir::IntoIter, - next: Option>, -} - -#[derive(Debug)] -enum WalkEvent { - Dir(walkdir::DirEntry), - File(walkdir::DirEntry), - Exit, -} - -impl From for WalkEventIter { - fn from(it: WalkDir) -> WalkEventIter { - WalkEventIter { depth: 0, it: it.into_iter(), next: None } - } -} - -impl Iterator for WalkEventIter { - type Item = walkdir::Result; - - #[inline(always)] - fn next(&mut self) -> Option> { - let dent = self.next.take().or_else(|| self.it.next()); - let depth = match dent { - None => 0, - Some(Ok(ref dent)) => dent.depth(), - Some(Err(ref err)) => err.depth(), - }; - if depth < self.depth { - self.depth -= 1; - self.next = dent; - return Some(Ok(WalkEvent::Exit)); - } - self.depth = depth; - match dent { - None => None, - Some(Err(err)) => Some(Err(err)), - Some(Ok(dent)) => { - if walkdir_entry_is_dir(&dent) { - self.depth += 1; - Some(Ok(WalkEvent::Dir(dent))) - } else { - Some(Ok(WalkEvent::File(dent))) - } - } - } - } -} - -/// WalkState is used in the parallel recursive directory iterator to indicate -/// whether walking should continue as normal, skip descending into a -/// particular directory or quit the walk entirely. -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum WalkState { - /// Continue walking as normal. - Continue, - /// If the directory entry given is a directory, don't descend into it. - /// In all other cases, this has no effect. - Skip, - /// Quit the entire iterator as soon as possible. - /// - /// Note that this is an inherently asynchronous action. It is possible - /// for more entries to be yielded even after instructing the iterator - /// to quit. - Quit, -} - -impl WalkState { - fn is_quit(&self) -> bool { - *self == WalkState::Quit - } -} - -/// WalkParallel is a parallel recursive directory iterator over files paths -/// in one or more directories. -/// -/// Only file and directory paths matching the rules are returned. By default, -/// ignore files like `.gitignore` are respected. The precise matching rules -/// and precedence is explained in the documentation for `WalkBuilder`. -/// -/// Unlike `Walk`, this uses multiple threads for traversing a directory. -pub struct WalkParallel { - paths: vec::IntoIter, - ig_root: Ignore, - parents: bool, - max_filesize: Option, - max_depth: Option, - follow_links: bool, - threads: usize, -} - -impl WalkParallel { - /// Execute the parallel recursive directory iterator. `mkf` is called - /// for each thread used for iteration. The function produced by `mkf` - /// is then in turn called for each visited file path. - pub fn run( - self, - mut mkf: F, - ) where F: FnMut() -> Box) -> WalkState + Send + 'static> { - let mut f = mkf(); - let threads = self.threads(); - let queue = Arc::new(MsQueue::new()); - let mut any_work = false; - // Send the initial set of root paths to the pool of workers. - // Note that we only send directories. For files, we send to them the - // callback directly. - for path in self.paths { - let dent = - if path == Path::new("-") { - DirEntry::new_stdin() - } else { - match DirEntryRaw::from_link(0, path) { - Ok(dent) => DirEntry::new_raw(dent, None), - Err(err) => { - if f(Err(err)).is_quit() { - return; - } - continue; - } - } - }; - queue.push(Message::Work(Work { - dent: dent, - ignore: self.ig_root.clone(), - })); - any_work = true; - } - // ... but there's no need to start workers if we don't need them. - if !any_work { - return; - } - // Create the workers and then wait for them to finish. - let num_waiting = Arc::new(AtomicUsize::new(0)); - let num_quitting = Arc::new(AtomicUsize::new(0)); - let quit_now = Arc::new(AtomicBool::new(false)); - let mut handles = vec![]; - for _ in 0..threads { - let worker = Worker { - f: mkf(), - queue: queue.clone(), - quit_now: quit_now.clone(), - is_waiting: false, - is_quitting: false, - num_waiting: num_waiting.clone(), - num_quitting: num_quitting.clone(), - threads: threads, - parents: self.parents, - max_depth: self.max_depth, - max_filesize: self.max_filesize, - follow_links: self.follow_links, - }; - handles.push(thread::spawn(|| worker.run())); - } - for handle in handles { - handle.join().unwrap(); - } - } - - fn threads(&self) -> usize { - if self.threads == 0 { - 2 - } else { - self.threads - } - } -} - -/// Message is the set of instructions that a worker knows how to process. -enum Message { - /// A work item corresponds to a directory that should be descended into. - /// Work items for entries that should be skipped or ignored should not - /// be produced. - Work(Work), - /// This instruction indicates that the worker should start quitting. - Quit, -} - -/// A unit of work for each worker to process. -/// -/// Each unit of work corresponds to a directory that should be descended -/// into. -struct Work { - /// The directory entry. - dent: DirEntry, - /// Any ignore matchers that have been built for this directory's parents. - ignore: Ignore, -} - -impl Work { - /// Returns true if and only if this work item is a directory. - fn is_dir(&self) -> bool { - self.dent.is_dir() - } - - /// Returns true if and only if this work item is a symlink. - fn is_symlink(&self) -> bool { - self.dent.file_type().map_or(false, |ft| ft.is_symlink()) - } - - /// Adds ignore rules for parent directories. - /// - /// Note that this only applies to entries at depth 0. On all other - /// entries, this is a no-op. - fn add_parents(&mut self) -> Option { - if self.dent.depth() > 0 { - return None; - } - // At depth 0, the path of this entry is a root path, so we can - // use it directly to add parent ignore rules. - let (ig, err) = self.ignore.add_parents(self.dent.path()); - self.ignore = ig; - err - } - - /// Reads the directory contents of this work item and adds ignore - /// rules for this directory. - /// - /// If there was a problem with reading the directory contents, then - /// an error is returned. If there was a problem reading the ignore - /// rules for this directory, then the error is attached to this - /// work item's directory entry. - fn read_dir(&mut self) -> Result { - let readdir = match fs::read_dir(self.dent.path()) { - Ok(readdir) => readdir, - Err(err) => { - let err = Error::from(err) - .with_path(self.dent.path()) - .with_depth(self.dent.depth()); - return Err(err); - } - }; - let (ig, err) = self.ignore.add_child(self.dent.path()); - self.ignore = ig; - self.dent.err = err; - Ok(readdir) - } -} - -/// A worker is responsible for descending into directories, updating the -/// ignore matchers, producing new work and invoking the caller's callback. -/// -/// Note that a worker is *both* a producer and a consumer. -struct Worker { - /// The caller's callback. - f: Box) -> WalkState + Send + 'static>, - /// A queue of work items. This is multi-producer and multi-consumer. - queue: Arc>, - /// Whether all workers should quit at the next opportunity. Note that - /// this is distinct from quitting because of exhausting the contents of - /// a directory. Instead, this is used when the caller's callback indicates - /// that the iterator should quit immediately. - quit_now: Arc, - /// Whether this worker is waiting for more work. - is_waiting: bool, - /// Whether this worker has started to quit. - is_quitting: bool, - /// The number of workers waiting for more work. - num_waiting: Arc, - /// The number of workers waiting to quit. - num_quitting: Arc, - /// The total number of workers. - threads: usize, - /// Whether to create ignore matchers for parents of caller specified - /// directories. - parents: bool, - /// The maximum depth of directories to descend. A value of `0` means no - /// descension at all. - max_depth: Option, - /// The maximum size a searched file can be (in bytes). If a file exceeds - /// this size it will be skipped. - max_filesize: Option, - /// Whether to follow symbolic links or not. When this is enabled, loop - /// detection is performed. - follow_links: bool, -} - -impl Worker { - /// Runs this worker until there is no more work left to do. - /// - /// The worker will call the caller's callback for all entries that aren't - /// skipped by the ignore matcher. - fn run(mut self) { - while let Some(mut work) = self.get_work() { - // If the work is not a directory, then we can just execute the - // caller's callback immediately and move on. - if work.is_symlink() || !work.is_dir() { - if (self.f)(Ok(work.dent)).is_quit() { - self.quit_now(); - return; - } - continue; - } - if self.parents { - if let Some(err) = work.add_parents() { - if (self.f)(Err(err)).is_quit() { - self.quit_now(); - return; - } - } - } - let readdir = match work.read_dir() { - Ok(readdir) => readdir, - Err(err) => { - if (self.f)(Err(err)).is_quit() { - self.quit_now(); - return; - } - continue; - } - }; - let depth = work.dent.depth(); - match (self.f)(Ok(work.dent)) { - WalkState::Continue => {} - WalkState::Skip => continue, - WalkState::Quit => { - self.quit_now(); - return; - } - } - if self.max_depth.map_or(false, |max| depth >= max) { - continue; - } - for result in readdir { - if self.run_one(&work.ignore, depth + 1, result).is_quit() { - self.quit_now(); - return; - } - } - } - } - - /// Runs the worker on a single entry from a directory iterator. - /// - /// If the entry is a path that should be ignored, then this is a no-op. - /// Otherwise, the entry is pushed on to the queue. (The actual execution - /// of the callback happens in `run`.) - /// - /// If an error occurs while reading the entry, then it is sent to the - /// caller's callback. - /// - /// `ig` is the `Ignore` matcher for the parent directory. `depth` should - /// be the depth of this entry. `result` should be the item yielded by - /// a directory iterator. - fn run_one( - &mut self, - ig: &Ignore, - depth: usize, - result: Result, - ) -> WalkState { - let fs_dent = match result { - Ok(fs_dent) => fs_dent, - Err(err) => { - return (self.f)(Err(Error::from(err).with_depth(depth))); - } - }; - let mut dent = match DirEntryRaw::from_entry(depth, &fs_dent) { - Ok(dent) => DirEntry::new_raw(dent, None), - Err(err) => { - return (self.f)(Err(err)); - } - }; - let is_symlink = dent.file_type().map_or(false, |ft| ft.is_symlink()); - if self.follow_links && is_symlink { - let path = dent.path().to_path_buf(); - dent = match DirEntryRaw::from_link(depth, path) { - Ok(dent) => DirEntry::new_raw(dent, None), - Err(err) => { - return (self.f)(Err(err)); - } - }; - if dent.is_dir() { - if let Err(err) = check_symlink_loop(ig, dent.path(), depth) { - return (self.f)(Err(err)); - } - } - } - let is_dir = dent.is_dir(); - let max_size = self.max_filesize; - let should_skip_path = skip_path(ig, dent.path(), is_dir); - let should_skip_filesize = if !is_dir && max_size.is_some() { - skip_filesize(max_size.unwrap(), dent.path(), &dent.metadata().ok()) - } else { - false - }; - - if !should_skip_path && !should_skip_filesize { - self.queue.push(Message::Work(Work { - dent: dent, - ignore: ig.clone(), - })); - } - WalkState::Continue - } - - /// Returns the next directory to descend into. - /// - /// If all work has been exhausted, then this returns None. The worker - /// should then subsequently quit. - fn get_work(&mut self) -> Option { - loop { - if self.is_quit_now() { - return None; - } - match self.queue.try_pop() { - Some(Message::Work(work)) => { - self.waiting(false); - self.quitting(false); - return Some(work); - } - Some(Message::Quit) => { - // We can't just quit because a Message::Quit could be - // spurious. For example, it's possible to observe that - // all workers are waiting even if there's more work to - // be done. - // - // Therefore, we do a bit of a dance to wait until all - // workers have signaled that they're ready to quit before - // actually quitting. - // - // If the Quit message turns out to be spurious, then the - // loop below will break and we'll go back to looking for - // more work. - self.waiting(true); - self.quitting(true); - while !self.is_quit_now() { - let nwait = self.num_waiting(); - let nquit = self.num_quitting(); - // If the number of waiting workers dropped, then - // abort our attempt to quit. - if nwait < self.threads { - break; - } - // If all workers are in this quit loop, then we - // can stop. - if nquit == self.threads { - return None; - } - // Otherwise, spin. - } - } - None => { - self.waiting(true); - self.quitting(false); - if self.num_waiting() == self.threads { - for _ in 0..self.threads { - self.queue.push(Message::Quit); - } - } else { - // You're right to consider this suspicious, but it's - // a useful heuristic to permit producers to catch up - // to consumers without burning the CPU. It is also - // useful as a means to prevent burning the CPU if only - // one worker is left doing actual work. It's not - // perfect and it doesn't leave the CPU completely - // idle, but it's not clear what else we can do. :-/ - thread::sleep(Duration::from_millis(1)); - } - } - } - } - } - - /// Indicates that all workers should quit immediately. - fn quit_now(&self) { - self.quit_now.store(true, Ordering::SeqCst); - } - - /// Returns true if this worker should quit immediately. - fn is_quit_now(&self) -> bool { - self.quit_now.load(Ordering::SeqCst) - } - - /// Returns the total number of workers waiting for work. - fn num_waiting(&self) -> usize { - self.num_waiting.load(Ordering::SeqCst) - } - - /// Returns the total number of workers ready to quit. - fn num_quitting(&self) -> usize { - self.num_quitting.load(Ordering::SeqCst) - } - - /// Sets this worker's "quitting" state to the value of `yes`. - fn quitting(&mut self, yes: bool) { - if yes { - if !self.is_quitting { - self.is_quitting = true; - self.num_quitting.fetch_add(1, Ordering::SeqCst); - } - } else { - if self.is_quitting { - self.is_quitting = false; - self.num_quitting.fetch_sub(1, Ordering::SeqCst); - } - } - } - - /// Sets this worker's "waiting" state to the value of `yes`. - fn waiting(&mut self, yes: bool) { - if yes { - if !self.is_waiting { - self.is_waiting = true; - self.num_waiting.fetch_add(1, Ordering::SeqCst); - } - } else { - if self.is_waiting { - self.is_waiting = false; - self.num_waiting.fetch_sub(1, Ordering::SeqCst); - } - } - } -} - -fn check_symlink_loop( - ig_parent: &Ignore, - child_path: &Path, - child_depth: usize, -) -> Result<(), Error> { - let hchild = Handle::from_path(child_path).map_err(|err| { - Error::from(err).with_path(child_path).with_depth(child_depth) - })?; - for ig in ig_parent.parents().take_while(|ig| !ig.is_absolute_parent()) { - let h = Handle::from_path(ig.path()).map_err(|err| { - Error::from(err).with_path(child_path).with_depth(child_depth) - })?; - if hchild == h { - return Err(Error::Loop { - ancestor: ig.path().to_path_buf(), - child: child_path.to_path_buf(), - }.with_depth(child_depth)); - } - } - Ok(()) -} - -// Before calling this function, make sure that you ensure that is really -// necessary as the arguments imply a file stat. -fn skip_filesize( - max_filesize: u64, - path: &Path, - ent: &Option -) -> bool { - let filesize = match *ent { - Some(ref md) => Some(md.len()), - None => None - }; - - if let Some(fs) = filesize { - if fs > max_filesize { - debug!("ignoring {}: {} bytes", path.display(), fs); - true - } else { - false - } - } else { - false - } -} - -fn skip_path(ig: &Ignore, path: &Path, is_dir: bool) -> bool { - let m = ig.matched(path, is_dir); - if m.is_ignore() { - debug!("ignoring {}: {:?}", path.display(), m); - true - } else if m.is_whitelist() { - debug!("whitelisting {}: {:?}", path.display(), m); - false - } else { - false - } -} - -/// Returns true if and only if this path points to a directory. -/// -/// This works around a bug in Rust's standard library: -/// https://github.com/rust-lang/rust/issues/46484 -#[cfg(windows)] -fn path_is_dir(path: &Path) -> bool { - fs::metadata(path).map(|md| metadata_is_dir(&md)).unwrap_or(false) -} - -/// Returns true if and only if this entry points to a directory. -#[cfg(not(windows))] -fn path_is_dir(path: &Path) -> bool { - path.is_dir() -} - -/// Returns true if and only if this path points to a file. -/// -/// This works around a bug in Rust's standard library: -/// https://github.com/rust-lang/rust/issues/46484 -#[cfg(windows)] -fn path_is_file(path: &Path) -> bool { - !path_is_dir(path) -} - -/// Returns true if and only if this entry points to a directory. -#[cfg(not(windows))] -fn path_is_file(path: &Path) -> bool { - path.is_file() -} - -/// Returns true if and only if the given walkdir entry points to a directory. -/// -/// This works around a bug in Rust's standard library: -/// https://github.com/rust-lang/rust/issues/46484 -#[cfg(windows)] -fn walkdir_entry_is_dir(dent: &walkdir::DirEntry) -> bool { - dent.metadata().map(|md| metadata_is_dir(&md)).unwrap_or(false) -} - -/// Returns true if and only if the given walkdir entry points to a directory. -#[cfg(not(windows))] -fn walkdir_entry_is_dir(dent: &walkdir::DirEntry) -> bool { - dent.file_type().is_dir() -} - -/// Returns true if and only if the given metadata points to a directory. -/// -/// This works around a bug in Rust's standard library: -/// https://github.com/rust-lang/rust/issues/46484 -#[cfg(windows)] -fn metadata_is_dir(md: &fs::Metadata) -> bool { - use std::os::windows::fs::MetadataExt; - use winapi::um::winnt::FILE_ATTRIBUTE_DIRECTORY; - md.file_attributes() & FILE_ATTRIBUTE_DIRECTORY != 0 -} - -#[cfg(test)] -mod tests { - use std::fs::{self, File}; - use std::io::Write; - use std::path::Path; - use std::sync::{Arc, Mutex}; - - use tempdir::TempDir; - - use super::{WalkBuilder, WalkState}; - - fn wfile>(path: P, contents: &str) { - let mut file = File::create(path).unwrap(); - file.write_all(contents.as_bytes()).unwrap(); - } - - fn wfile_size>(path: P, size: u64) { - let file = File::create(path).unwrap(); - file.set_len(size).unwrap(); - } - - #[cfg(unix)] - fn symlink, Q: AsRef>(src: P, dst: Q) { - use std::os::unix::fs::symlink; - symlink(src, dst).unwrap(); - } - - fn mkdirp>(path: P) { - fs::create_dir_all(path).unwrap(); - } - - fn normal_path(unix: &str) -> String { - if cfg!(windows) { - unix.replace("\\", "/") - } else { - unix.to_string() - } - } - - fn walk_collect(prefix: &Path, builder: &WalkBuilder) -> Vec { - let mut paths = vec![]; - for result in builder.build() { - let dent = match result { - Err(_) => continue, - Ok(dent) => dent, - }; - let path = dent.path().strip_prefix(prefix).unwrap(); - if path.as_os_str().is_empty() { - continue; - } - paths.push(normal_path(path.to_str().unwrap())); - } - paths.sort(); - paths - } - - fn walk_collect_parallel( - prefix: &Path, - builder: &WalkBuilder, - ) -> Vec { - let paths = Arc::new(Mutex::new(vec![])); - let prefix = Arc::new(prefix.to_path_buf()); - builder.build_parallel().run(|| { - let paths = paths.clone(); - let prefix = prefix.clone(); - Box::new(move |result| { - let dent = match result { - Err(_) => return WalkState::Continue, - Ok(dent) => dent, - }; - let path = dent.path().strip_prefix(&**prefix).unwrap(); - if path.as_os_str().is_empty() { - return WalkState::Continue; - } - let mut paths = paths.lock().unwrap(); - paths.push(normal_path(path.to_str().unwrap())); - WalkState::Continue - }) - }); - let mut paths = paths.lock().unwrap(); - paths.sort(); - paths.to_vec() - } - - fn mkpaths(paths: &[&str]) -> Vec { - let mut paths: Vec<_> = paths.iter().map(|s| s.to_string()).collect(); - paths.sort(); - paths - } - - fn assert_paths( - prefix: &Path, - builder: &WalkBuilder, - expected: &[&str], - ) { - let got = walk_collect(prefix, builder); - assert_eq!(got, mkpaths(expected)); - let got = walk_collect_parallel(prefix, builder); - assert_eq!(got, mkpaths(expected)); - } - - #[test] - fn no_ignores() { - let td = TempDir::new("walk-test-").unwrap(); - mkdirp(td.path().join("a/b/c")); - mkdirp(td.path().join("x/y")); - wfile(td.path().join("a/b/foo"), ""); - wfile(td.path().join("x/y/foo"), ""); - - assert_paths(td.path(), &WalkBuilder::new(td.path()), &[ - "x", "x/y", "x/y/foo", "a", "a/b", "a/b/foo", "a/b/c", - ]); - } - - #[test] - fn custom_ignore() { - let td = TempDir::new("walk-test-").unwrap(); - let custom_ignore = ".customignore"; - mkdirp(td.path().join("a")); - wfile(td.path().join(custom_ignore), "foo"); - wfile(td.path().join("foo"), ""); - wfile(td.path().join("a/foo"), ""); - wfile(td.path().join("bar"), ""); - wfile(td.path().join("a/bar"), ""); - - let mut builder = WalkBuilder::new(td.path()); - builder.add_custom_ignore_filename(&custom_ignore); - assert_paths(td.path(), &builder, &["bar", "a", "a/bar"]); - } - - #[test] - fn custom_ignore_exclusive_use() { - let td = TempDir::new("walk-test-").unwrap(); - let custom_ignore = ".customignore"; - mkdirp(td.path().join("a")); - wfile(td.path().join(custom_ignore), "foo"); - wfile(td.path().join("foo"), ""); - wfile(td.path().join("a/foo"), ""); - wfile(td.path().join("bar"), ""); - wfile(td.path().join("a/bar"), ""); - - let mut builder = WalkBuilder::new(td.path()); - builder.ignore(false); - builder.git_ignore(false); - builder.git_global(false); - builder.git_exclude(false); - builder.add_custom_ignore_filename(&custom_ignore); - assert_paths(td.path(), &builder, &["bar", "a", "a/bar"]); - } - - #[test] - fn gitignore() { - let td = TempDir::new("walk-test-").unwrap(); - mkdirp(td.path().join("a")); - wfile(td.path().join(".gitignore"), "foo"); - wfile(td.path().join("foo"), ""); - wfile(td.path().join("a/foo"), ""); - wfile(td.path().join("bar"), ""); - wfile(td.path().join("a/bar"), ""); - - assert_paths(td.path(), &WalkBuilder::new(td.path()), &[ - "bar", "a", "a/bar", - ]); - } - - #[test] - fn explicit_ignore() { - let td = TempDir::new("walk-test-").unwrap(); - let igpath = td.path().join(".not-an-ignore"); - mkdirp(td.path().join("a")); - wfile(&igpath, "foo"); - wfile(td.path().join("foo"), ""); - wfile(td.path().join("a/foo"), ""); - wfile(td.path().join("bar"), ""); - wfile(td.path().join("a/bar"), ""); - - let mut builder = WalkBuilder::new(td.path()); - assert!(builder.add_ignore(&igpath).is_none()); - assert_paths(td.path(), &builder, &["bar", "a", "a/bar"]); - } - - #[test] - fn gitignore_parent() { - let td = TempDir::new("walk-test-").unwrap(); - mkdirp(td.path().join("a")); - wfile(td.path().join(".gitignore"), "foo"); - wfile(td.path().join("a/foo"), ""); - wfile(td.path().join("a/bar"), ""); - - let root = td.path().join("a"); - assert_paths(&root, &WalkBuilder::new(&root), &["bar"]); - } - - #[test] - fn max_depth() { - let td = TempDir::new("walk-test-").unwrap(); - mkdirp(td.path().join("a/b/c")); - wfile(td.path().join("foo"), ""); - wfile(td.path().join("a/foo"), ""); - wfile(td.path().join("a/b/foo"), ""); - wfile(td.path().join("a/b/c/foo"), ""); - - let mut builder = WalkBuilder::new(td.path()); - assert_paths(td.path(), &builder, &[ - "a", "a/b", "a/b/c", "foo", "a/foo", "a/b/foo", "a/b/c/foo", - ]); - assert_paths(td.path(), builder.max_depth(Some(0)), &[]); - assert_paths(td.path(), builder.max_depth(Some(1)), &["a", "foo"]); - assert_paths(td.path(), builder.max_depth(Some(2)), &[ - "a", "a/b", "foo", "a/foo", - ]); - } - - #[test] - fn max_filesize() { - let td = TempDir::new("walk-test-").unwrap(); - mkdirp(td.path().join("a/b")); - wfile_size(td.path().join("foo"), 0); - wfile_size(td.path().join("bar"), 400); - wfile_size(td.path().join("baz"), 600); - wfile_size(td.path().join("a/foo"), 600); - wfile_size(td.path().join("a/bar"), 500); - wfile_size(td.path().join("a/baz"), 200); - - let mut builder = WalkBuilder::new(td.path()); - assert_paths(td.path(), &builder, &[ - "a", "a/b", "foo", "bar", "baz", "a/foo", "a/bar", "a/baz", - ]); - assert_paths(td.path(), builder.max_filesize(Some(0)), &[ - "a", "a/b", "foo" - ]); - assert_paths(td.path(), builder.max_filesize(Some(500)), &[ - "a", "a/b", "foo", "bar", "a/bar", "a/baz" - ]); - assert_paths(td.path(), builder.max_filesize(Some(50000)), &[ - "a", "a/b", "foo", "bar", "baz", "a/foo", "a/bar", "a/baz", - ]); - } - - #[cfg(unix)] // because symlinks on windows are weird - #[test] - fn symlinks() { - let td = TempDir::new("walk-test-").unwrap(); - mkdirp(td.path().join("a/b")); - symlink(td.path().join("a/b"), td.path().join("z")); - wfile(td.path().join("a/b/foo"), ""); - - let mut builder = WalkBuilder::new(td.path()); - assert_paths(td.path(), &builder, &[ - "a", "a/b", "a/b/foo", "z", - ]); - assert_paths(td.path(), &builder.follow_links(true), &[ - "a", "a/b", "a/b/foo", "z", "z/foo", - ]); - } - - #[cfg(unix)] // because symlinks on windows are weird - #[test] - fn symlink_loop() { - let td = TempDir::new("walk-test-").unwrap(); - mkdirp(td.path().join("a/b")); - symlink(td.path().join("a"), td.path().join("a/b/c")); - - let mut builder = WalkBuilder::new(td.path()); - assert_paths(td.path(), &builder, &[ - "a", "a/b", "a/b/c", - ]); - assert_paths(td.path(), &builder.follow_links(true), &[ - "a", "a/b", - ]); - } -} diff --git a/ignore/tests/gitignore_matched_path_or_any_parents_tests.gitignore b/ignore/tests/gitignore_matched_path_or_any_parents_tests.gitignore deleted file mode 100644 index ac09e12..0000000 --- a/ignore/tests/gitignore_matched_path_or_any_parents_tests.gitignore +++ /dev/null @@ -1,216 +0,0 @@ -# Based on https://github.com/behnam/gitignore-test/blob/master/.gitignore - -### file in root - -# MATCH /file_root_1 -file_root_00 - -# NO_MATCH -file_root_01/ - -# NO_MATCH -file_root_02/* - -# NO_MATCH -file_root_03/** - - -# MATCH /file_root_10 -/file_root_10 - -# NO_MATCH -/file_root_11/ - -# NO_MATCH -/file_root_12/* - -# NO_MATCH -/file_root_13/** - - -# NO_MATCH -*/file_root_20 - -# NO_MATCH -*/file_root_21/ - -# NO_MATCH -*/file_root_22/* - -# NO_MATCH -*/file_root_23/** - - -# MATCH /file_root_30 -**/file_root_30 - -# NO_MATCH -**/file_root_31/ - -# NO_MATCH -**/file_root_32/* - -# NO_MATCH -**/file_root_33/** - - -### file in sub-dir - -# MATCH /parent_dir/file_deep_1 -file_deep_00 - -# NO_MATCH -file_deep_01/ - -# NO_MATCH -file_deep_02/* - -# NO_MATCH -file_deep_03/** - - -# NO_MATCH -/file_deep_10 - -# NO_MATCH -/file_deep_11/ - -# NO_MATCH -/file_deep_12/* - -# NO_MATCH -/file_deep_13/** - - -# MATCH /parent_dir/file_deep_20 -*/file_deep_20 - -# NO_MATCH -*/file_deep_21/ - -# NO_MATCH -*/file_deep_22/* - -# NO_MATCH -*/file_deep_23/** - - -# MATCH /parent_dir/file_deep_30 -**/file_deep_30 - -# NO_MATCH -**/file_deep_31/ - -# NO_MATCH -**/file_deep_32/* - -# NO_MATCH -**/file_deep_33/** - - -### dir in root - -# MATCH /dir_root_00 -dir_root_00 - -# MATCH /dir_root_01 -dir_root_01/ - -# MATCH /dir_root_02 -dir_root_02/* - -# MATCH /dir_root_03 -dir_root_03/** - - -# MATCH /dir_root_10 -/dir_root_10 - -# MATCH /dir_root_11 -/dir_root_11/ - -# MATCH /dir_root_12 -/dir_root_12/* - -# MATCH /dir_root_13 -/dir_root_13/** - - -# NO_MATCH -*/dir_root_20 - -# NO_MATCH -*/dir_root_21/ - -# NO_MATCH -*/dir_root_22/* - -# NO_MATCH -*/dir_root_23/** - - -# MATCH /dir_root_30 -**/dir_root_30 - -# MATCH /dir_root_31 -**/dir_root_31/ - -# MATCH /dir_root_32 -**/dir_root_32/* - -# MATCH /dir_root_33 -**/dir_root_33/** - - -### dir in sub-dir - -# MATCH /parent_dir/dir_deep_00 -dir_deep_00 - -# MATCH /parent_dir/dir_deep_01 -dir_deep_01/ - -# NO_MATCH -dir_deep_02/* - -# NO_MATCH -dir_deep_03/** - - -# NO_MATCH -/dir_deep_10 - -# NO_MATCH -/dir_deep_11/ - -# NO_MATCH -/dir_deep_12/* - -# NO_MATCH -/dir_deep_13/** - - -# MATCH /parent_dir/dir_deep_20 -*/dir_deep_20 - -# MATCH /parent_dir/dir_deep_21 -*/dir_deep_21/ - -# MATCH /parent_dir/dir_deep_22 -*/dir_deep_22/* - -# MATCH /parent_dir/dir_deep_23 -*/dir_deep_23/** - - -# MATCH /parent_dir/dir_deep_30 -**/dir_deep_30 - -# MATCH /parent_dir/dir_deep_31 -**/dir_deep_31/ - -# MATCH /parent_dir/dir_deep_32 -**/dir_deep_32/* - -# MATCH /parent_dir/dir_deep_33 -**/dir_deep_33/** diff --git a/ignore/tests/gitignore_matched_path_or_any_parents_tests.rs b/ignore/tests/gitignore_matched_path_or_any_parents_tests.rs deleted file mode 100644 index 4de7cf3..0000000 --- a/ignore/tests/gitignore_matched_path_or_any_parents_tests.rs +++ /dev/null @@ -1,297 +0,0 @@ -extern crate ignore; - - -use std::path::Path; - -use ignore::gitignore::{Gitignore, GitignoreBuilder}; - - -const IGNORE_FILE: &'static str = "tests/gitignore_matched_path_or_any_parents_tests.gitignore"; - - -fn get_gitignore() -> Gitignore { - let mut builder = GitignoreBuilder::new("ROOT"); - let error = builder.add(IGNORE_FILE); - assert!(error.is_none(), "failed to open gitignore file"); - builder.build().unwrap() -} - - -#[test] -#[should_panic(expected = "path is expect to be under the root")] -fn test_path_should_be_under_root() { - let gitignore = get_gitignore(); - let path = "/tmp/some_file"; - gitignore.matched_path_or_any_parents(Path::new(path), false); - assert!(false); -} - - -#[test] -fn test_files_in_root() { - let gitignore = get_gitignore(); - let m = |path: &str| gitignore.matched_path_or_any_parents(Path::new(path), false); - - // 0x - assert!(m("ROOT/file_root_00").is_ignore()); - assert!(m("ROOT/file_root_01").is_none()); - assert!(m("ROOT/file_root_02").is_none()); - assert!(m("ROOT/file_root_03").is_none()); - - // 1x - assert!(m("ROOT/file_root_10").is_ignore()); - assert!(m("ROOT/file_root_11").is_none()); - assert!(m("ROOT/file_root_12").is_none()); - assert!(m("ROOT/file_root_13").is_none()); - - // 2x - assert!(m("ROOT/file_root_20").is_none()); - assert!(m("ROOT/file_root_21").is_none()); - assert!(m("ROOT/file_root_22").is_none()); - assert!(m("ROOT/file_root_23").is_none()); - - // 3x - assert!(m("ROOT/file_root_30").is_ignore()); - assert!(m("ROOT/file_root_31").is_none()); - assert!(m("ROOT/file_root_32").is_none()); - assert!(m("ROOT/file_root_33").is_none()); -} - - -#[test] -fn test_files_in_deep() { - let gitignore = get_gitignore(); - let m = |path: &str| gitignore.matched_path_or_any_parents(Path::new(path), false); - - // 0x - assert!(m("ROOT/parent_dir/file_deep_00").is_ignore()); - assert!(m("ROOT/parent_dir/file_deep_01").is_none()); - assert!(m("ROOT/parent_dir/file_deep_02").is_none()); - assert!(m("ROOT/parent_dir/file_deep_03").is_none()); - - // 1x - assert!(m("ROOT/parent_dir/file_deep_10").is_none()); - assert!(m("ROOT/parent_dir/file_deep_11").is_none()); - assert!(m("ROOT/parent_dir/file_deep_12").is_none()); - assert!(m("ROOT/parent_dir/file_deep_13").is_none()); - - // 2x - assert!(m("ROOT/parent_dir/file_deep_20").is_ignore()); - assert!(m("ROOT/parent_dir/file_deep_21").is_none()); - assert!(m("ROOT/parent_dir/file_deep_22").is_none()); - assert!(m("ROOT/parent_dir/file_deep_23").is_none()); - - // 3x - assert!(m("ROOT/parent_dir/file_deep_30").is_ignore()); - assert!(m("ROOT/parent_dir/file_deep_31").is_none()); - assert!(m("ROOT/parent_dir/file_deep_32").is_none()); - assert!(m("ROOT/parent_dir/file_deep_33").is_none()); -} - - -#[test] -fn test_dirs_in_root() { - let gitignore = get_gitignore(); - let m = - |path: &str, is_dir: bool| gitignore.matched_path_or_any_parents(Path::new(path), is_dir); - - // 00 - assert!(m("ROOT/dir_root_00", true).is_ignore()); - assert!(m("ROOT/dir_root_00/file", false).is_ignore()); - assert!(m("ROOT/dir_root_00/child_dir", true).is_ignore()); - assert!(m("ROOT/dir_root_00/child_dir/file", false).is_ignore()); - - // 01 - assert!(m("ROOT/dir_root_01", true).is_ignore()); - assert!(m("ROOT/dir_root_01/file", false).is_ignore()); - assert!(m("ROOT/dir_root_01/child_dir", true).is_ignore()); - assert!(m("ROOT/dir_root_01/child_dir/file", false).is_ignore()); - - // 02 - assert!(m("ROOT/dir_root_02", true).is_none()); // dir itself doesn't match - assert!(m("ROOT/dir_root_02/file", false).is_ignore()); - assert!(m("ROOT/dir_root_02/child_dir", true).is_ignore()); - assert!(m("ROOT/dir_root_02/child_dir/file", false).is_ignore()); - - // 03 - assert!(m("ROOT/dir_root_03", true).is_none()); // dir itself doesn't match - assert!(m("ROOT/dir_root_03/file", false).is_ignore()); - assert!(m("ROOT/dir_root_03/child_dir", true).is_ignore()); - assert!(m("ROOT/dir_root_03/child_dir/file", false).is_ignore()); - - // 10 - assert!(m("ROOT/dir_root_10", true).is_ignore()); - assert!(m("ROOT/dir_root_10/file", false).is_ignore()); - assert!(m("ROOT/dir_root_10/child_dir", true).is_ignore()); - assert!(m("ROOT/dir_root_10/child_dir/file", false).is_ignore()); - - // 11 - assert!(m("ROOT/dir_root_11", true).is_ignore()); - assert!(m("ROOT/dir_root_11/file", false).is_ignore()); - assert!(m("ROOT/dir_root_11/child_dir", true).is_ignore()); - assert!(m("ROOT/dir_root_11/child_dir/file", false).is_ignore()); - - // 12 - assert!(m("ROOT/dir_root_12", true).is_none()); // dir itself doesn't match - assert!(m("ROOT/dir_root_12/file", false).is_ignore()); - assert!(m("ROOT/dir_root_12/child_dir", true).is_ignore()); - assert!(m("ROOT/dir_root_12/child_dir/file", false).is_ignore()); - - // 13 - assert!(m("ROOT/dir_root_13", true).is_none()); - assert!(m("ROOT/dir_root_13/file", false).is_ignore()); - assert!(m("ROOT/dir_root_13/child_dir", true).is_ignore()); - assert!(m("ROOT/dir_root_13/child_dir/file", false).is_ignore()); - - // 20 - assert!(m("ROOT/dir_root_20", true).is_none()); - assert!(m("ROOT/dir_root_20/file", false).is_none()); - assert!(m("ROOT/dir_root_20/child_dir", true).is_none()); - assert!(m("ROOT/dir_root_20/child_dir/file", false).is_none()); - - // 21 - assert!(m("ROOT/dir_root_21", true).is_none()); - assert!(m("ROOT/dir_root_21/file", false).is_none()); - assert!(m("ROOT/dir_root_21/child_dir", true).is_none()); - assert!(m("ROOT/dir_root_21/child_dir/file", false).is_none()); - - // 22 - assert!(m("ROOT/dir_root_22", true).is_none()); - assert!(m("ROOT/dir_root_22/file", false).is_none()); - assert!(m("ROOT/dir_root_22/child_dir", true).is_none()); - assert!(m("ROOT/dir_root_22/child_dir/file", false).is_none()); - - // 23 - assert!(m("ROOT/dir_root_23", true).is_none()); - assert!(m("ROOT/dir_root_23/file", false).is_none()); - assert!(m("ROOT/dir_root_23/child_dir", true).is_none()); - assert!(m("ROOT/dir_root_23/child_dir/file", false).is_none()); - - // 30 - assert!(m("ROOT/dir_root_30", true).is_ignore()); - assert!(m("ROOT/dir_root_30/file", false).is_ignore()); - assert!(m("ROOT/dir_root_30/child_dir", true).is_ignore()); - assert!(m("ROOT/dir_root_30/child_dir/file", false).is_ignore()); - - // 31 - assert!(m("ROOT/dir_root_31", true).is_ignore()); - assert!(m("ROOT/dir_root_31/file", false).is_ignore()); - assert!(m("ROOT/dir_root_31/child_dir", true).is_ignore()); - assert!(m("ROOT/dir_root_31/child_dir/file", false).is_ignore()); - - // 32 - assert!(m("ROOT/dir_root_32", true).is_none()); // dir itself doesn't match - assert!(m("ROOT/dir_root_32/file", false).is_ignore()); - assert!(m("ROOT/dir_root_32/child_dir", true).is_ignore()); - assert!(m("ROOT/dir_root_32/child_dir/file", false).is_ignore()); - - // 33 - assert!(m("ROOT/dir_root_33", true).is_none()); // dir itself doesn't match - assert!(m("ROOT/dir_root_33/file", false).is_ignore()); - assert!(m("ROOT/dir_root_33/child_dir", true).is_ignore()); - assert!(m("ROOT/dir_root_33/child_dir/file", false).is_ignore()); -} - - -#[test] -fn test_dirs_in_deep() { - let gitignore = get_gitignore(); - let m = - |path: &str, is_dir: bool| gitignore.matched_path_or_any_parents(Path::new(path), is_dir); - - // 00 - assert!(m("ROOT/parent_dir/dir_deep_00", true).is_ignore()); - assert!(m("ROOT/parent_dir/dir_deep_00/file", false).is_ignore()); - assert!(m("ROOT/parent_dir/dir_deep_00/child_dir", true).is_ignore()); - assert!(m("ROOT/parent_dir/dir_deep_00/child_dir/file", false).is_ignore()); - - // 01 - assert!(m("ROOT/parent_dir/dir_deep_01", true).is_ignore()); - assert!(m("ROOT/parent_dir/dir_deep_01/file", false).is_ignore()); - assert!(m("ROOT/parent_dir/dir_deep_01/child_dir", true).is_ignore()); - assert!(m("ROOT/parent_dir/dir_deep_01/child_dir/file", false).is_ignore()); - - // 02 - assert!(m("ROOT/parent_dir/dir_deep_02", true).is_none()); - assert!(m("ROOT/parent_dir/dir_deep_02/file", false).is_none()); - assert!(m("ROOT/parent_dir/dir_deep_02/child_dir", true).is_none()); - assert!(m("ROOT/parent_dir/dir_deep_02/child_dir/file", false).is_none()); - - // 03 - assert!(m("ROOT/parent_dir/dir_deep_03", true).is_none()); - assert!(m("ROOT/parent_dir/dir_deep_03/file", false).is_none()); - assert!(m("ROOT/parent_dir/dir_deep_03/child_dir", true).is_none()); - assert!(m("ROOT/parent_dir/dir_deep_03/child_dir/file", false).is_none()); - - // 10 - assert!(m("ROOT/parent_dir/dir_deep_10", true).is_none()); - assert!(m("ROOT/parent_dir/dir_deep_10/file", false).is_none()); - assert!(m("ROOT/parent_dir/dir_deep_10/child_dir", true).is_none()); - assert!(m("ROOT/parent_dir/dir_deep_10/child_dir/file", false).is_none()); - - // 11 - assert!(m("ROOT/parent_dir/dir_deep_11", true).is_none()); - assert!(m("ROOT/parent_dir/dir_deep_11/file", false).is_none()); - assert!(m("ROOT/parent_dir/dir_deep_11/child_dir", true).is_none()); - assert!(m("ROOT/parent_dir/dir_deep_11/child_dir/file", false).is_none()); - - // 12 - assert!(m("ROOT/parent_dir/dir_deep_12", true).is_none()); - assert!(m("ROOT/parent_dir/dir_deep_12/file", false).is_none()); - assert!(m("ROOT/parent_dir/dir_deep_12/child_dir", true).is_none()); - assert!(m("ROOT/parent_dir/dir_deep_12/child_dir/file", false).is_none()); - - // 13 - assert!(m("ROOT/parent_dir/dir_deep_13", true).is_none()); - assert!(m("ROOT/parent_dir/dir_deep_13/file", false).is_none()); - assert!(m("ROOT/parent_dir/dir_deep_13/child_dir", true).is_none()); - assert!(m("ROOT/parent_dir/dir_deep_13/child_dir/file", false).is_none()); - - // 20 - assert!(m("ROOT/parent_dir/dir_deep_20", true).is_ignore()); - assert!(m("ROOT/parent_dir/dir_deep_20/file", false).is_ignore()); - assert!(m("ROOT/parent_dir/dir_deep_20/child_dir", true).is_ignore()); - assert!(m("ROOT/parent_dir/dir_deep_20/child_dir/file", false).is_ignore()); - - // 21 - assert!(m("ROOT/parent_dir/dir_deep_21", true).is_ignore()); - assert!(m("ROOT/parent_dir/dir_deep_21/file", false).is_ignore()); - assert!(m("ROOT/parent_dir/dir_deep_21/child_dir", true).is_ignore()); - assert!(m("ROOT/parent_dir/dir_deep_21/child_dir/file", false).is_ignore()); - - // 22 - assert!(m("ROOT/parent_dir/dir_deep_22", true).is_none()); // dir itself doesn't match - assert!(m("ROOT/parent_dir/dir_deep_22/file", false).is_ignore()); - assert!(m("ROOT/parent_dir/dir_deep_22/child_dir", true).is_ignore()); - assert!(m("ROOT/parent_dir/dir_deep_22/child_dir/file", false).is_ignore()); - - // 23 - assert!(m("ROOT/parent_dir/dir_deep_23", true).is_none()); // dir itself doesn't match - assert!(m("ROOT/parent_dir/dir_deep_23/file", false).is_ignore()); - assert!(m("ROOT/parent_dir/dir_deep_23/child_dir", true).is_ignore()); - assert!(m("ROOT/parent_dir/dir_deep_23/child_dir/file", false).is_ignore()); - - // 30 - assert!(m("ROOT/parent_dir/dir_deep_30", true).is_ignore()); - assert!(m("ROOT/parent_dir/dir_deep_30/file", false).is_ignore()); - assert!(m("ROOT/parent_dir/dir_deep_30/child_dir", true).is_ignore()); - assert!(m("ROOT/parent_dir/dir_deep_30/child_dir/file", false).is_ignore()); - - // 31 - assert!(m("ROOT/parent_dir/dir_deep_31", true).is_ignore()); - assert!(m("ROOT/parent_dir/dir_deep_31/file", false).is_ignore()); - assert!(m("ROOT/parent_dir/dir_deep_31/child_dir", true).is_ignore()); - assert!(m("ROOT/parent_dir/dir_deep_31/child_dir/file", false).is_ignore()); - - // 32 - assert!(m("ROOT/parent_dir/dir_deep_32", true).is_none()); // dir itself doesn't match - assert!(m("ROOT/parent_dir/dir_deep_32/file", false).is_ignore()); - assert!(m("ROOT/parent_dir/dir_deep_32/child_dir", true).is_ignore()); - assert!(m("ROOT/parent_dir/dir_deep_32/child_dir/file", false).is_ignore()); - - // 33 - assert!(m("ROOT/parent_dir/dir_deep_33", true).is_none()); // dir itself doesn't match - assert!(m("ROOT/parent_dir/dir_deep_33/file", false).is_ignore()); - assert!(m("ROOT/parent_dir/dir_deep_33/child_dir", true).is_ignore()); - assert!(m("ROOT/parent_dir/dir_deep_33/child_dir/file", false).is_ignore()); -} diff --git a/pkg/brew/ripgrep-bin.rb b/pkg/brew/ripgrep-bin.rb deleted file mode 100644 index 3dc617b..0000000 --- a/pkg/brew/ripgrep-bin.rb +++ /dev/null @@ -1,24 +0,0 @@ -class RipgrepBin < Formula - version '0.8.1' - desc "Recursively search directories for a regex pattern." - homepage "https://github.com/BurntSushi/ripgrep" - - if OS.mac? - url "https://github.com/BurntSushi/ripgrep/releases/download/#{version}/ripgrep-#{version}-x86_64-apple-darwin.tar.gz" - sha256 "71f8d2907b473e5fc30159b822b0f1de247634ee292d5cc3fa1bb80222e0f613" - elsif OS.linux? - url "https://github.com/BurntSushi/ripgrep/releases/download/#{version}/ripgrep-#{version}-x86_64-unknown-linux-musl.tar.gz" - sha256 "08b1aa1440a23a88c94cff41a860340ecf38e9108817aff30ff778c00c63eb76" - end - - conflicts_with "ripgrep" - - def install - bin.install "rg" - man1.install "doc/rg.1" - - bash_completion.install "complete/rg.bash" - fish_completion.install "complete/rg.fish" - zsh_completion.install "complete/_rg" - end -end diff --git a/snapcraft.yaml b/snapcraft.yaml deleted file mode 100644 index c83fb47..0000000 --- a/snapcraft.yaml +++ /dev/null @@ -1,14 +0,0 @@ -name: ripgrep # you probably want to 'snapcraft register ' -version: '0.8.1' # just for humans, typically '1.2+git' or '1.3.2' -summary: Fast file searcher # 79 char long summary -description: | - ripgrep combines the usability of The Silver Searcher with the raw speed of grep. -grade: stable # must be 'stable' to release into candidate/stable channels -confinement: classic # use 'strict' once you have the right plugs and slots -parts: - ripgrep: - plugin: rust - source: . -apps: - rg: - command: env PATH=$SNAP/bin:$PATH rg diff --git a/src/app.rs b/src/app.rs deleted file mode 100644 index 5728371..0000000 --- a/src/app.rs +++ /dev/null @@ -1,1713 +0,0 @@ -// This module defines the set of command line arguments that ripgrep supports, -// including some light validation. -// -// This module is purposely written in a bare-bones way, since it is included -// in ripgrep's build.rs file as a way to generate completion files for common -// shells. -// -// The only other place that ripgrep deals with clap is in src/args.rs, which -// is where we read clap's configuration from the end user's arguments and turn -// it into a ripgrep-specific configuration type that is not coupled with clap. - -use clap::{self, App, AppSettings}; - -const ABOUT: &str = " -ripgrep (rg) recursively searches your current directory for a regex pattern. -By default, ripgrep will respect your `.gitignore` and automatically skip -hidden files/directories and binary files. - -ripgrep's regex engine uses finite automata and guarantees linear time -searching. Because of this, features like backreferences and arbitrary -lookaround are not supported. - -ripgrep supports configuration files. Set RIPGREP_CONFIG_PATH to a -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 -README. - -Project home page: https://github.com/BurntSushi/ripgrep - -Use -h for short descriptions and --help for more details."; - -const USAGE: &str = " - rg [OPTIONS] PATTERN [PATH ...] - rg [OPTIONS] [-e PATTERN ...] [-f PATTERNFILE ...] [PATH ...] - rg [OPTIONS] --files [PATH ...] - rg [OPTIONS] --type-list"; - -const TEMPLATE: &str = "\ -{bin} {version} -{author} -{about} - -USAGE:{usage} - -ARGS: -{positionals} - -OPTIONS: -{unified}"; - -/// Build a clap application parameterized by usage strings. -pub fn app() -> App<'static, 'static> { - // We need to specify our version in a static because we've painted clap - // into a corner. We've told it that every string we give it will be - // 'static, but we need to build the version string dynamically. We can - // fake the 'static lifetime with lazy_static. - lazy_static! { - static ref LONG_VERSION: String = long_version(None); - } - - let mut app = App::new("ripgrep") - .author(crate_authors!()) - .version(crate_version!()) - .long_version(LONG_VERSION.as_str()) - .about(ABOUT) - .max_term_width(100) - .setting(AppSettings::UnifiedHelpMessage) - .setting(AppSettings::AllArgsOverrideSelf) - .usage(USAGE) - .template(TEMPLATE) - .help_message("Prints help information. Use --help for more details."); - for arg in all_args_and_flags() { - app = app.arg(arg.claparg); - } - app -} - -/// Return the "long" format of ripgrep's version string. -/// -/// If a revision hash is given, then it is used. If one isn't given, then -/// the RIPGREP_BUILD_GIT_HASH env var is inspect for it. If that isn't set, -/// then a revision hash is not included in the version string returned. -pub fn long_version(revision_hash: Option<&str>) -> String { - // Let's say whether faster CPU instructions are enabled or not. - let mut features = vec![]; - if cfg!(feature = "simd-accel") { - features.push("+SIMD"); - } else { - features.push("-SIMD"); - } - if cfg!(feature = "avx-accel") { - features.push("+AVX"); - } else { - features.push("-AVX"); - } - // Do we have a git hash? - // (Yes, if ripgrep was built on a machine with `git` installed.) - let hash = match revision_hash.or(option_env!("RIPGREP_BUILD_GIT_HASH")) { - None => String::new(), - Some(githash) => format!(" (rev {})", githash), - }; - // Put everything together. - format!("{}{}\n{}", crate_version!(), hash, features.join(" ")) -} - -/// Arg is a light alias for a clap::Arg that is specialized to compile time -/// string literals. -type Arg = clap::Arg<'static, 'static>; - -/// RGArg is a light wrapper around a clap::Arg and also contains some metadata -/// about the underlying Arg so that it can be inspected for other purposes -/// (e.g., hopefully generating a man page). -/// -/// Note that this type is purposely overly constrained to ripgrep's particular -/// use of clap. -#[allow(dead_code)] -#[derive(Clone)] -pub struct RGArg { - /// The underlying clap argument. - claparg: Arg, - /// The name of this argument. This is always present and is the name - /// used in the code to find the value of an argument at runtime. - pub name: &'static str, - /// A short documentation string describing this argument. This string - /// should fit on a single line and be a complete sentence. - /// - /// This is shown in the `-h` output. - pub doc_short: &'static str, - /// A longer documentation string describing this argument. This usually - /// starts with the contents of `doc_short`. This is also usually many - /// lines, potentially paragraphs, and may contain examples and additional - /// prose. - /// - /// This is shown in the `--help` output. - pub doc_long: &'static str, - /// Whether this flag is hidden or not. - /// - /// This is typically used for uncommon flags that only serve to override - /// other flags. For example, --no-ignore is a prominent flag that disables - /// ripgrep's gitignore functionality, but --ignore re-enables it. Since - /// gitignore support is enabled by default, use of the --ignore flag is - /// somewhat niche and relegated to special cases when users make use of - /// configuration files to set defaults. - /// - /// Generally, these flags should be documented in the documentation for - /// the flag they override. - pub hidden: bool, - /// The type of this argument. - pub kind: RGArgKind, -} - -/// The kind of a ripgrep argument. -/// -/// This can be one of three possibilities: a positional argument, a boolean -/// switch flag or a flag that accepts exactly one argument. Each variant -/// stores argument type specific data. -/// -/// Note that clap supports more types of arguments than this, but we don't -/// (and probably shouldn't) use them in ripgrep. -/// -/// Finally, note that we don't capture *all* state about an argument in this -/// type. Some state is only known to clap. There isn't any particular reason -/// why; the state we do capture is motivated by use cases (like generating -/// documentation). -#[derive(Clone)] -pub enum RGArgKind { - /// A positional argument. - Positional { - /// The name of the value used in the `-h/--help` output. By - /// convention, this is an all-uppercase string. e.g., `PATH` or - /// `PATTERN`. - value_name: &'static str, - /// Whether an argument can be repeated multiple times or not. - /// - /// The only argument this applies to is PATH, where an end user can - /// specify multiple paths for ripgrep to search. - /// - /// If this is disabled, then an argument can only be provided once. - /// For example, PATTERN is one such argument. (Note that the - /// -e/--regexp flag is distinct from the positional PATTERN argument, - /// and it can be provided multiple times.) - multiple: bool, - }, - /// A boolean switch. - Switch { - /// The long name of a flag. This is always non-empty. - long: &'static str, - /// The short name of a flag. This is empty if a flag only has a long - /// name. - short: Option<&'static str>, - /// Whether this switch can be provided multiple times where meaning - /// is attached to the number of times this flag is given. - /// - /// Note that every switch can be provided multiple times. This - /// particular state indicates whether all instances of a switch are - /// relevant or not. - /// - /// For example, the -u/--unrestricted flag can be provided multiple - /// times where each repeated use of it indicates more relaxing of - /// ripgrep's filtering. Conversely, the -i/--ignore-case flag can - /// also be provided multiple times, but it is simply considered either - /// present or not. In these cases, -u/--unrestricted has `multiple` - /// set to `true` while -i/--ignore-case has `multiple` set to `false`. - multiple: bool, - }, - /// A flag the accepts a single value. - Flag { - /// The long name of a flag. This is always non-empty. - long: &'static str, - /// The short name of a flag. This is empty if a flag only has a long - /// name. - short: Option<&'static str>, - /// The name of the value used in the `-h/--help` output. By - /// convention, this is an all-uppercase string. e.g., `PATH` or - /// `PATTERN`. - value_name: &'static str, - /// Whether this flag can be provided multiple times with multiple - /// distinct values. - /// - /// Note that every flag can be provided multiple times. This - /// particular state indicates whether all instances of a flag are - /// relevant or not. - /// - /// For example, the -g/--glob flag can be provided multiple times and - /// all of its values should be interpreted by ripgrep. Conversely, - /// while the -C/--context flag can also be provided multiple times, - /// only its last instance is used while all previous instances are - /// ignored. In these cases, -g/--glob has `multiple` set to `true` - /// while -C/--context has `multiple` set to `false`. - multiple: bool, - /// A set of possible values for this flag. If an end user provides - /// any value other than what's in this set, then clap will report an - /// error. - possible_values: Vec<&'static str>, - } -} - -impl RGArg { - /// Create a positional argument. - /// - /// The `long_name` parameter is the name of the argument, e.g., `pattern`. - /// The `value_name` parameter is a name that describes the type of - /// argument this flag accepts. It should be in uppercase, e.g., PATH or - /// PATTERN. - fn positional(name: &'static str, value_name: &'static str) -> RGArg { - RGArg { - claparg: Arg::with_name(name).value_name(value_name), - name: name, - doc_short: "", - doc_long: "", - hidden: false, - kind: RGArgKind::Positional { - value_name: value_name, - multiple: false, - }, - } - } - - /// Create a boolean switch. - /// - /// The `long_name` parameter is the name of the flag, e.g., `--long-name`. - /// - /// All switches may be repeated an arbitrary number of times. If a switch - /// is truly boolean, that consumers of clap's configuration should only - /// check whether the flag is present or not. Otherwise, consumers may - /// inspect the number of times the switch is used. - fn switch(long_name: &'static str) -> RGArg { - let claparg = Arg::with_name(long_name) - .long(long_name); - RGArg { - claparg: claparg, - name: long_name, - doc_short: "", - doc_long: "", - hidden: false, - kind: RGArgKind::Switch { - long: long_name, - short: None, - multiple: false, - }, - } - } - - /// Create a flag. A flag always accepts exactly one argument. - /// - /// The `long_name` parameter is the name of the flag, e.g., `--long-name`. - /// The `value_name` parameter is a name that describes the type of - /// argument this flag accepts. It should be in uppercase, e.g., PATH or - /// PATTERN. - /// - /// All flags may be repeated an arbitrary number of times. If a flag has - /// only one logical value, that consumers of clap's configuration should - /// only use the last value. - fn flag(long_name: &'static str, value_name: &'static str) -> RGArg { - let claparg = Arg::with_name(long_name) - .long(long_name) - .value_name(value_name) - .takes_value(true) - .number_of_values(1); - RGArg { - claparg: claparg, - name: long_name, - doc_short: "", - doc_long: "", - hidden: false, - kind: RGArgKind::Flag { - long: long_name, - short: None, - value_name: value_name, - multiple: false, - possible_values: vec![], - } - } - } - - /// Set the short flag name. - /// - /// This panics if this arg isn't a switch or a flag. - fn short(mut self, name: &'static str) -> RGArg { - match self.kind { - RGArgKind::Positional{..} => panic!("expected switch or flag"), - RGArgKind::Switch { ref mut short, .. } => { - *short = Some(name); - } - RGArgKind::Flag { ref mut short, .. } => { - *short = Some(name); - } - } - self.claparg = self.claparg.short(name); - self - } - - /// Set the "short" help text. - /// - /// This should be a single line. It is shown in the `-h` output. - fn help(mut self, text: &'static str) -> RGArg { - self.doc_short = text; - self.claparg = self.claparg.help(text); - self - } - - /// Set the "long" help text. - /// - /// This should be at least a single line, usually longer. It is shown in - /// the `--help` output. - fn long_help(mut self, text: &'static str) -> RGArg { - self.doc_long = text; - self.claparg = self.claparg.long_help(text); - self - } - - /// Enable this argument to accept multiple values. - /// - /// Note that while switches and flags can always be repeated an arbitrary - /// number of times, this particular method enables the flag to be - /// logically repeated where each occurrence of the flag may have - /// significance. That is, when this is disabled, then a switch is either - /// present or not and a flag has exactly one value (the last one given). - /// When this is enabled, then a switch has a count corresponding to the - /// number of times it is used and a flag's value is a list of all values - /// given. - /// - /// For the most part, this distinction is resolved by consumers of clap's - /// configuration. - fn multiple(mut self) -> RGArg { - // Why not put `multiple` on RGArg proper? Because it's useful to - // document it distinct for each different kind. See RGArgKind docs. - match self.kind { - RGArgKind::Positional { ref mut multiple, .. } => { - *multiple = true; - } - RGArgKind::Switch { ref mut multiple, .. } => { - *multiple = true; - } - RGArgKind::Flag { ref mut multiple, .. } => { - *multiple = true; - } - } - self.claparg = self.claparg.multiple(true); - self - } - - /// Hide this flag from all documentation. - fn hidden(mut self) -> RGArg { - self.hidden = true; - self.claparg = self.claparg.hidden(true); - self - } - - /// Set the possible values for this argument. If this argument is not - /// a flag, then this panics. - /// - /// If the end user provides any value other than what is given here, then - /// clap will report an error to the user. - /// - /// Note that this will suppress clap's automatic output of possible values - /// when using -h/--help, so users of this method should provide - /// appropriate documentation for the choices in the "long" help text. - fn possible_values(mut self, values: &[&'static str]) -> RGArg { - match self.kind { - RGArgKind::Positional{..} => panic!("expected flag"), - RGArgKind::Switch{..} => panic!("expected flag"), - RGArgKind::Flag { ref mut possible_values, .. } => { - *possible_values = values.to_vec(); - self.claparg = self.claparg - .possible_values(values) - .hide_possible_values(true); - } - } - self - } - - /// Add an alias to this argument. - /// - /// Aliases are not show in the output of -h/--help. - fn alias(mut self, name: &'static str) -> RGArg { - self.claparg = self.claparg.alias(name); - self - } - - /// Permit this flag to have values that begin with a hypen. - /// - /// This panics if this arg is not a flag. - fn allow_leading_hyphen(mut self) -> RGArg { - match self.kind { - RGArgKind::Positional{..} => panic!("expected flag"), - RGArgKind::Switch{..} => panic!("expected flag"), - RGArgKind::Flag {..} => { - self.claparg = self.claparg.allow_hyphen_values(true); - } - } - self - } - - /// Sets this argument to a required argument, unless one of the given - /// arguments is provided. - fn required_unless(mut self, names: &[&'static str]) -> RGArg { - self.claparg = self.claparg.required_unless_one(names); - self - } - - /// Sets conflicting arguments. That is, if this argument is used whenever - /// any of the other arguments given here are used, then clap will report - /// an error. - fn conflicts(mut self, names: &[&'static str]) -> RGArg { - self.claparg = self.claparg.conflicts_with_all(names); - self - } - - /// Sets an overriding argument. That is, if this argument and the given - /// argument are both provided by an end user, then the "last" one will - /// win. ripgrep will behave as if any previous instantiations did not - /// happen. - fn overrides(mut self, name: &'static str) -> RGArg { - self.claparg = self.claparg.overrides_with(name); - self - } - - /// Sets the default value of this argument if and only if the argument - /// given is present. - fn default_value_if( - mut self, - value: &'static str, - arg_name: &'static str, - ) -> RGArg { - self.claparg = self.claparg.default_value_if(arg_name, None, value); - self - } - - /// Indicate that any value given to this argument should be a number. If - /// it's not a number, then clap will report an error to the end user. - fn number(mut self) -> RGArg { - self.claparg = self.claparg.validator(|val| { - val.parse::().map(|_| ()).map_err(|err| err.to_string()) - }); - self - } -} - -// We add an extra space to long descriptions so that a black line is inserted -// between flag descriptions in --help output. -macro_rules! long { - ($lit:expr) => { concat!($lit, " ") } -} - -/// Generate a sequence of all positional and flag arguments. -pub fn all_args_and_flags() -> Vec { - let mut args = vec![]; - // The positional arguments must be defined first and in order. - arg_pattern(&mut args); - arg_path(&mut args); - // Flags can be defined in any order, but we do it alphabetically. - flag_after_context(&mut args); - flag_before_context(&mut args); - flag_byte_offset(&mut args); - flag_case_sensitive(&mut args); - flag_color(&mut args); - flag_colors(&mut args); - flag_column(&mut args); - flag_context(&mut args); - flag_context_separator(&mut args); - flag_count(&mut args); - flag_count_matches(&mut args); - flag_debug(&mut args); - flag_dfa_size_limit(&mut args); - flag_encoding(&mut args); - flag_file(&mut args); - flag_files(&mut args); - flag_files_with_matches(&mut args); - flag_files_without_match(&mut args); - flag_fixed_strings(&mut args); - flag_follow(&mut args); - flag_glob(&mut args); - flag_heading(&mut args); - flag_hidden(&mut args); - flag_iglob(&mut args); - flag_ignore_case(&mut args); - flag_ignore_file(&mut args); - flag_invert_match(&mut args); - flag_line_number(&mut args); - flag_line_regexp(&mut args); - flag_max_columns(&mut args); - flag_max_count(&mut args); - flag_max_depth(&mut args); - flag_max_filesize(&mut args); - flag_mmap(&mut args); - flag_no_config(&mut args); - flag_no_ignore(&mut args); - flag_no_ignore_messages(&mut args); - flag_no_ignore_parent(&mut args); - flag_no_ignore_vcs(&mut args); - flag_no_messages(&mut args); - flag_null(&mut args); - flag_only_matching(&mut args); - flag_path_separator(&mut args); - flag_passthru(&mut args); - flag_pretty(&mut args); - flag_quiet(&mut args); - flag_regex_size_limit(&mut args); - flag_regexp(&mut args); - flag_replace(&mut args); - flag_search_zip(&mut args); - flag_smart_case(&mut args); - flag_sort_files(&mut args); - flag_stats(&mut args); - flag_text(&mut args); - flag_threads(&mut args); - flag_type(&mut args); - flag_type_add(&mut args); - flag_type_clear(&mut args); - flag_type_list(&mut args); - flag_type_not(&mut args); - flag_unrestricted(&mut args); - flag_vimgrep(&mut args); - flag_with_filename(&mut args); - flag_word_regexp(&mut args); - args -} - -fn arg_pattern(args: &mut Vec) { - const SHORT: &str = "A regular expression used for searching."; - const LONG: &str = long!("\ -A regular expression used for searching. To match a pattern beginning with a -dash, use the -e/--regexp flag. - -For example, to search for the literal '-foo', you can use this flag: - - rg -e -foo - -You can also use the special '--' delimiter to indicate that no more flags -will be provided. Namely, the following is equivalent to the above: - - rg -- -foo -"); - let arg = RGArg::positional("pattern", "PATTERN") - .help(SHORT).long_help(LONG) - .required_unless(&[ - "file", "files", "regexp", "type-list", - ]); - args.push(arg); -} - -fn arg_path(args: &mut Vec) { - const SHORT: &str = "A file or directory to search."; - const LONG: &str = long!("\ -A file or directory to search. Directories are searched recursively. Paths \ -specified on the command line override glob and ignore rules. \ -"); - let arg = RGArg::positional("path", "PATH") - .help(SHORT).long_help(LONG) - .multiple(); - args.push(arg); -} - -fn flag_after_context(args: &mut Vec) { - const SHORT: &str = "Show NUM lines after each match."; - const LONG: &str = long!("\ -Show NUM lines after each match. - -This overrides the --context flag. -"); - let arg = RGArg::flag("after-context", "NUM").short("A") - .help(SHORT).long_help(LONG) - .number() - .overrides("context"); - args.push(arg); -} - -fn flag_before_context(args: &mut Vec) { - const SHORT: &str = "Show NUM lines before each match."; - const LONG: &str = long!("\ -Show NUM lines before each match. - -This overrides the --context flag. -"); - let arg = RGArg::flag("before-context", "NUM").short("B") - .help(SHORT).long_help(LONG) - .number() - .overrides("context"); - args.push(arg); -} - -fn flag_byte_offset(args: &mut Vec) { - const SHORT: &str = - "Print the 0-based byte offset for each matching line."; - const LONG: &str = long!("\ -Print the 0-based byte offset within the input file -before each line of output. If -o (--only-matching) is -specified, print the offset of the matching part itself. -"); - let arg = RGArg::switch("byte-offset").short("b") - .help(SHORT).long_help(LONG); - args.push(arg); -} - -fn flag_case_sensitive(args: &mut Vec) { - const SHORT: &str = "Search case sensitively (default)."; - const LONG: &str = long!("\ -Search case sensitively. - -This overrides the -i/--ignore-case and -S/--smart-case flags. -"); - let arg = RGArg::switch("case-sensitive").short("s") - .help(SHORT).long_help(LONG) - .overrides("ignore-case") - .overrides("smart-case"); - args.push(arg); -} - -fn flag_color(args: &mut Vec) { - const SHORT: &str = "Controls when to use color."; - const LONG: &str = long!("\ -This flag controls when to use colors. The default setting is 'auto', which -means ripgrep will try to guess when to use colors. For example, if ripgrep is -printing to a terminal, then it will use colors, but if it is redirected to a -file or a pipe, then it will suppress color output. ripgrep will suppress color -output in some other circumstances as well. For example, if the TERM -environment variable is not set or set to 'dumb', then ripgrep will not use -colors. - -The possible values for this flag are: - - never Colors will never be used. - auto The default. ripgrep tries to be smart. - always Colors will always be used regardless of where output is sent. - ansi Like 'always', but emits ANSI escapes (even in a Windows console). - -When the --vimgrep flag is given to ripgrep, then the default value for the ---color flag changes to 'never'. -"); - let arg = RGArg::flag("color", "WHEN") - .help(SHORT).long_help(LONG) - .possible_values(&["never", "auto", "always", "ansi"]) - .default_value_if("never", "vimgrep"); - args.push(arg); -} - -fn flag_colors(args: &mut Vec) { - const SHORT: &str = "Configure color settings and styles."; - const LONG: &str = long!("\ -This flag specifies color settings for use in the output. This flag may be -provided multiple times. Settings are applied iteratively. Colors are limited -to one of eight choices: red, blue, green, cyan, magenta, yellow, white and -black. Styles are limited to nobold, bold, nointense, intense, nounderline -or underline. - -The format of the flag is `{type}:{attribute}:{value}`. `{type}` should be -one of path, line, column or match. `{attribute}` can be fg, bg or style. -`{value}` is either a color (for fg and bg) or a text style. A special format, -`{type}:none`, will clear all color settings for `{type}`. - -For example, the following command will change the match color to magenta and -the background color for line numbers to yellow: - - rg --colors 'match:fg:magenta' --colors 'line:bg:yellow' foo. - -Extended colors can be used for `{value}` when the terminal supports ANSI color -sequences. These are specified as either 'x' (256-color) or 'x,x,x' (24-bit -truecolor) where x is a number between 0 and 255 inclusive. x may be given as -a normal decimal number or a hexadecimal number, which is prefixed by `0x`. - -For example, the following command will change the match background color to -that represented by the rgb value (0,128,255): - - rg --colors 'match:bg:0,128,255' - -or, equivalently, - - rg --colors 'match:bg:0x0,0x80,0xFF' - -Note that the the intense and nointense style flags will have no effect when -used alongside these extended color codes. -"); - let arg = RGArg::flag("colors", "COLOR_SPEC") - .help(SHORT).long_help(LONG) - .multiple(); - args.push(arg); -} - -fn flag_column(args: &mut Vec) { - const SHORT: &str = "Show column numbers."; - const LONG: &str = long!("\ -Show column numbers (1-based). This only shows the column numbers for the first -match on each line. This does not try to account for Unicode. One byte is equal -to one column. This implies --line-number. - -This flag can be disabled with --no-column. -"); - let arg = RGArg::switch("column") - .help(SHORT).long_help(LONG) - .overrides("no-column"); - args.push(arg); - - let arg = RGArg::switch("no-column") - .hidden() - .overrides("column"); - args.push(arg); -} - -fn flag_context(args: &mut Vec) { - const SHORT: &str = "Show NUM lines before and after each match."; - const LONG: &str = long!("\ -Show NUM lines before and after each match. This is equivalent to providing -both the -B/--before-context and -A/--after-context flags with the same value. - -This overrides both the -B/--before-context and -A/--after-context flags. -"); - let arg = RGArg::flag("context", "NUM").short("C") - .help(SHORT).long_help(LONG) - .number() - .overrides("before-context") - .overrides("after-context"); - args.push(arg); -} - -fn flag_context_separator(args: &mut Vec) { - const SHORT: &str = "Set the context separator string."; - const LONG: &str = long!("\ -The string used to separate non-contiguous context lines in the output. Escape -sequences like \\x7F or \\t may be used. The default value is --. -"); - let arg = RGArg::flag("context-separator", "SEPARATOR") - .help(SHORT).long_help(LONG); - args.push(arg); -} - -fn flag_count(args: &mut Vec) { - const SHORT: &str = "Only show the count of matching lines for each file."; - const LONG: &str = long!("\ -This flag suppresses normal output and shows the number of lines that match -the given patterns for each file searched. Each file containing a match has its -path and count printed on each line. Note that this reports the number of lines -that match and not the total number of matches. - -If only one file is given to ripgrep, then only the count is printed if there -is a match. The --with-filename flag can be used to force printing the file -path in this case. - -This overrides the --count-matches flag. Note that when --count is combined -with --only-matching, then ripgrep behaves as if --count-matches was given. -"); - let arg = RGArg::switch("count").short("c") - .help(SHORT).long_help(LONG).overrides("count-matches"); - args.push(arg); -} - -fn flag_count_matches(args: &mut Vec) { - const SHORT: &str = - "Only show the count of individual matches for each file."; - const LONG: &str = long!("\ -This flag suppresses normal output and shows the number of individual -matches of the given patterns for each file searched. Each file -containing matches has its path and match count printed on each line. -Note that this reports the total number of individual matches and not -the number of lines that match. - -If only one file is given to ripgrep, then only the count is printed if there -is a match. The --with-filename flag can be used to force printing the file -path in this case. - -This overrides the --count flag. Note that when --count is combined with ---only-matching, then ripgrep behaves as if --count-matches was given. -"); - let arg = RGArg::switch("count-matches") - .help(SHORT).long_help(LONG).overrides("count"); - args.push(arg); -} - -fn flag_debug(args: &mut Vec) { - const SHORT: &str = "Show debug messages."; - const LONG: &str = long!("\ -Show debug messages. Please use this when filing a bug report. -"); - let arg = RGArg::switch("debug") - .help(SHORT).long_help(LONG); - args.push(arg); -} - -fn flag_dfa_size_limit(args: &mut Vec) { - const SHORT: &str = "The upper size limit of the regex DFA."; - const LONG: &str = long!("\ -The upper size limit of the regex DFA. The default limit is 10M. This should -only be changed on very large regex inputs where the (slower) fallback regex -engine may otherwise be used if the limit is reached. - -The argument accepts the same size suffixes as allowed in with the ---max-filesize flag. -"); - let arg = RGArg::flag("dfa-size-limit", "NUM+SUFFIX?") - .help(SHORT).long_help(LONG); - args.push(arg); -} - -fn flag_encoding(args: &mut Vec) { - const SHORT: &str = "Specify the text encoding of files to search."; - const LONG: &str = long!("\ -Specify the text encoding that ripgrep will use on all files searched. The -default value is 'auto', which will cause ripgrep to do a best effort automatic -detection of encoding on a per-file basis. Other supported values can be found -in the list of labels here: -https://encoding.spec.whatwg.org/#concept-encoding-get -"); - let arg = RGArg::flag("encoding", "ENCODING").short("E") - .help(SHORT).long_help(LONG); - args.push(arg); -} - -fn flag_file(args: &mut Vec) { - const SHORT: &str = "Search for patterns from the given file."; - const LONG: &str = long!("\ -Search for patterns from the given file, with one pattern per line. When this -flag is used multiple times or in combination with the -e/--regexp flag, -then all patterns provided are searched. Empty pattern lines will match all -input lines, and the newline is not counted as part of the pattern. - -A line is printed if and only if it matches at least one of the patterns. -"); - let arg = RGArg::flag("file", "PATTERNFILE").short("f") - .help(SHORT).long_help(LONG) - .multiple() - .allow_leading_hyphen(); - args.push(arg); -} - -fn flag_files(args: &mut Vec) { - const SHORT: &str = "Print each file that would be searched."; - const LONG: &str = long!("\ -Print each file that would be searched without actually performing the search. -This is useful to determine whether a particular file is being search or not. -"); - let arg = RGArg::switch("files") - .help(SHORT).long_help(LONG) - // This also technically conflicts with pattern, but the first file - // path will actually be in pattern. - .conflicts(&["file", "regexp", "type-list"]); - args.push(arg); -} - -fn flag_files_with_matches(args: &mut Vec) { - const SHORT: &str = "Only print the paths with at least one match."; - const LONG: &str = long!("\ -Only print the paths with at least one match. - -This overrides --files-without-match. -"); - let arg = RGArg::switch("files-with-matches").short("l") - .help(SHORT).long_help(LONG) - .overrides("files-without-match"); - args.push(arg); -} - -fn flag_files_without_match(args: &mut Vec) { - const SHORT: &str = "Only print the paths that contain zero matches."; - const LONG: &str = long!("\ -Only print the paths that contain zero matches. This inverts/negates the ---files-with-matches flag. - -This overrides --files-with-matches. -"); - let arg = RGArg::switch("files-without-match") - .help(SHORT).long_help(LONG) - .overrides("files-with-matches"); - args.push(arg); -} - -fn flag_fixed_strings(args: &mut Vec) { - const SHORT: &str = "Treat the pattern as a literal string."; - const LONG: &str = long!("\ -Treat the pattern as a literal string instead of a regular expression. When -this flag is used, special regular expression meta characters such as .(){}*+ -do not need to be escaped. - -This flag can be disabled with --no-fixed-strings. -"); - let arg = RGArg::switch("fixed-strings").short("F") - .help(SHORT).long_help(LONG) - .overrides("no-fixed-strings"); - args.push(arg); - - let arg = RGArg::switch("no-fixed-strings") - .hidden() - .overrides("fixed-strings"); - args.push(arg); -} - -fn flag_follow(args: &mut Vec) { - const SHORT: &str = "Follow symbolic links."; - const LONG: &str = long!("\ -When this flag is enabled, ripgrep will follow symbolic links while traversing -directories. This is disabled by default. Note that ripgrep will check for -symbolic link loops and report errors if it finds one. - -This flag can be disabled with --no-follow. -"); - let arg = RGArg::switch("follow").short("L") - .help(SHORT).long_help(LONG) - .overrides("no-follow"); - args.push(arg); - - let arg = RGArg::switch("no-follow") - .hidden() - .overrides("follow"); - args.push(arg); -} - -fn flag_glob(args: &mut Vec) { - const SHORT: &str = "Include or exclude files."; - const LONG: &str = long!("\ -Include or exclude files and directories for searching that match the given -glob. This always overrides any other ignore logic. Multiple glob flags may be -used. Globbing rules match .gitignore globs. Precede a glob with a ! to exclude -it. -"); - let arg = RGArg::flag("glob", "GLOB").short("g") - .help(SHORT).long_help(LONG) - .multiple() - .allow_leading_hyphen(); - args.push(arg); -} - -fn flag_heading(args: &mut Vec) { - const SHORT: &str = "Print matches grouped by each file."; - const LONG: &str = long!("\ -This flag prints the file path above clusters of matches from each file instead -of printing the file path as a prefix for each matched line. This is the -default mode when printing to a terminal. - -This overrides the --no-heading flag. -"); - let arg = RGArg::switch("heading") - .help(SHORT).long_help(LONG) - .overrides("no-heading"); - args.push(arg); - - const NO_SHORT: &str = "Don't group matches by each file."; - const NO_LONG: &str = long!("\ -Don't group matches by each file. If --no-heading is provided in addition to -the -H/--with-filename flag, then file paths will be printed as a prefix for -every matched line. This is the default mode when not printing to a terminal. - -This overrides the --heading flag. -"); - let arg = RGArg::switch("no-heading") - .help(NO_SHORT).long_help(NO_LONG) - .overrides("heading"); - args.push(arg); -} - -fn flag_hidden(args: &mut Vec) { - const SHORT: &str = "Search hidden files and directories."; - const LONG: &str = long!("\ -Search hidden files and directories. By default, hidden files and directories -are skipped. Note that if a hidden file or a directory is whitelisted in an -ignore file, then it will be searched even if this flag isn't provided. - -This flag can be disabled with --no-hidden. -"); - let arg = RGArg::switch("hidden") - .help(SHORT).long_help(LONG) - .overrides("no-hidden"); - args.push(arg); - - let arg = RGArg::switch("no-hidden") - .hidden() - .overrides("hidden"); - args.push(arg); -} - -fn flag_iglob(args: &mut Vec) { - const SHORT: &str = - "Include or exclude files case insensitively."; - const LONG: &str = long!("\ -Include or exclude files and directories for searching that match the given -glob. This always overrides any other ignore logic. Multiple glob flags may be -used. Globbing rules match .gitignore globs. Precede a glob with a ! to exclude -it. Globs are matched case insensitively. -"); - let arg = RGArg::flag("iglob", "GLOB") - .help(SHORT).long_help(LONG) - .multiple() - .allow_leading_hyphen(); - args.push(arg); -} - -fn flag_ignore_case(args: &mut Vec) { - const SHORT: &str = "Case insensitive search."; - const LONG: &str = long!("\ -When this flag is provided, the given patterns will be searched case -insensitively. The case insensitivity rules used by ripgrep conform to -Unicode's \"simple\" case folding rules. - -This flag overrides -s/--case-sensitive and -S/--smart-case. -"); - let arg = RGArg::switch("ignore-case").short("i") - .help(SHORT).long_help(LONG) - .overrides("case-sensitive") - .overrides("smart-case"); - args.push(arg); -} - -fn flag_ignore_file(args: &mut Vec) { - const SHORT: &str = "Specify additional ignore files."; - const LONG: &str = long!("\ -Specifies a path to one or more .gitignore format rules files. These patterns -are applied after the patterns found in .gitignore and .ignore are applied -and are matched relative to the current working directory. Multiple additional -ignore files can be specified by using the --ignore-file flag several times. -When specifying multiple ignore files, earlier files have lower precedence -than later files. - -If you are looking for a way to include or exclude files and directories -directly on the command line, then used -g instead. -"); - let arg = RGArg::flag("ignore-file", "PATH") - .help(SHORT).long_help(LONG) - .multiple() - .allow_leading_hyphen(); - args.push(arg); -} - -fn flag_invert_match(args: &mut Vec) { - const SHORT: &str = "Invert matching."; - const LONG: &str = long!("\ -Invert matching. Show lines that do not match the given patterns. -"); - let arg = RGArg::switch("invert-match").short("v") - .help(SHORT).long_help(LONG); - args.push(arg); -} - -fn flag_line_number(args: &mut Vec) { - const SHORT: &str = "Show line numbers."; - const LONG: &str = long!("\ -Show line numbers (1-based). This is enabled by default when searching in a -terminal. -"); - let arg = RGArg::switch("line-number").short("n") - .help(SHORT).long_help(LONG) - .overrides("no-line-number"); - args.push(arg); - - const NO_SHORT: &str = "Suppress line numbers."; - const NO_LONG: &str = long!("\ -Suppress line numbers. This is enabled by default when not searching in a -terminal. -"); - let arg = RGArg::switch("no-line-number").short("N") - .help(NO_SHORT).long_help(NO_LONG) - .overrides("line-number"); - args.push(arg); -} - -fn flag_line_regexp(args: &mut Vec) { - const SHORT: &str = "Only show matches surrounded by line boundaries."; - const LONG: &str = long!("\ -Only show matches surrounded by line boundaries. This is equivalent to putting -^...$ around all of the search patterns. In other words, this only prints lines -where the entire line participates in a match. - -This overrides the --word-regexp flag. -"); - let arg = RGArg::switch("line-regexp").short("x") - .help(SHORT).long_help(LONG) - .overrides("word-regexp"); - args.push(arg); -} - -fn flag_max_columns(args: &mut Vec) { - const SHORT: &str = "Don't print lines longer than this limit."; - const LONG: &str = long!("\ -Don't print lines longer than this limit in bytes. Longer lines are omitted, -and only the number of matches in that line is printed. - -When this flag is omitted or is set to 0, then it has no effect. -"); - let arg = RGArg::flag("max-columns", "NUM").short("M") - .help(SHORT).long_help(LONG) - .number(); - args.push(arg); -} - -fn flag_max_count(args: &mut Vec) { - const SHORT: &str = "Limit the number of matches."; - const LONG: &str = long!("\ -Limit the number of matching lines per file searched to NUM. -"); - let arg = RGArg::flag("max-count", "NUM").short("m") - .help(SHORT).long_help(LONG) - .number(); - args.push(arg); -} - -fn flag_max_depth(args: &mut Vec) { - const SHORT: &str = "Descend at most NUM directories."; - const LONG: &str = long!("\ -Limit the depth of directory traversal to NUM levels beyond the paths given. A -value of zero only searches the explicitly given paths themselves. - -For example, 'rg --max-depth 0 dir/' is a no-op because dir/ will not be -descended into. 'rg --max-depth 1 dir/' will search only the direct children of -'dir'. -"); - let arg = RGArg::flag("max-depth", "NUM") - .help(SHORT).long_help(LONG) - .alias("maxdepth") - .number(); - args.push(arg); -} - -fn flag_max_filesize(args: &mut Vec) { - const SHORT: &str = "Ignore files larger than NUM in size."; - const LONG: &str = long!("\ -Ignore files larger than NUM in size. This does not apply to directories. - -The input format accepts suffixes of K, M or G which correspond to kilobytes, -megabytes and gigabytes, respectively. If no suffix is provided the input is -treated as bytes. - -Examples: --max-filesize 50K or --max-filesize 80M -"); - let arg = RGArg::flag("max-filesize", "NUM+SUFFIX?") - .help(SHORT).long_help(LONG); - args.push(arg); -} - -fn flag_mmap(args: &mut Vec) { - const SHORT: &str = "Search using memory maps when possible."; - const LONG: &str = long!("\ -Search using memory maps when possible. This is enabled by default when ripgrep -thinks it will be faster. - -Memory map searching doesn't currently support all options, so if an -incompatible option (e.g., --context) is given with --mmap, then memory maps -will not be used. - -Note that ripgrep may abort unexpectedly when --mmap if it searches a file that -is simultaneously truncated. - -This flag overrides --no-mmap. -"); - let arg = RGArg::switch("mmap") - .help(SHORT).long_help(LONG) - .overrides("no-mmap"); - args.push(arg); - - const NO_SHORT: &str = "Never use memory maps."; - const NO_LONG: &str = long!("\ -Never use memory maps, even when they might be faster. - -This flag overrides --mmap. -"); - let arg = RGArg::switch("no-mmap") - .help(NO_SHORT).long_help(NO_LONG) - .overrides("mmap"); - args.push(arg); -} - -fn flag_no_config(args: &mut Vec) { - const SHORT: &str = "Never read configuration files."; - const LONG: &str = long!("\ -Never read configuration files. When this flag is present, ripgrep will not -respect the RIPGREP_CONFIG_PATH environment variable. - -If ripgrep ever grows a feature to automatically read configuration files in -pre-defined locations, then this flag will also disable that behavior as well. -"); - let arg = RGArg::switch("no-config") - .help(SHORT).long_help(LONG); - args.push(arg); -} - -fn flag_no_ignore(args: &mut Vec) { - const SHORT: &str = "Don't respect ignore files."; - const LONG: &str = long!("\ -Don't respect ignore files (.gitignore, .ignore, etc.). This implies ---no-ignore-parent and --no-ignore-vcs. - -This flag can be disabled with the --ignore flag. -"); - let arg = RGArg::switch("no-ignore") - .help(SHORT).long_help(LONG) - .overrides("ignore"); - args.push(arg); - - let arg = RGArg::switch("ignore") - .hidden() - .overrides("no-ignore"); - args.push(arg); -} - -fn flag_no_ignore_messages(args: &mut Vec) { - const SHORT: &str = "Suppress gitignore parse error messages."; - const LONG: &str = long!("\ -Suppresses all error messages related to parsing ignore files such as .ignore -or .gitignore. - -This flag can be disabled with the --ignore-messages flag. -"); - let arg = RGArg::switch("no-ignore-messages") - .help(SHORT).long_help(LONG) - .overrides("ignore-messages"); - args.push(arg); - - let arg = RGArg::switch("ignore-messages") - .hidden() - .overrides("no-ignore-messages"); - args.push(arg); -} - -fn flag_no_ignore_parent(args: &mut Vec) { - const SHORT: &str = "Don't respect ignore files in parent directories."; - const LONG: &str = long!("\ -Don't respect ignore files (.gitignore, .ignore, etc.) in parent directories. - -This flag can be disabled with the --ignore-parent flag. -"); - let arg = RGArg::switch("no-ignore-parent") - .help(SHORT).long_help(LONG) - .overrides("ignore-parent"); - args.push(arg); - - let arg = RGArg::switch("ignore-parent") - .hidden() - .overrides("no-ignore-parent"); - args.push(arg); -} - -fn flag_no_ignore_vcs(args: &mut Vec) { - const SHORT: &str = "Don't respect VCS ignore files."; - const LONG: &str = long!("\ -Don't respect version control ignore files (.gitignore, etc.). This implies ---no-ignore-parent for VCS files. Note that .ignore files will continue to be -respected. - -This flag can be disabled with the --ignore-vcs flag. -"); - let arg = RGArg::switch("no-ignore-vcs") - .help(SHORT).long_help(LONG) - .overrides("ignore-vcs"); - args.push(arg); - - let arg = RGArg::switch("ignore-vcs") - .hidden() - .overrides("no-ignore-vcs"); - args.push(arg); -} - -fn flag_no_messages(args: &mut Vec) { - const SHORT: &str = "Suppress some error messages."; - const LONG: &str = long!("\ -Suppress all error messages related to opening and reading files. Error -messages related to the syntax of the pattern given are still shown. - -This flag can be disabled with the --messages flag. -"); - let arg = RGArg::switch("no-messages") - .help(SHORT).long_help(LONG) - .overrides("messages"); - args.push(arg); - - let arg = RGArg::switch("messages") - .hidden() - .overrides("no-messages"); - args.push(arg); -} - -fn flag_null(args: &mut Vec) { - const SHORT: &str = "Print a NUL byte after file paths."; - const LONG: &str = long!("\ -Whenever a file path is printed, follow it with a NUL byte. This includes -printing file paths before matches, and when printing a list of matching files -such as with --count, --files-with-matches and --files. This option is useful -for use with xargs. -"); - let arg = RGArg::switch("null").short("0") - .help(SHORT).long_help(LONG); - args.push(arg); -} - -fn flag_only_matching(args: &mut Vec) { - const SHORT: &str = "Print only matches parts of a line."; - const LONG: &str = long!("\ -Print only the matched (non-empty) parts of a matching line, with each such -part on a separate output line. -"); - let arg = RGArg::switch("only-matching").short("o") - .help(SHORT).long_help(LONG); - args.push(arg); -} - -fn flag_path_separator(args: &mut Vec) { - const SHORT: &str = "Set the path separator."; - const LONG: &str = long!("\ -Set the path separator to use when printing file paths. This defaults to your -platform's path separator, which is / on Unix and \\ on Windows. This flag is -intended for overriding the default when the environment demands it (e.g., -cygwin). A path separator is limited to a single byte. -"); - let arg = RGArg::flag("path-separator", "SEPARATOR") - .help(SHORT).long_help(LONG); - args.push(arg); -} - -fn flag_passthru(args: &mut Vec) { - const SHORT: &str = "Print both matching and non-matching lines."; - const LONG: &str = long!("\ -Print both matching and non-matching lines. - -Another way to achieve a similar effect is by modifying your pattern to match -the empty string. For example, if you are searching using 'rg foo' then using -'rg \"^|foo\"' instead will emit every line in every file searched, but only -occurrences of 'foo' will be highlighted. This flag enables the same behavior -without needing to modify the pattern. - -This flag conflicts with the --only-matching and --replace flags. -"); - let arg = RGArg::switch("passthru") - .help(SHORT).long_help(LONG) - .alias("passthrough") - .conflicts(&["only-matching", "replace"]); - args.push(arg); -} - -fn flag_pretty(args: &mut Vec) { - const SHORT: &str = "Alias for --color always --heading --line-number."; - const LONG: &str = long!("\ -This is a convenience alias for '--color always --heading --line-number'. This -flag is useful when you still want pretty output even if you're piping ripgrep -to another program or file. For example: 'rg -p foo | less -R'. -"); - let arg = RGArg::switch("pretty").short("p") - .help(SHORT).long_help(LONG); - args.push(arg); -} - -fn flag_quiet(args: &mut Vec) { - const SHORT: &str = "Do not print anything to stdout."; - const LONG: &str = long!("\ -Do not print anything to stdout. If a match is found in a file, then ripgrep -will stop searching. This is useful when ripgrep is used only for its exit -code (which will be an error if no matches are found). -"); - let arg = RGArg::switch("quiet").short("q") - .help(SHORT).long_help(LONG); - args.push(arg); -} - -fn flag_regex_size_limit(args: &mut Vec) { - const SHORT: &str = "The upper size limit of the compiled regex."; - const LONG: &str = long!("\ -The upper size limit of the compiled regex. The default limit is 10M. - -The argument accepts the same size suffixes as allowed in the --max-filesize -flag. -"); - let arg = RGArg::flag("regex-size-limit", "NUM+SUFFIX?") - .help(SHORT).long_help(LONG); - args.push(arg); -} - -fn flag_regexp(args: &mut Vec) { - const SHORT: &str = "A pattern to search for."; - const LONG: &str = long!("\ -A pattern to search for. This option can be provided multiple times, where -all patterns given are searched. Lines matching at least one of the provided -patterns are printed. This flag can also be used when searching for patterns -that start with a dash. - -For example, to search for the literal '-foo', you can use this flag: - - rg -e -foo - -You can also use the special '--' delimiter to indicate that no more flags -will be provided. Namely, the following is equivalent to the above: - - rg -- -foo -"); - let arg = RGArg::flag("regexp", "PATTERN").short("e") - .help(SHORT).long_help(LONG) - .multiple() - .allow_leading_hyphen(); - args.push(arg); -} - -fn flag_replace(args: &mut Vec) { - const SHORT: &str = "Replace matches with the given text."; - const LONG: &str = long!("\ -Replace every match with the text given when printing results. Neither this -flag nor any other ripgrep flag will modify your files. - -Capture group indices (e.g., $5) and names (e.g., $foo) are supported in the -replacement string. - -Note that the replacement by default replaces each match, and NOT the entire -line. To replace the entire line, you should match the entire line. - -This flag can be used with the -o/--only-matching flag. -"); - let arg = RGArg::flag("replace", "REPLACEMENT_TEXT").short("r") - .help(SHORT).long_help(LONG) - .allow_leading_hyphen(); - args.push(arg); -} - -fn flag_search_zip(args: &mut Vec) { - const SHORT: &str = "Search in compressed files."; - const LONG: &str = long!("\ -Search in compressed files. Currently gz, bz2, xz, and lzma files are -supported. This option expects the decompression binaries to be available in -your PATH. - -This flag can be disabled with --no-search-zip. -"); - let arg = RGArg::switch("search-zip").short("z") - .help(SHORT).long_help(LONG) - .overrides("no-search-zip"); - args.push(arg); - - let arg = RGArg::switch("no-search-zip") - .hidden() - .overrides("search-zip"); - args.push(arg); -} - -fn flag_smart_case(args: &mut Vec) { - const SHORT: &str = "Smart case search."; - const LONG: &str = long!("\ -Searches case insensitively if the pattern is all lowercase. Search case -sensitively otherwise. - -This overrides the -s/--case-sensitive and -i/--ignore-case flags. -"); - let arg = RGArg::switch("smart-case").short("S") - .help(SHORT).long_help(LONG) - .overrides("case-sensitive") - .overrides("ignore-case"); - args.push(arg); -} - -fn flag_sort_files(args: &mut Vec) { - const SHORT: &str = "Sort results by file path. Implies --threads=1."; - const LONG: &str = long!("\ -Sort results by file path. Note that this currently disables all parallelism -and runs search in a single thread. - -This flag can be disabled with --no-sort-files. -"); - let arg = RGArg::switch("sort-files") - .help(SHORT).long_help(LONG) - .overrides("no-sort-files"); - args.push(arg); - - let arg = RGArg::switch("no-sort-files") - .hidden() - .overrides("sort-files"); - args.push(arg); -} - -fn flag_stats(args: &mut Vec) { - const SHORT: &str = "Print statistics about this ripgrep search."; - const LONG: &str = long!("\ -Print aggregate statistics about this ripgrep search. When this flag is -present, ripgrep will print the following stats to stdout at the end of the -search: number of matched lines, number of files with matches, number of files -searched, and the time taken for the entire search to complete. - -This set of aggregate statistics may expand over time. - -Note that this flag has no effect if --files, --files-with-matches or ---files-without-match is passed."); - - let arg = RGArg::switch("stats") - .help(SHORT).long_help(LONG); - - args.push(arg); -} - -fn flag_text(args: &mut Vec) { - const SHORT: &str = "Search binary files as if they were text."; - const LONG: &str = long!("\ -Search binary files as if they were text. When this flag is present, ripgrep's -binary file detection is disabled. This means that when a binary file is -searched, its contents may be printed if there is a match. This may cause -escape codes to be printed that alter the behavior of your terminal. - -When binary file detection is enabled it is imperfect. In general, it uses -a simple heuristic. If a NUL byte is seen during search, then the file is -considered binary and search stops (unless this flag is present). - -Note that when the `-u/--unrestricted` flag is provided for a third time, then -this flag is automatically enabled. - -This flag can be disabled with --no-text. -"); - let arg = RGArg::switch("text").short("a") - .help(SHORT).long_help(LONG) - .overrides("no-text"); - args.push(arg); - - let arg = RGArg::switch("no-text") - .hidden() - .overrides("text"); - args.push(arg); -} - -fn flag_threads(args: &mut Vec) { - const SHORT: &str = "The approximate number of threads to use."; - const LONG: &str = long!("\ -The approximate number of threads to use. A value of 0 (which is the default) -causes ripgrep to choose the thread count using heuristics. -"); - let arg = RGArg::flag("threads", "NUM").short("j") - .help(SHORT).long_help(LONG); - args.push(arg); -} - -fn flag_type(args: &mut Vec) { - const SHORT: &str = "Only search files matching TYPE."; - const LONG: &str = long!("\ -Only search files matching TYPE. Multiple type flags may be provided. Use the ---type-list flag to list all available types. -"); - let arg = RGArg::flag("type", "TYPE").short("t") - .help(SHORT).long_help(LONG) - .multiple(); - args.push(arg); -} - -fn flag_type_add(args: &mut Vec) { - const SHORT: &str = "Add a new glob for a file type."; - const LONG: &str = long!("\ -Add a new glob for a particular file type. Only one glob can be added at a -time. Multiple --type-add flags can be provided. Unless --type-clear is used, -globs are added to any existing globs defined inside of ripgrep. - -Note that this MUST be passed to every invocation of ripgrep. Type settings are -NOT persisted. - -Example: - - rg --type-add 'foo:*.foo' -tfoo PATTERN. - ---type-add can also be used to include rules from other types with the special -include directive. The include directive permits specifying one or more other -type names (separated by a comma) that have been defined and its rules will -automatically be imported into the type specified. For example, to create a -type called src that matches C++, Python and Markdown files, one can use: - - --type-add 'src:include:cpp,py,md' - -Additional glob rules can still be added to the src type by using the ---type-add flag again: - - --type-add 'src:include:cpp,py,md' --type-add 'src:*.foo' - -Note that type names must consist only of Unicode letters or numbers. -Punctuation characters are not allowed. -"); - let arg = RGArg::flag("type-add", "TYPE_SPEC") - .help(SHORT).long_help(LONG) - .multiple(); - args.push(arg); -} - -fn flag_type_clear(args: &mut Vec) { - const SHORT: &str = "Clear globs for a file type."; - const LONG: &str = long!("\ -Clear the file type globs previously defined for TYPE. This only clears the -default type definitions that are found inside of ripgrep. - -Note that this MUST be passed to every invocation of ripgrep. Type settings are -NOT persisted. -"); - let arg = RGArg::flag("type-clear", "TYPE") - .help(SHORT).long_help(LONG) - .multiple(); - args.push(arg); -} - -fn flag_type_not(args: &mut Vec) { - const SHORT: &str = "Do not search files matching TYPE."; - const LONG: &str = long!("\ -Do not search files matching TYPE. Multiple type-not flags may be provided. Use -the --type-list flag to list all available types. -"); - let arg = RGArg::flag("type-not", "TYPE").short("T") - .help(SHORT).long_help(LONG) - .multiple(); - args.push(arg); -} - -fn flag_type_list(args: &mut Vec) { - const SHORT: &str = "Show all supported file types."; - const LONG: &str = long!("\ -Show all supported file types and their corresponding globs. -"); - let arg = RGArg::switch("type-list") - .help(SHORT).long_help(LONG) - // This also technically conflicts with PATTERN, but the first file - // path will actually be in PATTERN. - .conflicts(&["file", "files", "pattern", "regexp"]); - args.push(arg); -} - -fn flag_unrestricted(args: &mut Vec) { - const SHORT: &str = "Reduce the level of \"smart\" searching."; - const LONG: &str = long!("\ -Reduce the level of \"smart\" searching. A single -u won't respect .gitignore -(etc.) files. Two -u flags will additionally search hidden files and -directories. Three -u flags will additionally search binary files. - --uu is roughly equivalent to grep -r and -uuu is roughly equivalent to grep -a --r. -"); - let arg = RGArg::switch("unrestricted").short("u") - .help(SHORT).long_help(LONG) - .multiple(); - args.push(arg); -} - -fn flag_vimgrep(args: &mut Vec) { - const SHORT: &str = "Show results in vim compatible format."; - const LONG: &str = long!("\ -Show results with every match on its own line, including line numbers and -column numbers. With this option, a line with more than one match will be -printed more than once. -"); - let arg = RGArg::switch("vimgrep") - .help(SHORT).long_help(LONG); - args.push(arg); -} - -fn flag_with_filename(args: &mut Vec) { - const SHORT: &str = "Print the file path with the matched lines."; - const LONG: &str = long!("\ -Display the file path for matches. This is the default when more than one -file is searched. If --heading is enabled (the default when printing to a -terminal), the file path will be shown above clusters of matches from each -file; otherwise, the file name will be shown as a prefix for each matched line. - -This flag overrides --no-filename. -"); - let arg = RGArg::switch("with-filename").short("H") - .help(SHORT).long_help(LONG) - .overrides("no-filename"); - args.push(arg); - - const NO_SHORT: &str = "Never print the file path with the matched lines."; - const NO_LONG: &str = long!("\ -Never print the file path with the matched lines. This is the default when -ripgrep is explicitly instructed to search one file or stdin. - -This flag overrides --with-filename. -"); - let arg = RGArg::switch("no-filename") - .help(NO_SHORT).long_help(NO_LONG) - .overrides("with-filename"); - args.push(arg); -} - -fn flag_word_regexp(args: &mut Vec) { - const SHORT: &str = "Only show matches surrounded by word boundaries."; - const LONG: &str = long!("\ -Only show matches surrounded by word boundaries. This is roughly equivalent to -putting \\b before and after all of the search patterns. - -This overrides the --line-regexp flag. -"); - let arg = RGArg::switch("word-regexp").short("w") - .help(SHORT).long_help(LONG) - .overrides("line-regexp"); - args.push(arg); -} diff --git a/src/args.rs b/src/args.rs deleted file mode 100644 index aca9bcd..0000000 --- a/src/args.rs +++ /dev/null @@ -1,1217 +0,0 @@ -use std::cmp; -use std::env; -use std::ffi::OsStr; -use std::fs; -use std::io::{self, BufRead}; -use std::path::{Path, PathBuf}; -use std::sync::Arc; -use std::sync::atomic::{AtomicBool, Ordering}; - -use clap; -use encoding_rs::Encoding; -use grep::{Grep, GrepBuilder}; -use log; -use num_cpus; -use regex; -use same_file; -use termcolor; - -use app; -use atty; -use ignore::overrides::{Override, OverrideBuilder}; -use ignore::types::{FileTypeDef, Types, TypesBuilder}; -use ignore; -use printer::{ColorSpecs, Printer}; -use unescape::unescape; -use worker::{Worker, WorkerBuilder}; - -use config; -use logger::Logger; -use Result; - -/// `Args` are transformed/normalized from `ArgMatches`. -#[derive(Debug)] -pub struct Args { - paths: Vec, - after_context: usize, - before_context: usize, - byte_offset: bool, - color_choice: termcolor::ColorChoice, - colors: ColorSpecs, - column: bool, - context_separator: Vec, - count: bool, - count_matches: bool, - encoding: Option<&'static Encoding>, - files_with_matches: bool, - files_without_matches: bool, - eol: u8, - files: bool, - follow: bool, - glob_overrides: Override, - grep: Grep, - heading: bool, - hidden: bool, - ignore_files: Vec, - invert_match: bool, - line_number: bool, - line_per_match: bool, - max_columns: Option, - max_count: Option, - max_depth: Option, - max_filesize: Option, - mmap: bool, - no_ignore: bool, - no_ignore_messages: bool, - no_ignore_parent: bool, - no_ignore_vcs: bool, - no_messages: bool, - null: bool, - only_matching: bool, - path_separator: Option, - quiet: bool, - quiet_matched: QuietMatched, - replace: Option>, - sort_files: bool, - stdout_handle: Option, - text: bool, - threads: usize, - type_list: bool, - types: Types, - with_filename: bool, - search_zip_files: bool, - stats: bool -} - -impl Args { - /// Parse the command line arguments for this process. - /// - /// If a CLI usage error occurred, then exit the process and print a usage - /// or error message. Similarly, if the user requested the version of - /// ripgrep, then print the version and exit. - /// - /// Also, initialize a global logger. - pub fn parse() -> Result { - // We parse the args given on CLI. This does not include args from - // the config. We use the CLI args as an initial configuration while - // trying to parse config files. If a config file exists and has - // arguments, then we re-parse argv, otherwise we just use the matches - // we have here. - let early_matches = ArgMatches(app::app().get_matches()); - - if let Err(err) = Logger::init() { - errored!("failed to initialize logger: {}", err); - } - if early_matches.is_present("debug") { - log::set_max_level(log::LevelFilter::Debug); - } else { - log::set_max_level(log::LevelFilter::Warn); - } - - let matches = Args::matches(early_matches); - // The logging level may have changed if we brought in additional - // arguments from a configuration file, so recheck it and set the log - // level as appropriate. - if matches.is_present("debug") { - log::set_max_level(log::LevelFilter::Debug); - } else { - log::set_max_level(log::LevelFilter::Warn); - } - matches.to_args() - } - - /// Run clap and return the matches. If clap determines a problem with the - /// user provided arguments (or if --help or --version are given), then an - /// error/usage/version will be printed and the process will exit. - /// - /// If there are no additional arguments from the environment (e.g., a - /// config file), then the given matches are returned as is. - fn matches(early_matches: ArgMatches<'static>) -> ArgMatches<'static> { - // If the end user says no config, then respect it. - if early_matches.is_present("no-config") { - debug!("not reading config files because --no-config is present"); - return early_matches; - } - // If the user wants ripgrep to use a config file, then parse args - // from that first. - let mut args = config::args(early_matches.is_present("no-messages")); - if args.is_empty() { - return early_matches; - } - let mut cliargs = env::args_os(); - if let Some(bin) = cliargs.next() { - args.insert(0, bin); - } - args.extend(cliargs); - debug!("final argv: {:?}", args); - ArgMatches(app::app().get_matches_from(args)) - } - - /// Returns true if ripgrep should print the files it will search and exit - /// (but not do any actual searching). - pub fn files(&self) -> bool { - self.files - } - - /// Create a new line based matcher. The matcher returned can be used - /// across multiple threads simultaneously. This matcher only supports - /// basic searching of regular expressions in a single buffer. - /// - /// The pattern and other flags are taken from the command line. - pub fn grep(&self) -> Grep { - self.grep.clone() - } - - /// Whether ripgrep should be quiet or not. - pub fn quiet(&self) -> bool { - self.quiet - } - - /// Returns a thread safe boolean for determining whether to quit a search - /// early when quiet mode is enabled. - /// - /// If quiet mode is disabled, then QuietMatched.has_match always returns - /// false. - pub fn quiet_matched(&self) -> QuietMatched { - self.quiet_matched.clone() - } - - /// Create a new printer of individual search results that writes to the - /// writer given. - pub fn printer(&self, wtr: W) -> Printer { - let mut p = Printer::new(wtr) - .colors(self.colors.clone()) - .column(self.column) - .context_separator(self.context_separator.clone()) - .eol(self.eol) - .heading(self.heading) - .line_per_match(self.line_per_match) - .null(self.null) - .only_matching(self.only_matching) - .path_separator(self.path_separator) - .with_filename(self.with_filename) - .max_columns(self.max_columns); - if let Some(ref rep) = self.replace { - p = p.replace(rep.clone()); - } - p - } - - /// Retrieve the configured file separator. - pub fn file_separator(&self) -> Option> { - let contextless = - self.count - || self.count_matches - || self.files_with_matches - || self.files_without_matches; - let use_heading_sep = self.heading && !contextless; - - if use_heading_sep { - Some(b"".to_vec()) - } else if !contextless - && (self.before_context > 0 || self.after_context > 0) { - Some(self.context_separator.clone()) - } else { - None - } - } - - /// Returns true if the given arguments are known to never produce a match. - pub fn never_match(&self) -> bool { - self.max_count == Some(0) - } - - - /// Returns whether ripgrep should track stats for this run - pub fn stats(&self) -> bool { - self.stats - } - - /// Create a new writer for single-threaded searching with color support. - pub fn stdout(&self) -> Box { - if atty::is(atty::Stream::Stdout) { - Box::new(termcolor::StandardStream::stdout(self.color_choice)) - } else { - Box::new( - termcolor::BufferedStandardStream::stdout(self.color_choice)) - } - } - - /// Returns a handle to stdout for filtering search. - /// - /// A handle is returned if and only if ripgrep's stdout is being - /// redirected to a file. The handle returned corresponds to that file. - /// - /// This can be used to ensure that we do not attempt to search a file - /// that ripgrep is writing to. - pub fn stdout_handle(&self) -> Option<&same_file::Handle> { - self.stdout_handle.as_ref() - } - - /// Create a new buffer writer for multi-threaded searching with color - /// support. - pub fn buffer_writer(&self) -> termcolor::BufferWriter { - let mut wtr = termcolor::BufferWriter::stdout(self.color_choice); - wtr.separator(self.file_separator()); - wtr - } - - /// Return the paths that should be searched. - pub fn paths(&self) -> &[PathBuf] { - &self.paths - } - - /// Returns true if there is exactly one file path given to search. - pub fn is_one_path(&self) -> bool { - self.paths.len() == 1 - && (self.paths[0] == Path::new("-") || path_is_file(&self.paths[0])) - } - - /// Create a worker whose configuration is taken from the - /// command line. - pub fn worker(&self) -> Worker { - WorkerBuilder::new(self.grep()) - .after_context(self.after_context) - .before_context(self.before_context) - .byte_offset(self.byte_offset) - .count(self.count) - .count_matches(self.count_matches) - .encoding(self.encoding) - .files_with_matches(self.files_with_matches) - .files_without_matches(self.files_without_matches) - .eol(self.eol) - .line_number(self.line_number) - .invert_match(self.invert_match) - .max_count(self.max_count) - .mmap(self.mmap) - .no_messages(self.no_messages) - .quiet(self.quiet) - .text(self.text) - .search_zip_files(self.search_zip_files) - .build() - } - - /// Returns the number of worker search threads that should be used. - pub fn threads(&self) -> usize { - self.threads - } - - /// Returns a list of type definitions currently loaded. - pub fn type_defs(&self) -> &[FileTypeDef] { - self.types.definitions() - } - - /// Returns true if ripgrep should print the type definitions currently - /// loaded and then exit. - pub fn type_list(&self) -> bool { - self.type_list - } - - /// Returns true if error messages should be suppressed. - pub fn no_messages(&self) -> bool { - self.no_messages - } - - /// Returns true if error messages associated with parsing .ignore or - /// .gitignore files should be suppressed. - pub fn no_ignore_messages(&self) -> bool { - self.no_ignore_messages - } - - /// Create a new recursive directory iterator over the paths in argv. - pub fn walker(&self) -> ignore::Walk { - self.walker_builder().build() - } - - /// Create a new parallel recursive directory iterator over the paths - /// in argv. - pub fn walker_parallel(&self) -> ignore::WalkParallel { - self.walker_builder().build_parallel() - } - - fn walker_builder(&self) -> ignore::WalkBuilder { - let paths = self.paths(); - let mut wd = ignore::WalkBuilder::new(&paths[0]); - for path in &paths[1..] { - wd.add(path); - } - for path in &self.ignore_files { - if let Some(err) = wd.add_ignore(path) { - if !self.no_messages && !self.no_ignore_messages { - eprintln!("{}", err); - } - } - } - - wd.follow_links(self.follow); - wd.hidden(!self.hidden); - wd.max_depth(self.max_depth); - wd.max_filesize(self.max_filesize); - wd.overrides(self.glob_overrides.clone()); - wd.types(self.types.clone()); - wd.git_global(!self.no_ignore && !self.no_ignore_vcs); - wd.git_ignore(!self.no_ignore && !self.no_ignore_vcs); - wd.git_exclude(!self.no_ignore && !self.no_ignore_vcs); - wd.ignore(!self.no_ignore); - if !self.no_ignore { - wd.add_custom_ignore_filename(".rgignore"); - } - wd.parents(!self.no_ignore_parent); - wd.threads(self.threads()); - if self.sort_files { - wd.sort_by_file_name(|a, b| a.cmp(b)); - } - wd - } -} - -/// `ArgMatches` wraps `clap::ArgMatches` and provides semantic meaning to -/// several options/flags. -struct ArgMatches<'a>(clap::ArgMatches<'a>); - -impl<'a> ArgMatches<'a> { - /// Convert the result of parsing CLI arguments into ripgrep's - /// configuration. - fn to_args(&self) -> Result { - let paths = self.paths(); - let line_number = self.line_number(&paths); - let mmap = self.mmap(&paths)?; - let with_filename = self.with_filename(&paths); - let (before_context, after_context) = self.contexts()?; - let (count, count_matches) = self.counts(); - let quiet = self.is_present("quiet"); - let args = Args { - paths: paths, - after_context: after_context, - before_context: before_context, - byte_offset: self.is_present("byte-offset"), - color_choice: self.color_choice(), - colors: self.color_specs()?, - column: self.column(), - context_separator: self.context_separator(), - count: count, - count_matches: count_matches, - encoding: self.encoding()?, - files_with_matches: self.is_present("files-with-matches"), - files_without_matches: self.is_present("files-without-match"), - eol: b'\n', - files: self.is_present("files"), - follow: self.is_present("follow"), - glob_overrides: self.overrides()?, - grep: self.grep()?, - heading: self.heading(), - hidden: self.hidden(), - ignore_files: self.ignore_files(), - invert_match: self.is_present("invert-match"), - line_number: line_number, - line_per_match: self.is_present("vimgrep"), - max_columns: self.usize_of_nonzero("max-columns")?, - max_count: self.usize_of("max-count")?.map(|n| n as u64), - max_depth: self.usize_of("max-depth")?, - max_filesize: self.max_filesize()?, - mmap: mmap, - no_ignore: self.no_ignore(), - no_ignore_messages: self.is_present("no-ignore-messages"), - no_ignore_parent: self.no_ignore_parent(), - no_ignore_vcs: self.no_ignore_vcs(), - no_messages: self.is_present("no-messages"), - null: self.is_present("null"), - only_matching: self.is_present("only-matching"), - path_separator: self.path_separator()?, - quiet: quiet, - quiet_matched: QuietMatched::new(quiet), - replace: self.replace(), - sort_files: self.is_present("sort-files"), - stdout_handle: self.stdout_handle(), - text: self.text(), - threads: self.threads()?, - type_list: self.is_present("type-list"), - types: self.types()?, - with_filename: with_filename, - search_zip_files: self.is_present("search-zip"), - stats: self.stats() - }; - if args.mmap { - debug!("will try to use memory maps"); - } - Ok(args) - } - - /// Return all file paths that ripgrep should search. - fn paths(&self) -> Vec { - let mut paths: Vec = match self.values_of_os("path") { - None => vec![], - Some(vals) => vals.map(|p| Path::new(p).to_path_buf()).collect(), - }; - // If --file, --files or --regexp is given, then the first path is - // always in `pattern`. - if self.is_present("file") - || self.is_present("files") - || self.is_present("regexp") { - if let Some(path) = self.value_of_os("pattern") { - paths.insert(0, Path::new(path).to_path_buf()); - } - } - if paths.is_empty() { - paths.push(self.default_path()); - } - paths - } - - /// Return the default path that ripgrep should search. - fn default_path(&self) -> PathBuf { - let file_is_stdin = - self.values_of_os("file").map_or(false, |mut files| { - files.any(|f| f == "-") - }); - let search_cwd = atty::is(atty::Stream::Stdin) - || !stdin_is_readable() - || (self.is_present("file") && file_is_stdin) - || self.is_present("files") - || self.is_present("type-list"); - if search_cwd { - Path::new("./").to_path_buf() - } else { - Path::new("-").to_path_buf() - } - } - - /// Return all of the ignore files given on the command line. - fn ignore_files(&self) -> Vec { - match self.values_of_os("ignore-file") { - None => return vec![], - Some(vals) => vals.map(|p| Path::new(p).to_path_buf()).collect(), - } - } - - /// Return the pattern that should be used for searching. - /// - /// If multiple -e/--regexp flags are given, then they are all collapsed - /// into one pattern. - /// - /// If any part of the pattern isn't valid UTF-8, then an error is - /// returned. - fn pattern(&self) -> Result { - Ok(self.patterns()?.join("|")) - } - - /// Get a sequence of all available patterns from the command line. - /// This includes reading the -e/--regexp and -f/--file flags. - /// - /// Note that if -F/--fixed-strings is set, then all patterns will be - /// escaped. Similarly, if -w/--word-regexp is set, then all patterns - /// are surrounded by `\b`, and if -x/--line-regexp is set, then all - /// patterns are surrounded by `^...$`. Finally, if --passthru is set, - /// the pattern `^` is added to the end (to ensure that it works as - /// expected with multiple -e/-f patterns). - /// - /// If any pattern is invalid UTF-8, then an error is returned. - fn patterns(&self) -> Result> { - if self.is_present("files") || self.is_present("type-list") { - return Ok(vec![self.empty_pattern()]); - } - let mut pats = vec![]; - match self.values_of_os("regexp") { - None => { - if self.values_of_os("file").is_none() { - if let Some(os_pat) = self.value_of_os("pattern") { - pats.push(self.os_str_pattern(os_pat)?); - } - } - } - Some(os_pats) => { - for os_pat in os_pats { - pats.push(self.os_str_pattern(os_pat)?); - } - } - } - if let Some(files) = self.values_of_os("file") { - for file in files { - if file == "-" { - let stdin = io::stdin(); - for line in stdin.lock().lines() { - pats.push(self.str_pattern(&line?)); - } - } else { - let f = fs::File::open(file)?; - for line in io::BufReader::new(f).lines() { - pats.push(self.str_pattern(&line?)); - } - } - } - } - // It's important that this be at the end; otherwise it would always - // match first, and we wouldn't get colours in the output - if self.is_present("passthru") && !self.is_present("count") { - pats.push("^".to_string()) - } else if pats.is_empty() { - pats.push(self.empty_pattern()) - } - Ok(pats) - } - - /// Converts an OsStr pattern to a String pattern, including line/word - /// boundaries or escapes if applicable. - /// - /// If the pattern is not valid UTF-8, then an error is returned. - fn os_str_pattern(&self, pat: &OsStr) -> Result { - let s = pattern_to_str(pat)?; - Ok(self.str_pattern(s)) - } - - /// Converts a &str pattern to a String pattern, including line/word - /// boundaries or escapes if applicable. - fn str_pattern(&self, pat: &str) -> String { - let litpat = self.literal_pattern(pat.to_string()); - let s = self.line_pattern(self.word_pattern(litpat)); - - if s.is_empty() { - self.empty_pattern() - } else { - s - } - } - - /// Returns the given pattern as a literal pattern if the - /// -F/--fixed-strings flag is set. Otherwise, the pattern is returned - /// unchanged. - fn literal_pattern(&self, pat: String) -> String { - if self.is_present("fixed-strings") { - regex::escape(&pat) - } else { - pat - } - } - - /// Returns the given pattern as a word pattern if the -w/--word-regexp - /// flag is set. Otherwise, the pattern is returned unchanged. - fn word_pattern(&self, pat: String) -> String { - if self.is_present("word-regexp") { - format!(r"\b(?:{})\b", pat) - } else { - pat - } - } - - /// Returns the given pattern as a line pattern if the -x/--line-regexp - /// flag is set. Otherwise, the pattern is returned unchanged. - fn line_pattern(&self, pat: String) -> String { - if self.is_present("line-regexp") { - format!(r"^(?:{})$", pat) - } else { - pat - } - } - - /// Empty pattern returns a pattern that is guaranteed to produce an empty - /// regular expression that is valid in any position. - fn empty_pattern(&self) -> String { - // This would normally just be an empty string, which works on its - // own, but if the patterns are joined in a set of alternations, then - // you wind up with `foo|`, which is invalid. - self.word_pattern("(?:z{0})*".to_string()) - } - - /// Returns true if and only if file names containing each match should - /// be emitted. - /// - /// `paths` should be a slice of all top-level file paths that ripgrep - /// will need to search. - fn with_filename(&self, paths: &[PathBuf]) -> bool { - if self.is_present("no-filename") { - false - } else { - self.is_present("with-filename") - || self.is_present("vimgrep") - || paths.len() > 1 - || paths.get(0).map_or(false, |p| path_is_dir(p)) - } - } - - /// Returns a handle to stdout for filtering search. - /// - /// A handle is returned if and only if ripgrep's stdout is being - /// redirected to a file. The handle returned corresponds to that file. - /// - /// This can be used to ensure that we do not attempt to search a file - /// that ripgrep is writing to. - fn stdout_handle(&self) -> Option { - let h = match same_file::Handle::stdout() { - Err(_) => return None, - Ok(h) => h, - }; - let md = match h.as_file().metadata() { - Err(_) => return None, - Ok(md) => md, - }; - if !md.is_file() { - return None; - } - Some(h) - } - - /// Returns true if and only if memory map searching should be tried. - /// - /// `paths` should be a slice of all top-level file paths that ripgrep - /// will need to search. - fn mmap(&self, paths: &[PathBuf]) -> Result { - let (before, after) = self.contexts()?; - let enc = self.encoding()?; - Ok(if before > 0 || after > 0 || self.is_present("no-mmap") { - false - } else if self.is_present("mmap") { - true - } else if cfg!(target_os = "macos") { - // On Mac, memory maps appear to suck. Neat. - false - } else if enc.is_some() { - // There's no practical way to transcode a memory map that isn't - // isomorphic to searching over io::Read. - false - } else { - // If we're only searching a few paths and all of them are - // files, then memory maps are probably faster. - paths.len() <= 10 && paths.iter().all(|p| path_is_file(p)) - }) - } - - /// Returns true if and only if line numbers should be shown. - fn line_number(&self, paths: &[PathBuf]) -> bool { - if self.is_present("no-line-number") || self.is_present("count") { - false - } else { - let only_stdin = paths == [Path::new("-")]; - (atty::is(atty::Stream::Stdout) && !only_stdin) - || self.is_present("line-number") - || self.is_present("column") - || self.is_present("pretty") - || self.is_present("vimgrep") - } - } - - /// Returns true if and only if column numbers should be shown. - fn column(&self) -> bool { - if self.is_present("no-column") { - return false; - } - self.is_present("column") || self.is_present("vimgrep") - } - - /// Returns true if and only if matches should be grouped with file name - /// headings. - fn heading(&self) -> bool { - if self.is_present("no-heading") || self.is_present("vimgrep") { - false - } else { - atty::is(atty::Stream::Stdout) - || self.is_present("heading") - || self.is_present("pretty") - } - } - - /// Returns the replacement string as UTF-8 bytes if it exists. - fn replace(&self) -> Option> { - self.value_of_lossy("replace").map(|s| s.into_bytes()) - } - - /// Returns the unescaped context separator in UTF-8 bytes. - fn context_separator(&self) -> Vec { - match self.value_of_lossy("context-separator") { - None => b"--".to_vec(), - Some(sep) => unescape(&sep), - } - } - - /// Returns the unescaped path separator in UTF-8 bytes. - fn path_separator(&self) -> Result> { - match self.value_of_lossy("path-separator") { - None => Ok(None), - Some(sep) => { - let sep = unescape(&sep); - if sep.is_empty() { - Ok(None) - } else if sep.len() > 1 { - Err(From::from(format!( - "A path separator must be exactly one byte, but \ - the given separator is {} bytes.", sep.len()))) - } else { - Ok(Some(sep[0])) - } - } - } - } - - /// Returns the before and after contexts from the command line. - /// - /// If a context setting was absent, then `0` is returned. - /// - /// If there was a problem parsing the values from the user as an integer, - /// then an error is returned. - fn contexts(&self) -> Result<(usize, usize)> { - let after = self.usize_of("after-context")?.unwrap_or(0); - let before = self.usize_of("before-context")?.unwrap_or(0); - let both = self.usize_of("context")?.unwrap_or(0); - Ok(if both > 0 { - (both, both) - } else { - (before, after) - }) - } - - /// Returns whether the -c/--count or the --count-matches flags were - /// passed from the command line. - /// - /// If --count-matches and --invert-match were passed in, behave - /// as if --count and --invert-match were passed in (i.e. rg will - /// count inverted matches as per existing behavior). - fn counts(&self) -> (bool, bool) { - let count = self.is_present("count"); - let count_matches = self.is_present("count-matches"); - let invert_matches = self.is_present("invert-match"); - let only_matching = self.is_present("only-matching"); - if count_matches && invert_matches { - // Treat `-v --count-matches` as `-v -c`. - (true, false) - } else if count && only_matching { - // Treat `-c --only-matching` as `--count-matches`. - (false, true) - } else { - (count, count_matches) - } - } - - /// Returns the user's color choice based on command line parameters and - /// environment. - fn color_choice(&self) -> termcolor::ColorChoice { - let preference = match self.value_of_lossy("color") { - None => "auto".to_string(), - Some(v) => v, - }; - if preference == "always" { - termcolor::ColorChoice::Always - } else if preference == "ansi" { - termcolor::ColorChoice::AlwaysAnsi - } else if preference == "auto" { - if atty::is(atty::Stream::Stdout) || self.is_present("pretty") { - termcolor::ColorChoice::Auto - } else { - termcolor::ColorChoice::Never - } - } else { - termcolor::ColorChoice::Never - } - } - - /// Returns the color specifications given by the user on the CLI. - /// - /// If the was a problem parsing any of the provided specs, then an error - /// is returned. - fn color_specs(&self) -> Result { - // Start with a default set of color specs. - let mut specs = vec![ - #[cfg(unix)] - "path:fg:magenta".parse().unwrap(), - #[cfg(windows)] - "path:fg:cyan".parse().unwrap(), - "line:fg:green".parse().unwrap(), - "match:fg:red".parse().unwrap(), - "match:style:bold".parse().unwrap(), - ]; - for spec_str in self.values_of_lossy_vec("colors") { - specs.push(spec_str.parse()?); - } - Ok(ColorSpecs::new(&specs)) - } - - /// Return the text encoding specified. - /// - /// If the label given by the caller doesn't correspond to a valid - /// supported encoding (and isn't `auto`), then return an error. - /// - /// A `None` encoding implies that the encoding should be automatically - /// detected on a per-file basis. - fn encoding(&self) -> Result> { - match self.value_of_lossy("encoding") { - None => Ok(None), - Some(label) => { - if label == "auto" { - return Ok(None); - } - match Encoding::for_label_no_replacement(label.as_bytes()) { - Some(enc) => Ok(Some(enc)), - None => Err(From::from( - format!("unsupported encoding: {}", label))), - } - } - } - } - - /// Returns whether status should be tracked for this run of ripgrep - - /// This is automatically disabled if we're asked to only list the - /// files that wil be searched, files with matches or files - /// without matches. - fn stats(&self) -> bool { - if self.is_present("files-with-matches") || - self.is_present("files-without-match") { - return false; - } - self.is_present("stats") - } - - /// Returns the approximate number of threads that ripgrep should use. - fn threads(&self) -> Result { - if self.is_present("sort-files") { - return Ok(1); - } - let threads = self.usize_of("threads")?.unwrap_or(0); - Ok(if threads == 0 { - cmp::min(12, num_cpus::get()) - } else { - threads - }) - } - - /// Builds a grep matcher from the command line flags. - /// - /// If there was a problem extracting the pattern from the command line - /// flags, then an error is returned. - fn grep(&self) -> Result { - let smart = - self.is_present("smart-case") - && !self.is_present("ignore-case") - && !self.is_present("case-sensitive"); - let casei = - self.is_present("ignore-case") - && !self.is_present("case-sensitive"); - let mut gb = GrepBuilder::new(&self.pattern()?) - .case_smart(smart) - .case_insensitive(casei) - .line_terminator(b'\n'); - - if let Some(limit) = self.dfa_size_limit()? { - gb = gb.dfa_size_limit(limit); - } - if let Some(limit) = self.regex_size_limit()? { - gb = gb.size_limit(limit); - } - Ok(gb.build()?) - } - - /// Builds the set of glob overrides from the command line flags. - fn overrides(&self) -> Result { - let mut ovr = OverrideBuilder::new(env::current_dir()?); - for glob in self.values_of_lossy_vec("glob") { - ovr.add(&glob)?; - } - // this is smelly. In the long run it might make sense - // to change overridebuilder to be like globsetbuilder - // but this would be a breaking change to the ignore crate - // so it is being shelved for now... - ovr.case_insensitive(true)?; - for glob in self.values_of_lossy_vec("iglob") { - ovr.add(&glob)?; - } - ovr.build().map_err(From::from) - } - - /// Builds a file type matcher from the command line flags. - fn types(&self) -> Result { - let mut btypes = TypesBuilder::new(); - btypes.add_defaults(); - for ty in self.values_of_lossy_vec("type-clear") { - btypes.clear(&ty); - } - for def in self.values_of_lossy_vec("type-add") { - btypes.add_def(&def)?; - } - for ty in self.values_of_lossy_vec("type") { - btypes.select(&ty); - } - for ty in self.values_of_lossy_vec("type-not") { - btypes.negate(&ty); - } - btypes.build().map_err(From::from) - } - - /// Parses an argument of the form `[0-9]+(KMG)?`. - /// - /// This always returns the result as a type `u64`. This must be converted - /// to the appropriate type by the caller. - fn parse_human_readable_size_arg( - &self, - arg_name: &str, - ) -> Result> { - let arg_value = match self.value_of_lossy(arg_name) { - Some(x) => x, - None => return Ok(None) - }; - let re = regex::Regex::new("^([0-9]+)([KMG])?$").unwrap(); - let caps = - re.captures(&arg_value).ok_or_else(|| { - format!("invalid format for {}", arg_name) - })?; - - let value = caps[1].parse::()?; - let suffix = caps.get(2).map(|x| x.as_str()); - - let v_10 = value.checked_mul(1024); - let v_20 = v_10.and_then(|x| x.checked_mul(1024)); - let v_30 = v_20.and_then(|x| x.checked_mul(1024)); - - let try_suffix = |x: Option| { - if x.is_some() { - Ok(x) - } else { - Err(From::from(format!("number too large for {}", arg_name))) - } - }; - match suffix { - None => Ok(Some(value)), - Some("K") => try_suffix(v_10), - Some("M") => try_suffix(v_20), - Some("G") => try_suffix(v_30), - _ => Err(From::from(format!("invalid suffix for {}", arg_name))) - } - } - - /// Parse the dfa-size-limit argument option into a byte count. - fn dfa_size_limit(&self) -> Result> { - let r = self.parse_human_readable_size_arg("dfa-size-limit")?; - human_readable_to_usize("dfa-size-limit", r) - } - - /// Parse the regex-size-limit argument option into a byte count. - fn regex_size_limit(&self) -> Result> { - let r = self.parse_human_readable_size_arg("regex-size-limit")?; - human_readable_to_usize("regex-size-limit", r) - } - - /// Parses the max-filesize argument option into a byte count. - fn max_filesize(&self) -> Result> { - self.parse_human_readable_size_arg("max-filesize") - } - - /// Returns true if ignore files should be ignored. - fn no_ignore(&self) -> bool { - self.is_present("no-ignore") - || self.occurrences_of("unrestricted") >= 1 - } - - /// Returns true if parent ignore files should be ignored. - fn no_ignore_parent(&self) -> bool { - self.is_present("no-ignore-parent") || self.no_ignore() - } - - /// Returns true if VCS ignore files should be ignored. - fn no_ignore_vcs(&self) -> bool { - self.is_present("no-ignore-vcs") || self.no_ignore() - } - - /// Returns true if and only if hidden files/directories should be - /// searched. - fn hidden(&self) -> bool { - self.is_present("hidden") || self.occurrences_of("unrestricted") >= 2 - } - - /// Returns true if and only if all files should be treated as if they - /// were text, even if ripgrep would detect it as a binary file. - fn text(&self) -> bool { - self.is_present("text") || self.occurrences_of("unrestricted") >= 3 - } - - /// Like values_of_lossy, but returns an empty vec if the flag is not - /// present. - fn values_of_lossy_vec(&self, name: &str) -> Vec { - self.values_of_lossy(name).unwrap_or_else(Vec::new) - } - - /// Safely reads an arg value with the given name, and if it's present, - /// tries to parse it as a usize value. - /// - /// If the number is zero, then it is considered absent and `None` is - /// returned. - fn usize_of_nonzero(&self, name: &str) -> Result> { - match self.value_of_lossy(name) { - None => Ok(None), - Some(v) => v.parse().map_err(From::from).map(|n| { - if n == 0 { - None - } else { - Some(n) - } - }), - } - } - - /// Safely reads an arg value with the given name, and if it's present, - /// tries to parse it as a usize value. - fn usize_of(&self, name: &str) -> Result> { - match self.value_of_lossy(name) { - None => Ok(None), - Some(v) => v.parse().map(Some).map_err(From::from), - } - } - - // The following methods mostly dispatch to the underlying clap methods - // directly. Methods that would otherwise get a single value will fetch - // all values and return the last one. (Clap returns the first one.) We - // only define the ones we need. - - fn is_present(&self, name: &str) -> bool { - self.0.is_present(name) - } - - fn occurrences_of(&self, name: &str) -> u64 { - self.0.occurrences_of(name) - } - - fn value_of_lossy(&self, name: &str) -> Option { - self.0.value_of_lossy(name).map(|s| s.into_owned()) - } - - fn values_of_lossy(&self, name: &str) -> Option> { - self.0.values_of_lossy(name) - } - - fn value_of_os(&'a self, name: &str) -> Option<&'a OsStr> { - self.0.value_of_os(name) - } - - fn values_of_os(&'a self, name: &str) -> Option> { - self.0.values_of_os(name) - } -} - -fn pattern_to_str(s: &OsStr) -> Result<&str> { - match s.to_str() { - Some(s) => Ok(s), - None => Err(From::from(format!( - "Argument '{}' is not valid UTF-8. \ - Use hex escape sequences to match arbitrary \ - bytes in a pattern (e.g., \\xFF).", - s.to_string_lossy()))), - } -} - -/// A simple thread safe abstraction for determining whether a search should -/// stop if the user has requested quiet mode. -#[derive(Clone, Debug)] -pub struct QuietMatched(Arc>); - -impl QuietMatched { - /// Create a new QuietMatched value. - /// - /// If quiet is true, then set_match and has_match will reflect whether - /// a search should quit or not because it found a match. - /// - /// If quiet is false, then set_match is always a no-op and has_match - /// always returns false. - fn new(quiet: bool) -> QuietMatched { - let atomic = if quiet { Some(AtomicBool::new(false)) } else { None }; - QuietMatched(Arc::new(atomic)) - } - - /// Returns true if and only if quiet mode is enabled and a match has - /// occurred. - pub fn has_match(&self) -> bool { - match *self.0 { - None => false, - Some(ref matched) => matched.load(Ordering::SeqCst), - } - } - - /// Sets whether a match has occurred or not. - /// - /// If quiet mode is disabled, then this is a no-op. - pub fn set_match(&self, yes: bool) -> bool { - match *self.0 { - None => false, - Some(_) if !yes => false, - Some(ref m) => { m.store(true, Ordering::SeqCst); true } - } - } -} - -/// Convert the result of a `parse_human_readable_size_arg` call into -/// a `usize`, failing if the type does not fit. -fn human_readable_to_usize( - arg_name: &str, - value: Option, -) -> Result> { - use std::usize; - - match value { - None => Ok(None), - Some(v) => { - if v <= usize::MAX as u64 { - Ok(Some(v as usize)) - } else { - let msg = format!("number too large for {}", arg_name); - Err(From::from(msg)) - } - } - } -} - -/// Returns true if and only if stdin is deemed searchable. -#[cfg(unix)] -fn stdin_is_readable() -> bool { - use std::os::unix::fs::FileTypeExt; - use same_file::Handle; - - let ft = match Handle::stdin().and_then(|h| h.as_file().metadata()) { - Err(_) => return false, - Ok(md) => md.file_type(), - }; - ft.is_file() || ft.is_fifo() -} - -/// Returns true if and only if stdin is deemed searchable. -#[cfg(windows)] -fn stdin_is_readable() -> bool { - // On Windows, it's not clear what the possibilities are to me, so just - // always return true. - true -} - -/// Returns true if and only if this path points to a directory. -/// -/// This works around a bug in Rust's standard library: -/// https://github.com/rust-lang/rust/issues/46484 -#[cfg(windows)] -fn path_is_dir(path: &Path) -> bool { - fs::metadata(path).map(|md| metadata_is_dir(&md)).unwrap_or(false) -} - -/// Returns true if and only if this entry points to a directory. -#[cfg(not(windows))] -fn path_is_dir(path: &Path) -> bool { - path.is_dir() -} - -/// Returns true if and only if this path points to a file. -/// -/// This works around a bug in Rust's standard library: -/// https://github.com/rust-lang/rust/issues/46484 -#[cfg(windows)] -fn path_is_file(path: &Path) -> bool { - !path_is_dir(path) -} - -/// Returns true if and only if this entry points to a directory. -#[cfg(not(windows))] -fn path_is_file(path: &Path) -> bool { - path.is_file() -} - -/// Returns true if and only if the given metadata points to a directory. -/// -/// This works around a bug in Rust's standard library: -/// https://github.com/rust-lang/rust/issues/46484 -#[cfg(windows)] -fn metadata_is_dir(md: &fs::Metadata) -> bool { - use std::os::windows::fs::MetadataExt; - use winapi::um::winnt::FILE_ATTRIBUTE_DIRECTORY; - md.file_attributes() & FILE_ATTRIBUTE_DIRECTORY != 0 -} diff --git a/src/config.rs b/src/config.rs deleted file mode 100644 index c47e6a5..0000000 --- a/src/config.rs +++ /dev/null @@ -1,195 +0,0 @@ -// This module provides routines for reading ripgrep config "rc" files. The -// primary output of these routines is a sequence of arguments, where each -// argument corresponds precisely to one shell argument. - -use std::env; -use std::error::Error; -use std::fs::File; -use std::io::{self, BufRead}; -use std::ffi::OsString; -use std::path::{Path, PathBuf}; - -use Result; - -/// Return a sequence of arguments derived from ripgrep rc configuration files. -/// -/// If no_messages is false and there was a problem reading a config file, -/// then errors are printed to stderr. -pub fn args(no_messages: bool) -> Vec { - let config_path = match env::var_os("RIPGREP_CONFIG_PATH") { - None => return vec![], - Some(config_path) => { - if config_path.is_empty() { - return vec![]; - } - PathBuf::from(config_path) - } - }; - let (args, errs) = match parse(&config_path) { - Ok((args, errs)) => (args, errs), - Err(err) => { - if !no_messages { - eprintln!("{}", err); - } - return vec![]; - } - }; - if !no_messages && !errs.is_empty() { - for err in errs { - eprintln!("{}:{}", config_path.display(), err); - } - } - debug!( - "{}: arguments loaded from config file: {:?}", - config_path.display(), args); - args -} - -/// Parse a single ripgrep rc file from the given path. -/// -/// On success, this returns a set of shell arguments, in order, that should -/// be pre-pended to the arguments given to ripgrep at the command line. -/// -/// If the file could not be read, then an error is returned. If there was -/// a problem parsing one or more lines in the file, then errors are returned -/// for each line in addition to successfully parsed arguments. -fn parse>( - path: P, -) -> Result<(Vec, Vec>)> { - let path = path.as_ref(); - match File::open(&path) { - Ok(file) => parse_reader(file), - Err(err) => errored!("{}: {}", path.display(), err), - } -} - -/// Parse a single ripgrep rc file from the given reader. -/// -/// Callers should not provided a buffered reader, as this routine will use its -/// own buffer internally. -/// -/// On success, this returns a set of shell arguments, in order, that should -/// be pre-pended to the arguments given to ripgrep at the command line. -/// -/// If the reader could not be read, then an error is returned. If there was a -/// problem parsing one or more lines, then errors are returned for each line -/// in addition to successfully parsed arguments. -fn parse_reader( - rdr: R, -) -> Result<(Vec, Vec>)> { - let mut bufrdr = io::BufReader::new(rdr); - let (mut args, mut errs) = (vec![], vec![]); - let mut line = vec![]; - let mut line_number = 0; - while { - line.clear(); - line_number += 1; - bufrdr.read_until(b'\n', &mut line)? > 0 - } { - trim(&mut line); - if line.is_empty() || line[0] == b'#' { - continue; - } - match bytes_to_os_string(&line) { - Ok(osstr) => { - args.push(osstr); - } - Err(err) => { - errs.push(format!("{}: {}", line_number, err).into()); - } - } - } - Ok((args, errs)) -} - -/// Trim the given bytes of whitespace according to the ASCII definition. -fn trim(x: &mut Vec) { - let upto = x.iter().take_while(|b| is_space(**b)).count(); - x.drain(..upto); - let revto = x.len() - x.iter().rev().take_while(|b| is_space(**b)).count(); - x.drain(revto..); -} - -/// Returns true if and only if the given byte is an ASCII space character. -fn is_space(b: u8) -> bool { - b == b'\t' - || b == b'\n' - || b == b'\x0B' - || b == b'\x0C' - || b == b'\r' - || b == b' ' -} - -/// On Unix, get an OsString from raw bytes. -#[cfg(unix)] -fn bytes_to_os_string(bytes: &[u8]) -> Result { - use std::os::unix::ffi::OsStringExt; - Ok(OsString::from_vec(bytes.to_vec())) -} - -/// On non-Unix (like Windows), require UTF-8. -#[cfg(not(unix))] -fn bytes_to_os_string(bytes: &[u8]) -> Result { - String::from_utf8(bytes.to_vec()).map(OsString::from).map_err(From::from) -} - -#[cfg(test)] -mod tests { - use std::ffi::OsString; - use super::parse_reader; - - #[test] - fn basic() { - let (args, errs) = parse_reader(&b"\ -# Test ---context=0 - --smart-case --u - - - # --bar ---foo -"[..]).unwrap(); - assert!(errs.is_empty()); - let args: Vec = - args.into_iter().map(|s| s.into_string().unwrap()).collect(); - assert_eq!(args, vec![ - "--context=0", "--smart-case", "-u", "--foo", - ]); - } - - // We test that we can handle invalid UTF-8 on Unix-like systems. - #[test] - #[cfg(unix)] - fn error() { - use std::os::unix::ffi::OsStringExt; - - let (args, errs) = parse_reader(&b"\ -quux -foo\xFFbar -baz -"[..]).unwrap(); - assert!(errs.is_empty()); - assert_eq!(args, vec![ - OsString::from("quux"), - OsString::from_vec(b"foo\xFFbar".to_vec()), - OsString::from("baz"), - ]); - } - - // ... but test that invalid UTF-8 fails on Windows. - #[test] - #[cfg(not(unix))] - fn error() { - let (args, errs) = parse_reader(&b"\ -quux -foo\xFFbar -baz -"[..]).unwrap(); - assert_eq!(errs.len(), 1); - assert_eq!(args, vec![ - OsString::from("quux"), - OsString::from("baz"), - ]); - } -} diff --git a/src/decoder.rs b/src/decoder.rs deleted file mode 100644 index 0842fb5..0000000 --- a/src/decoder.rs +++ /dev/null @@ -1,456 +0,0 @@ -use std::cmp; -use std::io::{self, Read}; - -use encoding_rs::{Decoder, Encoding, UTF_8}; - -/// A BOM is at least 2 bytes and at most 3 bytes. -/// -/// If fewer than 2 bytes are available to be read at the beginning of a -/// reader, then a BOM is `None`. -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -struct Bom { - bytes: [u8; 3], - len: usize, -} - -impl Bom { - fn as_slice(&self) -> &[u8] { - &self.bytes[0..self.len] - } - - fn decoder(&self) -> Option { - let bom = self.as_slice(); - if bom.len() < 3 { - return None; - } - if let Some((enc, _)) = Encoding::for_bom(bom) { - if enc != UTF_8 { - return Some(enc.new_decoder_with_bom_removal()); - } - } - None - } -} - -/// `BomPeeker` wraps `R` and satisfies the `io::Read` interface while also -/// providing a peek at the BOM if one exists. Peeking at the BOM does not -/// advance the reader. -struct BomPeeker { - rdr: R, - bom: Option, - nread: usize, -} - -impl BomPeeker { - /// Create a new BomPeeker. - /// - /// The first three bytes can be read using the `peek_bom` method, but - /// will not advance the reader. - fn new(rdr: R) -> BomPeeker { - BomPeeker { rdr: rdr, bom: None, nread: 0 } - } - - /// Peek at the first three bytes of the underlying reader. - /// - /// This does not advance the reader provided by `BomPeeker`. - /// - /// If the underlying reader does not have at least two bytes available, - /// then `None` is returned. - fn peek_bom(&mut self) -> io::Result { - if let Some(bom) = self.bom { - return Ok(bom); - } - self.bom = Some(Bom { bytes: [0; 3], len: 0 }); - let mut buf = [0u8; 3]; - let bom_len = read_full(&mut self.rdr, &mut buf)?; - self.bom = Some(Bom { bytes: buf, len: bom_len }); - Ok(self.bom.unwrap()) - } -} - -impl io::Read for BomPeeker { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - if self.nread < 3 { - let bom = self.peek_bom()?; - let bom = bom.as_slice(); - if self.nread < bom.len() { - let rest = &bom[self.nread..]; - let len = cmp::min(buf.len(), rest.len()); - buf[..len].copy_from_slice(&rest[..len]); - self.nread += len; - return Ok(len); - } - } - let nread = self.rdr.read(buf)?; - self.nread += nread; - Ok(nread) - } -} - -/// Like `io::Read::read_exact`, except it never returns `UnexpectedEof` and -/// instead returns the number of bytes read if EOF is seen before filling -/// `buf`. -fn read_full( - mut rdr: R, - mut buf: &mut [u8], -) -> io::Result { - let mut nread = 0; - while !buf.is_empty() { - match rdr.read(buf) { - Ok(0) => break, - Ok(n) => { - nread += n; - let tmp = buf; - buf = &mut tmp[n..]; - } - Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} - Err(e) => return Err(e), - } - } - Ok(nread) -} - -/// A reader that transcodes to UTF-8. The source encoding is determined by -/// inspecting the BOM from the stream read from `R`, if one exists. If a -/// UTF-16 BOM exists, then the source stream is transcoded to UTF-8 with -/// invalid UTF-16 sequences translated to the Unicode replacement character. -/// In all other cases, the underlying reader is passed through unchanged. -/// -/// `R` is the type of the underlying reader and `B` is the type of an internal -/// buffer used to store the results of transcoding. -/// -/// Note that not all methods on `io::Read` work with this implementation. -/// For example, the `bytes` adapter method attempts to read a single byte at -/// a time, but this implementation requires a buffer of size at least `4`. If -/// a buffer of size less than 4 is given, then an error is returned. -pub struct DecodeReader { - /// The underlying reader, wrapped in a peeker for reading a BOM if one - /// exists. - rdr: BomPeeker, - /// The internal buffer to store transcoded bytes before they are read by - /// callers. - buf: B, - /// The current position in `buf`. Subsequent reads start here. - pos: usize, - /// The number of transcoded bytes in `buf`. Subsequent reads end here. - buflen: usize, - /// Whether this is the first read or not (in which we inspect the BOM). - first: bool, - /// Whether a "last" read has occurred. After this point, EOF will always - /// be returned. - last: bool, - /// The underlying text decoder derived from the BOM, if one exists. - decoder: Option, -} - -impl> DecodeReader { - /// Create a new transcoder that converts a source stream to valid UTF-8. - /// - /// If an encoding is specified, then it is used to transcode `rdr` to - /// UTF-8. Otherwise, if no encoding is specified, and if a UTF-16 BOM is - /// found, then the corresponding UTF-16 encoding is used to transcode - /// `rdr` to UTF-8. In all other cases, `rdr` is assumed to be at least - /// ASCII-compatible and passed through untouched. - /// - /// Errors in the encoding of `rdr` are handled with the Unicode - /// replacement character. If no encoding of `rdr` is specified, then - /// errors are not handled. - pub fn new( - rdr: R, - buf: B, - enc: Option<&'static Encoding>, - ) -> DecodeReader { - DecodeReader { - rdr: BomPeeker::new(rdr), - buf: buf, - buflen: 0, - pos: 0, - first: enc.is_none(), - last: false, - decoder: enc.map(|enc| enc.new_decoder_with_bom_removal()), - } - } - - /// Fill the internal buffer from the underlying reader. - /// - /// If there are unread bytes in the internal buffer, then we move them - /// to the beginning of the internal buffer and fill the remainder. - /// - /// If the internal buffer is too small to read additional bytes, then an - /// error is returned. - #[inline(always)] // massive perf benefit (???) - fn fill(&mut self) -> io::Result<()> { - if self.pos < self.buflen { - if self.buflen >= self.buf.as_mut().len() { - return Err(io::Error::new( - io::ErrorKind::Other, - "DecodeReader: internal buffer exhausted")); - } - let newlen = self.buflen - self.pos; - let mut tmp = Vec::with_capacity(newlen); - tmp.extend_from_slice(&self.buf.as_mut()[self.pos..self.buflen]); - self.buf.as_mut()[..newlen].copy_from_slice(&tmp); - self.buflen = newlen; - } else { - self.buflen = 0; - } - self.pos = 0; - self.buflen += - self.rdr.read(&mut self.buf.as_mut()[self.buflen..])?; - Ok(()) - } - - /// Transcode the inner stream to UTF-8 in `buf`. This assumes that there - /// is a decoder capable of transcoding the inner stream to UTF-8. This - /// returns the number of bytes written to `buf`. - /// - /// When this function returns, exactly one of the following things will - /// be true: - /// - /// 1. A non-zero number of bytes were written to `buf`. - /// 2. The underlying reader reached EOF. - /// 3. An error is returned: the internal buffer ran out of room. - /// 4. An I/O error occurred. - /// - /// Note that `buf` must have at least 4 bytes of space. - fn transcode(&mut self, buf: &mut [u8]) -> io::Result { - assert!(buf.len() >= 4); - if self.last { - return Ok(0); - } - if self.pos >= self.buflen { - self.fill()?; - } - let mut nwrite = 0; - loop { - let (_, nin, nout, _) = - self.decoder.as_mut().unwrap().decode_to_utf8( - &self.buf.as_mut()[self.pos..self.buflen], buf, false); - self.pos += nin; - nwrite += nout; - // If we've written at least one byte to the caller-provided - // buffer, then our mission is complete. - if nwrite > 0 { - break; - } - // Otherwise, we know that our internal buffer has insufficient - // data to transcode at least one char, so we attempt to refill it. - self.fill()?; - // Quit on EOF. - if self.buflen == 0 { - self.pos = 0; - self.last = true; - let (_, _, nout, _) = - self.decoder.as_mut().unwrap().decode_to_utf8( - &[], buf, true); - return Ok(nout); - } - } - Ok(nwrite) - } - - #[inline(never)] // impacts perf... - fn detect(&mut self) -> io::Result<()> { - let bom = self.rdr.peek_bom()?; - self.decoder = bom.decoder(); - Ok(()) - } -} - -impl> io::Read for DecodeReader { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - if self.first { - self.first = false; - self.detect()?; - } - if self.decoder.is_none() { - return self.rdr.read(buf); - } - // When decoding UTF-8, we need at least 4 bytes of space to guarantee - // that we can decode at least one codepoint. If we don't have it, we - // can either return `0` for the number of bytes read or return an - // error. Since `0` would be interpreted as a possibly premature EOF, - // we opt for an error. - if buf.len() < 4 { - return Err(io::Error::new( - io::ErrorKind::Other, - "DecodeReader: byte buffer must have length at least 4")); - } - self.transcode(buf) - } -} - -#[cfg(test)] -mod tests { - use std::io::Read; - - use encoding_rs::Encoding; - - use super::{Bom, BomPeeker, DecodeReader}; - - fn read_to_string(mut rdr: R) -> String { - let mut s = String::new(); - rdr.read_to_string(&mut s).unwrap(); - s - } - - #[test] - fn peeker_empty() { - let buf = []; - let mut peeker = BomPeeker::new(&buf[..]); - assert_eq!(Bom { bytes: [0; 3], len: 0}, peeker.peek_bom().unwrap()); - - let mut tmp = [0; 100]; - assert_eq!(0, peeker.read(&mut tmp).unwrap()); - } - - #[test] - fn peeker_one() { - let buf = [1]; - let mut peeker = BomPeeker::new(&buf[..]); - assert_eq!( - Bom { bytes: [1, 0, 0], len: 1}, - peeker.peek_bom().unwrap()); - - let mut tmp = [0; 100]; - assert_eq!(1, peeker.read(&mut tmp).unwrap()); - assert_eq!(1, tmp[0]); - assert_eq!(0, peeker.read(&mut tmp).unwrap()); - } - - #[test] - fn peeker_two() { - let buf = [1, 2]; - let mut peeker = BomPeeker::new(&buf[..]); - assert_eq!( - Bom { bytes: [1, 2, 0], len: 2}, - peeker.peek_bom().unwrap()); - - let mut tmp = [0; 100]; - assert_eq!(2, peeker.read(&mut tmp).unwrap()); - assert_eq!(1, tmp[0]); - assert_eq!(2, tmp[1]); - assert_eq!(0, peeker.read(&mut tmp).unwrap()); - } - - #[test] - fn peeker_three() { - let buf = [1, 2, 3]; - let mut peeker = BomPeeker::new(&buf[..]); - assert_eq!( - Bom { bytes: [1, 2, 3], len: 3}, - peeker.peek_bom().unwrap()); - - let mut tmp = [0; 100]; - assert_eq!(3, peeker.read(&mut tmp).unwrap()); - assert_eq!(1, tmp[0]); - assert_eq!(2, tmp[1]); - assert_eq!(3, tmp[2]); - assert_eq!(0, peeker.read(&mut tmp).unwrap()); - } - - #[test] - fn peeker_four() { - let buf = [1, 2, 3, 4]; - let mut peeker = BomPeeker::new(&buf[..]); - assert_eq!( - Bom { bytes: [1, 2, 3], len: 3}, - peeker.peek_bom().unwrap()); - - let mut tmp = [0; 100]; - assert_eq!(3, peeker.read(&mut tmp).unwrap()); - assert_eq!(1, tmp[0]); - assert_eq!(2, tmp[1]); - assert_eq!(3, tmp[2]); - assert_eq!(1, peeker.read(&mut tmp).unwrap()); - assert_eq!(4, tmp[0]); - assert_eq!(0, peeker.read(&mut tmp).unwrap()); - } - - #[test] - fn peeker_one_at_a_time() { - let buf = [1, 2, 3, 4]; - let mut peeker = BomPeeker::new(&buf[..]); - - let mut tmp = [0; 1]; - assert_eq!(0, peeker.read(&mut tmp[..0]).unwrap()); - assert_eq!(0, tmp[0]); - assert_eq!(1, peeker.read(&mut tmp).unwrap()); - assert_eq!(1, tmp[0]); - assert_eq!(1, peeker.read(&mut tmp).unwrap()); - assert_eq!(2, tmp[0]); - assert_eq!(1, peeker.read(&mut tmp).unwrap()); - assert_eq!(3, tmp[0]); - assert_eq!(1, peeker.read(&mut tmp).unwrap()); - assert_eq!(4, tmp[0]); - } - - // In cases where all we have is a bom, we expect the bytes to be - // passed through unchanged. - #[test] - fn trans_utf16_bom() { - let srcbuf = vec![0xFF, 0xFE]; - let mut dstbuf = vec![0; 8 * (1<<10)]; - let mut rdr = DecodeReader::new(&*srcbuf, vec![0; 8 * (1<<10)], None); - let n = rdr.read(&mut dstbuf).unwrap(); - assert_eq!(&*srcbuf, &dstbuf[..n]); - - let srcbuf = vec![0xFE, 0xFF]; - let mut rdr = DecodeReader::new(&*srcbuf, vec![0; 8 * (1<<10)], None); - let n = rdr.read(&mut dstbuf).unwrap(); - assert_eq!(&*srcbuf, &dstbuf[..n]); - - let srcbuf = vec![0xEF, 0xBB, 0xBF]; - let mut rdr = DecodeReader::new(&*srcbuf, vec![0; 8 * (1<<10)], None); - let n = rdr.read(&mut dstbuf).unwrap(); - assert_eq!(&*srcbuf, &dstbuf[..n]); - } - - // Test basic UTF-16 decoding. - #[test] - fn trans_utf16_basic() { - let srcbuf = vec![0xFF, 0xFE, 0x61, 0x00]; - let mut rdr = DecodeReader::new(&*srcbuf, vec![0; 8 * (1<<10)], None); - assert_eq!("a", read_to_string(&mut rdr)); - - let srcbuf = vec![0xFE, 0xFF, 0x00, 0x61]; - let mut rdr = DecodeReader::new(&*srcbuf, vec![0; 8 * (1<<10)], None); - assert_eq!("a", read_to_string(&mut rdr)); - } - - // Test incomplete UTF-16 decoding. This ensures we see a replacement char - // if the stream ends with an unpaired code unit. - #[test] - fn trans_utf16_incomplete() { - let srcbuf = vec![0xFF, 0xFE, 0x61, 0x00, 0x00]; - let mut rdr = DecodeReader::new(&*srcbuf, vec![0; 8 * (1<<10)], None); - assert_eq!("a\u{FFFD}", read_to_string(&mut rdr)); - } - - macro_rules! test_trans_simple { - ($name:ident, $enc:expr, $srcbytes:expr, $dst:expr) => { - #[test] - fn $name() { - let srcbuf = &$srcbytes[..]; - let enc = Encoding::for_label($enc.as_bytes()); - let mut rdr = DecodeReader::new( - &*srcbuf, vec![0; 8 * (1<<10)], enc); - assert_eq!($dst, read_to_string(&mut rdr)); - } - } - } - - // This isn't exhaustive obviously, but it lets us test base level support. - test_trans_simple!(trans_simple_auto, "does not exist", b"\xD0\x96", "Ж"); - test_trans_simple!(trans_simple_utf8, "utf-8", b"\xD0\x96", "Ж"); - test_trans_simple!(trans_simple_utf16le, "utf-16le", b"\x16\x04", "Ж"); - test_trans_simple!(trans_simple_utf16be, "utf-16be", b"\x04\x16", "Ж"); - test_trans_simple!(trans_simple_chinese, "chinese", b"\xA7\xA8", "Ж"); - test_trans_simple!(trans_simple_korean, "korean", b"\xAC\xA8", "Ж"); - test_trans_simple!( - trans_simple_big5_hkscs, "big5-hkscs", b"\xC7\xFA", "Ж"); - test_trans_simple!(trans_simple_gbk, "gbk", b"\xA7\xA8", "Ж"); - test_trans_simple!(trans_simple_sjis, "sjis", b"\x84\x47", "Ж"); - test_trans_simple!(trans_simple_eucjp, "euc-jp", b"\xA7\xA8", "Ж"); - test_trans_simple!(trans_simple_latin1, "latin1", b"\xA9", "©"); -} diff --git a/src/decompressor.rs b/src/decompressor.rs deleted file mode 100644 index a94948a..0000000 --- a/src/decompressor.rs +++ /dev/null @@ -1,191 +0,0 @@ -use std::collections::HashMap; -use std::ffi::OsStr; -use std::fmt; -use std::io::{self, Read}; -use std::path::Path; -use std::process::{self, Stdio}; - -use globset::{Glob, GlobSet, GlobSetBuilder}; - -/// A decompression command, contains the command to be spawned as well as any -/// necessary CLI args. -#[derive(Clone, Copy, Debug)] -struct DecompressionCommand { - cmd: &'static str, - args: &'static [&'static str], -} - -impl DecompressionCommand { - /// Create a new decompress command - fn new( - cmd: &'static str, - args: &'static [&'static str], - ) -> DecompressionCommand { - DecompressionCommand { - cmd, args - } - } -} - -impl fmt::Display for DecompressionCommand { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{} {}", self.cmd, self.args.join(" ")) - } -} - -lazy_static! { - static ref DECOMPRESSION_COMMANDS: HashMap< - &'static str, - DecompressionCommand, - > = { - let mut m = HashMap::new(); - - const ARGS: &[&str] = &["-d", "-c"]; - m.insert("gz", DecompressionCommand::new("gzip", ARGS)); - m.insert("bz2", DecompressionCommand::new("bzip2", ARGS)); - m.insert("xz", DecompressionCommand::new("xz", ARGS)); - - const LZMA_ARGS: &[&str] = &["--format=lzma", "-d", "-c"]; - m.insert("lzma", DecompressionCommand::new("xz", LZMA_ARGS)); - - m - }; - static ref SUPPORTED_COMPRESSION_FORMATS: GlobSet = { - let mut builder = GlobSetBuilder::new(); - builder.add(Glob::new("*.gz").unwrap()); - builder.add(Glob::new("*.bz2").unwrap()); - builder.add(Glob::new("*.xz").unwrap()); - builder.add(Glob::new("*.lzma").unwrap()); - builder.build().unwrap() - }; - static ref TAR_ARCHIVE_FORMATS: GlobSet = { - let mut builder = GlobSetBuilder::new(); - builder.add(Glob::new("*.tar.gz").unwrap()); - builder.add(Glob::new("*.tar.xz").unwrap()); - builder.add(Glob::new("*.tar.bz2").unwrap()); - builder.add(Glob::new("*.tgz").unwrap()); - builder.add(Glob::new("*.txz").unwrap()); - builder.add(Glob::new("*.tbz2").unwrap()); - builder.build().unwrap() - }; -} - -/// DecompressionReader provides an `io::Read` implementation for a limited -/// set of compression formats. -#[derive(Debug)] -pub struct DecompressionReader { - cmd: DecompressionCommand, - child: process::Child, - done: bool, -} - -impl DecompressionReader { - /// Returns a handle to the stdout of the spawned decompression process for - /// `path`, which can be directly searched in the worker. When the returned - /// value is exhausted, the underlying process is reaped. If the underlying - /// process fails, then its stderr is read and converted into a normal - /// io::Error. - /// - /// If there is any error in spawning the decompression command, then - /// return `None`, after outputting any necessary debug or error messages. - pub fn from_path(path: &Path) -> Option { - if is_tar_archive(path) { - debug!("{}: skipping tar archive", path.display()); - return None; - } - let extension = match path.extension().and_then(OsStr::to_str) { - Some(extension) => extension, - None => { - debug!( - "{}: failed to get compresson extension", path.display()); - return None; - } - }; - let decompression_cmd = match DECOMPRESSION_COMMANDS.get(extension) { - Some(cmd) => cmd, - None => { - debug!( - "{}: failed to get decompression command", path.display()); - return None; - } - }; - let cmd = process::Command::new(decompression_cmd.cmd) - .args(decompression_cmd.args) - .arg(path) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .spawn(); - let child = match cmd { - Ok(process) => process, - Err(_) => { - debug!( - "{}: decompression command '{}' not found", - path.display(), decompression_cmd.cmd); - return None; - } - }; - Some(DecompressionReader::new(*decompression_cmd, child)) - } - - fn new( - cmd: DecompressionCommand, - child: process::Child, - ) -> DecompressionReader { - DecompressionReader { - cmd: cmd, - child: child, - done: false, - } - } - - fn read_error(&mut self) -> io::Result { - let mut errbytes = vec![]; - self.child.stderr.as_mut().unwrap().read_to_end(&mut errbytes)?; - let errstr = String::from_utf8_lossy(&errbytes); - let errstr = errstr.trim(); - - Ok(if errstr.is_empty() { - let msg = format!("decompression command failed: '{}'", self.cmd); - io::Error::new(io::ErrorKind::Other, msg) - } else { - let msg = format!( - "decompression command '{}' failed: {}", self.cmd, errstr); - io::Error::new(io::ErrorKind::Other, msg) - }) - } -} - -impl io::Read for DecompressionReader { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - if self.done { - return Ok(0); - } - let nread = self.child.stdout.as_mut().unwrap().read(buf)?; - if nread == 0 { - self.done = true; - // Reap the child now that we're done reading. - // If the command failed, report stderr as an error. - if !self.child.wait()?.success() { - return Err(self.read_error()?); - } - } - Ok(nread) - } -} - -/// Returns true if the given path contains a supported compression format or -/// is a TAR archive. -pub fn is_compressed(path: &Path) -> bool { - is_supported_compression_format(path) || is_tar_archive(path) -} - -/// Returns true if the given path matches any one of the supported compression -/// formats -fn is_supported_compression_format(path: &Path) -> bool { - SUPPORTED_COMPRESSION_FORMATS.is_match(path) -} - -/// Returns true if the given path matches any of the known TAR file formats. -fn is_tar_archive(path: &Path) -> bool { - TAR_ARCHIVE_FORMATS.is_match(path) -} diff --git a/termcolor/src/lib.rs b/src/lib.rs similarity index 100% rename from termcolor/src/lib.rs rename to src/lib.rs diff --git a/src/logger.rs b/src/logger.rs deleted file mode 100644 index 8bd7e09..0000000 --- a/src/logger.rs +++ /dev/null @@ -1,57 +0,0 @@ -// This module defines a super simple logger that works with the `log` crate. -// We don't need anything fancy; just basic log levels and the ability to -// print to stderr. We therefore avoid bringing in extra dependencies just -// for this functionality. - -use log::{self, Log}; - -/// The simplest possible logger that logs to stderr. -/// -/// This logger does no filtering. Instead, it relies on the `log` crates -/// filtering via its global max_level setting. -#[derive(Debug)] -pub struct Logger(()); - -const LOGGER: &'static Logger = &Logger(()); - -impl Logger { - /// Create a new logger that logs to stderr and initialize it as the - /// global logger. If there was a problem setting the logger, then an - /// error is returned. - pub fn init() -> Result<(), log::SetLoggerError> { - log::set_logger(LOGGER) - } -} - -impl Log for Logger { - fn enabled(&self, _: &log::Metadata) -> bool { - // We set the log level via log::set_max_level, so we don't need to - // implement filtering here. - true - } - - fn log(&self, record: &log::Record) { - match (record.file(), record.line()) { - (Some(file), Some(line)) => { - eprintln!( - "{}/{}/{}:{}: {}", - record.level(), record.target(), - file, line, record.args()); - } - (Some(file), None) => { - eprintln!( - "{}/{}/{}: {}", - record.level(), record.target(), file, record.args()); - } - _ => { - eprintln!( - "{}/{}: {}", - record.level(), record.target(), record.args()); - } - } - } - - fn flush(&self) { - // We use eprintln! which is flushed on every call. - } -} diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index 6f01013..0000000 --- a/src/main.rs +++ /dev/null @@ -1,441 +0,0 @@ -extern crate atty; -extern crate bytecount; -#[macro_use] -extern crate clap; -extern crate encoding_rs; -extern crate globset; -extern crate grep; -extern crate ignore; -#[macro_use] -extern crate lazy_static; -extern crate libc; -#[macro_use] -extern crate log; -extern crate memchr; -extern crate memmap; -extern crate num_cpus; -extern crate regex; -extern crate same_file; -extern crate termcolor; -#[cfg(windows)] -extern crate winapi; - -use std::error::Error; -use std::process; -use std::result; -use std::sync::Arc; -use std::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::mpsc; -use std::thread; -use std::time::{Duration, Instant}; - -use args::Args; -use worker::Work; - -macro_rules! errored { - ($($tt:tt)*) => { - return Err(From::from(format!($($tt)*))); - } -} - -mod app; -mod args; -mod config; -mod decoder; -mod decompressor; -mod logger; -mod pathutil; -mod printer; -mod search_buffer; -mod search_stream; -mod unescape; -mod worker; - -pub type Result = result::Result>; - -fn main() { - reset_sigpipe(); - match Args::parse().map(Arc::new).and_then(run) { - Ok(0) => process::exit(1), - Ok(_) => process::exit(0), - Err(err) => { - eprintln!("{}", err); - process::exit(2); - } - } -} - -fn run(args: Arc) -> Result { - if args.never_match() { - return Ok(0); - } - let threads = args.threads(); - if args.files() { - if threads == 1 || args.is_one_path() { - run_files_one_thread(&args) - } else { - run_files_parallel(args) - } - } else if args.type_list() { - run_types(&args) - } else if threads == 1 || args.is_one_path() { - run_one_thread(&args) - } else { - run_parallel(&args) - } -} - -fn run_parallel(args: &Arc) -> Result { - let start_time = Instant::now(); - let bufwtr = Arc::new(args.buffer_writer()); - let quiet_matched = args.quiet_matched(); - let paths_searched = Arc::new(AtomicUsize::new(0)); - let match_line_count = Arc::new(AtomicUsize::new(0)); - let paths_matched = Arc::new(AtomicUsize::new(0)); - - args.walker_parallel().run(|| { - let args = Arc::clone(args); - let quiet_matched = quiet_matched.clone(); - let paths_searched = paths_searched.clone(); - let match_line_count = match_line_count.clone(); - let paths_matched = paths_matched.clone(); - let bufwtr = Arc::clone(&bufwtr); - let mut buf = bufwtr.buffer(); - let mut worker = args.worker(); - Box::new(move |result| { - use ignore::WalkState::*; - - if quiet_matched.has_match() { - return Quit; - } - let dent = match get_or_log_dir_entry( - result, - args.stdout_handle(), - args.files(), - args.no_messages(), - args.no_ignore_messages(), - ) { - None => return Continue, - Some(dent) => dent, - }; - paths_searched.fetch_add(1, Ordering::SeqCst); - buf.clear(); - { - // This block actually executes the search and prints the - // results into outbuf. - let mut printer = args.printer(&mut buf); - let count = - if dent.is_stdin() { - worker.run(&mut printer, Work::Stdin) - } else { - worker.run(&mut printer, Work::DirEntry(dent)) - }; - match_line_count.fetch_add(count as usize, Ordering::SeqCst); - if quiet_matched.set_match(count > 0) { - return Quit; - } - if args.stats() && count > 0 { - paths_matched.fetch_add(1, Ordering::SeqCst); - } - } - // BUG(burntsushi): We should handle this error instead of ignoring - // it. See: https://github.com/BurntSushi/ripgrep/issues/200 - let _ = bufwtr.print(&buf); - Continue - }) - }); - if !args.paths().is_empty() && paths_searched.load(Ordering::SeqCst) == 0 { - if !args.no_messages() { - eprint_nothing_searched(); - } - } - let match_line_count = match_line_count.load(Ordering::SeqCst) as u64; - let paths_searched = paths_searched.load(Ordering::SeqCst) as u64; - let paths_matched = paths_matched.load(Ordering::SeqCst) as u64; - if args.stats() { - print_stats( - match_line_count, - paths_searched, - paths_matched, - start_time.elapsed(), - ); - } - Ok(match_line_count) -} - -fn run_one_thread(args: &Arc) -> Result { - let start_time = Instant::now(); - let mut stdout = args.stdout(); - let mut worker = args.worker(); - let mut paths_searched: u64 = 0; - let mut match_line_count = 0; - let mut paths_matched: u64 = 0; - for result in args.walker() { - let dent = match get_or_log_dir_entry( - result, - args.stdout_handle(), - args.files(), - args.no_messages(), - args.no_ignore_messages(), - ) { - None => continue, - Some(dent) => dent, - }; - let mut printer = args.printer(&mut stdout); - if match_line_count > 0 { - if args.quiet() { - break; - } - if let Some(sep) = args.file_separator() { - printer = printer.file_separator(sep); - } - } - paths_searched += 1; - let count = - if dent.is_stdin() { - worker.run(&mut printer, Work::Stdin) - } else { - worker.run(&mut printer, Work::DirEntry(dent)) - }; - match_line_count += count; - if args.stats() && count > 0 { - paths_matched += 1; - } - } - if !args.paths().is_empty() && paths_searched == 0 { - if !args.no_messages() { - eprint_nothing_searched(); - } - } - if args.stats() { - print_stats( - match_line_count, - paths_searched, - paths_matched, - start_time.elapsed(), - ); - } - Ok(match_line_count) -} - -fn run_files_parallel(args: Arc) -> Result { - let print_args = Arc::clone(&args); - let (tx, rx) = mpsc::channel::(); - let print_thread = thread::spawn(move || { - let mut printer = print_args.printer(print_args.stdout()); - let mut file_count = 0; - for dent in rx.iter() { - if !print_args.quiet() { - printer.path(dent.path()); - } - file_count += 1; - } - file_count - }); - args.walker_parallel().run(move || { - let args = Arc::clone(&args); - let tx = tx.clone(); - Box::new(move |result| { - if let Some(dent) = get_or_log_dir_entry( - result, - args.stdout_handle(), - args.files(), - args.no_messages(), - args.no_ignore_messages(), - ) { - tx.send(dent).unwrap(); - } - ignore::WalkState::Continue - }) - }); - Ok(print_thread.join().unwrap()) -} - -fn run_files_one_thread(args: &Arc) -> Result { - let mut printer = args.printer(args.stdout()); - let mut file_count = 0; - for result in args.walker() { - let dent = match get_or_log_dir_entry( - result, - args.stdout_handle(), - args.files(), - args.no_messages(), - args.no_ignore_messages(), - ) { - None => continue, - Some(dent) => dent, - }; - if !args.quiet() { - printer.path(dent.path()); - } - file_count += 1; - } - Ok(file_count) -} - -fn run_types(args: &Arc) -> Result { - let mut printer = args.printer(args.stdout()); - let mut ty_count = 0; - for def in args.type_defs() { - printer.type_def(def); - ty_count += 1; - } - Ok(ty_count) -} - -fn get_or_log_dir_entry( - result: result::Result, - stdout_handle: Option<&same_file::Handle>, - files_only: bool, - no_messages: bool, - no_ignore_messages: bool, -) -> Option { - match result { - Err(err) => { - if !no_messages { - eprintln!("{}", err); - } - None - } - Ok(dent) => { - if let Some(err) = dent.error() { - if !no_messages && !no_ignore_messages { - eprintln!("{}", err); - } - } - if dent.file_type().is_none() { - return Some(dent); // entry is stdin - } - // A depth of 0 means the user gave the path explicitly, so we - // should always try to search it. - if dent.depth() == 0 && !ignore_entry_is_dir(&dent) { - return Some(dent); - } else if !ignore_entry_is_file(&dent) { - return None; - } - // If we are redirecting stdout to a file, then don't search that - // file. - if !files_only && is_stdout_file(&dent, stdout_handle, no_messages) { - return None; - } - Some(dent) - } - } -} - -/// Returns true if and only if the given `ignore::DirEntry` points to a -/// directory. -/// -/// This works around a bug in Rust's standard library: -/// https://github.com/rust-lang/rust/issues/46484 -#[cfg(windows)] -fn ignore_entry_is_dir(dent: &ignore::DirEntry) -> bool { - use std::os::windows::fs::MetadataExt; - use winapi::um::winnt::FILE_ATTRIBUTE_DIRECTORY; - - dent.metadata().map(|md| { - md.file_attributes() & FILE_ATTRIBUTE_DIRECTORY != 0 - }).unwrap_or(false) -} - -/// Returns true if and only if the given `ignore::DirEntry` points to a -/// directory. -#[cfg(not(windows))] -fn ignore_entry_is_dir(dent: &ignore::DirEntry) -> bool { - dent.file_type().map_or(false, |ft| ft.is_dir()) -} - -/// Returns true if and only if the given `ignore::DirEntry` points to a -/// file. -/// -/// This works around a bug in Rust's standard library: -/// https://github.com/rust-lang/rust/issues/46484 -#[cfg(windows)] -fn ignore_entry_is_file(dent: &ignore::DirEntry) -> bool { - !ignore_entry_is_dir(dent) -} - -/// Returns true if and only if the given `ignore::DirEntry` points to a -/// file. -#[cfg(not(windows))] -fn ignore_entry_is_file(dent: &ignore::DirEntry) -> bool { - dent.file_type().map_or(false, |ft| ft.is_file()) -} - -fn is_stdout_file( - dent: &ignore::DirEntry, - stdout_handle: Option<&same_file::Handle>, - no_messages: bool, -) -> bool { - let stdout_handle = match stdout_handle { - None => return false, - Some(stdout_handle) => stdout_handle, - }; - // If we know for sure that these two things aren't equal, then avoid - // the costly extra stat call to determine equality. - if !maybe_dent_eq_handle(dent, stdout_handle) { - return false; - } - match same_file::Handle::from_path(dent.path()) { - Ok(h) => stdout_handle == &h, - Err(err) => { - if !no_messages { - eprintln!("{}: {}", dent.path().display(), err); - } - false - } - } -} - -#[cfg(unix)] -fn maybe_dent_eq_handle( - dent: &ignore::DirEntry, - handle: &same_file::Handle, -) -> bool { - dent.ino() == Some(handle.ino()) -} - -#[cfg(not(unix))] -fn maybe_dent_eq_handle(_: &ignore::DirEntry, _: &same_file::Handle) -> bool { - true -} - -fn eprint_nothing_searched() { - eprintln!("No files were searched, which means ripgrep probably \ - applied a filter you didn't expect. \ - Try running again with --debug."); -} - -fn print_stats( - match_count: u64, - paths_searched: u64, - paths_matched: u64, - time_elapsed: Duration, -) { - let time_elapsed = - time_elapsed.as_secs() as f64 - + (time_elapsed.subsec_nanos() as f64 * 1e-9); - println!("\n{} matched lines\n\ - {} files contained matches\n\ - {} files searched\n\ - {:.3} seconds", match_count, paths_matched, - paths_searched, time_elapsed); -} - -// The Rust standard library suppresses the default SIGPIPE behavior, so that -// writing to a closed pipe doesn't kill the process. The goal is to instead -// handle errors through the normal result mechanism. Ripgrep needs some -// refactoring before it will be able to do that, however, so we re-enable the -// standard SIGPIPE behavior as a workaround. See -// https://github.com/BurntSushi/ripgrep/issues/200. -#[cfg(unix)] -fn reset_sigpipe() { - unsafe { - libc::signal(libc::SIGPIPE, libc::SIG_DFL); - } -} - -#[cfg(not(unix))] -fn reset_sigpipe() { - // no-op -} diff --git a/src/pathutil.rs b/src/pathutil.rs deleted file mode 100644 index 8d1c151..0000000 --- a/src/pathutil.rs +++ /dev/null @@ -1,42 +0,0 @@ -/*! -The pathutil module provides platform specific operations on paths that are -typically faster than the same operations as provided in `std::path`. In -particular, we really want to avoid the costly operation of parsing the path -into its constituent components. We give up on Windows, but on Unix, we deal -with the raw bytes directly. - -On large repositories (like chromium), this can have a ~25% performance -improvement on just listing the files to search (!). -*/ -use std::path::Path; - -/// Strip `prefix` from the `path` and return the remainder. -/// -/// If `path` doesn't have a prefix `prefix`, then return `None`. -#[cfg(unix)] -pub fn strip_prefix<'a, P: AsRef + ?Sized>( - prefix: &'a P, - path: &'a Path, -) -> Option<&'a Path> { - use std::ffi::OsStr; - use std::os::unix::ffi::OsStrExt; - - let prefix = prefix.as_ref().as_os_str().as_bytes(); - let path = path.as_os_str().as_bytes(); - if prefix.len() > path.len() || prefix != &path[0..prefix.len()] { - None - } else { - Some(Path::new(OsStr::from_bytes(&path[prefix.len()..]))) - } -} - -/// Strip `prefix` from the `path` and return the remainder. -/// -/// If `path` doesn't have a prefix `prefix`, then return `None`. -#[cfg(not(unix))] -pub fn strip_prefix<'a, P: AsRef + ?Sized>( - prefix: &'a P, - path: &'a Path, -) -> Option<&'a Path> { - path.strip_prefix(prefix).ok() -} diff --git a/src/printer.rs b/src/printer.rs deleted file mode 100644 index 20fd1c4..0000000 --- a/src/printer.rs +++ /dev/null @@ -1,928 +0,0 @@ -use std::error; -use std::fmt; -use std::path::Path; -use std::str::FromStr; - -use regex::bytes::{Captures, Match, Regex, Replacer}; -use termcolor::{Color, ColorSpec, ParseColorError, WriteColor}; - -use pathutil::strip_prefix; -use ignore::types::FileTypeDef; - -/// Track the start and end of replacements to allow coloring them on output. -#[derive(Debug)] -struct Offset { - start: usize, - end: usize, -} - -impl Offset { - fn new(start: usize, end: usize) -> Offset { - Offset { start: start, end: end } - } -} - -impl<'m, 'r> From<&'m Match<'r>> for Offset { - fn from(m: &'m Match<'r>) -> Self { - Offset{ start: m.start(), end: m.end() } - } -} - -/// `CountingReplacer` implements the Replacer interface for Regex, -/// and counts how often replacement is being performed. -struct CountingReplacer<'r> { - replace: &'r [u8], - count: &'r mut usize, - offsets: &'r mut Vec, -} - -impl<'r> CountingReplacer<'r> { - fn new( - replace: &'r [u8], - count: &'r mut usize, - offsets: &'r mut Vec, - ) -> CountingReplacer<'r> { - CountingReplacer { replace: replace, count: count, offsets: offsets, } - } -} - -impl<'r> Replacer for CountingReplacer<'r> { - fn replace_append(&mut self, caps: &Captures, dst: &mut Vec) { - *self.count += 1; - let start = dst.len(); - caps.expand(self.replace, dst); - let end = dst.len(); - if start != end { - self.offsets.push(Offset::new(start, end)); - } - } -} - -/// Printer encapsulates all output logic for searching. -/// -/// Note that we currently ignore all write errors. It's probably worthwhile -/// to fix this, but printers are only ever used for writes to stdout or -/// writes to memory, neither of which commonly fail. -pub struct Printer { - /// The underlying writer. - wtr: W, - /// Whether anything has been printed to wtr yet. - has_printed: bool, - /// Whether to show column numbers for the first match or not. - column: bool, - /// The string to use to separate non-contiguous runs of context lines. - context_separator: Vec, - /// The end-of-line terminator used by the printer. In general, eols are - /// printed via the match directly, but occasionally we need to insert them - /// ourselves (for example, to print a context separator). - eol: u8, - /// A file separator to show before any matches are printed. - file_separator: Option>, - /// Whether to show file name as a heading or not. - /// - /// N.B. If with_filename is false, then this setting has no effect. - heading: bool, - /// Whether to show every match on its own line. - line_per_match: bool, - /// Whether to print NUL bytes after a file path instead of new lines - /// or `:`. - null: bool, - /// Print only the matched (non-empty) parts of a matching line - only_matching: bool, - /// A string to use as a replacement of each match in a matching line. - replace: Option>, - /// Whether to prefix each match with the corresponding file name. - with_filename: bool, - /// The color specifications. - colors: ColorSpecs, - /// The separator to use for file paths. If empty, this is ignored. - path_separator: Option, - /// Restrict lines to this many columns. - max_columns: Option, -} - -impl Printer { - /// Create a new printer that writes to wtr with the given color settings. - pub fn new(wtr: W) -> Printer { - Printer { - wtr: wtr, - has_printed: false, - column: false, - context_separator: "--".to_string().into_bytes(), - eol: b'\n', - file_separator: None, - heading: false, - line_per_match: false, - null: false, - only_matching: false, - replace: None, - with_filename: false, - colors: ColorSpecs::default(), - path_separator: None, - max_columns: None, - } - } - - /// Set the color specifications. - pub fn colors(mut self, colors: ColorSpecs) -> Printer { - self.colors = colors; - self - } - - /// When set, column numbers will be printed for the first match on each - /// line. - pub fn column(mut self, yes: bool) -> Printer { - self.column = yes; - self - } - - /// Set the context separator. The default is `--`. - pub fn context_separator(mut self, sep: Vec) -> Printer { - self.context_separator = sep; - self - } - - /// Set the end-of-line terminator. The default is `\n`. - pub fn eol(mut self, eol: u8) -> Printer { - self.eol = eol; - self - } - - /// If set, the separator is printed before any matches. By default, no - /// separator is printed. - pub fn file_separator(mut self, sep: Vec) -> Printer { - self.file_separator = Some(sep); - self - } - - /// Whether to show file name as a heading or not. - /// - /// N.B. If with_filename is false, then this setting has no effect. - pub fn heading(mut self, yes: bool) -> Printer { - self.heading = yes; - self - } - - /// Whether to show every match on its own line. - pub fn line_per_match(mut self, yes: bool) -> Printer { - self.line_per_match = yes; - self - } - - /// Whether to cause NUL bytes to follow file paths instead of other - /// visual separators (like `:`, `-` and `\n`). - pub fn null(mut self, yes: bool) -> Printer { - self.null = yes; - self - } - - /// Print only the matched (non-empty) parts of a matching line - pub fn only_matching(mut self, yes: bool) -> Printer { - self.only_matching = yes; - self - } - - /// A separator to use when printing file paths. When empty, use the - /// default separator for the current platform. (/ on Unix, \ on Windows.) - pub fn path_separator(mut self, sep: Option) -> Printer { - self.path_separator = sep; - self - } - - /// Replace every match in each matching line with the replacement string - /// given. - pub fn replace(mut self, replacement: Vec) -> Printer { - self.replace = Some(replacement); - self - } - - /// When set, each match is prefixed with the file name that it came from. - pub fn with_filename(mut self, yes: bool) -> Printer { - self.with_filename = yes; - self - } - - /// Configure the max. number of columns used for printing matching lines. - pub fn max_columns(mut self, max_columns: Option) -> Printer { - self.max_columns = max_columns; - self - } - - /// Returns true if and only if something has been printed. - pub fn has_printed(&self) -> bool { - self.has_printed - } - - /// Flushes the underlying writer and returns it. - #[allow(dead_code)] - pub fn into_inner(mut self) -> W { - let _ = self.wtr.flush(); - self.wtr - } - - /// Prints a type definition. - pub fn type_def(&mut self, def: &FileTypeDef) { - self.write(def.name().as_bytes()); - self.write(b": "); - let mut first = true; - for glob in def.globs() { - if !first { - self.write(b", "); - } - self.write(glob.as_bytes()); - first = false; - } - self.write_eol(); - } - - /// Prints the given path. - pub fn path>(&mut self, path: P) { - let path = strip_prefix("./", path.as_ref()).unwrap_or(path.as_ref()); - self.write_path(path); - self.write_path_eol(); - } - - /// Prints the given path and a count of the number of matches found. - pub fn path_count>(&mut self, path: P, count: u64) { - if self.with_filename { - self.write_path(path); - self.write_path_sep(b':'); - } - self.write(count.to_string().as_bytes()); - self.write_eol(); - } - - /// Prints the context separator. - pub fn context_separate(&mut self) { - if self.context_separator.is_empty() { - return; - } - let _ = self.wtr.write_all(&self.context_separator); - self.write_eol(); - } - - pub fn matched>( - &mut self, - re: &Regex, - path: P, - buf: &[u8], - start: usize, - end: usize, - line_number: Option, - byte_offset: Option - ) { - if !self.line_per_match && !self.only_matching { - let mat = - if !self.needs_match() { - (0, 0) - } else { - re.find(&buf[start..end]) - .map(|m| (m.start(), m.end())) - .unwrap_or((0, 0)) - }; - return self.write_match( - re, path, buf, start, end, line_number, - byte_offset, mat.0, mat.1); - } - for m in re.find_iter(&buf[start..end]) { - self.write_match( - re, path.as_ref(), buf, start, end, line_number, - byte_offset, m.start(), m.end()); - } - } - - fn needs_match(&self) -> bool { - self.column - || self.replace.is_some() - || self.only_matching - } - - fn write_match>( - &mut self, - re: &Regex, - path: P, - buf: &[u8], - start: usize, - end: usize, - line_number: Option, - byte_offset: Option, - match_start: usize, - match_end: usize, - ) { - if self.heading && self.with_filename && !self.has_printed { - self.write_file_sep(); - self.write_path(path); - self.write_path_eol(); - } else if !self.heading && self.with_filename { - self.write_path(path); - self.write_path_sep(b':'); - } - if let Some(line_number) = line_number { - self.line_number(line_number, b':'); - } - if self.column { - self.column_number(match_start as u64 + 1, b':'); - } - if let Some(byte_offset) = byte_offset { - if self.only_matching { - self.write_byte_offset( - byte_offset + ((start + match_start) as u64), b':'); - } else { - self.write_byte_offset(byte_offset + (start as u64), b':'); - } - } - if self.replace.is_some() { - let mut count = 0; - let mut offsets = Vec::new(); - let line = { - let replacer = CountingReplacer::new( - self.replace.as_ref().unwrap(), &mut count, &mut offsets); - if self.only_matching { - re.replace_all( - &buf[start + match_start..start + match_end], replacer) - } else { - re.replace_all(&buf[start..end], replacer) - } - }; - if self.max_columns.map_or(false, |m| line.len() > m) { - let msg = format!( - "[Omitted long line with {} replacements]", count); - self.write_colored(msg.as_bytes(), |colors| colors.matched()); - self.write_eol(); - return; - } - self.write_matched_line(offsets, &*line, false); - } else { - let buf = if self.only_matching { - &buf[start + match_start..start + match_end] - } else { - &buf[start..end] - }; - if self.max_columns.map_or(false, |m| buf.len() > m) { - let count = re.find_iter(buf).count(); - let msg = format!("[Omitted long line with {} matches]", count); - self.write_colored(msg.as_bytes(), |colors| colors.matched()); - self.write_eol(); - return; - } - let only_match = self.only_matching; - self.write_matched_line( - re.find_iter(buf).map(|x| Offset::from(&x)), buf, only_match); - } - } - - fn write_matched_line(&mut self, offsets: I, buf: &[u8], only_match: bool) - where I: IntoIterator, - { - if !self.wtr.supports_color() || self.colors.matched().is_none() { - self.write(buf); - } else if only_match { - self.write_colored(buf, |colors| colors.matched()); - } else { - let mut last_written = 0; - for o in offsets { - self.write(&buf[last_written..o.start]); - // This conditional checks if the match is both empty *and* - // past the end of the line. In this case, we never want to - // emit an additional color escape. - if o.start != o.end || o.end != buf.len() { - self.write_colored( - &buf[o.start..o.end], |colors| colors.matched()); - } - last_written = o.end; - } - self.write(&buf[last_written..]); - } - if buf.last() != Some(&self.eol) { - self.write_eol(); - } - } - - pub fn context>( - &mut self, - path: P, - buf: &[u8], - start: usize, - end: usize, - line_number: Option, - byte_offset: Option, - ) { - if self.heading && self.with_filename && !self.has_printed { - self.write_file_sep(); - self.write_path(path); - self.write_path_eol(); - } else if !self.heading && self.with_filename { - self.write_path(path); - self.write_path_sep(b'-'); - } - if let Some(line_number) = line_number { - self.line_number(line_number, b'-'); - } - if let Some(byte_offset) = byte_offset { - self.write_byte_offset(byte_offset + (start as u64), b'-'); - } - if self.max_columns.map_or(false, |m| end - start > m) { - self.write(b"[Omitted long context line]"); - self.write_eol(); - return; - } - self.write(&buf[start..end]); - if buf[start..end].last() != Some(&self.eol) { - self.write_eol(); - } - } - - fn separator(&mut self, sep: &[u8]) { - self.write(sep); - } - - fn write_path_sep(&mut self, sep: u8) { - if self.null { - self.write(b"\x00"); - } else { - self.separator(&[sep]); - } - } - - fn write_path_eol(&mut self) { - if self.null { - self.write(b"\x00"); - } else { - self.write_eol(); - } - } - - #[cfg(unix)] - fn write_path>(&mut self, path: P) { - use std::os::unix::ffi::OsStrExt; - let path = path.as_ref().as_os_str().as_bytes(); - self.write_path_replace_separator(path); - } - - #[cfg(not(unix))] - fn write_path>(&mut self, path: P) { - let path = path.as_ref().to_string_lossy(); - self.write_path_replace_separator(path.as_bytes()); - } - - fn write_path_replace_separator(&mut self, path: &[u8]) { - match self.path_separator { - None => self.write_colored(path, |colors| colors.path()), - Some(sep) => { - let transformed_path: Vec<_> = path.iter().map(|&b| { - if b == b'/' || (cfg!(windows) && b == b'\\') { - sep - } else { - b - } - }).collect(); - self.write_colored(&transformed_path, |colors| colors.path()); - } - } - } - - fn line_number(&mut self, n: u64, sep: u8) { - let line_number = n.to_string(); - self.write_colored(line_number.as_bytes(), |colors| colors.line()); - self.separator(&[sep]); - } - - fn column_number(&mut self, n: u64, sep: u8) { - self.write_colored(n.to_string().as_bytes(), |colors| colors.column()); - self.separator(&[sep]); - } - - fn write_byte_offset(&mut self, o: u64, sep: u8) { - self.write_colored(o.to_string().as_bytes(), |colors| colors.column()); - self.separator(&[sep]); - } - - fn write(&mut self, buf: &[u8]) { - self.has_printed = true; - let _ = self.wtr.write_all(buf); - } - - fn write_eol(&mut self) { - let eol = self.eol; - self.write(&[eol]); - } - - fn write_colored(&mut self, buf: &[u8], get_color: F) - where F: Fn(&ColorSpecs) -> &ColorSpec - { - let _ = self.wtr.set_color(get_color(&self.colors)); - self.write(buf); - let _ = self.wtr.reset(); - } - - fn write_file_sep(&mut self) { - if let Some(ref sep) = self.file_separator { - self.has_printed = true; - let _ = self.wtr.write_all(sep); - let _ = self.wtr.write_all(b"\n"); - } - } -} - -/// An error that can occur when parsing color specifications. -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum Error { - /// This occurs when an unrecognized output type is used. - UnrecognizedOutType(String), - /// This occurs when an unrecognized spec type is used. - UnrecognizedSpecType(String), - /// This occurs when an unrecognized color name is used. - UnrecognizedColor(String, String), - /// This occurs when an unrecognized style attribute is used. - UnrecognizedStyle(String), - /// This occurs when the format of a color specification is invalid. - InvalidFormat(String), -} - -impl error::Error for Error { - fn description(&self) -> &str { - match *self { - Error::UnrecognizedOutType(_) => "unrecognized output type", - Error::UnrecognizedSpecType(_) => "unrecognized spec type", - Error::UnrecognizedColor(_, _) => "unrecognized color name", - Error::UnrecognizedStyle(_) => "unrecognized style attribute", - Error::InvalidFormat(_) => "invalid color spec", - } - } - - fn cause(&self) -> Option<&error::Error> { - None - } -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Error::UnrecognizedOutType(ref name) => { - write!(f, "Unrecognized output type '{}'. Choose from: \ - path, line, column, match.", name) - } - Error::UnrecognizedSpecType(ref name) => { - write!(f, "Unrecognized spec type '{}'. Choose from: \ - fg, bg, style, none.", name) - } - Error::UnrecognizedColor(_, ref msg) => { - write!(f, "{}", msg) - } - Error::UnrecognizedStyle(ref name) => { - write!(f, "Unrecognized style attribute '{}'. Choose from: \ - nobold, bold, nointense, intense, nounderline, \ - underline.", name) - } - Error::InvalidFormat(ref original) => { - write!( - f, - "Invalid color spec format: '{}'. Valid format \ - is '(path|line|column|match):(fg|bg|style):(value)'.", - original) - } - } - } -} - -impl From for Error { - fn from(err: ParseColorError) -> Error { - Error::UnrecognizedColor(err.invalid().to_string(), err.to_string()) - } -} - -/// A merged set of color specifications. -#[derive(Clone, Debug, Default, Eq, PartialEq)] -pub struct ColorSpecs { - path: ColorSpec, - line: ColorSpec, - column: ColorSpec, - matched: ColorSpec, -} - -/// A single color specification provided by the user. -/// -/// A `ColorSpecs` can be built by merging a sequence of `Spec`s. -/// -/// ## Example -/// -/// The only way to build a `Spec` is to parse it from a string. Once multiple -/// `Spec`s have been constructed, then can be merged into a single -/// `ColorSpecs` value. -/// -/// ```rust -/// use termcolor::{Color, ColorSpecs, Spec}; -/// -/// let spec1: Spec = "path:fg:blue".parse().unwrap(); -/// let spec2: Spec = "match:bg:green".parse().unwrap(); -/// let specs = ColorSpecs::new(&[spec1, spec2]); -/// -/// assert_eq!(specs.path().fg(), Some(Color::Blue)); -/// assert_eq!(specs.matched().bg(), Some(Color::Green)); -/// ``` -/// -/// ## Format -/// -/// The format of a `Spec` is a triple: `{type}:{attribute}:{value}`. Each -/// component is defined as follows: -/// -/// * `{type}` can be one of `path`, `line`, `column` or `match`. -/// * `{attribute}` can be one of `fg`, `bg` or `style`. `{attribute}` may also -/// be the special value `none`, in which case, `{value}` can be omitted. -/// * `{value}` is either a color name (for `fg`/`bg`) or a style instruction. -/// -/// `{type}` controls which part of the output should be styled and is -/// application dependent. -/// -/// When `{attribute}` is `none`, then this should cause any existing color -/// settings to be cleared. -/// -/// `{value}` should be a color when `{attribute}` is `fg` or `bg`, or it -/// should be a style instruction when `{attribute}` is `style`. When -/// `{attribute}` is `none`, `{value}` must be omitted. -/// -/// Valid colors are `black`, `blue`, `green`, `red`, `cyan`, `magenta`, -/// `yellow`, `white`. -/// -/// Valid style instructions are `nobold`, `bold`, `intense`, `nointense`, -/// `underline`, `nounderline`. -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct Spec { - ty: OutType, - value: SpecValue, -} - -/// The actual value given by the specification. -#[derive(Clone, Debug, Eq, PartialEq)] -enum SpecValue { - None, - Fg(Color), - Bg(Color), - Style(Style), -} - -/// The set of configurable portions of ripgrep's output. -#[derive(Clone, Debug, Eq, PartialEq)] -enum OutType { - Path, - Line, - Column, - Match, -} - -/// The specification type. -#[derive(Clone, Debug, Eq, PartialEq)] -enum SpecType { - Fg, - Bg, - Style, - None, -} - -/// The set of available styles for use in the terminal. -#[derive(Clone, Debug, Eq, PartialEq)] -enum Style { - Bold, - NoBold, - Intense, - NoIntense, - Underline, - NoUnderline -} - -impl ColorSpecs { - /// Create color specifications from a list of user supplied - /// specifications. - pub fn new(user_specs: &[Spec]) -> ColorSpecs { - let mut specs = ColorSpecs::default(); - for user_spec in user_specs { - match user_spec.ty { - OutType::Path => user_spec.merge_into(&mut specs.path), - OutType::Line => user_spec.merge_into(&mut specs.line), - OutType::Column => user_spec.merge_into(&mut specs.column), - OutType::Match => user_spec.merge_into(&mut specs.matched), - } - } - specs - } - - /// Return the color specification for coloring file paths. - fn path(&self) -> &ColorSpec { - &self.path - } - - /// Return the color specification for coloring line numbers. - fn line(&self) -> &ColorSpec { - &self.line - } - - /// Return the color specification for coloring column numbers. - fn column(&self) -> &ColorSpec { - &self.column - } - - /// Return the color specification for coloring matched text. - fn matched(&self) -> &ColorSpec { - &self.matched - } -} - -impl Spec { - /// Merge this spec into the given color specification. - fn merge_into(&self, cspec: &mut ColorSpec) { - self.value.merge_into(cspec); - } -} - -impl SpecValue { - /// Merge this spec value into the given color specification. - fn merge_into(&self, cspec: &mut ColorSpec) { - match *self { - SpecValue::None => cspec.clear(), - SpecValue::Fg(ref color) => { 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); } - } - } - } - } -} - -impl FromStr for Spec { - type Err = Error; - - fn from_str(s: &str) -> Result { - let pieces: Vec<&str> = s.split(':').collect(); - if pieces.len() <= 1 || pieces.len() > 3 { - return Err(Error::InvalidFormat(s.to_string())); - } - let otype: OutType = pieces[0].parse()?; - match pieces[1].parse()? { - SpecType::None => Ok(Spec { ty: otype, value: SpecValue::None }), - SpecType::Style => { - if pieces.len() < 3 { - return Err(Error::InvalidFormat(s.to_string())); - } - let style: Style = pieces[2].parse()?; - Ok(Spec { ty: otype, value: SpecValue::Style(style) }) - } - SpecType::Fg => { - if pieces.len() < 3 { - return Err(Error::InvalidFormat(s.to_string())); - } - let color: Color = pieces[2].parse()?; - Ok(Spec { ty: otype, value: SpecValue::Fg(color) }) - } - SpecType::Bg => { - if pieces.len() < 3 { - return Err(Error::InvalidFormat(s.to_string())); - } - let color: Color = pieces[2].parse()?; - Ok(Spec { ty: otype, value: SpecValue::Bg(color) }) - } - } - } -} - -impl FromStr for OutType { - type Err = Error; - - fn from_str(s: &str) -> Result { - match &*s.to_lowercase() { - "path" => Ok(OutType::Path), - "line" => Ok(OutType::Line), - "column" => Ok(OutType::Column), - "match" => Ok(OutType::Match), - _ => Err(Error::UnrecognizedOutType(s.to_string())), - } - } -} - -impl FromStr for SpecType { - type Err = Error; - - fn from_str(s: &str) -> Result { - match &*s.to_lowercase() { - "fg" => Ok(SpecType::Fg), - "bg" => Ok(SpecType::Bg), - "style" => Ok(SpecType::Style), - "none" => Ok(SpecType::None), - _ => Err(Error::UnrecognizedSpecType(s.to_string())), - } - } -} - -impl FromStr for Style { - type Err = Error; - - fn from_str(s: &str) -> Result { - match &*s.to_lowercase() { - "bold" => Ok(Style::Bold), - "nobold" => Ok(Style::NoBold), - "intense" => Ok(Style::Intense), - "nointense" => Ok(Style::NoIntense), - "underline" => Ok(Style::Underline), - "nounderline" => Ok(Style::NoUnderline), - _ => Err(Error::UnrecognizedStyle(s.to_string())), - } - } -} - -#[cfg(test)] -mod tests { - use termcolor::{Color, ColorSpec}; - use super::{ColorSpecs, Error, OutType, Spec, SpecValue, Style}; - - #[test] - fn merge() { - let user_specs: &[Spec] = &[ - "match:fg:blue".parse().unwrap(), - "match:none".parse().unwrap(), - "match:style:bold".parse().unwrap(), - ]; - let mut expect_matched = ColorSpec::new(); - expect_matched.set_bold(true); - assert_eq!(ColorSpecs::new(user_specs), ColorSpecs { - path: ColorSpec::default(), - line: ColorSpec::default(), - column: ColorSpec::default(), - matched: expect_matched, - }); - } - - #[test] - fn specs() { - let spec: Spec = "path:fg:blue".parse().unwrap(); - assert_eq!(spec, Spec { - ty: OutType::Path, - value: SpecValue::Fg(Color::Blue), - }); - - let spec: Spec = "path:bg:red".parse().unwrap(); - assert_eq!(spec, Spec { - ty: OutType::Path, - value: SpecValue::Bg(Color::Red), - }); - - let spec: Spec = "match:style:bold".parse().unwrap(); - assert_eq!(spec, Spec { - ty: OutType::Match, - value: SpecValue::Style(Style::Bold), - }); - - let spec: Spec = "match:style:intense".parse().unwrap(); - assert_eq!(spec, Spec { - ty: OutType::Match, - value: SpecValue::Style(Style::Intense), - }); - - let spec: Spec = "match:style:underline".parse().unwrap(); - assert_eq!(spec, Spec { - ty: OutType::Match, - value: SpecValue::Style(Style::Underline), - }); - - let spec: Spec = "line:none".parse().unwrap(); - assert_eq!(spec, Spec { - ty: OutType::Line, - value: SpecValue::None, - }); - - let spec: Spec = "column:bg:green".parse().unwrap(); - assert_eq!(spec, Spec { - ty: OutType::Column, - value: SpecValue::Bg(Color::Green), - }); - } - - #[test] - fn spec_errors() { - let err = "line:nonee".parse::().unwrap_err(); - assert_eq!(err, Error::UnrecognizedSpecType("nonee".to_string())); - - let err = "".parse::().unwrap_err(); - assert_eq!(err, Error::InvalidFormat("".to_string())); - - let err = "foo".parse::().unwrap_err(); - assert_eq!(err, Error::InvalidFormat("foo".to_string())); - - let err = "line:style:italic".parse::().unwrap_err(); - assert_eq!(err, Error::UnrecognizedStyle("italic".to_string())); - - let err = "line:fg:brown".parse::().unwrap_err(); - match err { - Error::UnrecognizedColor(name, _) => assert_eq!(name, "brown"), - err => assert!(false, "unexpected error: {:?}", err), - } - - let err = "foo:fg:brown".parse::().unwrap_err(); - assert_eq!(err, Error::UnrecognizedOutType("foo".to_string())); - } -} diff --git a/src/search_buffer.rs b/src/search_buffer.rs deleted file mode 100644 index 2777a06..0000000 --- a/src/search_buffer.rs +++ /dev/null @@ -1,424 +0,0 @@ -/*! -The `search_buffer` module is responsible for searching a single file all in a -single buffer. Typically, the source of the buffer is a memory map. This can -be useful for when memory maps are faster than streaming search. - -Note that this module doesn't quite support everything that `search_stream` -does. Notably, showing contexts. -*/ -use std::cmp; -use std::path::Path; - -use grep::Grep; -use termcolor::WriteColor; - -use printer::Printer; -use search_stream::{IterLines, Options, count_lines, is_binary}; - -pub struct BufferSearcher<'a, W: 'a> { - opts: Options, - printer: &'a mut Printer, - grep: &'a Grep, - path: &'a Path, - buf: &'a [u8], - match_line_count: u64, - match_count: Option, - line_count: Option, - byte_offset: Option, - last_line: usize, -} - -impl<'a, W: WriteColor> BufferSearcher<'a, W> { - pub fn new( - printer: &'a mut Printer, - grep: &'a Grep, - path: &'a Path, - buf: &'a [u8], - ) -> BufferSearcher<'a, W> { - BufferSearcher { - opts: Options::default(), - printer: printer, - grep: grep, - path: path, - buf: buf, - match_line_count: 0, - match_count: None, - line_count: None, - byte_offset: None, - last_line: 0, - } - } - - /// If enabled, searching will print a 0-based offset of the - /// matching line (or the actual match if -o is specified) before - /// printing the line itself. - /// - /// Disabled by default. - pub fn byte_offset(mut self, yes: bool) -> Self { - self.opts.byte_offset = yes; - self - } - - /// If enabled, searching will print a count instead of each match. - /// - /// Disabled by default. - pub fn count(mut self, yes: bool) -> Self { - self.opts.count = yes; - self - } - - /// If enabled, searching will print the count of individual matches - /// instead of each match. - /// - /// Disabled by default. - pub fn count_matches(mut self, yes: bool) -> Self { - self.opts.count_matches = yes; - self - } - - /// If enabled, searching will print the path instead of each match. - /// - /// Disabled by default. - pub fn files_with_matches(mut self, yes: bool) -> Self { - self.opts.files_with_matches = yes; - self - } - - /// If enabled, searching will print the path of files that *don't* match - /// the given pattern. - /// - /// Disabled by default. - pub fn files_without_matches(mut self, yes: bool) -> Self { - self.opts.files_without_matches = yes; - self - } - - /// Set the end-of-line byte used by this searcher. - pub fn eol(mut self, eol: u8) -> Self { - self.opts.eol = eol; - self - } - - /// If enabled, matching is inverted so that lines that *don't* match the - /// given pattern are treated as matches. - pub fn invert_match(mut self, yes: bool) -> Self { - self.opts.invert_match = yes; - self - } - - /// If enabled, compute line numbers and prefix each line of output with - /// them. - pub fn line_number(mut self, yes: bool) -> Self { - self.opts.line_number = yes; - self - } - - /// Limit the number of matches to the given count. - /// - /// The default is None, which corresponds to no limit. - pub fn max_count(mut self, count: Option) -> Self { - self.opts.max_count = count; - self - } - - /// If enabled, don't show any output and quit searching after the first - /// match is found. - pub fn quiet(mut self, yes: bool) -> Self { - self.opts.quiet = yes; - self - } - - /// If enabled, search binary files as if they were text. - pub fn text(mut self, yes: bool) -> Self { - self.opts.text = yes; - self - } - - #[inline(never)] - pub fn run(mut self) -> u64 { - let binary_upto = cmp::min(10_240, self.buf.len()); - if !self.opts.text && is_binary(&self.buf[..binary_upto], true) { - return 0; - } - - self.match_line_count = 0; - self.line_count = if self.opts.line_number { Some(0) } else { None }; - // The memory map searcher uses one contiguous block of bytes, so the - // offsets given the printer are sufficient to compute the byte offset. - self.byte_offset = if self.opts.byte_offset { Some(0) } else { None }; - self.match_count = if self.opts.count_matches { Some(0) } else { None }; - let mut last_end = 0; - for m in self.grep.iter(self.buf) { - if self.opts.invert_match { - self.print_inverted_matches(last_end, m.start()); - } else { - self.print_match(m.start(), m.end()); - } - last_end = m.end(); - if self.opts.terminate(self.match_line_count) { - break; - } - } - if self.opts.invert_match && !self.opts.terminate(self.match_line_count) { - let upto = self.buf.len(); - self.print_inverted_matches(last_end, upto); - } - if self.opts.count && self.match_line_count > 0 { - self.printer.path_count(self.path, self.match_line_count); - } else if self.opts.count_matches - && self.match_count.map_or(false, |c| c > 0) - { - self.printer.path_count(self.path, self.match_count.unwrap()); - } - if self.opts.files_with_matches && self.match_line_count > 0 { - self.printer.path(self.path); - } - if self.opts.files_without_matches && self.match_line_count == 0 { - self.printer.path(self.path); - } - self.match_line_count - } - - #[inline(always)] - fn count_individual_matches(&mut self, start: usize, end: usize) { - if let Some(ref mut count) = self.match_count { - for _ in self.grep.regex().find_iter(&self.buf[start..end]) { - *count += 1; - } - } - } - - #[inline(always)] - pub fn print_match(&mut self, start: usize, end: usize) { - self.match_line_count += 1; - self.count_individual_matches(start, end); - if self.opts.skip_matches() { - return; - } - self.count_lines(start); - self.add_line(end); - self.printer.matched( - self.grep.regex(), self.path, self.buf, - start, end, self.line_count, self.byte_offset); - } - - #[inline(always)] - fn print_inverted_matches(&mut self, start: usize, end: usize) { - debug_assert!(self.opts.invert_match); - let mut it = IterLines::new(self.opts.eol, start); - while let Some((s, e)) = it.next(&self.buf[..end]) { - if self.opts.terminate(self.match_line_count) { - return; - } - self.print_match(s, e); - } - } - - #[inline(always)] - fn count_lines(&mut self, upto: usize) { - if let Some(ref mut line_count) = self.line_count { - *line_count += count_lines( - &self.buf[self.last_line..upto], self.opts.eol); - self.last_line = upto; - } - } - - #[inline(always)] - fn add_line(&mut self, line_end: usize) { - if let Some(ref mut line_count) = self.line_count { - *line_count += 1; - self.last_line = line_end; - } - } -} - -#[cfg(test)] -mod tests { - use std::path::Path; - - use grep::GrepBuilder; - - use printer::Printer; - use termcolor; - - use super::BufferSearcher; - - const SHERLOCK: &'static str = "\ -For the Doctor Watsons of this world, as opposed to the Sherlock -Holmeses, success in the province of detective work must always -be, to a very large extent, the result of luck. Sherlock Holmes -can extract a clew from a wisp of straw or a flake of cigar ash; -but Doctor Watson has to have it taken out for him and dusted, -and exhibited clearly, with a label attached.\ -"; - - fn test_path() -> &'static Path { - &Path::new("/baz.rs") - } - - type TestSearcher<'a> = BufferSearcher<'a, termcolor::NoColor>>; - - fn search TestSearcher>( - pat: &str, - haystack: &str, - mut map: F, - ) -> (u64, String) { - let outbuf = termcolor::NoColor::new(vec![]); - let mut pp = Printer::new(outbuf).with_filename(true); - let grep = GrepBuilder::new(pat).build().unwrap(); - let count = { - let searcher = BufferSearcher::new( - &mut pp, &grep, test_path(), haystack.as_bytes()); - map(searcher).run() - }; - (count, String::from_utf8(pp.into_inner().into_inner()).unwrap()) - } - - #[test] - fn basic_search() { - let (count, out) = search("Sherlock", SHERLOCK, |s|s); - assert_eq!(2, count); - assert_eq!(out, "\ -/baz.rs:For the Doctor Watsons of this world, as opposed to the Sherlock -/baz.rs:be, to a very large extent, the result of luck. Sherlock Holmes -"); - } - - #[test] - fn binary() { - let text = "Sherlock\n\x00Holmes\n"; - let (count, out) = search("Sherlock|Holmes", text, |s|s); - assert_eq!(0, count); - assert_eq!(out, ""); - } - - - #[test] - fn binary_text() { - let text = "Sherlock\n\x00Holmes\n"; - let (count, out) = search("Sherlock|Holmes", text, |s| s.text(true)); - assert_eq!(2, count); - assert_eq!(out, "/baz.rs:Sherlock\n/baz.rs:\x00Holmes\n"); - } - - #[test] - fn line_numbers() { - let (count, out) = search( - "Sherlock", SHERLOCK, |s| s.line_number(true)); - assert_eq!(2, count); - assert_eq!(out, "\ -/baz.rs:1:For the Doctor Watsons of this world, as opposed to the Sherlock -/baz.rs:3:be, to a very large extent, the result of luck. Sherlock Holmes -"); - } - - #[test] - fn byte_offset() { - let (_, out) = search( - "Sherlock", SHERLOCK, |s| s.byte_offset(true)); - assert_eq!(out, "\ -/baz.rs:0:For the Doctor Watsons of this world, as opposed to the Sherlock -/baz.rs:129:be, to a very large extent, the result of luck. Sherlock Holmes -"); - } - - #[test] - fn byte_offset_inverted() { - let (_, out) = search("Sherlock", SHERLOCK, |s| { - s.invert_match(true).byte_offset(true) - }); - assert_eq!(out, "\ -/baz.rs:65:Holmeses, success in the province of detective work must always -/baz.rs:193:can extract a clew from a wisp of straw or a flake of cigar ash; -/baz.rs:258:but Doctor Watson has to have it taken out for him and dusted, -/baz.rs:321:and exhibited clearly, with a label attached. -"); - } - - #[test] - fn count() { - let (count, out) = search( - "Sherlock", SHERLOCK, |s| s.count(true)); - assert_eq!(2, count); - assert_eq!(out, "/baz.rs:2\n"); - } - - #[test] - fn count_matches() { - let (_, out) = search( - "the", SHERLOCK, |s| s.count_matches(true)); - assert_eq!(out, "/baz.rs:4\n"); - } - - #[test] - fn files_with_matches() { - let (count, out) = search( - "Sherlock", SHERLOCK, |s| s.files_with_matches(true)); - assert_eq!(1, count); - assert_eq!(out, "/baz.rs\n"); - } - - #[test] - fn files_without_matches() { - let (count, out) = search( - "zzzz", SHERLOCK, |s| s.files_without_matches(true)); - assert_eq!(0, count); - assert_eq!(out, "/baz.rs\n"); - } - - #[test] - fn max_count() { - let (count, out) = search( - "Sherlock", SHERLOCK, |s| s.max_count(Some(1))); - assert_eq!(1, count); - assert_eq!(out, "\ -/baz.rs:For the Doctor Watsons of this world, as opposed to the Sherlock -"); - } - - #[test] - fn invert_match_max_count() { - let (count, out) = search( - "zzzz", SHERLOCK, |s| s.invert_match(true).max_count(Some(1))); - assert_eq!(1, count); - assert_eq!(out, "\ -/baz.rs:For the Doctor Watsons of this world, as opposed to the Sherlock -"); - } - - #[test] - fn invert_match() { - let (count, out) = search( - "Sherlock", SHERLOCK, |s| s.invert_match(true)); - assert_eq!(4, count); - assert_eq!(out, "\ -/baz.rs:Holmeses, success in the province of detective work must always -/baz.rs:can extract a clew from a wisp of straw or a flake of cigar ash; -/baz.rs:but Doctor Watson has to have it taken out for him and dusted, -/baz.rs:and exhibited clearly, with a label attached. -"); - } - - #[test] - fn invert_match_line_numbers() { - let (count, out) = search("Sherlock", SHERLOCK, |s| { - s.invert_match(true).line_number(true) - }); - assert_eq!(4, count); - assert_eq!(out, "\ -/baz.rs:2:Holmeses, success in the province of detective work must always -/baz.rs:4:can extract a clew from a wisp of straw or a flake of cigar ash; -/baz.rs:5:but Doctor Watson has to have it taken out for him and dusted, -/baz.rs:6:and exhibited clearly, with a label attached. -"); - } - - #[test] - fn invert_match_count() { - let (count, out) = search("Sherlock", SHERLOCK, |s| { - s.invert_match(true).count(true) - }); - assert_eq!(4, count); - assert_eq!(out, "/baz.rs:4\n"); - } -} diff --git a/src/search_stream.rs b/src/search_stream.rs deleted file mode 100644 index b218dd1..0000000 --- a/src/search_stream.rs +++ /dev/null @@ -1,1466 +0,0 @@ -/*! -The `search_stream` module is responsible for searching a single file and -printing matches. In particular, it searches the file in a streaming fashion -using `read` calls and a (roughly) fixed size buffer. -*/ - -use std::cmp; -use std::error::Error as StdError; -use std::fmt; -use std::io; -use std::path::{Path, PathBuf}; - -use bytecount; -use grep::{Grep, Match}; -use memchr::{memchr, memrchr}; -use termcolor::WriteColor; - -use printer::Printer; - -/// The default read size (capacity of input buffer). -const READ_SIZE: usize = 8 * (1<<10); - -/// Error describes errors that can occur while searching. -#[derive(Debug)] -pub enum Error { - /// A standard I/O error attached to a particular file path. - Io { - err: io::Error, - path: PathBuf, - } -} - -impl Error { - fn from_io>(err: io::Error, path: P) -> Error { - Error::Io { err: err, path: path.as_ref().to_path_buf() } - } -} - -impl StdError for Error { - fn description(&self) -> &str { - match *self { - Error::Io { ref err, .. } => err.description(), - } - } - - fn cause(&self) -> Option<&StdError> { - match *self { - Error::Io { ref err, .. } => Some(err), - } - } -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Error::Io { ref err, ref path } => { - write!(f, "{}: {}", path.display(), err) - } - } - } -} - -pub struct Searcher<'a, R, W: 'a> { - opts: Options, - inp: &'a mut InputBuffer, - printer: &'a mut Printer, - grep: &'a Grep, - path: &'a Path, - haystack: R, - match_line_count: u64, - match_count: Option, - line_count: Option, - byte_offset: Option, - last_match: Match, - last_printed: usize, - last_line: usize, - after_context_remaining: usize, -} - -/// Options for configuring search. -#[derive(Clone)] -pub struct Options { - pub after_context: usize, - pub before_context: usize, - pub byte_offset: bool, - pub count: bool, - pub count_matches: bool, - pub files_with_matches: bool, - pub files_without_matches: bool, - pub eol: u8, - pub invert_match: bool, - pub line_number: bool, - pub max_count: Option, - pub quiet: bool, - pub text: bool, -} - -impl Default for Options { - fn default() -> Options { - Options { - after_context: 0, - before_context: 0, - byte_offset: false, - count: false, - count_matches: false, - files_with_matches: false, - files_without_matches: false, - eol: b'\n', - invert_match: false, - line_number: false, - max_count: None, - quiet: false, - text: false, - } - } - -} - -impl Options { - /// Several options (--quiet, --count, --count-matches, --files-with-matches, - /// --files-without-match) imply that we shouldn't ever display matches. - pub fn skip_matches(&self) -> bool { - self.count || self.files_with_matches || self.files_without_matches - || self.quiet || self.count_matches - } - - /// Some options (--quiet, --files-with-matches, --files-without-match) - /// imply that we can stop searching after the first match. - pub fn stop_after_first_match(&self) -> bool { - self.files_with_matches || self.files_without_matches || self.quiet - } - - /// Returns true if the search should terminate based on the match line count. - pub fn terminate(&self, match_line_count: u64) -> bool { - if match_line_count > 0 && self.stop_after_first_match() { - return true; - } - if self.max_count.map_or(false, |max| match_line_count >= max) { - return true; - } - false - } -} - -impl<'a, R: io::Read, W: WriteColor> Searcher<'a, R, W> { - /// Create a new searcher. - /// - /// `inp` is a reusable input buffer that is used as scratch space by this - /// searcher. - /// - /// `printer` is used to output all results of searching. - /// - /// `grep` is the actual matcher. - /// - /// `path` is the file path being searched. - /// - /// `haystack` is a reader of text to search. - pub fn new( - inp: &'a mut InputBuffer, - printer: &'a mut Printer, - grep: &'a Grep, - path: &'a Path, - haystack: R, - ) -> Searcher<'a, R, W> { - Searcher { - opts: Options::default(), - inp: inp, - printer: printer, - grep: grep, - path: path, - haystack: haystack, - match_line_count: 0, - match_count: None, - line_count: None, - byte_offset: None, - last_match: Match::default(), - last_printed: 0, - last_line: 0, - after_context_remaining: 0, - } - } - - /// The number of contextual lines to show after each match. The default - /// is zero. - pub fn after_context(mut self, count: usize) -> Self { - self.opts.after_context = count; - self - } - - /// The number of contextual lines to show before each match. The default - /// is zero. - pub fn before_context(mut self, count: usize) -> Self { - self.opts.before_context = count; - self - } - - /// If enabled, searching will print a 0-based offset of the - /// matching line (or the actual match if -o is specified) before - /// printing the line itself. - /// - /// Disabled by default. - pub fn byte_offset(mut self, yes: bool) -> Self { - self.opts.byte_offset = yes; - self - } - - /// If enabled, searching will print a count instead of each match. - /// - /// Disabled by default. - pub fn count(mut self, yes: bool) -> Self { - self.opts.count = yes; - self - } - - /// If enabled, searching will print the count of individual matches - /// instead of each match. - /// - /// Disabled by default. - pub fn count_matches(mut self, yes: bool) -> Self { - self.opts.count_matches = yes; - self - } - - /// If enabled, searching will print the path instead of each match. - /// - /// Disabled by default. - pub fn files_with_matches(mut self, yes: bool) -> Self { - self.opts.files_with_matches = yes; - self - } - - /// If enabled, searching will print the path of files without any matches. - /// - /// Disabled by default. - pub fn files_without_matches(mut self, yes: bool) -> Self { - self.opts.files_without_matches = yes; - self - } - - /// Set the end-of-line byte used by this searcher. - pub fn eol(mut self, eol: u8) -> Self { - self.opts.eol = eol; - self - } - - /// If enabled, matching is inverted so that lines that *don't* match the - /// given pattern are treated as matches. - pub fn invert_match(mut self, yes: bool) -> Self { - self.opts.invert_match = yes; - self - } - - /// If enabled, compute line numbers and prefix each line of output with - /// them. - pub fn line_number(mut self, yes: bool) -> Self { - self.opts.line_number = yes; - self - } - - /// Limit the number of matches to the given count. - /// - /// The default is None, which corresponds to no limit. - pub fn max_count(mut self, count: Option) -> Self { - self.opts.max_count = count; - self - } - - /// If enabled, don't show any output and quit searching after the first - /// match is found. - pub fn quiet(mut self, yes: bool) -> Self { - self.opts.quiet = yes; - self - } - - /// If enabled, search binary files as if they were text. - pub fn text(mut self, yes: bool) -> Self { - self.opts.text = yes; - self.inp.text(yes); - self - } - - /// Execute the search. Results are written to the printer and the total - /// number of matches is returned. - #[inline(never)] - pub fn run(mut self) -> Result { - self.inp.reset(); - self.match_line_count = 0; - self.line_count = if self.opts.line_number { Some(0) } else { None }; - self.byte_offset = if self.opts.byte_offset { Some(0) } else { None }; - self.match_count = if self.opts.count_matches { Some(0) } else { None }; - self.last_match = Match::default(); - self.after_context_remaining = 0; - while !self.terminate() { - let upto = self.inp.lastnl; - self.print_after_context(upto); - if !self.fill()? { - break; - } - while !self.terminate() && self.inp.pos < self.inp.lastnl { - let matched = self.grep.read_match( - &mut self.last_match, - &self.inp.buf[..self.inp.lastnl], - self.inp.pos); - if self.opts.invert_match { - let upto = - if matched { - self.last_match.start() - } else { - self.inp.lastnl - }; - if upto > self.inp.pos { - let upto_context = self.inp.pos; - self.print_after_context(upto_context); - self.print_before_context(upto_context); - self.print_inverted_matches(upto); - } - } else if matched { - let start = self.last_match.start(); - let end = self.last_match.end(); - self.print_after_context(start); - self.print_before_context(start); - self.print_match(start, end); - } - if matched { - self.inp.pos = self.last_match.end(); - } else { - self.inp.pos = self.inp.lastnl; - } - } - } - if self.after_context_remaining > 0 { - if self.last_printed == self.inp.lastnl { - self.fill()?; - } - let upto = self.inp.lastnl; - if upto > 0 { - self.print_after_context(upto); - } - } - if self.match_line_count > 0 { - if self.opts.count { - self.printer.path_count(self.path, self.match_line_count); - } else if self.opts.count_matches { - self.printer.path_count(self.path, self.match_count.unwrap()); - } else if self.opts.files_with_matches { - self.printer.path(self.path); - } - } else if self.opts.files_without_matches { - self.printer.path(self.path); - } - Ok(self.match_line_count) - } - - #[inline(always)] - fn terminate(&self) -> bool { - self.opts.terminate(self.match_line_count) - } - - #[inline(always)] - fn fill(&mut self) -> Result { - let keep = - if self.opts.before_context > 0 || self.opts.after_context > 0 { - let lines = 1 + cmp::max( - self.opts.before_context, self.opts.after_context); - start_of_previous_lines( - self.opts.eol, - &self.inp.buf, - self.inp.lastnl.saturating_sub(1), - lines) - } else { - self.inp.lastnl - }; - if keep < self.last_printed { - self.last_printed -= keep; - } else { - self.last_printed = 0; - } - if keep <= self.last_line { - self.last_line -= keep; - } else { - self.count_lines(keep); - self.last_line = 0; - } - self.count_byte_offset(keep); - let ok = self.inp.fill(&mut self.haystack, keep).map_err(|err| { - Error::from_io(err, &self.path) - })?; - Ok(ok) - } - - #[inline(always)] - fn print_inverted_matches(&mut self, upto: usize) { - debug_assert!(self.opts.invert_match); - let mut it = IterLines::new(self.opts.eol, self.inp.pos); - while let Some((start, end)) = it.next(&self.inp.buf[..upto]) { - if self.terminate() { - return; - } - self.print_match(start, end); - self.inp.pos = end; - } - } - - #[inline(always)] - fn print_before_context(&mut self, upto: usize) { - if self.opts.skip_matches() || self.opts.before_context == 0 { - return; - } - let start = self.last_printed; - let end = upto; - if start >= end { - return; - } - let before_context_start = - start + start_of_previous_lines( - self.opts.eol, - &self.inp.buf[start..], - end - start - 1, - self.opts.before_context); - let mut it = IterLines::new(self.opts.eol, before_context_start); - while let Some((s, e)) = it.next(&self.inp.buf[..end]) { - self.print_separator(s); - self.print_context(s, e); - } - } - - #[inline(always)] - fn print_after_context(&mut self, upto: usize) { - if self.opts.skip_matches() || self.after_context_remaining == 0 { - return; - } - let start = self.last_printed; - let end = upto; - let mut it = IterLines::new(self.opts.eol, start); - while let Some((s, e)) = it.next(&self.inp.buf[..end]) { - self.print_context(s, e); - self.after_context_remaining -= 1; - if self.after_context_remaining == 0 { - break; - } - } - } - - #[inline(always)] - fn print_match(&mut self, start: usize, end: usize) { - self.match_line_count += 1; - self.count_individual_matches(start, end); - if self.opts.skip_matches() { - return; - } - self.print_separator(start); - self.count_lines(start); - self.add_line(end); - self.printer.matched( - self.grep.regex(), self.path, - &self.inp.buf, start, end, self.line_count, self.byte_offset); - self.last_printed = end; - self.after_context_remaining = self.opts.after_context; - } - - #[inline(always)] - fn print_context(&mut self, start: usize, end: usize) { - self.count_lines(start); - self.add_line(end); - self.printer.context( - &self.path, &self.inp.buf, start, end, - self.line_count, self.byte_offset); - self.last_printed = end; - } - - #[inline(always)] - fn print_separator(&mut self, before: usize) { - if self.opts.before_context == 0 && self.opts.after_context == 0 { - return; - } - if !self.printer.has_printed() { - return; - } - if (self.last_printed == 0 && before > 0) - || self.last_printed < before { - self.printer.context_separate(); - } - } - - #[inline(always)] - fn count_byte_offset(&mut self, buf_last_end: usize) { - if let Some(ref mut byte_offset) = self.byte_offset { - *byte_offset += buf_last_end as u64; - } - } - - #[inline(always)] - fn count_individual_matches(&mut self, start: usize, end: usize) { - if let Some(ref mut count) = self.match_count { - for _ in self.grep.regex().find_iter(&self.inp.buf[start..end]) { - *count += 1; - } - } - } - - #[inline(always)] - fn count_lines(&mut self, upto: usize) { - if let Some(ref mut line_count) = self.line_count { - *line_count += count_lines( - &self.inp.buf[self.last_line..upto], self.opts.eol); - self.last_line = upto; - } - } - - #[inline(always)] - fn add_line(&mut self, line_end: usize) { - if let Some(ref mut line_count) = self.line_count { - *line_count += 1; - self.last_line = line_end; - } - } -} - -/// `InputBuffer` encapsulates the logic of maintaining a ~fixed sized buffer -/// on which to search. There are three key pieces of complexity: -/// -/// 1. We must be able to handle lines that are longer than the size of the -/// buffer. For this reason, the buffer is allowed to expand (and is -/// therefore not technically fixed). Note that once a buffer expands, it -/// will never contract. -/// 2. The contents of the buffer may end with a partial line, so we must keep -/// track of where the last complete line ends. Namely, the partial line -/// is only completed on subsequent reads *after* searching up through -/// the last complete line is done. -/// 3. When printing the context of a match, the last N lines of the buffer -/// may need to be rolled over into the next buffer. For example, a match -/// may occur at the beginning of a buffer, in which case, lines at the end -/// of the previous contents of the buffer need to be printed. -/// -/// An `InputBuffer` is designed to be reused and isn't tied to any particular -/// reader. -pub struct InputBuffer { - /// The number of bytes to attempt to read at a time. Once set, this is - /// never changed. - read_size: usize, - /// The end-of-line terminator used in this buffer. - eol: u8, - /// A scratch buffer. - tmp: Vec, - /// A buffer to read bytes into. All searches are executed directly against - /// this buffer and pos/lastnl/end point into it. - buf: Vec, - /// The current position in buf. The current position represents where the - /// next search should start. - pos: usize, - /// The position immediately following the last line terminator in buf. - /// This may be equal to end. - /// - /// Searching should never cross this boundary. In particular, the contents - /// of the buffer following this position may correspond to *partial* line. - /// All contents before this position are complete lines. - lastnl: usize, - /// The end position of the buffer. Data after this position is not - /// specified. - end: usize, - /// Set to true if and only if no reads have occurred yet. - first: bool, - /// Set to true if all binary data should be treated as if it were text. - text: bool, -} - -impl InputBuffer { - /// Create a new buffer with a default capacity. - pub fn new() -> InputBuffer { - InputBuffer::with_capacity(READ_SIZE) - } - - /// Create a new buffer with the capacity given. - /// - /// The capacity determines the size of each read from the underlying - /// reader. - /// - /// `cap` must be a minimum of `1`. - pub fn with_capacity(mut cap: usize) -> InputBuffer { - if cap == 0 { - cap = 1; - } - InputBuffer { - read_size: cap, - eol: b'\n', - buf: vec![0; cap], - tmp: vec![], - pos: 0, - lastnl: 0, - end: 0, - first: true, - text: false, - } - } - - /// Set the end-of-line terminator used by this input buffer. - pub fn eol(&mut self, eol: u8) -> &mut Self { - self.eol = eol; - self - } - - /// If enabled, search binary files as if they were text. - /// - /// Note that this may cause the buffer to load the entire contents of a - /// file into memory. - pub fn text(&mut self, yes: bool) -> &mut Self { - self.text = yes; - self - } - - /// Resets this buffer so that it may be reused with a new reader. - fn reset(&mut self) { - self.pos = 0; - self.lastnl = 0; - self.end = 0; - self.first = true; - } - - /// Fill the contents of this buffer with the reader given. The reader - /// given should be the same in every call to fill unless reset has been - /// called. - /// - /// The bytes in buf[keep_from..end] are rolled over into the beginning - /// of the buffer. - fn fill( - &mut self, - rdr: &mut R, - keep_from: usize, - ) -> Result { - // Rollover bytes from buf[keep_from..end] and update our various - // pointers. N.B. This could be done with the ptr::copy, but I haven't - // been able to produce a benchmark that notices a difference in - // performance. (Invariably, ptr::copy is seems clearer IMO, but it is - // not safe.) - self.tmp.clear(); - self.tmp.extend_from_slice(&self.buf[keep_from..self.end]); - self.buf[0..self.tmp.len()].copy_from_slice(&self.tmp); - self.pos = self.lastnl - keep_from; - self.lastnl = 0; - self.end = self.tmp.len(); - while self.lastnl == 0 { - // If our buffer isn't big enough to hold the contents of a full - // read, expand it. - if self.buf.len() - self.end < self.read_size { - let min_len = self.read_size + self.buf.len() - self.end; - let new_len = cmp::max(min_len, self.buf.len() * 2); - self.buf.resize(new_len, 0); - } - let n = rdr.read( - &mut self.buf[self.end..self.end + self.read_size])?; - if !self.text { - if is_binary(&self.buf[self.end..self.end + n], self.first) { - return Ok(false); - } - } - self.first = false; - // We assume that reading 0 bytes means we've hit EOF. - if n == 0 { - // If we've searched everything up to the end of the buffer, - // then there's nothing left to do. - if self.end - self.pos == 0 { - return Ok(false); - } - // Even if we hit EOF, we might still have to search the - // last line if it didn't contain a trailing terminator. - self.lastnl = self.end; - break; - } - self.lastnl = - memrchr(self.eol, &self.buf[self.end..self.end + n]) - .map(|i| self.end + i + 1) - .unwrap_or(0); - self.end += n; - } - Ok(true) - } -} - -/// Returns true if and only if the given buffer is determined to be "binary" -/// or otherwise not contain text data that is usefully searchable. -/// -/// Note that this may return both false positives and false negatives. -#[inline(always)] -pub fn is_binary(buf: &[u8], first: bool) -> bool { - if first && buf.len() >= 4 && &buf[0..4] == b"%PDF" { - return true; - } - memchr(b'\x00', buf).is_some() -} - -/// Count the number of lines in the given buffer. -#[inline(never)] -pub fn count_lines(buf: &[u8], eol: u8) -> u64 { - bytecount::count(buf, eol) as u64 -} - -/// Replaces a with b in buf. -#[allow(dead_code)] -fn replace_buf(buf: &mut [u8], a: u8, b: u8) { - if a == b { - return; - } - let mut pos = 0; - while let Some(i) = memchr(a, &buf[pos..]).map(|i| pos + i) { - buf[i] = b; - pos = i + 1; - while buf.get(pos) == Some(&a) { - buf[pos] = b; - pos += 1; - } - } -} - -/// An "iterator" over lines in a particular buffer. -/// -/// Idiomatic Rust would borrow the buffer and use it as internal state to -/// advance over the positions of each line. We neglect that approach to avoid -/// the borrow in the search code. (Because the borrow prevents composition -/// through other mutable methods.) -pub struct IterLines { - eol: u8, - pos: usize, -} - -impl IterLines { - /// Creates a new iterator over lines starting at the position given. - /// - /// The buffer is passed to the `next` method. - #[inline(always)] - pub fn new(eol: u8, start: usize) -> IterLines { - IterLines { - eol: eol, - pos: start, - } - } - - /// Return the start and end position of the next line in the buffer. The - /// buffer given should be the same on every call. - /// - /// The range returned includes the new line. - #[inline(always)] - pub fn next(&mut self, buf: &[u8]) -> Option<(usize, usize)> { - match memchr(self.eol, &buf[self.pos..]) { - None => { - if self.pos < buf.len() { - let start = self.pos; - self.pos = buf.len(); - Some((start, buf.len())) - } else { - None - } - } - Some(end) => { - let start = self.pos; - let end = self.pos + end + 1; - self.pos = end; - Some((start, end)) - } - } - } -} - -/// Returns the starting index of the Nth line preceding `end`. -/// -/// If `buf` is empty, then `0` is returned. If `count` is `0`, then `end` is -/// returned. -/// -/// If `end` points at a new line in `buf`, then searching starts as if `end` -/// pointed immediately before the new line. -/// -/// The position returned corresponds to the first byte in the given line. -#[inline(always)] -fn start_of_previous_lines( - eol: u8, - buf: &[u8], - mut end: usize, - mut count: usize, -) -> usize { - // TODO(burntsushi): This function needs to be badly simplified. The case - // analysis is impossible to follow. - if buf[..end].is_empty() { - return 0; - } - if count == 0 { - return end; - } - if end == buf.len() { - end -= 1; - } - if buf[end] == eol { - if end == 0 { - return end + 1; - } - end -= 1; - } - while count > 0 { - if buf[end] == eol { - count -= 1; - if count == 0 { - return end + 1; - } - if end == 0 { - return end; - } - end -= 1; - continue; - } - match memrchr(eol, &buf[..end]) { - None => { - return 0; - } - Some(i) => { - count -= 1; - end = i; - if end == 0 { - if buf[end] == eol && count == 0 { - end += 1; - } - return end; - } - end -= 1; - } - } - } - end + 2 -} - -#[cfg(test)] -mod tests { - use std::io; - use std::path::Path; - - use grep::GrepBuilder; - use printer::Printer; - use termcolor; - - use super::{InputBuffer, Searcher, start_of_previous_lines}; - - const SHERLOCK: &'static str = "\ -For the Doctor Watsons of this world, as opposed to the Sherlock -Holmeses, success in the province of detective work must always -be, to a very large extent, the result of luck. Sherlock Holmes -can extract a clew from a wisp of straw or a flake of cigar ash; -but Doctor Watson has to have it taken out for him and dusted, -and exhibited clearly, with a label attached.\ -"; - - const CODE: &'static str = "\ -extern crate snap; - -use std::io; - -fn main() { - let stdin = io::stdin(); - let stdout = io::stdout(); - - // Wrap the stdin reader in a Snappy reader. - let mut rdr = snap::Reader::new(stdin.lock()); - let mut wtr = stdout.lock(); - io::copy(&mut rdr, &mut wtr).expect(\"I/O operation failed\"); -} -"; - - fn hay(s: &str) -> io::Cursor> { - io::Cursor::new(s.to_string().into_bytes()) - } - - fn test_path() -> &'static Path { - &Path::new("/baz.rs") - } - - type TestSearcher<'a> = Searcher< - 'a, - io::Cursor>, - termcolor::NoColor>, - >; - - fn search_smallcap TestSearcher>( - pat: &str, - haystack: &str, - mut map: F, - ) -> (u64, String) { - let mut inp = InputBuffer::with_capacity(1); - let outbuf = termcolor::NoColor::new(vec![]); - let mut pp = Printer::new(outbuf).with_filename(true); - let grep = GrepBuilder::new(pat).build().unwrap(); - let count = { - let searcher = Searcher::new( - &mut inp, &mut pp, &grep, test_path(), hay(haystack)); - map(searcher).run().unwrap() - }; - (count, String::from_utf8(pp.into_inner().into_inner()).unwrap()) - } - - fn search TestSearcher>( - pat: &str, - haystack: &str, - mut map: F, - ) -> (u64, String) { - let mut inp = InputBuffer::with_capacity(4096); - let outbuf = termcolor::NoColor::new(vec![]); - let mut pp = Printer::new(outbuf).with_filename(true); - let grep = GrepBuilder::new(pat).build().unwrap(); - let count = { - let searcher = Searcher::new( - &mut inp, &mut pp, &grep, test_path(), hay(haystack)); - map(searcher).run().unwrap() - }; - (count, String::from_utf8(pp.into_inner().into_inner()).unwrap()) - } - - #[test] - fn previous_lines() { - let eol = b'\n'; - let text = SHERLOCK.as_bytes(); - assert_eq!(366, text.len()); - - assert_eq!(0, start_of_previous_lines(eol, text, 366, 100)); - assert_eq!(366, start_of_previous_lines(eol, text, 366, 0)); - - assert_eq!(321, start_of_previous_lines(eol, text, 366, 1)); - assert_eq!(321, start_of_previous_lines(eol, text, 365, 1)); - assert_eq!(321, start_of_previous_lines(eol, text, 364, 1)); - assert_eq!(321, start_of_previous_lines(eol, text, 322, 1)); - assert_eq!(321, start_of_previous_lines(eol, text, 321, 1)); - assert_eq!(258, start_of_previous_lines(eol, text, 320, 1)); - - assert_eq!(258, start_of_previous_lines(eol, text, 366, 2)); - assert_eq!(258, start_of_previous_lines(eol, text, 365, 2)); - assert_eq!(258, start_of_previous_lines(eol, text, 364, 2)); - assert_eq!(258, start_of_previous_lines(eol, text, 322, 2)); - assert_eq!(258, start_of_previous_lines(eol, text, 321, 2)); - assert_eq!(193, start_of_previous_lines(eol, text, 320, 2)); - - assert_eq!(65, start_of_previous_lines(eol, text, 66, 1)); - assert_eq!(0, start_of_previous_lines(eol, text, 66, 2)); - assert_eq!(64, start_of_previous_lines(eol, text, 64, 0)); - assert_eq!(0, start_of_previous_lines(eol, text, 64, 1)); - assert_eq!(0, start_of_previous_lines(eol, text, 64, 2)); - - assert_eq!(0, start_of_previous_lines(eol, text, 0, 2)); - assert_eq!(0, start_of_previous_lines(eol, text, 0, 1)); - } - - #[test] - fn previous_lines_short() { - let eol = b'\n'; - let text = &b"a\nb\nc\nd\ne\nf\n"[..]; - assert_eq!(12, text.len()); - - assert_eq!(10, start_of_previous_lines(eol, text, 12, 1)); - assert_eq!(8, start_of_previous_lines(eol, text, 12, 2)); - assert_eq!(6, start_of_previous_lines(eol, text, 12, 3)); - assert_eq!(4, start_of_previous_lines(eol, text, 12, 4)); - assert_eq!(2, start_of_previous_lines(eol, text, 12, 5)); - assert_eq!(0, start_of_previous_lines(eol, text, 12, 6)); - assert_eq!(0, start_of_previous_lines(eol, text, 12, 7)); - assert_eq!(10, start_of_previous_lines(eol, text, 11, 1)); - assert_eq!(8, start_of_previous_lines(eol, text, 11, 2)); - assert_eq!(6, start_of_previous_lines(eol, text, 11, 3)); - assert_eq!(4, start_of_previous_lines(eol, text, 11, 4)); - assert_eq!(2, start_of_previous_lines(eol, text, 11, 5)); - assert_eq!(0, start_of_previous_lines(eol, text, 11, 6)); - assert_eq!(0, start_of_previous_lines(eol, text, 11, 7)); - assert_eq!(10, start_of_previous_lines(eol, text, 10, 1)); - assert_eq!(8, start_of_previous_lines(eol, text, 10, 2)); - assert_eq!(6, start_of_previous_lines(eol, text, 10, 3)); - assert_eq!(4, start_of_previous_lines(eol, text, 10, 4)); - assert_eq!(2, start_of_previous_lines(eol, text, 10, 5)); - assert_eq!(0, start_of_previous_lines(eol, text, 10, 6)); - assert_eq!(0, start_of_previous_lines(eol, text, 10, 7)); - - assert_eq!(8, start_of_previous_lines(eol, text, 9, 1)); - assert_eq!(8, start_of_previous_lines(eol, text, 8, 1)); - - assert_eq!(6, start_of_previous_lines(eol, text, 7, 1)); - assert_eq!(6, start_of_previous_lines(eol, text, 6, 1)); - - assert_eq!(4, start_of_previous_lines(eol, text, 5, 1)); - assert_eq!(4, start_of_previous_lines(eol, text, 4, 1)); - - assert_eq!(2, start_of_previous_lines(eol, text, 3, 1)); - assert_eq!(2, start_of_previous_lines(eol, text, 2, 1)); - - assert_eq!(0, start_of_previous_lines(eol, text, 1, 1)); - assert_eq!(0, start_of_previous_lines(eol, text, 0, 1)); - } - - #[test] - fn previous_lines_empty() { - let eol = b'\n'; - let text = &b"\n\n\nd\ne\nf\n"[..]; - assert_eq!(9, text.len()); - - assert_eq!(7, start_of_previous_lines(eol, text, 9, 1)); - assert_eq!(5, start_of_previous_lines(eol, text, 9, 2)); - assert_eq!(3, start_of_previous_lines(eol, text, 9, 3)); - assert_eq!(2, start_of_previous_lines(eol, text, 9, 4)); - assert_eq!(1, start_of_previous_lines(eol, text, 9, 5)); - assert_eq!(0, start_of_previous_lines(eol, text, 9, 6)); - assert_eq!(0, start_of_previous_lines(eol, text, 9, 7)); - - let text = &b"a\n\n\nd\ne\nf\n"[..]; - assert_eq!(10, text.len()); - - assert_eq!(8, start_of_previous_lines(eol, text, 10, 1)); - assert_eq!(6, start_of_previous_lines(eol, text, 10, 2)); - assert_eq!(4, start_of_previous_lines(eol, text, 10, 3)); - assert_eq!(3, start_of_previous_lines(eol, text, 10, 4)); - assert_eq!(2, start_of_previous_lines(eol, text, 10, 5)); - assert_eq!(0, start_of_previous_lines(eol, text, 10, 6)); - assert_eq!(0, start_of_previous_lines(eol, text, 10, 7)); - } - - #[test] - fn basic_search1() { - let (count, out) = search_smallcap("Sherlock", SHERLOCK, |s|s); - assert_eq!(2, count); - assert_eq!(out, "\ -/baz.rs:For the Doctor Watsons of this world, as opposed to the Sherlock -/baz.rs:be, to a very large extent, the result of luck. Sherlock Holmes -"); - } - - #[test] - fn binary() { - let text = "Sherlock\n\x00Holmes\n"; - let (count, out) = search("Sherlock|Holmes", text, |s|s); - assert_eq!(0, count); - assert_eq!(out, ""); - } - - #[test] - fn binary_text() { - let text = "Sherlock\n\x00Holmes\n"; - let (count, out) = search("Sherlock|Holmes", text, |s| s.text(true)); - assert_eq!(2, count); - assert_eq!(out, "/baz.rs:Sherlock\n/baz.rs:\x00Holmes\n"); - } - - #[test] - fn line_numbers() { - let (count, out) = search_smallcap( - "Sherlock", SHERLOCK, |s| s.line_number(true)); - assert_eq!(2, count); - assert_eq!(out, "\ -/baz.rs:1:For the Doctor Watsons of this world, as opposed to the Sherlock -/baz.rs:3:be, to a very large extent, the result of luck. Sherlock Holmes -"); - } - - #[test] - fn count() { - let (count, out) = search_smallcap( - "Sherlock", SHERLOCK, |s| s.count(true)); - assert_eq!(2, count); - assert_eq!(out, "/baz.rs:2\n"); - } - - #[test] - fn byte_offset() { - let (_, out) = search_smallcap( - "Sherlock", SHERLOCK, |s| s.byte_offset(true)); - assert_eq!(out, "\ -/baz.rs:0:For the Doctor Watsons of this world, as opposed to the Sherlock -/baz.rs:129:be, to a very large extent, the result of luck. Sherlock Holmes -"); - } - - #[test] - fn byte_offset_with_before_context() { - let (_, out) = search_smallcap("dusted", SHERLOCK, |s| { - s.line_number(true).byte_offset(true).before_context(2) - }); - assert_eq!(out, "\ -/baz.rs-3-129-be, to a very large extent, the result of luck. Sherlock Holmes -/baz.rs-4-193-can extract a clew from a wisp of straw or a flake of cigar ash; -/baz.rs:5:258:but Doctor Watson has to have it taken out for him and dusted, -"); - } - - #[test] - fn byte_offset_inverted() { - let (_, out) = search_smallcap("Sherlock", SHERLOCK, |s| { - s.invert_match(true).byte_offset(true) - }); - assert_eq!(out, "\ -/baz.rs:65:Holmeses, success in the province of detective work must always -/baz.rs:193:can extract a clew from a wisp of straw or a flake of cigar ash; -/baz.rs:258:but Doctor Watson has to have it taken out for him and dusted, -/baz.rs:321:and exhibited clearly, with a label attached. -"); - } - - #[test] - fn count_matches() { - let (_, out) = search_smallcap( - "the", SHERLOCK, |s| s.count_matches(true)); - assert_eq!(out, "/baz.rs:4\n"); - } - - #[test] - fn files_with_matches() { - let (count, out) = search_smallcap( - "Sherlock", SHERLOCK, |s| s.files_with_matches(true)); - assert_eq!(1, count); - assert_eq!(out, "/baz.rs\n"); - } - - #[test] - fn files_without_matches() { - let (count, out) = search_smallcap( - "zzzz", SHERLOCK, |s| s.files_without_matches(true)); - assert_eq!(0, count); - assert_eq!(out, "/baz.rs\n"); - } - - #[test] - fn max_count() { - let (count, out) = search_smallcap( - "Sherlock", SHERLOCK, |s| s.max_count(Some(1))); - assert_eq!(1, count); - assert_eq!(out, "\ -/baz.rs:For the Doctor Watsons of this world, as opposed to the Sherlock -"); - } - - #[test] - fn invert_match_max_count() { - let (count, out) = search( - "zzzz", SHERLOCK, |s| s.invert_match(true).max_count(Some(1))); - assert_eq!(1, count); - assert_eq!(out, "\ -/baz.rs:For the Doctor Watsons of this world, as opposed to the Sherlock -"); - } - - #[test] - fn invert_match() { - let (count, out) = search_smallcap( - "Sherlock", SHERLOCK, |s| s.invert_match(true)); - assert_eq!(4, count); - assert_eq!(out, "\ -/baz.rs:Holmeses, success in the province of detective work must always -/baz.rs:can extract a clew from a wisp of straw or a flake of cigar ash; -/baz.rs:but Doctor Watson has to have it taken out for him and dusted, -/baz.rs:and exhibited clearly, with a label attached. -"); - } - - #[test] - fn invert_match_line_numbers() { - let (count, out) = search_smallcap("Sherlock", SHERLOCK, |s| { - s.invert_match(true).line_number(true) - }); - assert_eq!(4, count); - assert_eq!(out, "\ -/baz.rs:2:Holmeses, success in the province of detective work must always -/baz.rs:4:can extract a clew from a wisp of straw or a flake of cigar ash; -/baz.rs:5:but Doctor Watson has to have it taken out for him and dusted, -/baz.rs:6:and exhibited clearly, with a label attached. -"); - } - - #[test] - fn invert_match_count() { - let (count, out) = search_smallcap("Sherlock", SHERLOCK, |s| { - s.invert_match(true).count(true) - }); - assert_eq!(4, count); - assert_eq!(out, "/baz.rs:4\n"); - } - - #[test] - fn before_context_one1() { - let (count, out) = search_smallcap("Sherlock", SHERLOCK, |s| { - s.line_number(true).before_context(1) - }); - assert_eq!(2, count); - assert_eq!(out, "\ -/baz.rs:1:For the Doctor Watsons of this world, as opposed to the Sherlock -/baz.rs-2-Holmeses, success in the province of detective work must always -/baz.rs:3:be, to a very large extent, the result of luck. Sherlock Holmes -"); - } - - #[test] - fn before_context_invert_one1() { - let (count, out) = search_smallcap("Sherlock", SHERLOCK, |s| { - s.line_number(true).before_context(1).invert_match(true) - }); - assert_eq!(4, count); - assert_eq!(out, "\ -/baz.rs-1-For the Doctor Watsons of this world, as opposed to the Sherlock -/baz.rs:2:Holmeses, success in the province of detective work must always -/baz.rs-3-be, to a very large extent, the result of luck. Sherlock Holmes -/baz.rs:4:can extract a clew from a wisp of straw or a flake of cigar ash; -/baz.rs:5:but Doctor Watson has to have it taken out for him and dusted, -/baz.rs:6:and exhibited clearly, with a label attached. -"); - } - - #[test] - fn before_context_invert_one2() { - let (count, out) = search_smallcap(" a ", SHERLOCK, |s| { - s.line_number(true).before_context(1).invert_match(true) - }); - assert_eq!(3, count); - assert_eq!(out, "\ -/baz.rs:1:For the Doctor Watsons of this world, as opposed to the Sherlock -/baz.rs:2:Holmeses, success in the province of detective work must always --- -/baz.rs-4-can extract a clew from a wisp of straw or a flake of cigar ash; -/baz.rs:5:but Doctor Watson has to have it taken out for him and dusted, -"); - } - - #[test] - fn before_context_two1() { - let (count, out) = search_smallcap("Sherlock", SHERLOCK, |s| { - s.line_number(true).before_context(2) - }); - assert_eq!(2, count); - assert_eq!(out, "\ -/baz.rs:1:For the Doctor Watsons of this world, as opposed to the Sherlock -/baz.rs-2-Holmeses, success in the province of detective work must always -/baz.rs:3:be, to a very large extent, the result of luck. Sherlock Holmes -"); - } - - #[test] - fn before_context_two2() { - let (count, out) = search_smallcap("dusted", SHERLOCK, |s| { - s.line_number(true).before_context(2) - }); - assert_eq!(1, count); - assert_eq!(out, "\ -/baz.rs-3-be, to a very large extent, the result of luck. Sherlock Holmes -/baz.rs-4-can extract a clew from a wisp of straw or a flake of cigar ash; -/baz.rs:5:but Doctor Watson has to have it taken out for him and dusted, -"); - } - - #[test] - fn before_context_two3() { - let (count, out) = search_smallcap( - "success|attached", SHERLOCK, |s| { - s.line_number(true).before_context(2) - }); - assert_eq!(2, count); - assert_eq!(out, "\ -/baz.rs-1-For the Doctor Watsons of this world, as opposed to the Sherlock -/baz.rs:2:Holmeses, success in the province of detective work must always --- -/baz.rs-4-can extract a clew from a wisp of straw or a flake of cigar ash; -/baz.rs-5-but Doctor Watson has to have it taken out for him and dusted, -/baz.rs:6:and exhibited clearly, with a label attached. -"); - } - - #[test] - fn before_context_two4() { - let (count, out) = search("stdin", CODE, |s| { - s.line_number(true).before_context(2) - }); - assert_eq!(3, count); - assert_eq!(out, "\ -/baz.rs-4- -/baz.rs-5-fn main() { -/baz.rs:6: let stdin = io::stdin(); -/baz.rs-7- let stdout = io::stdout(); -/baz.rs-8- -/baz.rs:9: // Wrap the stdin reader in a Snappy reader. -/baz.rs:10: let mut rdr = snap::Reader::new(stdin.lock()); -"); - } - - #[test] - fn before_context_two5() { - let (count, out) = search("stdout", CODE, |s| { - s.line_number(true).before_context(2) - }); - assert_eq!(2, count); - assert_eq!(out, "\ -/baz.rs-5-fn main() { -/baz.rs-6- let stdin = io::stdin(); -/baz.rs:7: let stdout = io::stdout(); --- -/baz.rs-9- // Wrap the stdin reader in a Snappy reader. -/baz.rs-10- let mut rdr = snap::Reader::new(stdin.lock()); -/baz.rs:11: let mut wtr = stdout.lock(); -"); - } - - #[test] - fn before_context_three1() { - let (count, out) = search_smallcap("Sherlock", SHERLOCK, |s| { - s.line_number(true).before_context(3) - }); - assert_eq!(2, count); - assert_eq!(out, "\ -/baz.rs:1:For the Doctor Watsons of this world, as opposed to the Sherlock -/baz.rs-2-Holmeses, success in the province of detective work must always -/baz.rs:3:be, to a very large extent, the result of luck. Sherlock Holmes -"); - } - - #[test] - fn after_context_one1() { - let (count, out) = search_smallcap("Sherlock", SHERLOCK, |s| { - s.line_number(true).after_context(1) - }); - assert_eq!(2, count); - assert_eq!(out, "\ -/baz.rs:1:For the Doctor Watsons of this world, as opposed to the Sherlock -/baz.rs-2-Holmeses, success in the province of detective work must always -/baz.rs:3:be, to a very large extent, the result of luck. Sherlock Holmes -/baz.rs-4-can extract a clew from a wisp of straw or a flake of cigar ash; -"); - } - - #[test] - fn after_context_invert_one1() { - let (count, out) = search_smallcap("Sherlock", SHERLOCK, |s| { - s.line_number(true).after_context(1).invert_match(true) - }); - assert_eq!(4, count); - assert_eq!(out, "\ -/baz.rs:2:Holmeses, success in the province of detective work must always -/baz.rs-3-be, to a very large extent, the result of luck. Sherlock Holmes -/baz.rs:4:can extract a clew from a wisp of straw or a flake of cigar ash; -/baz.rs:5:but Doctor Watson has to have it taken out for him and dusted, -/baz.rs:6:and exhibited clearly, with a label attached. -"); - } - - #[test] - fn after_context_invert_one2() { - let (count, out) = search_smallcap(" a ", SHERLOCK, |s| { - s.line_number(true).after_context(1).invert_match(true) - }); - assert_eq!(3, count); - assert_eq!(out, "\ -/baz.rs:1:For the Doctor Watsons of this world, as opposed to the Sherlock -/baz.rs:2:Holmeses, success in the province of detective work must always -/baz.rs-3-be, to a very large extent, the result of luck. Sherlock Holmes --- -/baz.rs:5:but Doctor Watson has to have it taken out for him and dusted, -/baz.rs-6-and exhibited clearly, with a label attached. -"); - } - - #[test] - fn after_context_invert_one_max_count_two() { - let (count, out) = search_smallcap("Sherlock", SHERLOCK, |s| { - s.line_number(true) - .invert_match(true) - .after_context(1) - .max_count(Some(2)) - }); - assert_eq!(2, count); - assert_eq!(out, "\ -/baz.rs:2:Holmeses, success in the province of detective work must always -/baz.rs-3-be, to a very large extent, the result of luck. Sherlock Holmes -/baz.rs:4:can extract a clew from a wisp of straw or a flake of cigar ash; -/baz.rs-5-but Doctor Watson has to have it taken out for him and dusted, -"); - } - - #[test] - fn after_context_two1() { - let (count, out) = search_smallcap("Sherlock", SHERLOCK, |s| { - s.line_number(true).after_context(2) - }); - assert_eq!(2, count); - assert_eq!(out, "\ -/baz.rs:1:For the Doctor Watsons of this world, as opposed to the Sherlock -/baz.rs-2-Holmeses, success in the province of detective work must always -/baz.rs:3:be, to a very large extent, the result of luck. Sherlock Holmes -/baz.rs-4-can extract a clew from a wisp of straw or a flake of cigar ash; -/baz.rs-5-but Doctor Watson has to have it taken out for him and dusted, -"); - } - - #[test] - fn after_context_two2() { - let (count, out) = search_smallcap("dusted", SHERLOCK, |s| { - s.line_number(true).after_context(2) - }); - assert_eq!(1, count); - assert_eq!(out, "\ -/baz.rs:5:but Doctor Watson has to have it taken out for him and dusted, -/baz.rs-6-and exhibited clearly, with a label attached. -"); - } - - #[test] - fn after_context_two3() { - let (count, out) = search_smallcap( - "success|attached", SHERLOCK, |s| { - s.line_number(true).after_context(2) - }); - assert_eq!(2, count); - assert_eq!(out, "\ -/baz.rs:2:Holmeses, success in the province of detective work must always -/baz.rs-3-be, to a very large extent, the result of luck. Sherlock Holmes -/baz.rs-4-can extract a clew from a wisp of straw or a flake of cigar ash; --- -/baz.rs:6:and exhibited clearly, with a label attached. -"); - } - - #[test] - fn after_context_two_max_count_two() { - let (count, out) = search_smallcap( - "Doctor", SHERLOCK, |s| { - s.line_number(true).after_context(2).max_count(Some(2)) - }); - assert_eq!(2, count); - assert_eq!(out, "\ -/baz.rs:1:For the Doctor Watsons of this world, as opposed to the Sherlock -/baz.rs-2-Holmeses, success in the province of detective work must always -/baz.rs-3-be, to a very large extent, the result of luck. Sherlock Holmes --- -/baz.rs:5:but Doctor Watson has to have it taken out for him and dusted, -/baz.rs-6-and exhibited clearly, with a label attached. -"); - } - - #[test] - fn after_context_three1() { - let (count, out) = search_smallcap("Sherlock", SHERLOCK, |s| { - s.line_number(true).after_context(3) - }); - assert_eq!(2, count); - assert_eq!(out, "\ -/baz.rs:1:For the Doctor Watsons of this world, as opposed to the Sherlock -/baz.rs-2-Holmeses, success in the province of detective work must always -/baz.rs:3:be, to a very large extent, the result of luck. Sherlock Holmes -/baz.rs-4-can extract a clew from a wisp of straw or a flake of cigar ash; -/baz.rs-5-but Doctor Watson has to have it taken out for him and dusted, -/baz.rs-6-and exhibited clearly, with a label attached. -"); - } - - #[test] - fn before_after_context_two1() { - let (count, out) = search( - r"fn main|let mut rdr", CODE, |s| { - s.line_number(true).after_context(2).before_context(2) - }); - assert_eq!(2, count); - assert_eq!(out, "\ -/baz.rs-3-use std::io; -/baz.rs-4- -/baz.rs:5:fn main() { -/baz.rs-6- let stdin = io::stdin(); -/baz.rs-7- let stdout = io::stdout(); -/baz.rs-8- -/baz.rs-9- // Wrap the stdin reader in a Snappy reader. -/baz.rs:10: let mut rdr = snap::Reader::new(stdin.lock()); -/baz.rs-11- let mut wtr = stdout.lock(); -/baz.rs-12- io::copy(&mut rdr, &mut wtr).expect(\"I/O operation failed\"); -"); - } -} diff --git a/src/unescape.rs b/src/unescape.rs deleted file mode 100644 index c27e6e2..0000000 --- a/src/unescape.rs +++ /dev/null @@ -1,128 +0,0 @@ -/// A single state in the state machine used by `unescape`. -#[derive(Clone, Copy, Eq, PartialEq)] -enum State { - /// The state after seeing a `\`. - Escape, - /// The state after seeing a `\x`. - HexFirst, - /// The state after seeing a `\x[0-9A-Fa-f]`. - HexSecond(char), - /// Default state. - Literal, -} - -/// Unescapes a string given on the command line. It supports a limited set of -/// escape sequences: -/// -/// * `\t`, `\r` and `\n` are mapped to their corresponding ASCII bytes. -/// * `\xZZ` hexadecimal escapes are mapped to their byte. -pub fn unescape(s: &str) -> Vec { - use self::State::*; - - let mut bytes = vec![]; - let mut state = Literal; - for c in s.chars() { - match state { - Escape => { - match c { - '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; - } - } - } - 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 { - Escape => bytes.push(b'\\'), - HexFirst => bytes.extend(b"\\x"), - HexSecond(c) => bytes.extend(format!("\\x{}", c).into_bytes()), - Literal => {} - } - bytes -} - -#[cfg(test)] -mod tests { - use super::unescape; - - fn b(bytes: &'static [u8]) -> Vec { - bytes.to_vec() - } - - #[test] - fn unescape_nul() { - assert_eq!(b(b"\x00"), unescape(r"\x00")); - } - - #[test] - fn unescape_nl() { - assert_eq!(b(b"\n"), unescape(r"\n")); - } - - #[test] - fn unescape_tab() { - assert_eq!(b(b"\t"), unescape(r"\t")); - } - - #[test] - fn unescape_carriage() { - assert_eq!(b(b"\r"), unescape(r"\r")); - } - - #[test] - fn unescape_nothing_simple() { - assert_eq!(b(b"\\a"), unescape(r"\a")); - } - - #[test] - fn unescape_nothing_hex0() { - assert_eq!(b(b"\\x"), unescape(r"\x")); - } - - #[test] - fn unescape_nothing_hex1() { - assert_eq!(b(b"\\xz"), unescape(r"\xz")); - } - - #[test] - fn unescape_nothing_hex2() { - assert_eq!(b(b"\\xzz"), unescape(r"\xzz")); - } -} diff --git a/src/worker.rs b/src/worker.rs deleted file mode 100644 index a8327cd..0000000 --- a/src/worker.rs +++ /dev/null @@ -1,390 +0,0 @@ -use std::fs::File; -use std::io; -use std::path::Path; - -use encoding_rs::Encoding; -use grep::Grep; -use ignore::DirEntry; -use memmap::Mmap; -use termcolor::WriteColor; - -use decoder::DecodeReader; -use decompressor::{self, DecompressionReader}; -use pathutil::strip_prefix; -use printer::Printer; -use search_buffer::BufferSearcher; -use search_stream::{InputBuffer, Searcher}; - -use Result; - -pub enum Work { - Stdin, - DirEntry(DirEntry), -} - -pub struct WorkerBuilder { - grep: Grep, - opts: Options, -} - -#[derive(Clone, Debug)] -struct Options { - mmap: bool, - encoding: Option<&'static Encoding>, - after_context: usize, - before_context: usize, - byte_offset: bool, - count: bool, - count_matches: bool, - files_with_matches: bool, - files_without_matches: bool, - eol: u8, - invert_match: bool, - line_number: bool, - max_count: Option, - no_messages: bool, - quiet: bool, - text: bool, - search_zip_files: bool -} - -impl Default for Options { - fn default() -> Options { - Options { - mmap: false, - encoding: None, - after_context: 0, - before_context: 0, - byte_offset: false, - count: false, - count_matches: false, - files_with_matches: false, - files_without_matches: false, - eol: b'\n', - invert_match: false, - line_number: false, - max_count: None, - no_messages: false, - quiet: false, - text: false, - search_zip_files: false, - } - } -} - -impl WorkerBuilder { - /// Create a new builder for a worker. - /// - /// A reusable input buffer and a grep matcher are required, but there - /// are numerous additional options that can be configured on this builder. - pub fn new(grep: Grep) -> WorkerBuilder { - WorkerBuilder { - grep: grep, - opts: Options::default(), - } - } - - /// Create the worker from this builder. - pub fn build(self) -> Worker { - let mut inpbuf = InputBuffer::new(); - inpbuf.eol(self.opts.eol); - Worker { - grep: self.grep, - inpbuf: inpbuf, - decodebuf: vec![0; 8 * (1<<10)], - opts: self.opts, - } - } - - /// The number of contextual lines to show after each match. The default - /// is zero. - pub fn after_context(mut self, count: usize) -> Self { - self.opts.after_context = count; - self - } - - /// The number of contextual lines to show before each match. The default - /// is zero. - pub fn before_context(mut self, count: usize) -> Self { - self.opts.before_context = count; - self - } - - /// If enabled, searching will print a 0-based offset of the - /// matching line (or the actual match if -o is specified) before - /// printing the line itself. - /// - /// Disabled by default. - pub fn byte_offset(mut self, yes: bool) -> Self { - self.opts.byte_offset = yes; - self - } - - /// If enabled, searching will print a count instead of each match. - /// - /// Disabled by default. - pub fn count(mut self, yes: bool) -> Self { - self.opts.count = yes; - self - } - - /// If enabled, searching will print the count of individual matches - /// instead of each match. - /// - /// Disabled by default. - pub fn count_matches(mut self, yes: bool) -> Self { - self.opts.count_matches = yes; - self - } - - /// Set the encoding to use to read each file. - /// - /// If the encoding is `None` (the default), then the encoding is - /// automatically detected on a best-effort per-file basis. - pub fn encoding(mut self, enc: Option<&'static Encoding>) -> Self { - self.opts.encoding = enc; - self - } - - /// If enabled, searching will print the path instead of each match. - /// - /// Disabled by default. - pub fn files_with_matches(mut self, yes: bool) -> Self { - self.opts.files_with_matches = yes; - self - } - - /// If enabled, searching will print the path of files without any matches. - /// - /// Disabled by default. - pub fn files_without_matches(mut self, yes: bool) -> Self { - self.opts.files_without_matches = yes; - self - } - - /// Set the end-of-line byte used by this searcher. - pub fn eol(mut self, eol: u8) -> Self { - self.opts.eol = eol; - self - } - - /// If enabled, matching is inverted so that lines that *don't* match the - /// given pattern are treated as matches. - pub fn invert_match(mut self, yes: bool) -> Self { - self.opts.invert_match = yes; - self - } - - /// If enabled, compute line numbers and prefix each line of output with - /// them. - pub fn line_number(mut self, yes: bool) -> Self { - self.opts.line_number = yes; - self - } - - /// Limit the number of matches to the given count. - /// - /// The default is None, which corresponds to no limit. - pub fn max_count(mut self, count: Option) -> Self { - self.opts.max_count = count; - self - } - - /// If enabled, try to use memory maps for searching if possible. - pub fn mmap(mut self, yes: bool) -> Self { - self.opts.mmap = yes; - self - } - - /// If enabled, error messages are suppressed. - /// - /// This is disabled by default. - pub fn no_messages(mut self, yes: bool) -> Self { - self.opts.no_messages = yes; - self - } - - /// If enabled, don't show any output and quit searching after the first - /// match is found. - pub fn quiet(mut self, yes: bool) -> Self { - self.opts.quiet = yes; - self - } - - /// If enabled, search binary files as if they were text. - pub fn text(mut self, yes: bool) -> Self { - self.opts.text = yes; - self - } - - /// If enabled, search through compressed files as well - pub fn search_zip_files(mut self, yes: bool) -> Self { - self.opts.search_zip_files = yes; - self - } -} - -/// Worker is responsible for executing searches on file paths, while choosing -/// streaming search or memory map search as appropriate. -pub struct Worker { - grep: Grep, - inpbuf: InputBuffer, - decodebuf: Vec, - opts: Options, -} - -impl Worker { - /// Execute the worker with the given printer and work item. - /// - /// A work item can either be stdin or a file path. - pub fn run( - &mut self, - printer: &mut Printer, - work: Work, - ) -> u64 { - let result = match work { - Work::Stdin => { - let stdin = io::stdin(); - let stdin = stdin.lock(); - self.search(printer, Path::new(""), stdin) - } - Work::DirEntry(dent) => { - let mut path = dent.path(); - if self.opts.search_zip_files - && decompressor::is_compressed(path) - { - match DecompressionReader::from_path(path) { - Some(reader) => self.search(printer, path, reader), - None => { - return 0; - } - } - } else { - let file = match File::open(path) { - Ok(file) => file, - Err(err) => { - if !self.opts.no_messages { - eprintln!("{}: {}", path.display(), err); - } - return 0; - } - }; - if let Some(p) = strip_prefix("./", path) { - path = p; - } - if self.opts.mmap { - self.search_mmap(printer, path, &file) - } else { - self.search(printer, path, file) - } - } - } - }; - match result { - Ok(count) => { - count - } - Err(err) => { - if !self.opts.no_messages { - eprintln!("{}", err); - } - 0 - } - } - } - - fn search( - &mut self, - printer: &mut Printer, - path: &Path, - rdr: R, - ) -> Result { - let rdr = DecodeReader::new( - rdr, &mut self.decodebuf, self.opts.encoding); - let searcher = Searcher::new( - &mut self.inpbuf, printer, &self.grep, path, rdr); - searcher - .after_context(self.opts.after_context) - .before_context(self.opts.before_context) - .byte_offset(self.opts.byte_offset) - .count(self.opts.count) - .count_matches(self.opts.count_matches) - .files_with_matches(self.opts.files_with_matches) - .files_without_matches(self.opts.files_without_matches) - .eol(self.opts.eol) - .line_number(self.opts.line_number) - .invert_match(self.opts.invert_match) - .max_count(self.opts.max_count) - .quiet(self.opts.quiet) - .text(self.opts.text) - .run() - .map_err(From::from) - } - - fn search_mmap( - &mut self, - printer: &mut Printer, - path: &Path, - file: &File, - ) -> Result { - if file.metadata()?.len() == 0 { - // Opening a memory map with an empty file results in an error. - // However, this may not actually be an empty file! For example, - // /proc/cpuinfo reports itself as an empty file, but it can - // produce data when it's read from. Therefore, we fall back to - // regular read calls. - return self.search(printer, path, file); - } - let mmap = match self.mmap(file)? { - None => return self.search(printer, path, file), - Some(mmap) => mmap, - }; - let buf = &*mmap; - if buf.len() >= 3 && Encoding::for_bom(buf).is_some() { - // If we have a UTF-16 bom in our memory map, then we need to fall - // back to the stream reader, which will do transcoding. - return self.search(printer, path, file); - } - let searcher = BufferSearcher::new(printer, &self.grep, path, buf); - Ok(searcher - .byte_offset(self.opts.byte_offset) - .count(self.opts.count) - .count_matches(self.opts.count_matches) - .files_with_matches(self.opts.files_with_matches) - .files_without_matches(self.opts.files_without_matches) - .eol(self.opts.eol) - .line_number(self.opts.line_number) - .invert_match(self.opts.invert_match) - .max_count(self.opts.max_count) - .quiet(self.opts.quiet) - .text(self.opts.text) - .run()) - } - - #[cfg(not(unix))] - fn mmap(&self, file: &File) -> Result> { - Ok(Some(mmap_readonly(file)?)) - } - - #[cfg(unix)] - fn mmap(&self, file: &File) -> Result> { - use libc::{EOVERFLOW, ENODEV, ENOMEM}; - - let err = match mmap_readonly(file) { - Ok(mmap) => return Ok(Some(mmap)), - Err(err) => err, - }; - let code = err.raw_os_error(); - if code == Some(EOVERFLOW) - || code == Some(ENODEV) - || code == Some(ENOMEM) - { - return Ok(None); - } - Err(From::from(err)) - } -} - -fn mmap_readonly(file: &File) -> io::Result { - unsafe { Mmap::map(file) } -} diff --git a/termcolor/COPYING b/termcolor/COPYING deleted file mode 100644 index bb9c20a..0000000 --- a/termcolor/COPYING +++ /dev/null @@ -1,3 +0,0 @@ -This project is dual-licensed under the Unlicense and MIT licenses. - -You may use this code under the terms of either license. diff --git a/termcolor/Cargo.toml b/termcolor/Cargo.toml deleted file mode 100644 index d0a0ff4..0000000 --- a/termcolor/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "termcolor" -version = "0.3.6" #:version -authors = ["Andrew Gallant "] -description = """ -A simple cross platform library for writing colored text to a terminal. -""" -documentation = "https://docs.rs/termcolor" -homepage = "https://github.com/BurntSushi/ripgrep/tree/master/termcolor" -repository = "https://github.com/BurntSushi/ripgrep/tree/master/termcolor" -readme = "README.md" -keywords = ["windows", "win", "color", "ansi", "console"] -license = "Unlicense/MIT" - -[lib] -name = "termcolor" -bench = false - -[target.'cfg(windows)'.dependencies] -wincolor = { version = "0.1.6", path = "../wincolor" } diff --git a/termcolor/LICENSE-MIT b/termcolor/LICENSE-MIT deleted file mode 100644 index 3b0a5dc..0000000 --- a/termcolor/LICENSE-MIT +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Andrew Gallant - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/termcolor/README.md b/termcolor/README.md deleted file mode 100644 index 7317d43..0000000 --- a/termcolor/README.md +++ /dev/null @@ -1,86 +0,0 @@ -termcolor -========= -A simple cross platform library for writing colored text to a terminal. This -library writes colored text either using standard ANSI escape sequences or -by interacting with the Windows console. Several convenient abstractions -are provided for use in single-threaded or multi-threaded command line -applications. - -[![Linux build status](https://api.travis-ci.org/BurntSushi/ripgrep.png)](https://travis-ci.org/BurntSushi/ripgrep) -[![Windows build status](https://ci.appveyor.com/api/projects/status/github/BurntSushi/ripgrep?svg=true)](https://ci.appveyor.com/project/BurntSushi/ripgrep) -[![](https://img.shields.io/crates/v/termcolor.svg)](https://crates.io/crates/termcolor) - -Dual-licensed under MIT or the [UNLICENSE](http://unlicense.org). - -### Documentation - -[https://docs.rs/termcolor](https://docs.rs/termcolor) - -### Usage - -Add this to your `Cargo.toml`: - -```toml -[dependencies] -termcolor = "0.3" -``` - -and this to your crate root: - -```rust -extern crate termcolor; -``` - -### Organization - -The `WriteColor` trait extends the `io::Write` trait with methods for setting -colors or resetting them. - -`StandardStream` and `StandardStreamLock` both satisfy `WriteColor` and are -analogous to `std::io::Stdout` and `std::io::StdoutLock`, or `std::io::Stderr` -and `std::io::StderrLock`. - -`Buffer` is an in memory buffer that supports colored text. In a parallel -program, each thread might write to its own buffer. A buffer can be printed to -stdout or stderr using a `BufferWriter`. The advantage of this design is that -each thread can work in parallel on a buffer without having to synchronize -access to global resources such as the Windows console. Moreover, this design -also prevents interleaving of buffer output. - -`Ansi` and `NoColor` both satisfy `WriteColor` for arbitrary implementors of -`io::Write`. These types are useful when you know exactly what you need. An -analogous type for the Windows console is not provided since it cannot exist. - -### Example: using `StandardStream` - -The `StandardStream` type in this crate works similarly to `std::io::Stdout`, -except it is augmented with methods for coloring by the `WriteColor` trait. -For example, to write some green text: - -```rust -use std::io::Write; -use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; - -let mut stdout = StandardStream::stdout(ColorChoice::Always); -stdout.set_color(ColorSpec::new().set_fg(Some(Color::Green)))?; -writeln!(&mut stdout, "green text!")?; -``` - -### Example: using `BufferWriter` - -A `BufferWriter` can create buffers and write buffers to stdout or stderr. It -does *not* implement `io::Write` or `WriteColor` itself. Instead, `Buffer` -implements `io::Write` and `termcolor::WriteColor`. - -This example shows how to print some green text to stderr. - -```rust -use std::io::Write; -use termcolor::{BufferWriter, Color, ColorChoice, ColorSpec, WriteColor}; - -let mut bufwtr = BufferWriter::stderr(ColorChoice::Always); -let mut buffer = bufwtr.buffer(); -buffer.set_color(ColorSpec::new().set_fg(Some(Color::Green)))?; -writeln!(&mut buffer, "green text!")?; -bufwtr.print(&buffer)?; -``` diff --git a/termcolor/UNLICENSE b/termcolor/UNLICENSE deleted file mode 100644 index 68a49da..0000000 --- a/termcolor/UNLICENSE +++ /dev/null @@ -1,24 +0,0 @@ -This is free and unencumbered software released into the public domain. - -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a compiled -binary, for any purpose, commercial or non-commercial, and by any -means. - -In jurisdictions that recognize copyright laws, the author or authors -of this software dedicate any and all copyright interest in the -software to the public domain. We make this dedication for the benefit -of the public at large and to the detriment of our heirs and -successors. We intend this dedication to be an overt act of -relinquishment in perpetuity of all present and future rights to this -software under copyright law. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -For more information, please refer to diff --git a/tests/data/sherlock.bz2 b/tests/data/sherlock.bz2 deleted file mode 100644 index e4a6454..0000000 Binary files a/tests/data/sherlock.bz2 and /dev/null differ diff --git a/tests/data/sherlock.gz b/tests/data/sherlock.gz deleted file mode 100644 index 5629cbe..0000000 Binary files a/tests/data/sherlock.gz and /dev/null differ diff --git a/tests/data/sherlock.lzma b/tests/data/sherlock.lzma deleted file mode 100644 index bfdf7fb..0000000 Binary files a/tests/data/sherlock.lzma and /dev/null differ diff --git a/tests/data/sherlock.xz b/tests/data/sherlock.xz deleted file mode 100644 index 39cca0f..0000000 Binary files a/tests/data/sherlock.xz and /dev/null differ diff --git a/tests/hay.rs b/tests/hay.rs deleted file mode 100644 index 74d2f6c..0000000 --- a/tests/hay.rs +++ /dev/null @@ -1,24 +0,0 @@ -pub const SHERLOCK: &'static str = "\ -For the Doctor Watsons of this world, as opposed to the Sherlock -Holmeses, success in the province of detective work must always -be, to a very large extent, the result of luck. Sherlock Holmes -can extract a clew from a wisp of straw or a flake of cigar ash; -but Doctor Watson has to have it taken out for him and dusted, -and exhibited clearly, with a label attached. -"; - -pub const CODE: &'static str = "\ -extern crate snap; - -use std::io; - -fn main() { - let stdin = io::stdin(); - let stdout = io::stdout(); - - // Wrap the stdin reader in a Snappy reader. - let mut rdr = snap::Reader::new(stdin.lock()); - let mut wtr = stdout.lock(); - io::copy(&mut rdr, &mut wtr).expect(\"I/O operation failed\"); -} -"; diff --git a/tests/tests.rs b/tests/tests.rs deleted file mode 100644 index f3cc8f0..0000000 --- a/tests/tests.rs +++ /dev/null @@ -1,2223 +0,0 @@ -/*! -This module contains *integration* tests. Their purpose is to test the CLI -interface. Namely, that passing a flag does what it says on the tin. - -Tests for more fine grained behavior (like the search or the globber) should be -unit tests in their respective modules. -*/ - -#![allow(dead_code, unused_imports)] - -use std::process::Command; - -use workdir::WorkDir; - -mod hay; -mod workdir; - -macro_rules! sherlock { - ($name:ident, $fun:expr) => { - sherlock!($name, "Sherlock", $fun); - }; - ($name:ident, $query:expr, $fun:expr) => { - sherlock!($name, $query, "sherlock", $fun); - }; - ($name:ident, $query:expr, $path:expr, $fun:expr) => { - #[test] - fn $name() { - let wd = WorkDir::new(stringify!($name)); - wd.create("sherlock", hay::SHERLOCK); - let mut cmd = wd.command(); - cmd.arg($query).arg($path); - $fun(wd, cmd); - } - }; -} - -macro_rules! clean { - ($name:ident, $query:expr, $path:expr, $fun:expr) => { - #[test] - fn $name() { - let wd = WorkDir::new(stringify!($name)); - let mut cmd = wd.command(); - cmd.arg($query).arg($path); - $fun(wd, cmd); - } - }; -} - -fn path(unix: &str) -> String { - if cfg!(windows) { - unix.replace("/", "\\") - } else { - unix.to_string() - } -} - -fn paths(unix: &[&str]) -> Vec { - let mut xs: Vec<_> = unix.iter().map(|s| path(s)).collect(); - xs.sort(); - xs -} - -fn paths_from_stdout(stdout: String) -> Vec { - let mut paths: Vec<_> = stdout.lines().map(|s| { - s.split(':').next().unwrap().to_string() - }).collect(); - paths.sort(); - paths -} - -fn sort_lines(lines: &str) -> String { - let mut lines: Vec = - lines.trim().lines().map(|s| s.to_owned()).collect(); - lines.sort(); - format!("{}\n", lines.join("\n")) -} - -fn cmd_exists(name: &str) -> bool { - Command::new(name).arg("--help").output().is_ok() -} - -sherlock!(single_file, |wd: WorkDir, mut cmd| { - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -For the Doctor Watsons of this world, as opposed to the Sherlock -be, to a very large extent, the result of luck. Sherlock Holmes -"; - assert_eq!(lines, expected); -}); - -sherlock!(dir, "Sherlock", ".", |wd: WorkDir, mut cmd| { - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -sherlock:For the Doctor Watsons of this world, as opposed to the Sherlock -sherlock:be, to a very large extent, the result of luck. Sherlock Holmes -"; - assert_eq!(lines, expected); -}); - -sherlock!(line_numbers, |wd: WorkDir, mut cmd: Command| { - cmd.arg("-n"); - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -1:For the Doctor Watsons of this world, as opposed to the Sherlock -3:be, to a very large extent, the result of luck. Sherlock Holmes -"; - assert_eq!(lines, expected); -}); - -sherlock!(columns, |wd: WorkDir, mut cmd: Command| { - cmd.arg("--column"); - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -1:57:For the Doctor Watsons of this world, as opposed to the Sherlock -3:49:be, to a very large extent, the result of luck. Sherlock Holmes -"; - assert_eq!(lines, expected); -}); - -sherlock!(with_filename, |wd: WorkDir, mut cmd: Command| { - cmd.arg("-H"); - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -sherlock:For the Doctor Watsons of this world, as opposed to the Sherlock -sherlock:be, to a very large extent, the result of luck. Sherlock Holmes -"; - assert_eq!(lines, expected); -}); - -sherlock!(with_heading, |wd: WorkDir, mut cmd: Command| { - // This forces the issue since --with-filename is disabled by default - // when searching one file. - cmd.arg("--with-filename").arg("--heading"); - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -sherlock -For the Doctor Watsons of this world, as opposed to the Sherlock -be, to a very large extent, the result of luck. Sherlock Holmes -"; - assert_eq!(lines, expected); -}); - -sherlock!(with_heading_default, "Sherlock", ".", -|wd: WorkDir, mut cmd: Command| { - // Search two or more and get --with-filename enabled by default. - // Use -j1 to get deterministic results. - wd.create("foo", "Sherlock Holmes lives on Baker Street."); - cmd.arg("-j1").arg("--heading"); - let lines: String = wd.stdout(&mut cmd); - let expected1 = "\ -foo -Sherlock Holmes lives on Baker Street. - -sherlock -For the Doctor Watsons of this world, as opposed to the Sherlock -be, to a very large extent, the result of luck. Sherlock Holmes -"; - let expected2 = "\ -sherlock -For the Doctor Watsons of this world, as opposed to the Sherlock -be, to a very large extent, the result of luck. Sherlock Holmes - -foo -Sherlock Holmes lives on Baker Street. -"; - if lines != expected1 { - assert_eq!(lines, expected2); - } else { - assert_eq!(lines, expected1); - } -}); - -sherlock!(inverted, |wd: WorkDir, mut cmd: Command| { - cmd.arg("-v"); - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -Holmeses, success in the province of detective work must always -can extract a clew from a wisp of straw or a flake of cigar ash; -but Doctor Watson has to have it taken out for him and dusted, -and exhibited clearly, with a label attached. -"; - assert_eq!(lines, expected); -}); - -sherlock!(inverted_line_numbers, |wd: WorkDir, mut cmd: Command| { - cmd.arg("-n").arg("-v"); - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -2:Holmeses, success in the province of detective work must always -4:can extract a clew from a wisp of straw or a flake of cigar ash; -5:but Doctor Watson has to have it taken out for him and dusted, -6:and exhibited clearly, with a label attached. -"; - assert_eq!(lines, expected); -}); - -sherlock!(case_insensitive, "sherlock", |wd: WorkDir, mut cmd: Command| { - cmd.arg("-i"); - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -For the Doctor Watsons of this world, as opposed to the Sherlock -be, to a very large extent, the result of luck. Sherlock Holmes -"; - assert_eq!(lines, expected); -}); - -sherlock!(word, "as", |wd: WorkDir, mut cmd: Command| { - cmd.arg("-w"); - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -For the Doctor Watsons of this world, as opposed to the Sherlock -"; - assert_eq!(lines, expected); -}); - -sherlock!(line, "Watson|and exhibited clearly, with a label attached.", -|wd: WorkDir, mut cmd: Command| { - cmd.arg("-x"); - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -and exhibited clearly, with a label attached. -"; - assert_eq!(lines, expected); -}); - -sherlock!(literal, "()", "file", |wd: WorkDir, mut cmd: Command| { - wd.create("file", "blib\n()\nblab\n"); - cmd.arg("-F"); - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "()\n"); -}); - -sherlock!(quiet, |wd: WorkDir, mut cmd: Command| { - cmd.arg("-q"); - let lines: String = wd.stdout(&mut cmd); - assert!(lines.is_empty()); -}); - -sherlock!(replace, |wd: WorkDir, mut cmd: Command| { - cmd.arg("-r").arg("FooBar"); - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -For the Doctor Watsons of this world, as opposed to the FooBar -be, to a very large extent, the result of luck. FooBar Holmes -"; - assert_eq!(lines, expected); -}); - -sherlock!(replace_groups, "([A-Z][a-z]+) ([A-Z][a-z]+)", -|wd: WorkDir, mut cmd: Command| { - cmd.arg("-r").arg("$2, $1"); - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -For the Watsons, Doctor of this world, as opposed to the Sherlock -be, to a very large extent, the result of luck. Holmes, Sherlock -but Watson, Doctor has to have it taken out for him and dusted, -"; - assert_eq!(lines, expected); -}); - -sherlock!(replace_named_groups, "(?P[A-Z][a-z]+) (?P[A-Z][a-z]+)", -|wd: WorkDir, mut cmd: Command| { - cmd.arg("-r").arg("$last, $first"); - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -For the Watsons, Doctor of this world, as opposed to the Sherlock -be, to a very large extent, the result of luck. Holmes, Sherlock -but Watson, Doctor has to have it taken out for him and dusted, -"; - assert_eq!(lines, expected); -}); - -sherlock!(replace_with_only_matching, "of (\\w+)", -|wd: WorkDir, mut cmd: Command| { - cmd.arg("-o").arg("-r").arg("$1"); - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -this -detective -luck -straw -cigar -"; - assert_eq!(lines, expected); -}); - -sherlock!(file_types, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| { - wd.create("file.py", "Sherlock"); - wd.create("file.rs", "Sherlock"); - cmd.arg("-t").arg("rust"); - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "file.rs:Sherlock\n"); -}); - -sherlock!(file_types_all, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| { - wd.create("file.py", "Sherlock"); - cmd.arg("-t").arg("all"); - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "file.py:Sherlock\n"); -}); - -sherlock!(file_types_negate, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| { - wd.remove("sherlock"); - wd.create("file.py", "Sherlock"); - wd.create("file.rs", "Sherlock"); - cmd.arg("-T").arg("rust"); - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "file.py:Sherlock\n"); -}); - -sherlock!(file_types_negate_all, "Sherlock", ".", -|wd: WorkDir, mut cmd: Command| { - wd.create("file.py", "Sherlock"); - cmd.arg("-T").arg("all"); - - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "\ -sherlock:For the Doctor Watsons of this world, as opposed to the Sherlock -sherlock:be, to a very large extent, the result of luck. Sherlock Holmes -"); -}); - -sherlock!(file_type_clear, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| { - wd.create("file.py", "Sherlock"); - wd.create("file.rs", "Sherlock"); - cmd.arg("--type-clear").arg("rust").arg("-t").arg("rust"); - wd.assert_err(&mut cmd); -}); - -sherlock!(file_type_add, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| { - wd.create("file.py", "Sherlock"); - wd.create("file.rs", "Sherlock"); - wd.create("file.wat", "Sherlock"); - cmd.arg("--type-add").arg("wat:*.wat").arg("-t").arg("wat"); - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "file.wat:Sherlock\n"); -}); - -sherlock!(file_type_add_compose, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| { - wd.create("file.py", "Sherlock"); - wd.create("file.rs", "Sherlock"); - wd.create("file.wat", "Sherlock"); - cmd.arg("--type-add").arg("wat:*.wat"); - cmd.arg("--type-add").arg("combo:include:wat,py").arg("-t").arg("combo"); - let lines: String = wd.stdout(&mut cmd); - println!("{}", lines); - assert_eq!(sort_lines(&lines), "file.py:Sherlock\nfile.wat:Sherlock\n"); -}); - -sherlock!(glob, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| { - wd.create("file.py", "Sherlock"); - wd.create("file.rs", "Sherlock"); - cmd.arg("-g").arg("*.rs"); - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "file.rs:Sherlock\n"); -}); - -sherlock!(glob_negate, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| { - wd.remove("sherlock"); - wd.create("file.py", "Sherlock"); - wd.create("file.rs", "Sherlock"); - cmd.arg("-g").arg("!*.rs"); - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "file.py:Sherlock\n"); -}); - -sherlock!(iglob, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| { - wd.create("file.HTML", "Sherlock"); - cmd.arg("--iglob").arg("*.html"); - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "file.HTML:Sherlock\n"); -}); - -sherlock!(csglob, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| { - wd.create("file1.HTML", "Sherlock"); - wd.create("file2.html", "Sherlock"); - cmd.arg("--glob").arg("*.html"); - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "file2.html:Sherlock\n"); -}); - -sherlock!(byte_offset_only_matching, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| { - cmd.arg("-b").arg("-o"); - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -sherlock:56:Sherlock -sherlock:177:Sherlock -"; - assert_eq!(lines, expected); -}); - -sherlock!(count, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| { - cmd.arg("--count"); - let lines: String = wd.stdout(&mut cmd); - let expected = "sherlock:2\n"; - assert_eq!(lines, expected); -}); - -sherlock!(count_matches, "the", ".", |wd: WorkDir, mut cmd: Command| { - cmd.arg("--count-matches"); - let lines: String = wd.stdout(&mut cmd); - let expected = "sherlock:4\n"; - assert_eq!(lines, expected); -}); - -sherlock!(count_matches_inverted, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| { - cmd.arg("--count-matches").arg("--invert-match"); - let lines: String = wd.stdout(&mut cmd); - let expected = "sherlock:4\n"; - assert_eq!(lines, expected); -}); - -sherlock!(count_matches_via_only, "the", ".", |wd: WorkDir, mut cmd: Command| { - cmd.arg("--count").arg("--only-matching"); - let lines: String = wd.stdout(&mut cmd); - let expected = "sherlock:4\n"; - assert_eq!(lines, expected); -}); - -sherlock!(files_with_matches, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| { - cmd.arg("--files-with-matches"); - let lines: String = wd.stdout(&mut cmd); - let expected = "sherlock\n"; - assert_eq!(lines, expected); -}); - -sherlock!(files_without_matches, "Sherlock", ".", -|wd: WorkDir, mut cmd: Command| { - wd.create("file.py", "foo"); - cmd.arg("--files-without-match"); - let lines: String = wd.stdout(&mut cmd); - let expected = "file.py\n"; - assert_eq!(lines, expected); -}); - -sherlock!(after_context, |wd: WorkDir, mut cmd: Command| { - cmd.arg("-A").arg("1"); - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -For the Doctor Watsons of this world, as opposed to the Sherlock -Holmeses, success in the province of detective work must always -be, to a very large extent, the result of luck. Sherlock Holmes -can extract a clew from a wisp of straw or a flake of cigar ash; -"; - assert_eq!(lines, expected); -}); - -sherlock!(after_context_line_numbers, |wd: WorkDir, mut cmd: Command| { - cmd.arg("-A").arg("1").arg("-n"); - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -1:For the Doctor Watsons of this world, as opposed to the Sherlock -2-Holmeses, success in the province of detective work must always -3:be, to a very large extent, the result of luck. Sherlock Holmes -4-can extract a clew from a wisp of straw or a flake of cigar ash; -"; - assert_eq!(lines, expected); -}); - -sherlock!(before_context, |wd: WorkDir, mut cmd: Command| { - cmd.arg("-B").arg("1"); - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -For the Doctor Watsons of this world, as opposed to the Sherlock -Holmeses, success in the province of detective work must always -be, to a very large extent, the result of luck. Sherlock Holmes -"; - assert_eq!(lines, expected); -}); - -sherlock!(before_context_line_numbers, |wd: WorkDir, mut cmd: Command| { - cmd.arg("-B").arg("1").arg("-n"); - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -1:For the Doctor Watsons of this world, as opposed to the Sherlock -2-Holmeses, success in the province of detective work must always -3:be, to a very large extent, the result of luck. Sherlock Holmes -"; - assert_eq!(lines, expected); -}); - -sherlock!(context, "world|attached", |wd: WorkDir, mut cmd: Command| { - cmd.arg("-C").arg("1"); - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -For the Doctor Watsons of this world, as opposed to the Sherlock -Holmeses, success in the province of detective work must always --- -but Doctor Watson has to have it taken out for him and dusted, -and exhibited clearly, with a label attached. -"; - assert_eq!(lines, expected); -}); - -sherlock!(context_line_numbers, "world|attached", -|wd: WorkDir, mut cmd: Command| { - cmd.arg("-C").arg("1").arg("-n"); - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -1:For the Doctor Watsons of this world, as opposed to the Sherlock -2-Holmeses, success in the province of detective work must always --- -5-but Doctor Watson has to have it taken out for him and dusted, -6:and exhibited clearly, with a label attached. -"; - assert_eq!(lines, expected); -}); - -sherlock!(max_filesize_parse_error_length, "Sherlock", ".", -|wd: WorkDir, mut cmd: Command| { - cmd.arg("--max-filesize").arg("44444444444444444444"); - wd.assert_err(&mut cmd); -}); - -sherlock!(max_filesize_parse_error_suffix, "Sherlock", ".", -|wd: WorkDir, mut cmd: Command| { - cmd.arg("--max-filesize").arg("45k"); - wd.assert_err(&mut cmd); -}); - -sherlock!(max_filesize_parse_no_suffix, "Sherlock", ".", -|wd: WorkDir, mut cmd: Command| { - wd.remove("sherlock"); - wd.create_size("foo", 40); - wd.create_size("bar", 60); - - cmd.arg("--max-filesize").arg("50").arg("--files"); - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -foo -"; - assert_eq!(lines, expected); -}); - -sherlock!(max_filesize_parse_k_suffix, "Sherlock", ".", -|wd: WorkDir, mut cmd: Command| { - wd.remove("sherlock"); - wd.create_size("foo", 3048); - wd.create_size("bar", 4100); - - cmd.arg("--max-filesize").arg("4K").arg("--files"); - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -foo -"; - assert_eq!(lines, expected); -}); - -sherlock!(max_filesize_parse_m_suffix, "Sherlock", ".", -|wd: WorkDir, mut cmd: Command| { - wd.remove("sherlock"); - wd.create_size("foo", 1000000); - wd.create_size("bar", 1400000); - - cmd.arg("--max-filesize").arg("1M").arg("--files"); - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -foo -"; - assert_eq!(lines, expected); -}); - -sherlock!(max_filesize_suffix_overflow, "Sherlock", ".", -|wd: WorkDir, mut cmd: Command| { - wd.remove("sherlock"); - wd.create_size("foo", 1000000); - - // 2^35 * 2^30 would otherwise overflow - cmd.arg("--max-filesize").arg("34359738368G").arg("--files"); - wd.assert_err(&mut cmd); -}); - -sherlock!(ignore_hidden, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| { - wd.remove("sherlock"); - wd.create(".sherlock", hay::SHERLOCK); - wd.assert_err(&mut cmd); -}); - -sherlock!(no_ignore_hidden, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| { - wd.remove("sherlock"); - wd.create(".sherlock", hay::SHERLOCK); - - cmd.arg("--hidden"); - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -.sherlock:For the Doctor Watsons of this world, as opposed to the Sherlock -.sherlock:be, to a very large extent, the result of luck. Sherlock Holmes -"; - assert_eq!(lines, expected); -}); - -sherlock!(ignore_git, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| { - wd.create(".gitignore", "sherlock\n"); - wd.assert_err(&mut cmd); -}); - -sherlock!(ignore_generic, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| { - wd.create(".ignore", "sherlock\n"); - wd.assert_err(&mut cmd); -}); - -sherlock!(ignore_ripgrep, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| { - wd.create(".rgignore", "sherlock\n"); - wd.assert_err(&mut cmd); -}); - -sherlock!(no_ignore, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| { - wd.create(".gitignore", "sherlock\n"); - cmd.arg("--no-ignore"); - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -sherlock:For the Doctor Watsons of this world, as opposed to the Sherlock -sherlock:be, to a very large extent, the result of luck. Sherlock Holmes -"; - assert_eq!(lines, expected); -}); - -sherlock!(ignore_git_parent, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| { - wd.remove("sherlock"); - wd.create(".gitignore", "sherlock\n"); - wd.create_dir(".git"); - wd.create_dir("foo"); - wd.create("foo/sherlock", hay::SHERLOCK); - // Even though we search in foo/, which has no .gitignore, ripgrep will - // search parent directories and respect the gitignore files found. - cmd.current_dir(wd.path().join("foo")); - wd.assert_err(&mut cmd); -}); - -sherlock!(ignore_git_parent_stop, "Sherlock", ".", -|wd: WorkDir, mut cmd: Command| { - // This tests that searching parent directories for .gitignore files stops - // after it sees a .git directory. To test this, we create this directory - // hierarchy: - // - // .gitignore (contains `sherlock`) - // foo/ - // .git/ - // bar/ - // sherlock - // - // And we perform the search inside `foo/bar/`. ripgrep will stop looking - // for .gitignore files after it sees `foo/.git/`, and therefore not - // respect the top-level `.gitignore` containing `sherlock`. - wd.remove("sherlock"); - wd.create(".gitignore", "sherlock\n"); - wd.create_dir("foo"); - wd.create_dir("foo/.git"); - wd.create_dir("foo/bar"); - wd.create("foo/bar/sherlock", hay::SHERLOCK); - cmd.current_dir(wd.path().join("foo").join("bar")); - - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -sherlock:For the Doctor Watsons of this world, as opposed to the Sherlock -sherlock:be, to a very large extent, the result of luck. Sherlock Holmes -"; - assert_eq!(lines, expected); -}); - -// Like ignore_git_parent_stop, but with a .git file instead of a .git -// directory. -sherlock!(ignore_git_parent_stop_file, "Sherlock", ".", -|wd: WorkDir, mut cmd: Command| { - // This tests that searching parent directories for .gitignore files stops - // after it sees a .git *file*. A .git file is used for submodules. To test - // this, we create this directory hierarchy: - // - // .gitignore (contains `sherlock`) - // foo/ - // .git - // bar/ - // sherlock - // - // And we perform the search inside `foo/bar/`. ripgrep will stop looking - // for .gitignore files after it sees `foo/.git`, and therefore not - // respect the top-level `.gitignore` containing `sherlock`. - wd.remove("sherlock"); - wd.create(".gitignore", "sherlock\n"); - wd.create_dir("foo"); - wd.create("foo/.git", ""); - wd.create_dir("foo/bar"); - wd.create("foo/bar/sherlock", hay::SHERLOCK); - cmd.current_dir(wd.path().join("foo").join("bar")); - - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -sherlock:For the Doctor Watsons of this world, as opposed to the Sherlock -sherlock:be, to a very large extent, the result of luck. Sherlock Holmes -"; - assert_eq!(lines, expected); -}); - -sherlock!(ignore_ripgrep_parent_no_stop, "Sherlock", ".", -|wd: WorkDir, mut cmd: Command| { - // This is like the `ignore_git_parent_stop` test, except it checks that - // ripgrep *doesn't* stop checking for .rgignore files. - wd.remove("sherlock"); - wd.create(".rgignore", "sherlock\n"); - wd.create_dir("foo"); - wd.create_dir("foo/.git"); - wd.create_dir("foo/bar"); - wd.create("foo/bar/sherlock", hay::SHERLOCK); - cmd.current_dir(wd.path().join("foo").join("bar")); - // The top-level .rgignore applies. - wd.assert_err(&mut cmd); -}); - -sherlock!(no_parent_ignore_git, "Sherlock", ".", -|wd: WorkDir, mut cmd: Command| { - // Set up a directory hierarchy like this: - // - // .gitignore - // foo/ - // .gitignore - // sherlock - // watson - // - // Where `.gitignore` contains `sherlock` and `foo/.gitignore` contains - // `watson`. - // - // Now *do the search* from the foo directory. By default, ripgrep will - // search parent directories for .gitignore files. The --no-ignore-parent - // flag should prevent that. At the same time, the `foo/.gitignore` file - // will still be respected (since the search is happening in `foo/`). - // - // In other words, we should only see results from `sherlock`, not from - // `watson`. - wd.remove("sherlock"); - wd.create(".gitignore", "sherlock\n"); - wd.create_dir("foo"); - wd.create("foo/.gitignore", "watson\n"); - wd.create("foo/sherlock", hay::SHERLOCK); - wd.create("foo/watson", hay::SHERLOCK); - cmd.current_dir(wd.path().join("foo")); - cmd.arg("--no-ignore-parent"); - - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -sherlock:For the Doctor Watsons of this world, as opposed to the Sherlock -sherlock:be, to a very large extent, the result of luck. Sherlock Holmes -"; - assert_eq!(lines, expected); -}); - -#[cfg(not(windows))] -sherlock!(symlink_nofollow, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| { - wd.remove("sherlock"); - wd.create_dir("foo"); - wd.create_dir("foo/bar"); - wd.link_dir("foo/baz", "foo/bar/baz"); - wd.create_dir("foo/baz"); - wd.create("foo/baz/sherlock", hay::SHERLOCK); - cmd.current_dir(wd.path().join("foo/bar")); - wd.assert_err(&mut cmd); -}); - -#[cfg(not(windows))] -sherlock!(symlink_follow, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| { - wd.remove("sherlock"); - wd.create_dir("foo"); - wd.create_dir("foo/bar"); - wd.create_dir("foo/baz"); - wd.create("foo/baz/sherlock", hay::SHERLOCK); - wd.link_dir("foo/baz", "foo/bar/baz"); - cmd.arg("-L"); - cmd.current_dir(wd.path().join("foo/bar")); - - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -baz/sherlock:For the Doctor Watsons of this world, as opposed to the Sherlock -baz/sherlock:be, to a very large extent, the result of luck. Sherlock Holmes -"; - assert_eq!(lines, path(expected)); -}); - -sherlock!(unrestricted1, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| { - wd.create(".gitignore", "sherlock\n"); - cmd.arg("-u"); - - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -sherlock:For the Doctor Watsons of this world, as opposed to the Sherlock -sherlock:be, to a very large extent, the result of luck. Sherlock Holmes -"; - assert_eq!(lines, expected); -}); - -sherlock!(unrestricted2, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| { - wd.remove("sherlock"); - wd.create(".sherlock", hay::SHERLOCK); - cmd.arg("-uu"); - - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -.sherlock:For the Doctor Watsons of this world, as opposed to the Sherlock -.sherlock:be, to a very large extent, the result of luck. Sherlock Holmes -"; - assert_eq!(lines, expected); -}); - -sherlock!(unrestricted3, "foo", ".", |wd: WorkDir, mut cmd: Command| { - wd.create("file", "foo\x00bar\nfoo\x00baz\n"); - cmd.arg("-uuu"); - - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "file:foo\x00bar\nfile:foo\x00baz\n"); -}); - -sherlock!(vimgrep, "Sherlock|Watson", ".", |wd: WorkDir, mut cmd: Command| { - cmd.arg("--vimgrep"); - - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -sherlock:1:16:For the Doctor Watsons of this world, as opposed to the Sherlock -sherlock:1:57:For the Doctor Watsons of this world, as opposed to the Sherlock -sherlock:3:49:be, to a very large extent, the result of luck. Sherlock Holmes -sherlock:5:12:but Doctor Watson has to have it taken out for him and dusted, -"; - assert_eq!(lines, expected); -}); - -sherlock!(vimgrep_no_line, "Sherlock|Watson", ".", -|wd: WorkDir, mut cmd: Command| { - cmd.arg("--vimgrep").arg("-N"); - - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -sherlock:16:For the Doctor Watsons of this world, as opposed to the Sherlock -sherlock:57:For the Doctor Watsons of this world, as opposed to the Sherlock -sherlock:49:be, to a very large extent, the result of luck. Sherlock Holmes -sherlock:12:but Doctor Watson has to have it taken out for him and dusted, -"; - assert_eq!(lines, expected); -}); - -sherlock!(vimgrep_no_line_no_column, "Sherlock|Watson", ".", -|wd: WorkDir, mut cmd: Command| { - cmd.arg("--vimgrep").arg("-N").arg("--no-column"); - - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -sherlock:For the Doctor Watsons of this world, as opposed to the Sherlock -sherlock:For the Doctor Watsons of this world, as opposed to the Sherlock -sherlock:be, to a very large extent, the result of luck. Sherlock Holmes -sherlock:but Doctor Watson has to have it taken out for him and dusted, -"; - assert_eq!(lines, expected); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/16 -clean!(regression_16, "xyz", ".", |wd: WorkDir, mut cmd: Command| { - wd.create(".gitignore", "ghi/"); - wd.create_dir("ghi"); - wd.create_dir("def/ghi"); - wd.create("ghi/toplevel.txt", "xyz"); - wd.create("def/ghi/subdir.txt", "xyz"); - wd.assert_err(&mut cmd); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/25 -clean!(regression_25, "test", ".", |wd: WorkDir, mut cmd: Command| { - wd.create(".gitignore", "/llvm/"); - wd.create_dir("src/llvm"); - wd.create("src/llvm/foo", "test"); - - let lines: String = wd.stdout(&mut cmd); - let expected = path("src/llvm/foo:test\n"); - assert_eq!(lines, expected); - - cmd.current_dir(wd.path().join("src")); - let lines: String = wd.stdout(&mut cmd); - let expected = path("llvm/foo:test\n"); - assert_eq!(lines, expected); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/30 -clean!(regression_30, "test", ".", |wd: WorkDir, mut cmd: Command| { - wd.create(".gitignore", "vendor/**\n!vendor/manifest"); - wd.create_dir("vendor"); - wd.create("vendor/manifest", "test"); - - let lines: String = wd.stdout(&mut cmd); - let expected = path("vendor/manifest:test\n"); - assert_eq!(lines, expected); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/49 -clean!(regression_49, "xyz", ".", |wd: WorkDir, mut cmd: Command| { - wd.create(".gitignore", "foo/bar"); - wd.create_dir("test/foo/bar"); - wd.create("test/foo/bar/baz", "test"); - wd.assert_err(&mut cmd); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/50 -clean!(regression_50, "xyz", ".", |wd: WorkDir, mut cmd: Command| { - wd.create(".gitignore", "XXX/YYY/"); - wd.create_dir("abc/def/XXX/YYY"); - wd.create_dir("ghi/XXX/YYY"); - wd.create("abc/def/XXX/YYY/bar", "test"); - wd.create("ghi/XXX/YYY/bar", "test"); - wd.assert_err(&mut cmd); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/65 -clean!(regression_65, "xyz", ".", |wd: WorkDir, mut cmd: Command| { - wd.create(".gitignore", "a/"); - wd.create_dir("a"); - wd.create("a/foo", "xyz"); - wd.create("a/bar", "xyz"); - wd.assert_err(&mut cmd); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/67 -clean!(regression_67, "test", ".", |wd: WorkDir, mut cmd: Command| { - wd.create(".gitignore", "/*\n!/dir"); - wd.create_dir("dir"); - wd.create_dir("foo"); - wd.create("foo/bar", "test"); - wd.create("dir/bar", "test"); - - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, path("dir/bar:test\n")); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/87 -clean!(regression_87, "test", ".", |wd: WorkDir, mut cmd: Command| { - wd.create(".gitignore", "foo\n**no-vcs**"); - wd.create("foo", "test"); - wd.assert_err(&mut cmd); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/90 -clean!(regression_90, "test", ".", |wd: WorkDir, mut cmd: Command| { - wd.create(".gitignore", "!.foo"); - wd.create(".foo", "test"); - - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, ".foo:test\n"); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/93 -clean!(regression_93, r"(\d{1,3}\.){3}\d{1,3}", ".", -|wd: WorkDir, mut cmd: Command| { - wd.create("foo", "192.168.1.1"); - - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "foo:192.168.1.1\n"); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/99 -clean!(regression_99, "test", ".", -|wd: WorkDir, mut cmd: Command| { - wd.create("foo1", "test"); - wd.create("foo2", "zzz"); - wd.create("bar", "test"); - cmd.arg("-j1").arg("--heading"); - - let lines: String = wd.stdout(&mut cmd); - assert_eq!(sort_lines(&lines), sort_lines("bar\ntest\n\nfoo1\ntest\n")); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/105 -clean!(regression_105_part1, "test", ".", |wd: WorkDir, mut cmd: Command| { - wd.create("foo", "zztest"); - cmd.arg("--vimgrep"); - - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "foo:1:3:zztest\n"); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/105 -clean!(regression_105_part2, "test", ".", |wd: WorkDir, mut cmd: Command| { - wd.create("foo", "zztest"); - cmd.arg("--column"); - - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "foo:1:3:zztest\n"); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/127 -clean!(regression_127, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| { - // Set up a directory hierarchy like this: - // - // .gitignore - // foo/ - // sherlock - // watson - // - // Where `.gitignore` contains `foo/sherlock`. - // - // ripgrep should ignore 'foo/sherlock' giving us results only from - // 'foo/watson' but on Windows ripgrep will include both 'foo/sherlock' and - // 'foo/watson' in the search results. - wd.create(".gitignore", "foo/sherlock\n"); - wd.create_dir("foo"); - wd.create("foo/sherlock", hay::SHERLOCK); - wd.create("foo/watson", hay::SHERLOCK); - - let lines: String = wd.stdout(&mut cmd); - let expected = format!("\ -{path}:For the Doctor Watsons of this world, as opposed to the Sherlock -{path}:be, to a very large extent, the result of luck. Sherlock Holmes -", path=path("foo/watson")); - assert_eq!(lines, expected); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/128 -clean!(regression_128, "x", ".", |wd: WorkDir, mut cmd: Command| { - wd.create_bytes("foo", b"01234567\x0b\n\x0b\n\x0b\n\x0b\nx"); - cmd.arg("-n"); - - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "foo:5:x\n"); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/131 -// -// TODO(burntsushi): Darwin doesn't like this test for some reason. -#[cfg(not(target_os = "macos"))] -clean!(regression_131, "test", ".", |wd: WorkDir, mut cmd: Command| { - wd.create(".gitignore", "TopÑapa"); - wd.create("TopÑapa", "test"); - wd.assert_err(&mut cmd); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/137 -// -// TODO(burntsushi): Figure out why Windows gives "access denied" errors -// when trying to create a file symlink. For now, disable test on Windows. -#[cfg(not(windows))] -sherlock!(regression_137, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| { - wd.link_file("sherlock", "sym1"); - wd.link_file("sherlock", "sym2"); - cmd.arg("sym1"); - cmd.arg("sym2"); - cmd.arg("-j1"); - - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -sherlock:For the Doctor Watsons of this world, as opposed to the Sherlock -sherlock:be, to a very large extent, the result of luck. Sherlock Holmes -sym1:For the Doctor Watsons of this world, as opposed to the Sherlock -sym1:be, to a very large extent, the result of luck. Sherlock Holmes -sym2:For the Doctor Watsons of this world, as opposed to the Sherlock -sym2:be, to a very large extent, the result of luck. Sherlock Holmes -"; - assert_eq!(lines, path(expected)); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/156 -clean!( - regression_156, - r#"#(?:parse|include)\s*\(\s*(?:"|')[./A-Za-z_-]+(?:"|')"#, - "testcase.txt", -|wd: WorkDir, mut cmd: Command| { - const TESTCASE: &'static str = r#"#parse('widgets/foo_bar_macros.vm') -#parse ( 'widgets/mobile/foo_bar_macros.vm' ) -#parse ("widgets/foobarhiddenformfields.vm") -#parse ( "widgets/foo_bar_legal.vm" ) -#include( 'widgets/foo_bar_tips.vm' ) -#include('widgets/mobile/foo_bar_macros.vm') -#include ("widgets/mobile/foo_bar_resetpw.vm") -#parse('widgets/foo-bar-macros.vm') -#parse ( 'widgets/mobile/foo-bar-macros.vm' ) -#parse ("widgets/foo-bar-hiddenformfields.vm") -#parse ( "widgets/foo-bar-legal.vm" ) -#include( 'widgets/foo-bar-tips.vm' ) -#include('widgets/mobile/foo-bar-macros.vm') -#include ("widgets/mobile/foo-bar-resetpw.vm") -"#; - wd.create("testcase.txt", TESTCASE); - cmd.arg("-N"); - - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, TESTCASE); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/184 -clean!(regression_184, "test", ".", |wd: WorkDir, mut cmd: Command| { - wd.create(".gitignore", ".*"); - wd.create_dir("foo/bar"); - wd.create("foo/bar/baz", "test"); - - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, format!("{}:test\n", path("foo/bar/baz"))); - - cmd.current_dir(wd.path().join("./foo/bar")); - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "baz:test\n"); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/199 -clean!(regression_199, r"\btest\b", ".", |wd: WorkDir, mut cmd: Command| { - wd.create("foo", "tEsT"); - cmd.arg("--smart-case"); - - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "foo:tEsT\n"); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/206 -clean!(regression_206, "test", ".", |wd: WorkDir, mut cmd: Command| { - wd.create_dir("foo"); - wd.create("foo/bar.txt", "test"); - cmd.arg("-g").arg("*.txt"); - - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, format!("{}:test\n", path("foo/bar.txt"))); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/210 -#[cfg(unix)] -#[test] -fn regression_210() { - use std::ffi::OsStr; - use std::os::unix::ffi::OsStrExt; - - let badutf8 = OsStr::from_bytes(&b"foo\xffbar"[..]); - - let wd = WorkDir::new("regression_210"); - // APFS does not support creating files with invalid UTF-8 bytes. - // https://github.com/BurntSushi/ripgrep/issues/559 - if wd.try_create(badutf8, "test").is_ok() { - let mut cmd = wd.command(); - cmd.arg("-H").arg("test").arg(badutf8); - - let out = wd.output(&mut cmd); - assert_eq!(out.stdout, b"foo\xffbar:test\n".to_vec()); - } -} - -// See: https://github.com/BurntSushi/ripgrep/issues/228 -clean!(regression_228, "test", ".", |wd: WorkDir, mut cmd: Command| { - wd.create_dir("foo"); - cmd.arg("--ignore-file").arg("foo"); - wd.assert_err(&mut cmd); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/229 -clean!(regression_229, "[E]conomie", ".", |wd: WorkDir, mut cmd: Command| { - wd.create("foo", "economie"); - cmd.arg("-S"); - wd.assert_err(&mut cmd); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/251 -clean!(regression_251, "привет", ".", |wd: WorkDir, mut cmd: Command| { - wd.create("foo", "привет\nПривет\nПрИвЕт"); - cmd.arg("-i"); - - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "foo:привет\nfoo:Привет\nfoo:ПрИвЕт\n"); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/256 -#[cfg(not(windows))] -clean!(regression_256, "test", "foo", |wd: WorkDir, mut cmd: Command| { - wd.create_dir("bar"); - wd.create("bar/baz", "test"); - wd.link_dir("bar", "foo"); - - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "foo/baz:test\n"); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/256 -#[cfg(not(windows))] -clean!(regression_256_j1, "test", "foo", |wd: WorkDir, mut cmd: Command| { - wd.create_dir("bar"); - wd.create("bar/baz", "test"); - wd.link_dir("bar", "foo"); - cmd.arg("-j1"); - - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "foo/baz:test\n"); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/279 -clean!(regression_279, "test", ".", |wd: WorkDir, mut cmd: Command| { - wd.create("foo", "test"); - cmd.arg("-q"); - - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, ""); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/405 -clean!(regression_405, "test", ".", |wd: WorkDir, mut cmd: Command| { - wd.create_dir("foo/bar"); - wd.create_dir("bar/foo"); - wd.create("foo/bar/file1.txt", "test"); - wd.create("bar/foo/file2.txt", "test"); - cmd.arg("-g").arg("!/foo/**"); - - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, format!("{}:test\n", path("bar/foo/file2.txt"))); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/428 -#[cfg(not(windows))] -clean!(regression_428_color_context_path, "foo", ".", -|wd: WorkDir, mut cmd: Command| { - wd.create("sherlock", "foo\nbar"); - cmd.arg("-A1").arg("-H").arg("--no-heading").arg("-N") - .arg("--colors=match:none").arg("--color=always"); - - let lines: String = wd.stdout(&mut cmd); - let expected = format!( - "{colored_path}:foo\n{colored_path}-bar\n", - colored_path=format!( - "\x1b\x5b\x30\x6d\x1b\x5b\x33\x35\x6d{path}\x1b\x5b\x30\x6d", - path=path("sherlock"))); - assert_eq!(lines, expected); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/428 -clean!(regression_428_unrecognized_style, "Sherlok", ".", -|wd: WorkDir, mut cmd: Command| { - cmd.arg("--colors=match:style:"); - wd.assert_err(&mut cmd); - - let output = cmd.output().unwrap(); - let err = String::from_utf8_lossy(&output.stderr); - let expected = "\ -Unrecognized style attribute ''. Choose from: nobold, bold, nointense, intense, \ -nounderline, underline. -"; - assert_eq!(err, expected); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/493 -clean!(regression_493, " 're ", "input.txt", |wd: WorkDir, mut cmd: Command| { - wd.create("input.txt", "peshwaship 're seminomata"); - cmd.arg("-o").arg("-w"); - - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, " 're \n"); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/553 -sherlock!(regression_553_switch, "sherlock", ".", -|wd: WorkDir, mut cmd: Command| { - cmd.arg("-i"); - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -sherlock:For the Doctor Watsons of this world, as opposed to the Sherlock -sherlock:be, to a very large extent, the result of luck. Sherlock Holmes -"; - assert_eq!(lines, expected); - - // This repeats the `-i` flag. - cmd.arg("-i"); - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -sherlock:For the Doctor Watsons of this world, as opposed to the Sherlock -sherlock:be, to a very large extent, the result of luck. Sherlock Holmes -"; - assert_eq!(lines, expected); -}); - -sherlock!(regression_553_flag, "world|attached", -|wd: WorkDir, mut cmd: Command| { - cmd.arg("-C").arg("1"); - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -For the Doctor Watsons of this world, as opposed to the Sherlock -Holmeses, success in the province of detective work must always --- -but Doctor Watson has to have it taken out for him and dusted, -and exhibited clearly, with a label attached. -"; - assert_eq!(lines, expected); - - cmd.arg("-C").arg("0"); - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -For the Doctor Watsons of this world, as opposed to the Sherlock -and exhibited clearly, with a label attached. -"; - assert_eq!(lines, expected); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/599 -clean!(regression_599, "^$", "input.txt", |wd: WorkDir, mut cmd: Command| { - wd.create("input.txt", "\n\ntest\n"); - cmd.args(&[ - "--color", "ansi", - "--colors", "path:none", - "--colors", "line:none", - "--colors", "match:fg:red", - "--colors", "match:style:nobold", - "--line-number", - ]); - - let lines: String = wd.stdout(&mut cmd); - // Technically, the expected output should only be two lines, but: - // https://github.com/BurntSushi/ripgrep/issues/441 - let expected = "\ -1: -2: -4: -"; - assert_eq!(expected, lines); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/807 -clean!(regression_807, "test", ".", |wd: WorkDir, mut cmd: Command| { - wd.create(".gitignore", ".a/b"); - wd.create_dir(".a/b"); - wd.create_dir(".a/c"); - wd.create(".a/b/file", "test"); - wd.create(".a/c/file", "test"); - - cmd.arg("--hidden"); - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, format!("{}:test\n", path(".a/c/file"))); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/1 -clean!(feature_1_sjis, "Шерлок Холмс", ".", |wd: WorkDir, mut cmd: Command| { - let sherlock = - b"\x84Y\x84u\x84\x82\x84|\x84\x80\x84{ \x84V\x84\x80\x84|\x84}\x84\x83"; - wd.create_bytes("foo", &sherlock[..]); - cmd.arg("-Esjis"); - - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "foo:Шерлок Холмс\n"); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/1 -clean!(feature_1_utf16_auto, "Шерлок Холмс", ".", -|wd: WorkDir, mut cmd: Command| { - let sherlock = - b"\xff\xfe(\x045\x04@\x04;\x04>\x04:\x04 \x00%\x04>\x04;\x04<\x04A\x04"; - wd.create_bytes("foo", &sherlock[..]); - - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "foo:Шерлок Холмс\n"); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/1 -clean!(feature_1_utf16_explicit, "Шерлок Холмс", ".", -|wd: WorkDir, mut cmd: Command| { - let sherlock = - b"\xff\xfe(\x045\x04@\x04;\x04>\x04:\x04 \x00%\x04>\x04;\x04<\x04A\x04"; - wd.create_bytes("foo", &sherlock[..]); - cmd.arg("-Eutf-16le"); - - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "foo:Шерлок Холмс\n"); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/1 -clean!(feature_1_eucjp, "Шерлок Холмс", ".", -|wd: WorkDir, mut cmd: Command| { - let sherlock = - b"\xa7\xba\xa7\xd6\xa7\xe2\xa7\xdd\xa7\xe0\xa7\xdc \xa7\xb7\xa7\xe0\xa7\xdd\xa7\xde\xa7\xe3"; - wd.create_bytes("foo", &sherlock[..]); - cmd.arg("-Eeuc-jp"); - - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "foo:Шерлок Холмс\n"); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/1 -sherlock!(feature_1_unknown_encoding, "Sherlock", ".", -|wd: WorkDir, mut cmd: Command| { - cmd.arg("-Efoobar"); - wd.assert_non_empty_stderr(&mut cmd); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/1 -// Specific: https://github.com/BurntSushi/ripgrep/pull/398/files#r111109265 -sherlock!(feature_1_replacement_encoding, "Sherlock", ".", -|wd: WorkDir, mut cmd: Command| { - cmd.arg("-Ecsiso2022kr"); - wd.assert_non_empty_stderr(&mut cmd); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/7 -sherlock!(feature_7, "-fpat", "sherlock", |wd: WorkDir, mut cmd: Command| { - wd.create("pat", "Sherlock\nHolmes"); - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -For the Doctor Watsons of this world, as opposed to the Sherlock -Holmeses, success in the province of detective work must always -be, to a very large extent, the result of luck. Sherlock Holmes -"; - assert_eq!(lines, expected); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/7 -sherlock!(feature_7_dash, "-f-", ".", |wd: WorkDir, mut cmd: Command| { - let output = wd.pipe(&mut cmd, "Sherlock"); - let lines = String::from_utf8_lossy(&output.stdout); - let expected = "\ -sherlock:For the Doctor Watsons of this world, as opposed to the Sherlock -sherlock:be, to a very large extent, the result of luck. Sherlock Holmes -"; - assert_eq!(lines, expected); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/20 -sherlock!(feature_20_no_filename, "Sherlock", ".", -|wd: WorkDir, mut cmd: Command| { - cmd.arg("--no-filename"); - - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -For the Doctor Watsons of this world, as opposed to the Sherlock -be, to a very large extent, the result of luck. Sherlock Holmes -"; - assert_eq!(lines, expected); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/34 -sherlock!(feature_34_only_matching, "Sherlock", ".", -|wd: WorkDir, mut cmd: Command| { - cmd.arg("--only-matching"); - - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -sherlock:Sherlock -sherlock:Sherlock -"; - assert_eq!(lines, expected); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/34 -sherlock!(feature_34_only_matching_line_column, "Sherlock", ".", -|wd: WorkDir, mut cmd: Command| { - cmd.arg("--only-matching").arg("--column").arg("--line-number"); - - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -sherlock:1:57:Sherlock -sherlock:3:49:Sherlock -"; - assert_eq!(lines, expected); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/45 -sherlock!(feature_45_relative_cwd, "test", ".", -|wd: WorkDir, mut cmd: Command| { - wd.create(".not-an-ignore", "foo\n/bar"); - wd.create_dir("bar"); - wd.create_dir("baz/bar"); - wd.create_dir("baz/baz/bar"); - wd.create("bar/test", "test"); - wd.create("baz/bar/test", "test"); - wd.create("baz/baz/bar/test", "test"); - wd.create("baz/foo", "test"); - wd.create("baz/test", "test"); - wd.create("foo", "test"); - wd.create("test", "test"); - - // First, get a baseline without applying ignore rules. - let lines = paths_from_stdout(wd.stdout(&mut cmd)); - assert_eq!(lines, paths(&[ - "bar/test", "baz/bar/test", "baz/baz/bar/test", "baz/foo", - "baz/test", "foo", "test", - ])); - - // Now try again with the ignore file activated. - cmd.arg("--ignore-file").arg(".not-an-ignore"); - let lines = paths_from_stdout(wd.stdout(&mut cmd)); - assert_eq!(lines, paths(&[ - "baz/bar/test", "baz/baz/bar/test", "baz/test", "test", - ])); - - // Now do it again, but inside the baz directory. - // Since the ignore file is interpreted relative to the CWD, this will - // cause the /bar anchored pattern to filter out baz/bar, which is a - // subtle difference between true parent ignore files and manually - // specified ignore files. - let mut cmd = wd.command(); - cmd.arg("test").arg(".").arg("--ignore-file").arg("../.not-an-ignore"); - cmd.current_dir(wd.path().join("baz")); - let lines = paths_from_stdout(wd.stdout(&mut cmd)); - assert_eq!(lines, paths(&["baz/bar/test", "test"])); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/45 -sherlock!(feature_45_precedence_with_others, "test", ".", -|wd: WorkDir, mut cmd: Command| { - wd.create(".not-an-ignore", "*.log"); - wd.create(".ignore", "!imp.log"); - wd.create("imp.log", "test"); - wd.create("wat.log", "test"); - - cmd.arg("--ignore-file").arg(".not-an-ignore"); - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "imp.log:test\n"); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/45 -sherlock!(feature_45_precedence_internal, "test", ".", -|wd: WorkDir, mut cmd: Command| { - wd.create(".not-an-ignore1", "*.log"); - wd.create(".not-an-ignore2", "!imp.log"); - wd.create("imp.log", "test"); - wd.create("wat.log", "test"); - - cmd.arg("--ignore-file").arg(".not-an-ignore1"); - cmd.arg("--ignore-file").arg(".not-an-ignore2"); - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "imp.log:test\n"); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/68 -clean!(feature_68_no_ignore_vcs, "test", ".", |wd: WorkDir, mut cmd: Command| { - wd.create(".gitignore", "foo"); - wd.create(".ignore", "bar"); - wd.create("foo", "test"); - wd.create("bar", "test"); - cmd.arg("--no-ignore-vcs"); - - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "foo:test\n"); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/70 -sherlock!(feature_70_smart_case, "sherlock", ".", -|wd: WorkDir, mut cmd: Command| { - cmd.arg("--smart-case"); - - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -sherlock:For the Doctor Watsons of this world, as opposed to the Sherlock -sherlock:be, to a very large extent, the result of luck. Sherlock Holmes -"; - assert_eq!(lines, expected); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/89 -sherlock!(feature_89_files_with_matches, "Sherlock", ".", -|wd: WorkDir, mut cmd: Command| { - cmd.arg("--null").arg("--files-with-matches"); - - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "sherlock\x00"); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/89 -sherlock!(feature_89_files_without_matches, "Sherlock", ".", -|wd: WorkDir, mut cmd: Command| { - wd.create("file.py", "foo"); - cmd.arg("--null").arg("--files-without-match"); - - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "file.py\x00"); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/89 -sherlock!(feature_89_count, "Sherlock", ".", -|wd: WorkDir, mut cmd: Command| { - cmd.arg("--null").arg("--count"); - - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "sherlock\x002\n"); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/89 -sherlock!(feature_89_files, "NADA", ".", -|wd: WorkDir, mut cmd: Command| { - cmd.arg("--null").arg("--files"); - - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "sherlock\x00"); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/89 -sherlock!(feature_89_match, "Sherlock", ".", -|wd: WorkDir, mut cmd: Command| { - cmd.arg("--null").arg("-C1"); - - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -sherlock\x00For the Doctor Watsons of this world, as opposed to the Sherlock -sherlock\x00Holmeses, success in the province of detective work must always -sherlock\x00be, to a very large extent, the result of luck. Sherlock Holmes -sherlock\x00can extract a clew from a wisp of straw or a flake of cigar ash; -"; - assert_eq!(lines, expected); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/109 -clean!(feature_109_max_depth, "far", ".", |wd: WorkDir, mut cmd: Command| { - wd.create_dir("one"); - wd.create("one/pass", "far"); - wd.create_dir("one/too"); - wd.create("one/too/many", "far"); - - cmd.arg("--maxdepth").arg("2"); - - let lines: String = wd.stdout(&mut cmd); - let expected = path("one/pass:far\n"); - assert_eq!(lines, expected); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/124 -clean!(feature_109_case_sensitive_part1, "test", ".", -|wd: WorkDir, mut cmd: Command| { - wd.create("foo", "tEsT"); - cmd.arg("--smart-case").arg("--case-sensitive"); - wd.assert_err(&mut cmd); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/124 -clean!(feature_109_case_sensitive_part2, "test", ".", -|wd: WorkDir, mut cmd: Command| { - wd.create("foo", "tEsT"); - cmd.arg("--ignore-case").arg("--case-sensitive"); - wd.assert_err(&mut cmd); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/129 -clean!(feature_129_matches, "test", ".", |wd: WorkDir, mut cmd: Command| { - wd.create("foo", "test\ntest abcdefghijklmnopqrstuvwxyz test"); - cmd.arg("-M26"); - - let lines: String = wd.stdout(&mut cmd); - let expected = "foo:test\nfoo:[Omitted long line with 2 matches]\n"; - assert_eq!(lines, expected); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/129 -clean!(feature_129_context, "test", ".", |wd: WorkDir, mut cmd: Command| { - wd.create("foo", "test\nabcdefghijklmnopqrstuvwxyz"); - cmd.arg("-M20").arg("-C1"); - - let lines: String = wd.stdout(&mut cmd); - let expected = "foo:test\nfoo-[Omitted long context line]\n"; - assert_eq!(lines, expected); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/129 -clean!(feature_129_replace, "test", ".", |wd: WorkDir, mut cmd: Command| { - wd.create("foo", "test\ntest abcdefghijklmnopqrstuvwxyz test"); - cmd.arg("-M26").arg("-rfoo"); - - let lines: String = wd.stdout(&mut cmd); - let expected = "foo:foo\nfoo:[Omitted long line with 2 replacements]\n"; - assert_eq!(lines, expected); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/159 -clean!(feature_159_works, "test", ".", |wd: WorkDir, mut cmd: Command| { - wd.create("foo", "test\ntest"); - cmd.arg("-m1"); - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "foo:test\n"); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/159 -clean!(feature_159_zero_max, "test", ".", |wd: WorkDir, mut cmd: Command| { - wd.create("foo", "test\ntest"); - cmd.arg("-m0"); - wd.assert_err(&mut cmd); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/243 -clean!(feature_243_column_line, "test", ".", |wd: WorkDir, mut cmd: Command| { - wd.create("foo", "test"); - cmd.arg("--column"); - - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "foo:1:1:test\n"); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/263 -clean!(feature_263_sort_files, "test", ".", |wd: WorkDir, mut cmd: Command| { - wd.create("foo", "test"); - wd.create("abc", "test"); - wd.create("zoo", "test"); - wd.create("bar", "test"); - cmd.arg("--sort-files"); - - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "abc:test\nbar:test\nfoo:test\nzoo:test\n"); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/275 -clean!(feature_275_pathsep, "test", ".", |wd: WorkDir, mut cmd: Command| { - wd.create_dir("foo"); - wd.create("foo/bar", "test"); - cmd.arg("--path-separator").arg("Z"); - - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "fooZbar:test\n"); -}); - -// See: https://github.com/BurntSushi/ripgrep/issues/362 -sherlock!(feature_362_dfa_size_limit, r"For\s", -|wd: WorkDir, mut cmd: Command| { - // This should fall back to the nfa engine but should still produce the - // expected result. - cmd.arg("--dfa-size-limit").arg("10"); - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -For the Doctor Watsons of this world, as opposed to the Sherlock -"; - assert_eq!(lines, expected); -}); - -sherlock!(feature_362_exceeds_regex_size_limit, r"[0-9]\w+", -|wd: WorkDir, mut cmd: Command| { - cmd.arg("--regex-size-limit").arg("10K"); - wd.assert_err(&mut cmd); -}); - -#[cfg(target_pointer_width = "32")] -sherlock!(feature_362_u64_to_narrow_usize_suffix_overflow, "Sherlock", ".", -|wd: WorkDir, mut cmd: Command| { - wd.remove("sherlock"); - wd.create_size("foo", 1000000); - - // 2^35 * 2^20 is ok for u64, but not for usize - cmd.arg("--dfa-size-limit").arg("34359738368M").arg("--files"); - wd.assert_err(&mut cmd); -}); - - -// See: https://github.com/BurntSushi/ripgrep/issues/419 -sherlock!(feature_419_zero_as_shortcut_for_null, "Sherlock", ".", -|wd: WorkDir, mut cmd: Command| { - cmd.arg("-0").arg("--count"); - - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "sherlock\x002\n"); -}); - -#[test] -fn compressed_gzip() { - if !cmd_exists("gzip") { - return; - } - let gzip_file = include_bytes!("./data/sherlock.gz"); - - let wd = WorkDir::new("feature_search_compressed"); - wd.create_bytes("sherlock.gz", gzip_file); - - let mut cmd = wd.command(); - cmd.arg("-z").arg("Sherlock").arg("sherlock.gz"); - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -For the Doctor Watsons of this world, as opposed to the Sherlock -be, to a very large extent, the result of luck. Sherlock Holmes -"; - assert_eq!(lines, expected); -} - -#[test] -fn compressed_bzip2() { - if !cmd_exists("bzip2") { - return; - } - let bzip2_file = include_bytes!("./data/sherlock.bz2"); - - let wd = WorkDir::new("feature_search_compressed"); - wd.create_bytes("sherlock.bz2", bzip2_file); - - let mut cmd = wd.command(); - cmd.arg("-z").arg("Sherlock").arg("sherlock.bz2"); - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -For the Doctor Watsons of this world, as opposed to the Sherlock -be, to a very large extent, the result of luck. Sherlock Holmes -"; - assert_eq!(lines, expected); -} - -#[test] -fn compressed_xz() { - if !cmd_exists("xz") { - return; - } - let xz_file = include_bytes!("./data/sherlock.xz"); - - let wd = WorkDir::new("feature_search_compressed"); - wd.create_bytes("sherlock.xz", xz_file); - - let mut cmd = wd.command(); - cmd.arg("-z").arg("Sherlock").arg("sherlock.xz"); - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -For the Doctor Watsons of this world, as opposed to the Sherlock -be, to a very large extent, the result of luck. Sherlock Holmes -"; - assert_eq!(lines, expected); -} - -#[test] -fn compressed_lzma() { - if !cmd_exists("xz") { - return; - } - let lzma_file = include_bytes!("./data/sherlock.lzma"); - - let wd = WorkDir::new("feature_search_compressed"); - wd.create_bytes("sherlock.lzma", lzma_file); - - let mut cmd = wd.command(); - cmd.arg("-z").arg("Sherlock").arg("sherlock.lzma"); - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -For the Doctor Watsons of this world, as opposed to the Sherlock -be, to a very large extent, the result of luck. Sherlock Holmes -"; - assert_eq!(lines, expected); -} - -#[test] -fn compressed_failing_gzip() { - if !cmd_exists("gzip") { - return; - } - let wd = WorkDir::new("feature_search_compressed"); - wd.create("sherlock.gz", hay::SHERLOCK); - - let mut cmd = wd.command(); - cmd.arg("-z").arg("Sherlock").arg("sherlock.gz"); - - wd.assert_non_empty_stderr(&mut cmd); - - let output = cmd.output().unwrap(); - let err = String::from_utf8_lossy(&output.stderr); - assert_eq!(err.contains("not in gzip format"), true); -} - -sherlock!(feature_196_persistent_config, "sherlock", -|wd: WorkDir, mut cmd: Command| { - // Make sure we get no matches by default. - wd.assert_err(&mut cmd); - - // Now add our config file, and make sure it impacts ripgrep. - wd.create(".ripgreprc", "--ignore-case"); - cmd.env("RIPGREP_CONFIG_PATH", ".ripgreprc"); - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -For the Doctor Watsons of this world, as opposed to the Sherlock -be, to a very large extent, the result of luck. Sherlock Holmes -"; - assert_eq!(lines, expected); -}); - -sherlock!(feature_411_single_threaded_search_stats, -|wd: WorkDir, mut cmd: Command| { - cmd.arg("--stats"); - - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines.contains("2 matched lines"), true); - assert_eq!(lines.contains("1 files contained matches"), true); - assert_eq!(lines.contains("1 files searched"), true); - assert_eq!(lines.contains("seconds"), true); -}); - -#[test] -fn feature_411_parallel_search_stats() { - let wd = WorkDir::new("feature_411"); - wd.create("sherlock_1", hay::SHERLOCK); - wd.create("sherlock_2", hay::SHERLOCK); - - let mut cmd = wd.command(); - cmd.arg("--stats"); - cmd.arg("Sherlock"); - cmd.arg("./"); - - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines.contains("4 matched lines"), true); - assert_eq!(lines.contains("2 files contained matches"), true); - assert_eq!(lines.contains("2 files searched"), true); - assert_eq!(lines.contains("seconds"), true); -} - -sherlock!(feature_411_ignore_stats_1, |wd: WorkDir, mut cmd: Command| { - cmd.arg("--files-with-matches"); - cmd.arg("--stats"); - - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines.contains("seconds"), false); -}); - -sherlock!(feature_411_ignore_stats_2, |wd: WorkDir, mut cmd: Command| { - cmd.arg("--files-without-match"); - cmd.arg("--stats"); - - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines.contains("seconds"), false); -}); - -#[test] -fn feature_740_passthru() { - let wd = WorkDir::new("feature_740"); - wd.create("file", "\nfoo\nbar\nfoobar\n\nbaz\n"); - wd.create("patterns", "foo\n\nbar\n"); - - // We can't assume that the way colour specs are translated to ANSI - // sequences will remain stable, and --replace doesn't currently work with - // pass-through, so for now we don't actually test the match sub-strings - let common_args = &["-n", "--passthru"]; - let expected = "\ -1: -2:foo -3:bar -4:foobar -5: -6:baz -"; - - // With single pattern - let mut cmd = wd.command(); - cmd.args(common_args).arg("foo").arg("file"); - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, expected); - - // With multiple -e patterns - let mut cmd = wd.command(); - cmd.args(common_args) - .arg("-e").arg("foo").arg("-e").arg("bar").arg("file"); - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, expected); - - // With multiple -f patterns - let mut cmd = wd.command(); - cmd.args(common_args).arg("-f").arg("patterns").arg("file"); - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, expected); - - // -c should override - let mut cmd = wd.command(); - cmd.args(common_args).arg("-c").arg("foo").arg("file"); - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "2\n"); - - // -o should conflict - let mut cmd = wd.command(); - cmd.args(common_args).arg("-o").arg("foo").arg("file"); - wd.assert_err(&mut cmd); - - // -r should conflict - let mut cmd = wd.command(); - cmd.args(common_args).arg("-r").arg("$0").arg("foo").arg("file"); - wd.assert_err(&mut cmd); -} - -#[test] -fn binary_nosearch() { - let wd = WorkDir::new("binary_nosearch"); - wd.create("file", "foo\x00bar\nfoo\x00baz\n"); - let mut cmd = wd.command(); - cmd.arg("foo").arg("file"); - wd.assert_err(&mut cmd); -} - -// The following two tests show a discrepancy in search results between -// searching with memory mapped files and stream searching. Stream searching -// uses a heuristic (that GNU grep also uses) where NUL bytes are replaced with -// the EOL terminator, which tends to avoid allocating large amounts of memory -// for really long "lines." The memory map searcher has no need to worry about -// such things, and more than that, it would be pretty hard for it to match -// the semantics of streaming search in this case. -// -// Binary files with lots of NULs aren't really part of the use case of ripgrep -// (or any other grep-like tool for that matter), so we shouldn't feel too bad -// about it. -#[test] -fn binary_search_mmap() { - let wd = WorkDir::new("binary_search_mmap"); - wd.create("file", "foo\x00bar\nfoo\x00baz\n"); - let mut cmd = wd.command(); - cmd.arg("-a").arg("--mmap").arg("foo").arg("file"); - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "foo\x00bar\nfoo\x00baz\n"); -} - -#[test] -fn binary_search_no_mmap() { - let wd = WorkDir::new("binary_search_no_mmap"); - wd.create("file", "foo\x00bar\nfoo\x00baz\n"); - let mut cmd = wd.command(); - cmd.arg("-a").arg("--no-mmap").arg("foo").arg("file"); - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "foo\x00bar\nfoo\x00baz\n"); -} - -#[test] -fn files() { - let wd = WorkDir::new("files"); - wd.create("file", ""); - wd.create_dir("dir"); - wd.create("dir/file", ""); - - let mut cmd = wd.command(); - cmd.arg("--files"); - let lines: String = wd.stdout(&mut cmd); - assert!(lines == path("file\ndir/file\n") - || lines == path("dir/file\nfile\n")); -} - -// See: https://github.com/BurntSushi/ripgrep/issues/64 -#[test] -fn regression_64() { - let wd = WorkDir::new("regression_64"); - wd.create_dir("dir"); - wd.create_dir("foo"); - wd.create("dir/abc", ""); - wd.create("foo/abc", ""); - - let mut cmd = wd.command(); - cmd.arg("--files").arg("foo"); - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, path("foo/abc\n")); -} - -// See: https://github.com/BurntSushi/ripgrep/issues/270 -#[test] -fn regression_270() { - let wd = WorkDir::new("regression_270"); - wd.create("foo", "-test"); - - let mut cmd = wd.command(); - cmd.arg("-e").arg("-test").arg("./"); - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, path("foo:-test\n")); -} - -// See: https://github.com/BurntSushi/ripgrep/issues/391 -#[test] -fn regression_391() { - let wd = WorkDir::new("regression_391"); - wd.create_dir(".git"); - wd.create("lock", ""); - wd.create("bar.py", ""); - wd.create(".git/packed-refs", ""); - wd.create(".git/description", ""); - - let mut cmd = wd.command(); - cmd.arg("--no-ignore").arg("--hidden").arg("--follow").arg("--files") - .arg("--glob") - .arg("!{.git,node_modules,plugged}/**") - .arg("--glob") - .arg("*.{js,json,php,md,styl,scss,sass,pug,html,config,py,cpp,c,go,hs}"); - - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "bar.py\n"); -} - -// See: https://github.com/BurntSushi/ripgrep/issues/451 -#[test] -fn regression_451_only_matching_as_in_issue() { - let wd = WorkDir::new("regression_451_only_matching"); - let path = "digits.txt"; - wd.create(path, "1 2 3\n"); - - let mut cmd = wd.command(); - cmd.arg("[0-9]+").arg(path).arg("--only-matching"); - let lines: String = wd.stdout(&mut cmd); - - let expected = "\ -1 -2 -3 -"; - - assert_eq!(lines, expected); -} - -// See: https://github.com/BurntSushi/ripgrep/issues/451 -#[test] -fn regression_451_only_matching() { - let wd = WorkDir::new("regression_451_only_matching"); - let path = "digits.txt"; - wd.create(path, "1 2 3\n123\n"); - - let mut cmd = wd.command(); - cmd.arg("[0-9]").arg(path) - .arg("--only-matching") - .arg("--column"); - let lines: String = wd.stdout(&mut cmd); - - let expected = "\ -1:1:1 -1:3:2 -1:5:3 -2:1:1 -2:2:2 -2:3:3 -"; - - assert_eq!(lines, expected); -} - -// See: https://github.com/BurntSushi/ripgrep/issues/483 -#[test] -fn regression_483_matching_no_stdout() { - let wd = WorkDir::new("regression_483_matching_no_stdout"); - wd.create("file.py", ""); - - let mut cmd = wd.command(); - cmd.arg("--quiet") - .arg("--files") - .arg("--glob").arg("*.py"); - - let lines: String = wd.stdout(&mut cmd); - assert!(lines.is_empty()); -} - -// See: https://github.com/BurntSushi/ripgrep/issues/483 -#[test] -fn regression_483_non_matching_exit_code() { - let wd = WorkDir::new("regression_483_non_matching_exit_code"); - wd.create("file.rs", ""); - - let mut cmd = wd.command(); - cmd.arg("--quiet") - .arg("--files") - .arg("--glob").arg("*.py"); - - wd.assert_err(&mut cmd); -} - -// See: https://github.com/BurntSushi/ripgrep/issues/506 -#[test] -fn regression_506_word_boundaries_not_parenthesized() { - let wd = WorkDir::new("regression_506_word_boundaries_not_parenthesized"); - let path = "wb.txt"; - wd.create(path, "min minimum amin\n\ - max maximum amax"); - - let mut cmd = wd.command(); - cmd.arg("-w").arg("min|max").arg(path).arg("--only-matching"); - let lines: String = wd.stdout(&mut cmd); - - let expected = "min\nmax\n"; - - assert_eq!(lines, expected); -} - -// See: https://github.com/BurntSushi/ripgrep/issues/568 -#[test] -fn regression_568_leading_hyphen_option_arguments() { - let wd = WorkDir::new("regression_568_leading_hyphen_option_arguments"); - let path = "file"; - wd.create(path, "foo bar -baz\n"); - - let mut cmd = wd.command(); - cmd.arg("-e-baz").arg("-e").arg("-baz").arg(path); - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "foo bar -baz\n"); - - let mut cmd = wd.command(); - cmd.arg("-rni").arg("bar").arg(path); - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "foo ni -baz\n"); - - let mut cmd = wd.command(); - cmd.arg("-r").arg("-n").arg("-i").arg("bar").arg(path); - let lines: String = wd.stdout(&mut cmd); - assert_eq!(lines, "foo -n -baz\n"); -} - -// See: https://github.com/BurntSushi/ripgrep/issues/693 -#[test] -fn regression_693_context_option_in_contextless_mode() { - let wd = WorkDir::new("regression_693_context_option_in_contextless_mode"); - - wd.create("foo", "xyz\n"); - wd.create("bar", "xyz\n"); - - let mut cmd = wd.command(); - cmd.arg("-C1").arg("-c").arg("--sort-files").arg("xyz").arg("./"); - - let lines: String = wd.stdout(&mut cmd); - let expected = "\ -bar:1 -foo:1 -"; - assert_eq!(lines, expected); -} - -#[test] -fn type_list() { - let wd = WorkDir::new("type_list"); - - let mut cmd = wd.command(); - cmd.arg("--type-list"); - let lines: String = wd.stdout(&mut cmd); - // This can change over time, so just make sure we print something. - assert!(!lines.is_empty()); -} - -// See: https://github.com/BurntSushi/ripgrep/issues/948 -sherlock!( - exit_code_match_success, - ".", - ".", - |wd: WorkDir, mut cmd: Command| { - wd.assert_exit_code(0, &mut cmd); - } -); - -// See: https://github.com/BurntSushi/ripgrep/issues/948 -sherlock!( - exit_code_no_match, - "6d28e48b5224a42b167e{10}", - ".", - |wd: WorkDir, mut cmd: Command| { - wd.assert_exit_code(1, &mut cmd); - } -); - -// See: https://github.com/BurntSushi/ripgrep/issues/948 -sherlock!( - exit_code_error, - "*", - ".", - |wd: WorkDir, mut cmd: Command| { - wd.assert_exit_code(2, &mut cmd); - } -); diff --git a/tests/workdir.rs b/tests/workdir.rs deleted file mode 100644 index 99f0bf3..0000000 --- a/tests/workdir.rs +++ /dev/null @@ -1,336 +0,0 @@ -use std::env; -use std::error; -use std::fmt; -use std::fs::{self, File}; -use std::io::{self, Write}; -use std::path::{Path, PathBuf}; -use std::process; -use std::str::FromStr; -use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering}; -use std::thread; -use std::time::Duration; - -static TEST_DIR: &'static str = "ripgrep-tests"; -static NEXT_ID: AtomicUsize = ATOMIC_USIZE_INIT; - -/// `WorkDir` represents a directory in which tests are run. -/// -/// Directories are created from a global atomic counter to avoid duplicates. -#[derive(Debug)] -pub struct WorkDir { - /// The directory in which this test executable is running. - root: PathBuf, - /// The directory in which the test should run. If a test needs to create - /// files, they should go in here. - dir: PathBuf, -} - -impl WorkDir { - /// Create a new test working directory with the given name. The name - /// does not need to be distinct for each invocation, but should correspond - /// to a logical grouping of tests. - pub fn new(name: &str) -> WorkDir { - let id = NEXT_ID.fetch_add(1, Ordering::SeqCst); - let root = env::current_exe().unwrap() - .parent().expect("executable's directory").to_path_buf(); - let dir = root.join(TEST_DIR).join(name).join(&format!("{}", id)); - nice_err(&dir, repeat(|| fs::create_dir_all(&dir))); - WorkDir { - root: root, - dir: dir, - } - } - - /// Create a new file with the given name and contents in this directory, - /// or panic on error. - pub fn create>(&self, name: P, contents: &str) { - self.create_bytes(name, contents.as_bytes()); - } - - /// Try to create a new file with the given name and contents in this - /// directory. - pub fn try_create>(&self, name: P, contents: &str) -> io::Result<()> { - let path = self.dir.join(name); - self.try_create_bytes(path, contents.as_bytes()) - } - - /// Create a new file with the given name and size. - pub fn create_size>(&self, name: P, filesize: u64) { - let path = self.dir.join(name); - let file = nice_err(&path, File::create(&path)); - nice_err(&path, file.set_len(filesize)); - } - - /// Create a new file with the given name and contents in this directory, - /// or panic on error. - pub fn create_bytes>(&self, name: P, contents: &[u8]) { - let path = self.dir.join(name); - nice_err(&path, self.try_create_bytes(&path, contents)); - } - - /// Try to create a new file with the given name and contents in this - /// directory. - fn try_create_bytes>(&self, path: P, contents: &[u8]) -> io::Result<()> { - let mut file = File::create(&path)?; - file.write_all(contents)?; - file.flush() - } - - /// Remove a file with the given name from this directory. - pub fn remove>(&self, name: P) { - let path = self.dir.join(name); - nice_err(&path, fs::remove_file(&path)); - } - - /// Create a new directory with the given path (and any directories above - /// it) inside this directory. - pub fn create_dir>(&self, path: P) { - let path = self.dir.join(path); - nice_err(&path, repeat(|| fs::create_dir_all(&path))); - } - - /// Creates a new command that is set to use the ripgrep executable in - /// this working directory. - pub fn command(&self) -> process::Command { - let mut cmd = process::Command::new(&self.bin()); - cmd.env_remove("RIPGREP_CONFIG_PATH"); - cmd.current_dir(&self.dir); - cmd - } - - /// Returns the path to the ripgrep executable. - #[cfg(not(windows))] - pub fn bin(&self) -> PathBuf { - let path = self.root.join("rg"); - if !path.is_file() { - // Looks like a recent version of Cargo changed the cwd or the - // location of the test executable. - self.root.join("../rg") - } else { - path - } - } - - /// Returns the path to the ripgrep executable. - #[cfg(windows)] - pub fn bin(&self) -> PathBuf { - let path = self.root.join("rg.exe"); - if !path.is_file() { - // Looks like a recent version of Cargo changed the cwd or the - // location of the test executable. - self.root.join("../rg.exe") - } else { - path - } - } - - /// Returns the path to this directory. - pub fn path(&self) -> &Path { - &self.dir - } - - /// Creates a directory symlink to the src with the given target name - /// in this directory. - #[cfg(not(windows))] - pub fn link_dir, T: AsRef>(&self, src: S, target: T) { - use std::os::unix::fs::symlink; - let src = self.dir.join(src); - let target = self.dir.join(target); - let _ = fs::remove_file(&target); - nice_err(&target, symlink(&src, &target)); - } - - /// Creates a directory symlink to the src with the given target name - /// in this directory. - #[cfg(windows)] - pub fn link_dir, T: AsRef>(&self, src: S, target: T) { - use std::os::windows::fs::symlink_dir; - let src = self.dir.join(src); - let target = self.dir.join(target); - let _ = fs::remove_dir(&target); - nice_err(&target, symlink_dir(&src, &target)); - } - - /// Creates a file symlink to the src with the given target name - /// in this directory. - #[cfg(not(windows))] - pub fn link_file, T: AsRef>( - &self, - src: S, - target: T, - ) { - self.link_dir(src, target); - } - - /// Creates a file symlink to the src with the given target name - /// in this directory. - #[cfg(windows)] - pub fn link_file, T: AsRef>( - &self, - src: S, - target: T, - ) { - use std::os::windows::fs::symlink_file; - let src = self.dir.join(src); - let target = self.dir.join(target); - let _ = fs::remove_file(&target); - nice_err(&target, symlink_file(&src, &target)); - } - - /// Runs and captures the stdout of the given command. - /// - /// If the return type could not be created from a string, then this - /// panics. - pub fn stdout>( - &self, - cmd: &mut process::Command, - ) -> T { - let o = self.output(cmd); - let stdout = String::from_utf8_lossy(&o.stdout); - match stdout.parse() { - Ok(t) => t, - Err(err) => { - panic!("could not convert from string: {:?}\n\n{}", err, stdout); - } - } - } - - /// Gets the output of a command. If the command failed, then this panics. - pub fn output(&self, cmd: &mut process::Command) -> process::Output { - let output = cmd.output().unwrap(); - self.expect_success(cmd, output) - } - - /// Pipe `input` to a command, and collect the output. - pub fn pipe( - &self, - cmd: &mut process::Command, - input: &str - ) -> process::Output { - cmd.stdin(process::Stdio::piped()); - cmd.stdout(process::Stdio::piped()); - cmd.stderr(process::Stdio::piped()); - - let mut child = cmd.spawn().unwrap(); - - // Pipe input to child process using a separate thread to avoid - // risk of deadlock between parent and child process. - let mut stdin = child.stdin.take().expect("expected standard input"); - let input = input.to_owned(); - let worker = thread::spawn(move || { - write!(stdin, "{}", input) - }); - - let output = self.expect_success(cmd, child.wait_with_output().unwrap()); - worker.join().unwrap().unwrap(); - output - } - - /// If `o` is not the output of a successful process run - fn expect_success( - &self, - cmd: &process::Command, - o: process::Output - ) -> process::Output { - if !o.status.success() { - let suggest = - if o.stderr.is_empty() { - "\n\nDid your search end up with no results?".to_string() - } else { - "".to_string() - }; - - panic!("\n\n==========\n\ - command failed but expected success!\ - {}\ - \n\ncommand: {:?}\ - \ncwd: {}\ - \n\nstatus: {}\ - \n\nstdout: {}\ - \n\nstderr: {}\ - \n\n==========\n", - suggest, cmd, self.dir.display(), o.status, - String::from_utf8_lossy(&o.stdout), - String::from_utf8_lossy(&o.stderr)); - } - o - } - - /// Runs the given command and asserts that it resulted in an error exit - /// code. - pub fn assert_err(&self, cmd: &mut process::Command) { - let o = cmd.output().unwrap(); - if o.status.success() { - panic!( - "\n\n===== {:?} =====\n\ - command succeeded but expected failure!\ - \n\ncwd: {}\ - \n\nstatus: {}\ - \n\nstdout: {}\n\nstderr: {}\ - \n\n=====\n", - cmd, - self.dir.display(), - o.status, - String::from_utf8_lossy(&o.stdout), - String::from_utf8_lossy(&o.stderr) - ); - } - } - - /// Runs the given command and asserts that its exit code matches expected exit code. - pub fn assert_exit_code(&self, expected_code: i32, cmd: &mut process::Command) { - let code = cmd.status().unwrap().code().unwrap(); - - assert_eq!( - expected_code, code, - "\n\n===== {:?} =====\n\ - expected exit code did not match\ - \n\nexpected: {}\ - \n\nfound: {}\ - \n\n=====\n", - cmd, expected_code, code - ); - } - - /// Runs the given command and asserts that something was printed to - /// stderr. - pub fn assert_non_empty_stderr(&self, cmd: &mut process::Command) { - let o = cmd.output().unwrap(); - if o.status.success() || o.stderr.is_empty() { - panic!("\n\n===== {:?} =====\n\ - command succeeded but expected failure!\ - \n\ncwd: {}\ - \n\nstatus: {}\ - \n\nstdout: {}\n\nstderr: {}\ - \n\n=====\n", - cmd, self.dir.display(), o.status, - String::from_utf8_lossy(&o.stdout), - String::from_utf8_lossy(&o.stderr)); - } - } -} - -fn nice_err, T, E: error::Error>( - path: P, - res: Result, -) -> T { - match res { - Ok(t) => t, - Err(err) => { - panic!("{}: {:?}", path.as_ref().display(), err); - } - } -} - -fn repeat io::Result<()>>(mut f: F) -> io::Result<()> { - let mut last_err = None; - for _ in 0..10 { - if let Err(err) = f() { - last_err = Some(err); - thread::sleep(Duration::from_millis(500)); - } else { - return Ok(()); - } - } - Err(last_err.unwrap()) -} diff --git a/wincolor/Cargo.toml b/wincolor/Cargo.toml index 7c81175..f572b2d 100644 --- a/wincolor/Cargo.toml +++ b/wincolor/Cargo.toml @@ -6,8 +6,8 @@ description = """ A simple Windows specific API for controlling text color in a Windows console. """ documentation = "https://docs.rs/wincolor" -homepage = "https://github.com/BurntSushi/ripgrep/tree/master/wincolor" -repository = "https://github.com/BurntSushi/ripgrep/tree/master/wincolor" +homepage = "https://github.com/BurntSushi/termcolor/tree/master/wincolor" +repository = "https://github.com/BurntSushi/termcolor/tree/master/wincolor" readme = "README.md" keywords = ["windows", "win", "color", "ansi", "console"] license = "Unlicense/MIT"