mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-07-07 20:06:36 +02:00
Merge branch 'sequences' into 1.7.0
This commit is contained in:
commit
7fea1f6a63
6 changed files with 145 additions and 48 deletions
13
src/T.cpp
13
src/T.cpp
|
@ -37,6 +37,7 @@ T::T ()
|
||||||
mUUID = uuid ();
|
mUUID = uuid ();
|
||||||
mStatus = pending;
|
mStatus = pending;
|
||||||
mId = 0;
|
mId = 0;
|
||||||
|
mSequence.clear ();
|
||||||
mTags.clear ();
|
mTags.clear ();
|
||||||
mAttributes.clear ();
|
mAttributes.clear ();
|
||||||
mDescription = "";
|
mDescription = "";
|
||||||
|
@ -59,6 +60,7 @@ T::T (const T& other)
|
||||||
mStatus = other.mStatus;
|
mStatus = other.mStatus;
|
||||||
mUUID = other.mUUID;
|
mUUID = other.mUUID;
|
||||||
mId = other.mId;
|
mId = other.mId;
|
||||||
|
mSequence = other.mSequence;
|
||||||
mDescription = other.mDescription;
|
mDescription = other.mDescription;
|
||||||
mTags = other.mTags;
|
mTags = other.mTags;
|
||||||
mRemoveTags = other.mRemoveTags;
|
mRemoveTags = other.mRemoveTags;
|
||||||
|
@ -74,6 +76,7 @@ T& T::operator= (const T& other)
|
||||||
mStatus = other.mStatus;
|
mStatus = other.mStatus;
|
||||||
mUUID = other.mUUID;
|
mUUID = other.mUUID;
|
||||||
mId = other.mId;
|
mId = other.mId;
|
||||||
|
mSequence = other.mSequence;
|
||||||
mDescription = other.mDescription;
|
mDescription = other.mDescription;
|
||||||
mTags = other.mTags;
|
mTags = other.mTags;
|
||||||
mRemoveTags = other.mRemoveTags;
|
mRemoveTags = other.mRemoveTags;
|
||||||
|
@ -286,6 +289,16 @@ void T::addAnnotation (const std::string& description)
|
||||||
mAnnotations[time (NULL)] = sanitized;
|
mAnnotations[time (NULL)] = sanitized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
bool T::sequenceContains (int id) const
|
||||||
|
{
|
||||||
|
foreach (seq, mSequence)
|
||||||
|
if (*seq == id)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// uuid status [tags] [attributes] [annotations] description
|
// uuid status [tags] [attributes] [annotations] description
|
||||||
//
|
//
|
||||||
|
|
4
src/T.h
4
src/T.h
|
@ -50,6 +50,8 @@ public:
|
||||||
|
|
||||||
int getId () const { return mId; }
|
int getId () const { return mId; }
|
||||||
void setId (int id) { mId = id; }
|
void setId (int id) { mId = id; }
|
||||||
|
std::vector <int> getAllIds () const { return mSequence; }
|
||||||
|
void addId (int id) { mSequence.push_back (id); }
|
||||||
|
|
||||||
status getStatus () const { return mStatus; }
|
status getStatus () const { return mStatus; }
|
||||||
void setStatus (status s) { mStatus = s; }
|
void setStatus (status s) { mStatus = s; }
|
||||||
|
@ -82,6 +84,7 @@ public:
|
||||||
void getAnnotations (std::map <time_t, std::string>&) const;
|
void getAnnotations (std::map <time_t, std::string>&) const;
|
||||||
void setAnnotations (const std::map <time_t, std::string>&);
|
void setAnnotations (const std::map <time_t, std::string>&);
|
||||||
void addAnnotation (const std::string&);
|
void addAnnotation (const std::string&);
|
||||||
|
bool sequenceContains (int) const;
|
||||||
|
|
||||||
const std::string compose () const;
|
const std::string compose () const;
|
||||||
const std::string composeCSV ();
|
const std::string composeCSV ();
|
||||||
|
@ -95,6 +98,7 @@ private:
|
||||||
status mStatus;
|
status mStatus;
|
||||||
std::string mUUID;
|
std::string mUUID;
|
||||||
int mId;
|
int mId;
|
||||||
|
std::vector <int> mSequence;
|
||||||
std::string mDescription;
|
std::string mDescription;
|
||||||
std::vector<std::string> mTags;
|
std::vector<std::string> mTags;
|
||||||
std::vector<std::string> mRemoveTags;
|
std::vector<std::string> mRemoveTags;
|
||||||
|
|
|
@ -439,13 +439,13 @@ std::string handleDelete (TDB& tdb, T& task, Config& conf)
|
||||||
{
|
{
|
||||||
std::stringstream out;
|
std::stringstream out;
|
||||||
|
|
||||||
if (!conf.get (std::string ("confirmation"), false) || confirm ("Permanently delete task?"))
|
std::vector <T> all;
|
||||||
|
tdb.allPendingT (all);
|
||||||
|
foreach (t, all)
|
||||||
{
|
{
|
||||||
std::vector <T> all;
|
if (t->getId () == task.getId () || task.sequenceContains (t->getId ()))
|
||||||
tdb.allPendingT (all);
|
|
||||||
foreach (t, all)
|
|
||||||
{
|
{
|
||||||
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
|
// Check for the more complex case of a recurring task. If this is a
|
||||||
// recurring task, get confirmation to delete them all.
|
// recurring task, get confirmation to delete them all.
|
||||||
|
@ -494,13 +494,11 @@ std::string handleDelete (TDB& tdb, T& task, Config& conf)
|
||||||
<< t->getDescription ()
|
<< t->getDescription ()
|
||||||
<< std::endl;
|
<< 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 ();
|
return out.str ();
|
||||||
}
|
}
|
||||||
|
|
|
@ -306,6 +306,60 @@ static bool validId (const std::string& input)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// 1,2-4,6
|
||||||
|
static bool validSequence (
|
||||||
|
const std::string& input,
|
||||||
|
std::vector <int>& ids)
|
||||||
|
{
|
||||||
|
std::vector <std::string> ranges;
|
||||||
|
split (ranges, input, ',');
|
||||||
|
|
||||||
|
std::vector <std::string>::iterator it;
|
||||||
|
for (it = ranges.begin (); it != ranges.end (); ++it)
|
||||||
|
{
|
||||||
|
std::vector <std::string> 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)
|
static bool validTag (const std::string& input)
|
||||||
{
|
{
|
||||||
|
@ -390,15 +444,25 @@ bool validDuration (std::string& input)
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Token Distinguishing characteristic
|
// Token EBNF
|
||||||
// ------- -----------------------------
|
// ------- ----------------------------------
|
||||||
// command first positional
|
// command first non-id recognized argument
|
||||||
// id \d+
|
|
||||||
// description default, accumulate
|
|
||||||
// substitution /\w+/\w*/
|
|
||||||
// tags [-+]\w+
|
|
||||||
// attributes \w+:.+
|
|
||||||
//
|
//
|
||||||
|
// 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 (
|
void parse (
|
||||||
std::vector <std::string>& args,
|
std::vector <std::string>& args,
|
||||||
std::string& command,
|
std::string& command,
|
||||||
|
@ -420,12 +484,22 @@ void parse (
|
||||||
std::string from;
|
std::string from;
|
||||||
std::string to;
|
std::string to;
|
||||||
bool global;
|
bool global;
|
||||||
|
std::vector <int> sequence;
|
||||||
|
|
||||||
// An id is the first argument found that contains all digits.
|
// An id is the first argument found that contains all digits.
|
||||||
if (lowerCase (command) != "add" && // "add" doesn't require an ID
|
if (lowerCase (command) != "add" && // "add" doesn't require an ID
|
||||||
task.getId () == 0 &&
|
validSequence (arg, sequence))
|
||||||
validId (arg))
|
{
|
||||||
|
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 ()));
|
task.setId (::atoi (arg.c_str ()));
|
||||||
|
}
|
||||||
|
|
||||||
// Tags begin with + or - and contain arbitrary text.
|
// Tags begin with + or - and contain arbitrary text.
|
||||||
else if (validTag (arg))
|
else if (validTag (arg))
|
||||||
|
|
|
@ -265,35 +265,37 @@ std::string handleInfo (TDB& tdb, T& task, Config& conf)
|
||||||
std::vector <T> tasks;
|
std::vector <T> tasks;
|
||||||
tdb.allPendingT (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.
|
// Find the task.
|
||||||
|
int count = 0;
|
||||||
for (unsigned int i = 0; i < tasks.size (); ++i)
|
for (unsigned int i = 0; i < tasks.size (); ++i)
|
||||||
{
|
{
|
||||||
T refTask (tasks[i]);
|
T refTask (tasks[i]);
|
||||||
|
|
||||||
if (refTask.getId () == task.getId ())
|
if (refTask.getId () == task.getId () || task.sequenceContains (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 ();
|
int row = table.addRow ();
|
||||||
table.addCell (row, 0, "ID");
|
table.addCell (row, 0, "ID");
|
||||||
|
@ -454,14 +456,14 @@ std::string handleInfo (TDB& tdb, T& task, Config& conf)
|
||||||
}
|
}
|
||||||
|
|
||||||
table.addCell (row, 1, entry + " (" + age + ")");
|
table.addCell (row, 1, entry + " (" + age + ")");
|
||||||
|
|
||||||
|
out << optionalBlankLine (conf)
|
||||||
|
<< table.render ()
|
||||||
|
<< std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (table.rowCount ())
|
if (! count)
|
||||||
out << optionalBlankLine (conf)
|
|
||||||
<< table.render ()
|
|
||||||
<< std::endl;
|
|
||||||
else
|
|
||||||
out << "No matches." << std::endl;
|
out << "No matches." << std::endl;
|
||||||
|
|
||||||
return out.str ();
|
return out.str ();
|
||||||
|
|
|
@ -227,6 +227,12 @@ static std::string longUsage (Config& conf)
|
||||||
std::stringstream out;
|
std::stringstream out;
|
||||||
out << shortUsage (conf)
|
out << shortUsage (conf)
|
||||||
<< "ID is the numeric identifier displayed by the 'task list' command." << "\n"
|
<< "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"
|
<< "\n"
|
||||||
<< "Tags are arbitrary words, any quantity:" << "\n"
|
<< "Tags are arbitrary words, any quantity:" << "\n"
|
||||||
<< " +tag The + means add the tag" << "\n"
|
<< " +tag The + means add the tag" << "\n"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue