Skip to content

Commit

Permalink
Date format supports recent/non-recent format
Browse files Browse the repository at this point in the history
  • Loading branch information
manno committed Dec 22, 2021
1 parent 0a3a6f1 commit 0f9d4f5
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 40 deletions.
90 changes: 51 additions & 39 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,51 +290,63 @@ fn validate_date_argument(arg: String) -> Result<(), String> {
}

pub fn validate_time_format(formatter: &str) -> Result<(), String> {
let mut chars = formatter.chars();
loop {
match chars.next() {
Some('%') => match chars.next() {
Some('.') => match chars.next() {
Some('f') => (),
let str = formatter.to_string();
let vec: Vec<&str> = str.split('\n').collect();

if vec.len() > 2 {
return Err("invalid format, can only contain one newline separator".to_owned());
}

for s in vec {
let mut chars = s.chars();

loop {
match chars.next() {
Some('%') => match chars.next() {
Some('.') => match chars.next() {
Some('f') => (),
Some(n @ '3') | Some(n @ '6') | Some(n @ '9') => match chars.next() {
Some('f') => (),
Some(c) => {
return Err(format!("invalid format specifier: %.{}{}", n, c))
}
None => return Err("missing format specifier".to_owned()),
},
Some(c) => return Err(format!("invalid format specifier: %.{}", c)),
None => return Err("missing format specifier".to_owned()),
},
Some(n @ ':') | Some(n @ '#') => match chars.next() {
Some('z') => (),
Some(c) => return Err(format!("invalid format specifier: %{}{}", n, c)),
None => return Err("missing format specifier".to_owned()),
},
Some(n @ '-') | Some(n @ '_') | Some(n @ '0') => match chars.next() {
Some('C') | Some('d') | Some('e') | Some('f') | Some('G') | Some('g')
| Some('H') | Some('I') | Some('j') | Some('k') | Some('l') | Some('M')
| Some('m') | Some('S') | Some('s') | Some('U') | Some('u') | Some('V')
| Some('W') | Some('w') | Some('Y') | Some('y') => (),
Some(c) => return Err(format!("invalid format specifier: %{}{}", n, c)),
None => return Err("missing format specifier".to_owned()),
},
Some('A') | Some('a') | Some('B') | Some('b') | Some('C') | Some('c')
| Some('D') | Some('d') | Some('e') | Some('F') | Some('f') | Some('G')
| Some('g') | Some('H') | Some('h') | Some('I') | Some('j') | Some('k')
| Some('l') | Some('M') | Some('m') | Some('n') | Some('P') | Some('p')
| Some('R') | Some('r') | Some('S') | Some('s') | Some('T') | Some('t')
| Some('U') | Some('u') | Some('V') | Some('v') | Some('W') | Some('w')
| Some('X') | Some('x') | Some('Y') | Some('y') | Some('Z') | Some('z')
| Some('+') | Some('%') => (),
Some(n @ '3') | Some(n @ '6') | Some(n @ '9') => match chars.next() {
Some('f') => (),
Some(c) => return Err(format!("invalid format specifier: %.{}{}", n, c)),
Some(c) => return Err(format!("invalid format specifier: %{}{}", n, c)),
None => return Err("missing format specifier".to_owned()),
},
Some(c) => return Err(format!("invalid format specifier: %.{}", c)),
None => return Err("missing format specifier".to_owned()),
},
Some(n @ ':') | Some(n @ '#') => match chars.next() {
Some('z') => (),
Some(c) => return Err(format!("invalid format specifier: %{}{}", n, c)),
None => return Err("missing format specifier".to_owned()),
},
Some(n @ '-') | Some(n @ '_') | Some(n @ '0') => match chars.next() {
Some('C') | Some('d') | Some('e') | Some('f') | Some('G') | Some('g')
| Some('H') | Some('I') | Some('j') | Some('k') | Some('l') | Some('M')
| Some('m') | Some('S') | Some('s') | Some('U') | Some('u') | Some('V')
| Some('W') | Some('w') | Some('Y') | Some('y') => (),
Some(c) => return Err(format!("invalid format specifier: %{}{}", n, c)),
None => return Err("missing format specifier".to_owned()),
},
Some('A') | Some('a') | Some('B') | Some('b') | Some('C') | Some('c')
| Some('D') | Some('d') | Some('e') | Some('F') | Some('f') | Some('G')
| Some('g') | Some('H') | Some('h') | Some('I') | Some('j') | Some('k')
| Some('l') | Some('M') | Some('m') | Some('n') | Some('P') | Some('p')
| Some('R') | Some('r') | Some('S') | Some('s') | Some('T') | Some('t')
| Some('U') | Some('u') | Some('V') | Some('v') | Some('W') | Some('w')
| Some('X') | Some('x') | Some('Y') | Some('y') | Some('Z') | Some('z')
| Some('+') | Some('%') => (),
Some(n @ '3') | Some(n @ '6') | Some(n @ '9') => match chars.next() {
Some('f') => (),
Some(c) => return Err(format!("invalid format specifier: %{}{}", n, c)),
Some(c) => return Err(format!("invalid format specifier: %{}", c)),
None => return Err("missing format specifier".to_owned()),
},
Some(c) => return Err(format!("invalid format specifier: %{}", c)),
None => return Err("missing format specifier".to_owned()),
},
None => break,
_ => continue,
None => break,
_ => continue,
}
}
}
Ok(())
Expand Down
68 changes: 67 additions & 1 deletion src/meta/date.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,17 @@ impl Date {
val.format("%F").to_string()
}
}
DateFlag::Formatted(format) => val.format(format).to_string(),
DateFlag::Formatted(format) => {
let vec: Vec<&str> = format.split('\n').collect();

if vec.len() == 1 || *val > Local::now() - Duration::seconds(15_778_476) {
// non-recent or only one format
val.format(vec[0]).to_string()
} else {
// recent
val.format(vec[1]).to_string()
}
}
}
} else {
String::from("-")
Expand Down Expand Up @@ -308,6 +318,62 @@ mod test {
fs::remove_file(file_path).unwrap();
}

#[test]
fn test_recent_format_now() {
let mut file_path = env::temp_dir();
file_path.push("test_recent_format_now.tmp");

let creation_date = Local::now();
let success = cross_platform_touch(&file_path, &creation_date)
.unwrap()
.success();
assert_eq!(true, success, "failed to exec touch");

let colors = Colors::new(ThemeOption::Default);
let date = Date::from(&file_path.metadata().unwrap());

let mut flags = Flags::default();
flags.date = DateFlag::Formatted(String::from("%F\n%H:%M"));

assert_eq!(
creation_date
.format("%F")
.to_string()
.with(Color::AnsiValue(40)),
date.render(&colors, &flags)
);

fs::remove_file(file_path).unwrap();
}

#[test]
fn test_recent_format_year_old() {
let mut file_path = env::temp_dir();
file_path.push("test_recent_format_year_old.tmp");

let creation_date = Local::now() - Duration::days(400);
let success = cross_platform_touch(&file_path, &creation_date)
.unwrap()
.success();
assert_eq!(true, success, "failed to exec touch");

let colors = Colors::new(ThemeOption::Default);
let date = Date::from(&file_path.metadata().unwrap());

let mut flags = Flags::default();
flags.date = DateFlag::Formatted(String::from("%F\n%H:%M"));

assert_eq!(
creation_date
.format("%H:%M")
.to_string()
.with(Color::AnsiValue(36)),
date.render(&colors, &flags)
);

fs::remove_file(file_path).unwrap();
}

#[test]
#[cfg(all(not(windows), target_arch = "x86_64"))]
fn test_bad_date() {
Expand Down

0 comments on commit 0f9d4f5

Please sign in to comment.