mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-06-26 10:54:26 +02:00
Custom Reports - oldest, newest
- Added support for the "report.X.limit" configuration variable, to restrict the number of rows a report generates. - Added support for Table::render (limit) to limit the number of rows that are rendered. - Removed "oldest" and "newest" report code. - Added "oldest" and "newest" custom report details to Config.cpp - Updated various documentation.
This commit is contained in:
parent
8c95e82a63
commit
c35a764019
14 changed files with 101 additions and 369 deletions
|
@ -17,12 +17,13 @@
|
|||
+ Added support for custom reports, comprised of a set of column names and
|
||||
sort order, with optional filtering in the configuration file. This
|
||||
means user-defined reports can be written, and the reports currently
|
||||
in the configuration file can be renamed.
|
||||
in the configuration file can be renamed. Several of task's built in
|
||||
reports have been converted to user-defined reports.
|
||||
+ New online documentation for custom reports.
|
||||
+ New algorithm for determining when the "nag" message is displayed.
|
||||
+ Fixed bug where task hangs with a certain combination of recurring tasks
|
||||
and shadow files.
|
||||
+ Fixed bug with the task sort alogrithm, which led to an unstable sequence
|
||||
+ Fixed bug with the task sort algorithm, which led to an unstable sequence
|
||||
when there were only a handful of tasks.
|
||||
+ Performance enhanced by eliminating unnecessary sorting.
|
||||
+ Task now has a large (and growing) test suite and bug regression tests
|
||||
|
|
|
@ -179,18 +179,6 @@
|
|||
only show as many that will fit.
|
||||
</dd>
|
||||
|
||||
<dt>oldest</dt>
|
||||
<dd>
|
||||
Determines how many tasks the "task oldest" command displays.
|
||||
Defaults to 10.
|
||||
</dd>
|
||||
|
||||
<dt>newest</dt>
|
||||
<dd>
|
||||
Determines how many tasks the "task newest" command displays.
|
||||
Defaults to 10.
|
||||
</dd>
|
||||
|
||||
<dt>defaultwidth</dt>
|
||||
<dd>
|
||||
The width of tables used when ncurses support is not available.
|
||||
|
|
|
@ -36,9 +36,10 @@
|
|||
<div class="content">
|
||||
<p>
|
||||
Task allows you to customize reports, to a limited degree.
|
||||
The "list", "long", and "ls" reports are all now custom
|
||||
reports, whereas in previous releases of task they were not
|
||||
mutable. This means they can be modified, renamed, or deleted.
|
||||
The "list", "long", "ls", "oldest" and "newest" reports are
|
||||
all now custom reports, whereas in previous releases of task
|
||||
they were not mutable. This means they can be modified,
|
||||
renamed, or deleted.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
@ -74,6 +75,14 @@ report.mine.sort=priority-,project+</pre></code>
|
|||
definition is optional.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
An optional limit can also be specified, which limits the
|
||||
number of tasks shown in the report. If a limit is not
|
||||
specified, then the number of tasks is not limited.
|
||||
</p>
|
||||
|
||||
<code><pre>report.mine.limit=10</pre></code>
|
||||
|
||||
<p>
|
||||
Here is a list of all the possible columns that may be included
|
||||
in a report:
|
||||
|
|
|
@ -111,7 +111,8 @@
|
|||
<li>Added support for custom reports, comprised of a set of column names and
|
||||
sort order, with optional filtering in the configuration file. This
|
||||
means user-defined reports can be written, and the reports currently
|
||||
in the configuration file can be renamed.
|
||||
in the configuration file can be renamed. Several of task's built in
|
||||
reports have been converted to user-defined reports.
|
||||
<li>New online documentation for custom reports.
|
||||
<li>New algorithm for determining when the "nag" message is displayed.
|
||||
<li>Fixed bug where task hangs with a certain combination of recurring tasks
|
||||
|
|
|
@ -34,12 +34,10 @@
|
|||
<br />
|
||||
<h2 class="title"><a name="usage">Command Usage<a></h2>
|
||||
<div class="content">
|
||||
<pre><code>task add [tags] [attrs] desc...
|
||||
task list [tags] [attrs] desc...
|
||||
task long [tags] [attrs] desc...
|
||||
task ls [tags] [attrs] desc...
|
||||
<pre><code>Usage: task
|
||||
task add [tags] [attrs] desc...
|
||||
task completed [tags] [attrs] desc...
|
||||
task ID [tags] [attrs] ["desc..."]
|
||||
task ID [tags] [attrs] [desc...]
|
||||
task ID /from/to/
|
||||
task delete ID
|
||||
task undelete ID
|
||||
|
@ -57,12 +55,18 @@
|
|||
task calendar
|
||||
task active
|
||||
task overdue
|
||||
task oldest
|
||||
task newest
|
||||
task stats
|
||||
task export
|
||||
task color
|
||||
task version
|
||||
task help
|
||||
task list [tags] [attrs] desc...
|
||||
task long [tags] [attrs] desc...
|
||||
task ls [tags] [attrs] desc...
|
||||
task newest [tags] [attrs] desc...
|
||||
task oldest [tags] [attrs] desc...
|
||||
|
||||
See http://www.beckingham.net/task.html for the latest releases and a full tutorial.
|
||||
|
||||
ID is the numeric identifier displayed by the 'task list' command
|
||||
|
||||
|
@ -74,8 +78,11 @@ Attributes are:
|
|||
project: Project name
|
||||
priority: Priority
|
||||
due: Due date
|
||||
recur: Recurrence frequency
|
||||
until: Recurrence end date
|
||||
fg: Foreground color
|
||||
bg: Background color
|
||||
rc: Alternate .taskrc file
|
||||
|
||||
Any command or attribute name may be abbreviated if still unique:
|
||||
task list project:Home
|
||||
|
@ -86,7 +93,7 @@ Some task descriptions need to be escaped because of the shell:
|
|||
task add escaped \' quote
|
||||
|
||||
Many characters have special meaning to the shell, including:
|
||||
$ ! ' " ( ) ; \ ` * ? { } [ ] < > | & % # ~</code></pre>
|
||||
$ ! ' " ( ) ; \ ` * ? { } [ ] < > | & % # ~</code></pre>
|
||||
<div>
|
||||
|
||||
<br />
|
||||
|
|
|
@ -39,17 +39,32 @@
|
|||
// These are default (but overridable) reports. These entries are necessary
|
||||
// because these three reports were converted from hard-coded reports to custom
|
||||
// reports, and therefore need these config file entries. However, users are
|
||||
// already used to seeing these three reports, but do not have these entries.
|
||||
// already used to seeing these five reports, but do not have these entries.
|
||||
// The choice was a) make users edit their .taskrc files, b) write a .taskrc
|
||||
// upgrade program to make the change, or c) this.
|
||||
Config::Config ()
|
||||
{
|
||||
(*this)["report.long.columns"] = "id,project,priority,entry,start,due,age,tags,description";
|
||||
(*this)["report.long.description"] = "Lists all task, all data, matching the specified criteria";
|
||||
(*this)["report.long.columns"] = "id,project,priority,entry,start,due,recur,age,tags,description";
|
||||
(*this)["report.long.sort"] = "due+,priority-,project+";
|
||||
|
||||
(*this)["report.list.description"] = "Lists all tasks matching the specified criteria";
|
||||
(*this)["report.list.columns"] = "id,project,priority,due,active,age,description";
|
||||
(*this)["report.list.sort"] = "due+,priority-,project+";
|
||||
|
||||
(*this)["report.ls.description"] = "Minimal listing of all tasks matching the specified criteria";
|
||||
(*this)["report.ls.columns"] = "id,project,priority,description";
|
||||
(*this)["report.ls.sort"] = "priority-,project+";
|
||||
|
||||
(*this)["report.newest.description"] = "Shows the newest tasks";
|
||||
(*this)["report.newest.columns"] = "id,project,priority,due,active,age,description";
|
||||
(*this)["report.newest.sort"] = "id-";
|
||||
(*this)["report.newest.limit"] = "10";
|
||||
|
||||
(*this)["report.oldest.description"] = "Shows the oldest tasks";
|
||||
(*this)["report.oldest.columns"] = "id,project,priority,due,active,age,description";
|
||||
(*this)["report.oldest.sort"] = "id+";
|
||||
(*this)["report.oldest.limit"] = "10";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -59,9 +74,9 @@ Config::Config (const std::string& file)
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Read the Configuration filee and populate the *this map. The file format
|
||||
// is simply lines with name=value pairs. Whitespace between name, = and value
|
||||
// is not tolerated, but blank lines and comments starting with # are allowed.
|
||||
// Read the Configuration file and populate the *this map. The file format is
|
||||
// simply lines with name=value pairs. Whitespace between name, = and value is
|
||||
// not tolerated, but blank lines and comments starting with # are allowed.
|
||||
bool Config::load (const std::string& file)
|
||||
{
|
||||
std::ifstream in;
|
||||
|
@ -154,17 +169,33 @@ void Config::createDefault (const std::string& home)
|
|||
fprintf (out, "default.command=list\n");
|
||||
|
||||
// Custom reports.
|
||||
fprintf (out, "# Fields: id,uuid,project,priority,entry,start,due,age,active,tags,description\n");
|
||||
fprintf (out, "# Fields: id,uuid,project,priority,entry,start,due,recur,age,active,tags,description\n");
|
||||
fprintf (out, "# Description: This report is ...\n");
|
||||
fprintf (out, "# Sort: due+,priority-,project+\n");
|
||||
fprintf (out, "# Filter: pro:x pri:H +bug\n");
|
||||
fprintf (out, "report.large.columns=id,uuid,project,priority,entry,start,due,age,active,tags,description\n");
|
||||
fprintf (out, "report.large.sort=due+,priority-,project+\n");
|
||||
fprintf (out, "report.long.columns=id,project,priority,entry,start,due,age,tags,description\n");
|
||||
fprintf (out, "report.long.sort=due+,priority-,project+\n");
|
||||
fprintf (out, "report.list.columns=id,project,priority,due,active,age,description\n");
|
||||
fprintf (out, "report.list.sort=due+,priority-,project+\n");
|
||||
fprintf (out, "report.ls.columns=id,project,priority,description\n");
|
||||
fprintf (out, "report.ls.sort=priority-,project+\n");
|
||||
fprintf (out, "# Limit: 10\n");
|
||||
|
||||
fprintf (out, "report.long.description=Lists all task, all data, matching the specified criteria");
|
||||
fprintf (out, "report.long.columns=id,project,priority,entry,start,due,recur,age,tags,description");
|
||||
fprintf (out, "report.long.sort=due+,priority-,project+");
|
||||
|
||||
fprintf (out, "report.list.description=Lists all tasks matching the specified criteria");
|
||||
fprintf (out, "report.list.columns=id,project,priority,due,active,age,description");
|
||||
fprintf (out, "report.list.sort=due+,priority-,project+");
|
||||
|
||||
fprintf (out, "report.ls.description=Minimal listing of all tasks matching the specified criteria");
|
||||
fprintf (out, "report.ls.columns=id,project,priority,description");
|
||||
fprintf (out, "report.ls.sort=priority-,project+");
|
||||
|
||||
fprintf (out, "report.newest.description=Shows the newest tasks");
|
||||
fprintf (out, "report.newest.columns=id,project,priority,due,active,age,description");
|
||||
fprintf (out, "report.newest.sort=id-");
|
||||
fprintf (out, "report.newest.limit=10");
|
||||
|
||||
fprintf (out, "report.oldest.description=Shows the oldest tasks");
|
||||
fprintf (out, "report.oldest.columns=id,project,priority,due,active,age,description");
|
||||
fprintf (out, "report.oldest.sort=id+");
|
||||
fprintf (out, "report.oldest.limit=10");
|
||||
|
||||
fclose (out);
|
||||
|
||||
|
|
|
@ -325,7 +325,7 @@ Grid::Cell::operator int () const
|
|||
case CELL_INT: return mInt;
|
||||
case CELL_FLOAT: return (int) mFloat;
|
||||
case CELL_DOUBLE: return (int) mDouble;
|
||||
case CELL_STRING: return mString.length ();
|
||||
case CELL_STRING: return ::atoi (mString.c_str ());
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -340,7 +340,7 @@ Grid::Cell::operator float () const
|
|||
case CELL_INT: return (float) mInt;
|
||||
case CELL_FLOAT: return mFloat;
|
||||
case CELL_DOUBLE: return (float) mDouble;
|
||||
case CELL_STRING: return (float) mString.length ();
|
||||
case CELL_STRING: return (float) ::atof (mString.c_str ());
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
|
@ -355,7 +355,7 @@ Grid::Cell::operator double () const
|
|||
case CELL_INT: return (double) mInt;
|
||||
case CELL_FLOAT: return (double) mFloat;
|
||||
case CELL_DOUBLE: return mDouble;
|
||||
case CELL_STRING: return (double) mString.length ();
|
||||
case CELL_STRING: return (double) ::atof (mString.c_str ());
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
|
|
|
@ -994,7 +994,7 @@ void Table::clean (std::string& value)
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
const std::string Table::render ()
|
||||
const std::string Table::render (int maximum /* = 0 */)
|
||||
{
|
||||
calculateColumnWidths ();
|
||||
|
||||
|
@ -1028,8 +1028,14 @@ const std::string Table::render ()
|
|||
if (mSortColumns.size ())
|
||||
sort (order);
|
||||
|
||||
// If a non-zero maximum is specified, then it limits the number of rows of
|
||||
// the table that are rendered.
|
||||
int limit = mRows;
|
||||
if (maximum != 0)
|
||||
limit = maximum;
|
||||
|
||||
// Print all rows.
|
||||
for (int row = 0; row < mRows; ++row)
|
||||
for (int row = 0; row < limit; ++row)
|
||||
{
|
||||
std::vector <std::vector <std::string> > columns;
|
||||
std::vector <std::string> blanks;
|
||||
|
|
|
@ -91,7 +91,7 @@ public:
|
|||
|
||||
int rowCount ();
|
||||
int columnCount ();
|
||||
const std::string render ();
|
||||
const std::string render (int maximum = 0);
|
||||
|
||||
private:
|
||||
std::string getCell (const int, const int);
|
||||
|
|
|
@ -367,8 +367,8 @@ std::string handleVersion (Config& conf)
|
|||
"blanklines color color.active color.due color.overdue color.pri.H "
|
||||
"color.pri.L color.pri.M color.pri.none color.recurring color.tagged "
|
||||
"confirmation curses data.location dateformat default.command "
|
||||
"default.priority defaultwidth due locking monthsperline nag newest next "
|
||||
"oldest project shadow.command shadow.file shadow.notify";
|
||||
"default.priority defaultwidth due locking monthsperline nag next project "
|
||||
"shadow.command shadow.file shadow.notify";
|
||||
|
||||
// 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
|
||||
|
|
|
@ -130,12 +130,7 @@ static const char* commands[] =
|
|||
"history",
|
||||
"ghistory",
|
||||
"info",
|
||||
"list",
|
||||
"long",
|
||||
"ls",
|
||||
"newest",
|
||||
"next",
|
||||
"oldest",
|
||||
"overdue",
|
||||
"projects",
|
||||
"start",
|
||||
|
|
300
src/report.cpp
300
src/report.cpp
|
@ -1678,302 +1678,6 @@ std::string handleReportOverdue (TDB& tdb, T& task, Config& conf)
|
|||
return out.str ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Successively apply filters based on the task object built from the command
|
||||
// line. Tasks that match all the specified criteria are listed.
|
||||
std::string handleReportOldest (TDB& tdb, T& task, Config& conf)
|
||||
{
|
||||
std::stringstream out;
|
||||
|
||||
// Determine window size, and set table accordingly.
|
||||
int width = conf.get ("defaultwidth", 80);
|
||||
#ifdef HAVE_LIBNCURSES
|
||||
if (conf.get ("curses", true))
|
||||
{
|
||||
WINDOW* w = initscr ();
|
||||
width = w->_maxx + 1;
|
||||
endwin ();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Get the pending tasks.
|
||||
std::vector <T> tasks;
|
||||
tdb.allPendingT (tasks);
|
||||
handleRecurrence (tdb, tasks);
|
||||
filter (tasks, task);
|
||||
|
||||
initializeColorRules (conf);
|
||||
|
||||
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");
|
||||
table.addColumn ("Age");
|
||||
table.addColumn ("Description");
|
||||
|
||||
if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
|
||||
{
|
||||
table.setColumnUnderline (0);
|
||||
table.setColumnUnderline (1);
|
||||
table.setColumnUnderline (2);
|
||||
table.setColumnUnderline (3);
|
||||
table.setColumnUnderline (4);
|
||||
table.setColumnUnderline (5);
|
||||
table.setColumnUnderline (6);
|
||||
}
|
||||
else
|
||||
table.setTableDashedUnderline ();
|
||||
|
||||
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);
|
||||
table.setColumnWidth (5, Table::minimum);
|
||||
table.setColumnWidth (6, Table::flexible);
|
||||
|
||||
table.setColumnJustification (0, Table::right);
|
||||
table.setColumnJustification (3, Table::right);
|
||||
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"));
|
||||
|
||||
for (unsigned int i = 0; i < min (quantity, tasks.size ()); ++i)
|
||||
{
|
||||
T refTask (tasks[i]);
|
||||
Date now;
|
||||
|
||||
// Now format the matching task.
|
||||
bool imminent = false;
|
||||
bool overdue = false;
|
||||
std::string due = refTask.getAttribute ("due");
|
||||
if (due.length ())
|
||||
{
|
||||
switch (getDueState (due))
|
||||
{
|
||||
case 2: overdue = true; break;
|
||||
case 1: imminent = true; break;
|
||||
case 0:
|
||||
default: break;
|
||||
}
|
||||
|
||||
Date dt (::atoi (due.c_str ()));
|
||||
due = dt.toString (conf.get ("dateformat", "m/d/Y"));
|
||||
}
|
||||
|
||||
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);
|
||||
table.addCell (row, 5, age);
|
||||
table.addCell (row, 6, refTask.getDescription ());
|
||||
|
||||
if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
|
||||
{
|
||||
Text::color fg = Text::colorCode (refTask.getAttribute ("fg"));
|
||||
Text::color bg = Text::colorCode (refTask.getAttribute ("bg"));
|
||||
autoColorize (refTask, fg, bg, conf);
|
||||
table.setRowFg (row, fg);
|
||||
table.setRowBg (row, bg);
|
||||
|
||||
if (fg == Text::nocolor)
|
||||
{
|
||||
if (overdue)
|
||||
table.setCellFg (row, 3, Text::colorCode (conf.get ("color.overdue", "red")));
|
||||
else if (imminent)
|
||||
table.setCellFg (row, 3, Text::colorCode (conf.get ("color.due", "yellow")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (table.rowCount ())
|
||||
out << optionalBlankLine (conf)
|
||||
<< table.render ()
|
||||
<< optionalBlankLine (conf)
|
||||
<< table.rowCount ()
|
||||
<< (table.rowCount () == 1 ? " task" : " tasks")
|
||||
<< std::endl;
|
||||
else
|
||||
out << "No matches."
|
||||
<< std::endl;
|
||||
|
||||
return out.str ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Successively apply filters based on the task object built from the command
|
||||
// line. Tasks that match all the specified criteria are listed.
|
||||
std::string handleReportNewest (TDB& tdb, T& task, Config& conf)
|
||||
{
|
||||
std::stringstream out;
|
||||
|
||||
// Determine window size, and set table accordingly.
|
||||
int width = conf.get ("defaultwidth", 80);
|
||||
#ifdef HAVE_LIBNCURSES
|
||||
if (conf.get ("curses", true))
|
||||
{
|
||||
WINDOW* w = initscr ();
|
||||
width = w->_maxx + 1;
|
||||
endwin ();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Get the pending tasks.
|
||||
std::vector <T> tasks;
|
||||
tdb.allPendingT (tasks);
|
||||
handleRecurrence (tdb, tasks);
|
||||
filter (tasks, task);
|
||||
|
||||
initializeColorRules (conf);
|
||||
|
||||
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");
|
||||
table.addColumn ("Age");
|
||||
table.addColumn ("Description");
|
||||
|
||||
if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
|
||||
{
|
||||
table.setColumnUnderline (0);
|
||||
table.setColumnUnderline (1);
|
||||
table.setColumnUnderline (2);
|
||||
table.setColumnUnderline (3);
|
||||
table.setColumnUnderline (4);
|
||||
table.setColumnUnderline (5);
|
||||
table.setColumnUnderline (6);
|
||||
}
|
||||
else
|
||||
table.setTableDashedUnderline ();
|
||||
|
||||
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);
|
||||
table.setColumnWidth (5, Table::minimum);
|
||||
table.setColumnWidth (6, Table::flexible);
|
||||
|
||||
table.setColumnJustification (0, Table::right);
|
||||
table.setColumnJustification (3, Table::right);
|
||||
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"));
|
||||
|
||||
int total = tasks.size ();
|
||||
for (int i = total - 1; i >= max (0, total - quantity); --i)
|
||||
{
|
||||
T refTask (tasks[i]);
|
||||
Date now;
|
||||
|
||||
// Now format the matching task.
|
||||
bool imminent = false;
|
||||
bool overdue = false;
|
||||
std::string due = refTask.getAttribute ("due");
|
||||
if (due.length ())
|
||||
{
|
||||
switch (getDueState (due))
|
||||
{
|
||||
case 2: overdue = true; break;
|
||||
case 1: imminent = true; break;
|
||||
case 0:
|
||||
default: break;
|
||||
}
|
||||
|
||||
Date dt (::atoi (due.c_str ()));
|
||||
due = dt.toString (conf.get ("dateformat", "m/d/Y"));
|
||||
}
|
||||
|
||||
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);
|
||||
table.addCell (row, 5, age);
|
||||
table.addCell (row, 6, refTask.getDescription ());
|
||||
|
||||
if (conf.get ("color", true) || conf.get (std::string ("_forcecolor"), false))
|
||||
{
|
||||
Text::color fg = Text::colorCode (refTask.getAttribute ("fg"));
|
||||
Text::color bg = Text::colorCode (refTask.getAttribute ("bg"));
|
||||
autoColorize (refTask, fg, bg, conf);
|
||||
table.setRowFg (row, fg);
|
||||
table.setRowBg (row, bg);
|
||||
|
||||
if (fg == Text::nocolor)
|
||||
{
|
||||
if (overdue)
|
||||
table.setCellFg (row, 3, Text::colorCode (conf.get ("color.overdue", "red")));
|
||||
else if (imminent)
|
||||
table.setCellFg (row, 3, Text::colorCode (conf.get ("color.due", "yellow")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (table.rowCount ())
|
||||
out << optionalBlankLine (conf)
|
||||
<< table.render ()
|
||||
<< optionalBlankLine (conf)
|
||||
<< table.rowCount ()
|
||||
<< (table.rowCount () == 1 ? " task" : " tasks")
|
||||
<< std::endl;
|
||||
else
|
||||
out << "No matches."
|
||||
<< std::endl;
|
||||
|
||||
return out.str ();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string handleReportStats (TDB& tdb, T& task, Config& conf)
|
||||
{
|
||||
|
@ -2575,10 +2279,12 @@ std::string handleCustomReport (
|
|||
}
|
||||
}
|
||||
|
||||
int maximum = conf.get (std::string ("report.") + report + ".limit", (int)0);
|
||||
|
||||
std::stringstream out;
|
||||
if (table.rowCount ())
|
||||
out << optionalBlankLine (conf)
|
||||
<< table.render ()
|
||||
<< table.render (maximum)
|
||||
<< optionalBlankLine (conf)
|
||||
<< table.rowCount ()
|
||||
<< (table.rowCount () == 1 ? " task" : " tasks")
|
||||
|
|
10
src/task.cpp
10
src/task.cpp
|
@ -158,14 +158,6 @@ static void shortUsage (Config& conf)
|
|||
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 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 ();
|
||||
table.addCell (row, 1, "task stats");
|
||||
table.addCell (row, 2, "Shows task database statistics");
|
||||
|
@ -817,8 +809,6 @@ std::string runTaskCommand (
|
|||
else if (command == "calendar") { if (gc) tdb.gc (); out = handleReportCalendar (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); }
|
||||
else if (command == "active") { if (gc) tdb.gc (); out = handleReportActive (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); } // TODO replace with Custom
|
||||
else if (command == "overdue") { if (gc) tdb.gc (); out = handleReportOverdue (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); } // TODO replace with Custom
|
||||
else if (command == "oldest") { if (gc) tdb.gc (); out = handleReportOldest (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); } // TODO replace with Custom
|
||||
else if (command == "newest") { if (gc) tdb.gc (); out = handleReportNewest (tdb, task, conf ); if (shadow) updateShadowFile (tdb, conf); } // TODO replace with Custom
|
||||
else if (command == "colors") { out = handleColor ( conf ); }
|
||||
else if (command == "version") { out = handleVersion ( conf ); }
|
||||
else if (command == "help") { longUsage ( conf ); }
|
||||
|
|
|
@ -100,8 +100,6 @@ std::string handleReportCalendar (TDB&, T&, Config&);
|
|||
std::string handleReportActive (TDB&, T&, Config&);
|
||||
std::string handleReportOverdue (TDB&, T&, Config&);
|
||||
std::string handleReportStats (TDB&, T&, Config&);
|
||||
std::string handleReportOldest (TDB&, T&, Config&);
|
||||
std::string handleReportNewest (TDB&, T&, Config&);
|
||||
|
||||
std::string handleCustomReport (TDB&, T&, Config&, const std::string&);
|
||||
void validReportColumns (const std::vector <std::string>&);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue