diff --git a/CHANGELOG.md b/CHANGELOG.md index d016699f..bb6f8e0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ - Add new `--batch-size` flag, see #410 (@devonhollowood) +- Add opposing command-line options, see #595 (@Asha20) + ## Bugfixes - Set default path separator to `/` in MSYS, see #537 and #730 (@aswild) diff --git a/Cargo.lock b/Cargo.lock index c3bfee79..5c4918b8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -181,6 +181,7 @@ dependencies = [ "regex", "regex-syntax", "tempdir", + "test-case", "users", "version_check", ] @@ -395,6 +396,24 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" +[[package]] +name = "proc-macro2" +version = "1.0.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" +dependencies = [ + "proc-macro2", +] + [[package]] name = "rand" version = "0.4.6" @@ -492,6 +511,17 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" +[[package]] +name = "syn" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + [[package]] name = "tempdir" version = "0.3.7" @@ -512,6 +542,19 @@ dependencies = [ "winapi", ] +[[package]] +name = "test-case" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7cad0a06f9a61e94355aa3b3dc92d85ab9c83406722b1ca5e918d4297c12c23" +dependencies = [ + "cfg-if", + "proc-macro2", + "quote", + "syn", + "version_check", +] + [[package]] name = "textwrap" version = "0.11.0" @@ -547,6 +590,12 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + [[package]] name = "users" version = "0.11.0" diff --git a/Cargo.toml b/Cargo.toml index c7150913..c89b2e97 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -70,7 +70,8 @@ jemallocator = "0.3.0" [dev-dependencies] diff = "0.1" tempdir = "0.3" -filetime = "0.2.15" +filetime = "0.2" +test-case = "1.2" [profile.release] lto = true diff --git a/doc/fd.1 b/doc/fd.1 index 66413cc3..51d0c034 100644 --- a/doc/fd.1 +++ b/doc/fd.1 @@ -28,7 +28,7 @@ is a simple, fast and user-friendly alternative to .TP .B \-H, \-\-hidden Include hidden files and directories in the search results -(default: hidden files and directories are skipped). +(default: hidden files and directories are skipped). The flag can be overridden with '--no-hidden'. .TP .B \-I, \-\-no\-ignore Show search results from files and directories that would otherwise be ignored by @@ -49,6 +49,8 @@ The global fd ignore file (usually .I $HOME/.config/fd/ignore ) .RE +.IP +The flag can be overridden with '--ignore'. .TP .B \-u, \-\-unrestricted Alias for '--no-ignore'. Can be repeated; '-uu' is an alias for '--no-ignore --hidden'. @@ -62,6 +64,7 @@ and the global gitignore configuration .RI ( core.excludesFile git setting, which defaults to .IR $HOME/.config/git/ignore ). +The flag can be overridden with '--ignore-vcs'. .TP .B \-s, \-\-case\-sensitive Perform a case-sensitive search. By default, fd uses case-insensitive searches, unless the @@ -84,6 +87,7 @@ performs substring comparison. If you want to match on an exact filename, consid .TP .B \-a, \-\-absolute\-path Shows the full path starting from the root as opposed to relative paths. +The flag can be overridden with '--relative-path'. .TP .B \-l, \-\-list\-details Use a detailed listing format like 'ls -l'. This is basically an alias @@ -93,7 +97,7 @@ sort order. .TP .B \-L, \-\-follow By default, fd does not descend into symlinked directories. Using this flag, symbolic links are -also traversed. +also traversed. The flag can be overridden with '--no-follow'. .TP .B \-p, \-\-full\-path By default, the search pattern is only matched against the filename (or directory name). Using diff --git a/src/app.rs b/src/app.rs index efd11d76..4c17dca1 100644 --- a/src/app.rs +++ b/src/app.rs @@ -25,7 +25,17 @@ pub fn build_app() -> App<'static, 'static> { .long_help( "Include hidden directories and files in the search results (default: \ hidden files and directories are skipped). Files and directories are \ - considered to be hidden if their name starts with a `.` sign (dot).", + considered to be hidden if their name starts with a `.` sign (dot). \ + The flag can be overridden with --no-hidden.", + ), + ) + .arg( + Arg::with_name("no-hidden") + .long("no-hidden") + .overrides_with("hidden") + .hidden(true) + .long_help( + "Overrides --hidden.", ), ) .arg( @@ -36,7 +46,17 @@ pub fn build_app() -> App<'static, 'static> { .help("Do not respect .(git|fd)ignore files") .long_help( "Show search results from files and directories that would otherwise be \ - ignored by '.gitignore', '.ignore', '.fdignore', or the global ignore file.", + ignored by '.gitignore', '.ignore', '.fdignore', or the global ignore file. \ + The flag can be overridden with --ignore.", + ), + ) + .arg( + Arg::with_name("ignore") + .long("ignore") + .overrides_with("no-ignore") + .hidden(true) + .long_help( + "Overrides --no-ignore.", ), ) .arg( @@ -47,7 +67,16 @@ pub fn build_app() -> App<'static, 'static> { .help("Do not respect .gitignore files") .long_help( "Show search results from files and directories that would otherwise be \ - ignored by '.gitignore' files.", + ignored by '.gitignore' files. The flag can be overridden with --ignore-vcs.", + ), + ) + .arg( + Arg::with_name("ignore-vcs") + .long("ignore-vcs") + .overrides_with("no-ignore-vcs") + .hidden(true) + .long_help( + "Overrides --no-ignore-vcs.", ), ) .arg( @@ -72,6 +101,7 @@ pub fn build_app() -> App<'static, 'static> { Arg::with_name("rg-alias-hidden-ignore") .short("u") .long("unrestricted") + .overrides_with_all(&["ignore", "no-hidden"]) .multiple(true) .hidden_short_help(true) .help("Alias for '--no-ignore', and '--hidden' when given twice") @@ -145,7 +175,17 @@ pub fn build_app() -> App<'static, 'static> { .overrides_with("absolute-path") .help("Show absolute instead of relative paths") .long_help( - "Shows the full path starting from the root as opposed to relative paths.", + "Shows the full path starting from the root as opposed to relative paths. \ + The flag can be overridden with --relative-path.", + ), + ) + .arg( + Arg::with_name("relative-path") + .long("relative-path") + .overrides_with("absolute-path") + .hidden(true) + .long_help( + "Overrides --absolute-path.", ), ) .arg( @@ -170,7 +210,17 @@ pub fn build_app() -> App<'static, 'static> { .help("Follow symbolic links") .long_help( "By default, fd does not descend into symlinked directories. Using this \ - flag, symbolic links are also traversed.", + flag, symbolic links are also traversed. \ + Flag can be overriden with --no-follow.", + ), + ) + .arg( + Arg::with_name("no-follow") + .long("no-follow") + .overrides_with("follow") + .hidden(true) + .long_help( + "Overrides --follow.", ), ) .arg( diff --git a/tests/tests.rs b/tests/tests.rs index 1baf15ed..54b4ecce 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -4,6 +4,7 @@ use std::fs; use std::io::Write; use std::path::Path; use std::time::{Duration, SystemTime}; +use test_case::test_case; use normpath::PathExt; use regex::escape; @@ -1929,6 +1930,30 @@ fn test_number_parsing_errors() { te.assert_failure(&["--max-results=a"]); } +#[test_case("--hidden", &["--no-hidden"] ; "hidden")] +#[test_case("--no-ignore", &["--ignore"] ; "no-ignore")] +#[test_case("--no-ignore-vcs", &["--ignore-vcs"] ; "no-ignore-vcs")] +#[test_case("--follow", &["--no-follow"] ; "follow")] +#[test_case("--absolute-path", &["--relative-path"] ; "absolute-path")] +#[test_case("-u", &["--ignore"] ; "u")] +#[test_case("-uu", &["--ignore", "--no-hidden"] ; "uu")] +fn test_opposing(flag: &str, opposing_flags: &[&str]) { + let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES); + + let mut flags = vec![flag]; + flags.extend_from_slice(opposing_flags); + let out_no_flags = te.assert_success_and_get_output(".", &[]); + let out_opposing_flags = te.assert_success_and_get_output(".", &flags); + + assert_eq!( + out_no_flags, + out_opposing_flags, + "{} should override {}", + opposing_flags.join(" "), + flag + ); +} + /// Print error if search pattern starts with a dot and --hidden is not set /// (Unix only, hidden files on Windows work differently) #[test]