- Checking on a directory doesn’t tell us if supported elsewhere
(some filesystems, like tmpfs, don’t support created time)
- We want to be able to display a column even if some subfiles or
subdirectories don’t support it
So now if unsupported a time of zero is used, and displayed as `-`
The Default impls for DefaultFormat and LoadFormat were originally called ‘new’, to which Clippy suggested that they be changed. But as these functions change based on what the year is, a function called something other than ‘new’, like ‘load’.
This commit changes the definition of Arg so that it knows about which values it can accept, and can display them in the help text. They were already being shown in the help text, but they were passed in separately, so one argument could show two different sets of options if it wanted. Now, the argument itself knows whether there are suggestions, so it doesn’t have to be passed in separately.
This means we can use it for other things, including listing choices when an option is missed out, without having to repeat the list.
With Misfire::BadArgument now only having two fields, it’s not worth using a constructor function anymore.
This commit meddles about with both the Colours and the FileExtensions.
Even though all the renderable fields were turned into traits, the FileName struct kept on accessing fields directly on the Colours value instead of calling methods on it. It also did the usual amount of colour misappropriation (such as ‘punctuation’ instead of specifying ‘normal_arrow’)
In preparation for when custom file colours are configurable (any day now), the colourise-file-by-kind functionality (links, sockets, or directories) was separated from the colourise-file-by-name functionality (images, videos, archives). The FileStyle struct already allowed for both to be separate; it was only changed so that a type other than FileExtensions could be used instead, as long as it implements the FileColours trait. (I feel like I should re-visit the naming of all these at some point in the future)
The decision to separate the two means that FileExtensions is the one assigning the colours, rather than going through the fields on a Colours value, which have all been removed. This is why a bunch of arbitrary Styles now exist in filetype.rs.
Because the decision on which colourise-file-by-name code to use (currently just the standard extensions, or nothing if we aren’t colourising) is now determined by the Colours type (instead of being derived), it’s possible to get it wrong. And wrong it was! There was a bug where file names were colourised even though the rest of the --long output wasn’t, and this wasn’t caught by the xtests. It is now.
Just because the type that gets used right now is Copy and Clone doesn’t mean that when we pass mock ones in for tests they’ll be those two as well. So we have to go through and add &s everywhere.
No new features here, just some restructuring. Mode::GridDetails was nice and elegant with those two fields, but now there’s a grid-details-only option the elegance has gone out the window.
Some of the deduce functions used to just blatantly call std::env::var_os and not care, introducing global state into a module that was otherwise nice and functional and self-contained. (Well, almost. There’s still terminal width.)
Anyway, this made it hard to test, because we couldn’t test it fully with this global dependency in place. It *is* possible to work around this by actually setting the environment variables in the tests, but this way is more self-documenting.
With this in place, we can start to unit test things like deriving the view by passing in what the $COLUMNS environment variable should be, and that’s one of the first things checked.
src/options/mod.rs *almost* has all its tests moved to where they should be!
Sometimes, the type in the Ok part of the Result wouldn’t implement PartialEq, so the first macro (which uses assert_eq) won’t work. In these cases, this new macro can be used instead, which just unwraps the Err’s contents. In other cases, it can shave off a ) at the end of a few lines.
The table Options struct is roughly half runtime configuration and half flags to select which columns to display The column fields might as well be in their own struct, and now that the ‘for_dir’ function doesn’t use SizeFormat, it can be moved to Columns.
This changes the SizeFormat option parser from its old, strict-by-default behaviour (where passing both --bytes and --binary would be an error) to the new, use-the-last-argument behaviour (where passing --bytes --binary would use --binary because it came later).
Doing this meant adding functionality to Matches so that it could return *which* argument matched. Previously, the order of --bytes and --binary didn’t matter, because they couldn’t both be present, but now it does.
The assert_parses function was problematic because it insisted on using assert_eq! to check its contents. This won’t work for any type we want to test that doesn’t implement PartialEq, such as TimeFormat, which holds references to years and date strings and other such.
To go about fixing this, the first step is to change that function so it only does the initial processing, rather than the assertion, which is now done outside of it in the test macros instead.
Now the code actually starts to use the Strictness flag that was added in the earlier commit! Well, the *code* doesn’t, but the tests do: the macros that create the test cases now have a parameter for which tests they should run. It’s usually ‘Both’ for both strict mode and default mode, but can be specified to only run in one, for when the results differ (usually when options override one another)
The downside to strict mode is that, now, *any* call to `matches.has` or `matches.get` could fail, because an option could have been specified twice, and this is the place where those are checked for. This makes the code a little less ergonomic in places, but that’s what the ? operator is for. The only place this has really had an effect is in `Classify::deduce`, which used to just return a boolean but can now fail.
In order to more thoroughly test the mode, some of the older parts of the code can now act more strict. For example, `TerminalColours::deduce` will now use the last-given option rather than searching for “colours” before “colors”.
Help and Version continue doing their own thing.
The value is ignored, but this broke quite a lot of tests that assumed MatchedFlags had only one field.
Parsing tests have to have OsStr flags because I couldn’t get that part working right, but in general, some tests now re-use common functionality too.
This merges in exa’s own new options parser, which has the following features:
- You can specify an option twice and it’ll use the second one, making aliases usable for defaults (fixes#144)
- Lets arguments be specified more than once (fixes#125)
Strict mode is not done yet; I just wanted to merge this in because it’s been a while, and there’s work that needs to be done on master so I don’t want them drifting apart any further.
It’s likely that you’ll find cases where multiple arguments doesn’t work or where the wrong value is being used. There aren’t tests for *everything* yet, and it still uses global environment variables.
# Conflicts:
# src/options/view.rs
The term_size crate introduced in #237 did things *slightly* differently than exa: it tried to get the terminal width of stdout, stderr, and stdin. This broke some tests that only redirected stdout.
Originally, both the matched flags and the list of free strings were returned from the parsing function and then passed around to every type that had a ‘deduce’ method. This worked, but the list of free strings was carried around with it, never used.
Now, only the flags are passed around. They’re in a new struct which has the methods the Matches had.
Both of Matches’s fields are now just data, and all of the methods on MatchedFlags don’t ignore any fields, so it’s more cohesive, at least I think that’s the word.
Building up the MatchedFlags is a bit more annoying though because the vector is now hidden behind a field.