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
|
+ Added support for custom reports, comprised of a set of column names and
|
||||||
sort order, with optional filtering in the configuration file. This
|
sort order, with optional filtering in the configuration file. This
|
||||||
means user-defined reports can be written, and the reports currently
|
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 online documentation for custom reports.
|
||||||
+ New algorithm for determining when the "nag" message is displayed.
|
+ New algorithm for determining when the "nag" message is displayed.
|
||||||
+ Fixed bug where task hangs with a certain combination of recurring tasks
|
+ Fixed bug where task hangs with a certain combination of recurring tasks
|
||||||
and shadow files.
|
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.
|
when there were only a handful of tasks.
|
||||||
+ Performance enhanced by eliminating unnecessary sorting.
|
+ Performance enhanced by eliminating unnecessary sorting.
|
||||||
+ Task now has a large (and growing) test suite and bug regression tests
|
+ Task now has a large (and growing) test suite and bug regression tests
|
||||||
|
|
|
@ -179,18 +179,6 @@
|
||||||
only show as many that will fit.
|
only show as many that will fit.
|
||||||
</dd>
|
</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>
|
<dt>defaultwidth</dt>
|
||||||
<dd>
|
<dd>
|
||||||
The width of tables used when ncurses support is not available.
|
The width of tables used when ncurses support is not available.
|
||||||
|
|
|
@ -36,9 +36,10 @@
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<p>
|
<p>
|
||||||
Task allows you to customize reports, to a limited degree.
|
Task allows you to customize reports, to a limited degree.
|
||||||
The "list", "long", and "ls" reports are all now custom
|
The "list", "long", "ls", "oldest" and "newest" reports are
|
||||||
reports, whereas in previous releases of task they were not
|
all now custom reports, whereas in previous releases of task
|
||||||
mutable. This means they can be modified, renamed, or deleted.
|
they were not mutable. This means they can be modified,
|
||||||
|
renamed, or deleted.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
@ -74,6 +75,14 @@ report.mine.sort=priority-,project+</pre></code>
|
||||||
definition is optional.
|
definition is optional.
|
||||||
</p>
|
</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>
|
<p>
|
||||||
Here is a list of all the possible columns that may be included
|
Here is a list of all the possible columns that may be included
|
||||||
in a report:
|
in a report:
|
||||||
|
|
|
@ -111,7 +111,8 @@
|
||||||
<li>Added support for custom reports, comprised of a set of column names and
|
<li>Added support for custom reports, comprised of a set of column names and
|
||||||
sort order, with optional filtering in the configuration file. This
|
sort order, with optional filtering in the configuration file. This
|
||||||
means user-defined reports can be written, and the reports currently
|
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 online documentation for custom reports.
|
||||||
<li>New algorithm for determining when the "nag" message is displayed.
|
<li>New algorithm for determining when the "nag" message is displayed.
|
||||||
<li>Fixed bug where task hangs with a certain combination of recurring tasks
|
<li>Fixed bug where task hangs with a certain combination of recurring tasks
|
||||||
|
|
|
@ -34,12 +34,10 @@
|
||||||
<br />
|
<br />
|
||||||
<h2 class="title"><a name="usage">Command Usage<a></h2>
|
<h2 class="title"><a name="usage">Command Usage<a></h2>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<pre><code>task add [tags] [attrs] desc...
|
<pre><code>Usage: task
|
||||||
task list [tags] [attrs] desc...
|
task add [tags] [attrs] desc...
|
||||||
task long [tags] [attrs] desc...
|
|
||||||
task ls [tags] [attrs] desc...
|
|
||||||
task completed [tags] [attrs] desc...
|
task completed [tags] [attrs] desc...
|
||||||
task ID [tags] [attrs] ["desc..."]
|
task ID [tags] [attrs] [desc...]
|
||||||
task ID /from/to/
|
task ID /from/to/
|
||||||
task delete ID
|
task delete ID
|
||||||
task undelete ID
|
task undelete ID
|
||||||
|
@ -57,12 +55,18 @@
|
||||||
task calendar
|
task calendar
|
||||||
task active
|
task active
|
||||||
task overdue
|
task overdue
|
||||||
task oldest
|
|
||||||
task newest
|
|
||||||
task stats
|
task stats
|
||||||
task export
|
task export
|
||||||
task color
|
task color
|
||||||
task version
|
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
|
ID is the numeric identifier displayed by the 'task list' command
|
||||||
|
|
||||||
|
@ -74,8 +78,11 @@ Attributes are:
|
||||||
project: Project name
|
project: Project name
|
||||||
priority: Priority
|
priority: Priority
|
||||||
due: Due date
|
due: Due date
|
||||||
|
recur: Recurrence frequency
|
||||||
|
until: Recurrence end date
|
||||||
fg: Foreground color
|
fg: Foreground color
|
||||||
bg: Background color
|
bg: Background color
|
||||||
|
rc: Alternate .taskrc file
|
||||||
|
|
||||||
Any command or attribute name may be abbreviated if still unique:
|
Any command or attribute name may be abbreviated if still unique:
|
||||||
task list project:Home
|
task list project:Home
|
||||||
|
@ -86,7 +93,7 @@ Some task descriptions need to be escaped because of the shell:
|
||||||
task add escaped \' quote
|
task add escaped \' quote
|
||||||
|
|
||||||
Many characters have special meaning to the shell, including:
|
Many characters have special meaning to the shell, including:
|
||||||
$ ! ' " ( ) ; \ ` * ? { } [ ] < > | & % # ~</code></pre>
|
$ ! ' " ( ) ; \ ` * ? { } [ ] < > | & % # ~</code></pre>
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
|
|
|
@ -39,17 +39,32 @@
|
||||||
// These are default (but overridable) reports. These entries are necessary
|
// These are default (but overridable) reports. These entries are necessary
|
||||||
// because these three reports were converted from hard-coded reports to custom
|
// because these three reports were converted from hard-coded reports to custom
|
||||||
// reports, and therefore need these config file entries. However, users are
|
// 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
|
// The choice was a) make users edit their .taskrc files, b) write a .taskrc
|
||||||
// upgrade program to make the change, or c) this.
|
// upgrade program to make the change, or c) this.
|
||||||
Config::Config ()
|
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.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.columns"] = "id,project,priority,due,active,age,description";
|
||||||
(*this)["report.list.sort"] = "due+,priority-,project+";
|
(*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.columns"] = "id,project,priority,description";
|
||||||
(*this)["report.ls.sort"] = "priority-,project+";
|
(*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
|
// Read the Configuration file and populate the *this map. The file format is
|
||||||
// is simply lines with name=value pairs. Whitespace between name, = and value
|
// simply lines with name=value pairs. Whitespace between name, = and value is
|
||||||
// is not tolerated, but blank lines and comments starting with # are allowed.
|
// not tolerated, but blank lines and comments starting with # are allowed.
|
||||||
bool Config::load (const std::string& file)
|
bool Config::load (const std::string& file)
|
||||||
{
|
{
|
||||||
std::ifstream in;
|
std::ifstream in;
|
||||||
|
@ -154,17 +169,33 @@ void Config::createDefault (const std::string& home)
|
||||||
fprintf (out, "default.command=list\n");
|
fprintf (out, "default.command=list\n");
|
||||||
|
|
||||||
// Custom reports.
|
// 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, "# Sort: due+,priority-,project+\n");
|
||||||
fprintf (out, "# Filter: pro:x pri:H +bug\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, "# Limit: 10\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.description=Lists all task, all data, matching the specified criteria");
|
||||||
fprintf (out, "report.long.sort=due+,priority-,project+\n");
|
fprintf (out, "report.long.columns=id,project,priority,entry,start,due,recur,age,tags,description");
|
||||||
fprintf (out, "report.list.columns=id,project,priority,due,active,age,description\n");
|
fprintf (out, "report.long.sort=due+,priority-,project+");
|
||||||
fprintf (out, "report.list.sort=due+,priority-,project+\n");
|
|
||||||
fprintf (out, "report.ls.columns=id,project,priority,description\n");
|
fprintf (out, "report.list.description=Lists all tasks matching the specified criteria");
|
||||||
fprintf (out, "report.ls.sort=priority-,project+\n");
|
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);
|
fclose (out);
|
||||||
|
|
||||||
|
|
|
@ -325,7 +325,7 @@ Grid::Cell::operator int () const
|
||||||
case CELL_INT: return mInt;
|
case CELL_INT: return mInt;
|
||||||
case CELL_FLOAT: return (int) mFloat;
|
case CELL_FLOAT: return (int) mFloat;
|
||||||
case CELL_DOUBLE: return (int) mDouble;
|
case CELL_DOUBLE: return (int) mDouble;
|
||||||
case CELL_STRING: return mString.length ();
|
case CELL_STRING: return ::atoi (mString.c_str ());
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -340,7 +340,7 @@ Grid::Cell::operator float () const
|
||||||
case CELL_INT: return (float) mInt;
|
case CELL_INT: return (float) mInt;
|
||||||
case CELL_FLOAT: return mFloat;
|
case CELL_FLOAT: return mFloat;
|
||||||
case CELL_DOUBLE: return (float) mDouble;
|
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;
|
return 0.0;
|
||||||
|
@ -355,7 +355,7 @@ Grid::Cell::operator double () const
|
||||||
case CELL_INT: return (double) mInt;
|
case CELL_INT: return (double) mInt;
|
||||||
case CELL_FLOAT: return (double) mFloat;
|
case CELL_FLOAT: return (double) mFloat;
|
||||||
case CELL_DOUBLE: return mDouble;
|
case CELL_DOUBLE: return mDouble;
|
||||||
case CELL_STRING: return (double) mString.length ();
|
case CELL_STRING: return (double) ::atof (mString.c_str ());
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0.0;
|
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 ();
|
calculateColumnWidths ();
|
||||||
|
|
||||||
|
@ -1028,8 +1028,14 @@ const std::string Table::render ()
|
||||||
if (mSortColumns.size ())
|
if (mSortColumns.size ())
|
||||||
sort (order);
|
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.
|
// 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::vector <std::string> > columns;
|
||||||
std::vector <std::string> blanks;
|
std::vector <std::string> blanks;
|
||||||
|
|
|
@ -91,7 +91,7 @@ public:
|
||||||
|
|
||||||
int rowCount ();
|
int rowCount ();
|
||||||
int columnCount ();
|
int columnCount ();
|
||||||
const std::string render ();
|
const std::string render (int maximum = 0);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string getCell (const int, const int);
|
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 "
|
"blanklines color color.active color.due color.overdue color.pri.H "
|
||||||
"color.pri.L color.pri.M color.pri.none color.recurring color.tagged "
|
"color.pri.L color.pri.M color.pri.none color.recurring color.tagged "
|
||||||
"confirmation curses data.location dateformat default.command "
|
"confirmation curses data.location dateformat default.command "
|
||||||
"default.priority defaultwidth due locking monthsperline nag newest next "
|
"default.priority defaultwidth due locking monthsperline nag next project "
|
||||||
"oldest project shadow.command shadow.file shadow.notify";
|
"shadow.command shadow.file shadow.notify";
|
||||||
|
|
||||||
// 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
|
||||||
|
|
|
@ -130,12 +130,7 @@ static const char* commands[] =
|
||||||
"history",
|
"history",
|
||||||
"ghistory",
|
"ghistory",
|
||||||
"info",
|
"info",
|
||||||
"list",
|
|
||||||
"long",
|
|
||||||
"ls",
|
|
||||||
"newest",
|
|
||||||
"next",
|
"next",
|
||||||
"oldest",
|
|
||||||
"overdue",
|
"overdue",
|
||||||
"projects",
|
"projects",
|
||||||
"start",
|
"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 ();
|
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)
|
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;
|
std::stringstream out;
|
||||||
if (table.rowCount ())
|
if (table.rowCount ())
|
||||||
out << optionalBlankLine (conf)
|
out << optionalBlankLine (conf)
|
||||||
<< table.render ()
|
<< table.render (maximum)
|
||||||
<< optionalBlankLine (conf)
|
<< optionalBlankLine (conf)
|
||||||
<< table.rowCount ()
|
<< table.rowCount ()
|
||||||
<< (table.rowCount () == 1 ? " task" : " tasks")
|
<< (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, 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");
|
||||||
|
@ -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 == "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 == "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 == "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 == "colors") { out = handleColor ( conf ); }
|
||||||
else if (command == "version") { out = handleVersion ( conf ); }
|
else if (command == "version") { out = handleVersion ( conf ); }
|
||||||
else if (command == "help") { longUsage ( 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 handleReportActive (TDB&, T&, Config&);
|
||||||
std::string handleReportOverdue (TDB&, T&, Config&);
|
std::string handleReportOverdue (TDB&, T&, Config&);
|
||||||
std::string handleReportStats (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&);
|
std::string handleCustomReport (TDB&, T&, Config&, const std::string&);
|
||||||
void validReportColumns (const std::vector <std::string>&);
|
void validReportColumns (const std::vector <std::string>&);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue