Skip to content

Commit 690aa21

Browse files
committed
Merge branch 'time-styles-properly'
This merges in the ability to use different time styles, such as full ISO-formatted timestamps instead of just using the default variable style. Firstly, this moved the Environment from the Table to the Columns, so it 1) would only be instantiated when a table is actually used, and 2) can be affected by command-line options. Next, it renames Columns to table::Options, in line with what the view optionses were renamed to. Finally, it adds support for more time styles, deferring timestamp formatting to an enum. Fixes ogham#133.
2 parents 651d23f + 6afde85 commit 690aa21

27 files changed

+516
-309
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,12 @@ These options are available when running with --long (`-l`):
5151
- **-U**, **--created**: use the created timestamp field
5252
- **-@**, **--extended**: list each file's extended attributes and sizes
5353
- **--git**: list each file's Git status, if tracked
54+
- **--time-style**: how to format timestamps
5455

5556
- Valid **--color** options are **always**, **automatic**, and **never**.
5657
- Valid sort fields are **accessed**, **created**, **extension**, **Extension**, **inode**, **modified**, **name**, **Name**, **size**, **type**, and **none**. Fields starting with a capital letter are case-sensitive.
5758
- Valid time fields are **modified**, **accessed**, and **created**.
59+
- Valid time styles are **default**, **iso**, **long-iso**, and **full-iso**.
5860

5961

6062
## Installation

Vagrantfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,8 @@ Vagrant.configure(2) do |config|
320320
touch -t #{old} -a "#{test_dir}/dates/plum"
321321
touch -t #{med} -a "#{test_dir}/dates/pear"
322322
touch -t #{new} -a "#{test_dir}/dates/peach"
323+
324+
sudo chown #{user}:#{user} -R "#{test_dir}/dates"
323325
EOF
324326

325327

contrib/completions.bash

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ _exa()
2222
COMPREPLY=( $( compgen -W 'accessed modified created --' -- $cur ) )
2323
return
2424
;;
25+
26+
--time-style)
27+
COMPREPLY=( $( compgen -W 'default iso long-iso full-iso --' -- $cur ) )
28+
return
29+
;;
2530
esac
2631

2732
case "$cur" in

contrib/completions.fish

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,14 @@ complete -c exa -s 't' -l 'time' -x -d "Which timestamp field to list" -a "
5555
created\t'Display created time'
5656
modified\t'Display modified time'
5757
"
58-
complete -c exa -s 'u' -l 'accessed' -d "Use the accessed timestamp field"
59-
complete -c exa -s 'U' -l 'created' -d "Use the created timestamp field"
58+
complete -c exa -s 'u' -l 'accessed' -d "Use the accessed timestamp field"
59+
complete -c exa -s 'U' -l 'created' -d "Use the created timestamp field"
60+
complete -c exa -l 'time-style' -x -d "How to format timestamps" -a "
61+
default\t'Use the default time style'
62+
iso\t'Display brief ISO timestamps'
63+
long-iso\t'Display longer ISO timestaps, up to the minute'
64+
full-iso\t'Display full ISO timestamps, up to the nanosecond'
65+
"
6066

6167
# Optional extras
6268
complete -c exa -s 'g' -l 'git' -d "List each file's Git status, if tracked"

contrib/completions.zsh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ __exa() {
2929
{-m,--modified}"[Use the modified timestamp field]" \
3030
{-S,--blocks}"[List each file's number of filesystem blocks]" \
3131
{-t,--time}"[Which time field to show]:(time field):(accessed created modified)" \
32+
--time-style"[How to format timestamps]:(time style):(default iso long-iso full-iso)" \
3233
{-u,--accessed}"[Use the accessed timestamp field]" \
3334
{-U,--created}"[Use the created timestamp field]" \
3435
--git"[List each file's Git status, if tracked]" \

contrib/man/exa.1

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,11 @@ which timestamp field to list (modified, accessed, created)
145145
.RS
146146
.RE
147147
.TP
148+
.B \-\-time\-style=\f[I]STYLE\f[]
149+
how to format timestamps (default, iso, long-iso, full-iso)
150+
.RS
151+
.RE
152+
.TP
148153
.B \-u, \-\-accessed
149154
use the accessed timestamp field
150155
.RS

src/fs/fields.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,11 @@ pub struct DeviceIDs {
166166

167167

168168
/// One of a file’s timestamps (created, accessed, or modified).
169-
pub struct Time(pub time_t);
169+
#[derive(Copy, Clone)]
170+
pub struct Time {
171+
pub seconds: time_t,
172+
pub nanoseconds: time_t,
173+
}
170174

171175

172176
/// A file’s status in a Git repository. Whether a file is in a repository or

src/fs/file.rs

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -273,23 +273,35 @@ impl<'dir> File<'dir> {
273273
}
274274
}
275275

276+
/// This file’s last modified timestamp.
276277
pub fn modified_time(&self) -> f::Time {
277-
f::Time(self.metadata.mtime())
278+
f::Time {
279+
seconds: self.metadata.mtime(),
280+
nanoseconds: self.metadata.mtime_nsec()
281+
}
278282
}
279283

284+
/// This file’s created timestamp.
280285
pub fn created_time(&self) -> f::Time {
281-
f::Time(self.metadata.ctime())
286+
f::Time {
287+
seconds: self.metadata.ctime(),
288+
nanoseconds: self.metadata.ctime_nsec()
289+
}
282290
}
283291

292+
/// This file’s last accessed timestamp.
284293
pub fn accessed_time(&self) -> f::Time {
285-
f::Time(self.metadata.mtime())
294+
f::Time {
295+
seconds: self.metadata.atime(),
296+
nanoseconds: self.metadata.atime_nsec()
297+
}
286298
}
287299

288-
/// This file's 'type'.
300+
/// This file’s ‘type.
289301
///
290-
/// This is used in the leftmost column of the permissions column.
291-
/// Although the file type can usually be guessed from the colour of the
292-
/// file, `ls` puts this character there, so people will expect it.
302+
/// This is used a the leftmost character of the permissions column.
303+
/// The file type can usually be guessed from the colour of the file, but
304+
/// ls puts this character there.
293305
pub fn type_char(&self) -> f::Type {
294306
if self.is_file() {
295307
f::Type::File
@@ -341,7 +353,7 @@ impl<'dir> File<'dir> {
341353
}
342354
}
343355

344-
/// Whether this file's extension is any of the strings that get passed in.
356+
/// Whether this files extension is any of the strings that get passed in.
345357
///
346358
/// This will always return `false` if the file has no extension.
347359
pub fn extension_is_one_of(&self, choices: &[&str]) -> bool {

src/options/help.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ LONG VIEW OPTIONS
4040
-S, --blocks show number of file system blocks
4141
-t, --time FIELD which timestamp field to list (modified, accessed, created)
4242
-u, --accessed use the accessed timestamp field
43-
-U, --created use the created timestamp field"##;
43+
-U, --created use the created timestamp field
44+
--time-style how to format timestamps (default, iso, long-iso, full-iso)"##;
4445

4546
static GIT_HELP: &str = r##" --git list each file's Git status, if tracked"##;
4647
static EXTENDED_HELP: &str = r##" -@, --extended list each file's extended attributes and sizes"##;

src/options/mod.rs

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ pub use self::view::{View, Mode};
2323

2424
/// These **options** represent a parsed, error-checked versions of the
2525
/// user’s command-line options.
26-
#[derive(PartialEq, Debug, Clone)]
26+
#[derive(Debug)]
2727
pub struct Options {
2828

2929
/// The action to perform when encountering a directory rather than a
@@ -77,17 +77,18 @@ impl Options {
7777
opts.optopt ("I", "ignore-glob", "ignore files that match these glob patterns", "GLOB1|GLOB2...");
7878

7979
// Long view options
80-
opts.optflag("b", "binary", "list file sizes with binary prefixes");
81-
opts.optflag("B", "bytes", "list file sizes in bytes, without prefixes");
82-
opts.optflag("g", "group", "list each file's group");
83-
opts.optflag("h", "header", "add a header row to each column");
84-
opts.optflag("H", "links", "list each file's number of hard links");
85-
opts.optflag("i", "inode", "list each file's inode number");
86-
opts.optflag("m", "modified", "use the modified timestamp field");
87-
opts.optflag("S", "blocks", "list each file's number of file system blocks");
88-
opts.optopt ("t", "time", "which timestamp field to show", "WORD");
89-
opts.optflag("u", "accessed", "use the accessed timestamp field");
90-
opts.optflag("U", "created", "use the created timestamp field");
80+
opts.optflag("b", "binary", "list file sizes with binary prefixes");
81+
opts.optflag("B", "bytes", "list file sizes in bytes, without prefixes");
82+
opts.optflag("g", "group", "list each file's group");
83+
opts.optflag("h", "header", "add a header row to each column");
84+
opts.optflag("H", "links", "list each file's number of hard links");
85+
opts.optflag("i", "inode", "list each file's inode number");
86+
opts.optflag("m", "modified", "use the modified timestamp field");
87+
opts.optflag("S", "blocks", "list each file's number of file system blocks");
88+
opts.optopt ("t", "time", "which timestamp field to show", "WORD");
89+
opts.optflag("u", "accessed", "use the accessed timestamp field");
90+
opts.optflag("U", "created", "use the created timestamp field");
91+
opts.optopt ("", "time-style", "how to format timestamp fields", "STYLE");
9192

9293
if cfg!(feature="git") {
9394
opts.optflag("", "git", "list each file's git status");
@@ -124,8 +125,8 @@ impl Options {
124125
/// results will end up being displayed.
125126
pub fn should_scan_for_git(&self) -> bool {
126127
match self.view.mode {
127-
Mode::Details(details::Options { columns: Some(cols), .. }) |
128-
Mode::GridDetails(_, details::Options { columns: Some(cols), .. }) => cols.should_scan_for_git(),
128+
Mode::Details(details::Options { table: Some(ref table), .. }) |
129+
Mode::GridDetails(_, details::Options { table: Some(ref table), .. }) => table.should_scan_for_git(),
129130
_ => false,
130131
}
131132
}
@@ -201,13 +202,13 @@ mod test {
201202
#[test]
202203
fn long_across() {
203204
let opts = Options::getopts(&[ "--long", "--across" ]);
204-
assert_eq!(opts, Err(Misfire::Useless("across", true, "long")))
205+
assert_eq!(opts.unwrap_err(), Misfire::Useless("across", true, "long"))
205206
}
206207

207208
#[test]
208209
fn oneline_across() {
209210
let opts = Options::getopts(&[ "--oneline", "--across" ]);
210-
assert_eq!(opts, Err(Misfire::Useless("across", true, "oneline")))
211+
assert_eq!(opts.unwrap_err(), Misfire::Useless("across", true, "oneline"))
211212
}
212213

213214
#[test]

0 commit comments

Comments
 (0)