mirror of
https://github.com/BurntSushi/ripgrep.git
synced 2025-08-21 23:23:47 -07:00
Compare commits
21 Commits
wincolor-0
...
ignore-0.2
Author | SHA1 | Date | |
---|---|---|---|
|
92e5fad27d | ||
|
f86f987d71 | ||
|
bfbd53eb92 | ||
|
0668c74ed4 | ||
|
1c03298903 | ||
|
e0e8f26c56 | ||
|
f5337329f4 | ||
|
84f4b4ef68 | ||
|
aeac85389d | ||
|
9b3921098a | ||
|
ad262f1146 | ||
|
170c078440 | ||
|
db044a058a | ||
|
c1f8040b32 | ||
|
c8a5a7a3f4 | ||
|
dd3df0ded7 | ||
|
62a182af78 | ||
|
4047d9db71 | ||
|
4683a325fa | ||
|
b6f1e5db1a | ||
|
9e51b18ac7 |
@@ -3,6 +3,7 @@ language: rust
|
||||
env:
|
||||
global:
|
||||
- PROJECT_NAME=ripgrep
|
||||
- RUST_BACKTRACE: full
|
||||
matrix:
|
||||
include:
|
||||
# Nightly channel.
|
||||
|
8
Cargo.lock
generated
8
Cargo.lock
generated
@@ -8,7 +8,7 @@ dependencies = [
|
||||
"encoding_rs 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"grep 0.1.6",
|
||||
"ignore 0.2.0",
|
||||
"ignore 0.2.2",
|
||||
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -135,7 +135,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ignore"
|
||||
version = "0.2.0"
|
||||
version = "0.2.2"
|
||||
dependencies = [
|
||||
"crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"globset 0.2.0",
|
||||
@@ -249,7 +249,7 @@ dependencies = [
|
||||
name = "termcolor"
|
||||
version = "0.3.2"
|
||||
dependencies = [
|
||||
"wincolor 0.1.3",
|
||||
"wincolor 0.1.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -325,7 +325,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "wincolor"
|
||||
version = "0.1.3"
|
||||
version = "0.1.4"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@@ -32,7 +32,7 @@ clap = "2.24.1"
|
||||
encoding_rs = "0.5.0"
|
||||
env_logger = { version = "0.4", default-features = false }
|
||||
grep = { version = "0.1.5", path = "grep" }
|
||||
ignore = { version = "0.2.0", path = "ignore" }
|
||||
ignore = { version = "0.2.2", path = "ignore" }
|
||||
lazy_static = "0.2"
|
||||
libc = "0.2"
|
||||
log = "0.3"
|
||||
|
@@ -187,17 +187,17 @@ If you're a **Gentoo** user, you can install `ripgrep` from the [official repo](
|
||||
$ emerge ripgrep
|
||||
```
|
||||
|
||||
If you're a **Fedora 24+** user, you can install `ripgrep` from [copr](https://copr.fedorainfracloud.org/coprs/carlgeorge/ripgrep/):
|
||||
If you're a **Fedora 24+** user, you can install `ripgrep` from [copr](https://copr.fedorainfracloud.org/coprs/carlwgeorge/ripgrep/):
|
||||
|
||||
```
|
||||
$ dnf copr enable carlgeorge/ripgrep
|
||||
$ dnf copr enable carlwgeorge/ripgrep
|
||||
$ dnf install ripgrep
|
||||
```
|
||||
|
||||
If you're a **RHEL/CentOS 7** user, you can install `ripgrep` from [copr](https://copr.fedorainfracloud.org/coprs/carlgeorge/ripgrep/):
|
||||
If you're a **RHEL/CentOS 7** user, you can install `ripgrep` from [copr](https://copr.fedorainfracloud.org/coprs/carlwgeorge/ripgrep/):
|
||||
|
||||
```
|
||||
$ yum-config-manager --add-repo=https://copr.fedorainfracloud.org/coprs/carlgeorge/ripgrep/repo/epel-7/carlgeorge-ripgrep-epel-7.repo
|
||||
$ yum-config-manager --add-repo=https://copr.fedorainfracloud.org/coprs/carlwgeorge/ripgrep/repo/epel-7/carlwgeorge-ripgrep-epel-7.repo
|
||||
$ yum install ripgrep
|
||||
```
|
||||
|
||||
|
@@ -1,6 +1,7 @@
|
||||
environment:
|
||||
global:
|
||||
PROJECT_NAME: ripgrep
|
||||
RUST_BACKTRACE: full
|
||||
matrix:
|
||||
- TARGET: i686-pc-windows-gnu
|
||||
CHANNEL: stable
|
||||
|
@@ -1082,7 +1082,7 @@ def download_subtitles_en(suite_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], 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.
|
||||
@@ -1109,7 +1109,7 @@ def download_subtitles_ru(suite_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], cwd=subtitle_dir)
|
||||
run_cmd(['gunzip', ru_path_gz])
|
||||
|
||||
|
||||
def has_subtitles_ru(suite_dir):
|
||||
@@ -1184,6 +1184,7 @@ def collect_benchmarks(suite_dir, filter_pat=None,
|
||||
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)'
|
||||
@@ -1239,7 +1240,7 @@ def main():
|
||||
benchmarks = collect_benchmarks(
|
||||
args.dir, filter_pat=args.bench,
|
||||
allow_missing_commands=args.allow_missing,
|
||||
disabled_cmds=args.disabled.split(','),
|
||||
disabled_cmds=(args.disabled or '').split(','),
|
||||
warmup_iter=args.warmup_iter, bench_iter=args.bench_iter)
|
||||
for b in benchmarks:
|
||||
print(b.name)
|
||||
@@ -1266,7 +1267,7 @@ def main():
|
||||
benchmarks = collect_benchmarks(
|
||||
args.dir, filter_pat=args.bench,
|
||||
allow_missing_commands=args.allow_missing,
|
||||
disabled_cmds=args.disabled.split(','),
|
||||
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()
|
||||
|
@@ -28,6 +28,8 @@ run_test_suite() {
|
||||
cargo build --target $TARGET --verbose --manifest-path termcolor/Cargo.toml
|
||||
cargo test --target $TARGET --verbose --manifest-path termcolor/Cargo.toml
|
||||
|
||||
"$( dirname "${0}" )/test_complete.sh"
|
||||
|
||||
# sanity check the file type
|
||||
file target/$TARGET/debug/rg
|
||||
}
|
||||
|
83
ci/test_complete.sh
Executable file
83
ci/test_complete.sh
Executable file
@@ -0,0 +1,83 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Compares options in `rg --help` output to options in zsh completion function
|
||||
|
||||
set -e
|
||||
|
||||
main() {
|
||||
local rg="target/${TARGET}/release/rg"
|
||||
local _rg='complete/_rg'
|
||||
local ret='0'
|
||||
local helpTemp="$( mktemp )"
|
||||
local compTemp="$( mktemp )"
|
||||
local diff
|
||||
|
||||
[ -e "${rg}" ] || rg="target/${TARGET}/debug/rg"
|
||||
|
||||
if [ ! -e "${rg}" ]; then
|
||||
printf 'File not found: %s\n' "${rg}" >&2
|
||||
ret='1'
|
||||
elif [ ! -e "${_rg}" ]; then
|
||||
printf 'File not found: %s\n' "${_rg}" >&2
|
||||
ret='1'
|
||||
else
|
||||
# 'Parse' options out of the `--help` output. To prevent false positives
|
||||
# we only look at lines where the first non-white-space character is `-`
|
||||
"${rg}" --help |
|
||||
"${rg}" -- '^\s*-' |
|
||||
"${rg}" -io -- '[\t ,](-[a-z0-9]|--[a-z0-9-]+)\b' |
|
||||
tr -d '\t ,' |
|
||||
sort -u > "${helpTemp}"
|
||||
|
||||
# 'Parse' options out of the completion-function file. To prevent false
|
||||
# negatives, we:
|
||||
#
|
||||
# * Exclude lines that look like comments
|
||||
# * Exclude lines that don't appear to have a bracketed description
|
||||
# suitable for `_arguments`
|
||||
# * Exclude those bracketed descriptions so we don't match options
|
||||
# which might be referenced in them
|
||||
# * Exclude parenthetical lists of exclusive options so we don't match
|
||||
# those
|
||||
#
|
||||
# This does of course make the following assumptions:
|
||||
#
|
||||
# * Each option definition is on its own (single) line
|
||||
# * Each option definition has a description
|
||||
# * Option names are static — i.e., they aren't constructed from
|
||||
# variables or command substitutions. Brace expansion is OK as long as
|
||||
# each component of the expression is a complete option flag — in
|
||||
# other words, `{--foo,--bar}` is valid, but `--{foo,bar}` is not
|
||||
"${rg}" -v -- '^\s*#' "${_rg}" |
|
||||
"${rg}" --replace '$1' -- '^.*?(?:\(.+?\).*?)?(-.+)\[.+\].*' |
|
||||
tr -d "\t (){}*=+:'\"" |
|
||||
tr ',' '\n' |
|
||||
sort -u > "${compTemp}"
|
||||
|
||||
diff="$(
|
||||
if diff --help 2>&1 | grep -qF -- '--label'; then
|
||||
diff -U2 \
|
||||
--label '`rg --help`' \
|
||||
--label "${_rg}" \
|
||||
"${helpTemp}" "${compTemp}" || true
|
||||
else
|
||||
diff -U2 \
|
||||
-L '`rg --help`' \
|
||||
-L "${_rg}" \
|
||||
"${helpTemp}" "${compTemp}" || true
|
||||
fi
|
||||
)"
|
||||
|
||||
[ -n "${diff}" ] && {
|
||||
printf '%s\n' 'zsh completion options differ from `--help` options:' >&2
|
||||
printf '%s\n' "${diff}" >&2
|
||||
ret='1'
|
||||
}
|
||||
fi
|
||||
|
||||
rm -f "${helpTemp}" "${compTemp}"
|
||||
|
||||
return "${ret}"
|
||||
}
|
||||
|
||||
main "${@}"
|
153
complete/_rg
153
complete/_rg
@@ -47,70 +47,74 @@ local -a common_options
|
||||
common_options=(
|
||||
'(-a --text)'{-a,--text}'[search binary files as if they were text]'
|
||||
'(-c, --count)'{-c,--count}'[only show count of matches for each file]'
|
||||
'--color=[whether to use coloring in match]::when:( always never auto )'
|
||||
'--color=[specify when to use colors in output]:when:( never auto always ansi )'
|
||||
'(1)*'{-e,--regexp=}'[specify pattern]:pattern'
|
||||
'(-E --encoding)'{-E,--encoding=}'[specify the text encoding of files to search.]:encoding'
|
||||
'(-F --fixed-strings)'{-F,--fixed-strings}'[treat the pattern as a literal string instead of a regular expression]'
|
||||
'*'{-g,--glob=}'[include or exclude files for searching that match the given glob]:glob'
|
||||
'(-h --help)'{-h,--help}'[prints help information]'
|
||||
'(-i -s -S --ignore-case --case-sensitive --smart-case)'{-i,--ignore-case}'[case insensitive search]'
|
||||
'(-E --encoding)'{-E,--encoding=}'[specify text encoding of files to search]: :->encoding'
|
||||
'(-F --fixed-strings)'{-F,--fixed-strings}'[treat pattern as literal string instead of regular expression]'
|
||||
'*'{-g,--glob=}'[include or exclude files for searching that match the specified glob]:glob'
|
||||
'(-h --help)'{-h,--help}'[display help information]'
|
||||
'(-i -s -S --ignore-case --case-sensitive --smart-case)'{-i,--ignore-case}'[search case-insensitively]'
|
||||
'(-n -N --line-number --no-line-number)'{-n,--line-number}'[show line numbers]'
|
||||
'(-n -N --line-number --no-line-number)'{-N,--no-line-number}'[suppress line numbers]'
|
||||
'(-q --quiet)'{-q,--quiet}'[do not print anything to stdout]'
|
||||
'(-o --only-matching)'{-o,--only-matching}'[show only matching part of each line]'
|
||||
'(-q --quiet)'{-q,--quiet}'[suppress normal output]'
|
||||
'(-T --type-not)*'{-t,--type=}'[only search files matching specified type]: :->type'
|
||||
'(-t --type)*'{-T,--type-not=}'[do not search files matching type]: :->type'
|
||||
'*'{-u,--unrestricted}'[reduce the level of "smart" searching]'
|
||||
'(-t --type)*'{-T,--type-not=}"[don't search files matching specified type]: :->type"
|
||||
'*'{-u,--unrestricted}'[reduce level of "smart" searching]'
|
||||
'(-v --invert-match)'{-v,--invert-match}'[invert matching]'
|
||||
'(-w --word-regexp)'{-w,--word-regexp}'[only show matches surrounded by word boundaries]'
|
||||
)
|
||||
|
||||
local -a less_common_options
|
||||
less_common_options=(
|
||||
'(-A -C --after-context --context)'{-A,--after-context=}'[specify number of lines to show after each match]:number of lines'
|
||||
'(-B -C --before-context --context)'{-B,--before-context=}'[specify number of lines to show before each match]:number of lines'
|
||||
'(-A -B -C --after-context --before-context --context)'{-C,--context=}'[specify number of lines to show before and after each match]:number of lines'
|
||||
'*--colors=[configure color settings and styles]:spec'
|
||||
'--column[show column numbers in output]'
|
||||
'--context-separator=[the string used to separate non-continuous context lines in the output]:separator string'
|
||||
'--debug[show debug message]'
|
||||
'--dfa-size-limit=[the upper size limit of the generated dfa]:size'
|
||||
"--file=[search for patterns from the given file]:file:_files"
|
||||
"--ignore-file=[search additional ignore files]:file:_files"
|
||||
"--files[print each file that would be searched (but don't search)]"
|
||||
'(-l --files-with-matches)'{-l,--files-with-matches}'[only show path of each file with matches]'
|
||||
'(-H --with-filename --no-filename)'{-H,--with-filename}'[prefix each match with the file name that contains it]'
|
||||
'(-H --with-filename)--no-filename[never show the file name for a match]'
|
||||
'(-p --no-heading --pretty --vimgrep)--heading[show the file name above clusters of matches from each file]'
|
||||
"(-p --heading --pretty --vimgrep)--no-heading[don't show any file name heading]"
|
||||
'--hidden[search hidden directories and files]'
|
||||
'(-A -C --after-context --context)'{-A,--after-context=}'[specify lines to show after each match]:number of lines'
|
||||
'(-B -C --before-context --context)'{-B,--before-context=}'[specify lines to show before each match]:number of lines'
|
||||
'(-A -B -C --after-context --before-context --context)'{-C,--context=}'[specify lines to show before and after each match]:number of lines'
|
||||
'*--colors=[specify color settings and styles]: :->colorspec'
|
||||
'--column[show column numbers]'
|
||||
'--context-separator=[specify string used to separate non-continuous context lines in output]:separator string'
|
||||
'--debug[show debug messages]'
|
||||
'--dfa-size-limit=[specify upper size limit of generated DFA]:DFA size'
|
||||
'*'{-f,--file=}'[specify file containing patterns to search for]:file:_files'
|
||||
"--ignore-file=[specify additional ignore file]:file:_files"
|
||||
"--files[show each file that would be searched (but don't search)]"
|
||||
'(-l --files-with-matches --files-without-match)'{-l,--files-with-matches}'[only show names of files with matches]'
|
||||
'(-l --files-with-matches --files-without-match)--files-without-match[only show names of files without matches]'
|
||||
'(-H --with-filename --no-filename)'{-H,--with-filename}'[prefix each match with name of file that contains it]'
|
||||
'(-H --with-filename --no-filename)--no-filename[suppress all file names]'
|
||||
'(-p --no-heading --pretty --vimgrep)--heading[show matches grouped by file name]'
|
||||
"(-p --heading --pretty --vimgrep)--no-heading[don't group matches by file name]"
|
||||
'--hidden[search hidden files and directories]'
|
||||
'*--iglob=[include or exclude files for searching that match the specified case-insensitive glob]:glob'
|
||||
'(-L --follow)'{-L,--follow}'[follow symlinks]'
|
||||
'(-M --max-columns)'{-M,--max-columns=}"[don't print lines longer than this limit in bytes]:number"
|
||||
'(-m --max-count)'{-m,--max-count=}'[only show count of matches for each file]:number'
|
||||
'--max-filesize=[ignore files larger than NUM in size]:size'
|
||||
'--maxdepth[descend at most N directories below the command line arguments]:depth'
|
||||
'(-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]:size'
|
||||
'--maxdepth[specify max number of directories to descend]:number of directories'
|
||||
'(--no-mmap)--mmap[search using memory maps when possible]'
|
||||
'--no-messages[suppress all error messages]'
|
||||
'(--mmap)--no-mmap[never use memory maps, even when they might be faster]'
|
||||
"(--mmap)--no-mmap[don't search using memory maps]"
|
||||
"(--no-ignore-parent)--no-ignore[don't respect ignore files]"
|
||||
"--no-ignore-parent[don't respect ignore files in parent directories]"
|
||||
"--no-ignore-vcs[don't respect version control ignore files]"
|
||||
'(-0 --null)'{-0,--null}'[print NUL byte after file names]'
|
||||
'--path-separator=[path separator to use when printing file paths]'
|
||||
'--path-separator=[specify path separator to use when printing file names]'
|
||||
'(-p --heading --no-heading --pretty --vimgrep)'{-p,--pretty}'[alias for --color=always --heading -n]'
|
||||
'--regex-size-limit=[the upper size limit of the compiled regex]:size'
|
||||
'(-r --replace)'{-r,--replace=}'[replace matches with string given]:replace string'
|
||||
'(-i -s -S --ignore-case --case-sensitive --smart-case)'{-s,--case-sensitive}'[search case sensitively]'
|
||||
'(-i -s -S --ignore-case --case-sensitive --smart-case)'{-S,--smart-case}'[search case insensitively if the pattern is all lowercase]'
|
||||
'(-j --threads)'{-j,--threads=}'[the approximate number of threads to use]:number of threads'
|
||||
'(-v --version)'{-V,--version}'[print version information]'
|
||||
'(-p --heading --no-heading --pretty)--vimgrep[show results with every match on its own line, including line numbers and column numbers]'
|
||||
'--regex-size-limit=[specify upper size limit of compiled regex]:regex size'
|
||||
'(-r --replace)'{-r,--replace=}'[specify string used to replace matches]:replace string'
|
||||
'(-i -s -S --ignore-case --case-sensitive --smart-case)'{-s,--case-sensitive}'[search case-sensitively]'
|
||||
'(-i -s -S --ignore-case --case-sensitive --smart-case)'{-S,--smart-case}'[search case-insensitively if the pattern is all lowercase]'
|
||||
'--sort-files[sort results by file path (disables parallelism)]'
|
||||
'(-j --threads)'{-j,--threads=}'[specify approximate number of threads to use]:number of threads'
|
||||
'(-v --version)'{-V,--version}'[display version information]'
|
||||
'(-p --heading --no-heading --pretty)--vimgrep[show results in vim-compatible format]'
|
||||
)
|
||||
|
||||
local -a file_type_management_options
|
||||
file_type_management_options=(
|
||||
'--type-list[show all supported file types and their associated globs]'
|
||||
'*--type-add=[add a new glob for a particular file type]:type'
|
||||
'*--type-clear=[clear the file type globs previously defined for specified type]: :->type'
|
||||
'*--type-add=[add new glob for file type]: :->typespec'
|
||||
'*--type-clear=[clear globs previously defined for specified file type]: :->type'
|
||||
)
|
||||
|
||||
_arguments -S -s : \
|
||||
@@ -122,11 +126,74 @@ _arguments -S -s : \
|
||||
&& ret=0
|
||||
|
||||
case "$state" in
|
||||
type)
|
||||
colorspec)
|
||||
_values -S ':' 'color/style type' \
|
||||
'column[specify coloring for column numbers]: :->attribute' \
|
||||
'line[specify coloring for line numbers]: :->attribute' \
|
||||
'match[specify coloring for match text]: :->attribute' \
|
||||
'path[specify color for file names]: :->attribute' && ret=0
|
||||
|
||||
[[ "$state" == 'attribute' ]] &&
|
||||
_values -S ':' 'color/style attribute' \
|
||||
'none[clear color/style for type]' \
|
||||
'bg[specify background color]: :->color' \
|
||||
'fg[specify foreground color]: :->color' \
|
||||
'style[specify text style]: :->style' && ret=0
|
||||
|
||||
[[ "$state" == 'color' ]] &&
|
||||
_values -S ':' 'color value' \
|
||||
black blue green red cyan magenta yellow white && ret=0
|
||||
|
||||
[[ "$state" == 'style' ]] &&
|
||||
_values -S ':' 'style value' \
|
||||
bold nobold intense nointense && ret=0
|
||||
;;
|
||||
|
||||
encoding)
|
||||
# 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
|
||||
local -U encodings
|
||||
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
|
||||
)
|
||||
|
||||
_describe -t encodings 'encoding' encodings && ret=0
|
||||
;;
|
||||
|
||||
type|typespec)
|
||||
local -U types
|
||||
types=( ${${(f)"$(_call_program types rg --type-list)"}%%:*} )
|
||||
|
||||
_describe -t types "type" types && ret=0
|
||||
if [[ "$case" == 'type' ]]; then
|
||||
_describe -t types "type" types && ret=0
|
||||
else
|
||||
# @todo: Would be nice to complete type names if an include: directive is
|
||||
# provided here
|
||||
_values -S ':' 'type spec' \
|
||||
${^types}':glob or include directive' && ret=0
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "ignore"
|
||||
version = "0.2.0" #:version
|
||||
version = "0.2.2" #:version
|
||||
authors = ["Andrew Gallant <jamslam@gmail.com>"]
|
||||
description = """
|
||||
A fast library for efficiently matching ignore files such as `.gitignore`
|
||||
|
@@ -20,7 +20,7 @@ Add this to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
ignore = "0.1"
|
||||
ignore = "0.2"
|
||||
```
|
||||
|
||||
and this to your crate root:
|
||||
|
@@ -169,8 +169,8 @@ impl Gitignore {
|
||||
self.num_whitelists
|
||||
}
|
||||
|
||||
/// Returns whether the given file path matched a pattern in this gitignore
|
||||
/// matcher.
|
||||
/// 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.
|
||||
@@ -191,6 +191,48 @@ impl Gitignore {
|
||||
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<P: AsRef<Path>>(
|
||||
&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<P: AsRef<Path>>(
|
||||
&self,
|
||||
@@ -254,6 +296,7 @@ pub struct GitignoreBuilder {
|
||||
builder: GlobSetBuilder,
|
||||
root: PathBuf,
|
||||
globs: Vec<Glob>,
|
||||
case_insensitive: bool,
|
||||
}
|
||||
|
||||
impl GitignoreBuilder {
|
||||
@@ -269,6 +312,7 @@ impl GitignoreBuilder {
|
||||
builder: GlobSetBuilder::new(),
|
||||
root: strip_prefix("./", root).unwrap_or(root).to_path_buf(),
|
||||
globs: vec![],
|
||||
case_insensitive: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -424,6 +468,7 @@ impl GitignoreBuilder {
|
||||
let parsed = try!(
|
||||
GlobBuilder::new(&glob.actual)
|
||||
.literal_separator(literal_separator)
|
||||
.case_insensitive(self.case_insensitive)
|
||||
.build()
|
||||
.map_err(|err| {
|
||||
Error::Glob {
|
||||
@@ -435,6 +480,16 @@ impl GitignoreBuilder {
|
||||
self.globs.push(glob);
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Toggle whether the globs should be matched case insensitively or not.
|
||||
///
|
||||
/// 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.
|
||||
@@ -617,4 +672,21 @@ mod tests {
|
||||
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");
|
||||
}
|
||||
|
@@ -137,6 +137,16 @@ impl OverrideBuilder {
|
||||
try!(self.builder.add_line(None, glob));
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Toggle whether the globs should be matched case insensitively or not.
|
||||
///
|
||||
/// This is disabled by default.
|
||||
pub fn case_insensitive(
|
||||
&mut self, yes: bool
|
||||
) -> Result<&mut OverrideBuilder, Error> {
|
||||
try!(self.builder.case_insensitive(yes));
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -220,4 +230,27 @@ mod tests {
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
@@ -102,6 +102,7 @@ const DEFAULT_TYPES: &'static [(&'static str, &'static [&'static str])] = &[
|
||||
("asm", &["*.asm", "*.s", "*.S"]),
|
||||
("awk", &["*.awk"]),
|
||||
("c", &["*.c", "*.h", "*.H"]),
|
||||
("cabal", &["*.cabal"]),
|
||||
("cbor", &["*.cbor"]),
|
||||
("ceylon", &["*.ceylon"]),
|
||||
("clojure", &["*.clj", "*.cljc", "*.cljs", "*.cljx"]),
|
||||
|
@@ -380,16 +380,16 @@ impl DirEntryRaw {
|
||||
/// 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 over
|
||||
/// less nested ignore files.
|
||||
/// * Third, if the previous step yields an ignore match, than all matching
|
||||
/// is stopped and the path is skipped.. If it yields a whitelist match, then
|
||||
/// process continues. A whitelist match can be overridden by a later matcher.
|
||||
/// 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's an ignore match, then all matching is stopped
|
||||
/// and the path is skipped. If it's a whitelist match, then matching
|
||||
/// continues.
|
||||
/// 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
|
||||
|
@@ -0,0 +1,216 @@
|
||||
# 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/**
|
297
ignore/tests/gitignore_matched_path_or_any_parents_tests.rs
Normal file
297
ignore/tests/gitignore_matched_path_or_any_parents_tests.rs
Normal file
@@ -0,0 +1,297 @@
|
||||
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()); // dir itself doesn't match
|
||||
assert!(m("ROOT/parent_dir/dir_deep_02/file", false).is_ignore());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_02/child_dir", true).is_ignore());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_02/child_dir/file", false).is_ignore());
|
||||
|
||||
// 03
|
||||
assert!(m("ROOT/parent_dir/dir_deep_03", true).is_none()); // dir itself doesn't match
|
||||
assert!(m("ROOT/parent_dir/dir_deep_03/file", false).is_ignore());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_03/child_dir", true).is_ignore());
|
||||
assert!(m("ROOT/parent_dir/dir_deep_03/child_dir/file", false).is_ignore());
|
||||
|
||||
// 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());
|
||||
}
|
29
src/app.rs
29
src/app.rs
@@ -50,6 +50,7 @@ pub fn app() -> App<'static, 'static> {
|
||||
App::new("ripgrep")
|
||||
.author(crate_authors!())
|
||||
.version(crate_version!())
|
||||
.long_version(LONG_VERSION.as_str())
|
||||
.about(ABOUT)
|
||||
.max_term_width(100)
|
||||
.setting(AppSettings::UnifiedHelpMessage)
|
||||
@@ -90,6 +91,9 @@ pub fn app() -> App<'static, 'static> {
|
||||
.arg(flag("glob").short("g")
|
||||
.takes_value(true).multiple(true).number_of_values(1)
|
||||
.value_name("GLOB"))
|
||||
.arg(flag("iglob")
|
||||
.takes_value(true).multiple(true).number_of_values(1)
|
||||
.value_name("GLOB"))
|
||||
.arg(flag("ignore-case").short("i"))
|
||||
.arg(flag("line-number").short("n"))
|
||||
.arg(flag("no-line-number").short("N").overrides_with("line-number"))
|
||||
@@ -191,6 +195,24 @@ macro_rules! doc {
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref LONG_VERSION: String = {
|
||||
let mut features: Vec<&str> = vec![];
|
||||
|
||||
if cfg!(feature = "avx-accel") {
|
||||
features.push("+AVX");
|
||||
} else {
|
||||
features.push("-AVX");
|
||||
}
|
||||
|
||||
if cfg!(feature = "simd-accel") {
|
||||
features.push("+SIMD");
|
||||
} else {
|
||||
features.push("-SIMD");
|
||||
}
|
||||
|
||||
format!("{}\n{}", crate_version!(), features.join(" "))
|
||||
};
|
||||
|
||||
static ref USAGES: HashMap<&'static str, Usage> = {
|
||||
let mut h = HashMap::new();
|
||||
doc!(h, "help-short",
|
||||
@@ -270,6 +292,13 @@ lazy_static! {
|
||||
ignore logic. Multiple glob flags may be used. Globbing \
|
||||
rules match .gitignore globs. Precede a glob with a ! \
|
||||
to exclude it.");
|
||||
doc!(h, "iglob",
|
||||
"Include or exclude files/directories case insensitively.",
|
||||
"Include or exclude files/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.");
|
||||
doc!(h, "ignore-case",
|
||||
"Case insensitive search.",
|
||||
"Case insensitive search. This is overridden by \
|
||||
|
@@ -771,6 +771,14 @@ impl<'a> ArgMatches<'a> {
|
||||
for glob in self.values_of_lossy_vec("glob") {
|
||||
try!(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...
|
||||
try!(ovr.case_insensitive(true));
|
||||
for glob in self.values_of_lossy_vec("iglob") {
|
||||
try!(ovr.add(&glob));
|
||||
}
|
||||
ovr.build().map_err(From::from)
|
||||
}
|
||||
|
||||
|
@@ -336,6 +336,21 @@ sherlock!(glob_negate, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| {
|
||||
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!(count, "Sherlock", ".", |wd: WorkDir, mut cmd: Command| {
|
||||
cmd.arg("--count");
|
||||
let lines: String = wd.stdout(&mut cmd);
|
||||
|
Reference in New Issue
Block a user