1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
extern crate chrono;
extern crate clap;
extern crate colonnade;
extern crate two_timer;

use crate::configure::Configuration;
use crate::util::{fatal, remainder, some_nws, Style};
use clap::{App, Arg, ArgMatches, SubCommand};
use colonnade::Colonnade;
use two_timer::parse;

fn after_help() -> &'static str {
    "\
Natural language time expressions are easy to produce, but it isn't always obvious \
what fully-specified times they correspond to. Sometimes you may want to know this before \
you give one to Job Log. Perhaps you summarize the log for a particular period and the \
results don't look right. Perhaps you are about to make a change that involves a timestamp \
and you want to make sure you'll get the change you want. This is what parse-time is for. \
Give it a string and see what you get.

The parse-time subcommand returns the first moment inclusive of the time expression, the \
last moment exclusive and whether the expression explicitly name both the beginning and \
the end of the range.

Job log uses two grammars to parse time expressions: a simple grammar which it tries first \
and a more comprehensive grammar, which it falls back to. Here are some useful expressions \
which are available in the simple grammar:

  yesterday
  today
  now
  pay period
  pp
  Friday
  fri
  this week
  last week
  last month
  March
  March 20
  2016
  feb - mar

Both grammars are from https://github.com/dfhoughton/two-timer. You can find list of sample \
expressions at this URL and, in the source code, the actual grammars.

All prefixes of 'parse-time' are aliases of the subcommand.
"
}

pub fn cli(mast: App<'static, 'static>, display_order: usize) -> App<'static, 'static> {
    mast.subcommand(
        SubCommand::with_name("parse-time")
            .aliases(&[
                "p",
                "pa",
                "par",
                "pars",
                "parse",
                "parse-",
                "parse-t",
                "parse-ti",
                "parse-tim",
            ])
            .about("Shows the start and end timestamps you get from a particular time expression")
            .after_help(after_help())
            .arg(
                Arg::with_name("period")
                    .help("time expression")
                    .long_help("A time expression. E.g., 'last week' or '2016-10-2'.")
                    .value_name("word")
                    .multiple(true),
            )
            .display_order(display_order),
    )
}

pub fn run(directory: Option<&str>, matches: &ArgMatches) {
    let conf = Configuration::read(None, directory);
    if !matches.is_present("period") {
        fatal("no time expression provided", &conf);
    }
    let phrase = remainder("period", matches);
    if some_nws(&phrase) {
        match parse(&phrase.trim(), conf.two_timer_config()) {
            Ok((start, end, range)) => {
                let color = Style::new(&conf);
                let data = [
                    [String::from("start"), format!("{}", start)],
                    [String::from("end"), format!("{}", end)],
                    [String::from("explicit end"), format!("{}", range)],
                ];
                let mut table = Colonnade::new(2, conf.width()).unwrap();
                println!();
                for row in table.macerate(&data).unwrap() {
                    for line in row {
                        for (cell_num, (margin, contents)) in line.iter().enumerate() {
                            if cell_num == 0 {
                                print!("{}{}", margin, color.green(contents));
                            } else {
                                print!("{}{}", margin, contents);
                            }
                        }
                    }
                    println!();
                }
                println!();
            }
            Err(e) => fatal(e.msg(), &conf),
        }
    } else {
        fatal("no time expression provided", &conf);
    }
}