Compare commits

...

90 commits
dfa ... master

Author SHA1 Message Date
Geoff Greer
a61f1780b6
Merge pull request #1424 from sanjaymsh/ppc64le
Travis-ci: added support for ppc64le
2020-12-16 17:09:07 -08:00
sanjay-cpu
0da08b76af Travis-ci: added support for ppc64le 2020-12-11 07:18:23 +00:00
Geoff Greer
5a1c8d83ba Fix test. 2020-07-04 12:27:44 -07:00
Geoff Greer
cb9941b4bb
Merge pull request #1393 from JFLarvoire/winget
Document how to install ag.exe for Windows using winget
2020-07-04 12:22:31 -07:00
JFLarvoire
ed0fe56e79 Document how to install ag.exe for Windows using winget 2020-06-29 18:17:37 +02:00
Geoff Greer
5600c1b6b1
Merge pull request #1389 from aswild/getenv-segfault
options: fix segfault when TERM or HOME isn't set
2020-06-26 11:49:34 -07:00
Geoff Greer
6169c2d608
Merge pull request #1392 from corelight-chris/master
Change bro filetype support to zeek.
2020-06-26 11:48:57 -07:00
Geoff Greer
9b23390076
Merge pull request #1390 from matthewhughes934/fix-list_file_types-test
Add missing whitespace to test
2020-06-26 11:48:44 -07:00
Christopher M. Hobbs
01f2a97ab6 Change bro filetype support to zeek. 2020-06-25 17:19:16 -05:00
Allen Wild
0da483f0a5 tests: add empty_environment test, fix whitespace in list_file_types
Verify that ag works with no environment variables set.
2020-06-22 11:17:40 -04:00
Matthew Hughes
d949e71d9d Add missing whitespace to test
This fixes the failing test.

* Add missing indentation (missed in c95d72f)
* Add missing newline at end of file (removed with 328afb2)
2020-06-22 15:55:24 +01:00
Allen Wild
1dae7a25a3 options: fix segfault when TERM or HOME isn't set
Regression from 3289ab8fba, if TERM isn't
set in the environment, getenv returns NULL which we shouldn't strcmp.
Similarly guard against using home_dir if it's null when looking for
global gitignore files.

This can be reproduced and tested with `env -i ./ag foo`.
2020-06-22 00:14:30 -04:00
Geoff Greer
a9917e4490
Merge pull request #1326 from Redfoxymoon/master
midipix support
2020-06-20 17:09:43 -07:00
Geoff Greer
cd0705f12a
Merge pull request #1350 from sergeyklay/feature/zephir-support
Add Zephir support
2020-06-20 17:09:22 -07:00
Geoff Greer
8a7032e89b
Merge pull request #1387 from yymm/master
Add support for Vue SFC
2020-06-20 17:08:02 -07:00
Geoff Greer
f7b15a0b03
Merge pull request #1384 from felipefiali/master
Add support for Bazel files
2020-06-20 17:07:50 -07:00
Geoff Greer
3f6ecb6c02
Merge pull request #1377 from shlomif/fix-multi-defs-of-globals
Fix multiple global symbols definitions.
2020-06-20 17:07:07 -07:00
Geoff Greer
092d73b190
Merge pull request #1330 from MicahElliott/clojure-add-edn-file-type
Add .edn file type for clojure files
2020-06-19 18:40:58 -07:00
Geoff Greer
56e73c9f0a
Merge pull request #1332 from wgrr/nodefault-color
Default to no color when $TERM is dumb
2020-06-19 18:40:29 -07:00
Geoff Greer
0aa76d6bfe
Merge pull request #1383 from Alexis-D/ad/add-gradle
Add --gradle
2020-06-19 18:40:07 -07:00
Geoff Greer
6342a8ed28
Merge pull request #1374 from equwal/master
Update link to ack3
2020-06-19 17:31:59 -07:00
Geoff Greer
e55cc9baa6
Merge pull request #1372 from dzmitry-lahoda/patch-1
added fzf
2020-06-19 17:31:45 -07:00
Geoff Greer
4fc15ecd70
Merge pull request #1359 from nbarrios1337/fix_bash_completion
Update bash completion script to reflect v2.0 changes
2020-06-19 17:28:13 -07:00
Geoff Greer
594c447d28
Merge pull request #1362 from veprbl/patch-1
README: add NixOS/Nix/Nixpkgs instructions
2020-06-19 17:27:55 -07:00
yuya yano
cbebe3b77e Add support for Vue SFC 2020-06-09 14:57:14 +09:00
Felipe Fiali
c95d72f3e7 Add support for Bazel files 2020-05-26 10:55:25 +02:00
Alexis Daboville
31376c9c5c Add --gradle 2020-05-22 16:24:54 +01:00
Shlomi Fish
21eaa1c416 Fix multiple global symbols definitions.
See the use of extern here:

* https://www.geeksforgeeks.org/understanding-extern-keyword-in-c/

* https://en.wikipedia.org/wiki/External_variable

*
https://stackoverflow.com/questions/496448/how-to-correctly-use-the-extern-keyword-in-c
2020-04-15 20:26:10 +03:00
Spenser Truex
293697938c Update link to ack3
New version has a new repo.
2020-03-28 15:41:46 -07:00
Dzmitry Lahoda
cba17bc01f
added fzf 2020-03-25 15:01:24 +03:00
Dmitry Kalinkin
232b85bed5
README: add NixOS/Nix/Nixpkgs instructions 2020-02-27 11:10:26 -05:00
Geoff Greer
b93c271993
Merge pull request #1358 from gliptak/patch-1
Bring Ubuntu to 16.04 in Travis
2020-02-24 15:18:49 -08:00
Nicolas Barrios
860046891c
Updated bash completion script to reflect v2.0 changes 2020-02-21 14:01:01 -05:00
Gábor Lipták
9fc018f0f1
Bring Ubuntu to 16.04 in Travis 2020-02-18 10:26:31 -05:00
Geoff Greer
a509a8172b Fix formatting. 2020-01-10 11:25:39 -08:00
Geoff Greer
de3e3c7cac
Merge pull request #1354 from emoses/master
Fix ignore patterns in subdirectories with leading slashes
2020-01-10 11:23:05 -08:00
Evan Moses
755c6e5c06 Fix ignore patterns in subdirectories with leading slashes
Currenetly if you have an ignore file in a subdirectory "sub" with a pattern
like
    /ignorethis
The directory sub/ignorethis will be ignored if you run ag from
within sub, but it won't be ignored if you run it from sub's parent.
that is

    $ ag needle

will search files in sub/ignorethis, but

    $ cd sub
    $ ag needle

Will not.  This is a bug
2020-01-09 17:34:44 -08:00
Serghei Iakovlev
328afb27d3
Add Zephir support 2019-12-20 12:58:32 +02:00
Wagner Riffel
3289ab8fba default to no color when terminal is dumb
Signed-off-by: Wagner Riffel <wgrriffel@gmail.com>
2019-08-18 22:49:50 -03:00
Micah Elliott
c1514aeee0 Add .edn file type for clojure files
It's common that you'd want edn files to show up in your clojure
searching.

https://github.com/edn-format/edn
2019-08-13 10:47:17 -07:00
Ørjan Malde
b34f3e385e
midipix support
midipix uses the musl libc, which provides the same bits as on linux.
2019-06-29 23:13:49 +02:00
Geoff Greer
965f71dcbc
Merge pull request #1245 from kpengboy/fix_-L
Fix -L again and decouple from -v
2019-03-22 09:11:11 -07:00
Geoff Greer
55eaaddab5
Merge pull request #1306 from brianary/feature-windows-extensions
Add various Windows extensions
2019-03-18 19:30:42 -07:00
Geoff Greer
20941e2bfd
Merge pull request #1310 from DeeeeLAN/verilog/work
added .svh for verilog
2019-03-18 19:30:18 -07:00
Dillan Mills
41fd43f48c added .svh for verilog 2019-03-05 22:56:28 -07:00
Brian Lalonde
09a7c68921 Fix trailing whitespace 2019-02-18 20:18:56 -08:00
Brian Lalonde
c951fc2c40 Add various Windows extensions 2019-02-18 20:12:07 -08:00
Geoff Greer
4f7aca7b01
Merge pull request #1270 from zealoussnow/fix-rpmbuild-error
fix rpmbuild error
2019-02-16 11:41:03 -08:00
Geoff Greer
7c70fe3b9b
Merge pull request #1287 from jacwah/pipe-link
Skip symlinks to named pipes
2019-01-17 17:20:17 -08:00
Geoff Greer
fa8cd32008
Merge pull request #1290 from aitzkora/master
add some extensions in uppercase for fortran files : now, the list has a length < 12
2019-01-17 17:16:51 -08:00
aitzkora
23e5b507c5 suppress some extension in fortran to be less than 12 2018-12-03 13:54:58 +01:00
aitzkora
14e5fe6f91 add support in fortran types for preprocessed files with uppercases 2018-12-03 12:38:35 +01:00
Jacob Wahlgren
095c3f091e Skip symlinks to named pipes
The d_type field contains the type as lstat would put it, but when
checking for a named pipe we need the stat behavior.

Fixes https://github.com/ggreer/the_silver_searcher/issues/1272
2018-11-28 23:42:24 +01:00
Jeff Horelick
1b06a9fd8d
Merge pull request #1283 from zawataki/add-dependencies-for-CentOS-onto-README
Add necessary dependencies in case build on CentOS
2018-11-26 11:11:39 -05:00
Yuki Takizawa
7a8143a41d Add necessary dependencies in case build on CentOS 2018-11-23 17:56:40 +09:00
Leo Zhang
295ab1072e fix rpmbuild error 2018-09-18 14:52:33 +08:00
Geoff Greer
bd82cd3d2f Add Travis IRC notifications. 2018-08-07 00:07:25 -07:00
Geoff Greer
97f33796a1 Update LLVM version for travis. 2018-08-06 23:59:21 -07:00
Geoff Greer
520ff29c52 Bump version to v2.2.0 2018-08-06 23:43:51 -07:00
Geoff Greer
93bd01ae94
Merge pull request #1209 from travisjeffery/master
Support terraform file type
2018-08-06 23:41:04 -07:00
Geoff Greer
ea9080d373
Merge pull request #1249 from alexbiehl/patch-1
Also search Backpack signatures for Haskell
2018-08-06 23:40:31 -07:00
Geoff Greer
5afe087759
Merge pull request #1253 from bapfeld/master
Adds stata files as a filetype option
2018-08-06 23:40:18 -07:00
Geoff Greer
838c03ad27 Improve performance when not using mmap()ed I/O (mostly macOS)
If ignoring binary files (the default behavior), read the first 512 bytes and call is_binary(). Previously, ag read the entire file (possibly gigabytes), checked the first 512 bytes, then didn't search the file. That could be comically wasteful.
2018-08-06 23:36:18 -07:00
Geoff Greer
7ada8f665c clang-format 2018-08-06 23:20:37 -07:00
Geoff Greer
bd320d43a2 On some platforms, read() will only read 2GB-4GB maximum. read() again until the whole file is in memory. 2018-08-04 23:46:08 -07:00
Kevin Peng
1c2a64d58b Fix -L again and decouple from -v 2018-08-02 03:09:57 -07:00
Kevin Peng
5c2c18ca17 Refactor search_buf and search_stream to return # matches 2018-08-02 03:09:57 -07:00
Brendan Apfeld
70841b4892 Fix white space between lines 2018-07-06 08:06:04 -05:00
Brendan Apfeld
c442e39efb Adds stata files as a language option 2018-07-04 14:56:52 -05:00
Alexander Biehl
ae53f271d4
Update list_file_types.t 2018-06-18 16:47:30 +02:00
Alexander Biehl
1a556b587b
Add hsig files for Haskell 2018-06-18 16:32:19 +02:00
Travis Jeffery
9191a7b197 add tfvars 2018-06-07 09:08:18 -04:00
Geoff Greer
9163065a5e
Merge pull request #1208 from jschneier/master
Add pug as a supported file type
2018-06-07 00:15:29 -07:00
Geoff Greer
160ea7bb1e
Merge pull request #1239 from aswild/buf-readline
util: buf_getline: validate index of the next byte before reading it
2018-06-02 22:41:40 -07:00
Allen Wild
17072d8849 util: buf_getline: validate index of the next byte before reading it
buf_getline dereferences cur[i] before checking that i is a valid index
in the buffer. Under the right circumstances, this can cause
a segmentation fault.

The right circumstances are:
  * multiline search disabled (the only way buf_getline is called)
  * file size is an exact multiple of the page size (4096 bytes)
  * end of file has no trailing newline
  * searching a directory (not just a single file on the command line)
  * using several worker threads

(I don't think the last two points are directly related to this bug, but
I couldn't reproduce it otherwise)

Address Sanitizer catches this consistently as a heap overflow if run
when mmap is disabled.

Swap the order of the for loop's condition checks so that i is validated
before dereferencing cur[i].

Signed-off-by: Allen Wild <allenwild93@gmail.com>
2018-05-10 21:52:49 -04:00
Geoff Greer
5b10c68e0f
Merge pull request #1194 from bazzargh/patch-1
Add -W/--width option to man page
2018-04-22 17:57:30 -07:00
Geoff Greer
eebcd60784
Merge pull request #1224 from Liambeguin/master
add filter for devicetree source files
2018-04-22 17:54:02 -07:00
Geoff Greer
be53a330d9
Merge pull request #1231 from nbeernink/patch-1
fix ack.vim link in README.md
2018-04-22 17:53:08 -07:00
Niek Beernink
de495b00eb
Update README.md
fixed ack.vim link
2018-03-28 14:16:17 +02:00
Liam Beguin
7051a784aa add filter for devicetree source files
Signed-off-by: Liam Beguin <lvb@xiphos.com>
2018-03-03 18:55:59 -05:00
Travis Jeffery
261b60a57e support terraform file type 2018-01-27 21:31:24 -05:00
Josh Schneier
f56e91391d Add pug as a supported file type 2018-01-27 16:02:35 +07:00
Geoff Greer
4aa9f05ec3
Merge pull request #1203 from felipefiali/master
Adding support for .thrift files search by using --thrift
2018-01-24 03:12:51 +00:00
Geoff Greer
f54d31f650
Merge pull request #1202 from Nelyah/master
adding support for PDB (Protein Data Bank) with --pdb and Naccess format with --naccess
2018-01-24 03:12:37 +00:00
Felipe Fiali
e8b6b3e292 Adding support for .thrift files 2018-01-23 17:24:54 -02:00
Chloé Dequeker
3b20a68907 tests really pass for list_file_types.t 2018-01-22 20:49:48 +01:00
Chloé Dequeker
b6fc5e83ac fixing format list_file_types.t 2018-01-22 20:41:17 +01:00
Chloé Dequeker
2e9a22fb1a adding support for PDB (Protein Data Bank) and Naccess format 2018-01-22 20:19:54 +01:00
bazzargh
f4d22405ac
Add -W/--width option to man page
The option added in #720 never made it onto the man page.
2018-01-08 19:02:00 +00:00
Geoff Greer
5516568a30 Replace longs in ag_stats struct with size_t. Should help with #1158. 2017-12-26 22:25:16 -08:00
22 changed files with 331 additions and 88 deletions

View file

@ -1,9 +1,14 @@
language: c
dist: xenial
sudo: false
branches:
only:
- master
- ppc64le
arch:
- amd64
- ppc64le
compiler:
- clang
@ -22,12 +27,12 @@ addons:
env:
global:
- LLVM_VERSION=3.8.0
- LLVM_VERSION=6.0.1
- LLVM_PATH=$HOME/clang+llvm
- CLANG_FORMAT=$LLVM_PATH/bin/clang-format
before_install:
- wget http://llvm.org/releases/$LLVM_VERSION/clang+llvm-$LLVM_VERSION-x86_64-linux-gnu-ubuntu-14.04.tar.xz -O $LLVM_PATH.tar.xz
- wget http://llvm.org/releases/$LLVM_VERSION/clang+llvm-$LLVM_VERSION-x86_64-linux-gnu-ubuntu-16.04.tar.xz -O $LLVM_PATH.tar.xz
- mkdir $LLVM_PATH
- tar xf $LLVM_PATH.tar.xz -C $LLVM_PATH --strip-components=1
- export PATH=$HOME/.local/bin:$PATH
@ -37,3 +42,9 @@ install:
script:
- ./build.sh && make test
notifications:
irc: 'chat.freenode.net#ag'
on_success: change
on_failure: always
use_notice: true

View file

@ -76,14 +76,18 @@ or
sbopkg -i the_silver_searcher
* openSUSE:
* openSUSE
zypper install the_silver_searcher
* CentOS:
* CentOS
yum install the_silver_searcher
* NixOS/Nix/Nixpkgs
nix-env -iA silver-searcher
* SUSE Linux Enterprise: Follow [these simple instructions](https://software.opensuse.org/download.html?project=utilities&package=the_silver_searcher).
@ -102,6 +106,20 @@ or
Unofficial daily builds are [available](https://github.com/k-takata/the_silver_searcher-win32).
* winget
winget install "The Silver Searcher"
Notes:
- This installs a [release](https://github.com/JFLarvoire/the_silver_searcher/releases) of ag.exe optimized for Windows.
- winget is intended to become the default package manager client for Windows.
As of June 2020, it's still in beta, and can be installed using instructions [there](https://github.com/microsoft/winget-cli).
- The setup script in the Ag's winget package installs ag.exe in the first directory that matches one of these criteria:
1. Over a previous instance of ag.exe *from the same [origin](https://github.com/JFLarvoire/the_silver_searcher)* found in the PATH
2. In the directory defined in environment variable bindir_%PROCESSOR_ARCHITECTURE%
3. In the directory defined in environment variable bindir
4. In the directory defined in environment variable windir
* Chocolatey
choco install ag
@ -132,7 +150,7 @@ or
* CentOS:
yum -y groupinstall "Development Tools"
yum -y install pcre-devel xz-devel
yum -y install pcre-devel xz-devel zlib-devel
* openSUSE:
zypper source-install --build-deps-only the_silver_searcher
@ -167,7 +185,7 @@ You may need to use `sudo` or run as root for the make install.
### Vim
You can use Ag with [ack.vim][] by adding the following line to your `.vimrc`:
You can use Ag with [ack.vim](https://github.com/mileszs/ack.vim) by adding the following line to your `.vimrc`:
let g:ackprg = 'ag --nogroup --nocolor --column'
@ -190,9 +208,10 @@ TextMate users can use Ag with [my fork](https://github.com/ggreer/AckMate) of t
## Other stuff you might like
* [Ack](https://github.com/petdance/ack2) - Better than grep. Without Ack, Ag would not exist.
* [Ack](https://github.com/petdance/ack3) - Better than grep. Without Ack, Ag would not exist.
* [ack.vim](https://github.com/mileszs/ack.vim)
* [Exuberant Ctags](http://ctags.sourceforge.net/) - Faster than Ag, but it builds an index beforehand. Good for *really* big codebases.
* [Git-grep](http://git-scm.com/docs/git-grep) - As fast as Ag but only works on git repos.
* [fzf](https://github.com/junegunn/fzf) - A command-line fuzzy finder
* [ripgrep](https://github.com/BurntSushi/ripgrep)
* [Sack](https://github.com/sampson-chen/sack) - A utility that wraps Ack and Ag. It removes a lot of repetition from searching and opening matching files.

View file

@ -67,7 +67,7 @@ _ag() {
--parallel
--passthrough
--passthru
--path-to-agignore
--path-to-ignore
--print-long-lines
--print0
--recurse
@ -106,7 +106,7 @@ _ag() {
--ignore-dir) # directory completion
_filedir -d
return 0;;
--path-to-agignore) # file completion
--path-to-ignore) # file completion
_filedir
return 0;;
--pager) # command completion

View file

@ -1,6 +1,6 @@
AC_INIT(
[the_silver_searcher],
[2.1.0],
[2.2.0],
[https://github.com/ggreer/the_silver_searcher/issues],
[the_silver_searcher],
[https://github.com/ggreer/the_silver_searcher])

View file

@ -207,6 +207,9 @@ Recursively search for PATTERN in PATH. Like grep or ack, but faster.
* `--workers NUM`:
Use NUM worker threads. Default is the number of CPU cores, with a max of 8.
* `-W --width NUM`:
Truncate match lines after NUM characters.
* `-z --search-zip`:
Search contents of compressed files. Currently, gz and xz are supported.
This option requires that ag is built with lzma and zlib.

View file

@ -20,6 +20,8 @@
const int fnmatch_flags = FNM_PATHNAME;
#endif
ignores *root_ignores;
/* TODO: build a huge-ass list of files we want to ignore by default (build cache stuff, pyc files, etc) */
const char *evil_hardcoded_ignore_files[] = {
@ -206,6 +208,7 @@ static int ackmate_dir_match(const char *dir_name) {
/* This is the hottest code in Ag. 10-15% of all execution time is spent here */
static int path_ignore_search(const ignores *ig, const char *path, const char *filename) {
char *temp;
int temp_start_pos;
size_t i;
int match_pos;
@ -216,9 +219,12 @@ static int path_ignore_search(const ignores *ig, const char *path, const char *f
}
ag_asprintf(&temp, "%s/%s", path[0] == '.' ? path + 1 : path, filename);
//ig->abs_path has its leading slash stripped, so we have to strip the leading slash
//of temp as well
temp_start_pos = (temp[0] == '/') ? 1 : 0;
if (strncmp(temp, ig->abs_path, ig->abs_path_len) == 0) {
char *slash_filename = temp + ig->abs_path_len;
if (strncmp(temp + temp_start_pos, ig->abs_path, ig->abs_path_len) == 0) {
char *slash_filename = temp + temp_start_pos + ig->abs_path_len;
if (slash_filename[0] == '/') {
slash_filename++;
}

View file

@ -29,7 +29,7 @@ struct ignores {
};
typedef struct ignores ignores;
ignores *root_ignores;
extern ignores *root_ignores;
extern const char *evil_hardcoded_ignore_files[];
extern const char *ignore_pattern_files[];

View file

@ -10,38 +10,44 @@ lang_spec_t langs[] = {
{ "asciidoc", { "adoc", "ad", "asc", "asciidoc" } },
{ "apl", { "apl" } },
{ "asm", { "asm", "s" } },
{ "asp", { "asp", "asa", "aspx", "asax", "ashx", "ascx", "asmx" } },
{ "aspx", { "asp", "asa", "aspx", "asax", "ashx", "ascx", "asmx" } },
{ "batch", { "bat", "cmd" } },
{ "bazel", { "bazel" } },
{ "bitbake", { "bb", "bbappend", "bbclass", "inc" } },
{ "bro", { "bro", "bif" } },
{ "cc", { "c", "h", "xs" } },
{ "cfmx", { "cfc", "cfm", "cfml" } },
{ "chpl", { "chpl" } },
{ "clojure", { "clj", "cljs", "cljc", "cljx" } },
{ "clojure", { "clj", "cljs", "cljc", "cljx", "edn" } },
{ "coffee", { "coffee", "cjsx" } },
{ "config", { "config" } },
{ "coq", { "coq", "g", "v" } },
{ "cpp", { "cpp", "cc", "C", "cxx", "m", "hpp", "hh", "h", "H", "hxx", "tpp" } },
{ "crystal", { "cr", "ecr" } },
{ "csharp", { "cs" } },
{ "cshtml", { "cshtml" } },
{ "css", { "css" } },
{ "cython", { "pyx", "pxd", "pxi" } },
{ "delphi", { "pas", "int", "dfm", "nfm", "dof", "dpk", "dpr", "dproj", "groupproj", "bdsgroup", "bdsproj" } },
{ "dlang", { "d", "di" } },
{ "dot", { "dot", "gv" } },
{ "dts", { "dts", "dtsi" } },
{ "ebuild", { "ebuild", "eclass" } },
{ "elisp", { "el" } },
{ "elixir", { "ex", "eex", "exs" } },
{ "elm", { "elm" } },
{ "erlang", { "erl", "hrl" } },
{ "factor", { "factor" } },
{ "fortran", { "f", "f77", "f90", "f95", "f03", "for", "ftn", "fpp" } },
{ "fortran", { "f", "F", "f77", "f90", "F90", "f95", "f03", "for", "ftn", "fpp", "FPP" } },
{ "fsharp", { "fs", "fsi", "fsx" } },
{ "gettext", { "po", "pot", "mo" } },
{ "glsl", { "vert", "tesc", "tese", "geom", "frag", "comp" } },
{ "go", { "go" } },
{ "gradle", { "gradle" } },
{ "groovy", { "groovy", "gtmpl", "gpp", "grunit", "gradle" } },
{ "haml", { "haml" } },
{ "handlebars", { "hbs" } },
{ "haskell", { "hs", "lhs" } },
{ "haskell", { "hs", "hsig", "lhs" } },
{ "haxe", { "hx" } },
{ "hh", { "h" } },
{ "html", { "htm", "html", "shtml", "xhtml" } },
@ -72,6 +78,7 @@ lang_spec_t langs[] = {
{ "mathematica", { "m", "wl" } },
{ "md", { "markdown", "mdown", "mdwn", "mkdn", "mkd", "md" } },
{ "mercury", { "m", "moo" } },
{ "naccess", { "asa", "rsa" } },
{ "nim", { "nim" } },
{ "nix", { "nix" } },
{ "objc", { "m", "h" } },
@ -80,17 +87,22 @@ lang_spec_t langs[] = {
{ "octave", { "m" } },
{ "org", { "org" } },
{ "parrot", { "pir", "pasm", "pmc", "ops", "pod", "pg", "tg" } },
{ "pdb", { "pdb" } },
{ "perl", { "pl", "pm", "pm6", "pod", "t" } },
{ "php", { "php", "phpt", "php3", "php4", "php5", "phtml" } },
{ "pike", { "pike", "pmod" } },
{ "plist", { "plist" } },
{ "plone", { "pt", "cpt", "metadata", "cpy", "py", "xml", "zcml" } },
{ "powershell", { "ps1" } },
{ "proto", { "proto" } },
{ "ps1", { "ps1" } },
{ "pug", { "pug" } },
{ "puppet", { "pp" } },
{ "python", { "py" } },
{ "qml", { "qml" } },
{ "racket", { "rkt", "ss", "scm" } },
{ "rake", { "Rakefile" } },
{ "razor", { "cshtml" } },
{ "restructuredtext", { "rst" } },
{ "rs", { "rs" } },
{ "r", { "r", "R", "Rmd", "Rnw", "Rtex", "Rrst" } },
@ -105,10 +117,13 @@ lang_spec_t langs[] = {
{ "smalltalk", { "st" } },
{ "sml", { "sml", "fun", "mlb", "sig" } },
{ "sql", { "sql", "ctl" } },
{ "stata", { "do", "ado" } },
{ "stylus", { "styl" } },
{ "swift", { "swift" } },
{ "tcl", { "tcl", "itcl", "itk" } },
{ "terraform", { "tf", "tfvars" } },
{ "tex", { "tex", "cls", "sty" } },
{ "thrift", { "thrift" } },
{ "tla", { "tla" } },
{ "tt", { "tt", "tt2", "ttml" } },
{ "toml", { "toml" } },
@ -117,14 +132,17 @@ lang_spec_t langs[] = {
{ "vala", { "vala", "vapi" } },
{ "vb", { "bas", "cls", "frm", "ctl", "vb", "resx" } },
{ "velocity", { "vm", "vtl", "vsl" } },
{ "verilog", { "v", "vh", "sv" } },
{ "verilog", { "v", "vh", "sv", "svh" } },
{ "vhdl", { "vhd", "vhdl" } },
{ "vim", { "vim" } },
{ "vue", { "vue" } },
{ "wix", { "wxi", "wxs" } },
{ "wsdl", { "wsdl" } },
{ "wadl", { "wadl" } },
{ "xml", { "xml", "dtd", "xsl", "xslt", "ent", "tld", "plist" } },
{ "yaml", { "yaml", "yml" } }
{ "xml", { "xml", "dtd", "xsl", "xslt", "xsd", "ent", "tld", "plist", "wsdl" } },
{ "yaml", { "yaml", "yml" } },
{ "zeek", { "zeek", "bro", "bif" } },
{ "zephir", { "zep" } }
};
size_t get_lang_count() {

View file

@ -4,6 +4,7 @@
#include "log.h"
#include "util.h"
pthread_mutex_t print_mtx = PTHREAD_MUTEX_INITIALIZER;
static enum log_level log_threshold = LOG_LEVEL_ERR;
void set_log_level(enum log_level threshold) {

View file

@ -9,7 +9,7 @@
#include <pthread.h>
#endif
pthread_mutex_t print_mtx;
extern pthread_mutex_t print_mtx;
enum log_level {
LOG_LEVEL_DEBUG = 10,

View file

@ -154,7 +154,7 @@ int main(int argc, char **argv) {
}
#if defined(HAVE_PTHREAD_SETAFFINITY_NP) && (defined(USE_CPU_SET) || defined(HAVE_SYS_CPUSET_H))
if (opts.use_thread_affinity) {
#ifdef __linux__
#if defined(__linux__) || defined(__midipix__)
cpu_set_t cpu_set;
#elif __FreeBSD__
cpuset_t cpu_set;
@ -185,7 +185,7 @@ int main(int argc, char **argv) {
log_debug("searching path %s for %s", paths[i], opts.query);
symhash = NULL;
ignores *ig = init_ignore(root_ignores, "", 0);
struct stat s = {.st_dev = 0 };
struct stat s = { .st_dev = 0 };
#ifndef _WIN32
/* The device is ignored if opts.one_dev is false, so it's fine
* to leave it at the default 0
@ -213,7 +213,7 @@ int main(int argc, char **argv) {
double time_diff = ((long)stats.time_end.tv_sec * 1000000 + stats.time_end.tv_usec) -
((long)stats.time_start.tv_sec * 1000000 + stats.time_start.tv_usec);
time_diff /= 1000000;
printf("%ld matches\n%ld files contained matches\n%ld files searched\n%ld bytes searched\n%f seconds\n",
printf("%zu matches\n%zu files contained matches\n%zu files searched\n%zu bytes searched\n%f seconds\n",
stats.total_matches, stats.total_file_matches, stats.total_files, stats.total_bytes, time_diff);
pthread_mutex_destroy(&stats_mtx);
}

View file

@ -20,6 +20,8 @@ const char *color_line_number = "\033[1;33m"; /* bold yellow */
const char *color_match = "\033[30;43m"; /* black with yellow background */
const char *color_path = "\033[1;32m"; /* bold green */
cli_options opts;
/* TODO: try to obey out_fd? */
void usage(void) {
printf("\n");
@ -143,9 +145,14 @@ void print_version(void) {
}
void init_options(void) {
char *term = getenv("TERM");
memset(&opts, 0, sizeof(opts));
opts.casing = CASE_DEFAULT;
opts.color = TRUE;
if (term && !strcmp(term, "dumb")) {
opts.color = FALSE;
}
opts.color_win_ansi = FALSE;
opts.max_matches_per_file = 0;
opts.max_search_depth = DEFAULT_MAX_SEARCH_DEPTH;
@ -446,8 +453,9 @@ void parse_options(int argc, char **argv, char **base_paths[], char **paths[]) {
opts.casing = CASE_INSENSITIVE;
break;
case 'L':
opts.invert_match = 1;
/* fall through */
opts.print_nonmatching_files = 1;
opts.print_path = PATH_PRINT_TOP;
break;
case 'l':
needs_query = 0;
opts.print_filename_only = 1;
@ -705,8 +713,10 @@ void parse_options(int argc, char **argv, char **base_paths[], char **paths[]) {
const char *config_home = getenv("XDG_CONFIG_HOME");
if (config_home) {
ag_asprintf(&gitconfig_res, "%s/%s", config_home, "git/ignore");
} else {
} else if (home_dir) {
ag_asprintf(&gitconfig_res, "%s/%s", home_dir, ".config/git/ignore");
} else {
gitconfig_res = ag_strdup("");
}
}
log_debug("global core.excludesfile: %s", gitconfig_res);

View file

@ -60,6 +60,7 @@ typedef struct {
int print_break;
int print_count;
int print_filename_only;
int print_nonmatching_files;
int print_path;
int print_all_paths;
int print_line_numbers;
@ -91,7 +92,7 @@ typedef struct {
} cli_options;
/* global options. parse_options gives it sane values, everything else reads from it */
cli_options opts;
extern cli_options opts;
typedef struct option option_t;

View file

@ -2,18 +2,32 @@
#include "print.h"
#include "scandir.h"
void search_buf(const char *buf, const size_t buf_len,
const char *dir_full_path) {
size_t alpha_skip_lookup[256];
size_t *find_skip_lookup;
uint8_t h_table[H_SIZE] __attribute__((aligned(64)));
work_queue_t *work_queue = NULL;
work_queue_t *work_queue_tail = NULL;
int done_adding_files = 0;
pthread_cond_t files_ready = PTHREAD_COND_INITIALIZER;
pthread_mutex_t stats_mtx = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t work_queue_mtx = PTHREAD_MUTEX_INITIALIZER;
symdir_t *symhash = NULL;
/* Returns: -1 if skipped, otherwise # of matches */
ssize_t search_buf(const char *buf, const size_t buf_len,
const char *dir_full_path) {
int binary = -1; /* 1 = yes, 0 = no, -1 = don't know */
size_t buf_offset = 0;
if (opts.search_stream) {
binary = 0;
} else if (!opts.search_binary_files) {
} else if (!opts.search_binary_files && opts.mmap) { /* if not using mmap, binary files have already been skipped */
binary = is_binary((const void *)buf, buf_len);
if (binary) {
log_debug("File %s is binary. Skipping...", dir_full_path);
return;
return -1;
}
}
@ -174,25 +188,16 @@ multiline_done:
pthread_mutex_unlock(&stats_mtx);
}
if (matches_len > 0 || opts.print_all_paths) {
if (!opts.print_nonmatching_files && (matches_len > 0 || opts.print_all_paths)) {
if (binary == -1 && !opts.print_filename_only) {
binary = is_binary((const void *)buf, buf_len);
}
pthread_mutex_lock(&print_mtx);
if (opts.print_filename_only) {
/* If the --files-without-matches or -L option is passed we should
* not print a matching line. This option currently sets
* opts.print_filename_only and opts.invert_match. Unfortunately
* setting the latter has the side effect of making matches.len = 1
* on a file-without-matches which is not desired behaviour. See
* GitHub issue 206 for the consequences if this behaviour is not
* checked. */
if (!opts.invert_match || matches_len < 2) {
if (opts.print_count) {
print_path_count(dir_full_path, opts.path_sep, (size_t)matches_len);
} else {
print_path(dir_full_path, opts.path_sep);
}
if (opts.print_count) {
print_path_count(dir_full_path, opts.path_sep, (size_t)matches_len);
} else {
print_path(dir_full_path, opts.path_sep);
}
} else if (binary) {
print_binary_file_matches(dir_full_path);
@ -214,11 +219,16 @@ multiline_done:
if (matches_size > 0) {
free(matches);
}
/* FIXME: handle case where matches_len > SSIZE_MAX */
return (ssize_t)matches_len;
}
/* Return value: -1 if skipped, otherwise # of matches */
/* TODO: this will only match single lines. multi-line regexes silently don't match */
void search_stream(FILE *stream, const char *path) {
ssize_t search_stream(FILE *stream, const char *path) {
char *line = NULL;
ssize_t matches_count = 0;
ssize_t line_len = 0;
size_t line_cap = 0;
size_t i;
@ -226,8 +236,17 @@ void search_stream(FILE *stream, const char *path) {
print_init_context();
for (i = 1; (line_len = getline(&line, &line_cap, stream)) > 0; i++) {
ssize_t result;
opts.stream_line_num = i;
search_buf(line, line_len, path);
result = search_buf(line, line_len, path);
if (result > 0) {
if (matches_count == -1) {
matches_count = 0;
}
matches_count += result;
} else if (matches_count <= 0 && result == -1) {
matches_count = -1;
}
if (line[line_len - 1] == '\n') {
line_len--;
}
@ -236,6 +255,7 @@ void search_stream(FILE *stream, const char *path) {
free(line);
print_cleanup_context();
return matches_count;
}
void search_file(const char *file_full_path) {
@ -244,6 +264,7 @@ void search_file(const char *file_full_path) {
char *buf = NULL;
struct stat statbuf;
int rv = 0;
int matches_count = -1;
FILE *fp = NULL;
rv = stat(file_full_path, &statbuf);
@ -293,7 +314,7 @@ void search_file(const char *file_full_path) {
if (statbuf.st_mode & S_IFIFO) {
log_debug("%s is a named pipe. stream searching", file_full_path);
fp = fdopen(fd, "r");
search_stream(fp, file_full_path);
matches_count = search_stream(fp, file_full_path);
fclose(fp);
goto cleanup;
}
@ -302,7 +323,7 @@ void search_file(const char *file_full_path) {
if (f_len == 0) {
if (opts.query[0] == '.' && opts.query_len == 1 && !opts.literal && opts.search_all_files) {
search_buf(buf, f_len, file_full_path);
matches_count = search_buf(buf, f_len, file_full_path);
} else {
log_debug("Skipping %s: file is empty.", file_full_path);
}
@ -347,9 +368,23 @@ void search_file(const char *file_full_path) {
#endif
} else {
buf = ag_malloc(f_len);
size_t bytes_read = read(fd, buf, f_len);
if ((off_t)bytes_read != f_len) {
die("expected to read %u bytes but read %u", f_len, bytes_read);
ssize_t bytes_read = 0;
if (!opts.search_binary_files) {
bytes_read += read(fd, buf, ag_min(f_len, 512));
// Optimization: If skipping binary files, don't read the whole buffer before checking if binary or not.
if (is_binary(buf, f_len)) {
log_debug("File %s is binary. Skipping...", file_full_path);
goto cleanup;
}
}
while (bytes_read < f_len) {
bytes_read += read(fd, buf + bytes_read, f_len);
}
if (bytes_read != f_len) {
die("File %s read(): expected to read %u bytes but read %u", file_full_path, f_len, bytes_read);
}
}
#endif
@ -360,7 +395,7 @@ void search_file(const char *file_full_path) {
#if HAVE_FOPENCOOKIE
log_debug("%s is a compressed file. stream searching", file_full_path);
fp = decompress_open(fd, "r", zip_type);
search_stream(fp, file_full_path);
matches_count = search_stream(fp, file_full_path);
fclose(fp);
#else
int _buf_len = (int)f_len;
@ -369,17 +404,24 @@ void search_file(const char *file_full_path) {
log_err("Cannot decompress zipped file %s", file_full_path);
goto cleanup;
}
search_buf(_buf, _buf_len, file_full_path);
matches_count = search_buf(_buf, _buf_len, file_full_path);
free(_buf);
#endif
goto cleanup;
}
}
search_buf(buf, f_len, file_full_path);
matches_count = search_buf(buf, f_len, file_full_path);
cleanup:
if (opts.print_nonmatching_files && matches_count == 0) {
pthread_mutex_lock(&print_mtx);
print_path(file_full_path, opts.path_sep);
pthread_mutex_unlock(&print_mtx);
opts.match_found = 1;
}
print_cleanup_context();
if (buf != NULL) {
#ifdef _WIN32

View file

@ -31,9 +31,9 @@
#include "uthash.h"
#include "util.h"
size_t alpha_skip_lookup[256];
size_t *find_skip_lookup;
uint8_t h_table[H_SIZE] __attribute__((aligned(64)));
extern size_t alpha_skip_lookup[256];
extern size_t *find_skip_lookup;
extern uint8_t h_table[H_SIZE] __attribute__((aligned(64)));
struct work_queue_t {
char *path;
@ -41,12 +41,12 @@ struct work_queue_t {
};
typedef struct work_queue_t work_queue_t;
work_queue_t *work_queue;
work_queue_t *work_queue_tail;
int done_adding_files;
pthread_cond_t files_ready;
pthread_mutex_t stats_mtx;
pthread_mutex_t work_queue_mtx;
extern work_queue_t *work_queue;
extern work_queue_t *work_queue_tail;
extern int done_adding_files;
extern pthread_cond_t files_ready;
extern pthread_mutex_t stats_mtx;
extern pthread_mutex_t work_queue_mtx;
/* For symlink loop detection */
@ -64,11 +64,11 @@ typedef struct {
UT_hash_handle hh;
} symdir_t;
symdir_t *symhash;
extern symdir_t *symhash;
void search_buf(const char *buf, const size_t buf_len,
const char *dir_full_path);
void search_stream(FILE *stream, const char *path);
ssize_t search_buf(const char *buf, const size_t buf_len,
const char *dir_full_path);
ssize_t search_stream(FILE *stream, const char *path);
void search_file(const char *file_full_path);
void *search_file_worker(void *i);

View file

@ -21,6 +21,8 @@
} \
return ptr;
FILE *out_fd = NULL;
ag_stats stats;
void *ag_malloc(size_t size) {
void *ptr = malloc(size);
CHECK_AND_RETURN(ptr)
@ -148,6 +150,13 @@ size_t ag_max(size_t a, size_t b) {
return a;
}
size_t ag_min(size_t a, size_t b) {
if (b < a) {
return b;
}
return a;
}
void generate_hash(const char *find, const size_t f_len, uint8_t *h_table, const int case_sensitive) {
int i;
for (i = f_len - sizeof(uint16_t); i >= 0; i--) {
@ -509,7 +518,7 @@ int is_symlink(const char *path, const struct dirent *d) {
int is_named_pipe(const char *path, const struct dirent *d) {
#ifdef HAVE_DIRENT_DTYPE
if (d->d_type != DT_UNKNOWN) {
if (d->d_type != DT_UNKNOWN && d->d_type != DT_LNK) {
return d->d_type == DT_FIFO || d->d_type == DT_SOCK;
}
#endif
@ -617,7 +626,7 @@ ssize_t getline(char **lineptr, size_t *n, FILE *stream) {
ssize_t buf_getline(const char **line, const char *buf, const size_t buf_len, const size_t buf_offset) {
const char *cur = buf + buf_offset;
ssize_t i;
for (i = 0; cur[i] != '\n' && (buf_offset + i < buf_len); i++) {
for (i = 0; (buf_offset + i < buf_len) && cur[i] != '\n'; i++) {
}
*line = cur;
return i;

View file

@ -12,7 +12,7 @@
#include "log.h"
#include "options.h"
FILE *out_fd;
extern FILE *out_fd;
#ifndef TRUE
#define TRUE 1
@ -42,16 +42,16 @@ typedef struct {
} match_t;
typedef struct {
long total_bytes;
long total_files;
long total_matches;
long total_file_matches;
size_t total_bytes;
size_t total_files;
size_t total_matches;
size_t total_file_matches;
struct timeval time_start;
struct timeval time_end;
} ag_stats;
ag_stats stats;
extern ag_stats stats;
/* Union to translate between chars and words without violating strict aliasing */
typedef union {
@ -69,6 +69,7 @@ void generate_hash(const char *find, const size_t f_len, uint8_t *H, const int c
/* max is already defined on spec-violating compilers such as MinGW */
size_t ag_max(size_t a, size_t b);
size_t ag_min(size_t a, size_t b);
const char *boyer_moore_strnstr(const char *s, const char *find, const size_t s_len, const size_t f_len,
const size_t alpha_skip_lookup[], const size_t *find_skip_lookup, const int case_insensitive);

View file

@ -0,0 +1,9 @@
Setup:
$ . $TESTDIR/setup.sh
$ printf "hello world\n" >test.txt
Verify ag runs with an empty environment:
$ env -i $TESTDIR/../ag --noaffinity --nocolor --workers=1 --parallel hello
test.txt:1:hello world

View file

@ -3,6 +3,10 @@ Setup:
$ . $TESTDIR/setup.sh
$ printf 'foo\n' > ./foo.txt
$ printf 'bar\n' > ./bar.txt
$ printf 'foo\nbar\nbaz\n' > ./baz.txt
$ printf 'duck\nanother duck\nyet another duck\n' > ./duck.txt
$ cp duck.txt goose.txt
$ echo "GOOSE!!!" >> ./goose.txt
Files with matches:
@ -12,8 +16,17 @@ Files with matches:
foo.txt
$ ag --files-with-matches foo bar.txt
[1]
$ ag --files-with-matches foo foo.txt bar.txt baz.txt
foo.txt
baz.txt
$ ag --files-with-matches bar foo.txt bar.txt baz.txt
bar.txt
baz.txt
$ ag --files-with-matches foo bar.txt baz.txt
baz.txt
Files without matches:
(Prints names of files in which no line matches query)
$ ag --files-without-matches bar foo.txt
foo.txt
@ -21,3 +34,30 @@ Files without matches:
foo.txt
$ ag --files-without-matches bar bar.txt
[1]
$ ag --files-without-matches foo foo.txt bar.txt baz.txt
bar.txt
$ ag --files-without-matches bar foo.txt bar.txt baz.txt
foo.txt
Files with inverted matches:
(Prints names of files in which some line doesn't match query)
$ ag --files-with-matches --invert-match bar bar.txt
[1]
$ ag --files-with-matches --invert-match foo foo.txt bar.txt baz.txt
bar.txt
baz.txt
$ ag --files-with-matches --invert-match bar foo.txt bar.txt baz.txt
foo.txt
baz.txt
Files without inverted matches:
(Prints names of files in which no line doesn't match query,
i.e. where every line matches query)
$ ag --files-without-matches --invert-match duck duck.txt
duck.txt
$ ag --files-without-matches --invert-match duck goose.txt
[1]
$ ag --files-without-matches --invert-match duck duck.txt goose.txt
duck.txt

View file

@ -0,0 +1,19 @@
Setup:
$ . $TESTDIR/setup.sh
$ mkdir -p subdir/ignoredir
$ mkdir ignoredir
$ printf 'match1\n' > subdir/ignoredir/file1.txt
$ printf 'match1\n' > ignoredir/file1.txt
$ printf '/ignoredir\n' > subdir/.ignore
Ignore file in subdir/ignoredir, but not in ignoredir:
$ ag match
ignoredir/file1.txt:1:match1
From subdir, ignore file in subdir/ignoredir:
$ cd subdir
$ ag match
[1]

View file

@ -21,15 +21,21 @@ Language types are output:
--asm
.asm .s
--asp
.asp .asa .aspx .asax .ashx .ascx .asmx
--aspx
.asp .asa .aspx .asax .ashx .ascx .asmx
--batch
.bat .cmd
--bazel
.bazel
--bitbake
.bb .bbappend .bbclass .inc
--bro
.bro .bif
--cc
.c .h .xs
@ -40,11 +46,14 @@ Language types are output:
.chpl
--clojure
.clj .cljs .cljc .cljx
.clj .cljs .cljc .cljx .edn
--coffee
.coffee .cjsx
--config
.config
--coq
.coq .g .v
@ -57,6 +66,9 @@ Language types are output:
--csharp
.cs
--cshtml
.cshtml
--css
.css
@ -72,6 +84,9 @@ Language types are output:
--dot
.dot .gv
--dts
.dts .dtsi
--ebuild
.ebuild .eclass
@ -91,7 +106,7 @@ Language types are output:
.factor
--fortran
.f .f77 .f90 .f95 .f03 .for .ftn .fpp
.f .F .f77 .f90 .F90 .f95 .f03 .for .ftn .fpp .FPP
--fsharp
.fs .fsi .fsx
@ -105,6 +120,9 @@ Language types are output:
--go
.go
--gradle
.gradle
--groovy
.groovy .gtmpl .gpp .grunit .gradle
@ -115,7 +133,7 @@ Language types are output:
.hbs
--haskell
.hs .lhs
.hs .hsig .lhs
--haxe
.hx
@ -207,6 +225,9 @@ Language types are output:
--mercury
.m .moo
--naccess
.asa .rsa
--nim
.nim
@ -231,6 +252,9 @@ Language types are output:
--parrot
.pir .pasm .pmc .ops .pod .pg .tg
--pdb
.pdb
--perl
.pl .pm .pm6 .pod .t
@ -246,9 +270,18 @@ Language types are output:
--plone
.pt .cpt .metadata .cpy .py .xml .zcml
--powershell
.ps1
--proto
.proto
--ps1
.ps1
--pug
.pug
--puppet
.pp
@ -264,6 +297,9 @@ Language types are output:
--rake
.Rakefile
--razor
.cshtml
--restructuredtext
.rst
@ -306,6 +342,9 @@ Language types are output:
--sql
.sql .ctl
--stata
.do .ado
--stylus
.styl
@ -315,9 +354,15 @@ Language types are output:
--tcl
.tcl .itcl .itk
--terraform
.tf .tfvars
--tex
.tex .cls .sty
--thrift
.thrift
--tla
.tla
@ -343,7 +388,7 @@ Language types are output:
.vm .vtl .vsl
--verilog
.v .vh .sv
.v .vh .sv .svh
--vhdl
.vhd .vhdl
@ -351,6 +396,9 @@ Language types are output:
--vim
.vim
--vue
.vue
--wix
.wxi .wxs
@ -361,8 +409,14 @@ Language types are output:
.wadl
--xml
.xml .dtd .xsl .xslt .ent .tld .plist
.xml .dtd .xsl .xslt .xsd .ent .tld .plist .wsdl
--yaml
.yaml .yml
--zeek
.zeek .bro .bif
--zephir
.zep

View file

@ -1,5 +1,5 @@
%define _bashcompdir %_sysconfdir/bash_completion.d
%define _zshcompdir %{_datadir}/zsh/site-functions
Name: the_silver_searcher
Version: @VERSION@
@ -62,7 +62,7 @@ rm -rf ${RPM_BUILD_ROOT}
%{_mandir}/*
%config %{_bashcompdir}/ag.bashcomp.sh
%config %{_datadir}/%{name}/completions/ag.bashcomp.sh
%config %{_datadir}/zsh/site-functions/_the_silver_searcher
%changelog
* Thu Dec 5 2013 Emily Strickland <code@emily.st> - 0.18.1-1