mirror of
https://github.com/Llewellynvdm/exa.git
synced 2024-12-28 10:40:48 +00:00
Extract time formatter
This commit collects all the time-related fields from the Environment and bundles them all together in their own encapsulated struct.
This commit is contained in:
parent
fc60838ff3
commit
652e27e6dd
@ -8,6 +8,7 @@ pub mod file_name;
|
|||||||
pub mod grid_details;
|
pub mod grid_details;
|
||||||
pub mod grid;
|
pub mod grid;
|
||||||
pub mod lines;
|
pub mod lines;
|
||||||
|
pub mod time;
|
||||||
|
|
||||||
mod cell;
|
mod cell;
|
||||||
mod colours;
|
mod colours;
|
||||||
|
@ -1,45 +1,25 @@
|
|||||||
|
use datetime::TimeZone;
|
||||||
|
|
||||||
|
use fs::fields as f;
|
||||||
use output::cell::TextCell;
|
use output::cell::TextCell;
|
||||||
use output::colours::Colours;
|
use output::colours::Colours;
|
||||||
use fs::fields as f;
|
use output::time::TimeFormat;
|
||||||
|
|
||||||
use datetime::{LocalDateTime, TimeZone, DatePiece};
|
|
||||||
use datetime::fmt::DateFormat;
|
|
||||||
use locale;
|
|
||||||
|
|
||||||
|
|
||||||
#[allow(trivial_numeric_casts)]
|
#[allow(trivial_numeric_casts)]
|
||||||
impl f::Time {
|
impl f::Time {
|
||||||
pub fn render(&self, colours: &Colours, tz: &Option<TimeZone>,
|
pub fn render(&self, colours: &Colours,
|
||||||
date_and_time: &DateFormat<'static>, date_and_year: &DateFormat<'static>,
|
tz: &Option<TimeZone>,
|
||||||
time: &locale::Time, current_year: i64) -> TextCell {
|
style: &TimeFormat) -> TextCell {
|
||||||
|
|
||||||
// TODO(ogham): This method needs some serious de-duping!
|
|
||||||
// zoned and local times have different types at the moment,
|
|
||||||
// so it's tricky.
|
|
||||||
|
|
||||||
if let Some(ref tz) = *tz {
|
if let Some(ref tz) = *tz {
|
||||||
let date = tz.to_zoned(LocalDateTime::at(self.0 as i64));
|
let datestamp = style.format_zoned(self.0 as i64, tz);
|
||||||
|
|
||||||
let datestamp = if date.year() == current_year {
|
|
||||||
date_and_time.format(&date, time)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
date_and_year.format(&date, time)
|
|
||||||
};
|
|
||||||
|
|
||||||
TextCell::paint(colours.date, datestamp)
|
TextCell::paint(colours.date, datestamp)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
let date = LocalDateTime::at(self.0 as i64);
|
let datestamp = style.format_local(self.0 as i64);
|
||||||
|
|
||||||
let datestamp = if date.year() == current_year {
|
|
||||||
date_and_time.format(&date, time)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
date_and_year.format(&date, time)
|
|
||||||
};
|
|
||||||
|
|
||||||
TextCell::paint(colours.date, datestamp)
|
TextCell::paint(colours.date, datestamp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
use std::sync::{Mutex, MutexGuard};
|
use std::sync::{Mutex, MutexGuard};
|
||||||
|
|
||||||
use datetime::fmt::DateFormat;
|
|
||||||
use datetime::{LocalDateTime, DatePiece};
|
|
||||||
use datetime::TimeZone;
|
use datetime::TimeZone;
|
||||||
use zoneinfo_compiled::{CompiledData, Result as TZResult};
|
use zoneinfo_compiled::{CompiledData, Result as TZResult};
|
||||||
|
|
||||||
@ -13,6 +11,7 @@ use users::UsersCache;
|
|||||||
use output::cell::TextCell;
|
use output::cell::TextCell;
|
||||||
use output::colours::Colours;
|
use output::colours::Colours;
|
||||||
use output::column::{Alignment, Column};
|
use output::column::{Alignment, Column};
|
||||||
|
use output::time::TimeFormat;
|
||||||
|
|
||||||
use fs::{File, fields as f};
|
use fs::{File, fields as f};
|
||||||
|
|
||||||
@ -23,21 +22,11 @@ use fs::{File, fields as f};
|
|||||||
/// Any environment field should be able to be mocked up for test runs.
|
/// Any environment field should be able to be mocked up for test runs.
|
||||||
pub struct Environment {
|
pub struct Environment {
|
||||||
|
|
||||||
/// The year of the current time. This gets used to determine which date
|
|
||||||
/// format to use.
|
|
||||||
current_year: i64,
|
|
||||||
|
|
||||||
/// Localisation rules for formatting numbers.
|
/// Localisation rules for formatting numbers.
|
||||||
numeric: locale::Numeric,
|
numeric: locale::Numeric,
|
||||||
|
|
||||||
/// Localisation rules for formatting timestamps.
|
/// Rules for formatting timestamps.
|
||||||
time: locale::Time,
|
time_format: TimeFormat,
|
||||||
|
|
||||||
/// Date format for printing out timestamps that are in the current year.
|
|
||||||
date_and_time: DateFormat<'static>,
|
|
||||||
|
|
||||||
/// Date format for printing out timestamps that *aren’t*.
|
|
||||||
date_and_year: DateFormat<'static>,
|
|
||||||
|
|
||||||
/// The computer's current time zone. This gets used to determine how to
|
/// The computer's current time zone. This gets used to determine how to
|
||||||
/// offset files' timestamps.
|
/// offset files' timestamps.
|
||||||
@ -55,43 +44,22 @@ impl Environment {
|
|||||||
|
|
||||||
impl Default for Environment {
|
impl Default for Environment {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
use unicode_width::UnicodeWidthStr;
|
let tz = match determine_time_zone() {
|
||||||
|
Ok(t) => Some(t),
|
||||||
|
Err(ref e) => {
|
||||||
|
println!("Unable to determine time zone: {}", e);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let tz = determine_time_zone();
|
let time_format = TimeFormat::deduce();
|
||||||
if let Err(ref e) = tz {
|
|
||||||
println!("Unable to determine time zone: {}", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
let numeric = locale::Numeric::load_user_locale()
|
let numeric = locale::Numeric::load_user_locale()
|
||||||
.unwrap_or_else(|_| locale::Numeric::english());
|
.unwrap_or_else(|_| locale::Numeric::english());
|
||||||
|
|
||||||
let time = locale::Time::load_user_locale()
|
let users = Mutex::new(UsersCache::new());
|
||||||
.unwrap_or_else(|_| locale::Time::english());
|
|
||||||
|
|
||||||
// Some locales use a three-character wide month name (Jan to Dec);
|
Environment { tz, time_format, numeric, users }
|
||||||
// others vary between three and four (1月 to 12月). We assume that
|
|
||||||
// December is the month with the maximum width, and use the width of
|
|
||||||
// that to determine how to pad the other months.
|
|
||||||
let december_width = UnicodeWidthStr::width(&*time.short_month_name(11));
|
|
||||||
let date_and_time = match december_width {
|
|
||||||
4 => DateFormat::parse("{2>:D} {4>:M} {2>:h}:{02>:m}").unwrap(),
|
|
||||||
_ => DateFormat::parse("{2>:D} {:M} {2>:h}:{02>:m}").unwrap(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let date_and_year = match december_width {
|
|
||||||
4 => DateFormat::parse("{2>:D} {4>:M} {5>:Y}").unwrap(),
|
|
||||||
_ => DateFormat::parse("{2>:D} {:M} {5>:Y}").unwrap()
|
|
||||||
};
|
|
||||||
|
|
||||||
Environment {
|
|
||||||
current_year: LocalDateTime::now().year(),
|
|
||||||
numeric: numeric,
|
|
||||||
date_and_time: date_and_time,
|
|
||||||
date_and_year: date_and_year,
|
|
||||||
time: time,
|
|
||||||
tz: tz.ok(),
|
|
||||||
users: Mutex::new(UsersCache::new()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,17 +139,18 @@ impl<'a, 'f> Table<'a> {
|
|||||||
use output::column::TimeType::*;
|
use output::column::TimeType::*;
|
||||||
|
|
||||||
match *column {
|
match *column {
|
||||||
Column::Permissions => self.permissions_plus(file, xattrs).render(&self.colours),
|
Column::Permissions => self.permissions_plus(file, xattrs).render(&self.colours),
|
||||||
Column::FileSize(fmt) => file.size().render(&self.colours, fmt, &self.env.numeric),
|
Column::FileSize(fmt) => file.size().render(&self.colours, fmt, &self.env.numeric),
|
||||||
Column::Timestamp(Modified) => file.modified_time().render(&self.colours, &self.env.tz, &self.env.date_and_time, &self.env.date_and_year, &self.env.time, self.env.current_year),
|
Column::HardLinks => file.links().render(&self.colours, &self.env.numeric),
|
||||||
Column::Timestamp(Created) => file.created_time().render( &self.colours, &self.env.tz, &self.env.date_and_time, &self.env.date_and_year, &self.env.time, self.env.current_year),
|
Column::Inode => file.inode().render(&self.colours),
|
||||||
Column::Timestamp(Accessed) => file.accessed_time().render(&self.colours, &self.env.tz, &self.env.date_and_time, &self.env.date_and_year, &self.env.time, self.env.current_year),
|
Column::Blocks => file.blocks().render(&self.colours),
|
||||||
Column::HardLinks => file.links().render(&self.colours, &self.env.numeric),
|
Column::User => file.user().render(&self.colours, &*self.env.lock_users()),
|
||||||
Column::Inode => file.inode().render(&self.colours),
|
Column::Group => file.group().render(&self.colours, &*self.env.lock_users()),
|
||||||
Column::Blocks => file.blocks().render(&self.colours),
|
Column::GitStatus => file.git_status().render(&self.colours),
|
||||||
Column::User => file.user().render(&self.colours, &*self.env.lock_users()),
|
|
||||||
Column::Group => file.group().render(&self.colours, &*self.env.lock_users()),
|
Column::Timestamp(Modified) => file.modified_time().render(&self.colours, &self.env.tz, &self.env.time_format),
|
||||||
Column::GitStatus => file.git_status().render(&self.colours),
|
Column::Timestamp(Created) => file.created_time().render( &self.colours, &self.env.tz, &self.env.time_format),
|
||||||
|
Column::Timestamp(Accessed) => file.accessed_time().render(&self.colours, &self.env.tz, &self.env.time_format),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
79
src/output/time.rs
Normal file
79
src/output/time.rs
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
use datetime::{LocalDateTime, TimeZone, DatePiece};
|
||||||
|
use datetime::fmt::DateFormat;
|
||||||
|
use locale;
|
||||||
|
|
||||||
|
use fs::fields::time_t;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct TimeFormat {
|
||||||
|
|
||||||
|
/// The year of the current time. This gets used to determine which date
|
||||||
|
/// format to use.
|
||||||
|
pub current_year: i64,
|
||||||
|
|
||||||
|
/// Localisation rules for formatting timestamps.
|
||||||
|
pub locale: locale::Time,
|
||||||
|
|
||||||
|
/// Date format for printing out timestamps that are in the current year.
|
||||||
|
pub date_and_time: DateFormat<'static>,
|
||||||
|
|
||||||
|
/// Date format for printing out timestamps that *aren’t*.
|
||||||
|
pub date_and_year: DateFormat<'static>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TimeFormat {
|
||||||
|
fn is_recent(&self, date: LocalDateTime) -> bool {
|
||||||
|
date.year() == self.current_year
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(trivial_numeric_casts)]
|
||||||
|
pub fn format_local(&self, time: time_t) -> String {
|
||||||
|
let date = LocalDateTime::at(time as i64);
|
||||||
|
|
||||||
|
if self.is_recent(date) {
|
||||||
|
self.date_and_time.format(&date, &self.locale)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
self.date_and_year.format(&date, &self.locale)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(trivial_numeric_casts)]
|
||||||
|
pub fn format_zoned(&self, time: time_t, zone: &TimeZone) -> String {
|
||||||
|
let date = zone.to_zoned(LocalDateTime::at(time as i64));
|
||||||
|
|
||||||
|
if self.is_recent(date) {
|
||||||
|
self.date_and_time.format(&date, &self.locale)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
self.date_and_year.format(&date, &self.locale)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deduce() -> TimeFormat {
|
||||||
|
use unicode_width::UnicodeWidthStr;
|
||||||
|
|
||||||
|
let locale = locale::Time::load_user_locale()
|
||||||
|
.unwrap_or_else(|_| locale::Time::english());
|
||||||
|
|
||||||
|
let current_year = LocalDateTime::now().year();
|
||||||
|
|
||||||
|
// Some locales use a three-character wide month name (Jan to Dec);
|
||||||
|
// others vary between three and four (1月 to 12月). We assume that
|
||||||
|
// December is the month with the maximum width, and use the width of
|
||||||
|
// that to determine how to pad the other months.
|
||||||
|
let december_width = UnicodeWidthStr::width(&*locale.short_month_name(11));
|
||||||
|
let date_and_time = match december_width {
|
||||||
|
4 => DateFormat::parse("{2>:D} {4>:M} {2>:h}:{02>:m}").unwrap(),
|
||||||
|
_ => DateFormat::parse("{2>:D} {:M} {2>:h}:{02>:m}").unwrap(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let date_and_year = match december_width {
|
||||||
|
4 => DateFormat::parse("{2>:D} {4>:M} {5>:Y}").unwrap(),
|
||||||
|
_ => DateFormat::parse("{2>:D} {:M} {5>:Y}").unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
TimeFormat { current_year, locale, date_and_time, date_and_year }
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user