mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-08-19 09:53:08 +02:00
- Implemented "task ghistory" command to draw a bar chart.
This commit is contained in:
parent
5c91a0d963
commit
6066cc3bab
6 changed files with 238 additions and 4 deletions
|
@ -17,6 +17,7 @@ represents a feature release, and the Z represents a patch.
|
|||
reports have been run (and therefore TDB::gc run)
|
||||
+ Added averages to the "task history" report
|
||||
+ Added ability to override ~/.taskrc with rc:<file>
|
||||
+ Added bar chart history report "task ghistory"
|
||||
+ Bug: Fixed where Esc[0m sequences were being emitted for no good reason
|
||||
+ Bug: Fixed underlined table headers when color is turned off
|
||||
|
||||
|
|
27
TUTORIAL
27
TUTORIAL
|
@ -415,10 +415,12 @@ with no arguments will generate a help message that lists all these commands.
|
|||
|
||||
% task history
|
||||
|
||||
Year Month Added Completed Deleted Net
|
||||
2008 March 21 16 0 5
|
||||
April 13 11 1 1
|
||||
May 8 14 3 -9
|
||||
Year Month Added Completed Deleted Net
|
||||
2008 March 21 16 0 5
|
||||
April 13 11 1 1
|
||||
May 8 14 3 -9
|
||||
|
||||
Average 14 13 1 -1
|
||||
|
||||
This shows that for the three months that task has been used, March and April
|
||||
saw the total number of tasks increase, but in May the number decreased as
|
||||
|
@ -426,6 +428,23 @@ with no arguments will generate a help message that lists all these commands.
|
|||
|
||||
|
||||
|
||||
% task ghistory
|
||||
--------------
|
||||
|
||||
This report shows you an overview of how many tasks were added, completed and
|
||||
deleted, by month, as does "task history", but as a bar chart. It looks like this:
|
||||
|
||||
% task history
|
||||
|
||||
Year Month Added/Completed/Deleted
|
||||
2008 March +++++++++++++++++++++XXXXXXXXXXXXXXXX
|
||||
April +++++++++++++XXXXXXXXXXX-
|
||||
May ++++++++XXXXXXXXXXXXXX---
|
||||
|
||||
With color enabled, the bars contain the size of each bar.
|
||||
|
||||
|
||||
|
||||
% task calendar
|
||||
---------------
|
||||
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
<li>Added "task undelete" feature to restore a (very) recently deleted
|
||||
task
|
||||
<li>Added averages to the "task history" report
|
||||
<li>Added bar chart history report "task ghistory"
|
||||
<li>Added support for rc:<file> to allow override of the default
|
||||
~/.taskrc file
|
||||
<li>Fixed bug where Esc[0m sequences were being emitted for no good reason
|
||||
|
@ -1090,6 +1091,7 @@ on_white on_bright_white</code></pre>
|
|||
task tags
|
||||
task summary
|
||||
task history
|
||||
task ghistory
|
||||
task next
|
||||
task calendar
|
||||
task active
|
||||
|
|
|
@ -126,6 +126,7 @@ static const char* commands[] =
|
|||
"export",
|
||||
"help",
|
||||
"history",
|
||||
"ghistory",
|
||||
"info",
|
||||
"list",
|
||||
"long",
|
||||
|
|
210
src/task.cpp
210
src/task.cpp
|
@ -140,6 +140,10 @@ static void shortUsage (Config& conf)
|
|||
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 ghistory");
|
||||
table.addCell (row, 2, "Shows a graphical 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");
|
||||
|
@ -304,6 +308,7 @@ int main (int argc, char** argv)
|
|||
else if (command == "summary") handleReportSummary (tdb, task, conf);
|
||||
else if (command == "next") handleReportNext (tdb, task, conf);
|
||||
else if (command == "history") handleReportHistory (tdb, task, conf);
|
||||
else if (command == "ghistory") handleReportGHistory (tdb, task, conf);
|
||||
else if (command == "calendar") handleReportCalendar (tdb, task, conf);
|
||||
else if (command == "active") handleReportActive (tdb, task, conf);
|
||||
else if (command == "overdue") handleReportOverdue (tdb, task, conf);
|
||||
|
@ -1719,6 +1724,211 @@ void handleReportHistory (const TDB& tdb, T& task, Config& conf)
|
|||
std::cout << "No tasks." << std::endl;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void handleReportGHistory (const TDB& tdb, T& task, Config& conf)
|
||||
{
|
||||
// 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
|
||||
int widthOfBar = width - 15; // strlen ("2008 September ")
|
||||
|
||||
std::map <time_t, int> groups;
|
||||
std::map <time_t, int> addedGroup;
|
||||
std::map <time_t, int> completedGroup;
|
||||
std::map <time_t, int> deletedGroup;
|
||||
|
||||
// Scan the pending tasks.
|
||||
std::vector <T> pending;
|
||||
tdb.allPendingT (pending);
|
||||
for (unsigned int i = 0; i < pending.size (); ++i)
|
||||
{
|
||||
T task (pending[i]);
|
||||
time_t epoch = monthlyEpoch (task.getAttribute ("entry"));
|
||||
if (epoch)
|
||||
{
|
||||
groups[epoch] = 0;
|
||||
|
||||
if (addedGroup.find (epoch) != addedGroup.end ())
|
||||
addedGroup[epoch] = addedGroup[epoch] + 1;
|
||||
else
|
||||
addedGroup[epoch] = 1;
|
||||
|
||||
if (task.getStatus () == T::deleted)
|
||||
{
|
||||
epoch = monthlyEpoch (task.getAttribute ("end"));
|
||||
|
||||
if (deletedGroup.find (epoch) != deletedGroup.end ())
|
||||
deletedGroup[epoch] = deletedGroup[epoch] + 1;
|
||||
else
|
||||
deletedGroup[epoch] = 1;
|
||||
}
|
||||
else if (task.getStatus () == T::completed)
|
||||
{
|
||||
epoch = monthlyEpoch (task.getAttribute ("end"));
|
||||
|
||||
if (completedGroup.find (epoch) != completedGroup.end ())
|
||||
completedGroup[epoch] = completedGroup[epoch] + 1;
|
||||
else
|
||||
completedGroup[epoch] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Scan the completed tasks.
|
||||
std::vector <T> completed;
|
||||
tdb.allCompletedT (completed);
|
||||
for (unsigned int i = 0; i < completed.size (); ++i)
|
||||
{
|
||||
T task (completed[i]);
|
||||
time_t epoch = monthlyEpoch (task.getAttribute ("entry"));
|
||||
if (epoch)
|
||||
{
|
||||
groups[epoch] = 0;
|
||||
|
||||
if (addedGroup.find (epoch) != addedGroup.end ())
|
||||
addedGroup[epoch] = addedGroup[epoch] + 1;
|
||||
else
|
||||
addedGroup[epoch] = 1;
|
||||
|
||||
epoch = monthlyEpoch (task.getAttribute ("end"));
|
||||
if (task.getStatus () == T::deleted)
|
||||
{
|
||||
epoch = monthlyEpoch (task.getAttribute ("end"));
|
||||
|
||||
if (deletedGroup.find (epoch) != deletedGroup.end ())
|
||||
deletedGroup[epoch] = deletedGroup[epoch] + 1;
|
||||
else
|
||||
deletedGroup[epoch] = 1;
|
||||
}
|
||||
else if (task.getStatus () == T::completed)
|
||||
{
|
||||
epoch = monthlyEpoch (task.getAttribute ("end"));
|
||||
if (completedGroup.find (epoch) != completedGroup.end ())
|
||||
completedGroup[epoch] = completedGroup[epoch] + 1;
|
||||
else
|
||||
completedGroup[epoch] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now build the table.
|
||||
Table table;
|
||||
table.setDateFormat (conf.get ("dateformat", "m/d/Y"));
|
||||
table.addColumn ("Year");
|
||||
table.addColumn ("Month");
|
||||
table.addColumn ("Added/Completed/Deleted");
|
||||
|
||||
if (conf.get ("color", true))
|
||||
{
|
||||
table.setColumnUnderline (0);
|
||||
table.setColumnUnderline (1);
|
||||
}
|
||||
|
||||
// Determine the longest line.
|
||||
int maxLine = 0;
|
||||
foreach (i, groups)
|
||||
{
|
||||
int line = addedGroup[i->first] + completedGroup[i->first] + deletedGroup[i->first];
|
||||
|
||||
if (line > maxLine)
|
||||
maxLine = line;
|
||||
}
|
||||
|
||||
if (maxLine > 0)
|
||||
{
|
||||
int totalAdded = 0;
|
||||
int totalCompleted = 0;
|
||||
int totalDeleted = 0;
|
||||
|
||||
int priorYear = 0;
|
||||
int row = 0;
|
||||
foreach (i, groups)
|
||||
{
|
||||
row = table.addRow ();
|
||||
|
||||
totalAdded += addedGroup[i->first];
|
||||
totalCompleted += completedGroup[i->first];
|
||||
totalDeleted += deletedGroup[i->first];
|
||||
|
||||
Date dt (i->first);
|
||||
int m, d, y;
|
||||
dt.toMDY (m, d, y);
|
||||
|
||||
if (y != priorYear)
|
||||
{
|
||||
table.addCell (row, 0, y);
|
||||
priorYear = y;
|
||||
}
|
||||
table.addCell (row, 1, Date::monthName(m));
|
||||
|
||||
unsigned int addedBar = (widthOfBar * addedGroup[i->first]) / maxLine;
|
||||
unsigned int completedBar = (widthOfBar * completedGroup[i->first]) / maxLine;
|
||||
unsigned int deletedBar = (widthOfBar * deletedGroup[i->first]) / maxLine;
|
||||
|
||||
std::string bar;
|
||||
if (conf.get ("color", true))
|
||||
{
|
||||
char number[24];
|
||||
sprintf (number, "%d", addedGroup[i->first]);
|
||||
std::string aBar = number;
|
||||
while (aBar.length () < addedBar)
|
||||
aBar = " " + aBar;
|
||||
|
||||
sprintf (number, "%d", completedGroup[i->first]);
|
||||
std::string cBar = number;
|
||||
while (cBar.length () < completedBar)
|
||||
cBar = " " + cBar;
|
||||
|
||||
sprintf (number, "%d", deletedGroup[i->first]);
|
||||
std::string dBar = number;
|
||||
while (dBar.length () < deletedBar)
|
||||
dBar = " " + dBar;
|
||||
|
||||
bar = Text::colorize (Text::black, Text::on_green, aBar);
|
||||
bar += Text::colorize (Text::black, Text::on_yellow, cBar);
|
||||
bar += Text::colorize (Text::black, Text::on_red, dBar);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string aBar = ""; while (aBar.length () < addedBar) aBar += "+";
|
||||
std::string cBar = ""; while (cBar.length () < completedBar) cBar += "+";
|
||||
std::string dBar = ""; while (dBar.length () < deletedBar) dBar += "+";
|
||||
|
||||
bar = aBar + cBar + dBar;
|
||||
}
|
||||
|
||||
table.addCell (row, 2, bar);
|
||||
}
|
||||
}
|
||||
|
||||
if (table.rowCount ())
|
||||
{
|
||||
std::cout << optionalBlankLine (conf)
|
||||
<< table.render ()
|
||||
<< std::endl;
|
||||
|
||||
if (conf.get ("color", true))
|
||||
std::cout << "Legend: "
|
||||
<< Text::colorize (Text::black, Text::on_green, "added")
|
||||
<< ", "
|
||||
<< Text::colorize (Text::black, Text::on_yellow, "completed")
|
||||
<< ", "
|
||||
<< Text::colorize (Text::black, Text::on_red, "deleted")
|
||||
<< std::endl;
|
||||
else
|
||||
std::cout << "Legend: + added, X completed, - deleted" << std::endl;
|
||||
}
|
||||
else
|
||||
std::cout << "No tasks." << std::endl;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// A summary of the command usage. Not useful to users, but used to display
|
||||
// usage statistics for feedback.
|
||||
|
|
|
@ -69,6 +69,7 @@ void handleCompleted (const TDB&, T&, Config&);
|
|||
void handleReportSummary (const TDB&, T&, Config&);
|
||||
void handleReportNext (const TDB&, T&, Config&);
|
||||
void handleReportHistory (const TDB&, T&, Config&);
|
||||
void handleReportGHistory (const TDB&, T&, Config&);
|
||||
void handleReportUsage (const TDB&, T&, Config&);
|
||||
void handleReportCalendar (const TDB&, T&, Config&);
|
||||
void handleReportActive (const TDB&, T&, Config&);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue