mirror of
https://github.com/GothenburgBitFactory/timewarrior.git
synced 2025-06-26 10:54:28 +02:00
Make getFilter(cli) a method of CLI
This commit is contained in:
parent
547bda5ef8
commit
9ae3ace109
16 changed files with 204 additions and 201 deletions
188
src/CLI.cpp
188
src/CLI.cpp
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 ())
|
||||
{
|
||||
|
|
|
@ -81,7 +81,7 @@ int CmdContinue (
|
|||
to_copy = latest;
|
||||
}
|
||||
|
||||
auto filter = getFilter (cli);
|
||||
auto filter = cli.getFilter ();
|
||||
Datetime start_time;
|
||||
Datetime end_time;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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"))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 () : "");
|
||||
|
|
|
@ -37,7 +37,7 @@ int CmdStart (
|
|||
{
|
||||
auto verbose = rules.getBoolean ("verbose");
|
||||
|
||||
auto filter = getFilter (cli);
|
||||
auto filter = cli.getFilter ();
|
||||
|
||||
auto now = Datetime ();
|
||||
|
||||
|
|
|
@ -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 ();
|
||||
|
||||
|
|
|
@ -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"));
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
186
src/data.cpp
186
src/data.cpp
|
@ -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.
|
||||
|
|
|
@ -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>&);
|
||||
|
|
|
@ -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"));
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue