summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Peter <mail@david-peter.de>2021-11-26 18:18:25 +0100
committerDavid Peter <mail@david-peter.de>2021-11-26 18:19:28 +0100
commit92bd7850d0e6232d793135ad3f1c8cd4282b4b85 (patch)
treec8dff9bb9684b40c20bcd9561492b932bf912496
parent06c58b99f5e70e5fc7cb3167ab2fddb0703a6324 (diff)
parent0484486f3f704aecadd35b574f1ab179ce03bcd8 (diff)
Merge remote-tracking branch 'origin/master' into no-strip/760
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.md28
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.yaml41
-rw-r--r--CHANGELOG.md9
-rw-r--r--Cargo.lock91
-rw-r--r--Cargo.toml7
-rw-r--r--README.md9
-rw-r--r--contrib/completion/_fd1
-rw-r--r--doc/fd.150
-rw-r--r--src/app.rs115
-rw-r--r--src/config.rs4
-rw-r--r--src/exec/job.rs15
-rw-r--r--src/exec/mod.rs7
-rw-r--r--src/exit_codes.rs20
-rw-r--r--src/filter/size.rs7
-rw-r--r--src/filter/time.rs4
-rw-r--r--src/main.rs11
-rw-r--r--src/output.rs61
-rw-r--r--src/walk.rs15
-rw-r--r--tests/tests.rs67
19 files changed, 444 insertions, 118 deletions
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
deleted file mode 100644
index 58eb9f2..0000000
--- 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:**
-
-<!--
-Please check out the troubleshooting section first:
- https://github.com/sharkdp/fd#troubleshooting
--->
-
-
-**Describe what you expected to happen:**
-
-
-**What version of `fd` are you using?**
-<!-- paste the output of `fd --version` here -->
-
-**Which operating system / distribution are you on?**
-<!--
-Unix: paste the output of `uname -srm` and `lsb_release -a` here.
-Windows: please tell us your Windows version
--->
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml
new file mode 100644
index 0000000..bd8c609
--- /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
diff --git a/CHANGELOG.md b/CHANGELOG.md
index afe8f31..529cd52 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,13 +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
+- 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
@@ -23,6 +27,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/Cargo.lock b/Cargo.lock
index 7cfa182..4cc7fcf 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"
@@ -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.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0"
+checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee"
[[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",
@@ -172,15 +172,16 @@ dependencies = [
"humantime",
"ignore",
"jemallocator",
- "lazy_static",
"libc",
"lscolors",
+ "nix",
"normpath",
"num_cpus",
"once_cell",
"regex",
"regex-syntax",
"tempdir",
+ "test-case",
"users",
"version_check",
]
@@ -301,9 +302,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
-version = "0.2.103"
+version = "0.2.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6"
+checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219"
[[package]]
name = "log"
@@ -316,9 +317,9 @@ dependencies = [
[[package]]
name = "lscolors"
-version = "0.7.1"
+version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d24b894c45c9da468621cdd615a5a79ee5e5523dd4f75c76ebc03d458940c16e"
+checksum = "9dd58d8727f3035fa6d5272f16b519741fd4875936b99d8a7cde21291b7d9174"
dependencies = [
"ansi_term 0.12.1",
]
@@ -340,9 +341,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 +354,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",
]
@@ -396,6 +397,24 @@ 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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -493,6 +512,17 @@ 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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -513,6 +543,19 @@ dependencies = [
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -543,9 +586,15 @@ dependencies = [
[[package]]
name = "unicode-width"
-version = "0.1.8"
+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 = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
+checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "users"
diff --git a/Cargo.toml b/Cargo.toml
index 93fe845..e8f2129 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -37,13 +37,12 @@ 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"
ctrlc = "3.2"
humantime = "2.1"
-lscolors = "0.7"
+lscolors = "0.8"
globset = "0.4"
anyhow = "1.0"
dirs-next = "2.0"
@@ -57,6 +56,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"
@@ -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/README.md b/README.md
index e7b56d3..e0fc261 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`
@@ -667,7 +675,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
diff --git a/contrib/completion/_fd b/contrib/completion/_fd
index 28b37ee..f8521a7 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 69e8438..51deaff 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
@@ -154,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
@@ -243,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).
@@ -256,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).
@@ -405,5 +431,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 9c1c04e..dd4282b 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(
@@ -178,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(
@@ -249,7 +300,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")
@@ -281,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(
@@ -366,6 +440,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")
.short("E")
diff --git a/src/config.rs b/src/config.rs
index 91ca601..5a71714 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<Arc<CommandTemplate>>,
+ /// 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<String>,
diff --git a/src/exec/job.rs b/src/exec/job.rs
index 83abf1a..aa8164c 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/exec/mod.rs b/src/exec/mod.rs
index 15e1ae5..3f93acd 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;
@@ -71,9 +71,8 @@ impl CommandTemplate {
I: IntoIterator<Item = S>,
S: AsRef<str>,
{
- lazy_static! {
- static ref PLACEHOLDER_PATTERN: Regex = Regex::new(r"\{(/?\.?|//)\}").unwrap();
- }
+ static PLACEHOLDER_PATTERN: Lazy<Regex> =
+ Lazy::new(|| Regex::new(r"\{(/?\.?|//)\}").unwrap());
let mut args = Vec::new();
let mut has_placeholder = false;
diff --git a/src/exit_codes.rs b/src/exit_codes.rs
index 4f8a974..e44111b 100644
--- a/src/exit_codes.rs
+++ b/src/exit_codes.rs
@@ -1,3 +1,8 @@
+use std::process;
+
+#[cfg(unix)]
+use nix::sys::signal::{raise, signal, SigHandler, Signal};
+
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ExitCode {
Success,
@@ -21,6 +26,21 @@ impl ExitCode {
fn is_error(self) -> bool {
i32::from(self) != 0
}
+
+ /// 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())
+ }
}
pub fn merge_exitcodes(results: impl IntoIterator<Item = ExitCode>) -> ExitCode {
diff --git a/src/filter/size.rs b/src/filter/size.rs
index 5435b19..2af20bc 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<Regex> =
+ Lazy::new(|| Regex::new(r"(?i)^([+-]?)(\d+)(b|[kmgt]i?b?)$").unwrap());
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum SizeFilter {
diff --git a/src/filter/time.rs b/src/filter/time.rs
index 39979af..eb43c4b 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,
}
}
}
diff --git a/src/main.rs b/src/main.rs
index 974c561..cb6dfa8 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -12,7 +12,