mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-06-26 10:54:26 +02:00
Feature - Urgency
- Implemented the urgency algorithm according to rfc31. - Added a new '_urgency' command to test the algorithm.
This commit is contained in:
parent
3ac627978c
commit
d8544181ce
8 changed files with 237 additions and 8 deletions
|
@ -135,6 +135,7 @@ void Cmd::load ()
|
||||||
commands.push_back ("_config");
|
commands.push_back ("_config");
|
||||||
commands.push_back ("_version");
|
commands.push_back ("_version");
|
||||||
commands.push_back ("_merge");
|
commands.push_back ("_merge");
|
||||||
|
commands.push_back ("_urgency");
|
||||||
commands.push_back ("export.csv");
|
commands.push_back ("export.csv");
|
||||||
commands.push_back ("export.ical");
|
commands.push_back ("export.ical");
|
||||||
commands.push_back ("export.yaml");
|
commands.push_back ("export.yaml");
|
||||||
|
@ -232,6 +233,7 @@ bool Cmd::isReadOnlyCommand ()
|
||||||
command == "_ids" ||
|
command == "_ids" ||
|
||||||
command == "_config" ||
|
command == "_config" ||
|
||||||
command == "_version" ||
|
command == "_version" ||
|
||||||
|
command == "_urgency" ||
|
||||||
command == "export.csv" ||
|
command == "export.csv" ||
|
||||||
command == "export.ical" ||
|
command == "export.ical" ||
|
||||||
command == "export.yaml" ||
|
command == "export.yaml" ||
|
||||||
|
|
|
@ -101,6 +101,21 @@ std::string Config::defaults =
|
||||||
"journal.time.start.annotation=Started task # Annotation description for the start journal entry\n"
|
"journal.time.start.annotation=Started task # Annotation description for the start journal entry\n"
|
||||||
"journal.time.stop.annotation=Stopped task # Annotation description for the stop journal entry\n"
|
"journal.time.stop.annotation=Stopped task # Annotation description for the stop journal entry\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
"# Urgency Coefficients\n"
|
||||||
|
"urgency.next.coefficient=10.0 # Urgency coefficients for 'next' special tag\n"
|
||||||
|
"urgency.blocking.coefficient=9.0 # Urgency coefficients for blocking tasks\n"
|
||||||
|
"urgency.blocked.coefficient=8.0 # Urgency coefficients for blocked tasks\n"
|
||||||
|
"urgency.due.coefficient=7.0 # Urgency coefficients for due dates\n"
|
||||||
|
"urgency.priority.coefficient=6.0 # Urgency coefficients for priorities\n"
|
||||||
|
"urgency.waiting.coefficient=5.0 # Urgency coefficients for waiting status\n"
|
||||||
|
"urgency.active.coefficient=4.0 # Urgency coefficients for active tasks\n"
|
||||||
|
"urgency.project.coefficient=3.0 # Urgency coefficients for projects\n"
|
||||||
|
"urgency.tags.coefficient=2.0 # Urgency coefficients for tags\n"
|
||||||
|
"urgency.annotations.coefficient=1.0 # Urgency coefficients for annotations\n"
|
||||||
|
"\n"
|
||||||
|
"#urgency.user.project.foo.coefficient=5.0 # Urgency coefficients for 'foo' project\n"
|
||||||
|
"#urgency.user.tag.foo.coefficient=5.0 # Urgency coefficients for 'foo' tag\n"
|
||||||
|
"\n"
|
||||||
"# Color controls.\n"
|
"# Color controls.\n"
|
||||||
"color=on # Enable color\n"
|
"color=on # Enable color\n"
|
||||||
#ifdef LINUX
|
#ifdef LINUX
|
||||||
|
|
|
@ -249,6 +249,7 @@ int Context::dispatch (std::string &out)
|
||||||
else if (cmd.command == "_ids") { rc = handleCompletionIDs (out); }
|
else if (cmd.command == "_ids") { rc = handleCompletionIDs (out); }
|
||||||
else if (cmd.command == "_config") { rc = handleCompletionConfig (out); }
|
else if (cmd.command == "_config") { rc = handleCompletionConfig (out); }
|
||||||
else if (cmd.command == "_version") { rc = handleCompletionVersion (out); }
|
else if (cmd.command == "_version") { rc = handleCompletionVersion (out); }
|
||||||
|
else if (cmd.command == "_urgency") { rc = handleUrgency (out); }
|
||||||
else if (cmd.command == "" &&
|
else if (cmd.command == "" &&
|
||||||
sequence.size ()) { rc = handleModify (out); }
|
sequence.size ()) { rc = handleModify (out); }
|
||||||
|
|
||||||
|
|
169
src/Task.cpp
169
src/Task.cpp
|
@ -34,6 +34,7 @@
|
||||||
#include "Task.h"
|
#include "Task.h"
|
||||||
#include "text.h"
|
#include "text.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
extern Context context;
|
extern Context context;
|
||||||
|
|
||||||
|
@ -738,3 +739,171 @@ int Task::determineVersion (const std::string& line)
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Urgency is defined as a polynomial, the value of which is calculated in this
|
||||||
|
// function, according to:
|
||||||
|
//
|
||||||
|
// U = A.t + B.t + C.t ...
|
||||||
|
// a b c
|
||||||
|
//
|
||||||
|
// U = urgency
|
||||||
|
// A = coefficient for term a
|
||||||
|
// t sub a = numeric scale from 0 -> 1, with 1 being the highest
|
||||||
|
// urgency, derived from one task attribute and mapped
|
||||||
|
// to the numeric scale
|
||||||
|
//
|
||||||
|
// See rfc31-urgency.txt for full details.
|
||||||
|
//
|
||||||
|
float Task::urgency ()
|
||||||
|
{
|
||||||
|
float urgency = 0.0;
|
||||||
|
|
||||||
|
// urgency.priority.coefficient
|
||||||
|
float coefficient = (float) context.config.getReal ("urgency.priority.coefficient");
|
||||||
|
float term;
|
||||||
|
|
||||||
|
std::string value = get ("priority");
|
||||||
|
if (value == "H") term = 1.0;
|
||||||
|
else if (value == "M") term = 0.65;
|
||||||
|
else if (value == "L") term = 0.3;
|
||||||
|
else term = 0.0;
|
||||||
|
|
||||||
|
urgency += term * coefficient;
|
||||||
|
|
||||||
|
// urgency.project.coefficient
|
||||||
|
coefficient = (float) context.config.getReal ("urgency.project.coefficient");
|
||||||
|
|
||||||
|
value = get ("project");
|
||||||
|
if (value != "") term = 1.0;
|
||||||
|
else term = 0.0;
|
||||||
|
|
||||||
|
urgency += term * coefficient;
|
||||||
|
|
||||||
|
// urgency.active.coefficient
|
||||||
|
coefficient = (float) context.config.getReal ("urgency.active.coefficient");
|
||||||
|
|
||||||
|
value = get ("start");
|
||||||
|
if (value != "") term = 1.0;
|
||||||
|
else term = 0.0;
|
||||||
|
|
||||||
|
urgency += term * coefficient;
|
||||||
|
|
||||||
|
// urgency.waiting.coefficient
|
||||||
|
coefficient = (float) context.config.getReal ("urgency.waiting.coefficient");
|
||||||
|
|
||||||
|
value = get ("status");
|
||||||
|
if (value == "pending") term = 1.0;
|
||||||
|
else if (value == "waiting") term = 0.0;
|
||||||
|
|
||||||
|
urgency += term * coefficient;
|
||||||
|
|
||||||
|
// urgency.blocked.coefficient
|
||||||
|
coefficient = (float) context.config.getReal ("urgency.blocked.coefficient");
|
||||||
|
|
||||||
|
value = get ("depends");
|
||||||
|
if (value != "") term = 0.0;
|
||||||
|
else term = 1.0;
|
||||||
|
|
||||||
|
urgency += term * coefficient;
|
||||||
|
|
||||||
|
// urgency.annotations.coefficient
|
||||||
|
coefficient = (float) context.config.getReal ("urgency.annotations.coefficient");
|
||||||
|
|
||||||
|
std::vector <Att> annos;
|
||||||
|
getAnnotations (annos);
|
||||||
|
if (annos.size () >= 3) term = 1.0;
|
||||||
|
else if (annos.size () == 2) term = 0.9;
|
||||||
|
else if (annos.size () == 1) term = 0.8;
|
||||||
|
else term = 0.0;
|
||||||
|
|
||||||
|
urgency += term * coefficient;
|
||||||
|
|
||||||
|
// urgency.tags.coefficient
|
||||||
|
coefficient = (float) context.config.getReal ("urgency.tags.coefficient");
|
||||||
|
|
||||||
|
int count = getTagCount ();
|
||||||
|
if (count >= 3) term = 1.0;
|
||||||
|
else if (count == 2) term = 0.9;
|
||||||
|
else if (count == 1) term = 0.8;
|
||||||
|
else term = 0.0;
|
||||||
|
|
||||||
|
urgency += term * coefficient;
|
||||||
|
|
||||||
|
// urgency.next.coefficient
|
||||||
|
coefficient = (float) context.config.getReal ("urgency.next.coefficient");
|
||||||
|
|
||||||
|
if (hasTag ("next")) term = 1.0;
|
||||||
|
else term = 0.0;
|
||||||
|
|
||||||
|
urgency += term * coefficient;
|
||||||
|
|
||||||
|
// urgency.due.coefficient
|
||||||
|
// days overdue, capped at 7 -> 0.8 - 1.0
|
||||||
|
// due today -> 0.7
|
||||||
|
// days until due, capped at 14 -> 0.4 - 0.6
|
||||||
|
// has due date -> 0.3
|
||||||
|
// no due date -> 0.0
|
||||||
|
coefficient = (float) context.config.getReal ("urgency.due.coefficient");
|
||||||
|
if (has ("due"))
|
||||||
|
{
|
||||||
|
Date now;
|
||||||
|
Date due (get ("due"));
|
||||||
|
int days_overdue = (now - due) / 86400;
|
||||||
|
|
||||||
|
if (days_overdue > 7) term = 1.0;
|
||||||
|
else if (days_overdue > 0) term = (0.2 * days_overdue / 7.0) + 0.8;
|
||||||
|
else if (due.sameDay (now)) term = 0.7;
|
||||||
|
else if (days_overdue < -14) term = 0.4;
|
||||||
|
else if (days_overdue < 0) term = (0.2 * days_overdue / 14.0) + 0.6;
|
||||||
|
else term = 0.3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
term = 0.0;
|
||||||
|
|
||||||
|
urgency += term * coefficient;
|
||||||
|
|
||||||
|
// Tag- and project-specific coefficients.
|
||||||
|
std::vector <std::string> all;
|
||||||
|
context.config.all (all);
|
||||||
|
|
||||||
|
foreach (var, all)
|
||||||
|
{
|
||||||
|
if (var->substr (0, 13) == "urgency.user.")
|
||||||
|
{
|
||||||
|
// urgency.user.project.<project>.coefficient
|
||||||
|
std::string::size_type end = std::string::npos;
|
||||||
|
if (var->substr (13, 8) == "project." &&
|
||||||
|
(end = var->find (".coefficient")) != std::string::npos)
|
||||||
|
{
|
||||||
|
std::string project = var->substr (21, end - 21);
|
||||||
|
coefficient = (float) context.config.getReal (*var);
|
||||||
|
|
||||||
|
if (get ("project").find (project) == 0)
|
||||||
|
urgency += coefficient;
|
||||||
|
}
|
||||||
|
|
||||||
|
// urgency.user.tag.<tag>.coefficient
|
||||||
|
if (var->substr (13, 4) == "tag." &&
|
||||||
|
(end = var->find (".coefficient")) != std::string::npos)
|
||||||
|
{
|
||||||
|
std::string tag = var->substr (17, end - 17);
|
||||||
|
coefficient = (float) context.config.getReal (*var);
|
||||||
|
|
||||||
|
if (hasTag (tag))
|
||||||
|
urgency += coefficient;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// urgency.blocking.coefficient
|
||||||
|
coefficient = (float) context.config.getReal ("urgency.blocking.coefficient");
|
||||||
|
|
||||||
|
if (dependencyIsBlocking (*this)) term = 1.0;
|
||||||
|
else term = 0.0;
|
||||||
|
|
||||||
|
urgency += term * coefficient;
|
||||||
|
|
||||||
|
// Return the sum of all terms.
|
||||||
|
return urgency;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -81,6 +81,8 @@ public:
|
||||||
|
|
||||||
void validate () const;
|
void validate () const;
|
||||||
|
|
||||||
|
float urgency ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int determineVersion (const std::string&);
|
int determineVersion (const std::string&);
|
||||||
void legacyParse (const std::string&);
|
void legacyParse (const std::string&);
|
||||||
|
|
|
@ -515,6 +515,36 @@ int handleCompletionVersion (std::string &outs)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Temporary command to display urgency for a task.
|
||||||
|
int handleUrgency (std::string &outs)
|
||||||
|
{
|
||||||
|
// Get all the tasks.
|
||||||
|
std::vector <Task> tasks;
|
||||||
|
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||||
|
handleRecurrence ();
|
||||||
|
context.tdb.loadPending (tasks, context.filter);
|
||||||
|
context.tdb.commit ();
|
||||||
|
context.tdb.unlock ();
|
||||||
|
|
||||||
|
// Filter sequence.
|
||||||
|
context.filter.applySequence (tasks, context.sequence);
|
||||||
|
|
||||||
|
// Find the task(s).
|
||||||
|
std::stringstream out;
|
||||||
|
foreach (task, tasks)
|
||||||
|
{
|
||||||
|
out << "task "
|
||||||
|
<< task->id
|
||||||
|
<< " urgency "
|
||||||
|
<< task->urgency ()
|
||||||
|
<< "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
outs = out.str ();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
int handleCompletionIDs (std::string &outs)
|
int handleCompletionIDs (std::string &outs)
|
||||||
{
|
{
|
||||||
|
@ -715,7 +745,12 @@ int handleShow (std::string &outs)
|
||||||
"import.synonym.status import.synonym.tags import.synonym.entry "
|
"import.synonym.status import.synonym.tags import.synonym.entry "
|
||||||
"import.synonym.start import.synonym.due import.synonym.recur "
|
"import.synonym.start import.synonym.due import.synonym.recur "
|
||||||
"import.synonym.end import.synonym.project import.synonym.priority "
|
"import.synonym.end import.synonym.project import.synonym.priority "
|
||||||
"import.synonym.fg import.synonym.bg import.synonym.description ";
|
"import.synonym.fg import.synonym.bg import.synonym.description "
|
||||||
|
|
||||||
|
"urgency.next.coefficient urgency.blocking.coefficient urgency.blocked.coefficient "
|
||||||
|
"urgency.due.coefficient urgency.priority.coefficient urgency.waiting.coefficient "
|
||||||
|
"urgency.active.coefficient urgency.project.coefficient urgency.tags.coefficient "
|
||||||
|
"urgency.annotations.coefficient ";
|
||||||
|
|
||||||
// This configuration variable is supported, but not documented. It exists
|
// This configuration variable is supported, but not documented. It exists
|
||||||
// so that unit tests can force color to be on even when the output from task
|
// so that unit tests can force color to be on even when the output from task
|
||||||
|
@ -732,13 +767,15 @@ int handleShow (std::string &outs)
|
||||||
{
|
{
|
||||||
// These are special configuration variables, because their name is
|
// These are special configuration variables, because their name is
|
||||||
// dynamic.
|
// dynamic.
|
||||||
if (i->substr (0, 14) != "color.keyword." &&
|
if (i->substr (0, 14) != "color.keyword." &&
|
||||||
i->substr (0, 14) != "color.project." &&
|
i->substr (0, 14) != "color.project." &&
|
||||||
i->substr (0, 10) != "color.tag." &&
|
i->substr (0, 10) != "color.tag." &&
|
||||||
i->substr (0, 8) != "holiday." &&
|
i->substr (0, 8) != "holiday." &&
|
||||||
i->substr (0, 7) != "report." &&
|
i->substr (0, 7) != "report." &&
|
||||||
i->substr (0, 6) != "alias." &&
|
i->substr (0, 6) != "alias." &&
|
||||||
i->substr (0, 5) != "hook.")
|
i->substr (0, 5) != "hook." &&
|
||||||
|
i->substr (0, 21) != "urgency.user.project." &&
|
||||||
|
i->substr (0, 17) != "urgency.user.tag.")
|
||||||
{
|
{
|
||||||
unrecognized.push_back (*i);
|
unrecognized.push_back (*i);
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,6 +69,7 @@ int handleCompletionCommands (std::string &);
|
||||||
int handleCompletionIDs (std::string &);
|
int handleCompletionIDs (std::string &);
|
||||||
int handleCompletionConfig (std::string &);
|
int handleCompletionConfig (std::string &);
|
||||||
int handleCompletionVersion (std::string &);
|
int handleCompletionVersion (std::string &);
|
||||||
|
int handleUrgency (std::string &);
|
||||||
int handleVersion (std::string &);
|
int handleVersion (std::string &);
|
||||||
int handleConfig (std::string &);
|
int handleConfig (std::string &);
|
||||||
int handleShow (std::string &);
|
int handleShow (std::string &);
|
||||||
|
|
|
@ -153,6 +153,8 @@ TODO Task::removeDependency
|
||||||
TODO Task::getDependencies
|
TODO Task::getDependencies
|
||||||
TODO Task::getDependencies
|
TODO Task::getDependencies
|
||||||
|
|
||||||
|
TODO Task::urgency
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Task::operator==
|
// Task::operator==
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue