Feature: scheduled date

- Supports 'scheduled' date for tasks, which represent the earliest opportunity
  to work on a task.
- Added unit tests for urgency.
- Implemented color rule.
- Added scheduled to 'info' report.
- Updated assorted documentation.
- Removed comments in default rc because they are never seen.
- Added (broken) 'ready' report, which is like 'next' but only for ready tasks.
This commit is contained in:
Paul Beckingham
2012-05-13 17:19:22 -04:00
parent d08f189769
commit 98f215b1b5
17 changed files with 308 additions and 91 deletions

View File

@@ -13,6 +13,8 @@ Features
+ The 'summary' report now uses 'project.indented' format. + The 'summary' report now uses 'project.indented' format.
+ Applied patch to allow ID ranges and UUIDs when editing dependencies (thanks + Applied patch to allow ID ranges and UUIDs when editing dependencies (thanks
to Louis-Claude Canon). to Louis-Claude Canon).
+ Supports 'scheduled' date for tasks, which represent the earliest opportunity
to work on a task.
+ Performance improvements: + Performance improvements:
+ Added parse-free convenience functions + Added parse-free convenience functions
+ Filter optimization: with no 'OR' or 'XOR' operators, no UUIDS but with IDs + Filter optimization: with no 'OR' or 'XOR' operators, no UUIDS but with IDs

5
NEWS
View File

@@ -3,6 +3,8 @@ New Features in taskwarrior 2.0.1
- The new 'project.indented' format is available and used in the 'projects' - The new 'project.indented' format is available and used in the 'projects'
and 'summary' commands. and 'summary' commands.
- Support for the 'scheduled' date for a task, which represent the earliest
opportunity to work on a task.
Please refer to the ChangeLog file for full details. There are too many to Please refer to the ChangeLog file for full details. There are too many to
list here. list here.
@@ -13,7 +15,8 @@ New commands in taskwarrior 2.0.1
New configuration options in taskwarrior 2.0.1 New configuration options in taskwarrior 2.0.1
- None - urgency.scheduled.coefficient
- color.scheduled
Newly deprecated features in taskwarrior 2.0.1 Newly deprecated features in taskwarrior 2.0.1

View File

@@ -733,6 +733,9 @@ Task is due today
.B color.active .B color.active
Task is started, therefore active. Task is started, therefore active.
.br .br
.B color.scheduled
Task is scheduled, therefore ready for work.
.br
.B color.blocked .B color.blocked
Task is blocked by a dependency. Task is blocked by a dependency.
.br .br
@@ -944,47 +947,51 @@ has a configurable coefficient. Those coefficients are:
.TP .TP
.B urgency.next.coefficient=15.0 .B urgency.next.coefficient=15.0
.RS .RS
Urgency coefficients for 'next' special tag Urgency coefficient for 'next' special tag
.RE .RE
.B urgency.blocking.coefficient=8.0 .B urgency.blocking.coefficient=8.0
.RS .RS
Urgency coefficients for blocking tasks Urgency coefficient for blocking tasks
.RE .RE
.B urgency.blocked.coefficient=-5.0 .B urgency.blocked.coefficient=-5.0
.RS .RS
Urgency coefficients for blocked tasks Urgency coefficient for blocked tasks
.RE .RE
.B urgency.due.coefficient=12.0 .B urgency.due.coefficient=12.0
.RS .RS
Urgency coefficients for due dates Urgency coefficient for due dates
.RE .RE
.B urgency.priority.coefficient=6.0 .B urgency.priority.coefficient=6.0
.RS .RS
Urgency coefficients for priorities Urgency coefficient for priorities
.RE .RE
.B urgency.waiting.coefficient=-3.0 .B urgency.waiting.coefficient=-3.0
.RS .RS
Urgency coefficients for waiting status Urgency coefficient for waiting status
.RE .RE
.B urgency.active.coefficient=4.0 .B urgency.active.coefficient=4.0
.RS .RS
Urgency coefficients for active tasks Urgency coefficient for active tasks
.RE
.B urgency.scheduled.coefficient=5.0
.RS
Urgency coefficient for scheduled tasks
.RE .RE
.B urgency.project.coefficient=1.0 .B urgency.project.coefficient=1.0
.RS .RS
Urgency coefficients for projects Urgency coefficient for projects
.RE .RE
.B urgency.tags.coefficient=1.0 .B urgency.tags.coefficient=1.0
.RS .RS
Urgency coefficients for tags Urgency coefficient for tags
.RE .RE
.B urgency.annotations.coefficient=1.0 .B urgency.annotations.coefficient=1.0
.RS .RS
Urgency coefficients for annotations Urgency coefficient for annotations
.RE .RE
.B urgency.age.coefficient=2.0 .B urgency.age.coefficient=2.0
.RS .RS
Urgency coefficients for the age of tasks Urgency coefficient for the age of tasks
.RE .RE
.B urgency.age.max=365 .B urgency.age.max=365
.RS .RS

View File

@@ -140,12 +140,13 @@ std::string Config::_defaults =
"urgency.blocking.coefficient=8.0 # Urgency coefficient for blocking tasks\n" "urgency.blocking.coefficient=8.0 # Urgency coefficient for blocking tasks\n"
"urgency.priority.coefficient=6.0 # Urgency coefficient for priorities\n" "urgency.priority.coefficient=6.0 # Urgency coefficient for priorities\n"
"urgency.active.coefficient=4.0 # Urgency coefficient for active tasks\n" "urgency.active.coefficient=4.0 # Urgency coefficient for active tasks\n"
"urgency.scheduled.coefficient=5.0 # Urgency coefficient for scheduled tasks\n"
"urgency.age.coefficient=2.0 # Urgency coefficient for age\n" "urgency.age.coefficient=2.0 # Urgency coefficient for age\n"
"urgency.annotations.coefficient=1.0 # Urgency coefficient for annotations\n" "urgency.annotations.coefficient=1.0 # Urgency coefficient for annotations\n"
"urgency.tags.coefficient=1.0 # Urgency coefficient for tags\n" "urgency.tags.coefficient=1.0 # Urgency coefficient for tags\n"
"urgency.project.coefficient=1.0 # Urgency coefficient for projects\n" "urgency.project.coefficient=1.0 # Urgency coefficient for projects\n"
"urgency.blocked.coefficient=-5.0 # Urgency coefficient for blocked tasks\n" "urgency.blocked.coefficient=-5.0 # Urgency coefficient for blocked tasks\n"
"urgency.waiting.coefficient=-3.0 # Urgency coefficient for waiting status\n" "urgency.waiting.coefficient=-3.0 # Urgency coefficient for waiting status\n"
"urgency.age.max=365 # Maximum age in days\n" "urgency.age.max=365 # Maximum age in days\n"
"\n" "\n"
"#urgency.user.project.foo.coefficient=5.0 # Urgency coefficients for 'foo' project\n" "#urgency.user.project.foo.coefficient=5.0 # Urgency coefficients for 'foo' project\n"
@@ -315,138 +316,101 @@ std::string Config::_defaults =
"\n" "\n"
"# Reports\n" "# Reports\n"
"\n" "\n"
"# task long\n"
"report.long.description=Lists all pending tasks\n" "report.long.description=Lists all pending tasks\n"
"report.long.columns=id,project,priority,entry,start,due,recur,due.countdown,entry.age,depends,tags,description\n" "report.long.columns=id,project,priority,entry,start,due,recur,due.countdown,entry.age,depends,tags,description\n"
"report.long.labels=ID,Project,Pri,Added,Started,Due,Recur,Countdown,Age,Deps,Tags,Description\n" "report.long.labels=ID,Project,Pri,Added,Started,Due,Recur,Countdown,Age,Deps,Tags,Description\n"
"report.long.sort=due+,priority-,project+\n" "report.long.sort=due+,priority-,project+\n"
"report.long.filter=status:pending\n" "report.long.filter=status:pending\n"
"#report.long.dateformat=m/d/Y\n"
"#report.long.annotations=full\n"
"\n" "\n"
"# task list\n"
"report.list.description=Lists all pending tasks\n" "report.list.description=Lists all pending tasks\n"
"report.list.columns=id,project,priority,due,start.active,entry.age,description\n" "report.list.columns=id,project,priority,due,start.active,entry.age,description\n"
"report.list.labels=ID,Project,Pri,Due,Active,Age,Description\n" "report.list.labels=ID,Project,Pri,Due,Active,Age,Description\n"
"report.list.sort=due+,priority-,start-,project+\n" "report.list.sort=due+,priority-,start-,project+\n"
"report.list.filter=status:pending\n" "report.list.filter=status:pending\n"
"#report.list.dateformat=m/d/Y\n"
"#report.list.annotations=full\n"
"\n" "\n"
"# task ls\n"
"report.ls.description=Minimal listing of all pending tasks\n" "report.ls.description=Minimal listing of all pending tasks\n"
"report.ls.columns=id,project,priority,description\n" "report.ls.columns=id,project,priority,description\n"
"report.ls.labels=ID,Project,Pri,Description\n" "report.ls.labels=ID,Project,Pri,Description\n"
"report.ls.sort=priority-,project+\n" "report.ls.sort=priority-,project+\n"
"report.ls.filter=status:pending\n" "report.ls.filter=status:pending\n"
"#report.ls.dateformat=m/d/Y\n"
"#report.ls.annotations=full\n"
"\n" "\n"
"# task minimal\n"
"report.minimal.description=Minimal listing of all pending tasks\n" "report.minimal.description=Minimal listing of all pending tasks\n"
"report.minimal.columns=id,project,description.truncated\n" "report.minimal.columns=id,project,description.truncated\n"
"report.minimal.labels=ID,Project,Description\n" "report.minimal.labels=ID,Project,Description\n"
"report.minimal.sort=project+,description+\n" "report.minimal.sort=project+,description+\n"
"report.minimal.filter=status:pending\n" "report.minimal.filter=status:pending\n"
"#report.minimal.dateformat=m/d/Y\n"
"#report.minimal.annotations=full\n"
"\n" "\n"
"# task newest\n"
"report.newest.description=Shows the newest tasks\n" "report.newest.description=Shows the newest tasks\n"
"report.newest.columns=id,project,priority,due,start.active,entry.age,description\n" "report.newest.columns=id,project,priority,due,start.active,entry.age,description\n"
"report.newest.labels=ID,Project,Pri,Due,Active,Age,Description\n" "report.newest.labels=ID,Project,Pri,Due,Active,Age,Description\n"
"report.newest.sort=id-\n" "report.newest.sort=id-\n"
"report.newest.filter=status:pending limit:10\n" "report.newest.filter=status:pending limit:10\n"
"#report.newest.dateformat=m/d/Y\n"
"#report.newest.annotations=full\n"
"\n" "\n"
"# task oldest\n"
"report.oldest.description=Shows the oldest tasks\n" "report.oldest.description=Shows the oldest tasks\n"
"report.oldest.columns=id,project,priority,due,start.active,entry.age,description\n" "report.oldest.columns=id,project,priority,due,start.active,entry.age,description\n"
"report.oldest.labels=ID,Project,Pri,Due,Active,Age,Description\n" "report.oldest.labels=ID,Project,Pri,Due,Active,Age,Description\n"
"report.oldest.sort=id+\n" "report.oldest.sort=id+\n"
"report.oldest.filter=status:pending limit:10\n" "report.oldest.filter=status:pending limit:10\n"
"#report.oldest.dateformat=m/d/Y\n"
"#report.oldest.annotations=full\n"
"\n" "\n"
"# task overdue\n"
"report.overdue.description=Lists overdue tasks\n" "report.overdue.description=Lists overdue tasks\n"
"report.overdue.columns=id,project,priority,due,start.active,entry.age,description\n" "report.overdue.columns=id,project,priority,due,start.active,entry.age,description\n"
"report.overdue.labels=ID,Project,Pri,Due,Active,Age,Description\n" "report.overdue.labels=ID,Project,Pri,Due,Active,Age,Description\n"
"report.overdue.sort=due+,priority-,start-,project+\n" "report.overdue.sort=due+,priority-,start-,project+\n"
"report.overdue.filter=status:pending due.before:now\n" "report.overdue.filter=status:pending due.before:now\n"
"#report.overdue.dateformat=m/d/Y\n"
"#report.overdue.annotations=full\n"
"\n" "\n"
"# task active\n"
"report.active.description=Lists active tasks\n" "report.active.description=Lists active tasks\n"
"report.active.columns=id,project,priority,due,start.active,entry.age,description\n" "report.active.columns=id,project,priority,due,start.active,entry.age,description\n"
"report.active.labels=ID,Project,Pri,Due,Active,Age,Description\n" "report.active.labels=ID,Project,Pri,Due,Active,Age,Description\n"
"report.active.sort=due+,priority-,project+\n" "report.active.sort=due+,priority-,project+\n"
"report.active.filter=status:pending start.any:\n" "report.active.filter=status:pending start.any:\n"
"#report.active.dateformat=m/d/Y\n"
"#report.active.annotations=full\n"
"\n" "\n"
"# task completed\n"
"report.completed.description=Lists completed tasks\n" "report.completed.description=Lists completed tasks\n"
"report.completed.columns=end,project,priority,entry.age,description,uuid\n" "report.completed.columns=end,project,priority,entry.age,description,uuid\n"
"report.completed.labels=Complete,Project,Pri,Age,Description,UUID\n" "report.completed.labels=Complete,Project,Pri,Age,Description,UUID\n"
"report.completed.sort=end+,priority-,project+\n" "report.completed.sort=end+,priority-,project+\n"
"report.completed.filter=status:completed\n" "report.completed.filter=status:completed\n"
"#report.completed.dateformat=m/d/Y\n"
"#report.completed.annotations=full\n"
"\n" "\n"
"# task recurring\n"
"report.recurring.description=Lists recurring tasks\n" "report.recurring.description=Lists recurring tasks\n"
"report.recurring.columns=id,project,priority,due,recur,start.active,entry.age,description\n" "report.recurring.columns=id,project,priority,due,recur,start.active,entry.age,description\n"
"report.recurring.labels=ID,Project,Pri,Due,Recur,Active,Age,Description\n" "report.recurring.labels=ID,Project,Pri,Due,Recur,Active,Age,Description\n"
"report.recurring.sort=due+,priority-,start-,project+\n" "report.recurring.sort=due+,priority-,start-,project+\n"
"report.recurring.filter=status:pending parent.any:\n" "report.recurring.filter=status:pending parent.any:\n"
"#report.recurring.dateformat=m/d/Y\n"
"#report.recurring.annotations=full\n"
"\n" "\n"
"# task waiting\n"
"report.waiting.description=Lists all waiting tasks\n" "report.waiting.description=Lists all waiting tasks\n"
"report.waiting.columns=id,project,priority,wait,entry.age,description\n" "report.waiting.columns=id,project,priority,wait,entry.age,description\n"
"report.waiting.labels=ID,Project,Pri,Wait,Age,Description\n" "report.waiting.labels=ID,Project,Pri,Wait,Age,Description\n"
"report.waiting.sort=wait+,priority-,project+\n" "report.waiting.sort=wait+,priority-,project+\n"
"report.waiting.filter=status:waiting\n" "report.waiting.filter=status:waiting\n"
"#report.waiting.dateformat=m/d/Y\n"
"#report.waiting.annotations=full\n"
"\n" "\n"
"# task all\n"
"report.all.description=Lists all pending and completed tasks\n" "report.all.description=Lists all pending and completed tasks\n"
"report.all.columns=id,status,project,priority,due,end,start.active,entry.age,description\n" "report.all.columns=id,status,project,priority,due,end,start.active,entry.age,description\n"
"report.all.labels=ID,Status,Project,Pri,Due,Completed,Active,Age,Description\n" "report.all.labels=ID,Status,Project,Pri,Due,Completed,Active,Age,Description\n"
"report.all.sort=entry+\n" "report.all.sort=entry+\n"
"report.all.filter=status.not:deleted\n" "report.all.filter=status.not:deleted\n"
"#report.all.dateformat=m/d/Y\n"
"#report.all.annotations=full\n"
"\n" "\n"
"# task next\n"
"report.next.description=Lists the most urgent tasks\n" "report.next.description=Lists the most urgent tasks\n"
"report.next.columns=id,project,priority,due,start.active,entry.age,urgency,description\n" "report.next.columns=id,project,priority,due,start.active,entry.age,urgency,description\n"
"report.next.filter=status:pending limit:page\n" "report.next.filter=status:pending limit:page\n"
"report.next.labels=ID,Project,Pri,Due,A,Age,Urgency,Description\n" "report.next.labels=ID,Project,Pri,Due,A,Age,Urgency,Description\n"
"report.next.sort=urgency-,due+,priority-,start-,project+\n" "report.next.sort=urgency-,due+,priority-,start-,project+\n"
"#report.next.dateformat=m/d/Y\n"
"#report.next.annotations=full\n"
"\n" "\n"
"# task blocked\n" "report.ready.description=Lists the most urgent tasks\n"
"report.ready.columns=id,project,priority,due,start.active,entry.age,urgency,description\n"
"report.ready.filter=status:pending limit:page wait.none: (scheduled.none: or scheduled.before:now)\n"
"report.ready.labels=ID,Project,Pri,Due,A,Age,Urgency,Description\n"
"report.ready.sort=urgency-,due+,priority-,start-,project+\n"
"\n"
"report.blocked.description=Lists all blocked tasks\n" "report.blocked.description=Lists all blocked tasks\n"
"report.blocked.columns=id,depends,project,priority,due,start.active,entry.age,description\n" "report.blocked.columns=id,depends,project,priority,due,start.active,entry.age,description\n"
"report.blocked.labels=ID,Deps,Project,Pri,Due,Active,Age,Description\n" "report.blocked.labels=ID,Deps,Project,Pri,Due,Active,Age,Description\n"
"report.blocked.sort=due+,priority-,start-,project+\n" "report.blocked.sort=due+,priority-,start-,project+\n"
"report.blocked.filter=status:pending depends.any:\n" "report.blocked.filter=status:pending depends.any:\n"
"#report.blocked.dateformat=m/d/Y\n"
"\n" "\n"
"# task unblocked\n"
"report.unblocked.description=Lists all unblocked tasks\n" "report.unblocked.description=Lists all unblocked tasks\n"
"report.unblocked.columns=id,depends,project,priority,due,start.active,entry.age,description\n" "report.unblocked.columns=id,depends,project,priority,due,start.active,entry.age,description\n"
"report.unblocked.labels=ID,Deps,Project,Pri,Due,Active,Age,Description\n" "report.unblocked.labels=ID,Deps,Project,Pri,Due,Active,Age,Description\n"
"report.unblocked.sort=due+,priority-,start-,project+\n" "report.unblocked.sort=due+,priority-,start-,project+\n"
"report.unblocked.filter=status:pending depends.none:\n" "report.unblocked.filter=status:pending depends.none:\n"
"#report.unblocked.dateformat=m/d/Y\n"
"\n"; "\n";
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@@ -53,6 +53,7 @@ static std::map <std::string, float> coefficients;
float urgencyPriorityCoefficient = 0.0; float urgencyPriorityCoefficient = 0.0;
float urgencyProjectCoefficient = 0.0; float urgencyProjectCoefficient = 0.0;
float urgencyActiveCoefficient = 0.0; float urgencyActiveCoefficient = 0.0;
float urgencyScheduledCoefficient = 0.0;
float urgencyWaitingCoefficient = 0.0; float urgencyWaitingCoefficient = 0.0;
float urgencyBlockedCoefficient = 0.0; float urgencyBlockedCoefficient = 0.0;
float urgencyAnnotationsCoefficient = 0.0; float urgencyAnnotationsCoefficient = 0.0;
@@ -74,6 +75,7 @@ void initializeUrgencyCoefficients ()
urgencyPriorityCoefficient = context.config.getReal ("urgency.priority.coefficient"); urgencyPriorityCoefficient = context.config.getReal ("urgency.priority.coefficient");
urgencyProjectCoefficient = context.config.getReal ("urgency.project.coefficient"); urgencyProjectCoefficient = context.config.getReal ("urgency.project.coefficient");
urgencyActiveCoefficient = context.config.getReal ("urgency.active.coefficient"); urgencyActiveCoefficient = context.config.getReal ("urgency.active.coefficient");
urgencyScheduledCoefficient = context.config.getReal ("urgency.scheduled.coefficient");
urgencyWaitingCoefficient = context.config.getReal ("urgency.waiting.coefficient"); urgencyWaitingCoefficient = context.config.getReal ("urgency.waiting.coefficient");
urgencyBlockedCoefficient = context.config.getReal ("urgency.blocked.coefficient"); urgencyBlockedCoefficient = context.config.getReal ("urgency.blocked.coefficient");
urgencyAnnotationsCoefficient = context.config.getReal ("urgency.annotations.coefficient"); urgencyAnnotationsCoefficient = context.config.getReal ("urgency.annotations.coefficient");
@@ -1131,35 +1133,14 @@ void Task::validate ()
// 2) To provide suitable warnings about odd states // 2) To provide suitable warnings about odd states
// When a task has a due date, other dates should conform. // Date relationships.
if (has ("due")) validate_before ("wait", "due");
{ validate_before ("entry", "start");
Date due (get_date ("due")); validate_before ("entry", "end");
validate_before ("wait", "scheduled");
// Verify wait < due validate_before ("scheduled", "start");
if (has ("wait")) validate_before ("scheduled", "due");
{ validate_before ("scheduled", "end");
Date wait (get_date ("wait"));
if (wait > due)
context.footnote (STRING_TASK_VALID_WAIT);
}
Date entry (get_date ("entry"));
if (has ("start"))
{
Date start (get_date ("start"));
if (entry > start)
context.footnote (STRING_TASK_VALID_START);
}
if (has ("end"))
{
Date end (get_date ("end"));
if (entry > end)
context.footnote (STRING_TASK_VALID_END);
}
}
// 3) To generate errors when the inconsistencies are not fixable // 3) To generate errors when the inconsistencies are not fixable
@@ -1196,6 +1177,19 @@ void Task::validate ()
} }
} }
void Task::validate_before (const std::string& left, const std::string& right)
{
if (has (left) &&
has (right))
{
Date date_left (get_date (left));
Date date_right (get_date (right));
if (date_left > date_right)
context.footnote (format (STRING_TASK_VALID_BEFORE, left, right));
}
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
int Task::determineVersion (const std::string& line) int Task::determineVersion (const std::string& line)
{ {
@@ -1290,6 +1284,7 @@ float Task::urgency_c () const
value += fabsf (urgencyPriorityCoefficient) > epsilon ? (urgency_priority () * urgencyPriorityCoefficient) : 0.0; value += fabsf (urgencyPriorityCoefficient) > epsilon ? (urgency_priority () * urgencyPriorityCoefficient) : 0.0;
value += fabsf (urgencyProjectCoefficient) > epsilon ? (urgency_project () * urgencyProjectCoefficient) : 0.0; value += fabsf (urgencyProjectCoefficient) > epsilon ? (urgency_project () * urgencyProjectCoefficient) : 0.0;
value += fabsf (urgencyActiveCoefficient) > epsilon ? (urgency_active () * urgencyActiveCoefficient) : 0.0; value += fabsf (urgencyActiveCoefficient) > epsilon ? (urgency_active () * urgencyActiveCoefficient) : 0.0;
value += fabsf (urgencyScheduledCoefficient) > epsilon ? (urgency_scheduled () * urgencyScheduledCoefficient) : 0.0;
value += fabsf (urgencyWaitingCoefficient) > epsilon ? (urgency_waiting () * urgencyWaitingCoefficient) : 0.0; value += fabsf (urgencyWaitingCoefficient) > epsilon ? (urgency_waiting () * urgencyWaitingCoefficient) : 0.0;
value += fabsf (urgencyBlockedCoefficient) > epsilon ? (urgency_blocked () * urgencyBlockedCoefficient) : 0.0; value += fabsf (urgencyBlockedCoefficient) > epsilon ? (urgency_blocked () * urgencyBlockedCoefficient) : 0.0;
value += fabsf (urgencyAnnotationsCoefficient) > epsilon ? (urgency_annotations () * urgencyAnnotationsCoefficient) : 0.0; value += fabsf (urgencyAnnotationsCoefficient) > epsilon ? (urgency_annotations () * urgencyAnnotationsCoefficient) : 0.0;
@@ -1305,6 +1300,7 @@ float Task::urgency_c () const
<< "# pri " << (urgency_priority () * urgencyPriorityCoefficient) << "# pri " << (urgency_priority () * urgencyPriorityCoefficient)
<< "# pro " << (urgency_project () * urgencyProjectCoefficient) << "# pro " << (urgency_project () * urgencyProjectCoefficient)
<< "# act " << (urgency_active () * urgencyActiveCoefficient) << "# act " << (urgency_active () * urgencyActiveCoefficient)
<< "# sch " << (urgency_scheduled () * urgencyScheduledCoefficient)
<< "# wai " << (urgency_waiting () * urgencyWaitingCoefficient) << "# wai " << (urgency_waiting () * urgencyWaitingCoefficient)
<< "# blk " << (urgency_blocked () * urgencyBlockedCoefficient) << "# blk " << (urgency_blocked () * urgencyBlockedCoefficient)
<< "# ann " << (urgency_annotations () * urgencyAnnotationsCoefficient) << "# ann " << (urgency_annotations () * urgencyAnnotationsCoefficient)
@@ -1394,6 +1390,16 @@ float Task::urgency_active () const
return 0.0; return 0.0;
} }
////////////////////////////////////////////////////////////////////////////////
float Task::urgency_scheduled () const
{
if (has ("scheduled") &&
get_date ("scheduled") < time (NULL))
return 1.0;
return 0.0;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
float Task::urgency_waiting () const float Task::urgency_waiting () const
{ {

View File

@@ -110,10 +110,12 @@ public:
private: private:
int determineVersion (const std::string&); int determineVersion (const std::string&);
void legacyParse (const std::string&); void legacyParse (const std::string&);
void validate_before (const std::string&, const std::string&);
inline float urgency_priority () const; inline float urgency_priority () const;
inline float urgency_project () const; inline float urgency_project () const;
inline float urgency_active () const; inline float urgency_active () const;
inline float urgency_scheduled () const;
inline float urgency_waiting () const; inline float urgency_waiting () const;
inline float urgency_blocked () const; inline float urgency_blocked () const;
inline float urgency_annotations () const; inline float urgency_annotations () const;

View File

@@ -21,6 +21,7 @@ set (columns_SRCS Column.cpp Column.h
ColPriority.cpp ColPriority.h ColPriority.cpp ColPriority.h
ColProject.cpp ColProject.h ColProject.cpp ColProject.h
ColRecur.cpp ColRecur.h ColRecur.cpp ColRecur.h
ColScheduled.cpp ColScheduled.h
ColStart.cpp ColStart.h ColStart.cpp ColStart.h
ColStatus.cpp ColStatus.h ColStatus.cpp ColStatus.h
ColString.cpp ColString.h ColString.cpp ColString.h

View File

@@ -0,0 +1,118 @@
////////////////////////////////////////////////////////////////////////////////
// taskwarrior - a command line task list manager.
//
// Copyright 2006-2012, Paul Beckingham, Federico Hernandez.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// http://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////
#define L10N // Localization complete.
#include <stdlib.h>
#include <Context.h>
#include <ColScheduled.h>
#include <Date.h>
#include <Duration.h>
#include <text.h>
#include <i18n.h>
extern Context context;
////////////////////////////////////////////////////////////////////////////////
ColumnScheduled::ColumnScheduled ()
{
_name = "scheduled";
_label = STRING_COLUMN_LABEL_SCHED;
_styles.push_back ("countdown");
Date now;
now += 125;
_examples.push_back (Duration (now - Date ()).formatCompact ());
}
////////////////////////////////////////////////////////////////////////////////
ColumnScheduled::~ColumnScheduled ()
{
}
////////////////////////////////////////////////////////////////////////////////
bool ColumnScheduled::validate (std::string& value)
{
return ColumnDate::validate (value);
}
////////////////////////////////////////////////////////////////////////////////
// Overriden so that style <----> label are linked.
// Note that you can not determine which gets called first.
void ColumnScheduled::setStyle (const std::string& value)
{
_style = value;
if (_style == "countdown" && _label == STRING_COLUMN_LABEL_DUE)
_label = STRING_COLUMN_LABEL_COUNT;
}
////////////////////////////////////////////////////////////////////////////////
// Set the minimum and maximum widths for the value.
void ColumnScheduled::measure (Task& task, int& minimum, int& maximum)
{
minimum = maximum = 0;
if (task.has (_name))
{
if (_style == "countdown")
{
Date date ((time_t) strtol (task.get (_name).c_str (), NULL, 10));
Date now;
minimum = maximum = Duration (now - date).format ().length ();
}
else
ColumnDate::measure (task, minimum, maximum);
}
}
////////////////////////////////////////////////////////////////////////////////
void ColumnScheduled::render (
std::vector <std::string>& lines,
Task& task,
int width,
Color& color)
{
if (task.has (_name))
{
if (_style == "countdown")
{
Date date ((time_t) strtol (task.get (_name).c_str (), NULL, 10));
Date now;
lines.push_back (
color.colorize (
rightJustify (
Duration (now - date).format (), width)));
}
else
ColumnDate::render (lines, task, width, color);
}
}
////////////////////////////////////////////////////////////////////////////////

View File

@@ -0,0 +1,47 @@
////////////////////////////////////////////////////////////////////////////////
// taskwarrior - a command line task list manager.
//
// Copyright 2006-2012, Paul Beckingham, Federico Hernandez.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// http://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDED_COLSCHED
#define INCLUDED_COLSCHED
#define L10N // Localization complete.
#include <ColDate.h>
class ColumnScheduled : public ColumnDate
{
public:
ColumnScheduled ();
~ColumnScheduled ();
bool validate (std::string&);
void setStyle (const std::string&);
void measure (Task&, int&, int&);
void render (std::vector <std::string>&, Task&, int, Color&);
};
#endif
////////////////////////////////////////////////////////////////////////////////

View File

@@ -43,6 +43,7 @@
#include <ColPriority.h> #include <ColPriority.h>
#include <ColProject.h> #include <ColProject.h>
#include <ColRecur.h> #include <ColRecur.h>
#include <ColScheduled.h>
#include <ColStart.h> #include <ColStart.h>
#include <ColStatus.h> #include <ColStatus.h>
#include <ColString.h> #include <ColString.h>
@@ -94,6 +95,7 @@ Column* Column::factory (const std::string& name, const std::string& report)
else if (column_name == "priority") c = new ColumnPriority (); else if (column_name == "priority") c = new ColumnPriority ();
else if (column_name == "project") c = new ColumnProject (); else if (column_name == "project") c = new ColumnProject ();
else if (column_name == "recur") c = new ColumnRecur (); else if (column_name == "recur") c = new ColumnRecur ();
else if (column_name == "scheduled") c = new ColumnScheduled ();
else if (column_name == "start") c = new ColumnStart (); else if (column_name == "start") c = new ColumnStart ();
else if (column_name == "status") c = new ColumnStatus (); else if (column_name == "status") c = new ColumnStatus ();
else if (column_name == "tags") c = new ColumnTags (); else if (column_name == "tags") c = new ColumnTags ();
@@ -137,6 +139,7 @@ void Column::factory (std::map <std::string, Column*>& all)
c = new ColumnPriority (); all[c->_name] = c; c = new ColumnPriority (); all[c->_name] = c;
c = new ColumnProject (); all[c->_name] = c; c = new ColumnProject (); all[c->_name] = c;
c = new ColumnRecur (); all[c->_name] = c; c = new ColumnRecur (); all[c->_name] = c;
c = new ColumnScheduled (); all[c->_name] = c;
c = new ColumnStart (); all[c->_name] = c; c = new ColumnStart (); all[c->_name] = c;
c = new ColumnStatus (); all[c->_name] = c; c = new ColumnStatus (); all[c->_name] = c;
c = new ColumnTags (); all[c->_name] = c; c = new ColumnTags (); all[c->_name] = c;

View File

@@ -159,6 +159,7 @@ std::string CmdEdit::formatTask (Task task)
<< " Created: " << formatDate (task, "entry") << "\n" << " Created: " << formatDate (task, "entry") << "\n"
<< " Started: " << formatDate (task, "start") << "\n" << " Started: " << formatDate (task, "start") << "\n"
<< " Ended: " << formatDate (task, "end") << "\n" << " Ended: " << formatDate (task, "end") << "\n"
<< " Scheduled: " << formatDate (task, "scheduled") << "\n"
<< " Due: " << formatDate (task, "due") << "\n" << " Due: " << formatDate (task, "due") << "\n"
<< " Until: " << formatDate (task, "until") << "\n" << " Until: " << formatDate (task, "until") << "\n"
<< " Recur: " << task.get ("recur") << "\n" << " Recur: " << task.get ("recur") << "\n"
@@ -344,6 +345,37 @@ void CmdEdit::parseTask (Task& task, const std::string& after)
} }
} }
// scheduled
value = findValue (after, "\n Scheduled:");
if (value != "")
{
if (task.get ("scheduled") != "")
{
Date original (task.get_date ("scheduled"));
std::string formatted = original.toString (context.config.get ("dateformat"));
if (formatted != value)
{
context.footnote (STRING_EDIT_SCHED_MOD);
task.set ("scheduled", value);
}
}
else
{
context.footnote (STRING_EDIT_SCHED_MOD);
task.set ("scheduled", value);
}
}
else
{
if (task.get ("scheduled") != "")
{
context.footnote (STRING_EDIT_SCHED_DEL);
task.setStatus (Task::pending);
task.remove ("scheduled");
}
}
// due // due
value = findValue (after, "\n Due:"); value = findValue (after, "\n Due:");
if (value != "") if (value != "")

View File

@@ -244,6 +244,14 @@ int CmdInfo::execute (std::string& output)
view.set (row, 1, Date (task->get_date ("wait")).toString (dateformat)); view.set (row, 1, Date (task->get_date ("wait")).toString (dateformat));
} }
// scheduled
if (task->has ("scheduled"))
{
row = view.addRow ();
view.set (row, 0, STRING_COLUMN_LABEL_SCHED);
view.set (row, 1, Date (task->get_date ("scheduled")).toString (dateformat));
}
// start // start
if (task->has ("start")) if (task->has ("start"))
{ {

View File

@@ -112,6 +112,7 @@ int CmdShow::execute (std::string& output)
" color.pri.M" " color.pri.M"
" color.pri.none" " color.pri.none"
" color.recurring" " color.recurring"
" color.scheduled"
" color.summary.background" " color.summary.background"
" color.summary.bar" " color.summary.bar"
" color.sync.added" " color.sync.added"
@@ -185,6 +186,7 @@ int CmdShow::execute (std::string& output)
" taskd.credentials" " taskd.credentials"
" undo.style" " undo.style"
" urgency.active.coefficient" " urgency.active.coefficient"
" urgency.scheduled.coefficient"
" urgency.annotations.coefficient" " urgency.annotations.coefficient"
" urgency.blocked.coefficient" " urgency.blocked.coefficient"
" urgency.blocking.coefficient" " urgency.blocking.coefficient"

View File

@@ -182,6 +182,7 @@
#define STRING_COLUMN_LABEL_COLUMN "Columns" #define STRING_COLUMN_LABEL_COLUMN "Columns"
#define STRING_COLUMN_LABEL_STYLES "Supported Formats" #define STRING_COLUMN_LABEL_STYLES "Supported Formats"
#define STRING_COLUMN_LABEL_EXAMPLES "Example" #define STRING_COLUMN_LABEL_EXAMPLES "Example"
#define STRING_COLUMN_LABEL_SCHED "Scheduled"
// Column Examples // Column Examples
#define STRING_COLUMN_EXAMPLES_TAGS "home @chore" #define STRING_COLUMN_EXAMPLES_TAGS "home @chore"
@@ -615,6 +616,8 @@
#define STRING_EDIT_END_MOD "End date modified." #define STRING_EDIT_END_MOD "End date modified."
#define STRING_EDIT_END_DEL "End date removed." #define STRING_EDIT_END_DEL "End date removed."
#define STRING_EDIT_END_SET_ERR "Cannot set a done date on a pending task." #define STRING_EDIT_END_SET_ERR "Cannot set a done date on a pending task."
#define STRING_EDIT_SCHED_MOD "Scheduled date modified."
#define STRING_EDIT_SCHED_DEL "Scheduled date removed."
#define STRING_EDIT_DUE_MOD "Due date modified." #define STRING_EDIT_DUE_MOD "Due date modified."
#define STRING_EDIT_DUE_DEL "Due date removed." #define STRING_EDIT_DUE_DEL "Due date removed."
#define STRING_EDIT_DUE_DEL_ERR "Cannot remove a due date from a recurring task." #define STRING_EDIT_DUE_DEL_ERR "Cannot remove a due date from a recurring task."
@@ -761,9 +764,7 @@
#define STRING_TASK_DEPEND_CIRCULAR "Circular dependency detected and disallowed." #define STRING_TASK_DEPEND_CIRCULAR "Circular dependency detected and disallowed."
#define STRING_TASK_VALID_DESC "A task must have a description." #define STRING_TASK_VALID_DESC "A task must have a description."
#define STRING_TASK_VALID_BLANK "Cannot add a task that is blank." #define STRING_TASK_VALID_BLANK "Cannot add a task that is blank."
#define STRING_TASK_VALID_WAIT "Warning: You have specified a 'wait' date that is after the 'due' date." #define STRING_TASK_VALID_BEFORE "Warning: You have specified that the '{1}' date is after the '{2}' date."
#define STRING_TASK_VALID_START "Warning: You have specified a 'start' date that is before the 'entry' date."
#define STRING_TASK_VALID_END "Warning: You have specified an 'end' date that is before the 'entry' date."
#define STRING_TASK_VALID_REC_DUE "A recurring task must also have a 'due' date." #define STRING_TASK_VALID_REC_DUE "A recurring task must also have a 'due' date."
#define STRING_TASK_VALID_UNTIL "Only recurring tasks may have an 'until' date." #define STRING_TASK_VALID_UNTIL "Only recurring tasks may have an 'until' date."
#define STRING_TASK_VALID_RECUR "The recurrence value '{1}' is not valid." #define STRING_TASK_VALID_RECUR "The recurrence value '{1}' is not valid."
@@ -873,12 +874,14 @@
" priority: Priority\n" \ " priority: Priority\n" \
" due: Due date\n" \ " due: Due date\n" \
" recur: Recurrence frequency\n" \ " recur: Recurrence frequency\n" \
" until: Recurrence end date\n" \ " until: Expiration date of a task\n" \
" limit: Desired number of rows in report, or 'page'\n" \ " limit: Desired number of rows in report, or 'page'\n" \
" wait: Date until task becomes pending\n" \ " wait: Date until task becomes pending\n" \
" entry: Date task was created\n" \ " entry: Date task was created\n" \
" end: Date task was completed/deleted\n" \ " end: Date task was completed/deleted\n" \
" start: Date task was started\n" \ " start: Date task was started\n" \
" scheduled: Date task is scheduled to start\n" \
" depends: Other tasks that this task depends upon\n" \
"\n" \ "\n" \
"Attribute modifiers make filters more precise. Supported modifiers are:\n" \ "Attribute modifiers make filters more precise. Supported modifiers are:\n" \
" before (synonyms under, below)\n" \ " before (synonyms under, below)\n" \

View File

@@ -139,6 +139,14 @@ static void colorizeActive (Task& task, const std::string& rule, Color& c)
c.blend (gsColor[rule]); c.blend (gsColor[rule]);
} }
////////////////////////////////////////////////////////////////////////////////
static void colorizeScheduled (Task& task, const std::string& rule, Color& c)
{
if (gsColor[rule].nontrivial () &&
task.has ("scheduled"))
c.blend (gsColor[rule]);
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
static void colorizeTag (Task& task, const std::string& rule, Color& c) static void colorizeTag (Task& task, const std::string& rule, Color& c)
{ {
@@ -291,6 +299,7 @@ void autoColorize (Task& task, Color& c)
else if (*r == "color.pri.H") colorizePriorityH (task, *r, c); else if (*r == "color.pri.H") colorizePriorityH (task, *r, c);
else if (*r == "color.pri.none") colorizePriorityNone (task, *r, c); else if (*r == "color.pri.none") colorizePriorityNone (task, *r, c);
else if (*r == "color.active") colorizeActive (task, *r, c); else if (*r == "color.active") colorizeActive (task, *r, c);
else if (*r == "color.scheduled") colorizeScheduled (task, *r, c);
else if (*r == "color.project.none") colorizeProjectNone (task, *r, c); else if (*r == "color.project.none") colorizeProjectNone (task, *r, c);
else if (*r == "color.tag.none") colorizeTagNone (task, *r, c); else if (*r == "color.tag.none") colorizeTagNone (task, *r, c);
else if (*r == "color.due") colorizeDue (task, *r, c); else if (*r == "color.due") colorizeDue (task, *r, c);

View File

@@ -28,7 +28,7 @@
use strict; use strict;
use warnings; use warnings;
use Test::More tests => 46; use Test::More tests => 48;
# Create the rc file. # Create the rc file.
if (open my $fh, '>', 'urgency.rc') if (open my $fh, '>', 'urgency.rc')
@@ -300,6 +300,16 @@ qx{../src/task rc:urgency.rc add 11a +TAG}; # task 43
$output = qx{../src/task rc:urgency.rc 43 _urgency}; $output = qx{../src/task rc:urgency.rc 43 _urgency};
like ($output, qr/urgency 18$/ms, '+TAG = 18'); like ($output, qr/urgency 18$/ms, '+TAG = 18');
# scheduled 0 (scheduled future)
qx {../src/task rc:urgency.rc add 12a scheduled:eom};
$output = qx{../src/task rc:urgency.rc 44 _urgency};
like ($output, qr/urgency 0$/ms, 'scheduled future = 0');
# scheduled 5 (scheduled past)
qx {../src/task rc:urgency.rc add 12b scheduled:yesterday};
$output = qx{../src/task rc:urgency.rc 45 _urgency};
like ($output, qr/urgency 5$/ms, 'scheduled past = 5');
# Cleanup. # Cleanup.
unlink qw(pending.data completed.data undo.data backlog.data synch.key urgency.rc); unlink qw(pending.data completed.data undo.data backlog.data synch.key urgency.rc);
ok (! -r 'pending.data' && ok (! -r 'pending.data' &&

View File

@@ -75,7 +75,7 @@ $output = qx{../src/task rc:wait.rc all status:waiting wait:tomorrow};
like ($output, qr/tomorrow/ms, 'waiting task visible when specifically queried'); like ($output, qr/tomorrow/ms, 'waiting task visible when specifically queried');
$output = qx{../src/task rc:wait.rc add Complain due:today wait:tomorrow}; $output = qx{../src/task rc:wait.rc add Complain due:today wait:tomorrow};
like ($output, qr/Warning: You have specified a 'wait' date that is after the 'due' date\./, 'warning on wait after due'); like ($output, qr/Warning: You have specified that the 'wait' date is after the 'due' date\./, 'warning on wait after due');
# Cleanup. # Cleanup.
unlink qw(pending.data completed.data undo.data backlog.data synch.key wait.rc); unlink qw(pending.data completed.data undo.data backlog.data synch.key wait.rc);