Переглянути джерело

Extract time formatter

This commit collects all the time-related fields from the Environment and bundles them all together in their own encapsulated struct.
Benjamin Sago 8 роки тому
батько
коміт
652e27e6dd
4 змінених файлів з 115 додано та 86 видалено
  1. 1 0
      src/output/mod.rs
  2. 10 30
      src/output/render/times.rs
  3. 25 56
      src/output/table.rs
  4. 79 0
      src/output/time.rs

+ 1 - 0
src/output/mod.rs

@@ -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;

+ 10 - 30
src/output/render/times.rs

@@ -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 datetime::{LocalDateTime, TimeZone, DatePiece};
-use datetime::fmt::DateFormat;
-use locale;
+use output::time::TimeFormat;
 
 
 
 
 #[allow(trivial_numeric_casts)]
 #[allow(trivial_numeric_casts)]
 impl f::Time {
 impl f::Time {
-    pub fn render(&self, colours: &Colours, tz: &Option<TimeZone>,
-                          date_and_time: &DateFormat<'static>, date_and_year: &DateFormat<'static>,
-                          time: &locale::Time, current_year: i64) -> TextCell {
-
-        // TODO(ogham): This method needs some serious de-duping!
-        // zoned and local times have different types at the moment,
-        // so it's tricky.
+    pub fn render(&self, colours: &Colours,
+                         tz: &Option<TimeZone>,
+                         style: &TimeFormat) -> TextCell {
 
 
         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 = if date.year() == current_year {
-                date_and_time.format(&date, time)
-            }
-            else {
-                date_and_year.format(&date, time)
-            };
-
+            let datestamp = style.format_zoned(self.0 as i64, tz);
             TextCell::paint(colours.date, datestamp)
             TextCell::paint(colours.date, datestamp)
         }
         }
         else {
         else {
-            let date = LocalDateTime::at(self.0 as i64);
-
-            let datestamp = if date.year() == current_year {
-                date_and_time.format(&date, time)
-            }
-            else {
-                date_and_year.format(&date, time)
-            };
-
+            let datestamp = style.format_local(self.0 as i64);
             TextCell::paint(colours.date, datestamp)
             TextCell::paint(colours.date, datestamp)
         }
         }
     }
     }
 }
 }
+

+ 25 - 56
src/output/table.rs

@@ -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.
-    time: locale::Time,
-
-    /// 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>,
+    /// Rules for formatting timestamps.
+    time_format: TimeFormat,
 
 
     /// 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();
-        if let Err(ref e) = tz {
-            println!("Unable to determine time zone: {}", e);
-        }
+        let time_format = TimeFormat::deduce();
 
 
         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()
-                       .unwrap_or_else(|_| locale::Time::english());
-
-        // 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(&*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 users = Mutex::new(UsersCache::new());
 
 
-        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()),
-        }
+        Environment { tz, time_format, numeric, users }
     }
     }
 }
 }
 
 
@@ -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::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::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::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::HardLinks            => file.links().render(&self.colours, &self.env.numeric),
-            Column::Inode                => file.inode().render(&self.colours),
-            Column::Blocks               => file.blocks().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::GitStatus            => file.git_status().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::HardLinks      => file.links().render(&self.colours, &self.env.numeric),
+            Column::Inode          => file.inode().render(&self.colours),
+            Column::Blocks         => file.blocks().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::GitStatus      => file.git_status().render(&self.colours),
+
+            Column::Timestamp(Modified)  => file.modified_time().render(&self.colours, &self.env.tz, &self.env.time_format),
+            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 - 0
src/output/time.rs

@@ -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 }
+    }
+}