Make getFilter(cli) a method of CLI

This commit is contained in:
Thomas Lauf 2020-05-08 17:08:02 +02:00
parent 547bda5ef8
commit 9ae3ace109
16 changed files with 204 additions and 201 deletions

View file

@ -35,6 +35,7 @@
#include <algorithm>
#include <set>
#include <Duration.h>
#include <timew.h>
////////////////////////////////////////////////////////////////////////////////
A2::A2 (const std::string& raw, Lexer::Type lextype)
@ -622,3 +623,190 @@ std::vector <std::string> CLI::getDomReferences () const
return references;
}
////////////////////////////////////////////////////////////////////////////////
// A filter is just another interval, containing start, end and tags.
//
// Supported interval forms:
// ["from"] <date> ["to"|"-" <date>]
// ["from"] <date> "for" <duration>
// <duration> ["before"|"after" <date>]
// <duration> "ago"
//
Interval CLI::getFilter () const
{
// One instance, so we can directly compare.
Datetime now;
Interval filter;
std::string start;
std::string end;
std::string duration;
std::vector <std::string> args;
for (auto& arg : _args)
{
if (arg.hasTag ("BINARY") ||
arg.hasTag ("CMD") ||
arg.hasTag ("EXT"))
continue;
if (arg.hasTag ("FILTER"))
{
auto canonical = arg.attribute ("canonical");
auto raw = arg.attribute ("raw");
if (arg.hasTag ("HINT"))
{
Range range;
if (expandIntervalHint (canonical, range))
{
start = range.start.toISO ();
end = range.end.toISO ();
args.push_back ("<date>");
args.push_back ("-");
args.push_back ("<date>");
}
// Hints that are not expandable to a date range are ignored.
}
else if (arg._lextype == Lexer::Type::date)
{
if (start.empty ())
start = raw;
else if (end.empty ())
end = raw;
args.push_back ("<date>");
}
else if (arg._lextype == Lexer::Type::duration)
{
if (duration.empty ())
duration = raw;
args.push_back ("<duration>");
}
else if (arg.hasTag ("KEYWORD"))
{
// Note: that KEYWORDS are not entities (why not?) and there is a list
// in CLI.cpp of them that must be maintained and synced with this
// function.
args.push_back (raw);
}
else if (arg.hasTag ("ID"))
{
// Not part of a filter.
}
else
{
filter.tag (raw);
}
}
}
// <date>
if (args.size () == 1 &&
args[0] == "<date>")
{
filter.setRange ({Datetime (start), 0});
}
// from <date>
else if (args.size () == 2 &&
args[0] == "from" &&
args[1] == "<date>")
{
filter.setRange ({Datetime (start), 0});
}
// <date> to/- <date>
else if (args.size () == 3 &&
args[0] == "<date>" &&
(args[1] == "to" || args[1] == "-") &&
args[2] == "<date>")
{
filter.setRange ({Datetime (start), Datetime (end)});
}
// from <date> to/- <date>
else if (args.size () == 4 &&
args[0] == "from" &&
args[1] == "<date>" &&
(args[2] == "to" || args[2] == "-") &&
args[3] == "<date>")
{
filter.setRange ({Datetime (start), Datetime (end)});
}
// <date> for <duration>
else if (args.size () == 3 &&
args[0] == "<date>" &&
args[1] == "for" &&
args[2] == "<duration>")
{
filter.setRange ({Datetime (start), Datetime (start) + Duration (duration).toTime_t ()});
}
// from <date> for <duration>
else if (args.size () == 4 &&
args[0] == "from" &&
args[1] == "<date>" &&
args[2] == "for" &&
args[3] == "<duration>")
{
filter.setRange ({Datetime (start), Datetime (start) + Duration (duration).toTime_t ()});
}
// <duration> before <date>
else if (args.size () == 3 &&
args[0] == "<duration>" &&
args[1] == "before" &&
args[2] == "<date>")
{
filter.setRange ({Datetime (start) - Duration (duration).toTime_t (), Datetime (start)});
}
// <duration> after <date>
else if (args.size () == 3 &&
args[0] == "<duration>" &&
args[1] == "after" &&
args[2] == "<date>")
{
filter.setRange ({Datetime (start), Datetime (start) + Duration (duration).toTime_t ()});
}
// <duration> ago
else if (args.size () == 2 &&
args[0] == "<duration>" &&
args[1] == "ago")
{
filter.setRange ({now - Duration (duration).toTime_t (), 0});
}
// for <duration>
else if (args.size () == 2 &&
args[0] == "for" &&
args[1] == "<duration>")
{
filter.setRange ({now - Duration (duration).toTime_t (), now});
}
// <duration>
else if (args.size () == 1 &&
args[0] == "<duration>")
{
filter.setRange ({now - Duration (duration).toTime_t (), now});
}
// Unrecognized date range construct.
else if (! args.empty ())
{
throw std::string ("Unrecognized date range: '") + join (" ", args) + "'.";
}
if (filter.end != 0 && filter.start > filter.end)
throw std::string ("The end of a date range must be after the start.");
return filter;
}

View file

@ -33,6 +33,7 @@
#include <vector>
#include <map>
#include <Duration.h>
#include "Interval.h"
// Represents a single argument.
class A2
@ -71,6 +72,7 @@ public:
std::string getAnnotation() const;
Duration getDuration() const;
std::vector<std::string> getDomReferences () const;
Interval getFilter () const;
std::string dump (const std::string& title = "CLI Parser") const;
private:

View file

@ -46,7 +46,7 @@ int CmdChartDay (
Database& database)
{
// Create a filter, and if empty, choose the current day.
auto filter = getFilter (cli);
auto filter = cli.getFilter ();
if (! filter.is_started ())
{
@ -63,7 +63,7 @@ int CmdChartWeek (
Database& database)
{
// Create a filter, and if empty, choose the current week.
auto filter = getFilter (cli);
auto filter = cli.getFilter ();
if (! filter.is_started ())
{
@ -80,7 +80,7 @@ int CmdChartMonth (
Database& database)
{
// Create a filter, and if empty, choose the current month.
auto filter = getFilter (cli);
auto filter = cli.getFilter ();
if (! filter.is_started ())
{

View file

@ -81,7 +81,7 @@ int CmdContinue (
to_copy = latest;
}
auto filter = getFilter (cli);
auto filter = cli.getFilter ();
Datetime start_time;
Datetime end_time;

View file

@ -34,7 +34,7 @@ int CmdExport (
Rules& rules,
Database& database)
{
auto filter = getFilter (cli);
auto filter = cli.getFilter ();
std::cout << jsonFromIntervals (getTracked (database, rules, filter));
return 0;
}

View file

@ -40,7 +40,7 @@ int CmdGaps (
auto verbose = rules.getBoolean ("verbose");
// If filter is empty, choose 'today'.
auto filter = getFilter (cli);
auto filter = cli.getFilter ();
if (! filter.is_started ())
{
if (rules.has ("reports.gaps.range"))

View file

@ -39,7 +39,7 @@ int CmdModify (
{
bool verbose = rules.getBoolean ("verbose");
auto filter = getFilter (cli);
auto filter = cli.getFilter ();
std::set <int> ids = cli.getIds ();
std::vector <std::string> words = cli.getWords ();
enum { MODIFY_START, MODIFY_END } op = MODIFY_START;

View file

@ -90,7 +90,7 @@ int CmdReport (
throw std::string ("Specify which report to run.");
// Compose Header info.
auto filter = getFilter (cli);
auto filter = cli.getFilter ();
auto tracked = getTracked (database, rules, filter);
rules.set ("temp.report.start", filter.start.toEpoch () > 0 ? filter.start.toISO () : "");

View file

@ -37,7 +37,7 @@ int CmdStart (
{
auto verbose = rules.getBoolean ("verbose");
auto filter = getFilter (cli);
auto filter = cli.getFilter ();
auto now = Datetime ();

View file

@ -50,7 +50,7 @@ int CmdStop (
auto verbose = rules.getBoolean ("verbose");
// Load the most recent interval.
auto filter = getFilter (cli);
auto filter = cli.getFilter ();
auto latest = getLatestInterval (database);
std::set <int> ids = cli.getIds ();

View file

@ -45,7 +45,7 @@ int CmdSummary (
auto verbose = rules.getBoolean ("verbose");
// Create a filter, and if empty, choose 'today'.
auto filter = getFilter (cli);
auto filter = cli.getFilter ();
if (! filter.is_started ())
filter.setRange (Datetime ("today"), Datetime ("tomorrow"));

View file

@ -41,7 +41,7 @@ int CmdTags (
auto verbose = rules.getBoolean ("verbose");
// Create a filter, with no default range.
auto filter = getFilter (cli);
auto filter = cli.getFilter ();
// Generate a unique, ordered list of tags.
std::set <std::string> tags;

View file

@ -37,7 +37,7 @@ int CmdTrack (
{
auto boolean = rules.getBoolean ("verbose");
auto filter = getFilter (cli);
auto filter = cli.getFilter ();
// If this is not a proper closed interval, then the user is trying to make
// the 'track' command behave like 'start', so delegate to CmdStart.

View file

@ -37,192 +37,6 @@
#include <iostream>
#include <IntervalFactory.h>
////////////////////////////////////////////////////////////////////////////////
// A filter is just another interval, containing start, end and tags.
//
// Supported interval forms:
// ["from"] <date> ["to"|"-" <date>]
// ["from"] <date> "for" <duration>
// <duration> ["before"|"after" <date>]
// <duration> "ago"
//
Interval getFilter (const CLI& cli)
{
// One instance, so we can directly compare.
Datetime now;
Interval filter;
std::string start;
std::string end;
std::string duration;
std::vector <std::string> args;
for (auto& arg : cli._args)
{
if (arg.hasTag ("BINARY") ||
arg.hasTag ("CMD") ||
arg.hasTag ("EXT"))
continue;
if (arg.hasTag ("FILTER"))
{
auto canonical = arg.attribute ("canonical");
auto raw = arg.attribute ("raw");
if (arg.hasTag ("HINT"))
{
Range range;
if (expandIntervalHint (canonical, range))
{
start = range.start.toISO ();
end = range.end.toISO ();
args.push_back ("<date>");
args.push_back ("-");
args.push_back ("<date>");
}
// Hints that are not expandable to a date range are ignored.
}
else if (arg._lextype == Lexer::Type::date)
{
if (start.empty ())
start = raw;
else if (end.empty ())
end = raw;
args.push_back ("<date>");
}
else if (arg._lextype == Lexer::Type::duration)
{
if (duration.empty ())
duration = raw;
args.push_back ("<duration>");
}
else if (arg.hasTag ("KEYWORD"))
{
// Note: that KEYWORDS are not entities (why not?) and there is a list
// in CLI.cpp of them that must be maintained and synced with this
// function.
args.push_back (raw);
}
else if (arg.hasTag ("ID"))
{
// Not part of a filter.
}
else
{
filter.tag (raw);
}
}
}
// <date>
if (args.size () == 1 &&
args[0] == "<date>")
{
filter.setRange ({Datetime (start), 0});
}
// from <date>
else if (args.size () == 2 &&
args[0] == "from" &&
args[1] == "<date>")
{
filter.setRange ({Datetime (start), 0});
}
// <date> to/- <date>
else if (args.size () == 3 &&
args[0] == "<date>" &&
(args[1] == "to" || args[1] == "-") &&
args[2] == "<date>")
{
filter.setRange ({Datetime (start), Datetime (end)});
}
// from <date> to/- <date>
else if (args.size () == 4 &&
args[0] == "from" &&
args[1] == "<date>" &&
(args[2] == "to" || args[2] == "-") &&
args[3] == "<date>")
{
filter.setRange ({Datetime (start), Datetime (end)});
}
// <date> for <duration>
else if (args.size () == 3 &&
args[0] == "<date>" &&
args[1] == "for" &&
args[2] == "<duration>")
{
filter.setRange ({Datetime (start), Datetime (start) + Duration (duration).toTime_t ()});
}
// from <date> for <duration>
else if (args.size () == 4 &&
args[0] == "from" &&
args[1] == "<date>" &&
args[2] == "for" &&
args[3] == "<duration>")
{
filter.setRange ({Datetime (start), Datetime (start) + Duration (duration).toTime_t ()});
}
// <duration> before <date>
else if (args.size () == 3 &&
args[0] == "<duration>" &&
args[1] == "before" &&
args[2] == "<date>")
{
filter.setRange ({Datetime (start) - Duration (duration).toTime_t (), Datetime (start)});
}
// <duration> after <date>
else if (args.size () == 3 &&
args[0] == "<duration>" &&
args[1] == "after" &&
args[2] == "<date>")
{
filter.setRange ({Datetime (start), Datetime (start) + Duration (duration).toTime_t ()});
}
// <duration> ago
else if (args.size () == 2 &&
args[0] == "<duration>" &&
args[1] == "ago")
{
filter.setRange ({now - Duration (duration).toTime_t (), 0});
}
// for <duration>
else if (args.size () == 2 &&
args[0] == "for" &&
args[1] == "<duration>")
{
filter.setRange ({now - Duration (duration).toTime_t (), now});
}
// <duration>
else if (args.size () == 1 &&
args[0] == "<duration>")
{
filter.setRange ({now - Duration (duration).toTime_t (), now});
}
// Unrecognized date range construct.
else if (! args.empty ())
{
throw std::string ("Unrecognized date range: '") + join (" ", args) + "'.";
}
if (filter.end != 0 && filter.start > filter.end)
throw std::string ("The end of a date range must be after the start.");
return filter;
}
////////////////////////////////////////////////////////////////////////////////
// Read rules and extract all holiday definitions. Create a Range for each
// one that spans from midnight to midnight.

View file

@ -37,7 +37,6 @@
#include <Color.h>
// data.cpp
Interval getFilter (const CLI&);
std::vector <Range> getHolidays (const Rules&);
std::vector <Range> getAllExclusions (const Rules&, const Range&);
std::vector <Interval> getIntervalsByIds (Database&, const Rules&, const std::set <int>&);

View file

@ -173,7 +173,7 @@ void validate (
Interval& interval)
{
// Create a filter, and if empty, choose 'today'.
auto filter = getFilter (cli);
auto filter = cli.getFilter ();
if (! filter.is_started ())
filter.setRange (Datetime ("today"), Datetime ("tomorrow"));