Repository: sharkdp/fd (language: rust)

Issue:
Make `--type empty` its own option
```
-t, --type <filetype>...              
        Filter the search by type (multiple allowable filetypes can be specified):
          'f' or 'file':         regular files
          'd' or 'directory':    directories
          'l' or 'symlink':      symbolic links
          'x' or 'executable':   executables
          'e' or 'empty':        empty files or directories
          's' or 'socket':       socket
          'p' or 'pipe':         named pipe (FIFO)
```
the help `multiple allowable filetypes can be specified` suggests that adding multiple type parameters will have an `OR` effect (if a file is any of the types then it will be included in the results), but this is not always the case. In particular, the `empty` type is inconsistent. When used with `symlink`, `socket`, or `pipe`, it works in accordance with the help, anything that is `empty` `OR` the other type will be included. However, if you use it with `file`, `executable`, or `directory` it will only include results if they are both `empty` `AND` the other type (e.g. `fd --type empty --type directory` only includes empty directories.

`empty` being a type prevents me from searching for empty symlinks, sockets, or pipes. (I'm not sure if these are possible but I digress)

This issue is touched upon in #714 :
> You are right. executable and empty are special in that they mean: only show executable/empty results. Otherwise --type file --type empty would mean: "show me files OR empty directories/files", which would result in ALL files and empty directories. I don't think that's what most users would expect. See also: #246 (comment)

I think `empty` being made its own option would fix this issue, removing any confusion.


Discussion / hints:
I don't think an empty socket or pipe  makes sense. Does an empty symlink mean the target of the symlink  is empty?
> I don't think an empty socket or pipe makes sense. Does an empty symlink mean the target of the symlink is empty?

I'd assume so, but it's not so much about adding functionality by allowing to search for empty symlinks; rather, it's more about having a consistent behaviour. I find it kind of confusing because the help suggests a different behaviour to what is actually happening. A solution would be to document the special case in the help and leave it, but I don't think that will fix the underlying issue, which is, in my opinion, with the "flawed" design.

If you feel that it is fine, feel free to close the issue, this issue is based on my subjective opinion, so you and others may disagree.
So is this proposal to add a new `--empty` option that acts the same as the current `--type empty`, or is the behavior of the empty flag different? If it is different do we keep the `empty` file type? that seems like it would be confusing.

And what about `executable` that has similar behavior to `empty`, should that be a separate flag as well?

I'm not saying we shouldn't do this, just trying to get a clear idea of what would change.


I wonder if maybe there should be a different grouping that has things like `empty`, `executable`, and potentially `text` or `binary`.  Since those are more properties of the file rather than "filetype"s.
Yea the proposal is to add a new `--empty` flag that would act pretty much identically to the current `--type empty`. I just think that `empty` being put under the `--type` option is wrong.

I didn't want to suggest `executable` as I looked through a bit of the source code of `fd` and it seems like directories are classed as executable if they contain executables. I doubt that if someone is using the `--executable` flag they are looking for directories. Though, in a sense, it is a similar issue to `empty`.

I think some sort of `property` option would be a good idea, as, similar to file types, you could group the modifiers in the help menu, and it would also probably make the implementation cleaner and more understandable.
> it seems like directories are classed as executable if they contain executables

No, it tests if the directory has the `execute` permission. Which on directories means that you can access files within the directory. It does seem kind of odd to me that suppling a type of executable implies `--type file`, so you can't filter to executable directories.

I've started a branch to address this, I'll post a PR shortly.
Thank you for reporting and discussing this, @tsoutsman and @tmccombs.

The current behavior of the `--type` option was carefully designed and is not an oversight. I am fully aware of the (potentially confusing?) behavior when involving `empty`/`executable`. I also fully agree that the documentation should be improved.

But I don't really see that we need a new option for this. I haven't seen any valid use cases which we can not solve with the current option. And I think a certain simplificity in CLI design is a very valuable feature of `fd`.

I am proposing that we change the `--help` text and man page to the following text:
```
    -t, --type <filetype>...
            Filter the search by type:
              'f' or 'file':         regular files
              'd' or 'directory':    directories
              'l' or 'symlink':      symbolic links
              's' or 'socket':       socket
              'p' or 'pipe':         named pipe (FIFO)
            
              'x' or 'executable':   executables
              'e' or 'empty':        empty files or directories
            
            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
```
I think those five examples cover a huge percentage of use cases. And I also believe that the current syntax is actually quite intuitive... *unless* someone tries to interpret it as a strict `OR` - which it is not.

I agree that it's not fully satisfactory, but I still like this better than introducing a completely new command line option.

What do you think @tmccombs @tsoutsman?

Fix patch:
diff --git a/doc/fd.1 b/doc/fd.1
index 51d0c034a..f60a7ddd1 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 a54836595..ee514b40f 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(


Test patch: