Skip to content

Commit c57d0fb

Browse files
committed
config: add persistent configuration
This commit adds support for 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 This commit also adds a new 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 (which this commit does not add). 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. Closes #196
1 parent d83bab4 commit c57d0fb

File tree

10 files changed

+460
-5
lines changed

10 files changed

+460
-5
lines changed

README.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,50 @@ extensions.
362362
The syntax supported is
363363
[documented as part of Rust's regex library](https://doc.rust-lang.org/regex/regex/index.html#syntax).
364364

365+
### Configuration files
366+
367+
ripgrep supports reading configuration files that change ripgrep's default
368+
behavior. The format of the configuration file is an "rc" style and is very
369+
simple. It is defined by two rules:
370+
371+
1. Every line is a shell argument, after trimming ASCII whitespace.
372+
2. Lines starting with '#' (optionally preceded by any amount of
373+
ASCII whitespace) are ignored.
374+
375+
ripgrep will look for a single configuration file if and only if the
376+
`RIPGREP_CONFIG_PATH` environment variable is set and is non-empty. ripgrep
377+
will parse shell arguments from this file on startup and will behave as if
378+
the arguments in this file were prepended to any explicit arguments given to
379+
ripgrep on the command line.
380+
381+
For example, if your ripgreprc file contained a single line:
382+
383+
--smart-case
384+
385+
then the following command
386+
387+
RIPGREP_CONFIG_PATH=wherever/.ripgreprc rg foo
388+
389+
would behave identically to the following command
390+
391+
rg --smart-case foo
392+
393+
ripgrep also provides a flag, --no-config, that when present will suppress
394+
any and all support for configuration. This includes any future support for
395+
auto-loading configuration files from pre-determined paths.
396+
397+
Conflicts between configuration files and explicit arguments are handled
398+
exactly like conflicts in the same command line invocation. That is, this
399+
command:
400+
401+
RIPGREP_CONFIG_PATH=wherever/.ripgreprc rg foo --case-sensitive
402+
403+
is exactly equivalent to
404+
405+
rg --smart-case foo --case-sensitive
406+
407+
in which case, the --case-sensitive flag would override the --smart-case flag.
408+
365409
### Shell completions
366410

367411
Shell completion files are included in the release tarball for Bash, Fish, Zsh

complete/_rg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ _rg() {
5454
'(--mmap --no-mmap)--mmap[search using memory maps when possible]'
5555
'(-H --with-filename --no-filename)--no-filename[suppress all file names]'
5656
"(-p --heading --pretty --vimgrep)--no-heading[don't group matches by file name]"
57+
"--no-config[don't load configuration files]"
5758
"(--no-ignore-parent)--no-ignore[don't respect ignore files]"
5859
"--no-ignore-parent[don't respect ignore files in parent directories]"
5960
"--no-ignore-vcs[don't respect version control ignore files]"

doc/rg.1

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,17 @@ context related options.)
403403
.RS
404404
.RE
405405
.TP
406+
.B \-\-no\-config
407+
Never read configuration files.
408+
When this flag is present, ripgrep will not respect the
409+
RIPGREP_CONFIG_PATH environment variable.
410+
.RS
411+
.PP
412+
If ripgrep ever grows a feature to automatically read configuration
413+
files in pre\-defined locations, then this flag will also disable that
414+
behavior as well.
415+
.RE
416+
.TP
406417
.B \-\-no\-messages
407418
Suppress all error messages.
408419
.RS
@@ -597,6 +608,77 @@ ripgrep.
597608
Note that this must be passed to every invocation of rg.
598609
.RS
599610
.RE
611+
.SH CONFIGURATION FILES
612+
.PP
613+
ripgrep supports reading configuration files that change ripgrep\[aq]s
614+
default behavior.
615+
The format of the configuration file is an "rc" style and is very
616+
simple.
617+
It is defined by two rules:
618+
.IP
619+
.nf
620+
\f[C]
621+
1.\ Every\ line\ is\ a\ shell\ argument,\ after\ trimming\ ASCII\ whitespace.
622+
2.\ Lines\ starting\ with\ \[aq]#\[aq]\ (optionally\ preceded\ by\ any\ amount\ of
623+
\ \ \ ASCII\ whitespace)\ are\ ignored.
624+
\f[]
625+
.fi
626+
.PP
627+
ripgrep will look for a single configuration file if and only if the
628+
RIPGREP_CONFIG_PATH environment variable is set and is non\-empty.
629+
ripgrep will parse shell arguments from this file on startup and will
630+
behave as if the arguments in this file were prepended to any explicit
631+
arguments given to ripgrep on the command line.
632+
.PP
633+
For example, if your ripgreprc file contained a single line:
634+
.IP
635+
.nf
636+
\f[C]
637+
\-\-smart\-case
638+
\f[]
639+
.fi
640+
.PP
641+
then the following command
642+
.IP
643+
.nf
644+
\f[C]
645+
RIPGREP_CONFIG_PATH=wherever/.ripgreprc\ rg\ foo
646+
\f[]
647+
.fi
648+
.PP
649+
would behave identically to the following command
650+
.IP
651+
.nf
652+
\f[C]
653+
rg\ \-\-smart\-case\ foo
654+
\f[]
655+
.fi
656+
.PP
657+
ripgrep also provides a flag, \-\-no\-config, that when present will
658+
suppress any and all support for configuration.
659+
This includes any future support for auto\-loading configuration files
660+
from pre\-determined paths.
661+
.PP
662+
Conflicts between configuration files and explicit arguments are handled
663+
exactly like conflicts in the same command line invocation.
664+
That is, this command:
665+
.IP
666+
.nf
667+
\f[C]
668+
RIPGREP_CONFIG_PATH=wherever/.ripgreprc\ rg\ foo\ \-\-case\-sensitive
669+
\f[]
670+
.fi
671+
.PP
672+
is exactly equivalent to
673+
.IP
674+
.nf
675+
\f[C]
676+
rg\ \-\-smart\-case\ foo\ \-\-case\-sensitive
677+
\f[]
678+
.fi
679+
.PP
680+
in which case, the \-\-case\-sensitive flag would override the
681+
\-\-smart\-case flag.
600682
.SH SHELL COMPLETION
601683
.PP
602684
Shell completion files are included in the release tarball for Bash,

doc/rg.1.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,14 @@ Project home page: https://github.com/BurntSushi/ripgrep
268268
when ripgrep thinks it will be faster. (Note that mmap searching
269269
doesn't currently support the various context related options.)
270270

271+
--no-config
272+
: Never read configuration files. When this flag is present, ripgrep will not
273+
respect the RIPGREP_CONFIG_PATH environment variable.
274+
275+
If ripgrep ever grows a feature to automatically read configuration files
276+
in pre-defined locations, then this flag will also disable that behavior as
277+
well.
278+
271279
--no-messages
272280
: Suppress all error messages.
273281

@@ -392,6 +400,51 @@ Project home page: https://github.com/BurntSushi/ripgrep
392400
the default type definitions that are found inside of ripgrep. Note
393401
that this must be passed to every invocation of rg.
394402

403+
# CONFIGURATION FILES
404+
405+
ripgrep supports reading configuration files that change
406+
ripgrep's default behavior. The format of the configuration file is an
407+
"rc" style and is very simple. It is defined by two rules:
408+
409+
1. Every line is a shell argument, after trimming ASCII whitespace.
410+
2. Lines starting with '#' (optionally preceded by any amount of
411+
ASCII whitespace) are ignored.
412+
413+
ripgrep will look for a single configuration file if and only if the
414+
RIPGREP_CONFIG_PATH environment variable is set and is non-empty.
415+
ripgrep will parse shell arguments from this file on startup and will
416+
behave as if the arguments in this file were prepended to any explicit
417+
arguments given to ripgrep on the command line.
418+
419+
For example, if your ripgreprc file contained a single line:
420+
421+
--smart-case
422+
423+
then the following command
424+
425+
RIPGREP_CONFIG_PATH=wherever/.ripgreprc rg foo
426+
427+
would behave identically to the following command
428+
429+
rg --smart-case foo
430+
431+
ripgrep also provides a flag, --no-config, that when present will suppress
432+
any and all support for configuration. This includes any future support
433+
for auto-loading configuration files from pre-determined paths.
434+
435+
Conflicts between configuration files and explicit arguments are handled
436+
exactly like conflicts in the same command line invocation. That is,
437+
this command:
438+
439+
RIPGREP_CONFIG_PATH=wherever/.ripgreprc rg foo --case-sensitive
440+
441+
is exactly equivalent to
442+
443+
rg --smart-case foo --case-sensitive
444+
445+
in which case, the --case-sensitive flag would override the --smart-case
446+
flag.
447+
395448
# SHELL COMPLETION
396449

397450
Shell completion files are included in the release tarball for Bash, Fish, Zsh

src/app.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ Note that ripgrep may abort unexpectedly when using default settings if it
2222
searches a file that is simultaneously truncated. This behavior can be avoided
2323
by passing the --no-mmap flag.
2424
25+
ripgrep supports configuration files. Set RIPGREP_CONFIG_PATH to a
26+
configuration file. The file can specify one shell argument per line. Lines
27+
starting with '#' are ignored. For more details, see the man page or the
28+
README.
29+
2530
Project home page: https://github.com/BurntSushi/ripgrep
2631
2732
Use -h for short descriptions and --help for more details.";
@@ -513,6 +518,7 @@ fn all_args_and_flags() -> Vec<RGArg> {
513518
flag_max_filesize(&mut args);
514519
flag_maxdepth(&mut args);
515520
flag_mmap(&mut args);
521+
flag_no_config(&mut args);
516522
flag_no_ignore(&mut args);
517523
flag_no_ignore_parent(&mut args);
518524
flag_no_ignore_vcs(&mut args);
@@ -1113,6 +1119,20 @@ This flag overrides --mmap.
11131119
args.push(arg);
11141120
}
11151121

1122+
fn flag_no_config(args: &mut Vec<RGArg>) {
1123+
const SHORT: &str = "Never read configuration files.";
1124+
const LONG: &str = long!("\
1125+
Never read configuration files. When this flag is present, ripgrep will not
1126+
respect the RIPGREP_CONFIG_PATH environment variable.
1127+
1128+
If ripgrep ever grows a feature to automatically read configuration files in
1129+
pre-defined locations, then this flag will also disable that behavior as well.
1130+
");
1131+
let arg = RGArg::switch("no-config")
1132+
.help(SHORT).long_help(LONG);
1133+
args.push(arg);
1134+
}
1135+
11161136
fn flag_no_ignore(args: &mut Vec<RGArg>) {
11171137
const SHORT: &str = "Don't respect ignore files.";
11181138
const LONG: &str = long!("\
@@ -1182,8 +1202,7 @@ part on a separate output line.
11821202
}
11831203

11841204
fn flag_path_separator(args: &mut Vec<RGArg>) {
1185-
const SHORT: &str =
1186-
"Set the path separator to use when printing file paths.";
1205+
const SHORT: &str = "Set the path separator.";
11871206
const LONG: &str = long!("\
11881207
Set the path separator to use when printing file paths. This defaults to your
11891208
platform's path separator, which is / on Unix and \\ on Windows. This flag is

src/args.rs

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use printer::{ColorSpecs, Printer};
2525
use unescape::unescape;
2626
use worker::{Worker, WorkerBuilder};
2727

28+
use config;
2829
use logger::Logger;
2930
use Result;
3031

@@ -88,17 +89,59 @@ impl Args {
8889
///
8990
/// Also, initialize a global logger.
9091
pub fn parse() -> Result<Args> {
91-
let matches = app::app().get_matches();
92+
// We parse the args given on CLI. This does not include args from
93+
// the config. We use the CLI args as an initial configuration while
94+
// trying to parse config files. If a config file exists and has
95+
// arguments, then we re-parse argv, otherwise we just use the matches
96+
// we have here.
97+
let early_matches = ArgMatches(app::app().get_matches());
9298

9399
if let Err(err) = Logger::init() {
94100
errored!("failed to initialize logger: {}", err);
95101
}
102+
if early_matches.is_present("debug") {
103+
log::set_max_level(log::LevelFilter::Debug);
104+
} else {
105+
log::set_max_level(log::LevelFilter::Warn);
106+
}
107+
108+
let matches = Args::matches(early_matches);
109+
// The logging level may have changed if we brought in additional
110+
// arguments from a configuration file, so recheck it and set the log
111+
// level as appropriate.
96112
if matches.is_present("debug") {
97113
log::set_max_level(log::LevelFilter::Debug);
98114
} else {
99115
log::set_max_level(log::LevelFilter::Warn);
100116
}
101-
ArgMatches(matches).to_args()
117+
matches.to_args()
118+
}
119+
120+
/// Run clap and return the matches. If clap determines a problem with the
121+
/// user provided arguments (or if --help or --version are given), then an
122+
/// error/usage/version will be printed and the process will exit.
123+
///
124+
/// If there are no additional arguments from the environment (e.g., a
125+
/// config file), then the given matches are returned as is.
126+
fn matches(early_matches: ArgMatches<'static>) -> ArgMatches<'static> {
127+
// If the end user says no config, then respect it.
128+
if early_matches.is_present("no-config") {
129+
debug!("not reading config files because --no-config is present");
130+
return early_matches;
131+
}
132+
// If the user wants ripgrep to use a config file, then parse args
133+
// from that first.
134+
let mut args = config::args(early_matches.is_present("no-messages"));
135+
if args.is_empty() {
136+
return early_matches;
137+
}
138+
let mut cliargs = env::args_os();
139+
if let Some(bin) = cliargs.next() {
140+
args.insert(0, bin);
141+
}
142+
args.extend(cliargs);
143+
debug!("final argv: {:?}", args);
144+
ArgMatches(app::app().get_matches_from(args))
102145
}
103146

104147
/// Returns true if ripgrep should print the files it will search and exit

0 commit comments

Comments
 (0)