From d135dc233761c15f192914b21eff5f6fe949ee23 Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Mon, 4 May 2009 22:24:43 -0400 Subject: [PATCH 1/3] Enhancement - id sequences - Recognizes id sequences on the command line. Doesn't do anything with them yet. --- src/T.h | 3 ++ src/parse.cpp | 104 ++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 96 insertions(+), 11 deletions(-) diff --git a/src/T.h b/src/T.h index 14004a9c3..5e457aba1 100644 --- a/src/T.h +++ b/src/T.h @@ -50,6 +50,8 @@ public: int getId () const { return mId; } void setId (int id) { mId = id; } + std::vector getAllIds () const { return mSequence; } + void addId (int id) { mSequence.push_back (id); } status getStatus () const { return mStatus; } void setStatus (status s) { mStatus = s; } @@ -95,6 +97,7 @@ private: status mStatus; std::string mUUID; int mId; + std::vector mSequence; std::string mDescription; std::vector mTags; std::vector mRemoveTags; diff --git a/src/parse.cpp b/src/parse.cpp index f4778307e..c57762ec9 100644 --- a/src/parse.cpp +++ b/src/parse.cpp @@ -306,6 +306,60 @@ static bool validId (const std::string& input) return true; } +//////////////////////////////////////////////////////////////////////////////// +// 1,2-4,6 +static bool validSequence ( + const std::string& input, + std::vector & ids) +{ + std::vector ranges; + split (ranges, input, ','); + + std::vector ::iterator it; + for (it = ranges.begin (); it != ranges.end (); ++it) + { + std::vector range; + split (range, *it, '-'); + + switch (range.size ()) + { + case 1: + if (! validId (range[0])) + return false; + + int id = ::atoi (range[0].c_str ()); + ids.push_back (id); +// std::cout << "# seq: " << id << std::endl; + break; + + case 2: + { + if (! validId (range[0]) || + ! validId (range[1])) + return false; + + int low = ::atoi (range[0].c_str ()); + int high = ::atoi (range[1].c_str ()); + if (low >= high) + return false; + + for (int i = low; i <= high; ++i) +// { + ids.push_back (i); +// std::cout << "# seq: " << i << std::endl; +// } + } + break; + + default: + return false; + break; + } + } + + return ids.size () > 1 ? true : false; +} + //////////////////////////////////////////////////////////////////////////////// static bool validTag (const std::string& input) { @@ -390,15 +444,25 @@ bool validDuration (std::string& input) } //////////////////////////////////////////////////////////////////////////////// -// Token Distinguishing characteristic -// ------- ----------------------------- -// command first positional -// id \d+ -// description default, accumulate -// substitution /\w+/\w*/ -// tags [-+]\w+ -// attributes \w+:.+ +// Token EBNF +// ------- ---------------------------------- +// command first non-id recognized argument // +// id ::= \d+ +// +// substitution ::= "/" from "/" to "/g" +// | "/" from "/" to "/" ; +// +// tags ::= "+" word +// | "-" word ; +// +// attributes ::= word ":" value +// | word ":" +// +// sequence ::= id "," sequence +// | id "-" id ; +// +// description (whatever isn't one of the above) void parse ( std::vector & args, std::string& command, @@ -420,12 +484,30 @@ void parse ( std::string from; std::string to; bool global; + std::vector sequence; // An id is the first argument found that contains all digits. - if (lowerCase (command) != "add" && // "add" doesn't require an ID - task.getId () == 0 && - validId (arg)) + if (lowerCase (command) != "add" && +/* + task.getSequenceCount () == 0 && +*/ + validSequence (arg, sequence)) + { +/* + for (?) + task.addSequence (?) +*/ + std::cout << "# look like a sequence" << std::endl; + foreach (id, sequence) + task.addId (*id); + } + + else if (lowerCase (command) != "add" && // "add" doesn't require an ID + task.getId () == 0 && + validId (arg)) + { task.setId (::atoi (arg.c_str ())); + } // Tags begin with + or - and contain arbitrary text. else if (validTag (arg)) From fb674a562676bafd9d65554cb6c7f30ca40a3f23 Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Tue, 5 May 2009 01:59:07 -0400 Subject: [PATCH 2/3] Enhancement - parse sequence like 1,3,5-10 for IDs - Now parses sequences as well as IDs. - Sequences implemented for the info report. --- src/T.cpp | 13 +++++++++++ src/T.h | 1 + src/parse.cpp | 10 +-------- src/report.cpp | 59 ++++++++++++++++++++++++++------------------------ src/task.cpp | 6 +++++ 5 files changed, 52 insertions(+), 37 deletions(-) diff --git a/src/T.cpp b/src/T.cpp index 842613c56..b589ba628 100644 --- a/src/T.cpp +++ b/src/T.cpp @@ -37,6 +37,7 @@ T::T () mUUID = uuid (); mStatus = pending; mId = 0; + mSequence.clear (); mTags.clear (); mAttributes.clear (); mDescription = ""; @@ -59,6 +60,7 @@ T::T (const T& other) mStatus = other.mStatus; mUUID = other.mUUID; mId = other.mId; + mSequence = other.mSequence; mDescription = other.mDescription; mTags = other.mTags; mRemoveTags = other.mRemoveTags; @@ -74,6 +76,7 @@ T& T::operator= (const T& other) mStatus = other.mStatus; mUUID = other.mUUID; mId = other.mId; + mSequence = other.mSequence; mDescription = other.mDescription; mTags = other.mTags; mRemoveTags = other.mRemoveTags; @@ -286,6 +289,16 @@ void T::addAnnotation (const std::string& description) mAnnotations[time (NULL)] = sanitized; } +//////////////////////////////////////////////////////////////////////////////// +bool T::inSequence (int id) const +{ + foreach (seq, mSequence) + if (*seq == id) + return true; + + return false; +} + //////////////////////////////////////////////////////////////////////////////// // uuid status [tags] [attributes] [annotations] description // diff --git a/src/T.h b/src/T.h index 5e457aba1..23a219fb9 100644 --- a/src/T.h +++ b/src/T.h @@ -84,6 +84,7 @@ public: void getAnnotations (std::map &) const; void setAnnotations (const std::map &); void addAnnotation (const std::string&); + bool inSequence (int) const; const std::string compose () const; const std::string composeCSV (); diff --git a/src/parse.cpp b/src/parse.cpp index c57762ec9..c5bbfbbea 100644 --- a/src/parse.cpp +++ b/src/parse.cpp @@ -487,17 +487,9 @@ void parse ( std::vector sequence; // An id is the first argument found that contains all digits. - if (lowerCase (command) != "add" && -/* - task.getSequenceCount () == 0 && -*/ + if (lowerCase (command) != "add" && // "add" doesn't require an ID validSequence (arg, sequence)) { -/* - for (?) - task.addSequence (?) -*/ - std::cout << "# look like a sequence" << std::endl; foreach (id, sequence) task.addId (*id); } diff --git a/src/report.cpp b/src/report.cpp index cdf2a6a79..e389190e7 100644 --- a/src/report.cpp +++ b/src/report.cpp @@ -265,35 +265,38 @@ std::string handleInfo (TDB& tdb, T& task, Config& conf) std::vector tasks; tdb.allPendingT (tasks); - Table table; - table.setTableWidth (width); - table.setDateFormat (conf.get ("dateformat", "m/d/Y")); - - table.addColumn ("Name"); - table.addColumn ("Value"); - - if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false)) - { - table.setColumnUnderline (0); - table.setColumnUnderline (1); - } - else - table.setTableDashedUnderline (); - - table.setColumnWidth (0, Table::minimum); - table.setColumnWidth (1, Table::flexible); - - table.setColumnJustification (0, Table::left); - table.setColumnJustification (1, Table::left); - // Find the task. + int count = 0; for (unsigned int i = 0; i < tasks.size (); ++i) { T refTask (tasks[i]); - if (refTask.getId () == task.getId ()) + if (refTask.getId () == task.getId () || + task.inSequence (refTask.getId ())) { - Date now; + ++count; + + Table table; + table.setTableWidth (width); + table.setDateFormat (conf.get ("dateformat", "m/d/Y")); + + table.addColumn ("Name"); + table.addColumn ("Value"); + + if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false)) + { + table.setColumnUnderline (0); + table.setColumnUnderline (1); + } + else + table.setTableDashedUnderline (); + + table.setColumnWidth (0, Table::minimum); + table.setColumnWidth (1, Table::flexible); + + table.setColumnJustification (0, Table::left); + table.setColumnJustification (1, Table::left); + Date now; int row = table.addRow (); table.addCell (row, 0, "ID"); @@ -440,14 +443,14 @@ std::string handleInfo (TDB& tdb, T& task, Config& conf) } table.addCell (row, 1, entry + " (" + age + ")"); + + out << optionalBlankLine (conf) + << table.render () + << std::endl; } } - if (table.rowCount ()) - out << optionalBlankLine (conf) - << table.render () - << std::endl; - else + if (! count) out << "No matches." << std::endl; return out.str (); diff --git a/src/task.cpp b/src/task.cpp index e64fc0256..190d86daa 100644 --- a/src/task.cpp +++ b/src/task.cpp @@ -227,6 +227,12 @@ static std::string longUsage (Config& conf) std::stringstream out; out << shortUsage (conf) << "ID is the numeric identifier displayed by the 'task list' command." << "\n" + << "You can specify multiple IDs for task commands, and multiple tasks" << "\n" + << "will be affected. To specify multiple IDs make sure you use one" << "\n" + << "of these forms:" << "\n" + << " task delete 1,2,3" << "\n" + << " task info 1-3" << "\n" + << " task pri:H 1,2-5,19" << "\n" << "\n" << "Tags are arbitrary words, any quantity:" << "\n" << " +tag The + means add the tag" << "\n" From b67b27f5cdd1bdaf673df0a532a2c1e1ac0a5a7e Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Tue, 5 May 2009 02:14:43 -0400 Subject: [PATCH 3/3] Enhancement - delete sequences - Implemented sequences for delete command - Renamed T::inSequence to T::sequenceContains, which makes the code read more naturally. --- src/T.cpp | 2 +- src/T.h | 2 +- src/command.cpp | 16 +++++++--------- src/report.cpp | 3 +-- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/T.cpp b/src/T.cpp index b589ba628..ac4943e86 100644 --- a/src/T.cpp +++ b/src/T.cpp @@ -290,7 +290,7 @@ void T::addAnnotation (const std::string& description) } //////////////////////////////////////////////////////////////////////////////// -bool T::inSequence (int id) const +bool T::sequenceContains (int id) const { foreach (seq, mSequence) if (*seq == id) diff --git a/src/T.h b/src/T.h index 23a219fb9..29537053f 100644 --- a/src/T.h +++ b/src/T.h @@ -84,7 +84,7 @@ public: void getAnnotations (std::map &) const; void setAnnotations (const std::map &); void addAnnotation (const std::string&); - bool inSequence (int) const; + bool sequenceContains (int) const; const std::string compose () const; const std::string composeCSV (); diff --git a/src/command.cpp b/src/command.cpp index 968763656..d04953734 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -439,13 +439,13 @@ std::string handleDelete (TDB& tdb, T& task, Config& conf) { std::stringstream out; - if (!conf.get (std::string ("confirmation"), false) || confirm ("Permanently delete task?")) + std::vector all; + tdb.allPendingT (all); + foreach (t, all) { - std::vector all; - tdb.allPendingT (all); - foreach (t, all) + if (t->getId () == task.getId () || task.sequenceContains (t->getId ())) { - if (t->getId () == task.getId ()) + if (!conf.get (std::string ("confirmation"), false) || confirm ("Permanently delete task?")) { // Check for the more complex case of a recurring task. If this is a // recurring task, get confirmation to delete them all. @@ -494,13 +494,11 @@ std::string handleDelete (TDB& tdb, T& task, Config& conf) << t->getDescription () << std::endl; } - - break; // No point continuing the loop. } + else + out << "Task not deleted." << std::endl; } } - else - out << "Task not deleted." << std::endl; return out.str (); } diff --git a/src/report.cpp b/src/report.cpp index e389190e7..540a603fb 100644 --- a/src/report.cpp +++ b/src/report.cpp @@ -271,8 +271,7 @@ std::string handleInfo (TDB& tdb, T& task, Config& conf) { T refTask (tasks[i]); - if (refTask.getId () == task.getId () || - task.inSequence (refTask.getId ())) + if (refTask.getId () == task.getId () || task.sequenceContains (refTask.getId ())) { ++count;