- Added "task oldest" command

- Added "task newest" command
This commit is contained in:
Paul Beckingham 2008-06-18 00:41:33 -04:00
parent feb9959907
commit 0c17986303
6 changed files with 335 additions and 135 deletions

View file

@ -11,13 +11,15 @@ Configurable columns in reports
------ reality ----------------------------------- ------ reality -----------------------------------
1.3.0 (?) 1.3.0 (6/18/2008)
+ "task calendar" now displays multiple months per line, adjustable by the + "task calendar" now displays multiple months per line, adjustable by the
"monthsperline" configuration variable. Feature added by Damian Glenny "monthsperline" configuration variable. Feature added by Damian Glenny
+ "task export" can now filter tasks like the reports. + "task export" can now filter tasks like the reports
+ Factored out code to filter tasks. + Factored out code to filter tasks
+ Displays shorter message when a command is entered incorrectly, and the + Displays shorter message when a command is entered incorrectly, and the
full usage for "task help". full usage for "task help"
+ "task oldest" shows the oldest tasks
+ "task newest" shows the newest tasks
+ Bug: Segmentation fault when no "dateformat" configuration variable + Bug: Segmentation fault when no "dateformat" configuration variable
specified specified
+ Bug: Fixed bug whereby if you have more than one task with a due date, 7 + Bug: Fixed bug whereby if you have more than one task with a due date, 7

View file

@ -379,6 +379,22 @@ with no arguments will generate a help message that lists all these commands.
% task oldest
-------------
Lists the oldest tasks. Shows 10 tasks by default, but can be set via the
"oldest" configuration variable.
% task newest
-------------
Lists the newest tasks. Shows 10 tasks by default, but can be set via the
"newest" configuration variable.
% task history % task history
-------------- --------------
@ -691,6 +707,12 @@ Configuring Task
monthsperline Determines how many months the "task calendar" command monthsperline Determines how many months the "task calendar" command
renders across the screen. Defaults to 1. renders across the screen. Defaults to 1.
oldest Determines how many tasks are shown on the "oldest"
report. Defaults to 10.
newest Determines how many tasks are shown on the "newest"
report. Defaults to 10.
color May be "on" or "off". Determines whether task uses color May be "on" or "off". Determines whether task uses
color. color.

View file

@ -126,7 +126,9 @@ static const char* commands[] =
"list", "list",
"long", "long",
"ls", "ls",
"newest",
"next", "next",
"oldest",
"overdue", "overdue",
"projects", "projects",
"start", "start",

View file

@ -152,6 +152,14 @@ void shortUsage (Config& conf)
table.addCell (row, 1, "task overdue"); table.addCell (row, 1, "task overdue");
table.addCell (row, 2, "Shows all incomplete tasks that are beyond their due date"); table.addCell (row, 2, "Shows all incomplete tasks that are beyond their due date");
row = table.addRow ();
table.addCell (row, 1, "task oldest");
table.addCell (row, 2, "Shows the oldest tasks");
row = table.addRow ();
table.addCell (row, 1, "task newest");
table.addCell (row, 2, "Shows the newest tasks");
row = table.addRow (); row = table.addRow ();
table.addCell (row, 1, "task stats"); table.addCell (row, 1, "task stats");
table.addCell (row, 2, "Shows task database statistics"); table.addCell (row, 2, "Shows task database statistics");
@ -183,137 +191,7 @@ void shortUsage (Config& conf)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void longUsage (Config& conf) void longUsage (Config& conf)
{ {
Table table; shortUsage (conf);
int width = 80;
#ifdef HAVE_LIBNCURSES
if (conf.get ("curses", true))
{
WINDOW* w = initscr ();
width = w->_maxx + 1;
endwin ();
}
#endif
table.addColumn (" ");
table.addColumn (" ");
table.addColumn (" ");
table.setColumnJustification (0, Table::left);
table.setColumnJustification (1, Table::left);
table.setColumnJustification (2, Table::left);
table.setColumnWidth (0, Table::minimum);
table.setColumnWidth (1, Table::minimum);
table.setColumnWidth (2, Table::flexible);
table.setTableWidth (width);
table.setDateFormat (conf.get ("dateformat", "m/d/Y"));
int row = table.addRow ();
table.addCell (row, 0, "Usage:");
table.addCell (row, 1, "task");
row = table.addRow ();
table.addCell (row, 1, "task add [tags] [attrs] desc...");
table.addCell (row, 2, "Adds a new task");
row = table.addRow ();
table.addCell (row, 1, "task list [tags] [attrs] desc...");
table.addCell (row, 2, "Lists all tasks matching the specified criteria");
row = table.addRow ();
table.addCell (row, 1, "task long [tags] [attrs] desc...");
table.addCell (row, 2, "Lists all task, all data, matching the specified criteria");
row = table.addRow ();
table.addCell (row, 1, "task ls [tags] [attrs] desc...");
table.addCell (row, 2, "Minimal listing of all tasks matching the specified criteria");
row = table.addRow ();
table.addCell (row, 1, "task completed [tags] [attrs] desc...");
table.addCell (row, 2, "Chronological listing of all completed tasks matching the specified criteria");
row = table.addRow ();
table.addCell (row, 1, "task ID [tags] [attrs] [desc...]");
table.addCell (row, 2, "Modifies the existing task with provided arguments");
row = table.addRow ();
table.addCell (row, 1, "task ID /from/to/");
table.addCell (row, 2, "Perform the substitution on the desc, for fixing mistakes");
row = table.addRow ();
table.addCell (row, 1, "task delete ID");
table.addCell (row, 2, "Deletes the specified task");
row = table.addRow ();
table.addCell (row, 1, "task info ID");
table.addCell (row, 2, "Shows all data, metadata for specified task");
row = table.addRow ();
table.addCell (row, 1, "task start ID");
table.addCell (row, 2, "Marks specified task as started, starts the clock ticking");
row = table.addRow ();
table.addCell (row, 1, "task done ID");
table.addCell (row, 2, "Marks the specified task as completed");
row = table.addRow ();
table.addCell (row, 1, "task projects");
table.addCell (row, 2, "Shows a list of all project names used, and how many tasks are in each");
row = table.addRow ();
table.addCell (row, 1, "task tags");
table.addCell (row, 2, "Shows a list of all tags used");
row = table.addRow ();
table.addCell (row, 1, "task summary");
table.addCell (row, 2, "Shows a report of task status by project");
row = table.addRow ();
table.addCell (row, 1, "task history");
table.addCell (row, 2, "Shows a report of task history, by month");
row = table.addRow ();
table.addCell (row, 1, "task next");
table.addCell (row, 2, "Shows the most important tasks for each project");
row = table.addRow ();
table.addCell (row, 1, "task calendar");
table.addCell (row, 2, "Shows a monthly calendar, with due tasks marked");
row = table.addRow ();
table.addCell (row, 1, "task active");
table.addCell (row, 2, "Shows all task that are started, but not completed");
row = table.addRow ();
table.addCell (row, 1, "task overdue");
table.addCell (row, 2, "Shows all incomplete tasks that are beyond their due date");
row = table.addRow ();
table.addCell (row, 1, "task stats");
table.addCell (row, 2, "Shows task database statistics");
row = table.addRow ();
table.addCell (row, 1, "task usage");
table.addCell (row, 2, "Shows task command usage frequency");
row = table.addRow ();
table.addCell (row, 1, "task export");
table.addCell (row, 2, "Exports all tasks as a CSV file");
row = table.addRow ();
table.addCell (row, 1, "task color");
table.addCell (row, 2, "Displays all possible colors");
row = table.addRow ();
table.addCell (row, 1, "task version");
table.addCell (row, 2, "Shows the task version number");
row = table.addRow ();
table.addCell (row, 1, "task help");
table.addCell (row, 2, "Shows the long usage text");
std::cout << table.render ()
<< std::endl;
std::cout std::cout
<< "ID is the numeric identifier displayed by the 'task list' command" << "\n" << "ID is the numeric identifier displayed by the 'task list' command" << "\n"
@ -404,6 +282,8 @@ int main (int argc, char** argv)
else if (command == "calendar") handleReportCalendar (tdb, task, conf); else if (command == "calendar") handleReportCalendar (tdb, task, conf);
else if (command == "active") handleReportActive (tdb, task, conf); else if (command == "active") handleReportActive (tdb, task, conf);
else if (command == "overdue") handleReportOverdue (tdb, task, conf); else if (command == "overdue") handleReportOverdue (tdb, task, conf);
else if (command == "oldest") handleReportOldest (tdb, task, conf);
else if (command == "newest") handleReportNewest (tdb, task, conf);
else if (command == "stats") handleReportStats (tdb, task, conf); else if (command == "stats") handleReportStats (tdb, task, conf);
else if (command == "usage") handleReportUsage (tdb, task, conf); else if (command == "usage") handleReportUsage (tdb, task, conf);
else if (command == "" && task.getId ()) handleModify (tdb, task, conf); else if (command == "" && task.getId ()) handleModify (tdb, task, conf);
@ -2212,6 +2092,280 @@ void handleReportOverdue (const TDB& tdb, T& task, Config& conf)
std::cout << "No overdue tasks." << std::endl; std::cout << "No overdue tasks." << std::endl;
} }
////////////////////////////////////////////////////////////////////////////////
// Successively apply filters based on the task object built from the command
// line. Tasks that match all the specified criteria are listed.
void handleReportOldest (const TDB& tdb, T& task, Config& conf)
{
// Determine window size, and set table accordingly.
int width = 80;
#ifdef HAVE_LIBNCURSES
if (conf.get ("curses", true))
{
WINDOW* w = initscr ();
width = w->_maxx + 1;
endwin ();
}
#endif
tdb.gc ();
// Get the pending tasks.
std::vector <T> tasks;
tdb.pendingT (tasks);
initializeColorRules (conf);
bool showAge = conf.get ("showage", true);
unsigned int quantity = conf.get ("oldest", 10);
// Create a table for output.
Table table;
table.setTableWidth (width);
table.addColumn ("ID");
table.addColumn ("Project");
table.addColumn ("Pri");
table.addColumn ("Due");
table.addColumn ("Active");
if (showAge) table.addColumn ("Age");
table.addColumn ("Description");
table.setColumnUnderline (0);
table.setColumnUnderline (1);
table.setColumnUnderline (2);
table.setColumnUnderline (3);
table.setColumnUnderline (4);
table.setColumnUnderline (5);
if (showAge) table.setColumnUnderline (6);
table.setColumnWidth (0, Table::minimum);
table.setColumnWidth (1, Table::minimum);
table.setColumnWidth (2, Table::minimum);
table.setColumnWidth (3, Table::minimum);
table.setColumnWidth (4, Table::minimum);
if (showAge) table.setColumnWidth (5, Table::minimum);
table.setColumnWidth ((showAge ? 6 : 5), Table::flexible);
table.setColumnJustification (0, Table::right);
table.setColumnJustification (3, Table::right);
if (showAge) table.setColumnJustification (5, Table::right);
table.sortOn (3, Table::ascendingDate);
table.sortOn (2, Table::descendingPriority);
table.sortOn (1, Table::ascendingCharacter);
table.setDateFormat (conf.get ("dateformat", "m/d/Y"));
filter (tasks, task);
for (unsigned int i = 0; i < min (quantity, tasks.size ()); ++i)
{
T refTask (tasks[i]);
// Now format the matching task.
bool imminent = false;
bool overdue = false;
Date now;
std::string due = refTask.getAttribute ("due");
if (due.length ())
{
Date dt (::atoi (due.c_str ()));
due = dt.toString (conf.get ("dateformat", "m/d/Y"));
overdue = (dt < now) ? true : false;
Date nextweek = now + 7 * 86400;
imminent = dt < nextweek ? true : false;
}
std::string active;
if (refTask.getAttribute ("start") != "")
active = "*";
std::string age;
std::string created = refTask.getAttribute ("entry");
if (created.length ())
{
Date dt (::atoi (created.c_str ()));
formatTimeDeltaDays (age, (time_t) (now - dt));
}
// All criteria match, so add refTask to the output table.
int row = table.addRow ();
table.addCell (row, 0, refTask.getId ());
table.addCell (row, 1, refTask.getAttribute ("project"));
table.addCell (row, 2, refTask.getAttribute ("priority"));
table.addCell (row, 3, due);
table.addCell (row, 4, active);
if (showAge) table.addCell (row, 5, age);
table.addCell (row, (showAge ? 6 : 5), refTask.getDescription ());
if (conf.get ("color", true))
{
Text::color fg = Text::colorCode (refTask.getAttribute ("fg"));
Text::color bg = Text::colorCode (refTask.getAttribute ("bg"));
autoColorize (refTask, fg, bg);
table.setRowFg (row, fg);
table.setRowBg (row, bg);
if (fg == Text::nocolor)
{
if (overdue)
table.setCellFg (row, 3, Text::red);
else if (imminent)
table.setCellFg (row, 3, Text::yellow);
}
}
}
if (table.rowCount ())
std::cout << optionalBlankLine (conf)
<< table.render ()
<< optionalBlankLine (conf)
<< table.rowCount ()
<< (table.rowCount () == 1 ? " task" : " tasks")
<< std::endl;
else
std::cout << "No matches."
<< std::endl;
}
////////////////////////////////////////////////////////////////////////////////
// Successively apply filters based on the task object built from the command
// line. Tasks that match all the specified criteria are listed.
void handleReportNewest (const TDB& tdb, T& task, Config& conf)
{
// Determine window size, and set table accordingly.
int width = 80;
#ifdef HAVE_LIBNCURSES
if (conf.get ("curses", true))
{
WINDOW* w = initscr ();
width = w->_maxx + 1;
endwin ();
}
#endif
tdb.gc ();
// Get the pending tasks.
std::vector <T> tasks;
tdb.pendingT (tasks);
initializeColorRules (conf);
bool showAge = conf.get ("showage", true);
int quantity = conf.get ("newest", 10);
// Create a table for output.
Table table;
table.setTableWidth (width);
table.addColumn ("ID");
table.addColumn ("Project");
table.addColumn ("Pri");
table.addColumn ("Due");
table.addColumn ("Active");
if (showAge) table.addColumn ("Age");
table.addColumn ("Description");
table.setColumnUnderline (0);
table.setColumnUnderline (1);
table.setColumnUnderline (2);
table.setColumnUnderline (3);
table.setColumnUnderline (4);
table.setColumnUnderline (5);
if (showAge) table.setColumnUnderline (6);
table.setColumnWidth (0, Table::minimum);
table.setColumnWidth (1, Table::minimum);
table.setColumnWidth (2, Table::minimum);
table.setColumnWidth (3, Table::minimum);
table.setColumnWidth (4, Table::minimum);
if (showAge) table.setColumnWidth (5, Table::minimum);
table.setColumnWidth ((showAge ? 6 : 5), Table::flexible);
table.setColumnJustification (0, Table::right);
table.setColumnJustification (3, Table::right);
if (showAge) table.setColumnJustification (5, Table::right);
table.sortOn (3, Table::ascendingDate);
table.sortOn (2, Table::descendingPriority);
table.sortOn (1, Table::ascendingCharacter);
table.setDateFormat (conf.get ("dateformat", "m/d/Y"));
filter (tasks, task);
int total = tasks.size ();
for (int i = total - 1; i >= max (0, total - quantity); --i)
{
T refTask (tasks[i]);
// Now format the matching task.
bool imminent = false;
bool overdue = false;
Date now;
std::string due = refTask.getAttribute ("due");
if (due.length ())
{
Date dt (::atoi (due.c_str ()));
due = dt.toString (conf.get ("dateformat", "m/d/Y"));
overdue = (dt < now) ? true : false;
Date nextweek = now + 7 * 86400;
imminent = dt < nextweek ? true : false;
}
std::string active;
if (refTask.getAttribute ("start") != "")
active = "*";
std::string age;
std::string created = refTask.getAttribute ("entry");
if (created.length ())
{
Date dt (::atoi (created.c_str ()));
formatTimeDeltaDays (age, (time_t) (now - dt));
}
// All criteria match, so add refTask to the output table.
int row = table.addRow ();
table.addCell (row, 0, refTask.getId ());
table.addCell (row, 1, refTask.getAttribute ("project"));
table.addCell (row, 2, refTask.getAttribute ("priority"));
table.addCell (row, 3, due);
table.addCell (row, 4, active);
if (showAge) table.addCell (row, 5, age);
table.addCell (row, (showAge ? 6 : 5), refTask.getDescription ());
if (conf.get ("color", true))
{
Text::color fg = Text::colorCode (refTask.getAttribute ("fg"));
Text::color bg = Text::colorCode (refTask.getAttribute ("bg"));
autoColorize (refTask, fg, bg);
table.setRowFg (row, fg);
table.setRowBg (row, bg);
if (fg == Text::nocolor)
{
if (overdue)
table.setCellFg (row, 3, Text::red);
else if (imminent)
table.setCellFg (row, 3, Text::yellow);
}
}
}
if (table.rowCount ())
std::cout << optionalBlankLine (conf)
<< table.render ()
<< optionalBlankLine (conf)
<< table.rowCount ()
<< (table.rowCount () == 1 ? " task" : " tasks")
<< std::endl;
else
std::cout << "No matches."
<< std::endl;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void handleReportStats (const TDB& tdb, T& task, Config& conf) void handleReportStats (const TDB& tdb, T& task, Config& conf)
{ {

View file

@ -36,6 +36,10 @@
#include "T.h" #include "T.h"
#include "../auto.h" #include "../auto.h"
#ifndef min
#define min(a,b) ((a) < (b) ? (a) : (b))
#endif
#ifndef max #ifndef max
#define max(a,b) ((a) > (b) ? (a) : (b)) #define max(a,b) ((a) > (b) ? (a) : (b))
#endif #endif
@ -69,6 +73,8 @@ void handleReportCalendar (const TDB&, T&, Config&);
void handleReportActive (const TDB&, T&, Config&); void handleReportActive (const TDB&, T&, Config&);
void handleReportOverdue (const TDB&, T&, Config&); void handleReportOverdue (const TDB&, T&, Config&);
void handleReportStats (const TDB&, T&, Config&); void handleReportStats (const TDB&, T&, Config&);
void handleReportOldest (const TDB&, T&, Config&);
void handleReportNewest (const TDB&, T&, Config&);
void handleVersion (Config&); void handleVersion (Config&);
void handleExport (const TDB&, T&, Config&); void handleExport (const TDB&, T&, Config&);
void handleDelete (const TDB&, T&, Config&); void handleDelete (const TDB&, T&, Config&);

View file

@ -182,6 +182,8 @@ a img { border: none; padding: 0; margin: 0; }
<li>Displays shorter message when a command is entered incorrectly, <li>Displays shorter message when a command is entered incorrectly,
and the full usage for "task help" and the full usage for "task help"
<li>"task export" can now filter tasks like the reports <li>"task export" can now filter tasks like the reports
<li>"task oldest" shows the oldest tasks
<li>"task newest" shows the newest tasks
<li>Fixed bug where task generates a segmentation fault for several <li>Fixed bug where task generates a segmentation fault for several
commands, when no "dateformat" configuration variable was present commands, when no "dateformat" configuration variable was present
<li>Fixed bug whereby if you have more than one task with a due date, <li>Fixed bug whereby if you have more than one task with a due date,
@ -760,6 +762,18 @@ ID Project Pri Description
12 Errand L Remember to deposit bonus check 12 Errand L Remember to deposit bonus check
...</code></pre> ...</code></pre>
<strong>% task oldest</strong>
<p>
Lists the oldest tasks. Shows 10 tasks by default, but can be
set via the "oldest" configuration variable.
</p>
<strong>% task newest</strong>
<p>
Lists the newest tasks. Shows 10 tasks by default, but can be
set via the "newest" configuration variable.
</p>
<strong>% task /from/to/</strong> <strong>% task /from/to/</strong>
<p> <p>
If a task has been entered with a typo, it can be easily corrected If a task has been entered with a typo, it can be easily corrected