From 37852aa388466539d025b27c4aed570bb36ed652 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vuka=C5=A1in=20Stepanovi=C4=87?= Date: Mon, 9 Aug 2021 15:49:48 +0200 Subject: [PATCH 01/21] Add 5 opposing CLI options Those are: - `--no-hidden`, which overrides `--hidden` - `--ignore`, which overrides `--no-ignore` - `--ignore-vcs`, which overrides `--no-ignore-vcs` - `--no-follow`, which overrides `--follow` - `--relative-path`, which overrides `--absolute-path` --- CHANGELOG.md | 2 ++ Cargo.lock | 49 +++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + src/app.rs | 59 +++++++++++++++++++++++++++++++++++++++++++++----- src/main.rs | 30 ++++++++++++++----------- tests/tests.rs | 25 +++++++++++++++++++++ 6 files changed, 148 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 08e4e60f..55889caa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Features +- 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 dede4b7a..5b5359cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -173,6 +173,7 @@ dependencies = [ "regex", "regex-syntax", "tempdir", + "test-case", "users", "version_check", ] @@ -352,6 +353,24 @@ dependencies = [ "libc", ] +[[package]] +name = "proc-macro2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + [[package]] name = "rand" version = "0.4.6" @@ -455,6 +474,17 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" +[[package]] +name = "syn" +version = "1.0.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1873d832550d4588c3dbc20f01361ab00bfe741048f71e3fecf145a7cc18b29c" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + [[package]] name = "tempdir" version = "0.3.7" @@ -475,6 +505,19 @@ dependencies = [ "winapi", ] +[[package]] +name = "test-case" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b114ece25254e97bf48dd4bfc2a12bad0647adacfe4cae1247a9ca6ad302cec" +dependencies = [ + "cfg-if 1.0.0", + "proc-macro2", + "quote", + "syn", + "version_check", +] + [[package]] name = "textwrap" version = "0.11.0" @@ -500,6 +543,12 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" +[[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 a4d479d7..43494887 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,6 +69,7 @@ jemallocator = "0.3.0" diff = "0.1" tempdir = "0.3" filetime = "0.2.14" +test-case = "1.2.0" [profile.release] lto = true diff --git a/src/app.rs b/src/app.rs index 2d6ec948..7ca6a515 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). \ + Flag can be overridden with --no-hidden.", + ), + ) + .arg( + Arg::with_name("no-hidden") + .long("no-hidden") + .overrides_with("no-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. \ + Flag can be overridden with --ignore.", + ), + ) + .arg( + Arg::with_name("ignore") + .long("ignore") + .overrides_with("ignore") + .hidden(true) + .long_help( + "Overrides --no-ignore.", ), ) .arg( @@ -46,7 +66,16 @@ pub fn build_app() -> App<'static, 'static> { .hidden_short_help(true) .long_help( "Show search results from files and directories that would otherwise be \ - ignored by '.gitignore' files.", + ignored by '.gitignore' files. Flag can be overridden with --ignore-vcs.", + ), + ) + .arg( + Arg::with_name("ignore-vcs") + .long("ignore-vcs") + .overrides_with("ignore-vcs") + .hidden(true) + .long_help( + "Overrides --no-ignore-vcs.", ), ) .arg( @@ -129,7 +158,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. \ + Flag can be overridden with --relative-path.", + ), + ) + .arg( + Arg::with_name("relative-path") + .long("relative-path") + .overrides_with("relative-path") + .hidden(true) + .long_help( + "Overrides --absolute-path.", ), ) .arg( @@ -154,7 +193,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("no-follow") + .hidden(true) + .long_help( + "Overrides --follow.", ), ) .arg( diff --git a/src/main.rs b/src/main.rs index 8654688a..9572a25d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,8 +20,8 @@ use anyhow::{anyhow, Context, Result}; use atty::Stream; use globset::GlobBuilder; use lscolors::LsColors; -use regex::bytes::{RegexBuilder, RegexSetBuilder}; use normpath::PathExt; +use regex::bytes::{RegexBuilder, RegexSetBuilder}; use crate::error::print_error; use crate::exec::CommandTemplate; @@ -116,7 +116,7 @@ fn run() -> Result { return Err(anyhow!("No valid search paths given.")); } - if matches.is_present("absolute-path") { + if matches.is_present("absolute-path") && !matches.is_present("relative-path") { search_paths = search_paths .iter() .map(|path_buffer| { @@ -331,17 +331,21 @@ fn run() -> Result { let config = Options { case_sensitive, search_full_path: matches.is_present("full-path"), - ignore_hidden: !(matches.is_present("hidden") - || matches.occurrences_of("rg-alias-hidden-ignore") >= 2), - read_fdignore: !(matches.is_present("no-ignore") - || matches.is_present("rg-alias-hidden-ignore")), - read_vcsignore: !(matches.is_present("no-ignore") - || matches.is_present("rg-alias-hidden-ignore") - || matches.is_present("no-ignore-vcs")), - read_global_ignore: !(matches.is_present("no-ignore") - || matches.is_present("rg-alias-hidden-ignore") - || matches.is_present("no-global-ignore-file")), - follow_links: matches.is_present("follow"), + ignore_hidden: matches.is_present("no-hidden") + || !(matches.is_present("hidden") + || matches.occurrences_of("rg-alias-hidden-ignore") >= 2), + read_fdignore: matches.is_present("ignore") + || !(matches.is_present("no-ignore") || matches.is_present("rg-alias-hidden-ignore")), + read_vcsignore: matches.is_present("ignore") || matches.is_present("ignore-vcs") || { + !(matches.is_present("no-ignore") + || matches.is_present("rg-alias-hidden-ignore") + || matches.is_present("no-ignore-vcs")) + }, + read_global_ignore: matches.is_present("ignore") + || !(matches.is_present("no-ignore") + || matches.is_present("rg-alias-hidden-ignore") + || matches.is_present("no-global-ignore-file")), + follow_links: matches.is_present("follow") && !matches.is_present("no-follow"), one_file_system: matches.is_present("one-file-system"), null_separator: matches.is_present("null_separator"), max_depth: matches diff --git a/tests/tests.rs b/tests/tests.rs index 0b6e6b5c..03bbea57 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; @@ -1788,6 +1789,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] From 9bc8fabba0a4b8665a4bbf407acf42e511ea8580 Mon Sep 17 00:00:00 2001 From: Thayne McCombs Date: Wed, 11 Aug 2021 01:48:42 -0600 Subject: [PATCH 02/21] Update Cargo.lock --- Cargo.lock | 235 ++++++++++++++++++++--------------------------------- 1 file changed, 88 insertions(+), 147 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4be105d9..9d642c0e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -31,21 +31,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.31" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85bb70cc08ec97ca5450e6eba421deeea5f172c0fc61f78b5357b2a8e8be195f" - -[[package]] -name = "arrayref" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" - -[[package]] -name = "arrayvec" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" +checksum = "595d3cfa7a60d4555cb5067b99f07142a08ea778de5cf993f7b75c7d8fabc486" [[package]] name = "atty" @@ -60,15 +48,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" - -[[package]] -name = "base64" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "bitflags" @@ -76,37 +58,20 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -[[package]] -name = "blake2b_simd" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" -dependencies = [ - "arrayref", - "arrayvec", - "constant_time_eq", -] - [[package]] name = "bstr" -version = "0.2.13" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31accafdb70df7871592c058eca3985b71104e15ac32f64706022c58867da931" +checksum = "90682c8d613ad3373e66de8c6411e0ae2ab2571e879d2efbf73558cc66f21279" dependencies = [ "memchr", ] [[package]] name = "cc" -version = "1.0.53" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "404b1fe4f65288577753b17e3b36a04596ee784493ec249bf81c7f2d2acd751c" - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2" [[package]] name = "cfg-if" @@ -129,9 +94,9 @@ dependencies = [ [[package]] name = "clap" -version = "2.33.1" +version = "2.33.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129" +checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" dependencies = [ "ansi_term 0.11.0", "atty", @@ -143,28 +108,21 @@ dependencies = [ "vec_map", ] -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - [[package]] name = "crossbeam-utils" -version = "0.7.2" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" dependencies = [ - "autocfg", - "cfg-if 0.1.10", + "cfg-if", "lazy_static", ] [[package]] name = "ctrlc" -version = "3.1.4" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a4ba686dff9fa4c1c9636ce1010b0cf98ceb421361b0bb3d6faeec43bd217a7" +checksum = "377c9b002a72a0b2c1a18c62e2f3864bdfea4a015e3683a96e24aa45dd6c02d1" dependencies = [ "nix", "winapi", @@ -182,15 +140,15 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "dirs-sys-next", ] [[package]] name = "dirs-sys-next" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c60f7b8a8953926148223260454befb50c751d3c50e1c178c4fd1ace4083c9a" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" dependencies = [ "libc", "redox_users", @@ -229,13 +187,13 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d34cfa13a63ae058bfa601fe9e313bbdb3746427c1459185464ce0fcf62e1e8" +checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", - "redox_syscall 0.2.10", + "redox_syscall", "winapi", ] @@ -247,9 +205,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "fs_extra" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f2a4a2034423744d2cc7ca2068453168dcdb82c438419e639a26bd87839c674" +checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" [[package]] name = "fuchsia-cprng" @@ -259,20 +217,20 @@ checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" [[package]] name = "getrandom" -version = "0.1.14" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ - "cfg-if 0.1.10", + "cfg-if", "libc", - "wasi 0.9.0+wasi-snapshot-preview1", + "wasi", ] [[package]] name = "globset" -version = "0.4.5" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ad1da430bd7281dde2576f44c84cc3f0f7b475e7202cd503042dff01a8c8120" +checksum = "10463d9ff00a2a068db14231982f5132edebad0d7660cd956a1c30292dbcbfbd" dependencies = [ "aho-corasick", "bstr", @@ -283,24 +241,24 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.13" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91780f809e750b0a89f5544be56617ff6b1227ee485bcb06ebe10cdf89bd3b71" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ "libc", ] [[package]] name = "humantime" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9b6c53306532d3c8e8087b44e6580e10db51a023cf9b433cea2ac38066b92da" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "ignore" -version = "0.4.15" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128b9e89d15a3faa642ee164c998fd4fae3d89d054463cddb2c25a7baad3a352" +checksum = "713f1b139373f96a2e0ce3ac931cd01ee973c3c5dd7c40c0c2efe96ad2b6751d" dependencies = [ "crossbeam-utils", "globset", @@ -343,24 +301,24 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.70" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3baa92041a6fec78c687fa0cc2b3fae8884f743d672cf551bed1d6dac6988d0f" +checksum = "a7f823d141fe0a24df1e23b4af4e3c7ba9e5966ec514ea068c93024aa7deb765" [[package]] name = "log" -version = "0.4.8" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ - "cfg-if 0.1.10", + "cfg-if", ] [[package]] name = "lscolors" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f77452267149eac960ded529fe5f5460ddf792845a1d71b5d0cfcee5642e47e" +checksum = "d24b894c45c9da468621cdd615a5a79ee5e5523dd4f75c76ebc03d458940c16e" dependencies = [ "ansi_term 0.12.1", ] @@ -372,16 +330,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" [[package]] -name = "nix" -version = "0.17.0" +name = "memoffset" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50e4785f2c3b7589a0d0c1dd60285e1188adac4006e8abd6dd578e1567027363" +checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" +dependencies = [ + "autocfg", +] + +[[package]] +name = "nix" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1e25ee6b412c2a1e3fcb6a4499a5c1bfe7f43e014bdce9a6b6666e5aa2d187" dependencies = [ "bitflags", "cc", - "cfg-if 0.1.10", + "cfg-if", "libc", - "void", + "memoffset", ] [[package]] @@ -395,9 +362,9 @@ dependencies = [ [[package]] name = "num-integer" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" dependencies = [ "autocfg", "num-traits", @@ -405,9 +372,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" dependencies = [ "autocfg", ] @@ -422,6 +389,12 @@ dependencies = [ "libc", ] +[[package]] +name = "once_cell" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" + [[package]] name = "proc-macro2" version = "1.0.28" @@ -477,12 +450,6 @@ dependencies = [ "rand_core 0.3.1", ] -[[package]] -name = "redox_syscall" -version = "0.1.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" - [[package]] name = "redox_syscall" version = "0.2.10" @@ -494,13 +461,12 @@ dependencies = [ [[package]] name = "redox_users" -version = "0.3.4" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431" +checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" dependencies = [ "getrandom", - "redox_syscall 0.1.56", - "rust-argon2", + "redox_syscall", ] [[package]] @@ -522,25 +488,13 @@ checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "remove_dir_all" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" dependencies = [ "winapi", ] -[[package]] -name = "rust-argon2" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017" -dependencies = [ - "base64", - "blake2b_simd", - "constant_time_eq", - "crossbeam-utils", -] - [[package]] name = "same-file" version = "1.0.6" @@ -593,7 +547,7 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b114ece25254e97bf48dd4bfc2a12bad0647adacfe4cae1247a9ca6ad302cec" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "proc-macro2", "quote", "syn", @@ -612,29 +566,28 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.0.1" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" +checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd" dependencies = [ - "lazy_static", + "once_cell", ] [[package]] name = "time" -version = "0.1.44" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" dependencies = [ "libc", - "wasi 0.10.0+wasi-snapshot-preview1", "winapi", ] [[package]] name = "unicode-width" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" +checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" [[package]] name = "unicode-xid" @@ -660,21 +613,15 @@ checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] name = "version_check" -version = "0.9.1" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" - -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" [[package]] name = "walkdir" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" dependencies = [ "same-file", "winapi", @@ -683,21 +630,15 @@ dependencies = [ [[package]] name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" +version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - -[[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "winapi" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", From 668af05dcae2a708bf7100ab744ce71d66b7f1ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vuka=C5=A1in=20Stepanovi=C4=87?= Date: Mon, 23 Aug 2021 15:27:52 +0200 Subject: [PATCH 03/21] Add opposing options to manpage --- doc/fd.1 | 7 +++++-- src/app.rs | 8 ++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/doc/fd.1 b/doc/fd.1 index bff3b0e4..a826f55b 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 @@ -36,6 +36,7 @@ Show search results from files and directories that would otherwise be ignored b .IR .ignore , .IR .fdignore , or the global ignore file. +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'. @@ -44,6 +45,7 @@ Alias for '--no-ignore'. Can be repeated; '-uu' is an alias for '--no-ignore --h Show search results from files and directories that would otherwise be ignored by .I .gitignore files. +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 @@ -65,6 +67,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 @@ -74,7 +77,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 7ca6a515..6e08c1a7 100644 --- a/src/app.rs +++ b/src/app.rs @@ -26,7 +26,7 @@ pub fn build_app() -> App<'static, 'static> { "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). \ - Flag can be overridden with --no-hidden.", + The flag can be overridden with --no-hidden.", ), ) .arg( @@ -47,7 +47,7 @@ pub fn build_app() -> App<'static, 'static> { .long_help( "Show search results from files and directories that would otherwise be \ ignored by '.gitignore', '.ignore', '.fdignore', or the global ignore file. \ - Flag can be overridden with --ignore.", + The flag can be overridden with --ignore.", ), ) .arg( @@ -66,7 +66,7 @@ pub fn build_app() -> App<'static, 'static> { .hidden_short_help(true) .long_help( "Show search results from files and directories that would otherwise be \ - ignored by '.gitignore' files. Flag can be overridden with --ignore-vcs.", + ignored by '.gitignore' files. The flag can be overridden with --ignore-vcs.", ), ) .arg( @@ -159,7 +159,7 @@ pub fn build_app() -> App<'static, 'static> { .help("Show absolute instead of relative paths") .long_help( "Shows the full path starting from the root as opposed to relative paths. \ - Flag can be overridden with --relative-path.", + The flag can be overridden with --relative-path.", ), ) .arg( From 3ebd78cf0222cc993a0fec255cc237705ae324bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vuka=C5=A1in=20Stepanovi=C4=87?= Date: Mon, 23 Aug 2021 15:44:11 +0200 Subject: [PATCH 04/21] Use overrides_with to clean up opposing arg logic --- src/app.rs | 11 ++++++----- src/main.rs | 28 ++++++++++++---------------- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/src/app.rs b/src/app.rs index 6e08c1a7..04e93591 100644 --- a/src/app.rs +++ b/src/app.rs @@ -32,7 +32,7 @@ pub fn build_app() -> App<'static, 'static> { .arg( Arg::with_name("no-hidden") .long("no-hidden") - .overrides_with("no-hidden") + .overrides_with("hidden") .hidden(true) .long_help( "Overrides --hidden.", @@ -53,7 +53,7 @@ pub fn build_app() -> App<'static, 'static> { .arg( Arg::with_name("ignore") .long("ignore") - .overrides_with("ignore") + .overrides_with("no-ignore") .hidden(true) .long_help( "Overrides --no-ignore.", @@ -72,7 +72,7 @@ pub fn build_app() -> App<'static, 'static> { .arg( Arg::with_name("ignore-vcs") .long("ignore-vcs") - .overrides_with("ignore-vcs") + .overrides_with("no-ignore-vcs") .hidden(true) .long_help( "Overrides --no-ignore-vcs.", @@ -88,6 +88,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) .long_help( @@ -165,7 +166,7 @@ pub fn build_app() -> App<'static, 'static> { .arg( Arg::with_name("relative-path") .long("relative-path") - .overrides_with("relative-path") + .overrides_with("absolute-path") .hidden(true) .long_help( "Overrides --absolute-path.", @@ -200,7 +201,7 @@ pub fn build_app() -> App<'static, 'static> { .arg( Arg::with_name("no-follow") .long("no-follow") - .overrides_with("no-follow") + .overrides_with("follow") .hidden(true) .long_help( "Overrides --follow.", diff --git a/src/main.rs b/src/main.rs index e4dde7a3..7acba889 100644 --- a/src/main.rs +++ b/src/main.rs @@ -116,7 +116,7 @@ fn run() -> Result { return Err(anyhow!("No valid search paths given.")); } - if matches.is_present("absolute-path") && !matches.is_present("relative-path") { + if matches.is_present("absolute-path") { search_paths = search_paths .iter() .map(|path_buffer| { @@ -333,21 +333,17 @@ fn run() -> Result { let config = Options { case_sensitive, search_full_path: matches.is_present("full-path"), - ignore_hidden: matches.is_present("no-hidden") - || !(matches.is_present("hidden") - || matches.occurrences_of("rg-alias-hidden-ignore") >= 2), - read_fdignore: matches.is_present("ignore") - || !(matches.is_present("no-ignore") || matches.is_present("rg-alias-hidden-ignore")), - read_vcsignore: matches.is_present("ignore") || matches.is_present("ignore-vcs") || { - !(matches.is_present("no-ignore") - || matches.is_present("rg-alias-hidden-ignore") - || matches.is_present("no-ignore-vcs")) - }, - read_global_ignore: matches.is_present("ignore") - || !(matches.is_present("no-ignore") - || matches.is_present("rg-alias-hidden-ignore") - || matches.is_present("no-global-ignore-file")), - follow_links: matches.is_present("follow") && !matches.is_present("no-follow"), + ignore_hidden: !(matches.is_present("hidden") + || matches.occurrences_of("rg-alias-hidden-ignore") >= 2), + read_fdignore: !(matches.is_present("no-ignore") + || matches.is_present("rg-alias-hidden-ignore")), + read_vcsignore: !(matches.is_present("no-ignore") + || matches.is_present("rg-alias-hidden-ignore") + || matches.is_present("no-ignore-vcs")), + read_global_ignore: !(matches.is_present("no-ignore") + || matches.is_present("rg-alias-hidden-ignore") + || matches.is_present("no-global-ignore-file")), + follow_links: matches.is_present("follow"), one_file_system: matches.is_present("one-file-system"), null_separator: matches.is_present("null_separator"), max_depth: matches From 17dd2a6dfec1ca2086c3d279f5c458758bc9a71b Mon Sep 17 00:00:00 2001 From: Devon Hollowood Date: Thu, 21 Oct 2021 23:05:13 -0700 Subject: [PATCH 05/21] Implement `--batch-size` (#866) --- CHANGELOG.md | 2 ++ contrib/completion/_fd | 1 + doc/fd.1 | 6 ++++++ src/app.rs | 15 +++++++++++++++ src/config.rs | 4 ++++ src/exec/job.rs | 15 ++++++++++++++- src/main.rs | 6 ++++++ src/walk.rs | 8 +++++++- tests/tests.rs | 42 ++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 97 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d48c3177..d016699f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ - Add new `--no-ignore-parent` flag, see #787 (@will459) +- Add new `--batch-size` flag, see #410 (@devonhollowood) + ## Bugfixes - Set default path separator to `/` in MSYS, see #537 and #730 (@aswild) diff --git a/contrib/completion/_fd b/contrib/completion/_fd index 28b37eef..a17c748d 100644 --- a/contrib/completion/_fd +++ b/contrib/completion/_fd @@ -138,6 +138,7 @@ _fd() { + '(exec-cmds)' # execute command '(long-listing max-results)'{-x+,--exec=}'[execute command for each search result]:command: _command_names -e:*\;::program arguments: _normal' '(long-listing max-results)'{-X+,--exec-batch=}'[execute command for all search results at once]:command: _command_names -e:*\;::program arguments: _normal' + '(long-listing max-results)'{--batch-size=}'[max number of args for each -X call]:size' + other '!(--max-buffer-time)--max-buffer-time=[set amount of time to buffer before showing output]:time (ms)' diff --git a/doc/fd.1 b/doc/fd.1 index 69e84385..66413cc3 100644 --- a/doc/fd.1 +++ b/doc/fd.1 @@ -405,5 +405,11 @@ $ fd -e py .TP .RI "Open all search results with vim:" $ fd pattern -X vim +.TP +.BI "\-\-batch\-size " size +Pass at most +.I size +arguments to each call to the command given with -X. +.TP .SH SEE ALSO .BR find (1) diff --git a/src/app.rs b/src/app.rs index b26593be..3f5bc2b1 100644 --- a/src/app.rs +++ b/src/app.rs @@ -365,6 +365,21 @@ pub fn build_app() -> App<'static, 'static> { " ), ) + .arg( + Arg::with_name("batch-size") + .long("batch-size") + .takes_value(true) + .value_name("size") + .hidden_short_help(true) + .requires("exec-batch") + .help("Max number of arguments to run as a batch with -X") + .long_help( + "Maximum number of arguments to pass to the command given with -X. \ + If the number of results is greater than the given size, \ + the command given with -X is run again with remaining arguments. \ + A batch size of zero means there is no limit.", + ), + ) .arg( Arg::with_name("exclude") .long("exclude") diff --git a/src/config.rs b/src/config.rs index a053e6ef..c11f88ba 100644 --- a/src/config.rs +++ b/src/config.rs @@ -85,6 +85,10 @@ pub struct Config { /// If a value is supplied, each item found will be used to generate and execute commands. pub command: Option>, + /// Maximum number of search results to pass to each `command`. If zero, the number is + /// unlimited. + pub batch_size: usize, + /// A list of glob patterns that should be excluded from the search. pub exclude_patterns: Vec, diff --git a/src/exec/job.rs b/src/exec/job.rs index 83abf1a1..aa8164cd 100644 --- a/src/exec/job.rs +++ b/src/exec/job.rs @@ -50,6 +50,7 @@ pub fn batch( cmd: &CommandTemplate, show_filesystem_errors: bool, buffer_output: bool, + limit: usize, ) -> ExitCode { let paths = rx.iter().filter_map(|value| match value { WorkerResult::Entry(val) => Some(val), @@ -60,5 +61,17 @@ pub fn batch( None } }); - cmd.generate_and_execute_batch(paths, buffer_output) + if limit == 0 { + // no limit + return cmd.generate_and_execute_batch(paths, buffer_output); + } + + let mut exit_codes = Vec::new(); + let mut peekable = paths.peekable(); + while peekable.peek().is_some() { + let limited = peekable.by_ref().take(limit); + let exit_code = cmd.generate_and_execute_batch(limited, buffer_output); + exit_codes.push(exit_code); + } + merge_exitcodes(exit_codes) } diff --git a/src/main.rs b/src/main.rs index da5fcd9c..321df542 100644 --- a/src/main.rs +++ b/src/main.rs @@ -348,6 +348,12 @@ fn construct_config(matches: clap::ArgMatches, pattern_regex: &str) -> Result()) + .transpose() + .context("Failed to parse --batch-size argument")? + .unwrap_or_default(), exclude_patterns: matches .values_of("exclude") .map(|v| v.map(|p| String::from("!") + p).collect()) diff --git a/src/walk.rs b/src/walk.rs index 7850ad7e..789a5008 100644 --- a/src/walk.rs +++ b/src/walk.rs @@ -179,7 +179,13 @@ fn spawn_receiver( // This will be set to `Some` if the `--exec` argument was supplied. if let Some(ref cmd) = config.command { if cmd.in_batch_mode() { - exec::batch(rx, cmd, show_filesystem_errors, enable_output_buffering) + exec::batch( + rx, + cmd, + show_filesystem_errors, + enable_output_buffering, + config.batch_size, + ) } else { let shared_rx = Arc::new(Mutex::new(rx)); diff --git a/tests/tests.rs b/tests/tests.rs index a7c04f49..1baf15ed 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -1418,6 +1418,48 @@ fn test_exec_batch() { } } +#[test] +fn test_exec_batch_with_limit() { + // TODO Test for windows + if cfg!(windows) { + return; + } + + let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES); + + te.assert_output( + &["foo", "--batch-size", "0", "--exec-batch", "echo", "{}"], + "a.foo one/b.foo one/two/C.Foo2 one/two/c.foo one/two/three/d.foo one/two/three/directory_foo", + ); + + let output = te.assert_success_and_get_output( + ".", + &["foo", "--batch-size=2", "--exec-batch", "echo", "{}"], + ); + let stdout = String::from_utf8_lossy(&output.stdout); + + for line in stdout.lines() { + assert_eq!(2, line.split_whitespace().count()); + } + + let mut paths: Vec<_> = stdout + .lines() + .flat_map(|line| line.split_whitespace()) + .collect(); + paths.sort_unstable(); + assert_eq!( + &paths, + &[ + "a.foo", + "one/b.foo", + "one/two/C.Foo2", + "one/two/c.foo", + "one/two/three/d.foo", + "one/two/three/directory_foo" + ], + ); +} + /// Shell script execution (--exec) with a custom --path-separator #[test] fn test_exec_with_separator() { From 1236b1dbcfce14a77e9470ab53a702ef08acaabc Mon Sep 17 00:00:00 2001 From: Thayne McCombs Date: Mon, 1 Nov 2021 22:41:56 -0600 Subject: [PATCH 06/21] Update some dependencies Combination of dependabot prs. --- Cargo.lock | 36 ++++++++++++++++++------------------ Cargo.toml | 2 +- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7cfa182d..c3bfee79 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -54,24 +54,24 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "bitflags" -version = "1.2.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bstr" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90682c8d613ad3373e66de8c6411e0ae2ab2571e879d2efbf73558cc66f21279" +checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" dependencies = [ "memchr", ] [[package]] name = "cc" -version = "1.0.70" +version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0" +checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd" [[package]] name = "cfg-if" @@ -120,9 +120,9 @@ dependencies = [ [[package]] name = "ctrlc" -version = "3.2.0" +version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "377c9b002a72a0b2c1a18c62e2f3864bdfea4a015e3683a96e24aa45dd6c02d1" +checksum = "a19c6cedffdc8c03a3346d723eb20bd85a13362bb96dc2ac000842c6381ec7bf" dependencies = [ "nix", "winapi", @@ -301,9 +301,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.103" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6" +checksum = "a60553f9a9e039a333b4e9b20573b9e9b9c0bb3a11e201ccc48ef4283456d673" [[package]] name = "log" @@ -316,9 +316,9 @@ dependencies = [ [[package]] name = "lscolors" -version = "0.7.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d24b894c45c9da468621cdd615a5a79ee5e5523dd4f75c76ebc03d458940c16e" +checksum = "bd0aa49b10c47f9a4391a99198b5e65c74f9ca771c0dcc856bb75a3f46c8627d" dependencies = [ "ansi_term 0.12.1", ] @@ -340,9 +340,9 @@ dependencies = [ [[package]] name = "nix" -version = "0.22.1" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7555d6c7164cc913be1ce7f95cbecdabda61eb2ccd89008524af306fb7f5031" +checksum = "f305c2c2e4c39a82f7bf0bf65fb557f9070ce06781d4f2454295cc34b1c43188" dependencies = [ "bitflags", "cc", @@ -353,9 +353,9 @@ dependencies = [ [[package]] name = "normpath" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27e6e8f70e9fbbe3752d330d769e3424f24b9458ce266df93a3b456902fd696a" +checksum = "640c20e9df4a2d4a5adad5b47e17d76dac3e824346b181931c3ec9f7a85687b1" dependencies = [ "winapi", ] @@ -543,9 +543,9 @@ dependencies = [ [[package]] name = "unicode-width" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" [[package]] name = "users" diff --git a/Cargo.toml b/Cargo.toml index 93fe8456..c7150913 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,7 +43,7 @@ regex = "1.5.4" regex-syntax = "0.6" ctrlc = "3.2" humantime = "2.1" -lscolors = "0.7" +lscolors = "0.8" globset = "0.4" anyhow = "1.0" dirs-next = "2.0" From fd493eb7093f8d7a83afda7712b956a56081bdca Mon Sep 17 00:00:00 2001 From: Thayne McCombs Date: Mon, 1 Nov 2021 23:05:33 -0600 Subject: [PATCH 07/21] Change bug_report from an issue template to an issue form --- .github/ISSUE_TEMPLATE/bug_report.md | 28 ------------------ .github/ISSUE_TEMPLATE/bug_report.yaml | 41 ++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 28 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yaml diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 58eb9f2e..00000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -name: Bug Report -about: Report a bug. -title: "" -labels: bug -assignees: '' - ---- - -**Describe the bug you encountered:** - - - - -**Describe what you expected to happen:** - - -**What version of `fd` are you using?** - - -**Which operating system / distribution are you on?** - diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml new file mode 100644 index 00000000..778408d8 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -0,0 +1,41 @@ +name: Bug Report +description: Report a bug. +title: "[BUG] " +labels: bug +body: + - type: markdown + attributes: + value: | + Please check out the [troubleshooting section](https://github.com/sharkdp/fd#troubleshooting) first. + - type: checkboxes + attributes: + options: + - label: I have read the troubleshooting section and still think this is a bug. + required: true + - type: textarea + id: bug + attributes: + label: "Describe the bug you encountered:" + validations: + required: true + - type: textarea + id: expected + attributes: + label: "Describe what you expected to happen:" + - type: input + id: version + attributes: + label: "What version of `fd` are you using?" + placeholder: "paste the output of `fd --version` here" + validations: + required: true + - type: textarea + id: os + attributes: + label: Which operating system / distribution are you on? + placeholder: | + Unix: paste the output of `uname -srm` and lsb_release -a` here. + Windows: please tell us your Windows version + render: shell + validations: + required: true From 653bc0e55ddc43b03e1b9acf3b39f6dbc00ba8ab Mon Sep 17 00:00:00 2001 From: Joseph Lee Date: Thu, 11 Nov 2021 23:30:01 +0800 Subject: [PATCH 08/21] fix zsh completion --- contrib/completion/_fd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/completion/_fd b/contrib/completion/_fd index a17c748d..f8521a76 100644 --- a/contrib/completion/_fd +++ b/contrib/completion/_fd @@ -138,7 +138,7 @@ _fd() { + '(exec-cmds)' # execute command '(long-listing max-results)'{-x+,--exec=}'[execute command for each search result]:command: _command_names -e:*\;::program arguments: _normal' '(long-listing max-results)'{-X+,--exec-batch=}'[execute command for all search results at once]:command: _command_names -e:*\;::program arguments: _normal' - '(long-listing max-results)'{--batch-size=}'[max number of args for each -X call]:size' + '(long-listing max-results)--batch-size=[max number of args for each -X call]:size' + other '!(--max-buffer-time)--max-buffer-time=[set amount of time to buffer before showing output]:time (ms)' From 828649a30d7c419ac1c83d309126d90bc0deee66 Mon Sep 17 00:00:00 2001 From: David Peter Date: Sun, 14 Nov 2021 13:58:57 +0100 Subject: [PATCH 09/21] Revert "Add pemistahl as a maintainer" This reverts commit c06c9952b61f35a7881b399cd21d0a4f821e7055. --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index e7b56d38..f10d9610 100644 --- a/README.md +++ b/README.md @@ -667,7 +667,6 @@ cargo install --path . - [sharkdp](https://github.com/sharkdp) - [tmccombs](https://github.com/tmccombs) - [tavianator](https://github.com/tavianator) -- [pemistahl](https://github.com/pemistahl/) ## License From 690976380db1f11f6ed848761a2931e1424318d4 Mon Sep 17 00:00:00 2001 From: David Peter Date: Sun, 14 Nov 2021 16:21:24 +0100 Subject: [PATCH 10/21] Add section concerning aliases, shell functions closes #870 --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index f10d9610..e0fc261e 100644 --- a/README.md +++ b/README.md @@ -418,6 +418,14 @@ use a character class with a single hyphen character: > fd '[-]pattern' ``` +### "Command not found" for `alias`es or shell functions + +Shell `alias`es and shell functions can not be used for command execution via `fd -x` or +`fd -X`. In `zsh`, you can make the alias global via `alias -g myalias="…"`. In `bash`, +you can use `export -f my_function` to make available to child processes. You would still +need to call `fd -x bash -c 'my_function "$1"' bash`. For other use cases or shells, use +a (temporary) shell script. + ## Integration with other programs ### Using fd with `fzf` From 2570fbd04e058ed449e95b2583e7145c40e9c925 Mon Sep 17 00:00:00 2001 From: David Peter Date: Sun, 14 Nov 2021 16:29:10 +0100 Subject: [PATCH 11/21] Add longer help text for --prune, closes #727 --- src/app.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app.rs b/src/app.rs index 3f5bc2b1..efd11d76 100644 --- a/src/app.rs +++ b/src/app.rs @@ -249,7 +249,8 @@ pub fn build_app() -> App<'static, 'static> { .conflicts_with_all(&["size", "exact-depth"]) .hidden_short_help(true) .help("Do not traverse into matching directories") - .long_help("Do not traverse into matching directories.") + .long_help("Do not traverse into directories that match the search criteria. If \ + you want to exclude specific directories, use the '--exclude=…' option.") ) .arg( Arg::with_name("file-type") From 21fd01307313e7442670f6f2047371e465c53bba Mon Sep 17 00:00:00 2001 From: David Peter Date: Sun, 14 Nov 2021 17:14:21 +0100 Subject: [PATCH 12/21] Improve --full-path documentation, closes #839 --- src/app.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/app.rs b/src/app.rs index 4c17dca1..a5483659 100644 --- a/src/app.rs +++ b/src/app.rs @@ -228,11 +228,12 @@ pub fn build_app() -> App<'static, 'static> { .long("full-path") .short("p") .overrides_with("full-path") - .help("Search full path (default: file-/dirname only)") + .help("Search full abs. path (default: filename only)") .long_help( "By default, the search pattern is only matched against the filename (or \ - directory name). Using this flag, the pattern is matched against the \ - full path.", + directory name). Using this flag, the pattern is matched against the full \ + (absolute) path. Example:\n \ + fd --glob -p '**/.git/config'", ), ) .arg( From 66e3ccc5e185f334b51f64b9d7d126645e12bb52 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 16 Sep 2021 15:20:12 -0400 Subject: [PATCH 13/21] Don't color each path component separately It can be expensive to color each path component separately, requiring a stat() call on each component. For deep hierarchies this can result in quadratic overhead. Instead, just color the path up to the basename as a directory. Fixes #720. --- src/output.rs | 60 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 20 deletions(-) diff --git a/src/output.rs b/src/output.rs index 536626d1..828d9950 100644 --- a/src/output.rs +++ b/src/output.rs @@ -1,10 +1,11 @@ +use std::borrow::Cow; use std::io::{self, StdoutLock, Write}; use std::path::Path; use std::process; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; -use lscolors::{LsColors, Style}; +use lscolors::{Indicator, LsColors, Style}; use crate::config::Config; use crate::error::print_error; @@ -53,32 +54,51 @@ fn print_entry_colorized( ls_colors: &LsColors, wants_to_quit: &Arc, ) -> io::Result<()> { - let default_style = ansi_term::Style::default(); + // Split the path between the parent and the last component + let mut offset = 0; + let path_str = path.to_string_lossy(); - // Traverse the path and colorize each component - for (component, style) in ls_colors.style_for_path_components(path) { - let style = style - .map(Style::to_ansi_term_style) - .unwrap_or(default_style); - - let mut path_string = component.to_string_lossy(); - if let Some(ref separator) = config.path_separator { - *path_string.to_mut() = replace_path_separator(&path_string, separator); - } - write!(stdout, "{}", style.paint(path_string))?; - - // TODO: can we move this out of the if-statement? Why do we call it that often? - if wants_to_quit.load(Ordering::Relaxed) { - writeln!(stdout)?; - process::exit(ExitCode::KilledBySigint.into()); + if let Some(parent) = path.parent() { + offset = parent.to_string_lossy().len(); + for c in path_str[offset..].chars() { + if std::path::is_separator(c) { + offset += c.len_utf8(); + } else { + break; + } } } + if offset > 0 { + let mut parent_str = Cow::from(&path_str[..offset]); + if let Some(ref separator) = config.path_separator { + *parent_str.to_mut() = replace_path_separator(&parent_str, separator); + } + + let style = ls_colors + .style_for_indicator(Indicator::Directory) + .map(Style::to_ansi_term_style) + .unwrap_or_default(); + write!(stdout, "{}", style.paint(parent_str))?; + } + + let style = ls_colors + .style_for_path(path) + .map(Style::to_ansi_term_style) + .unwrap_or_default(); + write!(stdout, "{}", style.paint(&path_str[offset..]))?; + if config.null_separator { - write!(stdout, "\0") + write!(stdout, "\0")?; } else { - writeln!(stdout) + writeln!(stdout)?; } + + if wants_to_quit.load(Ordering::Relaxed) { + process::exit(ExitCode::KilledBySigint.into()); + } + + Ok(()) } // TODO: this function is performance critical and can probably be optimized From fc2a97208264f4cd6d092c28c0c6aac4ee6df7dd Mon Sep 17 00:00:00 2001 From: David Peter Date: Sun, 14 Nov 2021 17:20:31 +0100 Subject: [PATCH 14/21] Add CHANGELOG entry --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bb6f8e0e..ffb2fb10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ - File metadata is now cached between the different filters that require it (e.g. `--owner`, `--size`), reducing the number of `stat` syscalls when multiple filters are used; see #863 +- Colorized output is now significantly faster, see #720 and #853 (@tavianator) + ## Features - Don't buffer command output from `--exec` when using a single thread. See #522 From ecdaf58e7f16609089bc9f91c3d964d11e9a7466 Mon Sep 17 00:00:00 2001 From: David Peter Date: Sun, 14 Nov 2021 18:28:21 +0100 Subject: [PATCH 15/21] Update to latest lscolors dependency --- CHANGELOG.md | 8 +++----- Cargo.lock | 16 ++++++++-------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ffb2fb10..f8a1b6a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,19 +4,17 @@ - File metadata is now cached between the different filters that require it (e.g. `--owner`, `--size`), reducing the number of `stat` syscalls when multiple filters are used; see #863 - - Colorized output is now significantly faster, see #720 and #853 (@tavianator) ## Features + - Don't buffer command output from `--exec` when using a single thread. See #522 - - Add new `-q, --quiet` flag, see #303 (@Asha20) - - Add new `--no-ignore-parent` flag, see #787 (@will459) - - Add new `--batch-size` flag, see #410 (@devonhollowood) - - Add opposing command-line options, see #595 (@Asha20) +- Add support for more filesystem indicators in `LS_COLORS`, see + https://github.com/sharkdp/lscolors/pull/35 (@tavianator) ## Bugfixes diff --git a/Cargo.lock b/Cargo.lock index 5c4918b8..c24c3a59 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -31,9 +31,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.44" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1" +checksum = "ee10e43ae4a853c0a3591d4e2ada1719e553be18199d9da9d4a83f5927c2f5c7" [[package]] name = "atty" @@ -69,9 +69,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.71" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd" +checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" [[package]] name = "cfg-if" @@ -302,9 +302,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.106" +version = "0.2.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a60553f9a9e039a333b4e9b20573b9e9b9c0bb3a11e201ccc48ef4283456d673" +checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219" [[package]] name = "log" @@ -317,9 +317,9 @@ dependencies = [ [[package]] name = "lscolors" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd0aa49b10c47f9a4391a99198b5e65c74f9ca771c0dcc856bb75a3f46c8627d" +checksum = "9dd58d8727f3035fa6d5272f16b519741fd4875936b99d8a7cde21291b7d9174" dependencies = [ "ansi_term 0.12.1", ] From 088e42deef5a8aa49bcb3b80ba3ef18f42af9d4b Mon Sep 17 00:00:00 2001 From: David Peter Date: Sun, 14 Nov 2021 19:06:55 +0100 Subject: [PATCH 16/21] Improve --type help text closes #823 --- doc/fd.1 | 32 +++++++++++++++++++++++++++----- src/app.rs | 30 ++++++++++++++++++++++++++---- 2 files changed, 53 insertions(+), 9 deletions(-) diff --git a/doc/fd.1 b/doc/fd.1 index 51d0c034..f60a7ddd 100644 --- a/doc/fd.1 +++ b/doc/fd.1 @@ -158,18 +158,40 @@ regular files directories .IP "l, symlink" symbolic links -.IP "x, executable" -executable (files) -.IP "e, empty" -empty files or directories .IP "s, socket" sockets .IP "p, pipe" named pipes (FIFOs) +.IP "x, executable" +executable (files) +.IP "e, empty" +empty files or directories .RE .RS -This option can be used repeatedly to allow for multiple file types. +This option can be specified more than once to include multiple file types. +Searching for '--type file --type symlink' will show both regular files as well as +symlinks. Note that the 'executable' and 'empty' filters work differently: '--type +executable' implies '--type file' by default. And '--type empty' searches for +empty files and directories, unless either '--type file' or '--type directory' is +specified in addition. + +Examples: + - Only search for files: + fd --type file … + fd -tf … + - Find both files and symlinks + fd --type file --type symlink … + fd -tf -tl … + - Find executable files: + fd --type executable + fd -tx + - Find empty files: + fd --type empty --type file + fd -te -tf + - Find empty directories: + fd --type empty --type directory + fd -te -td .RE .TP .BI "\-e, \-\-extension " ext diff --git a/src/app.rs b/src/app.rs index a5483659..ee514b40 100644 --- a/src/app.rs +++ b/src/app.rs @@ -333,14 +333,36 @@ pub fn build_app() -> App<'static, 'static> { empty (e), socket (s), pipe (p)", ) .long_help( - "Filter the search by type (multiple allowable filetypes can be specified):\n \ + "Filter the search by type:\n \ 'f' or 'file': regular files\n \ 'd' or 'directory': directories\n \ 'l' or 'symlink': symbolic links\n \ - 'x' or 'executable': executables\n \ - 'e' or 'empty': empty files or directories\n \ 's' or 'socket': socket\n \ - 'p' or 'pipe': named pipe (FIFO)", + 'p' or 'pipe': named pipe (FIFO)\n\n \ + 'x' or 'executable': executables\n \ + 'e' or 'empty': empty files or directories\n\n\ + This option can be specified more than once to include multiple file types. \ + Searching for '--type file --type symlink' will show both regular files as \ + well as symlinks. Note that the 'executable' and 'empty' filters work differently: \ + '--type executable' implies '--type file' by default. And '--type empty' searches \ + for empty files and directories, unless either '--type file' or '--type directory' \ + is specified in addition.\n\n\ + Examples:\n \ + - Only search for files:\n \ + fd --type file …\n \ + fd -tf …\n \ + - Find both files and symlinks\n \ + fd --type file --type symlink …\n \ + fd -tf -tl …\n \ + - Find executable files:\n \ + fd --type executable\n \ + fd -tx\n \ + - Find empty files:\n \ + fd --type empty --type file\n \ + fd -te -tf\n \ + - Find empty directories:\n \ + fd --type empty --type directory\n \ + fd -te -td" ), ) .arg( From cab31e280bcdcd1b367ef36837d0f7c26bfbb878 Mon Sep 17 00:00:00 2001 From: David Peter Date: Mon, 15 Nov 2021 07:38:48 +0100 Subject: [PATCH 17/21] Add missing single-tick in issue template --- .github/ISSUE_TEMPLATE/bug_report.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 778408d8..bd8c609b 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -34,7 +34,7 @@ body: attributes: label: Which operating system / distribution are you on? placeholder: | - Unix: paste the output of `uname -srm` and lsb_release -a` here. + Unix: paste the output of `uname -srm` and `lsb_release -a` here. Windows: please tell us your Windows version render: shell validations: From 2b1bf471b1e503f076838faa9ba57c64a989c66c Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Sun, 14 Nov 2021 16:31:38 -0500 Subject: [PATCH 18/21] Add an exit() method to ExitCode --- src/exit_codes.rs | 7 +++++++ src/main.rs | 5 ++--- src/output.rs | 7 +++---- src/walk.rs | 7 ++----- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/exit_codes.rs b/src/exit_codes.rs index 4f8a9748..2225667d 100644 --- a/src/exit_codes.rs +++ b/src/exit_codes.rs @@ -1,3 +1,5 @@ +use std::process; + #[derive(Debug, Clone, Copy, PartialEq)] pub enum ExitCode { Success, @@ -21,6 +23,11 @@ impl ExitCode { fn is_error(self) -> bool { i32::from(self) != 0 } + + /// Exit the process with the appropriate code. + pub fn exit(self) -> ! { + process::exit(self.into()) + } } pub fn merge_exitcodes(results: impl IntoIterator) -> ExitCode { diff --git a/src/main.rs b/src/main.rs index 321df542..172d570e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,7 +12,6 @@ mod walk; use std::env; use std::path::{Path, PathBuf}; -use std::process; use std::sync::Arc; use std::time; @@ -54,11 +53,11 @@ fn main() { let result = run(); match result { Ok(exit_code) => { - process::exit(exit_code.into()); + exit_code.exit(); } Err(err) => { eprintln!("[fd error]: {:#}", err); - process::exit(ExitCode::GeneralError.into()); + ExitCode::GeneralError.exit(); } } } diff --git a/src/output.rs b/src/output.rs index 828d9950..194cb2ad 100644 --- a/src/output.rs +++ b/src/output.rs @@ -1,7 +1,6 @@ use std::borrow::Cow; use std::io::{self, StdoutLock, Write}; use std::path::Path; -use std::process; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; @@ -38,10 +37,10 @@ pub fn print_entry( if let Err(e) = r { if e.kind() == ::std::io::ErrorKind::BrokenPipe { // Exit gracefully in case of a broken pipe (e.g. 'fd ... | head -n 3'). - process::exit(0); + ExitCode::Success.exit(); } else { print_error(format!("Could not write to output: {}", e)); - process::exit(ExitCode::GeneralError.into()); + ExitCode::GeneralError.exit(); } } } @@ -95,7 +94,7 @@ fn print_entry_colorized( } if wants_to_quit.load(Ordering::Relaxed) { - process::exit(ExitCode::KilledBySigint.into()); + ExitCode::KilledBySigint.exit(); } Ok(()) diff --git a/src/walk.rs b/src/walk.rs index 789a5008..ed3bf9f5 100644 --- a/src/walk.rs +++ b/src/walk.rs @@ -3,7 +3,6 @@ use std::ffi::OsStr; use std::fs::{FileType, Metadata}; use std::io; use std::path::{Path, PathBuf}; -use std::process; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::mpsc::{channel, Receiver, Sender}; use std::sync::{Arc, Mutex}; @@ -137,11 +136,9 @@ pub fn scan(path_vec: &[PathBuf], pattern: Arc, config: Arc) -> R if config.ls_colors.is_some() && config.command.is_none() { let wq = Arc::clone(&wants_to_quit); ctrlc::set_handler(move || { - if wq.load(Ordering::Relaxed) { + if wq.fetch_or(true, Ordering::Relaxed) { // Ctrl-C has been pressed twice, exit NOW - process::exit(ExitCode::KilledBySigint.into()); - } else { - wq.store(true, Ordering::Relaxed); + ExitCode::KilledBySigint.exit(); } }) .unwrap(); From fe992706ae78f59b8dac6e55834bc69ed08a3b02 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Sun, 14 Nov 2021 16:55:14 -0500 Subject: [PATCH 19/21] Raise SIGINT when dying by ^C Fixes #854. --- Cargo.lock | 1 + Cargo.toml | 1 + src/exit_codes.rs | 13 +++++++++++++ 3 files changed, 15 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index c24c3a59..469adcfb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -175,6 +175,7 @@ dependencies = [ "lazy_static", "libc", "lscolors", + "nix", "normpath", "num_cpus", "once_cell", diff --git a/Cargo.toml b/Cargo.toml index c89b2e97..674772f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,6 +57,7 @@ features = ["suggestions", "color", "wrap_help"] [target.'cfg(unix)'.dependencies] users = "0.11.0" +nix = "0.23.0" [target.'cfg(all(unix, not(target_os = "redox")))'.dependencies] libc = "0.2" diff --git a/src/exit_codes.rs b/src/exit_codes.rs index 2225667d..e44111bb 100644 --- a/src/exit_codes.rs +++ b/src/exit_codes.rs @@ -1,5 +1,8 @@ use std::process; +#[cfg(unix)] +use nix::sys::signal::{raise, signal, SigHandler, Signal}; + #[derive(Debug, Clone, Copy, PartialEq)] pub enum ExitCode { Success, @@ -26,6 +29,16 @@ impl ExitCode { /// Exit the process with the appropriate code. pub fn exit(self) -> ! { + #[cfg(unix)] + if self == ExitCode::KilledBySigint { + // Get rid of the SIGINT handler, if present, and raise SIGINT + unsafe { + if signal(Signal::SIGINT, SigHandler::SigDfl).is_ok() { + let _ = raise(Signal::SIGINT); + } + } + } + process::exit(self.into()) } } From f32060b0de34b52c255027aea12ac5ce53e40d6e Mon Sep 17 00:00:00 2001 From: Jacob Mischka Date: Wed, 17 Nov 2021 02:55:12 -0600 Subject: [PATCH 20/21] Change time comparisons to exclusive Closes #794 --- CHANGELOG.md | 1 + doc/fd.1 | 4 ++-- src/filter/time.rs | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f8a1b6a6..f3b4e3cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ - Support `--list-details` on more platforms (like BusyBox), see #783 - The filters `--owner`, `--size`, and `--changed-{within,before}` now apply to symbolic links themselves, rather than the link target, except when `--follow` is specified; see #863 +- Change time comparisons to be exclusive, see #794 (@jacobmischka) ## Changes diff --git a/doc/fd.1 b/doc/fd.1 index f60a7ddd..51deaff6 100644 --- a/doc/fd.1 +++ b/doc/fd.1 @@ -269,7 +269,7 @@ tebibytes .TP .BI "\-\-changed-within " date|duration Filter results based on the file modification time. -Files with modification times greater than or equal to the argument will be returned. +Files with modification times greater than the argument will be returned. The argument can be provided as a duration (\fI10h, 1d, 35min\fR) or as a specific point in time in either full RFC3339 format with time zone, or as a date or datetime in the local time zone (\fIYYYY-MM-DD\fR or \fIYYYY-MM-DD HH:MM:SS\fR). @@ -282,7 +282,7 @@ Examples: .TP .BI "\-\-changed-before " date|duration Filter results based on the file modification time. -Files with modification times less than or equal to the argument will be returned. +Files with modification times less than the argument will be returned. The argument can be provided as a duration (\fI10h, 1d, 35min\fR) or as a specific point in time in either full RFC3339 format with time zone, or as a date or datetime in the local time zone (\fIYYYY-MM-DD\fR or \fIYYYY-MM-DD HH:MM:SS\fR). diff --git a/src/filter/time.rs b/src/filter/time.rs index 39979afa..eb43c4bb 100644 --- a/src/filter/time.rs +++ b/src/filter/time.rs @@ -39,8 +39,8 @@ impl TimeFilter { pub fn applies_to(&self, t: &SystemTime) -> bool { match self { - TimeFilter::Before(limit) => t <= limit, - TimeFilter::After(limit) => t >= limit, + TimeFilter::Before(limit) => t < limit, + TimeFilter::After(limit) => t > limit, } } } From 0484486f3f704aecadd35b574f1ab179ce03bcd8 Mon Sep 17 00:00:00 2001 From: Shun Sakai Date: Thu, 25 Nov 2021 22:34:54 +0900 Subject: [PATCH 21/21] Remove `lazy_static` from dependencies --- Cargo.lock | 1 - Cargo.toml | 1 - src/exec/mod.rs | 7 +++---- src/filter/size.rs | 7 +++---- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 469adcfb..4cc7fcfc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -172,7 +172,6 @@ dependencies = [ "humantime", "ignore", "jemallocator", - "lazy_static", "libc", "lscolors", "nix", diff --git a/Cargo.toml b/Cargo.toml index 674772f4..e8f21290 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,7 +37,6 @@ version_check = "0.9" ansi_term = "0.12" atty = "0.2" ignore = "0.4.3" -lazy_static = "1.1.0" num_cpus = "1.8" regex = "1.5.4" regex-syntax = "0.6" diff --git a/src/exec/mod.rs b/src/exec/mod.rs index a364e86d..fc22e6f9 100644 --- a/src/exec/mod.rs +++ b/src/exec/mod.rs @@ -10,7 +10,7 @@ use std::process::{Command, Stdio}; use std::sync::{Arc, Mutex}; use anyhow::{anyhow, Result}; -use lazy_static::lazy_static; +use once_cell::sync::Lazy; use regex::Regex; use crate::exit_codes::ExitCode; @@ -72,9 +72,8 @@ impl CommandTemplate { I: IntoIterator, S: AsRef, { - lazy_static! { - static ref PLACEHOLDER_PATTERN: Regex = Regex::new(r"\{(/?\.?|//)\}").unwrap(); - } + static PLACEHOLDER_PATTERN: Lazy = + Lazy::new(|| Regex::new(r"\{(/?\.?|//)\}").unwrap()); let mut args = Vec::new(); let mut has_placeholder = false; diff --git a/src/filter/size.rs b/src/filter/size.rs index 5435b195..2af20bc4 100644 --- a/src/filter/size.rs +++ b/src/filter/size.rs @@ -1,9 +1,8 @@ -use lazy_static::lazy_static; +use once_cell::sync::Lazy; use regex::Regex; -lazy_static! { - static ref SIZE_CAPTURES: Regex = Regex::new(r"(?i)^([+-]?)(\d+)(b|[kmgt]i?b?)$").unwrap(); -} +static SIZE_CAPTURES: Lazy = + Lazy::new(|| Regex::new(r"(?i)^([+-]?)(\d+)(b|[kmgt]i?b?)$").unwrap()); #[derive(Clone, Copy, Debug, PartialEq)] pub enum SizeFilter {