mirror of
https://github.com/Llewellynvdm/exa.git
synced 2024-11-26 13:56:27 +00:00
Add “changed” sort option, to replace old incorrect “created”
This commit is contained in:
parent
b0da0c9055
commit
56717c7336
@ -62,8 +62,8 @@ These options are available when running with --long (`-l`):
|
||||
- **--time-style**: how to format timestamps
|
||||
|
||||
- Valid **--color** options are **always**, **automatic**, and **never**.
|
||||
- Valid sort fields are **accessed**, **created**, **extension**, **Extension**, **inode**, **modified**, **name**, **Name**, **size**, **type**, and **none**. Fields starting with a capital letter sort uppercase before lowercase. The modified field has the aliases **date**, **time**, and **newest**, while its reverse has the aliases **age** and **oldest**.
|
||||
- Valid time fields are **modified**, **accessed**, and **created**.
|
||||
- Valid sort fields are **accessed**, **changed**, **created**, **extension**, **Extension**, **inode**, **modified**, **name**, **Name**, **size**, **type**, and **none**. Fields starting with a capital letter sort uppercase before lowercase. The modified field has the aliases **date**, **time**, and **newest**, while its reverse has the aliases **age** and **oldest**.
|
||||
- Valid time fields are **modified**, **changed**, **accessed**, and **created**.
|
||||
- Valid time styles are **default**, **iso**, **long-iso**, and **full-iso**.
|
||||
|
||||
|
||||
|
@ -14,12 +14,12 @@ _exa()
|
||||
;;
|
||||
|
||||
-s|--sort)
|
||||
COMPREPLY=( $( compgen -W 'name filename Name Filename size filesize extension Extension date time modified accessed created type inode oldest newest age none --' -- "$cur" ) )
|
||||
COMPREPLY=( $( compgen -W 'name filename Name Filename size filesize extension Extension date time modified changed accessed created type inode oldest newest age none --' -- "$cur" ) )
|
||||
return
|
||||
;;
|
||||
|
||||
-t|--time)
|
||||
COMPREPLY=( $( compgen -W 'accessed modified created --' -- $cur ) )
|
||||
COMPREPLY=( $( compgen -W 'modified changed accessed created --' -- $cur ) )
|
||||
return
|
||||
;;
|
||||
|
||||
|
@ -25,6 +25,7 @@ complete -c exa -s 'r' -l 'reverse' -d "Reverse the sort order"
|
||||
complete -c exa -s 's' -l 'sort' -x -d "Which field to sort by" -a "
|
||||
accessed\t'Sort by file accessed time'
|
||||
age\t'Sort by file modified time (newest first)'
|
||||
changed\t'Sort by changed time'
|
||||
created\t'Sort by file modified time'
|
||||
date\t'Sort by file modified time'
|
||||
ext\t'Sort by file extension'
|
||||
@ -54,13 +55,15 @@ complete -c exa -s 'g' -l 'group' -d "List each file's group"
|
||||
complete -c exa -s 'h' -l 'header' -d "Add a header row to each column"
|
||||
complete -c exa -s 'h' -l 'links' -d "List each file's number of hard links"
|
||||
complete -c exa -s 'g' -l 'group' -d "List each file's inode number"
|
||||
complete -c exa -s 'm' -l 'modified' -d "Use the modified timestamp field"
|
||||
complete -c exa -s 'S' -l 'blocks' -d "List each file's number of filesystem blocks"
|
||||
complete -c exa -s 't' -l 'time' -x -d "Which timestamp field to list" -a "
|
||||
modified\t'Display modified time'
|
||||
changed\t'Display changed time'
|
||||
accessed\t'Display accessed time'
|
||||
created\t'Display created time'
|
||||
modified\t'Display modified time'
|
||||
"
|
||||
complete -c exa -s 'm' -l 'modified' -d "Use the modified timestamp field"
|
||||
complete -c exa -l 'changed' -d "Use the changed timestamp field"
|
||||
complete -c exa -s 'u' -l 'accessed' -d "Use the accessed timestamp field"
|
||||
complete -c exa -s 'U' -l 'created' -d "Use the created timestamp field"
|
||||
complete -c exa -l 'time-style' -x -d "How to format timestamps" -a "
|
||||
|
@ -27,7 +27,7 @@ __exa() {
|
||||
{-d,--list-dirs}"[List directories like regular files]" \
|
||||
{-L,--level}"+[Limit the depth of recursion]" \
|
||||
{-r,--reverse}"[Reverse the sort order]" \
|
||||
{-s,--sort}="[Which field to sort by]:(sort field):(accessed age created date extension Extension filename Filename inode modified oldest name Name newest none size time type)" \
|
||||
{-s,--sort}="[Which field to sort by]:(sort field):(accessed age changed created date extension Extension filename Filename inode modified oldest name Name newest none size time type)" \
|
||||
{-I,--ignore-glob}"[Ignore files that match these glob patterns]" \
|
||||
{-b,--binary}"[List file sizes with binary prefixes]" \
|
||||
{-B,--bytes}"[List file sizes in bytes, without any prefixes]" \
|
||||
@ -37,7 +37,7 @@ __exa() {
|
||||
{-i,--inode}"[List each file's inode number]" \
|
||||
{-m,--modified}"[Use the modified timestamp field]" \
|
||||
{-S,--blocks}"[List each file's number of filesystem blocks]" \
|
||||
{-t,--time}="[Which time field to show]:(time field):(accessed created modified)" \
|
||||
{-t,--time}="[Which time field to show]:(time field):(accessed changed created modified)" \
|
||||
--time-style="[How to format timestamps]:(time style):(default iso long-iso full-iso)" \
|
||||
{-u,--accessed}"[Use the accessed timestamp field]" \
|
||||
{-U,--created}"[Use the created timestamp field]" \
|
||||
|
@ -1,5 +1,5 @@
|
||||
.hy
|
||||
.TH "exa" "1" "2017\-07\-07" "exa 0.7.0" ""
|
||||
.TH "exa" "1" "2018\-12\-17" "exa 0.9.0" ""
|
||||
.SH NAME
|
||||
.PP
|
||||
exa \- a modern replacement for ls
|
||||
@ -86,7 +86,7 @@ reverse the sort order
|
||||
.TP
|
||||
.B \-s, \-\-sort=\f[I]SORT_FIELD\f[]
|
||||
which field to sort by.
|
||||
Valid fields are name, Name, extension, Extension, size, modified, accessed, created, inode, type, and none.
|
||||
Valid fields are name, Name, extension, Extension, size, modified, changed, accessed, created, inode, type, and none.
|
||||
The modified field has the aliases date, time, and newest, and its reverse order has the aliases age and oldest.
|
||||
Fields starting with a capital letter will sort uppercase before lowercase: 'A' then 'B' then 'a' then 'b'.
|
||||
Fields starting with a lowercase letter will mix them: 'A' then 'a' then 'B' then 'b'.
|
||||
@ -158,7 +158,7 @@ list each file\[aq]s number of file system blocks
|
||||
.RE
|
||||
.TP
|
||||
.B \-t, \-\-time=\f[I]WORD\f[]
|
||||
which timestamp field to list (modified, accessed, created)
|
||||
which timestamp field to list (modified, changed, accessed, created)
|
||||
.RS
|
||||
.RE
|
||||
.TP
|
||||
|
@ -301,6 +301,11 @@ impl<'dir> File<'dir> {
|
||||
self.metadata.modified().unwrap().duration_since(UNIX_EPOCH).unwrap()
|
||||
}
|
||||
|
||||
/// This file’s last changed timestamp.
|
||||
pub fn changed_time(&self) -> Duration {
|
||||
Duration::new(self.metadata.ctime() as u64, self.metadata.ctime_nsec() as u32)
|
||||
}
|
||||
|
||||
/// This file’s last accessed timestamp.
|
||||
pub fn accessed_time(&self) -> Duration {
|
||||
self.metadata.accessed().unwrap().duration_since(UNIX_EPOCH).unwrap()
|
||||
|
@ -173,13 +173,16 @@ pub enum SortField {
|
||||
/// http://unix.stackexchange.com/a/8842
|
||||
AccessedDate,
|
||||
|
||||
/// The time the file was changed or created (the “ctime”).
|
||||
/// The time the file was changed (the “ctime”).
|
||||
///
|
||||
/// Contrary to the name, this field is used to mark the time when a
|
||||
/// file’s metadata changed -- its permissions, owners, or link count.
|
||||
/// This field is used to mark the time when a file’s metadata
|
||||
/// changed -- its permissions, owners, or link count.
|
||||
///
|
||||
/// In original Unix, this was, however, meant as creation time.
|
||||
/// https://www.bell-labs.com/usr/dmr/www/cacm.html
|
||||
ChangedDate,
|
||||
|
||||
/// The time the file was created (the "btime" or "birthtime").
|
||||
CreatedDate,
|
||||
|
||||
/// The type of the file: directories, links, pipes, regular, files, etc.
|
||||
@ -247,6 +250,7 @@ impl SortField {
|
||||
SortField::FileInode => a.metadata.ino().cmp(&b.metadata.ino()),
|
||||
SortField::ModifiedDate => a.modified_time().cmp(&b.modified_time()),
|
||||
SortField::AccessedDate => a.accessed_time().cmp(&b.accessed_time()),
|
||||
SortField::ChangedDate => a.changed_time().cmp(&b.changed_time()),
|
||||
SortField::CreatedDate => a.created_time().cmp(&b.created_time()),
|
||||
SortField::ModifiedAge => b.modified_time().cmp(&a.modified_time()), // flip b and a
|
||||
|
||||
|
@ -70,6 +70,9 @@ impl SortField {
|
||||
// age (the oldest) at the bottom.
|
||||
Ok(SortField::ModifiedAge)
|
||||
}
|
||||
else if word == "ch" || word == "changed" {
|
||||
Ok(SortField::ChangedDate)
|
||||
}
|
||||
else if word == "acc" || word == "accessed" {
|
||||
Ok(SortField::AccessedDate)
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ pub static GIT_IGNORE: Arg = Arg { short: None, long: "git-ignore", t
|
||||
pub static DIRS_FIRST: Arg = Arg { short: None, long: "group-directories-first", takes_value: TakesValue::Forbidden };
|
||||
pub static ONLY_DIRS: Arg = Arg { short: Some(b'D'), long: "only-dirs", takes_value: TakesValue::Forbidden };
|
||||
const SORTS: Values = &[ "name", "Name", "size", "extension",
|
||||
"Extension", "modified", "accessed",
|
||||
"Extension", "modified", "changed", "accessed",
|
||||
"created", "inode", "type", "none" ];
|
||||
|
||||
// display options
|
||||
@ -43,12 +43,13 @@ pub static HEADER: Arg = Arg { short: Some(b'h'), long: "header", takes_
|
||||
pub static INODE: Arg = Arg { short: Some(b'i'), long: "inode", takes_value: TakesValue::Forbidden };
|
||||
pub static LINKS: Arg = Arg { short: Some(b'H'), long: "links", takes_value: TakesValue::Forbidden };
|
||||
pub static MODIFIED: Arg = Arg { short: Some(b'm'), long: "modified", takes_value: TakesValue::Forbidden };
|
||||
pub static CHANGED: Arg = Arg { short: None, long: "changed", takes_value: TakesValue::Forbidden };
|
||||
pub static BLOCKS: Arg = Arg { short: Some(b'S'), long: "blocks", takes_value: TakesValue::Forbidden };
|
||||
pub static TIME: Arg = Arg { short: Some(b't'), long: "time", takes_value: TakesValue::Necessary(Some(TIMES)) };
|
||||
pub static ACCESSED: Arg = Arg { short: Some(b'u'), long: "accessed", takes_value: TakesValue::Forbidden };
|
||||
pub static CREATED: Arg = Arg { short: Some(b'U'), long: "created", takes_value: TakesValue::Forbidden };
|
||||
pub static TIME_STYLE: Arg = Arg { short: None, long: "time-style", takes_value: TakesValue::Necessary(Some(TIME_STYLES)) };
|
||||
const TIMES: Values = &["modified", "accessed", "created"];
|
||||
const TIMES: Values = &["modified", "changed", "accessed", "created"];
|
||||
const TIME_STYLES: Values = &["default", "long-iso", "full-iso", "iso"];
|
||||
|
||||
// optional feature options
|
||||
@ -65,9 +66,8 @@ pub static ALL_ARGS: Args = Args(&[
|
||||
&ALL, &LIST_DIRS, &LEVEL, &REVERSE, &SORT, &DIRS_FIRST,
|
||||
&IGNORE_GLOB, &GIT_IGNORE, &ONLY_DIRS,
|
||||
|
||||
&BINARY, &BYTES, &GROUP, &HEADER, &INODE, &LINKS, &MODIFIED, &BLOCKS,
|
||||
&TIME, &ACCESSED, &CREATED, &TIME_STYLE,
|
||||
&BINARY, &BYTES, &GROUP, &HEADER, &INODE, &LINKS, &MODIFIED, &CHANGED,
|
||||
&BLOCKS, &TIME, &ACCESSED, &CREATED, &TIME_STYLE,
|
||||
|
||||
&GIT, &EXTENDED,
|
||||
]);
|
||||
|
||||
|
@ -296,34 +296,41 @@ impl TimeTypes {
|
||||
fn deduce(matches: &MatchedFlags) -> Result<TimeTypes, Misfire> {
|
||||
let possible_word = matches.get(&flags::TIME)?;
|
||||
let modified = matches.has(&flags::MODIFIED)?;
|
||||
let created = matches.has(&flags::CREATED)?;
|
||||
let changed = matches.has(&flags::CHANGED)?;
|
||||
let accessed = matches.has(&flags::ACCESSED)?;
|
||||
let created = matches.has(&flags::CREATED)?;
|
||||
|
||||
if let Some(word) = possible_word {
|
||||
if modified {
|
||||
Err(Misfire::Useless(&flags::MODIFIED, true, &flags::TIME))
|
||||
}
|
||||
else if created {
|
||||
Err(Misfire::Useless(&flags::CREATED, true, &flags::TIME))
|
||||
else if changed {
|
||||
Err(Misfire::Useless(&flags::CHANGED, true, &flags::TIME))
|
||||
}
|
||||
else if accessed {
|
||||
Err(Misfire::Useless(&flags::ACCESSED, true, &flags::TIME))
|
||||
}
|
||||
else if created {
|
||||
Err(Misfire::Useless(&flags::CREATED, true, &flags::TIME))
|
||||
}
|
||||
else if word == "mod" || word == "modified" {
|
||||
Ok(TimeTypes { accessed: false, modified: true, created: false })
|
||||
Ok(TimeTypes { modified: true, changed: false, accessed: false, created: false })
|
||||
}
|
||||
else if word == "ch" || word == "changed" {
|
||||
Ok(TimeTypes { modified: false, changed: true, accessed: false, created: false })
|
||||
}
|
||||
else if word == "acc" || word == "accessed" {
|
||||
Ok(TimeTypes { accessed: true, modified: false, created: false })
|
||||
Ok(TimeTypes { modified: false, changed: false, accessed: true, created: false })
|
||||
}
|
||||
else if word == "cr" || word == "created" {
|
||||
Ok(TimeTypes { accessed: false, modified: false, created: true })
|
||||
Ok(TimeTypes { modified: false, changed: false, accessed: false, created: true })
|
||||
}
|
||||
else {
|
||||
Err(Misfire::BadArgument(&flags::TIME, word.into()))
|
||||
}
|
||||
}
|
||||
else if modified || created || accessed {
|
||||
Ok(TimeTypes { accessed, modified, created })
|
||||
else if modified || changed || accessed || created {
|
||||
Ok(TimeTypes { modified, changed, accessed, created })
|
||||
}
|
||||
else {
|
||||
Ok(TimeTypes::default())
|
||||
|
@ -79,6 +79,10 @@ impl Columns {
|
||||
columns.push(Column::Timestamp(TimeType::Modified));
|
||||
}
|
||||
|
||||
if self.time_types.changed {
|
||||
columns.push(Column::Timestamp(TimeType::Changed));
|
||||
}
|
||||
|
||||
if self.time_types.created {
|
||||
columns.push(Column::Timestamp(TimeType::Created));
|
||||
}
|
||||
@ -176,14 +180,16 @@ impl Default for SizeFormat {
|
||||
/// across most (all?) operating systems.
|
||||
#[derive(PartialEq, Debug, Copy, Clone)]
|
||||
pub enum TimeType {
|
||||
/// The file’s modified time (`st_mtime`).
|
||||
Modified,
|
||||
|
||||
/// The file’s changed time (`st_ctime`)
|
||||
Changed,
|
||||
|
||||
/// The file’s accessed time (`st_atime`).
|
||||
Accessed,
|
||||
|
||||
/// The file’s modified time (`st_mtime`).
|
||||
Modified,
|
||||
|
||||
/// The file’s creation time (`st_ctime`).
|
||||
/// The file’s creation time (`btime` or `birthtime`).
|
||||
Created,
|
||||
}
|
||||
|
||||
@ -192,8 +198,9 @@ impl TimeType {
|
||||
/// Returns the text to use for a column’s heading in the columns output.
|
||||
pub fn header(self) -> &'static str {
|
||||
match self {
|
||||
TimeType::Accessed => "Date Accessed",
|
||||
TimeType::Modified => "Date Modified",
|
||||
TimeType::Changed => "Date Changed",
|
||||
TimeType::Accessed => "Date Accessed",
|
||||
TimeType::Created => "Date Created",
|
||||
}
|
||||
}
|
||||
@ -207,8 +214,9 @@ impl TimeType {
|
||||
/// the time columns entirely (yet).
|
||||
#[derive(PartialEq, Debug, Copy, Clone)]
|
||||
pub struct TimeTypes {
|
||||
pub accessed: bool,
|
||||
pub modified: bool,
|
||||
pub changed: bool,
|
||||
pub accessed: bool,
|
||||
pub created: bool,
|
||||
}
|
||||
|
||||
@ -217,7 +225,7 @@ impl Default for TimeTypes {
|
||||
/// By default, display just the ‘modified’ time. This is the most
|
||||
/// common option, which is why it has this shorthand.
|
||||
fn default() -> TimeTypes {
|
||||
TimeTypes { accessed: false, modified: true, created: false }
|
||||
TimeTypes { modified: true, changed: false, accessed: false, created: false }
|
||||
}
|
||||
}
|
||||
|
||||
@ -343,6 +351,7 @@ impl<'a, 'f> Table<'a> {
|
||||
Column::GitStatus => self.git_status(file).render(self.colours),
|
||||
|
||||
Column::Timestamp(Modified) => file.modified_time().render(self.colours.date, &self.env.tz, &self.time_format),
|
||||
Column::Timestamp(Changed) => file.changed_time() .render(self.colours.date, &self.env.tz, &self.time_format),
|
||||
Column::Timestamp(Created) => file.created_time() .render(self.colours.date, &self.env.tz, &self.time_format),
|
||||
Column::Timestamp(Accessed) => file.accessed_time().render(self.colours.date, &self.env.tz, &self.time_format),
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user